./nsf2.4.0/man/xowish.1000644 000766 000024 00000006352 13217712707 015363 0ustar00neumannstaff000000 000000 '\" '\" XOTcl - Extended OTcl '\" Copyright (C) 1999-2008 Uwe Zdun '\" Copyright (C) 1999-2014 Gustaf Neumann '\" '\" .so man.macros .TH xowish 1 "" XOWish "XOTcl Applications" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME xowish \- Graphical shell containing object-oriented scripting language XOTcl .SH SYNOPSIS \fBxowish\fR ?\fIfileName arg arg ...\fR? .BE .SH DESCRIPTION .PP \fBxowish\fR is a shell-like application that reads XOTcl commands from its standard input or from a file and evaluates them. In addition to \fBxotclsh\fR it provides graphical user interface support for TK widgets. .PP XOTcl (XOTcl, pronounced exotickle) is an object-oriented scripting language based on MIT's OTcl. It is intended as a value added replacement for OTcl. .PP Scripting languages, like Tcl, are designed for glueing components together, provide features like dynamic extensibility and dynamic typing with automatic conversion, that make them well suited for rapid application development. .PP The basic object system of XOTcl is adopted from OTcl. The object system enables us to define objects, classes, and meta-classes. Classes are special objects with the purpose of managing other objects. ``Managing'' means that a class controls the creation and destruction of its instances and that it contains a repository of methods accessible for the instances. Every object may be enhanced with object-specific methods. XOTcl supports single and multiple inheritance. All relationships in XOTcl, including class and superclass relationships, are completely dynamic and can be introspected. Through method chaining without explicit naming of the intended method, ambiguities in name resolution of methods are avoided. This way a shadowed method can be ``mixed into'' the execution of the current method. .PP XOTcl combines the ideas of scripting and object-orientation in a way that preserves the benefits of both of them. It is equipped with several new language functionalities that help building and managing complex systems. We added the following support: .PP Dynamic Object Aggregations, to provide dynamic aggregations through nested namespaces (objects). .PP Nested Classes, to reduce the interference of independently developed program structures. .PP Assertions, to reduce the interface and the reliability problems caused by dynamic typing and, therefore, to ease the combination of many components. .PP Meta-data, to enhance self-documentation of objects and classes. .PP Per-object mixins, as a means to improve flexibility of mixin methods by giving an object access to several different supplemental classes, which may be changed dynamically. .PP Per-class mixins, as a means to improve flexibility of mixin methods to a class, all instances of the class have access to the mixed in methods like for multiple inheritance, but without the need of intersection classes. .PP Filters as a means of abstractions over method invocations to implement large program structures, like design patterns. .PP Dynamic Component Loading XOTcl integrates the Tcl package loading with architectural support for integration with object-oriented constructs. Moreover, it provides tracking/tracing of component loading. .PP .SH KEYWORDS argument, interpreter, prompt, script file, shell ./nsf2.4.0/man/man.macros000644 000766 000024 00000011417 12501766547 015745 0ustar00neumannstaff000000 000000 '\" The definitions below are for supplemental macros used in Tcl/Tk '\" manual entries. '\" '\" .AP type name in/out ?indent? '\" Start paragraph describing an argument to a library procedure. '\" type is type of argument (int, etc.), in/out is either "in", "out", '\" or "in/out" to describe whether procedure reads or modifies arg, '\" and indent is equivalent to second arg of .IP (shouldn't ever be '\" needed; use .AS below instead) '\" '\" .AS ?type? ?name? '\" Give maximum sizes of arguments for setting tab stops. Type and '\" name are examples of largest possible arguments that will be passed '\" to .AP later. If args are omitted, default tab stops are used. '\" '\" .BS '\" Start box enclosure. From here until next .BE, everything will be '\" enclosed in one large box. '\" '\" .BE '\" End of box enclosure. '\" '\" .CS '\" Begin code excerpt. '\" '\" .CE '\" End code excerpt. '\" '\" .VS ?version? ?br? '\" Begin vertical sidebar, for use in marking newly-changed parts '\" of man pages. The first argument is ignored and used for recording '\" the version when the .VS was added, so that the sidebars can be '\" found and removed when they reach a certain age. If another argument '\" is present, then a line break is forced before starting the sidebar. '\" '\" .VE '\" End of vertical sidebar. '\" '\" .DS '\" Begin an indented unfilled display. '\" '\" .DE '\" End of indented unfilled display. '\" '\" .SO '\" Start of list of standard options for a Tk widget. The '\" options follow on successive lines, in four columns separated '\" by tabs. '\" '\" .SE '\" End of list of standard options for a Tk widget. '\" '\" .OP cmdName dbName dbClass '\" Start of description of a specific option. cmdName gives the '\" option's name as specified in the class command, dbName gives '\" the option's name in the option database, and dbClass gives '\" the option's class in the option database. '\" '\" .UL arg1 arg2 '\" Print arg1 underlined, then print arg2 normally. '\" '\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. '\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out '\" # BS - start boxed text '\" # ^y = starting y location '\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. '\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. '\" # Special macro to handle page bottom: finish off current '\" # box/sidebar if in box/sidebar mode, then invoked standard '\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. '\" # DS - begin display .de DS .RS .nf .sp .. '\" # DE - end display .de DE .fi .RE .sp .. '\" # SO - start of list of standard options .de SO .SH "STANDARD OPTIONS" .LP .nf .ta 4c 8c 12c .ft B .. '\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\fBoptions\\fR manual entry for details on the standard options. .. '\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. '\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. '\" # CE - end code excerpt .de CE .fi .RE .. .de UL \\$1\l'|0\(ul'\\$2 .. ./nsf2.4.0/man/xotclsh.1000644 000766 000024 00000006464 13331304242 015516 0ustar00neumannstaff000000 000000 '\" '\" XOTcl - Extended OTcl '\" Copyright (C) 1999-2008 Uwe Zdun '\" Copyright (C) 1999-2014 Gustaf Neumann '\" '\" .so man.macros .TH xotclsh 1 "" XOTcl "XOTcl Applications" .BS .SH NAME xotclsh \- Tcl Shell containing object-oriented scripting language XOTcl .SH SYNOPSIS \fBxotclsh\fR \fI?filename arg arg ...?\fR .BE .SH DESCRIPTION .PP \fBxotclsh\fR is a shell-like application that reads XOTcl commands from its standard input or from a file and evaluates them. Similarly as the relation between \fBtclsh\fR and \fBwish\fR, \fBxowish\fR provides all functionality of xotclsh and provides as well predefined support for TK widgets. .PP XOTcl (XOTcl, pronounced exotickle) is an object-oriented scripting language based on MIT's OTcl. It is intended as a value added replacement of OTcl. .PP Scripting languages, such as Tcl, are designed for glueing components together, provide features such as dynamic extensibility and dynamic typing with automatic conversion, that make them well suited for rapid application development. .PP The object system of XOTcl enables a user to define objects, classes, and meta-classes. Classes are special objects with the purpose of managing other objects. ``Managing'' means that a class controls the creation and destruction of its instances and that it contains a repository of methods accessible for the instances. Every object may be enhanced with object-specific methods. XOTcl supports single and multiple inheritance. All object-class and class-class relationships in XOTcl are introspectable and can be dynamically changed at arbitrary times. Ambiguities in name resolution of methods are avoided through method chaining through "next", which does not require explicit method naming. .PP XOTcl combines the ideas of scripting and object-orientation in a way that preserves the benefits of both of them. It is equipped with several new language constructs that help building and managing complex systems. We added the following support: .PP \fIDynamic Object Aggregations\fR, to provide dynamic aggregations through nested namespaces (objects). .PP \fINested Classes\fR, to reduce the interference of independently developed program structures. .PP \fIAssertions\fR, to reduce the interface and the reliability problems caused by dynamic typing and, therefore, to ease the combination of many components. .PP \fIMeta-data\fR, to enhance self-documentation of objects and classes. .PP \fIPer-object mixins\fR, as a means to give an object dynamically access to the methods of one or several supplemental classes. .PP \fIPer-class mixins\fR, as a means to give all instances of an class dynamically access to the methods of one or several supplemental classes. .PP \fIFilters\fR as a means of abstractions over method invocations to implement large program structures, like design patterns. XOTcl provides a value-added replacement of Tcl package loading providing integration with object-oriented constructs and tracking/tracing of component loading. .SH VARIABLES .PP \fBxotclsh\fR sets all variables that \fBtclsh\fR sets, and additionally the following variables: .TP 15 \fB::xotcl::version\fR XOTcl version number. .TP 15 \fB::xotcl::confdir\fR Directory for XOTcl configuration. .TP 15 \fB::xotcl::logdir\fR Directory where logfiles are placed. .PP .SH KEYWORDS argument, interpreter, prompt, script file, shell ./nsf2.4.0/COMMIT000644 000766 000024 00000000032 14276141440 014101 0ustar00neumannstaff000000 000000 2.3.0-248-ge733b10d-dirty ./nsf2.4.0/tcl-license.terms000644 000766 000024 00000004321 11257471376 016463 0ustar00neumannstaff000000 000000 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-7013 (c) (1) 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. ./nsf2.4.0/nx-mode.el000644 000766 000024 00000006641 12501766547 015105 0ustar00neumannstaff000000 000000 ; Simple nx-mode designed as an extension of the tcl-mode in tcl.el ; in popular emacs distribitions ; ; gustaf neumann (May 2013) ; TODO: ; - complete definitions, ; - maybe set indent level ; - finish var highlighting for nx variable syntax ; ; For now, load it e.g. with M-x load-library ; ~/.emacs.d/nx-mode.el (load-library "tcl") (setq nx-typeword-list (append tcl-typeword-list '("property"))) ;; extra commands/methods to define something (setq nx-proc-list (append tcl-proc-list '("method" "alias" "forward"))) ;; Tcl control operators are rendered as keywords (if, while, ... (setq nx-keyword-list tcl-keyword-list) (setq nx-builtin-list (append tcl-builtin-list '("apply" "chan" "dict" "lassign" "lsearch" "lrepeat" "lreverse" "lset" "pkg_mkIndex" "refchan" "unload" "update" "cget" "children" "configure" "create" "copy" "delete" "destroy" "filter" "has" "lookup" "heritage" "instances" "methods" "mixinof" "move" "object" "new" "parameter" "parent" "precedence" "require" "slots" "subclass" "superclass" "volatile" "variables" "vars" ))) (setq nx-typeword-regexp (regexp-opt nx-typeword-list 'words)) (setq nx-proc-regexp (regexp-opt nx-proc-list 'words)) (setq nx-keyword-regexp (regexp-opt nx-keyword-list 'words)) (setq nx-builtin-regexp (regexp-opt nx-builtin-list 'words)) (add-to-list 'myKeywords (cons nx-typeword-regexp 'font-lock-type-face)) (add-to-list 'myKeywords (cons nx-proc-regexp 'font-lock-function-name-face)) (add-to-list 'myKeywords (cons nx-keyword-regexp 'font-lock-keyword-face)) (add-to-list 'myKeywords (cons nx-builtin-regexp 'font-lock-builtin-face)) ;;(message "My keywords is: %S" myKeywords) (define-derived-mode nx-mode tcl-mode (setq font-lock-defaults '(myKeywords)) (setq mode-name "NX Tcl") ) ;;;; the following section contains already an adapted regexp for vars in nx ;;; (to highlight "set :x a" the same way as "set x a"), but this has still ;;; to be mangeled into the nicer style of above... (setq myKeywords0 (append '("nx::Class\\|nx::Object\\|\\bmethod\\b\\|\\balias\\b\\|\\bforward\\b\\|\\bobject\\b\\|\\bproc\\b" . 'font-lock-function-name-face) '("\\bclass\\b\\|\\bcget\\b\\|\\bconfigure\\b\\|\\bcreate\\b\\|\\beval\\b\\|\\bfilter\\b\\|\\binfo\\b\\|\\blookup\\b\\|\\bmixin\\b\\|\\bsuperclass\\b" . 'font-lock-builtin-face) ;; '(nx-typeword-regexp . 'font-lock-type-face) '("\\bproperty\\b\\|\\bprotected\\b\\|\\bprivate\\b\\|\\bpublic\\b\\|\\bvariable\\b\\|\\bupvar\\b" . 'font-lock-type-face) ;; (list (concat "\\(\\s-\\|^\\)" ;; (regexp-opt nx-typeword-list t) ;; "\\(\\s-\\|$\\)") ;; 2 'font-lock-type-face) ;; When variable names are enclosed in {} braces, any ;; character can be used. Otherwise just letters, digits, ;; underscores. Variable names can be prefixed with any ;; number of "namespace::" qualifiers. A leading "::" refers ;; to the global namespace. '("\\${\\([^}]+\\)}" 1 'font-lock-variable-name-face) '("\\$\\(\\(?:::\\)?\\(?:[[:alnum:]_]+::\\)*[[:alnum:]_]+\\)" 1 'font-lock-variable-name-face) '("\\(?:\\s-\\|^\\|\\[\\)set\\s-+{\\([^}]+\\)}" 1 'font-lock-variable-name-face 'keep) '("\\(?:\\s-\\|^\\|\\[\\)set\\s-+\\(\\(?:::\\)?\ \\(?:[[:alnum:]_]+::\\)*:?[[:alnum:]_]+\\)" 1 'font-lock-variable-name-face 'keep) ) )./nsf2.4.0/configure.ac000644 000766 000024 00000044102 14274463622 015471 0ustar00neumannstaff000000 000000 #-------------------------------------------------------------------- # Sample configure.in for Tcl Extensions. The only places you should # need to modify this file are marked by the string __CHANGE__ #-------------------------------------------------------------------- #-------------------------------------------------------------------- # __CHANGE__ # This very first macro is used to verify that the configure script can # find the sources. The argument to AC_INIT should be a unique filename # for this package, and can be a relative path, such as: # #-------------------------------------------------------------------- AC_PREREQ([2.71]) define(NsfVersion, 2.4.0) AC_INIT([nsf],[NsfVersion],[https://sourceforge.net/p/next-scripting/tickets/]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([tclconfig]) #-------------------------------------------------------------------- # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable == "unix" or "windows". #-------------------------------------------------------------------- TEA_INIT([3.10]) #-------------------------------------------------------------------- # specify some extra flags #-------------------------------------------------------------------- # According to http://www.gnu.org/software/autoconf/manual/autoconf.html # - "with" is for external software (optional packages) # - "enable" is for optional features # AC_ARG_WITH([aolserver3], AS_HELP_STRING([--with-aolserver3=AOL_SERVER_DIR], [build an AOLserver 3 module; point to directory containing aolsever/include (default: off)]), [with_aol3=$withval], [with_aol3=no]) AC_ARG_WITH([dtrace], AS_HELP_STRING([--with-dtrace], [build nsf with dtrace (default: without)]), [with_dtrace=$withval], [with_dtrace=no]) AC_ARG_WITH([mongoc], AS_HELP_STRING([--with-mongoc=MONGOC_INCLUDE_DIR[,MONGOC_LIB_DIR]], [build nsf with mongodb c-driver support (default: without)]), [with_mongoc=$withval], [with_mongoc=no]) AC_ARG_WITH([bson], AS_HELP_STRING([--with-bson=BSON_INCLUDE_DIR[,BSON_LIB_DIR]], [build nsf with mongodb bson support (default: without)]), [with_bson=$withval], [with_bson=no]) AC_ARG_ENABLE([profile], AS_HELP_STRING([--enable-profile], [build nsf with profile support (default: disabled)]), [enable_profile=$enableval], [enable_profile=no]) AC_ARG_ENABLE([memcount], AS_HELP_STRING([--enable-memcount=yes|trace], [build nsf with memcount debug support (default: disabled)]), [enable_memcount=$enableval], [enable_memcount=no]) AC_ARG_ENABLE([development], AS_HELP_STRING([--enable-development=yes|test], [build nsf with development support (intensive runtime checking, etc.; default: disabled)]), [enable_development=$enableval], [enable_development=no]) AC_ARG_ENABLE([assertions], AS_HELP_STRING([--enable-assertions], [build nsf with assertion support (default: enabled)]), [enable_assertions=$enableval], [enable_assertions=yes]) AC_ARG_ENABLE([assemble], AS_HELP_STRING([--enable-assemble=yes|label|call], [build nsf with assemble support (default: disabled)]), [enable_assemble=$enableval], [enable_assemble=no]) subdirs="" if ! test "$with_mongoc" = no; then test_mongodb=test-mongdb subdirs="$subdirs ${srcdir}/library/mongodb" fi test_actiweb="" libdirs_actiweb="" apps_actiweb="" AC_SUBST([subdirs]) #-------------------------------------------------------------------- # __CHANGE__ # Set your package name and version numbers here. The NODOT_VERSION is # required for constructing the library name on systems that don't like # dots in library names (Windows). The VERSION variable is used on the # other systems. #-------------------------------------------------------------------- NSF_MAJOR_VERSION=2 NSF_MINOR_VERSION=4 NSF_PATCH_LEVEL=$PACKAGE_VERSION NSF_VERSION=${NSF_MAJOR_VERSION}.${NSF_MINOR_VERSION} NODOT_VERSION=${NSF_MAJOR_VERSION}${NSF_MINOR_VERSION} AC_SUBST([NSF_VERSION]) AC_SUBST([NSF_MAJOR_VERSION]) AC_SUBST([NSF_MINOR_VERSION]) AC_SUBST([NSF_PATCH_LEVEL]) echo "Configuring NSF Version $PACKAGE_VERSION" AC_CHECK_PROG(git_installed,git,"yes", "no") if test "$git_installed" = "yes" -a -d ".git" ; then nsf_commit=`git describe --always --dirty` elif test -f "COMMIT" ; then nsf_commit=`cat COMMIT` else nsf_commit=unknown-${PACKAGE_VERSION} fi NSF_COMMIT=$nsf_commit AC_SUBST([NSF_COMMIT]) # AC_DEFINE_UNQUOTED([NSF_COMMIT], "$nsf_commit", # [Commit ID at the time of the last configure run.]) AC_CHECK_TYPES([intptr_t, uintptr_t]) #-------------------------------------------------------------------- # Load the tclConfig.sh file #-------------------------------------------------------------------- TEA_PATH_TCLCONFIG TEA_LOAD_TCLCONFIG AC_CHECK_FUNCS([strnstr]) #-------------------------------------------------------------------- # check for TK #-------------------------------------------------------------------- #-------------------------------------------------------------------- # Handle the --prefix=... option by defaulting to what Tcl gave. # Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. #----------------------------------------------------------------------- TEA_PREFIX #----------------------------------------------------------------------- # Standard compiler checks. # This sets up CC by using the CC env var, or looks for gcc otherwise. # This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create # the basic setup necessary to compile executables. #----------------------------------------------------------------------- TEA_SETUP_COMPILER #-------------------------------------------------------------------- # check for extra flags # # FORCE_NO_STUBS is deactivated for now if ! test "$with_aol3" = "no"; then echo "Pre-configuring AOL-Server (nsf)" AOL_DEFINES="-DAOL_SERVER -DUSE_TCL8X -I$with_aol3/include -I$TCL_SRC_DIR/generic" FORCE_NO_STUBS=1 else AOL_DEFINES="" FORCE_NO_STUBS=0 fi # set the default aol_prefix aol_prefix="/usr/local/aolserver" # if we have under ${prefix} either modules/tcl/init.tcl (aolserver # style) or modules/tcl/init.tcl (naviserver style), then use # ${prefix} as aol_prefix (path for the installation of # aolserver/naviserver specific tcl files). if test -f "${prefix}/modules/tcl/init.tcl" ; then aol_prefix="${prefix}" else if test -f "${prefix}/tcl/init.tcl" ; then aol_prefix="${prefix}" fi fi AC_SUBST([aol_prefix]) #-------------------------------------------------------------------- # check for tclCompile.h (needed, when compiled without full source) if test -f "$TCL_SRC_DIR/generic/tclCompile.h"; then AC_DEFINE([HAVE_TCL_COMPILE_H], [1], [Do we have tclCompile.h installed?]) fi if test "$enable_assertions" = yes; then AC_DEFINE([NSF_WITH_ASSERTIONS], [1], [Are we building with assertions support?]) fi if test "$enable_profile" = yes; then AC_DEFINE([NSF_PROFILE], [1], [Are we building with profile support?]) fi if test "$enable_development" = yes; then AC_DEFINE([NSF_DEVELOPMENT], [1], [Are we building with development support?]) fi if test "$enable_development" = test; then AC_DEFINE([NSF_DEVELOPMENT_TEST], [1], [Are we building with development support and intesive testing?]) fi if test "$enable_memcount" = yes; then AC_DEFINE([NSF_MEM_COUNT], [1], [Are we building with memcount support?]) fi if test "$enable_memcount" = trace; then AC_DEFINE([NSF_MEM_TRACE], [1], [Are we building with memcount tracing support?]) fi if test "$enable_assemble" = yes; then AC_DEFINE([NSF_ASSEMBLE], [1], [Are we building with assembly support?]) fi if test "$enable_assemble" = call; then AC_DEFINE([NSF_ASSEMBLE_CT], [1], [Are we building with assembly call threading support?]) fi if test "$enable_assemble" = call; then AC_DEFINE([NSF_ASSEMBLE_LT], [1], [Are we building with assembly label threading support?]) fi DTRACE_OBJ= if test "$with_dtrace" = yes; then AC_DEFINE([NSF_DTRACE], [1], [Are we building with DTrace support?]) # Under macOS, we need no nsfDTrace.o if test "`uname -s`" != "Darwin" ; then DTRACE_OBJ=nsfDTrace.o fi DTRACE_HDR='$(src_generic_dir)/nsfDTrace.h' DTRACE_SRC='$(src_generic_dir)/nsfDTrace.d' fi AC_SUBST([DTRACE_OBJ]) AC_SUBST([DTRACE_HDR]) AC_SUBST([DTRACE_SRC]) #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, # public headers that need to be installed in TEA_ADD_HEADERS, # stub library C source files to compile in TEA_ADD_STUB_SOURCES, # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- stubdir=stubs${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION} TEA_ADD_SOURCES([nsf.c nsfError.c nsfObjectData.c nsfProfile.c \ nsfDebug.c nsfUtil.c nsfObj.c nsfPointer.c nsfEnumerationType.c \ nsfCmdDefinitions.c nsfFunPtrHashTable.c nsfShadow.c nsfCompile.c aolstub.c \${srcdir}/generic/${stubdir}/nsfStubInit.${OBJEXT}]) TEA_ADD_HEADERS([generic/nsf.h generic/nsfInt.h generic/${stubdir}/nsfDecls.h generic/${stubdir}/nsfIntDecls.h]) TEA_ADD_INCLUDES([]) TEA_ADD_LIBS([]) TEA_ADD_CFLAGS([-DNSF_VERSION=\\\"$NSF_VERSION\\\" -DNSF_PATCHLEVEL=\\\"$NSF_PATCH_LEVEL\\\" \ -DNSF_COMMIT=\\\"$NSF_COMMIT\\\" $AOL_DEFINES ]) TEA_ADD_STUB_SOURCES([nsfStubLib.c]) TEA_ADD_TCL_SOURCES([]) #-------------------------------------------------------------------- # __CHANGE__ # # You can add more files to clean if your extension creates any extra # files by extending CLEANFILES. # Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure # and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var. # # A few miscellaneous platform-specific items: # TEA_ADD_* any platform specific compiler/build info here. #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then if test "$GCC" != "yes" ; then AC_DEFINE([VISUAL_CC]) fi CLEANFILES="*.lib *.dll *.exp *.ilk *.pdb vc50.pch vc60.pch " #TEA_ADD_SOURCES([win/winFile.c]) #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"]) else CLEANFILES="*.a *.so *~ core gmon.out" #TEA_ADD_SOURCES([unix/unixFile.c]) #TEA_ADD_LIBS([-lsuperfly]) fi CLEANFILES="$CLEANFILES *.${OBJEXT} pkgIndex.tcl" #-------------------------------------------------------------------- # __CHANGE__ # Choose which headers you need. Extension authors should try very # hard to only rely on the Tcl public header files. Internal headers # contain private data structures and are subject to change without # notice. # This must be done AFTER calling TEA_PATH_TCLCONFIG/TEA_LOAD_TCLCONFIG # so that we can extract TCL_SRC_DIR from the config file (in the case # of private headers #-------------------------------------------------------------------- #TEA_PUBLIC_TCL_HEADERS TEA_PRIVATE_TCL_HEADERS #TEA_PUBLIC_TK_HEADERS #TEA_PRIVATE_TK_HEADERS #TEA_PATH_X #-------------------------------------------------------------------- # Check whether --enable-threads or --disable-threads was given. #-------------------------------------------------------------------- TEA_ENABLE_THREADS #-------------------------------------------------------------------- # The statement below defines a collection of symbols related to # building as a shared library instead of a static library. #-------------------------------------------------------------------- TEA_ENABLE_SHARED #-------------------------------------------------------------------- # This macro figures out what flags to use with the compiler/linker # when building shared/static debug/optimized objects. This information # can be taken from the tclConfig.sh file, but this figures it all out. #-------------------------------------------------------------------- TEA_CONFIG_CFLAGS # Without the following two eval statements, NSF_SHARED_LIB_SUFFIX # in nsfConfig.sh has $PACKAGE_VERSION unresolved. When another # app links against nsf, the PACKAGE_VERSIONs are confused. # # Without the first eval, we get # NSF_SHARED_LIB_SUFFIX=${PACKAGE_VERSION}\$\{DBGX\}${SHLIB_SUFFIX} # NSF_UNSHARED_LIB_SUFFIX=${PACKAGE_VERSION}\$\{DBGX\}.a # # after the first eval, we get # NSF_SHARED_LIB_SUFFIX=1.2.1${DBGX}.so # NSF_UNSHARED_LIB_SUFFIX=1.2.1${DBGX}.a # after the second eval, all variables are resolved. eval "SHARED_LIB_SUFFIX=${SHARED_LIB_SUFFIX}" eval "UNSHARED_LIB_SUFFIX=${UNSHARED_LIB_SUFFIX}" #eval "SHARED_LIB_SUFFIX=${SHARED_LIB_SUFFIX}" #eval "UNSHARED_LIB_SUFFIX=${UNSHARED_LIB_SUFFIX}" #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols # option. #-------------------------------------------------------------------- TEA_ENABLE_SYMBOLS #-------------------------------------------------------------------- # Everyone should be linking against the Tcl stub library. If you # can't for some reason, remove this definition. If you aren't using # stubs, you also need to modify the SHLIB_LD_LIBS setting below to # link against the non-stubbed Tcl library. #-------------------------------------------------------------------- AC_DEFINE([USE_TCL_STUBS], [1], [Use Tcl stubs]) #-------------------------------------------------------------------- # This macro generates a line to use when building a library. It # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, # and TEA_LOAD_TCLCONFIG macros above. #-------------------------------------------------------------------- TEA_MAKE_LIB #-------------------------------------------------------------------- # Find tclsh so that we can run pkg_mkIndex to generate the pkgIndex.tcl # file during the install process. Don't run the TCLSH_PROG through # ${CYGPATH} because it's being used directly by make. # Require that we use a tclsh shell version 8.2 or later since earlier # versions have bugs in the pkg_mkIndex routine. #-------------------------------------------------------------------- TEA_PROG_TCLSH # make this available, for such as nsfConfig.sh NSF_COMPATIBLE_TCLSH=${TCLSH_PROG} AC_SUBST([NSF_COMPATIBLE_TCLSH]) AC_SUBST([TCL_EXEC_PREFIX]) # # Next Scripting specific configs # #NSF_SRC_DIR=$srcdir #NSF_SRC_DIR="`pwd`" NSF_BUILD_DIR=${PWD} cd ${srcdir} NSF_SRC_DIR=${PWD} cd ${NSF_BUILD_DIR} AC_SUBST([NSF_SRC_DIR]) eval "NSF_PKG_LIBDIR=\"${libdir}/${PACKAGE_NAME}${PACKAGE_VERSION}\"" AC_SUBST([NSF_PKG_LIBDIR]) if test "${TEA_PLATFORM}" != "windows" ; then NSF_BUILD_LIB_SPEC="-L${NSF_BUILD_DIR} -lnsf${PACKAGE_VERSION}" NSF_LIB_SPEC="-L${NSF_PKG_LIBDIR} -lnsf${PACKAGE_VERSION}" # If someone wants to build without stubs, as it was the case for # earlier Tcl versions, we keep the following block as a reference. if test "${TCL_MAJOR_VERSION}" = "8" -a "${TCL_MINOR_VERSION}" = "0"; then NSF_BUILD_STUB_LIB_PATH="" NSF_STUB_LIB_PATH="" NSF_BUILD_STUB_LIB_SPEC="" NSF_STUB_LIB_SPEC="" else NSF_BUILD_STUB_LIB_PATH="${NSF_SRC_DIR}/${PKG_STUB_LIB_FILE}" NSF_STUB_LIB_PATH="${NSF_PKG_LIBDIR}/${PKG_STUB_LIB_FILE}" NSF_BUILD_STUB_LIB_SPEC="-L${NSF_BUILD_DIR} -lnsfstub${PACKAGE_VERSION}" NSF_STUB_LIB_SPEC="-L${NSF_PKG_LIBDIR} -lnsfstub${PACKAGE_VERSION}" AC_DEFINE([COMPILE_NSF_STUBS]) fi else NSF_BUILD_LIB_SPEC="${NSF_SRC_DIR}/${PKG_LIB_FILE}" NSF_LIB_SPEC="${NSF_PKG_LIBDIR}/${PKG_LIB_FILE}" NSF_BUILD_STUB_LIB_PATH="${NSF_BUILD_DIR}/${PKG_STUB_LIB_FILE}" NSF_STUB_LIB_PATH="${NSF_PKG_LIBDIR}/${PKG_STUB_LIB_FILE}" NSF_BUILD_STUB_LIB_SPEC="${NSF_BUILD_DIR}/${PKG_STUB_LIB_FILE}" NSF_STUB_LIB_SPEC="${NSF_PKG_LIBDIR}/${PKG_STUB_LIB_FILE}" AC_DEFINE([COMPILE_NSF_STUBS]) fi AC_SUBST([SHARED_LIB_SUFFIX]) AC_SUBST([UNSHARED_LIB_SUFFIX]) AC_SUBST([NSF_BUILD_LIB_SPEC]) AC_SUBST([NSF_LIB_SPEC]) AC_SUBST([NSF_BUILD_STUB_LIB_SPEC]) AC_SUBST([NSF_STUB_LIB_SPEC]) AC_SUBST([NSF_BUILD_STUB_LIB_PATH]) AC_SUBST([NSF_STUB_LIB_PATH]) AC_SUBST([NXSH]) AC_SUBST([XOWISH]) # include dirs for nsf during build process (i.e., does not assume installed) NSF_BUILD_INCLUDE_DIR="${NSF_SRC_DIR}/generic" NSF_BUILD_INCLUDE_SPEC="-I${NSF_BUILD_INCLUDE_DIR}" AC_SUBST([NSF_BUILD_INCLUDE_DIR]) AC_SUBST([NSF_BUILD_INCLUDE_SPEC]) eval "NSF_INCLUDE_DIR=\"$includedir\"" AC_SUBST([NSF_INCLUDE_DIR]) AC_SUBST([test_actiweb]) AC_SUBST([libdirs_actiweb]) AC_SUBST([apps_actiweb]) AC_SUBST([TEA_PLATFORM]) dnl macro expanding to the names of files ./configure is to generate. dnl reasoning: this is a factoring; I use this value elsewhere. dnl dnl Change the value of -this- macro if you want to add or remove dnl such files. AC_DEFUN([CONFIG_OUTPUT_FILES], [[Makefile ${srcdir}/nsfConfig.sh ${srcdir}/library/xotcl/xotclsh ${srcdir}/library/xotcl/xowish nxsh nxwish ${srcdir}/doc/version.inc]]) #-------------------------------------------------------------------- # the value of this variable is set to the files which are to be # removed when the user invokes 'make distclean' (i.e., those # files generated by ./configure) and is used in the make distclean # target, defined in Makefile.in #-------------------------------------------------------------------- CONFIG_CLEAN_FILES="CONFIG_OUTPUT_FILES autom4te.cache/" AC_SUBST([CONFIG_CLEAN_FILES]) AC_CONFIG_FILES(CONFIG_OUTPUT_FILES) #-------------------------------------------------------------------- # Finally, substitute all of the various values into the Makefile, # and generate the other output files. (this is done by invoking # config.status) # # NOTE the lack of parameters! AC_OUTPUT with params is deprecated; # use macros such as AC_CONFIG_FILES, AC_HEADER_FILES, etc to add # to the files output by ./configure. #-------------------------------------------------------------------- AC_OUTPUT chmod +x nxsh nxwish ${srcdir}/library/xotcl/xotclsh ${srcdir}/library/xotcl/xowish for subdir in ${subdirs} do echo "==================== configure $subdir" if test x"${srcdir}" = x. ; then confdir=. else #mkdir -p $subdir confdir=${srcdir}/$subdir fi (cd $subdir; echo $SHELL ${confdir}/configure ${ac_configure_args} --prefix=${prefix} --with-nsf=${NSF_SRC_DIR}; eval $SHELL ${confdir}/configure ${ac_configure_args} --prefix=${prefix} --with-nsf=${NSF_SRC_DIR}) done ./nsf2.4.0/host.cert000644 000766 000024 00000000000 13465515122 015016 0ustar00neumannstaff000000 000000 ./nsf2.4.0/nsfConfig.sh.in000644 000766 000024 00000004723 12501766547 016070 0ustar00neumannstaff000000 000000 # nsfConfig.sh -- # # This shell script (for sh) is generated automatically by the Next # Scripting configure script. It will create shell variables for most # of the configuration options discovered by the configure script. # This script is intended to be included by the configure scripts for # Next Scripting extensions so that they don't have to figure this all # out for themselves. This file does not duplicate information # already provided by tclConfig.sh, so you may need to use that file # in addition to this one. # # The information in this file is specific to a single platform. # Version number. NSF_VERSION='@NSF_VERSION@' NSF_PATCH_LEVEL='@NSF_PATCH_LEVEL@' # String to pass to compiles to pick up includes during build # (i.e., assuming nothing has been installed) NSF_BUILD_INCLUDE_DIR='@NSF_BUILD_INCLUDE_DIR@' NSF_BUILD_INCLUDE_SPEC="-I${NSF_BUILD_INCLUDE_DIR}" # String to pass to compiles to pick up the nsf includes from their # installed directory. NSF_INCLUDE_DIR="@NSF_INCLUDE_DIR@" NSF_INCLUDE_SPEC="-I${NSF_INCLUDE_DIR}" # The name of the nsf library (may be either a .a file or a shared library): NSF_LIB_FILE=@PKG_LIB_FILE@ # String to pass to linker to pick up the nsf library from its # build directory. NSF_BUILD_LIB_SPEC='@NSF_BUILD_LIB_SPEC@' # String to pass to linker to pick up the nsf library from its # installed directory. NSF_LIB_SPEC='@NSF_LIB_SPEC@' # The name of the NSF stub library (a .a file): # NSF_STUB_LIB_FILE=@PKG_STUB_LIB_FILE@ # String to pass to linker to pick up the NSF stub library from its # build directory. NSF_BUILD_STUB_LIB_SPEC='@NSF_BUILD_STUB_LIB_SPEC@' # String to pass to linker to pick up the NSF stub library from its # installed directory. NSF_STUB_LIB_SPEC='@NSF_STUB_LIB_SPEC@' # Name of the NSF stub library with full path in build and install directory NSF_BUILD_STUB_LIB_PATH='@NSF_BUILD_STUB_LIB_PATH@' NSF_STUB_LIB_PATH='@NSF_STUB_LIB_PATH@' # Location of the top-level source directories from which nsf # was built. This is the directory that contains generic, unix, etc. # If nsf was compiled in a different place than the directory # containing the source files, this points to the location of the sources, # not the location where nsf was compiled. NSF_SRC_DIR='@NSF_SRC_DIR@' # shared and unshared library suffix NSF_SHARED_LIB_SUFFIX=@SHARED_LIB_SUFFIX@ NSF_UNSHARED_LIB_SUFFIX=@UNSHARED_LIB_SUFFIX@ # the shell in whose installation dirs the nsf package is installed NSF_COMPATIBLE_TCLSH=@NSF_COMPATIBLE_TCLSH@ ./nsf2.4.0/tclconfig/install-sh000755 000766 000024 00000033054 12327667054 017165 0ustar00neumannstaff000000 000000 #!/bin/sh # install - install a program, script, or datafile scriptversion=2011-04-20.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -S $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -S) stripcmd="$stripprog $2" shift;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ./nsf2.4.0/tclconfig/mktar.sh000755 000766 000024 00000001303 13353342636 016622 0ustar00neumannstaff000000 000000 #!/bin/sh pwd=`pwd` name=`basename $(pwd)` echo "name=$name" OPTIONS=--disable-copyfile #OPTIONS= make distclean cd .. tar zcvf ./$name.tar.gz $OPTIONS \ `find ./$name -type f -o -type l| fgrep -v .git| fgrep -v .dSYM | fgrep -v .DS_Store |\ fgrep -v "~"| fgrep -v "#" | fgrep -v -- -orig | fgrep -v .junk |\ fgrep -v .gcov |fgrep -v .gcda|fgrep -v .gcno|fgrep -v lcov-result|fgrep -v lcov.info |\ egrep -v "doc/example.*[.]txt"| fgrep -v '.c-' | fgrep -v '.tcl-' |\ fgrep -v .dylib | fgrep -v ._ | egrep -v ".o$" |\ fgrep -v "autom4te"| fgrep -v config. | fgrep -v callgrind.out. | fgrep -v .plist |\ fgrep -v .db | fgrep -v .gdb | fgrep -v .graffle` ./nsf2.4.0/configure000755 000766 000024 00001146235 14274463622 015125 0ustar00neumannstaff000000 000000 #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for nsf 2.4.0. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="as_nop=: if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else $as_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and $0: https://sourceforge.net/p/next-scripting/tickets/ about $0: your system, including any error possibly output before $0: this message. Then install a modern shell, or manually $0: run the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='nsf' PACKAGE_TARNAME='nsf' PACKAGE_VERSION='2.4.0' PACKAGE_STRING='nsf 2.4.0' PACKAGE_BUGREPORT='https://sourceforge.net/p/next-scripting/tickets/' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS CONFIG_CLEAN_FILES TEA_PLATFORM apps_actiweb libdirs_actiweb test_actiweb NSF_INCLUDE_DIR NSF_BUILD_INCLUDE_SPEC NSF_BUILD_INCLUDE_DIR XOWISH NXSH NSF_STUB_LIB_PATH NSF_BUILD_STUB_LIB_PATH NSF_STUB_LIB_SPEC NSF_BUILD_STUB_LIB_SPEC NSF_LIB_SPEC NSF_BUILD_LIB_SPEC UNSHARED_LIB_SUFFIX SHARED_LIB_SUFFIX NSF_PKG_LIBDIR NSF_SRC_DIR TCL_EXEC_PREFIX NSF_COMPATIBLE_TCLSH TCLSH_PROG PRACTCL_NAME_LIBRARY PRACTCL_VC_MANIFEST_EMBED_EXE PRACTCL_VC_MANIFEST_EMBED_DLL PRACTCL_STUB_LIB PRACTCL_STATIC_LIB PRACTCL_SHARED_LIB PRACTCL_TOOLSET PRACTCL_CFLAGS VC_MANIFEST_EMBED_EXE VC_MANIFEST_EMBED_DLL RANLIB_STUB MAKE_STUB_LIB MAKE_STATIC_LIB MAKE_SHARED_LIB MAKE_LIB TCL_DBGX LDFLAGS_DEFAULT CFLAGS_DEFAULT LD_LIBRARY_PATH_VAR SHLIB_CFLAGS SHLIB_LD_LIBS SHLIB_SUFFIX SHLIB_LD STLIB_LD CFLAGS_WARNING CFLAGS_OPTIMIZE CFLAGS_DEBUG RC CELIB_DIR AR STUBS_BUILD SHARED_BUILD TCL_THREADS TCL_TOP_DIR_NATIVE TCL_INCLUDES PKG_OBJECTS PKG_SOURCES DTRACE_SRC DTRACE_HDR DTRACE_OBJ aol_prefix EGREP GREP MATH_LIBS RANLIB SET_MAKE INSTALL_LIBRARY INSTALL_SCRIPT INSTALL_PROGRAM INSTALL_DATA INSTALL_DATA_DIR INSTALL CPP TCL_SHLIB_LD_LIBS TCL_LD_FLAGS TCL_EXTRA_CFLAGS TCL_DEFS TCL_LIBS CLEANFILES TCL_STUB_LIB_SPEC TCL_STUB_LIB_FLAG TCL_STUB_LIB_FILE TCL_LIB_SPEC TCL_LIB_FLAG TCL_LIB_FILE TCL_SRC_DIR TCL_BIN_DIR TCL_PATCH_LEVEL TCL_VERSION OBJEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC NSF_COMMIT git_installed NSF_PATCH_LEVEL NSF_MINOR_VERSION NSF_MAJOR_VERSION NSF_VERSION subdirs PKG_CFLAGS PKG_LIBS PKG_INCLUDES PKG_HEADERS PKG_TCL_SOURCES PKG_STUB_OBJECTS PKG_STUB_SOURCES PKG_STUB_LIB_FILE PKG_LIB_FILE9 PKG_LIB_FILE8 PKG_LIB_FILE EXEEXT CYGPATH TEA_TK_EXTENSION target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_aolserver3 with_dtrace with_mongoc with_bson enable_profile enable_memcount enable_development enable_assertions enable_assemble with_tcl with_tclinclude enable_threads enable_shared enable_stubs enable_64bit enable_64bit_vis enable_rpath enable_wince with_celib enable_symbols with_tclsh ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures nsf 2.4.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/nsf] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of nsf 2.4.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-profile build nsf with profile support (default: disabled) --enable-memcount=yes|trace build nsf with memcount debug support (default: disabled) --enable-development=yes|test build nsf with development support (intensive runtime checking, etc.; default: disabled) --enable-assertions build nsf with assertion support (default: enabled) --enable-assemble=yes|label|call build nsf with assemble support (default: disabled) --enable-threads build with threads --enable-shared build and link with shared libraries (default: on) --enable-stubs build and link with stub libraries. Always true for shared builds (default: on) --enable-64bit enable 64bit support (default: off) --enable-64bit-vis enable 64bit Sparc VIS support (default: off) --disable-rpath disable rpath support (default: on) --enable-wince enable Win/CE support (where applicable) --enable-symbols build with debugging symbols (default: off) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-aolserver3=AOL_SERVER_DIR build an AOLserver 3 module; point to directory containing aolsever/include (default: off) --with-dtrace build nsf with dtrace (default: without) --with-mongoc=MONGOC_INCLUDE_DIR,MONGOC_LIB_DIR build nsf with mongodb c-driver support (default: without) --with-bson=BSON_INCLUDE_DIR,BSON_LIB_DIR build nsf with mongodb bson support (default: without) --with-tcl directory containing tcl configuration (tclConfig.sh) --with-tclinclude directory containing the public Tcl header files --with-celib=DIR use Windows/CE support library from DIR --with-tclsh Specify a local tcl shell to use for dynamic code Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF nsf configure 2.4.0 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main (void) { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. */ #include #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that # executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: program exited with status $ac_status" >&5 printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run ac_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by nsf $as_me 2.4.0, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu #-------------------------------------------------------------------- # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable == "unix" or "windows". #-------------------------------------------------------------------- # TEA extensions pass this us the version of TEA they think they # are compatible with. TEA_VERSION="3.10" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for correct TEA configuration" >&5 printf %s "checking for correct TEA configuration... " >&6; } if test x"${PACKAGE_NAME}" = x ; then as_fn_error $? " The PACKAGE_NAME variable must be defined by your TEA configure.ac" "$LINENO" 5 fi if test x"3.10" = x ; then as_fn_error $? " TEA version not specified." "$LINENO" 5 elif test "3.10" != "${TEA_VERSION}" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: warning: requested TEA version \"3.10\", have \"${TEA_VERSION}\"" >&5 printf "%s\n" "warning: requested TEA version \"3.10\", have \"${TEA_VERSION}\"" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok (TEA ${TEA_VERSION})" >&5 printf "%s\n" "ok (TEA ${TEA_VERSION})" >&6; } fi # If the user did not set CFLAGS, set it now to keep macros # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi TEA_TK_EXTENSION=0 case "`uname -s`" in *win32*|*WIN32*|*MINGW32_*) # Extract the first word of "cygpath", so it can be a program name with args. set dummy cygpath; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CYGPATH+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CYGPATH"; then ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CYGPATH="cygpath -m" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo" fi fi CYGPATH=$ac_cv_prog_CYGPATH if test -n "$CYGPATH"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CYGPATH" >&5 printf "%s\n" "$CYGPATH" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi EXEEXT=".exe" TEA_PLATFORM="windows" ;; *CYGWIN_*) EXEEXT=".exe" # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG ;; *) CYGPATH=echo # Maybe we are cross-compiling.... case ${host_alias} in *mingw32*) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *) EXEEXT="" TEA_PLATFORM="unix" ;; esac ;; esac # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}" >&5 printf "%s\n" "$as_me: configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}" >&6;} # This package name must be replaced statically for AC_SUBST to work # Substitute STUB_LIB_FILE in case package creates a stub library too. # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... #-------------------------------------------------------------------- # specify some extra flags #-------------------------------------------------------------------- # According to http://www.gnu.org/software/autoconf/manual/autoconf.html # - "with" is for external software (optional packages) # - "enable" is for optional features # # Check whether --with-aolserver3 was given. if test ${with_aolserver3+y} then : withval=$with_aolserver3; with_aol3=$withval else $as_nop with_aol3=no fi # Check whether --with-dtrace was given. if test ${with_dtrace+y} then : withval=$with_dtrace; with_dtrace=$withval else $as_nop with_dtrace=no fi # Check whether --with-mongoc was given. if test ${with_mongoc+y} then : withval=$with_mongoc; with_mongoc=$withval else $as_nop with_mongoc=no fi # Check whether --with-bson was given. if test ${with_bson+y} then : withval=$with_bson; with_bson=$withval else $as_nop with_bson=no fi # Check whether --enable-profile was given. if test ${enable_profile+y} then : enableval=$enable_profile; enable_profile=$enableval else $as_nop enable_profile=no fi # Check whether --enable-memcount was given. if test ${enable_memcount+y} then : enableval=$enable_memcount; enable_memcount=$enableval else $as_nop enable_memcount=no fi # Check whether --enable-development was given. if test ${enable_development+y} then : enableval=$enable_development; enable_development=$enableval else $as_nop enable_development=no fi # Check whether --enable-assertions was given. if test ${enable_assertions+y} then : enableval=$enable_assertions; enable_assertions=$enableval else $as_nop enable_assertions=yes fi # Check whether --enable-assemble was given. if test ${enable_assemble+y} then : enableval=$enable_assemble; enable_assemble=$enableval else $as_nop enable_assemble=no fi subdirs="" if ! test "$with_mongoc" = no; then test_mongodb=test-mongdb subdirs="$subdirs ${srcdir}/library/mongodb" fi test_actiweb="" libdirs_actiweb="" apps_actiweb="" #-------------------------------------------------------------------- # __CHANGE__ # Set your package name and version numbers here. The NODOT_VERSION is # required for constructing the library name on systems that don't like # dots in library names (Windows). The VERSION variable is used on the # other systems. #-------------------------------------------------------------------- NSF_MAJOR_VERSION=2 NSF_MINOR_VERSION=4 NSF_PATCH_LEVEL=$PACKAGE_VERSION NSF_VERSION=${NSF_MAJOR_VERSION}.${NSF_MINOR_VERSION} NODOT_VERSION=${NSF_MAJOR_VERSION}${NSF_MINOR_VERSION} echo "Configuring NSF Version $PACKAGE_VERSION" # Extract the first word of "git", so it can be a program name with args. set dummy git; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_git_installed+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$git_installed"; then ac_cv_prog_git_installed="$git_installed" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_git_installed=""yes"" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_git_installed" && ac_cv_prog_git_installed=""no"" fi fi git_installed=$ac_cv_prog_git_installed if test -n "$git_installed"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $git_installed" >&5 printf "%s\n" "$git_installed" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "$git_installed" = "yes" -a -d ".git" ; then nsf_commit=`git describe --always --dirty` elif test -f "COMMIT" ; then nsf_commit=`cat COMMIT` else nsf_commit=unknown-${PACKAGE_VERSION} fi NSF_COMMIT=$nsf_commit # AC_DEFINE_UNQUOTED([NSF_COMMIT], "$nsf_commit", # [Commit ID at the time of the last configure run.]) ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "intptr_t" "ac_cv_type_intptr_t" "$ac_includes_default" if test "x$ac_cv_type_intptr_t" = xyes then : printf "%s\n" "#define HAVE_INTPTR_T 1" >>confdefs.h fi ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "$ac_includes_default" if test "x$ac_cv_type_uintptr_t" = xyes then : printf "%s\n" "#define HAVE_UINTPTR_T 1" >>confdefs.h fi #-------------------------------------------------------------------- # Load the tclConfig.sh file #-------------------------------------------------------------------- # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true # Check whether --with-tcl was given. if test ${with_tcl+y} then : withval=$with_tcl; with_tclconfig="${withval}" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Tcl configuration" >&5 printf %s "checking for Tcl configuration... " >&6; } if test ${ac_cv_c_tclconfig+y} then : printf %s "(cached) " >&6 else $as_nop # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case "${with_tclconfig}" in */tclConfig.sh ) if test -f "${with_tclconfig}"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&5 printf "%s\n" "$as_me: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&2;} with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" else as_fn_error $? "${with_tclconfig} directory doesn't contain tclConfig.sh" "$LINENO" 5 fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../tcl[8-9].[0-9]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../tcl[8-9].[0-9]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../../tcl[8-9].[0-9]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/pkg/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ `ls -d /usr/lib/tcl8.6 2>/dev/null` \ `ls -d /usr/lib/tcl8.5 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi fi if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" as_fn_error $? "Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh" "$LINENO" 5 else no_tcl= TCL_BIN_DIR="${ac_cv_c_tclconfig}" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found ${TCL_BIN_DIR}/tclConfig.sh" >&5 printf "%s\n" "found ${TCL_BIN_DIR}/tclConfig.sh" >&6; } fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for existence of ${TCL_BIN_DIR}/tclConfig.sh" >&5 printf %s "checking for existence of ${TCL_BIN_DIR}/tclConfig.sh... " >&6; } if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: loading" >&5 printf "%s\n" "loading" >&6; } . "${TCL_BIN_DIR}/tclConfig.sh" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: could not find ${TCL_BIN_DIR}/tclConfig.sh" >&5 printf "%s\n" "could not find ${TCL_BIN_DIR}/tclConfig.sh" >&6; } fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitrary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" break fi done fi if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking platform" >&5 printf %s "checking platform... " >&6; } hold_cc=$CC; CC="$TCL_CC" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifdef _WIN32 #error win32 #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : TEA_PLATFORM="unix" CYGPATH=echo else $as_nop TEA_PLATFORM="windows" # Extract the first word of "cygpath", so it can be a program name with args. set dummy cygpath; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CYGPATH+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CYGPATH"; then ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CYGPATH="cygpath -m" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo" fi fi CYGPATH=$ac_cv_prog_CYGPATH if test -n "$CYGPATH"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CYGPATH" >&5 printf "%s\n" "$CYGPATH" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CC=$hold_cc { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TEA_PLATFORM" >&5 printf "%s\n" "$TEA_PLATFORM" >&6; } # The BUILD_$pkg is to define the correct extern storage class # handling when making this package printf "%s\n" "#define BUILD_${PACKAGE_NAME} /**/" >>confdefs.h # Do this here as we have fully defined TEA_PLATFORM now if test "${TEA_PLATFORM}" = "windows" ; then EXEEXT=".exe" CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp" fi # TEA specific: ac_fn_c_check_func "$LINENO" "strnstr" "ac_cv_func_strnstr" if test "x$ac_cv_func_strnstr" = xyes then : printf "%s\n" "#define HAVE_STRNSTR 1" >>confdefs.h fi #-------------------------------------------------------------------- # check for TK #-------------------------------------------------------------------- #-------------------------------------------------------------------- # Handle the --prefix=... option by defaulting to what Tcl gave. # Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. #----------------------------------------------------------------------- if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&5 printf "%s\n" "$as_me: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&6;} prefix=${TCL_PREFIX} else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: --prefix defaulting to /usr/local" >&5 printf "%s\n" "$as_me: --prefix defaulting to /usr/local" >&6;} prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&5 printf "%s\n" "$as_me: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&6;} exec_prefix=${TCL_EXEC_PREFIX} else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: --exec-prefix defaulting to ${prefix}" >&5 printf "%s\n" "$as_me: --exec-prefix defaulting to ${prefix}" >&6;} exec_prefix=$prefix fi fi #----------------------------------------------------------------------- # Standard compiler checks. # This sets up CC by using the CC env var, or looks for gcc otherwise. # This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create # the basic setup necessary to compile executables. #----------------------------------------------------------------------- # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 printf %s "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test ${ac_cv_prog_CPP+y} then : printf %s "(cached) " >&6 else $as_nop # Double quotes because $CC needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 printf "%s\n" "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c' INSTALL_DATA_DIR='${INSTALL} -d -m 755' INSTALL_DATA='${INSTALL} -m 644' INSTALL_PROGRAM='${INSTALL}' INSTALL_SCRIPT='${INSTALL}' INSTALL_LIBRARY='${INSTALL_DATA}' #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 else $as_nop cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SET_MAKE= else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 printf "%s\n" "$RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 printf "%s\n" "$ac_ct_RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 printf %s "checking for grep that handles long lines and -e... " >&6; } if test ${ac_cv_path_GREP+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in grep ggrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 printf "%s\n" "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 printf %s "checking for egrep... " >&6; } if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in egrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the compiler understands -pipe" >&5 printf %s "checking if the compiler understands -pipe... " >&6; } if test ${tcl_cv_cc_pipe+y} then : printf %s "(cached) " >&6 else $as_nop hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_cc_pipe=yes else $as_nop tcl_cv_cc_pipe=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$hold_cflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_pipe" >&5 printf "%s\n" "$tcl_cv_cc_pipe" >&6; } if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 printf %s "checking whether byte ordering is bigendian... " >&6; } if test ${ac_cv_c_bigendian+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO" then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_bigendian=yes else $as_nop ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_bigendian=yes else $as_nop ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ unsigned short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; unsigned short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } unsigned short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; unsigned short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main (void) { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_c_bigendian=no else $as_nop ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 printf "%s\n" "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) printf "%s\n" "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac if test "${TEA_PLATFORM}" = "unix" ; then #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- ac_fn_c_check_func "$LINENO" "sin" "ac_cv_func_sin" if test "x$ac_cv_func_sin" = xyes then : MATH_LIBS="" else $as_nop MATH_LIBS="-lm" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -lieee" >&5 printf %s "checking for main in -lieee... " >&6; } if test ${ac_cv_lib_ieee_main+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lieee $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_ieee_main=yes else $as_nop ac_cv_lib_ieee_main=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee_main" >&5 printf "%s\n" "$ac_cv_lib_ieee_main" >&6; } if test "x$ac_cv_lib_ieee_main" = xyes then : MATH_LIBS="-lieee $MATH_LIBS" fi #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -linet" >&5 printf %s "checking for main in -linet... " >&6; } if test ${ac_cv_lib_inet_main+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-linet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_inet_main=yes else $as_nop ac_cv_lib_inet_main=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_main" >&5 printf "%s\n" "$ac_cv_lib_inet_main" >&6; } if test "x$ac_cv_lib_inet_main" = xyes then : LIBS="$LIBS -linet" fi ac_fn_c_check_header_compile "$LINENO" "net/errno.h" "ac_cv_header_net_errno_h" "$ac_includes_default" if test "x$ac_cv_header_net_errno_h" = xyes then : printf "%s\n" "#define HAVE_NET_ERRNO_H 1" >>confdefs.h fi #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = xyes then : tcl_checkSocket=0 else $as_nop tcl_checkSocket=1 fi if test "$tcl_checkSocket" = 1; then ac_fn_c_check_func "$LINENO" "setsockopt" "ac_cv_func_setsockopt" if test "x$ac_cv_func_setsockopt" = xyes then : else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for setsockopt in -lsocket" >&5 printf %s "checking for setsockopt in -lsocket... " >&6; } if test ${ac_cv_lib_socket_setsockopt+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char setsockopt (); int main (void) { return setsockopt (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_socket_setsockopt=yes else $as_nop ac_cv_lib_socket_setsockopt=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_setsockopt" >&5 printf "%s\n" "$ac_cv_lib_socket_setsockopt" >&6; } if test "x$ac_cv_lib_socket_setsockopt" = xyes then : LIBS="$LIBS -lsocket" else $as_nop tcl_checkBoth=1 fi fi fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" ac_fn_c_check_func "$LINENO" "accept" "ac_cv_func_accept" if test "x$ac_cv_func_accept" = xyes then : tcl_checkNsl=0 else $as_nop LIBS=$tk_oldLibs fi fi ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" if test "x$ac_cv_func_gethostbyname" = xyes then : else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 printf %s "checking for gethostbyname in -lnsl... " >&6; } if test ${ac_cv_lib_nsl_gethostbyname+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char gethostbyname (); int main (void) { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_nsl_gethostbyname=yes else $as_nop ac_cv_lib_nsl_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 printf "%s\n" "$ac_cv_lib_nsl_gethostbyname" >&6; } if test "x$ac_cv_lib_nsl_gethostbyname" = xyes then : LIBS="$LIBS -lnsl" fi fi # TEA specific: Don't perform the eval of the libraries here because # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dirent.h" >&5 printf %s "checking dirent.h... " >&6; } if test ${tcl_cv_dirent_h+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_dirent_h=yes else $as_nop tcl_cv_dirent_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_dirent_h" >&5 printf "%s\n" "$tcl_cv_dirent_h" >&6; } if test $tcl_cv_dirent_h = no; then printf "%s\n" "#define NO_DIRENT_H 1" >>confdefs.h fi # TEA specific: ac_fn_c_check_header_compile "$LINENO" "errno.h" "ac_cv_header_errno_h" "$ac_includes_default" if test "x$ac_cv_header_errno_h" = xyes then : else $as_nop printf "%s\n" "#define NO_ERRNO_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "float.h" "ac_cv_header_float_h" "$ac_includes_default" if test "x$ac_cv_header_float_h" = xyes then : else $as_nop printf "%s\n" "#define NO_FLOAT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "values.h" "ac_cv_header_values_h" "$ac_includes_default" if test "x$ac_cv_header_values_h" = xyes then : else $as_nop printf "%s\n" "#define NO_VALUES_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default" if test "x$ac_cv_header_limits_h" = xyes then : printf "%s\n" "#define HAVE_LIMITS_H 1" >>confdefs.h else $as_nop printf "%s\n" "#define NO_LIMITS_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes then : tcl_ok=1 else $as_nop tcl_ok=0 fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtol" >/dev/null 2>&1 then : else $as_nop tcl_ok=0 fi rm -rf conftest* cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtoul" >/dev/null 2>&1 then : else $as_nop tcl_ok=0 fi rm -rf conftest* cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtod" >/dev/null 2>&1 then : else $as_nop tcl_ok=0 fi rm -rf conftest* if test $tcl_ok = 0; then printf "%s\n" "#define NO_STDLIB_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default" if test "x$ac_cv_header_string_h" = xyes then : tcl_ok=1 else $as_nop tcl_ok=0 fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strstr" >/dev/null 2>&1 then : else $as_nop tcl_ok=0 fi rm -rf conftest* cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strerror" >/dev/null 2>&1 then : else $as_nop tcl_ok=0 fi rm -rf conftest* # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then printf "%s\n" "#define NO_STRING_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/wait.h" "ac_cv_header_sys_wait_h" "$ac_includes_default" if test "x$ac_cv_header_sys_wait_h" = xyes then : else $as_nop printf "%s\n" "#define NO_SYS_WAIT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" if test "x$ac_cv_header_dlfcn_h" = xyes then : else $as_nop printf "%s\n" "#define NO_DLFCN_H 1" >>confdefs.h fi # OS/390 lacks sys/param.h (and doesn't need it, by chance). ac_fn_c_check_header_compile "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" if test "x$ac_cv_header_sys_param_h" = xyes then : printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h fi # Let the user call this, because if it triggers, they will # need a compat/strtod.c that is correct. Users can also # use Tcl_GetDouble(FromObj) instead. #TEA_BUGGY_STRTOD fi #-------------------------------------------------------------------- # check for extra flags # # FORCE_NO_STUBS is deactivated for now if ! test "$with_aol3" = "no"; then echo "Pre-configuring AOL-Server (nsf)" AOL_DEFINES="-DAOL_SERVER -DUSE_TCL8X -I$with_aol3/include -I$TCL_SRC_DIR/generic" FORCE_NO_STUBS=1 else AOL_DEFINES="" FORCE_NO_STUBS=0 fi # set the default aol_prefix aol_prefix="/usr/local/aolserver" # if we have under ${prefix} either modules/tcl/init.tcl (aolserver # style) or modules/tcl/init.tcl (naviserver style), then use # ${prefix} as aol_prefix (path for the installation of # aolserver/naviserver specific tcl files). if test -f "${prefix}/modules/tcl/init.tcl" ; then aol_prefix="${prefix}" else if test -f "${prefix}/tcl/init.tcl" ; then aol_prefix="${prefix}" fi fi #-------------------------------------------------------------------- # check for tclCompile.h (needed, when compiled without full source) if test -f "$TCL_SRC_DIR/generic/tclCompile.h"; then printf "%s\n" "#define HAVE_TCL_COMPILE_H 1" >>confdefs.h fi if test "$enable_assertions" = yes; then printf "%s\n" "#define NSF_WITH_ASSERTIONS 1" >>confdefs.h fi if test "$enable_profile" = yes; then printf "%s\n" "#define NSF_PROFILE 1" >>confdefs.h fi if test "$enable_development" = yes; then printf "%s\n" "#define NSF_DEVELOPMENT 1" >>confdefs.h fi if test "$enable_development" = test; then printf "%s\n" "#define NSF_DEVELOPMENT_TEST 1" >>confdefs.h fi if test "$enable_memcount" = yes; then printf "%s\n" "#define NSF_MEM_COUNT 1" >>confdefs.h fi if test "$enable_memcount" = trace; then printf "%s\n" "#define NSF_MEM_TRACE 1" >>confdefs.h fi if test "$enable_assemble" = yes; then printf "%s\n" "#define NSF_ASSEMBLE 1" >>confdefs.h fi if test "$enable_assemble" = call; then printf "%s\n" "#define NSF_ASSEMBLE_CT 1" >>confdefs.h fi if test "$enable_assemble" = call; then printf "%s\n" "#define NSF_ASSEMBLE_LT 1" >>confdefs.h fi DTRACE_OBJ= if test "$with_dtrace" = yes; then printf "%s\n" "#define NSF_DTRACE 1" >>confdefs.h # Under macOS, we need no nsfDTrace.o if test "`uname -s`" != "Darwin" ; then DTRACE_OBJ=nsfDTrace.o fi DTRACE_HDR='$(src_generic_dir)/nsfDTrace.h' DTRACE_SRC='$(src_generic_dir)/nsfDTrace.d' fi #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, # public headers that need to be installed in TEA_ADD_HEADERS, # stub library C source files to compile in TEA_ADD_STUB_SOURCES, # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- stubdir=stubs${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION} vars="nsf.c nsfError.c nsfObjectData.c nsfProfile.c \ nsfDebug.c nsfUtil.c nsfObj.c nsfPointer.c nsfEnumerationType.c \ nsfCmdDefinitions.c nsfFunPtrHashTable.c nsfShadow.c nsfCompile.c aolstub.c \${srcdir}/generic/${stubdir}/nsfStubInit.${OBJEXT}" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then as_fn_error $? "could not find source file '$i'" "$LINENO" 5 fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="generic/nsf.h generic/nsfInt.h generic/${stubdir}/nsfDecls.h generic/${stubdir}/nsfIntDecls.h" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then as_fn_error $? "could not find header file '${srcdir}/$i'" "$LINENO" 5 fi PKG_HEADERS="$PKG_HEADERS $i" done vars="" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done vars="" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done PKG_CFLAGS="$PKG_CFLAGS -DNSF_VERSION=\\\"$NSF_VERSION\\\" -DNSF_PATCHLEVEL=\\\"$NSF_PATCH_LEVEL\\\" \ -DNSF_COMMIT=\\\"$NSF_COMMIT\\\" $AOL_DEFINES " vars="nsfStubLib.c" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then as_fn_error $? "could not find stub source file '$i'" "$LINENO" 5 fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done vars="" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then as_fn_error $? "could not find tcl source file '${srcdir}/$i'" "$LINENO" 5 fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done #-------------------------------------------------------------------- # __CHANGE__ # # You can add more files to clean if your extension creates any extra # files by extending CLEANFILES. # Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure # and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var. # # A few miscellaneous platform-specific items: # TEA_ADD_* any platform specific compiler/build info here. #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then if test "$GCC" != "yes" ; then printf "%s\n" "#define VISUAL_CC 1" >>confdefs.h fi CLEANFILES="*.lib *.dll *.exp *.ilk *.pdb vc50.pch vc60.pch " #TEA_ADD_SOURCES([win/winFile.c]) #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"]) else CLEANFILES="*.a *.so *~ core gmon.out" #TEA_ADD_SOURCES([unix/unixFile.c]) #TEA_ADD_LIBS([-lsuperfly]) fi CLEANFILES="$CLEANFILES *.${OBJEXT} pkgIndex.tcl" #-------------------------------------------------------------------- # __CHANGE__ # Choose which headers you need. Extension authors should try very # hard to only rely on the Tcl public header files. Internal headers # contain private data structures and are subject to change without # notice. # This must be done AFTER calling TEA_PATH_TCLCONFIG/TEA_LOAD_TCLCONFIG # so that we can extract TCL_SRC_DIR from the config file (in the case # of private headers #-------------------------------------------------------------------- #TEA_PUBLIC_TCL_HEADERS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Tcl public headers" >&5 printf %s "checking for Tcl public headers... " >&6; } # Check whether --with-tclinclude was given. if test ${with_tclinclude+y} then : withval=$with_tclinclude; with_tclinclude=${withval} fi if test ${ac_cv_c_tclh+y} then : printf %s "(cached) " >&6 else $as_nop # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else as_fn_error $? "${with_tclinclude} directory does not contain tcl.h" "$LINENO" 5 fi else list="" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi fi # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then as_fn_error $? "tcl.h not found. Please specify its location with --with-tclinclude" "$LINENO" 5 else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${ac_cv_c_tclh}" >&5 printf "%s\n" "${ac_cv_c_tclh}" >&6; } fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Tcl private include files" >&5 printf %s "checking for Tcl private include files... " >&6; } TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" # Check to see if tclPort.h isn't already with the public headers # Don't look for tclInt.h because that resides with tcl.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tclh}/tclWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tclh}/tclUnixPort.h"; then result="private headers found with public headers" else TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" if test "${TEA_PLATFORM}" = "windows"; then TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" else TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TCL_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -d "${TCL_BIN_DIR}/Headers" -a \ -d "${TCL_BIN_DIR}/PrivateHeaders"; then TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" else TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TCL_INCLUDES}" else if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then as_fn_error $? "Cannot find private header tclInt.h in ${TCL_SRC_DIR}" "$LINENO" 5 fi result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${result}" >&5 printf "%s\n" "${result}" >&6; } #TEA_PUBLIC_TK_HEADERS #TEA_PRIVATE_TK_HEADERS #TEA_PATH_X #-------------------------------------------------------------------- # Check whether --enable-threads or --disable-threads was given. #-------------------------------------------------------------------- # Check whether --enable-threads was given. if test ${enable_threads+y} then : enableval=$enable_threads; tcl_ok=$enableval else $as_nop tcl_ok=yes fi if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention printf "%s\n" "#define USE_THREAD_ALLOC 1" >>confdefs.h printf "%s\n" "#define _REENTRANT 1" >>confdefs.h if test "`uname -s`" = "SunOS" ; then printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h fi printf "%s\n" "#define _THREAD_SAFE 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthread" >&5 printf %s "checking for pthread_mutex_init in -lpthread... " >&6; } if test ${ac_cv_lib_pthread_pthread_mutex_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char pthread_mutex_init (); int main (void) { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_pthread_pthread_mutex_init=yes else $as_nop ac_cv_lib_pthread_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_init" >&5 printf "%s\n" "$ac_cv_lib_pthread_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthread_pthread_mutex_init" = xyes then : tcl_ok=yes else $as_nop tcl_ok=no fi if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __pthread_mutex_init in -lpthread" >&5 printf %s "checking for __pthread_mutex_init in -lpthread... " >&6; } if test ${ac_cv_lib_pthread___pthread_mutex_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char __pthread_mutex_init (); int main (void) { return __pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_pthread___pthread_mutex_init=yes else $as_nop ac_cv_lib_pthread___pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_mutex_init" >&5 printf "%s\n" "$ac_cv_lib_pthread___pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthread___pthread_mutex_init" = xyes then : tcl_ok=yes else $as_nop tcl_ok=no fi fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthreads" >&5 printf %s "checking for pthread_mutex_init in -lpthreads... " >&6; } if test ${ac_cv_lib_pthreads_pthread_mutex_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpthreads $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char pthread_mutex_init (); int main (void) { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_pthreads_pthread_mutex_init=yes else $as_nop ac_cv_lib_pthreads_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_mutex_init" >&5 printf "%s\n" "$ac_cv_lib_pthreads_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthreads_pthread_mutex_init" = xyes then : tcl_ok=yes else $as_nop tcl_ok=no fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc" >&5 printf %s "checking for pthread_mutex_init in -lc... " >&6; } if test ${ac_cv_lib_c_pthread_mutex_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char pthread_mutex_init (); int main (void) { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_c_pthread_mutex_init=yes else $as_nop ac_cv_lib_c_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_pthread_mutex_init" >&5 printf "%s\n" "$ac_cv_lib_c_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_c_pthread_mutex_init" = xyes then : tcl_ok=yes else $as_nop tcl_ok=no fi if test "$tcl_ok" = "no"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc_r" >&5 printf %s "checking for pthread_mutex_init in -lc_r... " >&6; } if test ${ac_cv_lib_c_r_pthread_mutex_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char pthread_mutex_init (); int main (void) { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_c_r_pthread_mutex_init=yes else $as_nop ac_cv_lib_c_r_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_mutex_init" >&5 printf "%s\n" "$ac_cv_lib_c_r_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_c_r_pthread_mutex_init" = xyes then : tcl_ok=yes else $as_nop tcl_ok=no fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&5 printf "%s\n" "$as_me: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&2;} fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for building with threads" >&5 printf %s "checking for building with threads... " >&6; } if test "${TCL_THREADS}" = 1; then printf "%s\n" "#define TCL_THREADS 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (default)" >&5 printf "%s\n" "yes (default)" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads." >&5 printf "%s\n" "$as_me: WARNING: Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads." >&2;} fi ;; *) if test "${TCL_THREADS}" = "1"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core." >&5 printf "%s\n" "$as_me: WARNING: --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core." >&2;} fi ;; esac #-------------------------------------------------------------------- # The statement below defines a collection of symbols related to # building as a shared library instead of a static library. #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to build libraries" >&5 printf %s "checking how to build libraries... " >&6; } # Check whether --enable-shared was given. if test ${enable_shared+y} then : enableval=$enable_shared; shared_ok=$enableval else $as_nop shared_ok=yes fi if test "${enable_shared+set}" = set; then enableval="$enable_shared" shared_ok=$enableval else shared_ok=yes fi # Check whether --enable-stubs was given. if test ${enable_stubs+y} then : enableval=$enable_stubs; stubs_ok=$enableval else $as_nop stubs_ok=yes fi if test "${enable_stubs+set}" = set; then enableval="$enable_stubs" stubs_ok=$enableval else stubs_ok=yes fi # Stubs are always enabled for shared builds if test "$shared_ok" = "yes" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: shared" >&5 printf "%s\n" "shared" >&6; } SHARED_BUILD=1 STUBS_BUILD=1 else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: static" >&5 printf "%s\n" "static" >&6; } SHARED_BUILD=0 printf "%s\n" "#define STATIC_BUILD 1" >>confdefs.h if test "$stubs_ok" = "yes" ; then STUBS_BUILD=1 else STUBS_BUILD=0 fi fi if test "${STUBS_BUILD}" = "1" ; then printf "%s\n" "#define USE_TCL_STUBS 1" >>confdefs.h printf "%s\n" "#define USE_TCLOO_STUBS 1" >>confdefs.h if test "${TEA_WINDOWINGSYSTEM}" != ""; then printf "%s\n" "#define USE_TK_STUBS 1" >>confdefs.h fi fi #-------------------------------------------------------------------- # This macro figures out what flags to use with the compiler/linker # when building shared/static debug/optimized objects. This information # can be taken from the tclConfig.sh file, but this figures it all out. #-------------------------------------------------------------------- if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 printf "%s\n" "$RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 printf "%s\n" "$ac_ct_RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi # Step 0.a: Enable 64 bit support? { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if 64bit support is requested" >&5 printf %s "checking if 64bit support is requested... " >&6; } # Check whether --enable-64bit was given. if test ${enable_64bit+y} then : enableval=$enable_64bit; do64bit=$enableval else $as_nop do64bit=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $do64bit" >&5 printf "%s\n" "$do64bit" >&6; } # Step 0.b: Enable Solaris 64 bit VIS support? { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if 64bit Sparc VIS support is requested" >&5 printf %s "checking if 64bit Sparc VIS support is requested... " >&6; } # Check whether --enable-64bit-vis was given. if test ${enable_64bit_vis+y} then : enableval=$enable_64bit_vis; do64bitVIS=$enableval else $as_nop do64bitVIS=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $do64bitVIS" >&5 printf "%s\n" "$do64bitVIS" >&6; } # Force 64bit on with VIS if test "$do64bitVIS" = "yes" then : do64bit=yes fi # Step 0.c: Check if visibility support is available. Do this here so # that platform specific alternatives can be used below if this fails. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler supports visibility \"hidden\"" >&5 printf %s "checking if compiler supports visibility \"hidden\"... " >&6; } if test ${tcl_cv_cc_visibility_hidden+y} then : printf %s "(cached) " >&6 else $as_nop hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ extern __attribute__((__visibility__("hidden"))) void f(void); void f(void) {} int main (void) { f(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_cc_visibility_hidden=yes else $as_nop tcl_cv_cc_visibility_hidden=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_visibility_hidden" >&5 printf "%s\n" "$tcl_cv_cc_visibility_hidden" >&6; } if test $tcl_cv_cc_visibility_hidden = yes then : printf "%s\n" "#define MODULE_SCOPE extern __attribute__((__visibility__(\"hidden\")))" >>confdefs.h printf "%s\n" "#define HAVE_HIDDEN 1" >>confdefs.h fi # Step 0.d: Disable -rpath support? { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if rpath support is requested" >&5 printf %s "checking if rpath support is requested... " >&6; } # Check whether --enable-rpath was given. if test ${enable_rpath+y} then : enableval=$enable_rpath; doRpath=$enableval else $as_nop doRpath=yes fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $doRpath" >&5 printf "%s\n" "$doRpath" >&6; } # TEA specific: Cross-compiling options for Windows/CE builds? if test "${TEA_PLATFORM}" = windows then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if Windows/CE build is requested" >&5 printf %s "checking if Windows/CE build is requested... " >&6; } # Check whether --enable-wince was given. if test ${enable_wince+y} then : enableval=$enable_wince; doWince=$enableval else $as_nop doWince=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $doWince" >&5 printf "%s\n" "$doWince" >&6; } fi # Set the variable "system" to hold the name and version number # for the system. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking system version" >&5 printf %s "checking system version... " >&6; } if test ${tcl_cv_sys_version+y} then : printf %s "(cached) " >&6 else $as_nop # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: can't find uname command" >&5 printf "%s\n" "$as_me: WARNING: can't find uname command" >&2;} tcl_cv_sys_version=unknown else if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_sys_version" >&5 printf "%s\n" "$tcl_cv_sys_version" >&6; } system=$tcl_cv_sys_version # Require ranlib early so we can override it in special cases below. # Set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case and removed some core-only vars. do64bit_ok=no # default to '{$LIBS}' and set to "" on per-platform necessary basis SHLIB_LD_LIBS='${LIBS}' # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" UNSHARED_LIB_SUFFIX="" # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g if test "$GCC" = yes then : CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall" else $as_nop CFLAGS_OPTIMIZE=-O CFLAGS_WARNING="" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 printf "%s\n" "$AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 printf "%s\n" "$ac_ct_AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" if test "x$SHLIB_VERSION" = x then : SHLIB_VERSION="" else $as_nop SHLIB_VERSION=".$SHLIB_VERSION" fi case $system in # TEA specific: windows) # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test "$GCC" != "yes" -a ! -d "${PATH64}" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&5 printf "%s\n" "$as_me: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Ensure latest Platform SDK is installed" >&5 printf "%s\n" "$as_me: WARNING: Ensure latest Platform SDK is installed" >&2;} do64bit="no" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using 64-bit $MACHINE mode" >&5 printf "%s\n" " Using 64-bit $MACHINE mode" >&6; } do64bit_ok="yes" fi fi if test "$doWince" != "no" ; then if test "$do64bit" != "no" ; then as_fn_error $? "Windows/CE and 64-bit builds incompatible" "$LINENO" 5 fi if test "$GCC" = "yes" ; then as_fn_error $? "Windows/CE and GCC builds incompatible" "$LINENO" 5 fi # First, look for one uninstalled. # the alternative search directory is invoked by --with-celib if test x"${no_celib}" = x ; then # we reset no_celib in case something fails here no_celib=true # Check whether --with-celib was given. if test ${with_celib+y} then : withval=$with_celib; with_celibconfig=${withval} fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Windows/CE celib directory" >&5 printf %s "checking for Windows/CE celib directory... " >&6; } if test ${ac_cv_c_celibconfig+y} then : printf %s "(cached) " >&6 else $as_nop # First check to see if --with-celibconfig was specified. if test x"${with_celibconfig}" != x ; then if test -d "${with_celibconfig}/inc" ; then ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` else as_fn_error $? "${with_celibconfig} directory doesn't contain inc directory" "$LINENO" 5 fi fi # then check for a celib library if test x"${ac_cv_c_celibconfig}" = x ; then for i in \ ../celib-palm-3.0 \ ../celib \ ../../celib-palm-3.0 \ ../../celib \ `ls -dr ../celib-*3.[0-9]* 2>/dev/null` \ ${srcdir}/../celib-palm-3.0 \ ${srcdir}/../celib \ `ls -dr ${srcdir}/../celib-*3.[0-9]* 2>/dev/null` \ ; do if test -d "$i/inc" ; then ac_cv_c_celibconfig=`(cd $i; pwd)` break fi done fi fi if test x"${ac_cv_c_celibconfig}" = x ; then as_fn_error $? "Cannot find celib support library directory" "$LINENO" 5 else no_celib= CELIB_DIR=${ac_cv_c_celibconfig} CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found $CELIB_DIR" >&5 printf "%s\n" "found $CELIB_DIR" >&6; } fi fi # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F, '{ \ if (length($1)) { printf "CEVERSION=\"%s\"\n", $1; \ if ($1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length($2)) { printf "TARGETCPU=\"%s\"\n", toupper($2) }; \ if (length($3)) { printf "ARCH=\"%s\"\n", toupper($3) }; \ if (length($4)) { printf "PLATFORM=\"%s\"\n", $4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then as_fn_error $? "could not find PocketPC SDK or target compiler to enable WinCE mode $CEVERSION,$TARGETCPU,$ARCH,$PLATFORM" "$LINENO" 5 doWince="no" else # We could PATH_NOSPACE these, but that's not important, # as long as we quote them when used. CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi case "x`echo \${VisualStudioVersion}`" in x1[4-9]*) lflags="${lflags} -nodefaultlib:libucrt.lib" vars="ucrt.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done ;; *) ;; esac if test "$do64bit" != "no" ; then # All this magic is necessary for the Win64 SDK RC1 - hobbs CC="\"${PATH64}/cl.exe\"" CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" lflags="${lflags} -nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 vars="bufferoverflowU.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done elif test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="\"${CEBINROOT}/cl.exe\"" else CC="\"${CEBINROOT}/cl${ARCH}.exe\"" fi CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower($0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" if test "${SHARED_BUILD}" = "1" ; then # Static CE builds require static celib as well defs="${defs} _DLL" fi for i in $defs ; do printf "%s\n" "#define $i 1" >>confdefs.h done printf "%s\n" "#define _WIN32_WCE $CEVERSION" >>confdefs.h printf "%s\n" "#define UNDER_CE $CEVERSION" >>confdefs.h CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -Ox" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="${lflags} -MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" else RC="rc" lflags="${lflags} -nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args. set dummy ${ac_tool_prefix}windres; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$RC"; then ac_cv_prog_RC="$RC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_RC="${ac_tool_prefix}windres" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RC=$ac_cv_prog_RC if test -n "$RC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RC" >&5 printf "%s\n" "$RC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_RC"; then ac_ct_RC=$RC # Extract the first word of "windres", so it can be a program name with args. set dummy windres; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_RC"; then ac_cv_prog_ac_ct_RC="$ac_ct_RC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RC="windres" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RC=$ac_cv_prog_ac_ct_RC if test -n "$ac_ct_RC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RC" >&5 printf "%s\n" "$ac_ct_RC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RC" = x; then RC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RC=$ac_ct_RC fi else RC="$ac_cv_prog_RC" fi CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD='${CC} -shared' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' PRACTCL_UNSHARED_LIB_SUFFIX='.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cross-compile version of gcc" >&5 printf %s "checking for cross-compile version of gcc... " >&6; } if test ${ac_cv_cross+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef _WIN32 #error cross-compiler #endif int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_cross=yes else $as_nop ac_cv_cross=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cross" >&5 printf "%s\n" "$ac_cv_cross" >&6; } if test "$ac_cv_cross" = "yes"; then case "$do64bit" in amd64|x64|yes) CC="x86_64-w64-mingw32-gcc" LD="x86_64-w64-mingw32-ld" AR="x86_64-w64-mingw32-ar" RANLIB="x86_64-w64-mingw32-ranlib" RC="x86_64-w64-mingw32-windres" ;; *) CC="i686-w64-mingw32-gcc" LD="i686-w64-mingw32-ld" AR="i686-w64-mingw32-ar" RANLIB="i686-w64-mingw32-ranlib" RC="i686-w64-mingw32-windres" ;; esac fi else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" if test "$doWince" != "no" ; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots ;; AIX-*) if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes" then : # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r|*_r\ *) # ok ... ;; *) # Make sure only first arg gets _r CC=`echo "$CC" | sed -e 's/^\([^ ]*\)/\1_r/'` ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using $CC for compiling with threads" >&5 printf "%s\n" "Using $CC for compiling with threads" >&6; } fi LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_SUFFIX=".so" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = yes then : if test "$GCC" = yes then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 printf "%s\n" "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;} else $as_nop do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" fi fi if test "`uname -m`" = ia64 then : # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" if test "$GCC" = yes then : CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' else $as_nop CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' else $as_nop if test "$GCC" = yes then : SHLIB_LD='${CC} -shared -Wl,-bexpall' else $as_nop SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" LDFLAGS="$LDFLAGS -brtl" fi SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_SUFFIX=".so" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lbind" >&5 printf %s "checking for inet_ntoa in -lbind... " >&6; } if test ${ac_cv_lib_bind_inet_ntoa+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lbind $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char inet_ntoa (); int main (void) { return inet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_bind_inet_ntoa=yes else $as_nop ac_cv_lib_bind_inet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bind_inet_ntoa" >&5 printf "%s\n" "$ac_cv_lib_bind_inet_ntoa" >&6; } if test "x$ac_cv_lib_bind_inet_ntoa" = xyes then : LIBS="$LIBS -lbind -lsocket" fi ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; CYGWIN_*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$@.a" SHLIB_SUFFIX=".dll" EXEEXT=".exe" do64bit_ok=yes CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lnetwork" >&5 printf %s "checking for inet_ntoa in -lnetwork... " >&6; } if test ${ac_cv_lib_network_inet_ntoa+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnetwork $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char inet_ntoa (); int main (void) { return inet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_network_inet_ntoa=yes else $as_nop ac_cv_lib_network_inet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_inet_ntoa" >&5 printf "%s\n" "$ac_cv_lib_network_inet_ntoa" >&6; } if test "x$ac_cv_lib_network_inet_ntoa" = xyes then : LIBS="$LIBS -lnetwork" fi ;; HP-UX-*.11.*) # Use updated header definitions where possible printf "%s\n" "#define _XOPEN_SOURCE_EXTENDED 1" >>confdefs.h # TEA specific: Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library if test "`uname -m`" = ia64 then : SHLIB_SUFFIX=".so" # Use newer C++ library for C++ extensions #if test "$GCC" != "yes" ; then # CPPFLAGS="-AA" #fi else $as_nop SHLIB_SUFFIX=".sl" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 printf %s "checking for shl_load in -ldld... " >&6; } if test ${ac_cv_lib_dld_shl_load+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char shl_load (); int main (void) { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_shl_load=yes else $as_nop ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 printf "%s\n" "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes then : tcl_ok=yes else $as_nop tcl_ok=no fi if test "$tcl_ok" = yes then : LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" fi if test "$GCC" = yes then : SHLIB_LD='${CC} -shared' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} else $as_nop CFLAGS="$CFLAGS -z" # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" fi # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes" then : if test "$GCC" = yes then : case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 printf "%s\n" "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;} ;; esac else $as_nop do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" fi fi ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "$GCC" = yes then : CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" else $as_nop case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" fi ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = yes then : if test "$GCC" = yes then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported by gcc" >&5 printf "%s\n" "$as_me: WARNING: 64bit mode not supported by gcc" >&2;} else $as_nop do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" fi fi ;; Linux*|GNU*|NetBSD-Debian) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "`uname -m`" = "alpha" then : CFLAGS="$CFLAGS -mieee" fi if test $do64bit = yes then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -m64 flag" >&5 printf %s "checking if compiler accepts -m64 flag... " >&6; } if test ${tcl_cv_cc_m64+y} then : printf %s "(cached) " >&6 else $as_nop hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_cc_m64=yes else $as_nop tcl_cv_cc_m64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_m64" >&5 printf "%s\n" "$tcl_cv_cc_m64" >&6; } if test $tcl_cv_cc_m64 = yes then : CFLAGS="$CFLAGS -m64" do64bit_ok=yes fi fi # The combo of gcc + glibc has a bug related to inlining of # functions like strtod(). The -fno-builtin flag should address # this problem but it does not work. The -fno-inline flag is kind # of overkill but it works. Disable inlining only when one of the # files in compat/*.c is being linked in. if test x"${USE_COMPAT}" != x then : CFLAGS="$CFLAGS -fno-inline" fi ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' LD_FLAGS="-Wl,--export-dynamic" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi ;; OpenBSD-*) arch=`arch -s` case "$arch" in vax) SHLIB_SUFFIX="" SHARED_LIB_SUFFIX="" LDFLAGS="" ;; *) case "$arch" in alpha|sparc64) SHLIB_CFLAGS="-fPIC" ;; *) SHLIB_CFLAGS="-fpic" ;; esac SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}' LDFLAGS="-Wl,-export-dynamic" ;; esac case "$arch" in vax) CFLAGS_OPTIMIZE="-O1" ;; *) CFLAGS_OPTIMIZE="-O2" ;; esac if test "${TCL_THREADS}" = "1" then : # On OpenBSD: Compile with -pthread # Don't link with -lpthread LIBS=`echo $LIBS | sed s/-lpthread//` CFLAGS="$CFLAGS -pthread" fi # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*) # NetBSD has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "${TCL_THREADS}" = "1" then : # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi ;; FreeBSD-*) # This configuration from FreeBSD Ports. SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,-soname,\$@" SHLIB_SUFFIX=".so" LDFLAGS="" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi if test "${TCL_THREADS}" = "1" then : # The -pthread needs to go in the LDFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LDFLAGS="$LDFLAGS $PTHREAD_LIBS" fi case $system in FreeBSD-3.*) # Version numbers are dot-stripped by system policy. TCL_TRIM_DOTS=`echo ${PACKAGE_VERSION} | tr -d .` UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ($i~/^(isysroot|mmacosx-version-min)/) print "-"$i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!($i~/^(isysroot|mmacosx-version-min)/)) print "-"$i}'`" if test $do64bit = yes then : case `arch` in ppc) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch ppc64 flag" >&5 printf %s "checking if compiler accepts -arch ppc64 flag... " >&6; } if test ${tcl_cv_cc_arch_ppc64+y} then : printf %s "(cached) " >&6 else $as_nop hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_cc_arch_ppc64=yes else $as_nop tcl_cv_cc_arch_ppc64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_arch_ppc64" >&5 printf "%s\n" "$tcl_cv_cc_arch_ppc64" >&6; } if test $tcl_cv_cc_arch_ppc64 = yes then : CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes fi;; i386) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch x86_64 flag" >&5 printf %s "checking if compiler accepts -arch x86_64 flag... " >&6; } if test ${tcl_cv_cc_arch_x86_64+y} then : printf %s "(cached) " >&6 else $as_nop hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_cc_arch_x86_64=yes else $as_nop tcl_cv_cc_arch_x86_64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_arch_x86_64" >&5 printf "%s\n" "$tcl_cv_cc_arch_x86_64" >&6; } if test $tcl_cv_cc_arch_x86_64 = yes then : CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes fi;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Don't know how enable 64-bit on architecture \`arch\`" >&5 printf "%s\n" "$as_me: WARNING: Don't know how enable 64-bit on architecture \`arch\`" >&2;};; esac else $as_nop # Check for combined 32-bit and 64-bit fat build if echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) ' then : fat_32_64=yes fi fi # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ld accepts -single_module flag" >&5 printf %s "checking if ld accepts -single_module flag... " >&6; } if test ${tcl_cv_ld_single_module+y} then : printf %s "(cached) " >&6 else $as_nop hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { int i; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_ld_single_module=yes else $as_nop tcl_cv_ld_single_module=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_single_module" >&5 printf "%s\n" "$tcl_cv_ld_single_module" >&6; } if test $tcl_cv_ld_single_module = yes then : SHLIB_LD="${SHLIB_LD} -Wl,-single_module" fi # TEA specific: link shlib with current and compatibility version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([0-9]\{1,5\}\)\(\(\.[0-9]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" SHLIB_SUFFIX=".dylib" # Don't use -prebind when building for Mac OS X 10.4 or later only: if test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int($2)}'`" -lt 4 -a \ "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int($2)}'`" -lt 4 then : LDFLAGS="$LDFLAGS -prebind" fi LDFLAGS="$LDFLAGS -headerpad_max_install_names" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ld accepts -search_paths_first flag" >&5 printf %s "checking if ld accepts -search_paths_first flag... " >&6; } if test ${tcl_cv_ld_search_paths_first+y} then : printf %s "(cached) " >&6 else $as_nop hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { int i; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_ld_search_paths_first=yes else $as_nop tcl_cv_ld_search_paths_first=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_search_paths_first" >&5 printf "%s\n" "$tcl_cv_ld_search_paths_first" >&6; } if test $tcl_cv_ld_search_paths_first = yes then : LDFLAGS="$LDFLAGS -Wl,-search_paths_first" fi if test "$tcl_cv_cc_visibility_hidden" != yes then : printf "%s\n" "#define MODULE_SCOPE __private_extern__" >>confdefs.h tcl_cv_cc_visibility_hidden=yes fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for combined 32 & 64 bit fat builds of Tk # extensions, verify that 64-bit build is possible. if test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}" then : if test "${TEA_WINDOWINGSYSTEM}" = x11 then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit X11" >&5 printf %s "checking for 64-bit X11... " >&6; } if test ${tcl_cv_lib_x11_64+y} then : printf %s "(cached) " >&6 else $as_nop for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { XrmInitialize(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_lib_x11_64=yes else $as_nop tcl_cv_lib_x11_64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_lib_x11_64" >&5 printf "%s\n" "$tcl_cv_lib_x11_64" >&6; } fi if test "${TEA_WINDOWINGSYSTEM}" = aqua then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit Tk" >&5 printf %s "checking for 64-bit Tk... " >&6; } if test ${tcl_cv_lib_tk_64+y} then : printf %s "(cached) " >&6 else $as_nop for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { Tk_InitStubs(NULL, "", 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_lib_tk_64=yes else $as_nop tcl_cv_lib_tk_64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_lib_tk_64" >&5 printf "%s\n" "$tcl_cv_lib_tk_64" >&6; } fi # remove 64-bit arch flags from CFLAGS et al. if configuration # does not support 64-bit. if test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Removing 64-bit architectures from compiler & linker flags" >&5 printf "%s\n" "$as_me: Removing 64-bit architectures from compiler & linker flags" >&6;} for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done fi fi ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy printf "%s\n" "#define _OE_SOCKETS 1" >>confdefs.h ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" if test "$SHARED_BUILD" = 1 then : SHLIB_LD='ld -shared -expect_unresolved "*"' else $as_nop SHLIB_LD='ld -non_shared -expect_unresolved "*"' fi SHLIB_SUFFIX=".so" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "$GCC" = yes then : CFLAGS="$CFLAGS -mieee" else $as_nop CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee" fi # see pthread_intro(3) for pthread support on osf1, k.furukawa if test "${TCL_THREADS}" = 1 then : CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` if test "$GCC" = yes then : LIBS="$LIBS -lpthread -lmach -lexc" else $as_nop CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi fi ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) if test "$GCC" = yes then : SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" else $as_nop SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" fi SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-5.[0-6]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. printf "%s\n" "#define _REENTRANT 1" >>confdefs.h printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h SHLIB_CFLAGS="-KPIC" SHLIB_SUFFIX=".so" if test "$GCC" = yes then : SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} else $as_nop SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. printf "%s\n" "#define _REENTRANT 1" >>confdefs.h printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = yes then : arch=`isainfo` if test "$arch" = "sparcv9 sparc" then : if test "$GCC" = yes then : if test "`${CC} -dumpversion | awk -F. '{print $1}'`" -lt 3 then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&5 printf "%s\n" "$as_me: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&2;} else $as_nop do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" fi else $as_nop do64bit_ok=yes if test "$do64bitVIS" = yes then : CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" else $as_nop CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" fi # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" fi else $as_nop if test "$arch" = "amd64 i386" then : if test "$GCC" = yes then : case $system in SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 printf "%s\n" "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;};; esac else $as_nop do64bit_ok=yes case $system in SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac fi else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported for $arch" >&5 printf "%s\n" "$as_me: WARNING: 64bit mode not supported for $arch" >&2;} fi fi fi SHLIB_SUFFIX=".so" if test "$GCC" = yes then : SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "$do64bit_ok" = yes then : if test "$arch" = "sparcv9 sparc" then : # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" else $as_nop if test "$arch" = "amd64 i386" then : # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" fi fi fi else $as_nop case $system in SunOS-5.[1-9][0-9]*) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' fi ;; UNIX_SV* | UnixWare-5*) SHLIB_CFLAGS="-KPIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers # that don't grok the -Bexport option. Test that it does. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld accepts -Bexport flag" >&5 printf %s "checking for ld accepts -Bexport flag... " >&6; } if test ${tcl_cv_ld_Bexport+y} then : printf %s "(cached) " >&6 else $as_nop hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-Bexport" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { int i; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_ld_Bexport=yes else $as_nop tcl_cv_ld_Bexport=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_Bexport" >&5 printf "%s\n" "$tcl_cv_ld_Bexport" >&6; } if test $tcl_cv_ld_Bexport = yes then : LDFLAGS="$LDFLAGS -Wl,-Bexport" fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; esac if test "$do64bit" = yes -a "$do64bit_ok" = no then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit support being disabled -- don't know magic for this platform" >&5 printf "%s\n" "$as_me: WARNING: 64bit support being disabled -- don't know magic for this platform" >&2;} fi # Add in the arch flags late to ensure it wasn't removed. # Not necessary in TEA, but this is aligned with core LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. if test "$GCC" = yes then : case $system in AIX-*) ;; BSD/OS*) ;; CYGWIN_*|MINGW32_*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*|OpenBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; windows) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac fi if test "$tcl_cv_cc_visibility_hidden" != yes then : printf "%s\n" "#define MODULE_SCOPE extern" >>confdefs.h fi if test "$SHARED_LIB_SUFFIX" = "" then : # TEA specific: use PACKAGE_VERSION instead of VERSION SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}' fi if test "$UNSHARED_LIB_SUFFIX" = "" then : # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a' fi if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SEH support in compiler" >&5 printf %s "checking for SEH support in compiler... " >&6; } if test ${tcl_cv_seh+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : tcl_cv_seh=no else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN int main(int argc, char** argv) { int a, b = 0; __try { a = 666 / b; } __except (EXCEPTION_EXECUTE_HANDLER) { return 0; } return 1; } _ACEOF if ac_fn_c_try_run "$LINENO" then : tcl_cv_seh=yes else $as_nop tcl_cv_seh=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_seh" >&5 printf "%s\n" "$tcl_cv_seh" >&6; } if test "$tcl_cv_seh" = "no" ; then printf "%s\n" "#define HAVE_NO_SEH 1" >>confdefs.h fi # # Check to see if the excpt.h include file provided contains the # definition for EXCEPTION_DISPOSITION; if not, which is the case # with Cygwin's version as of 2002-04-10, define it to be int, # sufficient for getting the current code to work. # { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for EXCEPTION_DISPOSITION support in include files" >&5 printf %s "checking for EXCEPTION_DISPOSITION support in include files... " >&6; } if test ${tcl_cv_eh_disposition+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # define WIN32_LEAN_AND_MEAN # include # undef WIN32_LEAN_AND_MEAN int main (void) { EXCEPTION_DISPOSITION x; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_eh_disposition=yes else $as_nop tcl_cv_eh_disposition=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_eh_disposition" >&5 printf "%s\n" "$tcl_cv_eh_disposition" >&6; } if test "$tcl_cv_eh_disposition" = "no" ; then printf "%s\n" "#define EXCEPTION_DISPOSITION int" >>confdefs.h fi # Check to see if winnt.h defines CHAR, SHORT, and LONG # even if VOID has already been #defined. The win32api # used by mingw and cygwin is known to do this. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for winnt.h that ignores VOID define" >&5 printf %s "checking for winnt.h that ignores VOID define... " >&6; } if test ${tcl_cv_winnt_ignore_void+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define VOID void #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN int main (void) { CHAR c; SHORT s; LONG l; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_winnt_ignore_void=yes else $as_nop tcl_cv_winnt_ignore_void=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_winnt_ignore_void" >&5 printf "%s\n" "$tcl_cv_winnt_ignore_void" >&6; } if test "$tcl_cv_winnt_ignore_void" = "yes" ; then printf "%s\n" "#define HAVE_WINNT_IGNORE_VOID 1" >>confdefs.h fi fi # See if the compiler supports casting to a union type. # This is used to stop gcc from printing a compiler # warning when initializing a union member. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cast to union support" >&5 printf %s "checking for cast to union support... " >&6; } if test ${tcl_cv_cast_to_union+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { union foo { int i; double d; }; union foo f = (union foo) (int) 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_cast_to_union=yes else $as_nop tcl_cv_cast_to_union=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cast_to_union" >&5 printf "%s\n" "$tcl_cv_cast_to_union" >&6; } if test "$tcl_cv_cast_to_union" = "yes"; then printf "%s\n" "#define HAVE_CAST_TO_UNION 1" >>confdefs.h fi # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for required early compiler flags" >&5 printf %s "checking for required early compiler flags... " >&6; } tcl_flags="" if test ${tcl_cv_flag__isoc99_source+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { char *p = (char *)strtoll; char *q = (char *)strtoull; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_flag__isoc99_source=no else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _ISOC99_SOURCE 1 #include int main (void) { char *p = (char *)strtoll; char *q = (char *)strtoull; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_flag__isoc99_source=yes else $as_nop tcl_cv_flag__isoc99_source=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "x${tcl_cv_flag__isoc99_source}" = "xyes" ; then printf "%s\n" "#define _ISOC99_SOURCE 1" >>confdefs.h tcl_flags="$tcl_flags _ISOC99_SOURCE" fi if test ${tcl_cv_flag__largefile64_source+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { struct stat64 buf; int i = stat64("/", &buf); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_flag__largefile64_source=no else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE64_SOURCE 1 #include int main (void) { struct stat64 buf; int i = stat64("/", &buf); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_flag__largefile64_source=yes else $as_nop tcl_cv_flag__largefile64_source=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "x${tcl_cv_flag__largefile64_source}" = "xyes" ; then printf "%s\n" "#define _LARGEFILE64_SOURCE 1" >>confdefs.h tcl_flags="$tcl_flags _LARGEFILE64_SOURCE" fi if test ${tcl_cv_flag__largefile_source64+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { char *p = (char *)open64; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_flag__largefile_source64=no else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE_SOURCE64 1 #include int main (void) { char *p = (char *)open64; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_flag__largefile_source64=yes else $as_nop tcl_cv_flag__largefile_source64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "x${tcl_cv_flag__largefile_source64}" = "xyes" ; then printf "%s\n" "#define _LARGEFILE_SOURCE64 1" >>confdefs.h tcl_flags="$tcl_flags _LARGEFILE_SOURCE64" fi if test "x${tcl_flags}" = "x" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5 printf "%s\n" "none" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${tcl_flags}" >&5 printf "%s\n" "${tcl_flags}" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit integer type" >&5 printf %s "checking for 64-bit integer type... " >&6; } if test ${tcl_cv_type_64bit+y} then : printf %s "(cached) " >&6 else $as_nop tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { __int64 value = (__int64) 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_type_64bit=__int64 else $as_nop tcl_type_64bit="long long" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { switch (0) { case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ; } ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_type_64bit=${tcl_type_64bit} fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "${tcl_cv_type_64bit}" = none ; then printf "%s\n" "#define TCL_WIDE_INT_IS_LONG 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: using long" >&5 printf "%s\n" "using long" >&6; } elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # TEA specific: We actually want to use the default tcl.h checks in # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: using Tcl header defaults" >&5 printf "%s\n" "using Tcl header defaults" >&6; } else printf "%s\n" "#define TCL_WIDE_INT_TYPE ${tcl_cv_type_64bit}" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${tcl_cv_type_64bit}" >&5 printf "%s\n" "${tcl_cv_type_64bit}" >&6; } # Now check for auxiliary declarations { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct dirent64" >&5 printf %s "checking for struct dirent64... " >&6; } if test ${tcl_cv_struct_dirent64+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { struct dirent64 p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_struct_dirent64=yes else $as_nop tcl_cv_struct_dirent64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_struct_dirent64" >&5 printf "%s\n" "$tcl_cv_struct_dirent64" >&6; } if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then printf "%s\n" "#define HAVE_STRUCT_DIRENT64 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct stat64" >&5 printf %s "checking for struct stat64... " >&6; } if test ${tcl_cv_struct_stat64+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { struct stat64 p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_struct_stat64=yes else $as_nop tcl_cv_struct_stat64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_struct_stat64" >&5 printf "%s\n" "$tcl_cv_struct_stat64" >&6; } if test "x${tcl_cv_struct_stat64}" = "xyes" ; then printf "%s\n" "#define HAVE_STRUCT_STAT64 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "open64" "ac_cv_func_open64" if test "x$ac_cv_func_open64" = xyes then : printf "%s\n" "#define HAVE_OPEN64 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "lseek64" "ac_cv_func_lseek64" if test "x$ac_cv_func_lseek64" = xyes then : printf "%s\n" "#define HAVE_LSEEK64 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for off64_t" >&5 printf %s "checking for off64_t... " >&6; } if test ${tcl_cv_type_off64_t+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { off64_t offset; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_type_off64_t=yes else $as_nop tcl_cv_type_off64_t=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then printf "%s\n" "#define HAVE_TYPE_OFF64_T 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi # Without the following two eval statements, NSF_SHARED_LIB_SUFFIX # in nsfConfig.sh has $PACKAGE_VERSION unresolved. When another # app links against nsf, the PACKAGE_VERSIONs are confused. # # Without the first eval, we get # NSF_SHARED_LIB_SUFFIX=${PACKAGE_VERSION}\$\{DBGX\}${SHLIB_SUFFIX} # NSF_UNSHARED_LIB_SUFFIX=${PACKAGE_VERSION}\$\{DBGX\}.a # # after the first eval, we get # NSF_SHARED_LIB_SUFFIX=1.2.1${DBGX}.so # NSF_UNSHARED_LIB_SUFFIX=1.2.1${DBGX}.a # after the second eval, all variables are resolved. eval "SHARED_LIB_SUFFIX=${SHARED_LIB_SUFFIX}" eval "UNSHARED_LIB_SUFFIX=${UNSHARED_LIB_SUFFIX}" #eval "SHARED_LIB_SUFFIX=${SHARED_LIB_SUFFIX}" #eval "UNSHARED_LIB_SUFFIX=${UNSHARED_LIB_SUFFIX}" #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols # option. #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build with symbols" >&5 printf %s "checking for build with symbols... " >&6; } # Check whether --enable-symbols was given. if test ${enable_symbols+y} then : enableval=$enable_symbols; tcl_ok=$enableval else $as_nop tcl_ok=no fi DBGX="" if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (standard debugging)" >&5 printf "%s\n" "yes (standard debugging)" >&6; } fi fi # TEA specific: if test "${TEA_PLATFORM}" != "windows" ; then LDFLAGS_DEFAULT="${LDFLAGS}" fi if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then printf "%s\n" "#define TCL_MEM_DEBUG 1" >>confdefs.h fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: enabled symbols mem debugging" >&5 printf "%s\n" "enabled symbols mem debugging" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: enabled $tcl_ok debugging" >&5 printf "%s\n" "enabled $tcl_ok debugging" >&6; } fi fi #-------------------------------------------------------------------- # Everyone should be linking against the Tcl stub library. If you # can't for some reason, remove this definition. If you aren't using # stubs, you also need to modify the SHLIB_LD_LIBS setting below to # link against the non-stubbed Tcl library. #-------------------------------------------------------------------- printf "%s\n" "#define USE_TCL_STUBS 1" >>confdefs.h #-------------------------------------------------------------------- # This macro generates a line to use when building a library. It # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, # and TEA_LOAD_TCLCONFIG macros above. #-------------------------------------------------------------------- PRACTCL_TOOLSET="gcc" PRACTCL_VC_MANIFEST_EMBED_DLL=: PRACTCL_VC_MANIFEST_EMBED_EXE=: if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then PRACTCL_TOOLSET="msvc" PRACTCL_STATIC_LIB="%STLIB_LD% -out:%OUTFILE% %LIBRARY_OBJECTS%" PRACTCL_SHARED_LIB="%SHLIB_LD% %SHLIB_LD_LIBS% %LDFLAGS_DEFAULT% -out:%OUTFILE% %LIBRARY_OBJECTS%" MAKE_STATIC_LIB="\${STLIB_LD} -out:\$@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\$@ \$(PKG_OBJECTS)" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined(_MSC_VER) && _MSC_VER >= 1400 print("manifest needed") #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "manifest needed" >/dev/null 2>&1 then : # Could do a CHECK_PROG for mt, but should always be with MSVC8+ PRACTCL_VC_MANIFEST_EMBED_DLL="mt.exe -nologo -manifest %OUTFILE%.manifest -outputresource:%OUTFILE%\;2" PRACTCL_VC_MANIFEST_EMBED_EXE="mt.exe -nologo -manifest %OUTFILE%.manifest -outputresource:%OUTFILE%\;1" VC_MANIFEST_EMBED_DLL="if test -f \$@.manifest ; then mt.exe -nologo -manifest \$@.manifest -outputresource:\$@\;2 ; fi" VC_MANIFEST_EMBED_EXE="if test -f \$@.manifest ; then mt.exe -nologo -manifest \$@.manifest -outputresource:\$@\;1 ; fi" MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" CLEANFILES="$CLEANFILES *.manifest" fi rm -rf conftest* PRACTCL_STUB_LIB="%STLIB_LD% -nodefaultlib -out:%OUTFILE% %LIBRARY_OBJECTS%" MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\$@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \$@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} -o \$@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \$@ \$(PKG_STUB_OBJECTS)" PRACTCL_STATIC_LIB="%STLIB_LD% %OUTFILE% %LIBRARY_OBJECTS%" PRACTCL_SHARED_LIB="%SHLIB_LD% -o %OUTFILE% %LIBRARY_OBJECTS% %SHLIB_LD_LIBS%" PRACTCL_STUB_LIB="%STLIB_LD% %OUTFILE% %LIBRARY_OBJECTS%" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}" PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9" if test "${TCL_MAJOR_VERSION}" -gt 8 ; then PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}" else PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}" fi if test "${TEA_PLATFORM}" = "windows" ; then PRACTCL_NAME_LIBRARY="%LIBRARY_PREFIX%%LIBRARY_NAME%%LIBRARY_VERSION_NODOTS%" if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test "$GCC" = "yes"; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc" fi eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_LIB_FILE=lib${PKG_LIB_FILE} fi fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else PRACTCL_NAME_LIBRARY="lib%LIBRARY_PREFIX%%LIBRARY_NAME%%LIBRARY_VERSION%" RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # Store the raw CFLAGS before we add the trimmings PRACTCL_CFLAGS=${CFLAGS} # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi #-------------------------------------------------------------------- # Find tclsh so that we can run pkg_mkIndex to generate the pkgIndex.tcl # file during the install process. Don't run the TCLSH_PROG through # ${CYGPATH} because it's being used directly by make. # Require that we use a tclsh shell version 8.2 or later since earlier # versions have bugs in the pkg_mkIndex routine. #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tclsh" >&5 printf %s "checking for tclsh... " >&6; } # Check whether --with-tclsh was given. if test ${with_tclsh+y} then : withval=$with_tclsh; with_tclsh=${withval} fi # Use the value from --with-tclsh, if it was given TCLSH_PROG=0 if test x"${with_tclsh}" != x ; then if test -f "${with_tclsh}" ; then TCLSH_PROG=${with_tclsh} else if test -f "${with_tclsh}/tcl8.6" ; then TCLSH_PROG="${with_tclsh}/tcl8.6" else if test -f "${with_tclsh}/tclsh86.exe" ; then TCLSH_PROG="${with_tclsh}/tclsh86.exe" else as_fn_error $? "${with_tclsh} does not point to a valid Tcl executable" "$LINENO" 5 fi fi fi else if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" fi else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${TCLSH_PROG}" >&5 printf "%s\n" "${TCLSH_PROG}" >&6; } # make this available, for such as nsfConfig.sh NSF_COMPATIBLE_TCLSH=${TCLSH_PROG} # # Next Scripting specific configs # #NSF_SRC_DIR=$srcdir #NSF_SRC_DIR="`pwd`" NSF_BUILD_DIR=${PWD} cd ${srcdir} NSF_SRC_DIR=${PWD} cd ${NSF_BUILD_DIR} eval "NSF_PKG_LIBDIR=\"${libdir}/${PACKAGE_NAME}${PACKAGE_VERSION}\"" if test "${TEA_PLATFORM}" != "windows" ; then NSF_BUILD_LIB_SPEC="-L${NSF_BUILD_DIR} -lnsf${PACKAGE_VERSION}" NSF_LIB_SPEC="-L${NSF_PKG_LIBDIR} -lnsf${PACKAGE_VERSION}" # If someone wants to build without stubs, as it was the case for # earlier Tcl versions, we keep the following block as a reference. if test "${TCL_MAJOR_VERSION}" = "8" -a "${TCL_MINOR_VERSION}" = "0"; then NSF_BUILD_STUB_LIB_PATH="" NSF_STUB_LIB_PATH="" NSF_BUILD_STUB_LIB_SPEC="" NSF_STUB_LIB_SPEC="" else NSF_BUILD_STUB_LIB_PATH="${NSF_SRC_DIR}/${PKG_STUB_LIB_FILE}" NSF_STUB_LIB_PATH="${NSF_PKG_LIBDIR}/${PKG_STUB_LIB_FILE}" NSF_BUILD_STUB_LIB_SPEC="-L${NSF_BUILD_DIR} -lnsfstub${PACKAGE_VERSION}" NSF_STUB_LIB_SPEC="-L${NSF_PKG_LIBDIR} -lnsfstub${PACKAGE_VERSION}" printf "%s\n" "#define COMPILE_NSF_STUBS 1" >>confdefs.h fi else NSF_BUILD_LIB_SPEC="${NSF_SRC_DIR}/${PKG_LIB_FILE}" NSF_LIB_SPEC="${NSF_PKG_LIBDIR}/${PKG_LIB_FILE}" NSF_BUILD_STUB_LIB_PATH="${NSF_BUILD_DIR}/${PKG_STUB_LIB_FILE}" NSF_STUB_LIB_PATH="${NSF_PKG_LIBDIR}/${PKG_STUB_LIB_FILE}" NSF_BUILD_STUB_LIB_SPEC="${NSF_BUILD_DIR}/${PKG_STUB_LIB_FILE}" NSF_STUB_LIB_SPEC="${NSF_PKG_LIBDIR}/${PKG_STUB_LIB_FILE}" printf "%s\n" "#define COMPILE_NSF_STUBS 1" >>confdefs.h fi # include dirs for nsf during build process (i.e., does not assume installed) NSF_BUILD_INCLUDE_DIR="${NSF_SRC_DIR}/generic" NSF_BUILD_INCLUDE_SPEC="-I${NSF_BUILD_INCLUDE_DIR}" eval "NSF_INCLUDE_DIR=\"$includedir\"" #-------------------------------------------------------------------- # the value of this variable is set to the files which are to be # removed when the user invokes 'make distclean' (i.e., those # files generated by ./configure) and is used in the make distclean # target, defined in Makefile.in #-------------------------------------------------------------------- CONFIG_CLEAN_FILES="Makefile ${srcdir}/nsfConfig.sh ${srcdir}/library/xotcl/xotclsh ${srcdir}/library/xotcl/xowish nxsh nxwish ${srcdir}/doc/version.inc autom4te.cache/" ac_config_files="$ac_config_files Makefile ${srcdir}/nsfConfig.sh ${srcdir}/library/xotcl/xotclsh ${srcdir}/library/xotcl/xowish nxsh nxwish ${srcdir}/doc/version.inc" #-------------------------------------------------------------------- # Finally, substitute all of the various values into the Makefile, # and generate the other output files. (this is done by invoking # config.status) # # NOTE the lack of parameters! AC_OUTPUT with params is deprecated; # use macros such as AC_CONFIG_FILES, AC_HEADER_FILES, etc to add # to the files output by ./configure. #-------------------------------------------------------------------- cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS="" : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by nsf $as_me 2.4.0, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to ." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ nsf config.status 2.4.0 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "${srcdir}/nsfConfig.sh") CONFIG_FILES="$CONFIG_FILES ${srcdir}/nsfConfig.sh" ;; "${srcdir}/library/xotcl/xotclsh") CONFIG_FILES="$CONFIG_FILES ${srcdir}/library/xotcl/xotclsh" ;; "${srcdir}/library/xotcl/xowish") CONFIG_FILES="$CONFIG_FILES ${srcdir}/library/xotcl/xowish" ;; "nxsh") CONFIG_FILES="$CONFIG_FILES nxsh" ;; "nxwish") CONFIG_FILES="$CONFIG_FILES nxwish" ;; "${srcdir}/doc/version.inc") CONFIG_FILES="$CONFIG_FILES ${srcdir}/doc/version.inc" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi chmod +x nxsh nxwish ${srcdir}/library/xotcl/xotclsh ${srcdir}/library/xotcl/xowish for subdir in ${subdirs} do echo "==================== configure $subdir" if test x"${srcdir}" = x. ; then confdir=. else #mkdir -p $subdir confdir=${srcdir}/$subdir fi (cd $subdir; echo $SHELL ${confdir}/configure ${ac_configure_args} --prefix=${prefix} --with-nsf=${NSF_SRC_DIR}; eval $SHELL ${confdir}/configure ${ac_configure_args} --prefix=${prefix} --with-nsf=${NSF_SRC_DIR}) done ./nsf2.4.0/host.key000644 000766 000024 00000001567 13465515127 014701 0ustar00neumannstaff000000 000000 -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDlc86E/05SCY1hBzhF7PjQS75jxEqZ8eI3p+4jph7XSNnQX2cS e6+gIy7aaruQen3awtMRKUKZF2WE4qjh/1KbvN9Jmk25UuxhVJnEq5/amQUPLYcy QqNJa5bAVRW//VfEjAUvn2W+6/JSA3CvRI3gU8ZvTFLaa/kPxROtYqZqTwIDAQAB AoGBALQoHnIch2EwcNpLMertalsZ7a4l1DFVUzpB12AUMcj1QVgzYBmKFdZVaZdD EGwbUS/vooup6smLLkGNOe7gavmx66+GOoJuDFIKLOsYAYgYS++TEBkCejQtFIf2 QHcu/xKMlWs1+rI+FhJrlr2w3bivuvpwyvhvKSxkgcbfkVchAkEA/e16lcuyQZKe izQUyKUl6PW6Cl0wfZkibQ3CtAE3BZTMZ/Fscx1FtE4uAzY0t6tlUkoD4KWoTR/F rMytjAEucQJBAOdTMU9FwHqz+4oTRPf8Wh+JAej+IwKMwitAi08jrowAUEuPJioC jakrdDHu4bv/A7ZcGx/zGUjVwmcNFAU7BL8CQCkc8TMdtu/dAGSDezX9X0T3vDZ/ XiGH0MYdaz/fznvN2sadlTSSMb3+xn5ooWJ3ksEfEL+nsrdCBKx0u0imzFECQG+7 cDrQ/yqFWr8TlaGOY12OCL0oW3K02GiZ0XAVVQ7Ma/xDFXT/LLuEgKhJsQDkKT/g 9z0UZ6cVkMPDvmLUYfMCQBcZzbp/uCmZeFXTwBkCpXgGX/Ka+fFg8Q49p0hsDUyF lblmlJ5pX4L0TSfBX8GNuIwKJ2geAyLBU7BOsxrMMis= -----END RSA PRIVATE KEY----- ./nsf2.4.0/infer-out/logs000644 000766 000024 00000340462 14271435441 016005 0ustar00neumannstaff000000 000000 [889][ debug] Loading models took 155ms [890][ debug] Sqlite write daemon: starting up [890][ debug] Sqlite write daemon: set up complete, waiting for connections [889][environment] CWD = /nsf [889][environment] No .inferconfig file found [889][environment] Project root = /nsf [889][environment] INFER_ARGS = @/tmp/args.tmp.61173a [889][environment] command line arguments: infer run -- make [889][environment] Available memory at startup: 596 MB [889][environment] Active checkers: self-in-block (C/C++/ObjC), starvation (C/C++/ObjC, Java), uninit (C/C++/ObjC), siof (C/C++/ObjC), dotnet-resource-leak (C#/.Net), racerd (C/C++/ObjC, Java), liveness (C/C++/ObjC), inefficient-keyset-iterator (Java), fragment-retains-view (Java), biabduction (C/C++/ObjC, Java, C#/.Net) [889][environment] Scheduler: file [889][environment] Cores used: 8 [889][environment] Infer version v1.1.0 [889][environment] Copyright 2009 - present Facebook. All Rights Reserved. [889][environment] [889][ progress] Capturing in make/cc mode... [889][environment] Running command make with env: [889][environment] (Extend((PATH /opt/infer-linux64-v1.1.0/lib/infer/infer/bin/../lib/wrappers:/infer/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin)(INFER_OLD_PATH /infer/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin))) [889][environment] [894][environment] CWD = /nsf [894][environment] No .inferconfig file found [894][environment] Project root = /nsf [894][environment] INFER_ARGS = @/tmp/args.tmp.3458cf [894][environment] command line arguments: gcc -DPACKAGE_NAME="nsf" -DPACKAGE_TARNAME="nsf" [894][environment] -DPACKAGE_VERSION="2.4.0" [894][environment] -DPACKAGE_STRING="nsf 2.4.0" [894][environment] -DPACKAGE_BUGREPORT="https://sourceforge.net/p/next-scripting/tickets/" [894][environment] -DPACKAGE_URL="" -DHAVE_STDIO_H=1 -DHAVE_STDLIB_H=1 [894][environment] -DHAVE_STRING_H=1 -DHAVE_INTTYPES_H=1 [894][environment] -DHAVE_STDINT_H=1 -DHAVE_STRINGS_H=1 [894][environment] -DHAVE_SYS_STAT_H=1 -DHAVE_SYS_TYPES_H=1 [894][environment] -DHAVE_UNISTD_H=1 -DSTDC_HEADERS=1 [894][environment] -DHAVE_INTPTR_T=1 -DHAVE_UINTPTR_T=1 [894][environment] -DBUILD_nsf=/**/ -DHAVE_STRNSTR=1 -DNO_VALUES_H=1 [894][environment] -DHAVE_LIMITS_H=1 -DHAVE_SYS_PARAM_H=1 [894][environment] -DHAVE_TCL_COMPILE_H=1 -DNSF_WITH_ASSERTIONS=1 [894][environment] -DNSF_PROFILE=1 -DNSF_DEVELOPMENT=1 [894][environment] -DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 [894][environment] -D_THREAD_SAFE=1 -DTCL_THREADS=1 -DUSE_TCL_STUBS=1 [894][environment] -DUSE_TCLOO_STUBS=1 [894][environment] -DMODULE_SCOPE=extern __attribute__((__visibility__("hidden"))) [894][environment] -DHAVE_HIDDEN=1 -DHAVE_CAST_TO_UNION=1 [894][environment] -DTCL_WIDE_INT_IS_LONG=1 -DUSE_TCL_STUBS=1 [894][environment] -DCOMPILE_NSF_STUBS=1 -DNSF_VERSION="2.4" [894][environment] -DNSF_PATCHLEVEL="2.4.0" [894][environment] -DNSF_COMMIT="2.3.0-204-g20b47273-dirty" [894][environment] -I/usr/local/src/tcl-trunk/generic [894][environment] -I/usr/local/src/tcl-trunk/unix [894][environment] -I/Users/neumann/src/nsf2.3.0/generic -Os -Wall [894][environment] -pipe -pedantic -g -std=c99 -DTCL_NO_DEPRECATED [894][environment] -Wconversion -Wsign-conversion -Wsign-compare [894][environment] -Wwrite-strings -Wextra [894][environment] -Wdeclaration-after-statement -Wendif-labels [894][environment] -Wshadow -Wmissing-prototypes -Wstrict-prototypes [894][environment] -Wpacked -Wno-redundant-decls [894][environment] -Wno-zero-length-array -Wmissing-braces [894][environment] -Wmissing-declarations -Wundef -Wunreachable-code [894][environment] -Wswitch-enum -Wpointer-arith [894][environment] -Wold-style-definition -Wmissing-format-attribute [894][environment] -Wformat-security -Wall -fno-common -c [894][environment] ./generic/nsf.c -o nsf.o [894][environment] Available memory at startup: 560 MB [894][environment] Active checkers: self-in-block (C/C++/ObjC), starvation (C/C++/ObjC, Java), uninit (C/C++/ObjC), siof (C/C++/ObjC), dotnet-resource-leak (C#/.Net), racerd (C/C++/ObjC, Java), liveness (C/C++/ObjC), inefficient-keyset-iterator (Java), fragment-retains-view (Java), biabduction (C/C++/ObjC, Java, C#/.Net) [894][ debug] [894][ debug] *** Beginning capture of file /nsf/generic/nsf.c *** [894][ debug] Loading the following linters files: /opt/infer-linux64-v1.1.0/lib/infer/infer/bin/../lib/linter_rules/linters.al [894][ debug] generic/nsf.c:681:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfDListAppend' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:833:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfDStringEval' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfLog' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:1071:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParseContextExtendObjv' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:1258:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CallMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:1312:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfCallMethodWithArgs' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'VarHashCreateVar' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:1396:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'Nsf_NextHashEntry' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:1513:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfIsClass' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:1548:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'Nsf_ObjSetVar2' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'Nsf_ObjGetVar2' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:1591:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'Nsf_UnsetVar2' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:1618:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfCreate' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:1659:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfRemoveObjectMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:1685:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfRemoveClassMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:1819:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'IsClassNsName' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:1819:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'IsClassNsName' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:1889:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'DStringAppendQualName' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:1929:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfCleanupObject_' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:1985:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'TclObjIsNsfObject' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'GetObjectFromObj' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:2273:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GetClassFromObj' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:2362:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'IsObjectOfType' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:2397:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NameInNamespaceObj' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:2437:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NewTclCommand' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:2547:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfClassListAdd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:2596:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfClassListAddNoDup' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:2745:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfClassListUnlink' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:3167:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'MergeInheritanceLists' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:3264:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'TopoSortSuper' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:3394:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'PrecedenceOrder' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:3562:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'RemoveInstance' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:3600:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AddSuper' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:3633:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'RemoveSuper1' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:3633:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'RemoveSuper1' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:3633:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'RemoveSuper1' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:3704:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GetEnsembleObjectFromName' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:3759:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GetRegObject' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:3968:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ResolveMethodName' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:4098:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GetTclProcFromCommand' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'FindMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:4428:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ObjectFindMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:4504:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ObjectSystemFree' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:4736:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CallDirectly' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:4804:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfRequireObjectOpt' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:4834:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfRequireClassOpt' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'MakeObjNamespace' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'CompiledLocalsLookup' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:5217:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CompiledColonLocalsLookup' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:5318:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfMethodNamePath' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:5471:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsColonVarResolver' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'HashVarFree' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'CompiledColonVarFetch' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:5678:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CompiledColonVarFree' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'InterpCompiledColonVarResolver' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:5799:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'InterpGetFrameAndFlags' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:5974:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'InterpColonVarResolver' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:6120:7: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'InterpColonCmdResolver' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:6279:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'SlotContainerCmdResolver' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'RequireObjNamespace' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:6374:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NSNamespaceRelease' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:6402:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NSDeleteCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:6507:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NSDeleteChild' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:6689:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'UnsetTracedVars' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:6828:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'Nsf_DeleteNamespace' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:6882:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NSValidObjectName' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NSGetFreshNamespace' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:6984:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NSRequireParentObject' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NSCheckNamespace' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NSFindCommand' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'GetObjectFromString' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:7404:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CanRedefineCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:7455:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfAddObjectMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:7521:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfAddClassMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:7605:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AutonameIncr' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'CallStackDoDestroy' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:7839:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CallStackDestroyObject' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:7934:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CmdListAdd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:7985:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CmdListAddSorted' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:8045:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CmdListDeleteCmdListEntry' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:8079:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CmdListRemoveFromList' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:8274:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CheckConditionInScope' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:8346:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'TclObjListNewElement' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:8450:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AddObjToTclList' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:8476:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AssertionNewList' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:8509:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AssertionListCheckOption' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'AssertionFindProcs' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'AssertionRemoveProc' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:8568:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AssertionRemoveProc' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:8630:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AssertionRemoveStore' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:8732:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AssertionCheckList' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:8775:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AssertionCheckInvars' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:8824:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AssertionCheck' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:8876:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AssertionSetCheckOptions' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'AssertionSetInvariants' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:10889:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GuardDel' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:9201:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'MixinComputeOrder' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:9266:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'MixinAdd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'AppendMatchingElement' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:9486:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GetAllInstances' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:9528:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AddToResultSet' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:9588:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AddToResultSetWithGuards' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:9700:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GetAllObjectMixinsOf' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:9893:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GetAllClassMixinsOf' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:9981:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GetAllClassMixins' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:10215:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ResetOrderOfObjectsUsingThisClassAsObjectMixin' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:10319:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'MixinComputeDefined' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:3394:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'PrecedenceOrder' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:10370:9: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ComputePrecedenceList' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:10422:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'SeekCurrent' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:10467:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CanInvokeMixinMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:10634:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'MixinSearchProc' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:10798:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'FilterSearch' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:10862:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GuardCheck' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'GuardDel' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'GuardAdd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:10940:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GuardCall' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:10983:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GuardAddFromDefinitionList' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:11070:7: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GuardAddInheritedGuards' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'GuardList' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:11295:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'FilterAdd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:10889:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GuardDel' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:10889:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GuardDel' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:10889:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GuardDel' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:11740:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'FilterComputeOrder' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'FilterComputeDefined' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:11926:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'FilterFindReg' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'FilterSearchProc' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'SuperclassAdd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:12264:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'VarExists' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:12424:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ByteCompiled' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:12496:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'PushProcCallFrame' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:12709:67: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParamFree' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:12779:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParamDefsGet' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'ParamDefsGetReturns' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfParamDefsNonposLookup' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:12995:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CGetParamLookup' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:13044:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfProcDeleteProc' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:13094:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ProcContextRequire' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:13124:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ProcContextGet' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'ParamDefsStore' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:13249:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParamDefsFree' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:13249:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParamDefsFree' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:13362:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParamsDefMatchPattern' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:13617:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParamGetType' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:13617:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParamGetType' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:13748:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfParamDefsVirtualFormat' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:13795:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfParamDefsAppendVirtual' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:13939:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParsedParamFree' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:14014:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ProcMethodDispatchFinalize' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:14077:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ProcDispatchFinalize' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:14288:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ProcMethodDispatch' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:14359:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CmdMethodDispatch' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:14770:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ObjectCmdMethodDispatch' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:15042:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'MethodDispatchCsc' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:15085:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'MethodDispatch' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:15211:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ObjectDispatchFinalize' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:15329:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CmdObjProcName' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:15518:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CacheCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:16126:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ObjectDispatch' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:16187:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'DispatchDefaultMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:16298:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'DispatchDestroyMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:16353:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'DispatchInitMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:16460:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'DispatchUnknownMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:16798:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'Nsf_ConvertToTclobj' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:16839:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'Nsf_ConvertToBoolean' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:16881:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'Nsf_ConvertToInt32' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:16985:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'Nsf_ConvertToInteger' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:17059:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'Nsf_ConvertToObject' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:17101:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'Nsf_ConvertToClass' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:17144:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'Nsf_ConvertToFilterreg' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:17185:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'Nsf_ConvertToMixinreg' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:17352:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ConvertViaCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'ConvertToObjpattern' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:17495:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParamOptionSetConverter' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:17913:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParamOptionParse' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:12709:67: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParamFree' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:18253:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParamDefinitionParse' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:18360:7: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParamDefsParse' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:18496:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParameterMethodForwardDispatch' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:18735:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParameterMethodDispatch' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:18925:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'MakeProc' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:19055:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'MakeMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:19089:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfProcStubDeleteProc' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:19158:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'InvokeShadowedProc' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:19337:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfProcStub' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:19547:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfProcAdd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:19639:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ProcessMethodArguments' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:19704:60: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ForwardCmdDeleteProc' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:19735:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'SetterCmdDeleteProc' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:19812:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AliasCmdDeleteProc' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:19853:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GetMatchObject' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:19991:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ForwardProcessOptions' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:20153:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AddSlotObjects' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:20213:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'FindCalledClass' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NextSearchMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:20516:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NextGetArguments' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:20599:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NextInvokeFinalize' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:20881:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NextSearchAndInvoke' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:20955:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfNextObjCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'FindNextMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'ComputeLevelObj' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:21181:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'UnsetInAllNamespaces' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'FreeUnsetTraceVariable' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:21310:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfUnsetTrace' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'CleanupDestroyObject' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:21464:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CleanupInitObject' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'PrimitiveDestroy' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'TclDeletesObject' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'PrimitiveODestroy' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:21684:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'DoDealloc' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:21778:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'PrimitiveOInit' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:21855:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'PrimitiveOCreate' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:21945:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'DefaultSuperClass' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:22113:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CleanupDestroyClass' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:3600:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AddSuper' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:22205:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CleanupInitClass' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:22286:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'PrimitiveCDestroy' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:22326:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'PrimitiveCInit' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:22405:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'PrimitiveCCreate' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:3562:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'RemoveInstance' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:22470:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ChangeClass' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:22584:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'DoObjInitialization' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:22716:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'IsMetaClass' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:22942:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ImportInstVarIntoCurrentScope' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'SetInstVar' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:23077:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'SetInstArray' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'UnsetInstVar' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:23205:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfSetterMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:23288:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfForwardPrintError' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:23578:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ForwardArg' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:23664:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CallForwarder' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:23897:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfForwardMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:24047:7: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'IsDashArg' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:24116:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CallConfigureMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:24203:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'CallingNameSpace' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:24307:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ArgumentCheckHelper' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:24437:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ArgumentCheck' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:24629:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ArgumentDefaults' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:25160:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ArgumentParse' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'ListVarKeys' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:25372:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GetOriginalCommand' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:25632:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ListCmdParams' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'AppendForwardDefinition' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'AppendMethodRegistration' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'AppendReturnsClause' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'DisassembleProc' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'ListMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:26471:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ListMethodResolve' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:26524:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'MethodSourceMatches' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:26577:7: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'MethodTypeMatches' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:26914:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ListMethodKeys' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'ListChildren' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:27059:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ListForward' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'ListDefinedMethods' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'ListSuperClasses' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:27381:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AliasGet' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:27424:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AliasDeleteObjectReference' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:27497:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AliasRefetch' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'AliasDereference' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:27614:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'SetBooleanFlag' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:27703:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfDebugShowObj' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfDebugGetDict' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:28027:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfUnsetUnknownArgsCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:28250:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfConfigureCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:28350:9: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfColonCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:28437:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfDirectDispatchCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:28618:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfFinalizeCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:28686:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfInterpObjCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:28740:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfIsCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:28823:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfParseArgsCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:29060:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfMethodAliasCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:29122:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfMethodAssertionCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfMethodCreateCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:29227:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfMethodDeleteCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:29304:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfMethodForwardCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:29380:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfForwardPropertyCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:29558:7: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfMethodPropertyCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:29676:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfMethodSetterCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:29738:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfObjectAllocCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:29867:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfObjectPropertyCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:3600:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'AddSuper' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:30008:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfObjectSystemCreateCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:30086:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfMyCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:30147:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfNextCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:30281:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfNSCopyVarsCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:30395:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfParameterInfoCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfParameterCacheClassInvalidateCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfParameterCacheObjectInvalidateCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:30592:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfParameterSpecsCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:30650:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfProcCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:30742:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfRelationClassMixinsSet' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:31008:7: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfRelationSetCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:31242:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfCurrentCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfSelfCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfVarExistsCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:31396:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfVarSetCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfVarUnsetCmd' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:31501:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParamFreeInternalRep' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:31575:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParamSetFromAny2' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:31676:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ComputeParameterDefinition' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:31775:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GetObjectParameterDefinition' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:31848:43: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ParameterCheck' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfOAutonameMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:31957:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfOCleanupMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:31981:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'GetSlotObject' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:32358:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfOConfigureMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:32493:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfOCgetMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:32563:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfODestroyMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:32620:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfOFilterGuardMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:32648:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfOInstvarMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfOMixinGuardMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:32836:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfOResidualargsMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:32939:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfOUplevelMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:33000:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfOUpvarMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:33125:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'VolatileMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:33183:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfCAllocMethod_' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:33249:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfCAllocMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:33461:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfCCreateMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfCDeallocMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfCFilterGuardMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfCGetCachendParametersMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfCMixinGuardMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:33675:7: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfCNewMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:33748:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'RecreateObject' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfCRecreateMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:33983:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfObjInfoLookupFilterMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:34030:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfObjInfoLookupMethodMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:34147:9: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfObjInfoLookupMethodsMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:34216:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfObjInfoLookupSlotsMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:34331:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfObjInfoParentMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfObjInfoPrecedenceMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:34426:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfObjInfoVarsMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:34522:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfClassInfoHeritageMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:34682:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfClassInfoMethodsMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:34746:5: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfClassInfoMixinsMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:34860:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'NsfClassInfoMixinOfMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfClassInfoSlotobjectsMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'NsfClassInfoSubclassMethod' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:35139:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'FinalObjectDeletion' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr Aborting translation of method 'DeleteNsfProcs' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:35308:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'ObjectHasChildren' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] generic/nsf.c:36147:3: ERROR translating statement 'OpaqueValueExpr' [894][ debug] [894][ intern err] Aborting translation of method 'Nsf_Init' in file 'generic/nsf.c' Known incorrect assumption in the frontend: Expected source expression for OpaqueValueExpr [894][ debug] Elapsed: 3.349s. [894][ debug] [894][ extern err] Error: the following clang command did not run successfully: [894][ extern err] /opt/infer-linux64-v1.1.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-11 [894][ extern err] @/nsf/infer-out/tmp/clang_command_.tmp.e307ea.txt ++Contents of '/nsf/infer-out/tmp/clang_command_.tmp.e307ea.txt': [894][ extern err] "-cc1" "-load" [894][ extern err] "/opt/infer-linux64-v1.1.0/lib/infer/infer/bin/../../facebook-clang-plugins/libtooling/build/FacebookClangPlugin.dylib" [894][ extern err] "-add-plugin" [894][ extern err] "BiniouASTExporter" [894][ extern err] "-plugin-arg-BiniouASTExporter" [894][ extern err] "-" [894][ extern err] "-plugin-arg-BiniouASTExporter" [894][ extern err] "PREPEND_CURRENT_DIR=1" [894][ extern err] "-plugin-arg-BiniouASTExporter" [894][ extern err] "MAX_STRING_SIZE=65535" [894][ extern err] "-cc1" "-triple" [894][ extern err] "x86_64-unknown-linux-gnu" [894][ extern err] "-emit-obj" [894][ extern err] "-disable-free" [894][ extern err] "-disable-llvm-verifier" [894][ extern err] "-discard-value-names" [894][ extern err] "-main-file-name" [894][ extern err] "nsf.c" [894][ extern err] "-mrelocation-model" [894][ extern err] "static" [894][ extern err] "-mframe-pointer=none" [894][ extern err] "-fmath-errno" [894][ extern err] "-fno-rounding-math" [894][ extern err] "-mconstructor-aliases" [894][ extern err] "-munwind-tables" [894][ extern err] "-target-cpu" [894][ extern err] "x86-64" [894][ extern err] "-fno-split-dwarf-inlining" [894][ extern err] "-debug-info-kind=limited" [894][ extern err] "-dwarf-version=4" [894][ extern err] "-debugger-tuning=gdb" [894][ extern err] "-resource-dir" [894][ extern err] "/opt/infer-linux64-v1.1.0/lib/infer/facebook-clang-plugins/clang/install/lib/clang/11.1.0" [894][ extern err] "-include" [894][ extern err] "/opt/infer-linux64-v1.1.0/lib/infer/infer/bin/../lib/clang_wrappers/global_defines.h" [894][ extern err] "-D" [894][ extern err] "PACKAGE_NAME=\"nsf\"" [894][ extern err] "-D" [894][ extern err] "PACKAGE_TARNAME=\"nsf\"" [894][ extern err] "-D" [894][ extern err] "PACKAGE_VERSION=\"2.4.0\"" [894][ extern err] "-D" [894][ extern err] "PACKAGE_STRING=\"nsf 2.4.0\"" [894][ extern err] "-D" [894][ extern err] "PACKAGE_BUGREPORT=\"https://sourceforge.net/p/next-scripting/tickets/\"" [894][ extern err] "-D" [894][ extern err] "PACKAGE_URL=\"\"" [894][ extern err] "-D" [894][ extern err] "HAVE_STDIO_H=1" [894][ extern err] "-D" [894][ extern err] "HAVE_STDLIB_H=1" [894][ extern err] "-D" [894][ extern err] "HAVE_STRING_H=1" [894][ extern err] "-D" [894][ extern err] "HAVE_INTTYPES_H=1" [894][ extern err] "-D" [894][ extern err] "HAVE_STDINT_H=1" [894][ extern err] "-D" [894][ extern err] "HAVE_STRINGS_H=1" [894][ extern err] "-D" [894][ extern err] "HAVE_SYS_STAT_H=1" [894][ extern err] "-D" [894][ extern err] "HAVE_SYS_TYPES_H=1" [894][ extern err] "-D" [894][ extern err] "HAVE_UNISTD_H=1" [894][ extern err] "-D" [894][ extern err] "STDC_HEADERS=1" [894][ extern err] "-D" [894][ extern err] "HAVE_INTPTR_T=1" [894][ extern err] "-D" [894][ extern err] "HAVE_UINTPTR_T=1" [894][ extern err] "-D" [894][ extern err] "BUILD_nsf=/**/" [894][ extern err] "-D" [894][ extern err] "HAVE_STRNSTR=1" [894][ extern err] "-D" "NO_VALUES_H=1" [894][ extern err] "-D" [894][ extern err] "HAVE_LIMITS_H=1" [894][ extern err] "-D" [894][ extern err] "HAVE_SYS_PARAM_H=1" [894][ extern err] "-D" [894][ extern err] "HAVE_TCL_COMPILE_H=1" [894][ extern err] "-D" [894][ extern err] "NSF_WITH_ASSERTIONS=1" [894][ extern err] "-D" "NSF_PROFILE=1" [894][ extern err] "-D" [894][ extern err] "NSF_DEVELOPMENT=1" [894][ extern err] "-D" [894][ extern err] "USE_THREAD_ALLOC=1" [894][ extern err] "-D" "_REENTRANT=1" [894][ extern err] "-D" [894][ extern err] "_THREAD_SAFE=1" [894][ extern err] "-D" "TCL_THREADS=1" [894][ extern err] "-D" [894][ extern err] "USE_TCL_STUBS=1" [894][ extern err] "-D" [894][ extern err] "USE_TCLOO_STUBS=1" [894][ extern err] "-D" [894][ extern err] "MODULE_SCOPE=extern __attribute__((__visibility__(\"hidden\")))" [894][ extern err] "-D" "HAVE_HIDDEN=1" [894][ extern err] "-D" [894][ extern err] "HAVE_CAST_TO_UNION=1" [894][ extern err] "-D" [894][ extern err] "TCL_WIDE_INT_IS_LONG=1" [894][ extern err] "-D" [894][ extern err] "USE_TCL_STUBS=1" [894][ extern err] "-D" [894][ extern err] "COMPILE_NSF_STUBS=1" [894][ extern err] "-D" [894][ extern err] "NSF_VERSION=\"2.4\"" [894][ extern err] "-D" [894][ extern err] "NSF_PATCHLEVEL=\"2.4.0\"" [894][ extern err] "-D" [894][ extern err] "NSF_COMMIT=\"2.3.0-204-g20b47273-dirty\"" [894][ extern err] "-I" [894][ extern err] "/usr/local/src/tcl-trunk/generic" [894][ extern err] "-I" [894][ extern err] "/usr/local/src/tcl-trunk/unix" [894][ extern err] "-I" [894][ extern err] "/Users/neumann/src/nsf2.3.0/generic" [894][ extern err] "-D" [894][ extern err] "TCL_NO_DEPRECATED" [894][ extern err] "-internal-isystem" [894][ extern err] "/usr/local/include" [894][ extern err] "-internal-isystem" [894][ extern err] "/opt/infer-linux64-v1.1.0/lib/infer/facebook-clang-plugins/clang/install/lib/clang/11.1.0/include" [894][ extern err] "-internal-externc-isystem" [894][ extern err] "/usr/include/x86_64-linux-gnu" [894][ extern err] "-internal-externc-isystem" [894][ extern err] "/include" [894][ extern err] "-internal-externc-isystem" [894][ extern err] "/usr/include" "-Os" [894][ extern err] "-Wall" [894][ extern err] "-Wconversion" [894][ extern err] "-Wsign-conversion" [894][ extern err] "-Wsign-compare" [894][ extern err] "-Wwrite-strings" [894][ extern err] "-Wextra" [894][ extern err] "-Wdeclaration-after-statement" [894][ extern err] "-Wendif-labels" [894][ extern err] "-Wshadow" [894][ extern err] "-Wmissing-prototypes" [894][ extern err] "-Wstrict-prototypes" [894][ extern err] "-Wpacked" [894][ extern err] "-Wno-redundant-decls" [894][ extern err] "-Wno-zero-length-array" [894][ extern err] "-Wmissing-braces" [894][ extern err] "-Wmissing-declarations" [894][ extern err] "-Wundef" [894][ extern err] "-Wunreachable-code" [894][ extern err] "-Wswitch-enum" [894][ extern err] "-Wpointer-arith" [894][ extern err] "-Wold-style-definition" [894][ extern err] "-Wmissing-format-attribute" [894][ extern err] "-Wformat-security" [894][ extern err] "-Wall" [894][ extern err] "-Wno-ignored-optimization-argument" [894][ extern err] "-Wno-everything" [894][ extern err] "-pedantic" [894][ extern err] "-std=c99" [894][ extern err] "-fconst-strings" [894][ extern err] "-fdebug-compilation-dir" [894][ extern err] "/nsf" [894][ extern err] "-ferror-limit" "19" [894][ extern err] "-fgnuc-version=4.2.1" [894][ extern err] "-vectorize-loops" [894][ extern err] "-vectorize-slp" [894][ extern err] "-o" "nsf.o" "-x" [894][ extern err] "c" [894][ extern err] "./generic/nsf.c" [894][ extern err] "-O0" "-include" [894][ extern err] "/opt/infer-linux64-v1.1.0/lib/infer/infer/bin/../lib/clang_wrappers/global_defines.h" [894][ extern err] "-Wno-everything" [894][ extern err] [894][ extern err] [894][environment] Scheduler: file [894][environment] Cores used: 8 [894][environment] [889][ extern err] *** capture command failed: *** make *** exited with code 2 [889][ extern err] Raised at Stdlib__scanf.bad_input in file "scanf.ml" (inlined), line 444, characters 18-40 Called from Stdlib__scanf.scanf_bad_input in file "scanf.ml", line 1164, characters 4-75 Called from IBase__Utils.get_available_memory_MB.scan_for_expected_output in file "src/base/Utils.ml", line 447, characters 10-86 [890][ debug] Sqlite write daemon: terminating ./nsf2.4.0/infer-out/tmp/clang_command_.tmp.e307ea.txt000600 000766 000024 00000006443 14271435441 023150 0ustar00neumannstaff000000 000000 "-cc1" "-load" "/opt/infer-linux64-v1.1.0/lib/infer/infer/bin/../../facebook-clang-plugins/libtooling/build/FacebookClangPlugin.dylib" "-add-plugin" "BiniouASTExporter" "-plugin-arg-BiniouASTExporter" "-" "-plugin-arg-BiniouASTExporter" "PREPEND_CURRENT_DIR=1" "-plugin-arg-BiniouASTExporter" "MAX_STRING_SIZE=65535" "-cc1" "-triple" "x86_64-unknown-linux-gnu" "-emit-obj" "-disable-free" "-disable-llvm-verifier" "-discard-value-names" "-main-file-name" "nsf.c" "-mrelocation-model" "static" "-mframe-pointer=none" "-fmath-errno" "-fno-rounding-math" "-mconstructor-aliases" "-munwind-tables" "-target-cpu" "x86-64" "-fno-split-dwarf-inlining" "-debug-info-kind=limited" "-dwarf-version=4" "-debugger-tuning=gdb" "-resource-dir" "/opt/infer-linux64-v1.1.0/lib/infer/facebook-clang-plugins/clang/install/lib/clang/11.1.0" "-include" "/opt/infer-linux64-v1.1.0/lib/infer/infer/bin/../lib/clang_wrappers/global_defines.h" "-D" "PACKAGE_NAME=\"nsf\"" "-D" "PACKAGE_TARNAME=\"nsf\"" "-D" "PACKAGE_VERSION=\"2.4.0\"" "-D" "PACKAGE_STRING=\"nsf 2.4.0\"" "-D" "PACKAGE_BUGREPORT=\"https://sourceforge.net/p/next-scripting/tickets/\"" "-D" "PACKAGE_URL=\"\"" "-D" "HAVE_STDIO_H=1" "-D" "HAVE_STDLIB_H=1" "-D" "HAVE_STRING_H=1" "-D" "HAVE_INTTYPES_H=1" "-D" "HAVE_STDINT_H=1" "-D" "HAVE_STRINGS_H=1" "-D" "HAVE_SYS_STAT_H=1" "-D" "HAVE_SYS_TYPES_H=1" "-D" "HAVE_UNISTD_H=1" "-D" "STDC_HEADERS=1" "-D" "HAVE_INTPTR_T=1" "-D" "HAVE_UINTPTR_T=1" "-D" "BUILD_nsf=/**/" "-D" "HAVE_STRNSTR=1" "-D" "NO_VALUES_H=1" "-D" "HAVE_LIMITS_H=1" "-D" "HAVE_SYS_PARAM_H=1" "-D" "HAVE_TCL_COMPILE_H=1" "-D" "NSF_WITH_ASSERTIONS=1" "-D" "NSF_PROFILE=1" "-D" "NSF_DEVELOPMENT=1" "-D" "USE_THREAD_ALLOC=1" "-D" "_REENTRANT=1" "-D" "_THREAD_SAFE=1" "-D" "TCL_THREADS=1" "-D" "USE_TCL_STUBS=1" "-D" "USE_TCLOO_STUBS=1" "-D" "MODULE_SCOPE=extern __attribute__((__visibility__(\"hidden\")))" "-D" "HAVE_HIDDEN=1" "-D" "HAVE_CAST_TO_UNION=1" "-D" "TCL_WIDE_INT_IS_LONG=1" "-D" "USE_TCL_STUBS=1" "-D" "COMPILE_NSF_STUBS=1" "-D" "NSF_VERSION=\"2.4\"" "-D" "NSF_PATCHLEVEL=\"2.4.0\"" "-D" "NSF_COMMIT=\"2.3.0-204-g20b47273-dirty\"" "-I" "/usr/local/src/tcl-trunk/generic" "-I" "/usr/local/src/tcl-trunk/unix" "-I" "/Users/neumann/src/nsf2.3.0/generic" "-D" "TCL_NO_DEPRECATED" "-internal-isystem" "/usr/local/include" "-internal-isystem" "/opt/infer-linux64-v1.1.0/lib/infer/facebook-clang-plugins/clang/install/lib/clang/11.1.0/include" "-internal-externc-isystem" "/usr/include/x86_64-linux-gnu" "-internal-externc-isystem" "/include" "-internal-externc-isystem" "/usr/include" "-Os" "-Wall" "-Wconversion" "-Wsign-conversion" "-Wsign-compare" "-Wwrite-strings" "-Wextra" "-Wdeclaration-after-statement" "-Wendif-labels" "-Wshadow" "-Wmissing-prototypes" "-Wstrict-prototypes" "-Wpacked" "-Wno-redundant-decls" "-Wno-zero-length-array" "-Wmissing-braces" "-Wmissing-declarations" "-Wundef" "-Wunreachable-code" "-Wswitch-enum" "-Wpointer-arith" "-Wold-style-definition" "-Wmissing-format-attribute" "-Wformat-security" "-Wall" "-Wno-ignored-optimization-argument" "-Wno-everything" "-pedantic" "-std=c99" "-fconst-strings" "-fdebug-compilation-dir" "/nsf" "-ferror-limit" "19" "-fgnuc-version=4.2.1" "-vectorize-loops" "-vectorize-slp" "-o" "nsf.o" "-x" "c" "./generic/nsf.c" "-O0" "-include" "/opt/infer-linux64-v1.1.0/lib/infer/infer/bin/../lib/clang_wrappers/global_defines.h" "-Wno-everything" ./nsf2.4.0/infer-out/tmp/clang_command_.tmp.f6d95c.txt000600 000766 000024 00000003616 14271435435 023166 0ustar00neumannstaff000000 000000 '-###' '-DPACKAGE_NAME="nsf"' '-DPACKAGE_TARNAME="nsf"' '-DPACKAGE_VERSION="2.4.0"' '-DPACKAGE_STRING="nsf 2.4.0"' '-DPACKAGE_BUGREPORT="https://sourceforge.net/p/next-scripting/tickets/"' '-DPACKAGE_URL=""' '-DHAVE_STDIO_H=1' '-DHAVE_STDLIB_H=1' '-DHAVE_STRING_H=1' '-DHAVE_INTTYPES_H=1' '-DHAVE_STDINT_H=1' '-DHAVE_STRINGS_H=1' '-DHAVE_SYS_STAT_H=1' '-DHAVE_SYS_TYPES_H=1' '-DHAVE_UNISTD_H=1' '-DSTDC_HEADERS=1' '-DHAVE_INTPTR_T=1' '-DHAVE_UINTPTR_T=1' '-DBUILD_nsf=/**/' '-DHAVE_STRNSTR=1' '-DNO_VALUES_H=1' '-DHAVE_LIMITS_H=1' '-DHAVE_SYS_PARAM_H=1' '-DHAVE_TCL_COMPILE_H=1' '-DNSF_WITH_ASSERTIONS=1' '-DNSF_PROFILE=1' '-DNSF_DEVELOPMENT=1' '-DUSE_THREAD_ALLOC=1' '-D_REENTRANT=1' '-D_THREAD_SAFE=1' '-DTCL_THREADS=1' '-DUSE_TCL_STUBS=1' '-DUSE_TCLOO_STUBS=1' '-DMODULE_SCOPE=extern __attribute__((__visibility__("hidden")))' '-DHAVE_HIDDEN=1' '-DHAVE_CAST_TO_UNION=1' '-DTCL_WIDE_INT_IS_LONG=1' '-DUSE_TCL_STUBS=1' '-DCOMPILE_NSF_STUBS=1' '-DNSF_VERSION="2.4"' '-DNSF_PATCHLEVEL="2.4.0"' '-DNSF_COMMIT="2.3.0-204-g20b47273-dirty"' '-I/usr/local/src/tcl-trunk/generic' '-I/usr/local/src/tcl-trunk/unix' '-I/Users/neumann/src/nsf2.3.0/generic' '-Os' '-Wall' '-pipe' '-pedantic' '-g' '-std=c99' '-DTCL_NO_DEPRECATED' '-Wconversion' '-Wsign-conversion' '-Wsign-compare' '-Wwrite-strings' '-Wextra' '-Wdeclaration-after-statement' '-Wendif-labels' '-Wshadow' '-Wmissing-prototypes' '-Wstrict-prototypes' '-Wpacked' '-Wno-redundant-decls' '-Wno-zero-length-array' '-Wmissing-braces' '-Wmissing-declarations' '-Wundef' '-Wunreachable-code' '-Wswitch-enum' '-Wpointer-arith' '-Wold-style-definition' '-Wmissing-format-attribute' '-Wformat-security' '-Wall' '-fno-common' '-c' './generic/nsf.c' '-o' 'nsf.o' '-fno-cxx-modules' '-Qunused-arguments' '-Wno-ignored-optimization-argument' '-fno-addrsig' '-fembed-bitcode=off' '-include' '/opt/infer-linux64-v1.1.0/lib/infer/infer/bin/../lib/clang_wrappers/global_defines.h' '-Wno-everything' ./nsf2.4.0/infer-out/tmp/clang_command_.tmp.4a0147.txt000600 000766 000024 00000006443 14271435435 023007 0ustar00neumannstaff000000 000000 "-cc1" "-load" "/opt/infer-linux64-v1.1.0/lib/infer/infer/bin/../../facebook-clang-plugins/libtooling/build/FacebookClangPlugin.dylib" "-add-plugin" "BiniouASTExporter" "-plugin-arg-BiniouASTExporter" "-" "-plugin-arg-BiniouASTExporter" "PREPEND_CURRENT_DIR=1" "-plugin-arg-BiniouASTExporter" "MAX_STRING_SIZE=65535" "-cc1" "-triple" "x86_64-unknown-linux-gnu" "-emit-obj" "-disable-free" "-disable-llvm-verifier" "-discard-value-names" "-main-file-name" "nsf.c" "-mrelocation-model" "static" "-mframe-pointer=none" "-fmath-errno" "-fno-rounding-math" "-mconstructor-aliases" "-munwind-tables" "-target-cpu" "x86-64" "-fno-split-dwarf-inlining" "-debug-info-kind=limited" "-dwarf-version=4" "-debugger-tuning=gdb" "-resource-dir" "/opt/infer-linux64-v1.1.0/lib/infer/facebook-clang-plugins/clang/install/lib/clang/11.1.0" "-include" "/opt/infer-linux64-v1.1.0/lib/infer/infer/bin/../lib/clang_wrappers/global_defines.h" "-D" "PACKAGE_NAME=\"nsf\"" "-D" "PACKAGE_TARNAME=\"nsf\"" "-D" "PACKAGE_VERSION=\"2.4.0\"" "-D" "PACKAGE_STRING=\"nsf 2.4.0\"" "-D" "PACKAGE_BUGREPORT=\"https://sourceforge.net/p/next-scripting/tickets/\"" "-D" "PACKAGE_URL=\"\"" "-D" "HAVE_STDIO_H=1" "-D" "HAVE_STDLIB_H=1" "-D" "HAVE_STRING_H=1" "-D" "HAVE_INTTYPES_H=1" "-D" "HAVE_STDINT_H=1" "-D" "HAVE_STRINGS_H=1" "-D" "HAVE_SYS_STAT_H=1" "-D" "HAVE_SYS_TYPES_H=1" "-D" "HAVE_UNISTD_H=1" "-D" "STDC_HEADERS=1" "-D" "HAVE_INTPTR_T=1" "-D" "HAVE_UINTPTR_T=1" "-D" "BUILD_nsf=/**/" "-D" "HAVE_STRNSTR=1" "-D" "NO_VALUES_H=1" "-D" "HAVE_LIMITS_H=1" "-D" "HAVE_SYS_PARAM_H=1" "-D" "HAVE_TCL_COMPILE_H=1" "-D" "NSF_WITH_ASSERTIONS=1" "-D" "NSF_PROFILE=1" "-D" "NSF_DEVELOPMENT=1" "-D" "USE_THREAD_ALLOC=1" "-D" "_REENTRANT=1" "-D" "_THREAD_SAFE=1" "-D" "TCL_THREADS=1" "-D" "USE_TCL_STUBS=1" "-D" "USE_TCLOO_STUBS=1" "-D" "MODULE_SCOPE=extern __attribute__((__visibility__(\"hidden\")))" "-D" "HAVE_HIDDEN=1" "-D" "HAVE_CAST_TO_UNION=1" "-D" "TCL_WIDE_INT_IS_LONG=1" "-D" "USE_TCL_STUBS=1" "-D" "COMPILE_NSF_STUBS=1" "-D" "NSF_VERSION=\"2.4\"" "-D" "NSF_PATCHLEVEL=\"2.4.0\"" "-D" "NSF_COMMIT=\"2.3.0-204-g20b47273-dirty\"" "-I" "/usr/local/src/tcl-trunk/generic" "-I" "/usr/local/src/tcl-trunk/unix" "-I" "/Users/neumann/src/nsf2.3.0/generic" "-D" "TCL_NO_DEPRECATED" "-internal-isystem" "/usr/local/include" "-internal-isystem" "/opt/infer-linux64-v1.1.0/lib/infer/facebook-clang-plugins/clang/install/lib/clang/11.1.0/include" "-internal-externc-isystem" "/usr/include/x86_64-linux-gnu" "-internal-externc-isystem" "/include" "-internal-externc-isystem" "/usr/include" "-Os" "-Wall" "-Wconversion" "-Wsign-conversion" "-Wsign-compare" "-Wwrite-strings" "-Wextra" "-Wdeclaration-after-statement" "-Wendif-labels" "-Wshadow" "-Wmissing-prototypes" "-Wstrict-prototypes" "-Wpacked" "-Wno-redundant-decls" "-Wno-zero-length-array" "-Wmissing-braces" "-Wmissing-declarations" "-Wundef" "-Wunreachable-code" "-Wswitch-enum" "-Wpointer-arith" "-Wold-style-definition" "-Wmissing-format-attribute" "-Wformat-security" "-Wall" "-Wno-ignored-optimization-argument" "-Wno-everything" "-pedantic" "-std=c99" "-fconst-strings" "-fdebug-compilation-dir" "/nsf" "-ferror-limit" "19" "-fgnuc-version=4.2.1" "-vectorize-loops" "-vectorize-slp" "-o" "nsf.o" "-x" "c" "./generic/nsf.c" "-O0" "-include" "/opt/infer-linux64-v1.1.0/lib/infer/infer/bin/../lib/clang_wrappers/global_defines.h" "-Wno-everything" ./nsf2.4.0/infer-out/.infer_runstate.json000644 000766 000024 00000002355 14271435435 021116 0ustar00neumannstaff000000 000000 {"run_sequence":[{"date":"2022-07-31 08:19:41.181599Z","command":"run","infer_version":{"major":1,"minor":1,"patch":0,"commit":"f9b6f2b"}}],"results_dir_format":"db_filename: infer-out/results.db\ndb_schema: \n CREATE TABLE IF NOT EXISTS procedures\n ( proc_uid TEXT PRIMARY KEY NOT NULL\n , proc_name BLOB NOT NULL\n , attr_kind INTEGER NOT NULL\n , source_file TEXT NOT NULL\n , proc_attributes BLOB NOT NULL\n , cfg BLOB\n , callees BLOB NOT NULL\n )\n ;\n\n CREATE TABLE IF NOT EXISTS source_files\n ( source_file TEXT PRIMARY KEY\n , type_environment BLOB NOT NULL\n , integer_type_widths BLOB\n , procedure_names BLOB NOT NULL\n , freshly_captured INT NOT NULL )\n ;\n\n CREATE TABLE IF NOT EXISTS specs\n ( proc_uid TEXT PRIMARY KEY NOT NULL\n , proc_name BLOB NOT NULL\n , analysis_summary BLOB NOT NULL\n , report_summary BLOB NOT NULL\n )\n ;\n\n CREATE TABLE IF NOT EXISTS model_specs\n ( proc_uid TEXT PRIMARY KEY NOT NULL\n , proc_name BLOB NOT NULL\n , analysis_summary BLOB NOT NULL\n , report_summary BLOB NOT NULL\n )\n ","should_merge_capture":false}./nsf2.4.0/ChangeLog-2.3.0-2.4.0.log000644 000766 000024 00000064350 14275417765 016651 0ustar00neumannstaff000000 000000 2022-08-11 Gustaf Neumann * nsf.c (Nsf_ObjSetVar2): Address the maybe-uninitialized warnings. I do not really like the approach based on pragmas, but i do even less like the warnings, when compiled with -pedantic [c8791939] 2022-08-10 Gustaf Neumann *Announce2.4.0: Tested with recent MongoDB (server 5.0.9, driver 1.22.1) [f20c1eaf] * nsf.c (VarHashTableCreate, DStringAppendQualName) (NewTclCommand): Reduced compiler warnings when compiling against Tcl 8.6* with TIDY settings. [286401d1] * nsf.c (ObjectDispatch): Deactivate block for double-checking cached data for Tcl commands. Leave the code for potential future debugging purposes. [4808f8e3] 2022-08-09 Gustaf Neumann * next-tutorial.txt: Improve spelling [dc9c6c5d] * ChangeLog-2.3.0-2.4.0.log, Announce2.0b3, Announce-1.3.5: Improve spelling [e2998b4f] 2022-08-09 Stefan Sobernig * next-tutorial, next-migration: Fix version number [51fc6ac1] * mkIndex.tcl: Have mkIndex produce package-provide compliant ifneeded scripts [5bd3de95] * Makefile.in, configure: Re-worked pkgIndex.tcl handling [aa25ce85] * README.release: Document changes to doc pipeline [8f63a682] * doc/: Re-generated man pages and tutorials [f63b1bb9] * Makefile.in, doc/*.css: Replace prince with Chrome headless for PDF doc generation, PDF-specific CSS now organized as @media print queries. [6f2b5aab] 2022-08-08 Stefan Sobernig * doc/Announce2.4.0: Cont'd [skip ci] [297884f8] * ChangeLog-2.3.0-2.4.0.log: Added entries since late Jan 2021 [skip ci] [af95cd6e] 2022-08-07 Stefan Sobernig * tcl86.test, nsf-cmd.test, forward.test, destroy.test: Make sure to run all 8.6+/ 8.7+ specific tests also under Tcl 9 [982b1e8d] 2022-08-06 Stefan Sobernig * rules.vc: Have TCL_MAJOR_VERSION properly picked up from newer tcl.h via nmakehlp [d55aa4b7] * makefile.vc: Make sure Tcl 9 handles TIP-595 guessing of the _Init function, avoid third argument to load [58a12e0d] 2022-07-31 Gustaf Neumann * nsfDebug.c, nsfPointer.c: Minor polishing [9f2bb394] 2022-07-29 Gustaf Neumann * build.tcl: Turn on debugging (AppVeyor) [e4569ae5, 0f2f3c4f, c18dacc8, 584687ed] 2022-07-29 Stefan Sobernig * build.tcl: Turn on debugging (AppVeyor) [b59caea3, 01ff609d, a0d10764, 58cb7088, 64ce7231]; try using 7z instead of internal unpacking [00ac4c06] 2022-07-29 Gustaf Neumann * nsfAccessInt.h: Fix comment [58c09af3] * mongodb/m4/tcl.m4, tcl.m4: Revert back to earlier version of tcl.m4; The version from head is not yet ready [d1bea33b] * configure, mongodb/configure: Re-generated files [52070e0d] 2022-07-29 Stefan Sobernig * build.tcl: Turn on more debugging output [dd6a0a0b] 2022-07-29 Gustaf Neumann * mongodb/README.md: update README for mongoDB interface [20b47273] * mongodb/configure: re-generated file [28349668] * Makefile.in: Fix line break [bbb3b835] * tcl.m4, mongodb/m4/tcl.m4: Updated with upstream versions of tcl.m4 [1ddf01fe, a817b85f, 3137543b, afda2d90] * nsfStubLib.c (Nsf_InitStubs): Fix compilation hickups for Tcl 8.5 [8c0fd2cd] 2022-07-27 Gustaf Neumann * nsf.h, nsfInt.h: Reduce warnings from redefined constants [fc37052d] * configure, mongodb/configure: Re-generated files [fb1613b4] * Makefile.in: Don't include "package provide" Tcl command in pkgIndex.tcl file, since the binary performs the provide operation [86365e57] * mkIndex.tcl: Exclude pkgIndex.tcl from searched files, whitespace changes [e2825dd0] 2022-07-27 Gustaf Neumann * Makefile.in: Pack Tcl version into name for Tcl 9.* With Tcl 9, it is possible to install NSF for 8.7 and 9.0 in parallel, in the same directories. The trick is naming the shared library "libtcl9nsf2.4.0.so" instead of "libnsf2.4.0.so" when compiled with Tcl 9.0 (keeping the original name when compiled with Tcl 8.x). Many thanks to Jan Nijtmans for the patch. [0b577d09] 2022-07-20 Stefan Sobernig * appveyor.yml: Allow failures on trunk builds [a0e21882] 2022-07-17 Stefan Sobernig * build.yml: Remove build jobs for 8-7-a3 (GH and AppVeyor); add trunk builds for win (AppVeyor) [9a007250] 2022-07-06 Gustaf Neumann * build.yml: Added GitHub event for workflow dispatches [42704e31]; cosmetic change to trigger workflow run [d661abd3]; added build for tcl9 under macOS [8515b3d2]; added build for Tcl 9 (branch trunk) [1b526520] * nsfAccessInt.h: Fix typo [5e66d95c] * nsf.h, nsfAccessInt.h: Improve compatibility with core-8 branch [2db70d13]; fix for Tcl versions having Tcl_LibraryInitProc() already defined (core-8-branch) [4501d2e2] * object-system.test: Report Tcl version at the begin of regression test to ease reading output of Git workflows [f546d287] * nsf.h: Provide compatibility for core-8-7-a3 [e7b25cd9] * nsfAccessInt.h: fix compatibility with earlier versions of Tcl 8.7 [1a327d6a] * nsf.c (ParseContextExtendObjv, AssertionCheck, ListMethod) (NsfMethodPropertyCmd, NsfCurrentCmd, NsfRelationSetCmd), nsfInt.h: Improve cleanness of compilation under gcc-11+ and "-pedantic" + -Wextra" [958b24f9] 2022-07-05 Gustaf Neumann * Makefile.in, generic/nsf*.c, generic/nsf*.h, generic/stubs9.0/*, nsfmongo.c: Added support for compiling with Tcl 9.0 (Many Thanks to Jan Nijtmans for first steps) This version compiles cleanly at least with Tcl 8.6.* and Tcl 9.0 (fossil main) having -pedantic and -Wextra defined. [e48161ab] 2022-04-29 Stefan Sobernig * ChangeLog-2.3.0-2.4.0.log: Adding changelog entries since July/ August 2021. [9b3cf1ba] 2022-01-22 Gustaf Neumann * next-migration.txt, next-tutorial.txt: Improve spelling [a1996616] * nsf.c (NsfParseArgsCmd): Cleanup to avoid memory leak in cases the Tcl_DictObjPut fails [e3f1c112] 2022-01-21 Gustaf Neumann * nsf.c (NsfParseArgsCmd): Added option "-asdict" to nsf::parseargs. The new option makes it easier to process the parsed argument in different contexts [b2781b9d] 2022-01-18 Stefan Sobernig * build.yml, appveyor.yml: Bumps to 8.6.12 and 8.7a5 [96f4eb32] 2022-01-03 Gustaf Neumann * nsf.c (ListMethodKeys), nx.tcl, class-method.test, methods.test, plain-object-method.test: Include alias to object in "info methods -path" Previously, it was not possible to define an alias to an object for NaviServer, since it was not returned by "info methods -path" and was, therefore, not included into the blueprint. Extended regression tests. [40b842e5] 2021-12-03 Gustaf Neumann * nsf.c (CallStackDoDestroy): Improve function description [344ce3ff] 2021-10-16 Gustaf Neumann * object-system.test: Fix broken test [8fe8acb5] 2021-10-12 Stefan Sobernig * nsfAccessInt.h (TclFreeIntRep): A recent name reform requires an explicit define for backwards compat. [7645e8f8] * nx-zip.tcl: Add closing paren in comment [8bb94eca] 2021-10-08 Stefan Sobernig * nx-zip.tcl (writeToZipFile): 'writeToStream' requires a command prefixed defined by an object variable 'writer'. In a direct call on 'writeToZipFile', this variable was not defined. Thanks to Héctor Romojaro for the catch and patch. [2a99a6a1] 2021-09-01 Gustaf Neumann s * nx-zip.tcl: Use buffered ns_connchan for writing to slow channels for handling partial write operations properly [d82ed6ca] 2021-08-23 Gustaf Neumann * Makefile.in: Make it possible to pass "CFLAGS_OPTIMIZE=..." to Makefile [379ac9a3] 2021-08-12 Gustaf Neumann * nsf.c, nsf.h (NsColonVarResolver): Remove relatively costly asserts when not in development mode [f01f68ea] 2021-07-26 Stefan Sobernig * README.release: Complete description of vagrant setup [f826efe9] 2021-07-25 Stefan Sobernig * nsf.c (ObjectDispatch): Fix another invalid read of a cached cmd structure (NsfColonCommandContext) [da6d8cc3] 2021-07-24 Stefan Sobernig * nsf.c (NsfUnsetTrace, VolatileMethod): Plug a post-mortem memleak related to volatile objects (The Tcl_Obj carrying an auto-qualified object name was not cleaned up properly during interp shutdown because the matching decrement operations used to be disabled during shutdown.) [fc14b058] * nsf.c (ObjectDispatch): Fix invalid read as indicated by valgrind by guarding access to intrep. [a6e4b1ad] * README.release: Describe valgrind via vagrant procedure [304b0654] 2021-07-23 Stefan Sobernig * nsf.c (ObjectDispatch): First attempt to fight valgrind warning on cond/uninitialized jump [f4077b42] * ChangeLog-2.3.0-2.4.0.log: Completed changelog work [a3149d6b] 2021-07-21 Stefan Sobernig * README.release: Add note on using gnulibs' gitlog-to-changelog [999de5b9] 2021-07-14 Gustaf Neumann * nx-zip.tcl: Added support for returning streaming zip files via HTTPS. The old version was just replying via ns_write, which can be only used for plain TCP connections (no TLS). [4f198095] 2021-07-08 Gustaf Neumann * nsf.c (MakeProc): Fixed false positive from facebook infer 1.1.0 [2b630211] 2021-06-23 Gustaf Neumann * ChangeLog-*.log: Improved spelling [b431d2c0] * nsf.c: Reduced warnings from clang12 static checker (null value passed to non-null arguments, dead assignment, ...) [e791865c] 2021-06-09 Stefan Sobernig * build.yml, appveyor.yml: Add 8.7a5 branch to build matrices. [2a01cc6f] * nsf.c (Nsf_Init): Plumb a small memory leak due to not clearing mp_int data. Make sure _not_ to use mp_clear (TIP 538). [5338fea8] * ChangeLog-2.3.0-2.4.0.log, Announce2.4.0: Continued work on release files [63b2e82e] 2021-06-05 Gustaf Neumann * nsfmongo.c, nsf.c: Update copyright dates [6b1f85df] * nsfmongo.c: Minor cleanup: reduce strlen operations, reduce hard-coded constants, perfer Tcl_Obj based interfaces of string based ones (opens opportunities for special objtypes) [725dc72f] 2021-05-25 Gustaf Neumann * nsf.c (ParamOptionParse): Do not support predefined parameter options spelled with trailing content This change makes argument type checking more strict by rejecting names as synonyms which are longer than the specified values. Background: Previous versions did not handle cases correctly where an application type name starts with the same characters as a built-in type. So it was not possible to define a type "object_id", since a a spec of the form "x:object_id" was interpreted as "x:object". [9bc1a996] 2021-05-13 Stefan Sobernig * build.yml: clang 11 is default on macos-latest runners; add remaining macos configs [f29f3c69] * build.yml: Fix expressions [cf79aef0] * build.yml: Remove artifacts from workflow [4f7b34fe] * build.yml: Added initial GitHub Actions workflow enabling Linux and macOS builds [e372b812] 2021-05-12 Stefan Sobernig * appveyor.yml: Bump build matrix to include the tag 8.6.11 [7bb2abc4] 2021-05-11 Stefan Sobernig * nsfAccessInt.h (TclIsCommandDeleted), nsf.c, nsfObj.c: More recent Tcl 8.7 (starting Sep 2020) has replaced the macro CMD_IS_DELETED by CMD_DYING. [e01e3055] 2021-05-05 Stefan Sobernig * nsf.c (ParamOptionParse): Simplify option parsing for substdefault; Tcl_GetInt knows how to handle 0b binary constants, no expr call needed. [9e705a33] * nsf.c (VolatileMethod): Save a little by checking first chars [eb3b441c] 2021-05-02 Stefan Sobernig * nsf.c (VolatileMethod), volatile.test: Fix volatile for XOTcl 2: frame skipping must be limited to configure, otherwise, for self calls (e.g., 'my volatile'), the sentinel variable plus unset trace become created in the wrong callframe context (leading to corruption of any non-proc callframe); added test cases [3916bf00] 2021-02-17 Gustaf Neumann * nsfProfile.c (NsfProfileDebugExit): Fix provided length values for string arguments [460ae16a] 2021-02-06 Gustaf Neumann * nx.tcl: Whitespace cleanup (replace tabs) [75f60be7] * nx.tcl: Make warning message more precise about unexpected slot structures during delete [473a993c] 2021-01-03 Gustaf Neumann * Makefile.in: Added target for clang-tidy, fine-tuning of compile flags [e3c98331] * generic/nsf.c, generic/nsf.h, generic/nsfAPI.decls, generic/nsfAPI.h, generic/nsfInt.h, library/mongodb/mongoAPI.h: Added enumeration values [f0f87b41] * gentclAPI.tcl: Added support for enumeration values replaced anonymous arrays by dicts [91a7b7d1] 2021-01-02 Gustaf Neumann * generic/gentclAPI.tcl, generic/nsfAPI.h: Improve type safety of generated code [deed56d5] * generic/*/*.h: Reduced usage of reserved identifiers: cert-dcl37-c, cert-dcl51-cpp [65d1c0f8] * generic/aolstub.c, generic/asm/asmAssembleTemplate.c, generic/asm/nsfAsmAssemble.c, generic/nsf.c, generic/nsfObj.c, generic/nsfProfile.c, generic/nsfStack.c: Improve comments and spelling [84ebec01] * generic/*/*.c: Improve regularity and linebreaking in comments, mostly in function headers [42dbfd5d] 2021-01-01 Gustaf Neumann * generic/*/*.c: Whitespace changes: more consistent indentation of comments [83e2a1bc] * doc/next-migration.txt, doc/next-tutorial/next-tutorial.txt, generic/predefined_part1.tcl, generic/predefined_part2.tcl: Improve spelling [18b65162] 2020-10-28 Gustaf Neumann * nsf.c (ObjectDispatch): Add one more test to sanity check [a4cc4075]; added debugging output for a case, where a Tcl cmd looks perfectly fine, but its procPtr (scripted cases) contains invalid data [57eb831d] * nx.tcl: Reduce debugging output [226d979a] 2020-10-27 Gustaf Neumann * nsf.c, nsf.h, nsfInt.h, nsfStubLib.c: Make clean compile, when TRACE flags are defined [a422e30c] 2020-10-21 Gustaf Neumann * nsf.c (MethodDispatchCsc, ComputeLevelObj): Reduce verbosity, silence checker [77a6f178] * doc/*.man: Improve spelling [be71d48c] * nsf.c (NsfDebugGetDict): Use memmove() instead of strncat() since the former supports overlapping buffers. [c72f84a5] 2020-08-31 Gustaf Neumann * nsf.c (Nsf_Init): Do not try to initialize Tcl_TomMath_InitStubs when TCL_MAJOR_VERSION > 8 || TCL_MINOR_VERSION > 6 [4bd7db4e] * nsf.c (Nsf_ConvertToInt32): Include for Tcl 8.5 tclTomMath.h to define the mp_int type [61c07a2b]; check, if the flag MP_INT_DECLARED is defined in 8.7* builds [f3258689] * nsf.c (Nsf_ConvertToInteger): Avoid creation of Tcl_NewBignumObj() when argument is already of the bignum type [9d4daad1]; added mp_int type definion for Tcl >= 8.7 see: https://core.tcl-lang.org/tcl/tktview/4663e0636f7a24b9363e67c7a3dd25e9e495be17 [e157ce6c]; getting rid of mp_free (we still need the type for mp_int) [0e957261] 2020-08-30 Stefan Sobernig * win/rules.vc: Starting with recent 8.7, there is no 't' suffix appended to binaries and libs anymore, to indicate a threaded build. [c5097786] 2020-08-28 Stefan Sobernig * appveyor.yml: Use newer VS image [77053610, 9647540c, 7c4a1425,d8bc09f6, db9147b0,8d4ac524] 2020-08-19 Gustaf Neumann * README.profile: Added readme document on profiling [e40a0652] * Connection.xotcl, xodoc.xotcl: Improve spelling [dc6b2eb2] * slottest.xotcl, testx.xotcl: Avoid overly short method names [c493c042] 2020-08-07 Gustaf Neumann * doc/next-tutorial/next-tutorial.txt, generic/asm/nsfAssemble.c, generic/nsfError.c: Improve spelling [d25e6ec7] 2020-07-02 Gustaf Neumann * doc/example-scripts/per-object-mixins.tcl, doc/example-scripts/rosetta-add-variable.tcl, doc/example-scripts/rosetta-multiple-distinct.tcl, doc/next-migration.txt, doc/next-tutorial/next-tutorial.txt, generic/nsf.c, generic/nsfInt.h, generic/nsfStack.c, library/lib/nx-shell.tcl, library/lib/nx-zip.tcl, library/mongodb/nsfmongo.c, library/mongodb/tests/nsf-gridfs.test, library/serialize/serializer.tcl, tests/alias.test, tests/disposition.test, tests/doc.test, tests/methods.test, tests/parameters.test, tests/shells.test, tests/tcloo.test: Improve spelling by moving closer to the Linux documentation recommendations [78c12b94] * Makefile.in, library/mongodb/Makefile.in: Reduce useless output of "make test" [754d1562] 2020-06-11 Gustaf Neumann * doc/next-migration.txt, doc/next-tutorial/next-tutorial.txt, library/lib/make.tcl, tests/parameters.test: Improve spelling [30864532] 2020-05-29 Stefan Sobernig * nsf.c (Nsf_ConvertToInteger): Use Jan's hot fix TCL_NO_TOMMATH_H, not yet integrated into Tcl's 8.7 branch. [0aae1296] 2020-05-15 Stefan Sobernig * build.tcl: Force use of internal libtommath (TIP 538) in 8.7 builds [5a80e290] * .travis.yml: Bump Travis macOS image and use gcc-9 [6259567b] 2020-03-21 Gustaf Neumann * nsf.c (NsfMethodAliasCmd, ProtectionMatches): Make sure, variable is always initialized [6ef097d5, 053960da] 2020-03-09 Gustaf Neumann * generic/nsf.c, generic/nsfEnumerationType.c, generic/nsfPointer.c, generic/nsfStack.c, tests/methods.test, tests/nsf-cmd.test, tests/parameters.test: Improve spelling [5bcb005e] 2020-02-18 Gustaf Neumann * generic/nsf.c, library/lib/nx-zip.tcl: Improve spelling [10011595] 2020-02-06 Gustaf Neumann * xotcl2.tcl: Add object level method "dict" similar to "array" for larger symmetry of commands [34c85637] 2019-12-09 Gustaf Neumann * doc/example-scripts/rosetta-constraint-genericity.tcl, doc/example-scripts/rosetta-delegates.tcl, doc/example-scripts/ruby-mixins.tcl, doc/next-migration.txt, doc/next-tutorial/next-tutorial.txt, generic/nsf.c, library/xotcl/library/xotcl2.tcl: Improve spelling [a11d866d] * nsfDebug.c (NsfStackDump): Remove redundant tests [a77455e1] 2019-11-25 Stefan Sobernig * .travis.yml, appveyor.xml: Updates to build descriptors (incl. new Tcl release tags) [d2a20690, e1be9ee9, 9808a2f3] 2019-11-21 Gustaf Neumann * library/nx/nx.tcl, library/xotcl/doc/langRef.xotcl, library/xotcl/tests/slottest.xotcl, library/xotcl/tests/testx.xotcl: Improve spelling [cd6385e4] 2019-11-06 Gustaf Neumann * doc/Object.3, library/mongodb/tests/nsf-mongo.test, library/mongodb/tests/nx-mongo.test, library/xotcl/apps/utils/xo-daemon, library/xotcl/doc/Announce-1.3.6, library/xotcl/doc/Announce-1.4.0, library/xotcl/library/comm/Access.xotcl, library/xotcl/library/comm/PCache.xotcl, tests/alias.test, tests/parameters.test: Improve spelling [f10f6e08] * nsf.c (NsfParseArgsCmd): Reduce debugging output [eef40b99] 2019-10-08 Stefan Sobernig * Makefile.in: Avoid pathnames as targets and target dependencies, as they may break make in presence of colons or whitespaces in pathnames as set by autoconf (e.g., --prefix=/data/bin-2019-10-04:19:39:35 or --exec-prefix=/tmp/data/bin-2019-10-04:19:39:35). Thanks to Héctor Romojaro for reporting. [8eebb7d3] * nsf.c, testx.xotcl: Substitute tab-based indentation (1x) for space-based one (8x) for 'required argument' error msg. [5a31aba4] 2019-10-06 Gustaf Neumann * nsf.c, parameters.test: Fix potential crash, whe nsf::parseargs is called with a nonempty argspec and empty argv Extended regression test to cover such cases. [f69d5326] 2019-10-05 Gustaf Neumann * gentclAPI.tcl: Add missing EXTERN declarations [37833d29] * nsf.c, nx-bi.test, contains.test, disposition.test, method-parameter.test, nsf-cmd.test, tcl86.test: typographic changes, most prominently, more consistent comma settings https://onlinewritingtraining.com.au/however-therefore-furthermore/ [9e281d51] 2019-09-27 Gustaf Neumann * nsf.c: Remove "default" from fully initialized switches. initialize variable to slience compiler warnings [3493340e] 2019-09-23 Gustaf Neumann * Object.man, nsfAccessInt.h, webserver.xotcl, htmllib.xotcl, makeDoc.xotcl, destroy.test, doc.test, info-method.test, methods.test, object-system.test, protected.test, tcloo.test: Improve spelling [8024df76] * tcl.m4: Use newer m4 file [a4a0ad0e, 7792a2a9] * nsf.c: Remove redundant test [d32646c8] 2019-08-20 Gustaf Neumann * nsf.c: Fix indentation [83d91f91] 2019-08-20 Stefan Sobernig * nsf.c (NSDeleteChildren): Remove redundant check on NSDeleteChild, leading to endless loop. [84a79b3f] * appveyor.yml: Fix MinGW, ultimate attempt, long story [5c433a50] 2019-08-20 Gustaf Neumann * nsf.c, nsf.h, nsfInt.h, nsfStack.c: Avoid dangerous and potentially recursive macro definition "pure" [7ad03f0f] 2019-08-19 Stefan Sobernig * appveyor.yml: Fix MAKE, Nth attempt [0ac89591..df7f1017] 2019-08-16 Gustaf Neumann * nsf.c, nsfAccessInt.h (FilterAddActive, ProcDispatchFinalize, CallForwarder): Fix compilation issues with recent version of the Tcl core-8.branch (aka newest Tcl 8.7 branch) [8f7c25f9] 2019-08-13 Gustaf Neumann * *.log, nx-zip.tcl, get-regression-nb.xotcl, Httpd.xotcl, parameters.test, tcloo.test: Improve spelling [3c7374ae] 2019-08-10 Gustaf Neumann * Class.3, Class.man, tutorial2.html: Improve spelling [f817725e] 2019-08-09 Gustaf Neumann * doc/example-scripts/*.html: Improve spelling [f35ab630] 2019-08-08 Gustaf Neumann * nsf.c: Don't preallocate elements in Tcl_NewListObj with 2nd arg NULL (deprecated) nsf::__db_get_obj: make sure, the returned dict is valid [febe765f] 2019-08-06 Gustaf Neumann * nsf.c, nx.tcl, object-system.test: Enable temporary debugging output to investigate AppVeyor build failures [1e698728, 9e6766c4, 63c904a4, 8e725616, faa3eeb7] 2019-08-05 Gustaf Neumann * nsfShadow.c (Nsf_RenameObjCmd, Nsf_InfoBodyObjCmd): Fix shadowing of variable names [114f2ea7] * Makefile.in: fine-tuning of gcc warnings [89894f47] * Serializer.xotcl: Fix version number [c1612273] 2019-07-21 Stefan Sobernig * tests/submethods.test: Test for various conditions of unknown handling for ensemble methods of varying depth; also covers the crash condition reported on c.l.t, introduced with [156a37f] [37735fae] 2019-07-21 Gustaf Neumann * nsf.c (NextSearchAndInvoke): Fix but on top-level shell on unknown ensemble submethods [5368627b] 2019-07-07 Stefan Sobernig * nx.tcl, pkgIndex.tcl: Fix version number to include patch level: x.y.z [31adfd57] * properties.test: Add a case to test for the bug on cget/configure NsfFlagObjType sharing [13ac2740] 2019-07-06 Gustaf Neumann * nsf.h: Let developer control NDEBUG via Makefile (Tcl seems to define it nowadays) [1fb16685] * nsf.c (ArgumentParse): Fix for a caching bug reported by Manfred Stelzhammer at comp.lang.tcl. See https://groups.google.com/g/comp.lang.tcl/c/F9cn_Ah4js4/m/eL22xbQaCgAJ [94a8ea7c]; improve cleanness of compilation [172a32e2];improve fall-through markup for case statements [3a4c6144] 2019-06-26 Stefan Sobernig * appveyor.yml: Fix tclkit URL for win. [2b4d1bca] 2019-06-19 Stefan Sobernig * apps/build.tcl: Fallback to curl, in case we run under a non-TLS-enabled Tcl environment. [cc4c9b92] 2019-06-17 Stefan Sobernig * .travis.yml, apps/build.tcl, appveyor.yml: Fix build environment to be able to fetch Tcl tarballs via https; updated tclkits for linux, macos, and win. [1544e5c0] 2019-06-16 Gustaf Neumann * nsf.c, nsf.h, nsfFunPtrHashTable.c, nsfInt.h: Silence gcc7+ by using attribute-based approach for denoting fall through in case statements [ec5702da] 2019-05-25 Gustaf Neumann * nsf.c: Code gardening (make unused argument explicitly as unused, cleanness of compilation when compiled without threads) [937c6deb, 51302024] * library/mongodb/pkgIndex.add: Fix missed version bump [641f75e3] * nsf.c (ObjectSystemsCleanup): Fix endless loop at exit, when compiled without thread support. Many thanks to Pavel Demin for reporting this bug. [8dbedb9a] 2019-05-14 Gustaf Neumann * nsf.c (NsfUnsetTrace): Eliminate TCL_INTERP_DESTROYED flag (as suggested by TIP #543) [e2349563] 2019-05-13 Stefan Sobernig * configure.ac, library/mongodb/configure.ac, nx-mongo.tcl, nx.tcl, nx/pkgIndex.tcl, serialize/pkgIndex.tcl, serialize/serializer.tcl, xotcl/library/pkgIndex.tcl, xotcl/library/xotcl2.tcl: Bump version number to 2.4.0 [39197485, c80b57b9] * .travis.yml, appveyor.yml: Update branch settings in CI descriptors, Added CI entries to README.release [8c195577, 717b102a] 2019-05-12 Stefan Sobernig * .travis.yml, appveyor.yml: Update branch settings in CI descriptors [4ee2e547] ./nsf2.4.0/win.patch000644 000766 000024 00000001036 13441227315 015010 0ustar00neumannstaff000000 000000 index c17895e..1ab1fd0 100644 --- a/win/makefile.vc +++ b/win/makefile.vc @@ -537,6 +537,7 @@ install-binaries: @echo Installing binaries to '$(SCRIPT_INSTALL_DIR)' @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)" @$(CPY) $(PRJLIB) "$(SCRIPT_INSTALL_DIR)" >NUL + @if not exist "$(INCLUDE_INSTALL_DIR)" mkdir "$(INCLUDE_INSTALL_DIR)" @echo Installing header files to "$(INCLUDE_INSTALL_DIR)" @$(CPY) "$(GENERICDIR)\nsf.h" "$(INCLUDE_INSTALL_DIR)" @$(CPY) "$(GENERICDIR)\nsfInt.h" "$(INCLUDE_INSTALL_DIR)" ./nsf2.4.0/win/pkg.vc000644 000766 000024 00000000407 13466507354 015116 0ustar00neumannstaff000000 000000 # remember to change configure.in as well when these change # (then re-autoconf) PACKAGE_MAJOR = 2 PACKAGE_MINOR = 4 PACKAGE_VERSION = "2.4.0" !if exists("..\COMMIT") NSF_COMMIT = \ !include "..\COMMIT" !else NSF_COMMIT = unknown-msvc-$(PACKAGE_VERSION) !endif ./nsf2.4.0/win/makefile.vc000644 000766 000024 00000050061 14274463622 016110 0ustar00neumannstaff000000 000000 #------------------------------------------------------------- -*- makefile -*- # makefile.vc -- # # Microsoft Visual C++ makefile for use with nmake.exe v1.62+ # (VC++ 5.0+, MVSVC 11, MVSVC 12) # # This makefile is based upon the Tcl 8.6 Makefile.vc and modified to # make it suitable as an NSF package makefile. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # Copyright (c) 1995-1996 Sun Microsystems, Inc. # Copyright (c) 1998-2000 Ajuba Solutions. # Copyright (c) 2001-2005 ActiveState Corporation. # Copyright (c) 2001-2004 David Gravereaux. # Copyright (c) 2003-2008 Pat Thoyts. # Copyright (c) 2013-2018 Stefan Sobernig #------------------------------------------------------------------------------ # Check to see we are configured to build with MSVC (MSDEVDIR, MSVCDIR or # VCINSTALLDIR) or with the MS Platform SDK (MSSDK or WindowsSDKDir) !if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(VCINSTALLDIR) && !defined(MSSDK) && !defined(WINDOWSSDKDIR) MSG = ^ You need to run vcvars32.bat from Developer Studio or setenv.bat from the^ Platform SDK first to setup the environment. Jump to this line to read^ the build instructions. !error $(MSG) !endif #------------------------------------------------------------------------------ # HOW TO USE this makefile: # # 1) It is now necessary to have MSVCDir, MSDevDir or MSSDK set in the # environment. This is used as a check to see if vcvars32.bat had been # run prior to running nmake or during the installation of Microsoft # Visual C++, MSVCDir had been set globally and the PATH adjusted. # Either way is valid. # # You'll need to run vcvars32.bat contained in the MsDev's vc(98)/bin # directory to setup the proper environment, if needed, for your # current setup. This is a needed bootstrap requirement and allows the # swapping of different environments to be easier. # # 2) To use the Platform SDK (not expressly needed), run setenv.bat after # vcvars32.bat according to the instructions for it. This can also # turn on the 64-bit compiler, if your SDK has it. # # 3) Targets are: # all -- Builds everything. # -- Builds the project (eg: nmake sample) # test -- Builds and runs the test suite. # install -- Installs the built binaries and libraries to $(INSTALLDIR) # in an appropriate subdirectory. # clean/realclean/distclean -- varying levels of cleaning. # # 4) Macros usable on the commandline: # INSTALLDIR= # Sets where to install Tcl from the built binaries. # C:\Progra~1\Tcl is assumed when not specified. # # OPTS=loimpact,msvcrt,nothreads,pdbs,profile,static,symbols,unchecked,none # Sets special options for the core. The default is for none. # Any combination of the above may be used (comma separated). # 'none' will over-ride everything to nothing. # # loimpact = Adds a flag for how NT treats the heap to keep memory # in use, low. This is said to impact alloc performance. # msvcrt = Affects the static option only to switch it from # using libcmt(d) as the C runtime [by default] to # msvcrt(d). This is useful for static embedding # support. # nothreads = Turns off multithreading support (not recommended) # static = Builds a static library of the core instead of a # dll. The shell will be static (and large), as well. # pdbs = Build detached symbols for release builds. # profile = Adds profiling hooks. Map file is assumed. # symbols = Debug build. Links to the debug C runtime, disables # optimizations and creates pdb symbols files. # unchecked= Allows a symbols build to not use the debug # enabled runtime (msvcrt.dll not msvcrtd.dll # or libcmt.lib not libcmtd.lib). # # STATS=compdbg,memdbg,none # Sets optional memory and bytecode compiler debugging code added # to the core. The default is for none. Any combination of the # above may be used (comma separated). 'none' will over-ride # everything to nothing. # # compdbg = Enables byte compilation logging. # memdbg = Enables the debugging memory allocator. # # CHECKS=64bit,fullwarn,nodep,none # Sets special macros for checking compatibility. # # 64bit = Enable 64bit portability warnings (if available) # fullwarn = Builds with full compiler and link warnings enabled. # Very verbose. # nodep = Turns off compatibility macros to ensure the extension # isn't being built with deprecated functions. # # MACHINE=(ALPHA|AMD64|IA64|IX86) # Set the machine type used for the compiler, linker, and # resource compiler. This hook is needed to tell the tools # when alternate platforms are requested. IX86 is the default # when not specified. If the CPU environment variable has been # set (ie: recent Platform SDK) then MACHINE is set from CPU. # # TMP_DIR= # OUT_DIR= # Hooks to allow the intermediate and output directories to be # changed. $(OUT_DIR) is assumed to be # $(BINROOT)\(Release|Debug) based on if symbols are requested. # $(TMP_DIR) will de $(OUT_DIR)\ by default. # # TESTPAT= # Reads the tests requested to be run from this file. # # 5) Examples: # # Basic syntax of calling nmake looks like this: # nmake [-nologo] -f makefile.vc [target|macrodef [target|macrodef] [...]] # # Using VC++: # # Standard (in cmd.exe, no frills, x86) # c:\nsf_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat # Setting environment for using Microsoft Visual C++ tools. # c:\nsf_src\win\>nmake -f makefile.vc TCLDIR=c:\tcl_src\ # c:\nsf_src\win\>nmake -f makefile.vc install INSTALLDIR=c:\progra~1\tcl # # Building for Win64 (IA64) # c:\nsf_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat # Setting environment for using Microsoft Visual C++ tools. # c:\nsf_src\win\>c:\progra~1\platfo~1\setenv.bat /pre64 /RETAIL # Targeting Windows pre64 RETAIL # c:\nsf_src\win\>nmake -f makefile.vc MACHINE=IA64 # # Using Microsoft Visual Compiler 11+: # see also http://msdn.microsoft.com/en-us/library/vstudio/x4d2c09s.aspx # # Standard (in cmd.exe, no frills, x86) # c:\nsf_src\win>"c:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" x86 # c:\nsf_src\win\>nmake -f makefile.vc all TCLDIR=c:\tcl_src\ MACHINE=X86 # c:\nsf_src\win\>nmake -f makefile.vc install INSTALLDIR=c:\progra~1\tcl # # Building for Win64 (AMD64) # c:\nsf_src\win>"c:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" amd64 # c:\nsf_src\win\>nmake -f makefile.vc all TCLDIR=c:\tcl_src\ MACHINE=AMD64 # c:\nsf_src\win\>nmake -f makefile.vc install INSTALLDIR=c:\progra~1\tcl # #------------------------------------------------------------------------------ #============================================================================== #------------------------------------------------------------------------------ !if !exist("makefile.vc") MSG = ^ You must run this makefile only from the directory it is in.^ Please `cd` to its location first. !error $(MSG) !endif #------------------------------------------------------------------------- # Project specific information (EDIT) # # You should edit this with the name and version of your project. This # information is used to generate the name of the package library and # it's install location. # # For example, the sample extension is going to build sample05.dll and # would install it into $(INSTALLDIR)\lib\sample05 # # You need to specify the object files that need to be linked into your # binary here. # #------------------------------------------------------------------------- PROJECT = nsf # Uncomment the following line if this is a Tk extension. #PROJECT_REQUIRES_TK=1 !include "pkg.vc" DOTVERSION = $(PACKAGE_VERSION:"=) #" VERSION = $(PACKAGE_MAJOR)$(PACKAGE_MINOR) STUBPREFIX = $(PROJECT)stub !include "rules.vc" PRJ_CFLAGS = -DNSF_VERSION=\"$(DOTVERSION)\" -DNSF_PATCHLEVEL=\"$(PACKAGE_VERSION)\" -DNSF_COMMIT=\"$(NSF_COMMIT)\" -DHAVE_INTPTR_T -DHAVE_UINTPTR_T DLLOBJS = \ $(TMP_DIR)\nsf.obj \ $(TMP_DIR)\nsfError.obj \ $(TMP_DIR)\nsfObjectData.obj \ $(TMP_DIR)\nsfProfile.obj \ $(TMP_DIR)\nsfDebug.obj \ $(TMP_DIR)\nsfUtil.obj \ $(TMP_DIR)\nsfObj.obj \ $(TMP_DIR)\nsfPointer.obj \ $(TMP_DIR)\nsfShadow.obj \ $(TMP_DIR)\nsfCompile.obj \ $(TMP_DIR)\aolstub.obj \ $(TMP_DIR)\nsfStubInit.obj \ $(TMP_DIR)\nsfEnumerationType.obj \ $(TMP_DIR)\nsfCmdDefinitions.obj \ $(TMP_DIR)\nsfFunPtrHashTable.obj EXTESTS = \ $(ROOT)\doc\example-scripts\bagel.tcl \ $(ROOT)\doc\example-scripts\container.tcl \ $(ROOT)\doc\example-scripts\rosetta-abstract-type.tcl \ $(ROOT)\doc\example-scripts\rosetta-classes.tcl \ $(ROOT)\doc\example-scripts\rosetta-constraint-genericity.tcl \ $(ROOT)\doc\example-scripts\rosetta-delegates.tcl \ $(ROOT)\doc\example-scripts\rosetta-polymorphism.tcl \ $(ROOT)\doc\example-scripts\rosetta-serialization.tcl \ $(ROOT)\doc\example-scripts\rosetta-singleton.tcl \ $(ROOT)\doc\example-scripts\rosetta-sudoku.tcl \ $(ROOT)\doc\example-scripts\rosetta-unknown-method.tcl \ $(ROOT)\doc\example-scripts\ruby-mixins.tcl \ $(ROOT)\doc\example-scripts\traits-composite.tcl \ $(ROOT)\doc\example-scripts\traits-simple.tcl \ $(ROOT)\doc\example-scripts\rosetta-tokenizer.tcl \ $(ROOT)\doc\example-scripts\rosetta-tree.tcl \ $(ROOT)\doc\example-scripts\rosetta-multiple-distinct.tcl \ $(ROOT)\doc\example-scripts\rosetta-add-variable.tcl \ $(ROOT)\doc\example-scripts\rosetta-clone.tcl \ $(ROOT)\doc\example-scripts\rosetta-multiple-inheritance.tcl \ $(ROOT)\doc\example-scripts\rosetta-single-inheritance.tcl PRJTESTS = \ $(ROOT)\tests\object-system.test \ $(ROOT)\tests\alias.test \ $(ROOT)\tests\returns.test \ $(ROOT)\tests\cget.test \ $(ROOT)\tests\method-parameter.test \ $(ROOT)\tests\serialize.test \ $(ROOT)\tests\contains.test \ $(ROOT)\tests\method-require.test \ $(ROOT)\tests\submethods.test \ $(ROOT)\tests\destroy.test \ $(ROOT)\tests\methods.test \ $(ROOT)\tests\disposition.test \ $(ROOT)\tests\mixinof.test \ $(ROOT)\tests\tcl86.test \ $(ROOT)\tests\tcloo.test \ $(ROOT)\tests\forward.test \ $(ROOT)\tests\var-access.test \ $(ROOT)\tests\info-method.test \ $(ROOT)\tests\varresolution.test \ $(ROOT)\tests\interceptor-slot.test\ $(ROOT)\tests\properties.test \ $(ROOT)\tests\volatile.test \ $(ROOT)\tests\interp.test \ $(ROOT)\tests\protected.test \ $(ROOT)\tests\parameters.test \ $(ROOT)\tests\plain-object-method.test \ $(ROOT)\tests\class-method.test \ $(ROOT)\tests\nsf-cmd.test \ $(ROOT)\tests\accessor.test \ $(ROOT)\tests\linearization.test \ $(ROOT)\tests\traits.test \ $(ROOT)\tests\info-variable.test \ $(EXTESTS) PRJHEADERS = #------------------------------------------------------------------------- # Target names and paths ( shouldn't need changing ) #------------------------------------------------------------------------- BINROOT = . # ROOT = .. PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib PRJLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT) PRJLIB = $(OUT_DIR)\$(PRJLIBNAME) PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME) ### Make sure we use backslash only. PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION) LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR) BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR) DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR) SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR) INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\include ### The following paths CANNOT have spaces in them. GENERICDIR = $(ROOT)\generic WINDIR = $(ROOT)\win LIBDIR = $(ROOT)\library DOCDIR = $(ROOT)\doc COMPATDIR = $(ROOT)\compat UTILDIR = $(ROOT)\apps\utils STUBSDIR = $(GENERICDIR)\stubs$(TCL_DOTVERSION) #--------------------------------------------------------------------- # Compile flags #--------------------------------------------------------------------- !if !$(DEBUG) !if $(OPTIMIZING) ### This cranks the optimization level to maximize speed cdebug = $(OPTIMIZATIONS) !else cdebug = !endif !else if "$(MACHINE)" == "IA64" ### Warnings are too many, can't support warnings into errors. cdebug = -Zi -Od $(DEBUGFLAGS) !else cdebug = -Zi -WX $(DEBUGFLAGS) !endif ### Declarations common to all compiler options cwarn = $(WARNINGS) -D _CRT_SECURE_NO_DEPRECATE -D _CRT_NONSTDC_NO_DEPRECATE cflags = -nologo -c $(COMPILERFLAGS) -DBUILD_$(PROJECT) $(cwarn) -Fp$(TMP_DIR)^\ !if $(MSVCRT) !if $(DEBUG) && !$(UNCHECKED) crt = -MDd !else crt = -MD !endif !else !if $(DEBUG) && !$(UNCHECKED) crt = -MTd !else crt = -MT !endif !endif cflags = $(cflags) -DMODULE_SCOPE=extern !if !$(STATIC_BUILD) cflags = $(cflags) -DUSE_TCL_STUBS !if defined(TKSTUBLIB) cflags = $(cflags) -DUSE_TK_STUBS !endif !endif INCLUDES = $(TCL_INCLUDES) -I"$(WINDIR)" -I"$(GENERICDIR)" BASE_CFLAGS = $(cflags) $(cdebug) $(crt) $(INCLUDES) CON_CFLAGS = $(cflags) $(cdebug) $(crt) -DCONSOLE TCL_CFLAGS = -DPACKAGE_NAME="\"$(PROJECT)\"" \ -DPACKAGE_VERSION="\"$(DOTVERSION)\"" \ -DBUILD_$(PROJECT) \ $(BASE_CFLAGS) $(OPTDEFINES) $(PRJ_CFLAGS) #--------------------------------------------------------------------- # Link flags #--------------------------------------------------------------------- !if $(DEBUG) ldebug = -debug -debugtype:cv !if $(MSVCRT) ldebug = $(ldebug) -nodefaultlib:msvcrt !endif !else ldebug = -release -opt:ref -opt:noicf !endif ### Declarations common to all linker options lflags = -nologo -machine:$(MACHINE) $(LINKERFLAGS) $(ldebug) !if $(PROFILE) lflags = $(lflags) -profile !endif dlllflags = $(lflags) -dll conlflags = $(lflags) -subsystem:console guilflags = $(lflags) -subsystem:windows !if !$(STATIC_BUILD) baselibs = $(TCLSTUBLIB) !if defined(TKSTUBLIB) baselibs = $(baselibs) $(TKSTUBLIB) !endif !endif # Avoid 'unresolved external symbol __security_cookie' errors. # c.f. http://support.microsoft.com/?id=894573 !if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64" !if $(VCVERSION) > 1399 && $(VCVERSION) < 1500 baselibs = $(baselibs) bufferoverflowU.lib !endif !endif baselibs = $(baselibs) user32.lib gdi32.lib #--------------------------------------------------------------------- # TclTest flags #--------------------------------------------------------------------- !if "$(TESTPAT)" != "" TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT) !endif #--------------------------------------------------------------------- # Project specific targets (EDIT) #--------------------------------------------------------------------- all: setup $(PROJECT) $(PROJECT): setup pkgIndex $(PRJLIB) install: install-binaries install-libraries install-docs pkgIndex: $(OUT_DIR)\pkgIndex.tcl test: setup $(PROJECT) @set TCL_LIBRARY=$(TCL_LIBRARY:\=/) @set TCLLIBPATH=. @set TCL_PKG_PREFER_LATEST=1 @$(CPY) $(ROOT)\library library /e !if $(TCLINSTALL) @set PATH=$(_TCLDIR)\bin;$(PATH) !else @set PATH=$(_TCLDIR)\win\$(BUILDDIRTOP);$(PATH) !endif !if "$(OS)" == "Windows_NT" || "$(MSVCDIR)" == "IDE" for %i in ($(PRJTESTS)) do \ $(DEBUGGER) $(TCLSH) %i -testlog __test.log !else @echo Please wait while the tests are collected... for %i in ($(PRJTESTS)) do \ $(DEBUGGER) $(TCLSH) %i -testlog __test.log >> tests.log type tests.log | more !endif @$(TCLSH) "$(ROOT)/tests/summary.tcl" -title NX+XOTcl -testlog __test.log @rd library /s /q @del __test.log shell: setup $(PROJECT) @set VLERQ_LIBRARY=$(LIBDIR:\=/) @set TCL_LIBRARY=$(TCL_LIBRARY:\=/) @set TCLLIBPATH=. @set TCL_PKG_PREFER_LATEST=1 !if $(TCLINSTALL) @set PATH=$(_TCLDIR)\bin;$(PATH) !else @set PATH=$(_TCLDIR)\win\$(BUILDDIRTOP);$(PATH) !endif @echo lappend auto_path $(ROOT:\=/) .; puts $$auto_path; package req nx::shell 1.1; exit [nx::shell run $$argc $$argv;] > nsfshell.tcl $(DEBUGGER) $(TCLSH) nsfshell.tcl $(SCRIPT) @del nsfshell.tcl setup: @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR) @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR) # See /win/coffbase.txt for extension base addresses. $(PRJLIB): $(DLLOBJS) !if $(STATIC_BUILD) $(lib32) -nologo -out:$@ @<< $** << !else $(link32) $(dlllflags) -out:$@ $(baselibs) @<< $** << $(_VC_MANIFEST_EMBED_DLL) -@del $*.exp !endif $(PRJSTUBLIB): $(PRJSTUBOBJS) $(lib32) -nologo -out:$@ $(PRJSTUBOBJS) #--------------------------------------------------------------------- # Implicit rules #--------------------------------------------------------------------- {$(WINDIR)}.c{$(TMP_DIR)}.obj:: $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< $< << {$(GENERICDIR)}.c{$(TMP_DIR)}.obj:: $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< $< << {$(STUBSDIR)}.c{$(TMP_DIR)}.obj:: $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< $< << {$(COMPATDIR)}.c{$(TMP_DIR)}.obj:: $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< $< << {$(WINDIR)}.rc{$(TMP_DIR)}.res: $(rc32) -fo $@ -r -i "$(GENERICDIR)" -D__WIN32__ \ -DCOMMAVERSION=$(DOTVERSION:.=,),0 \ -DDOTVERSION=\"$(DOTVERSION)\" \ -DVERSION=\"$(VERSION)$(SUFX)\" \ !if $(DEBUG) -d DEBUG \ !endif !if $(TCL_THREADS) -d TCL_THREADS \ !endif !if $(STATIC_BUILD) -d STATIC_BUILD \ !endif $< .SUFFIXES: .SUFFIXES:.c .rc #------------------------------------------------------------------------- # Explicit dependency rules # #------------------------------------------------------------------------- $(OUT_DIR)\pkgIndex.tcl: @set TCL_PKG_PREFER_LATEST=1 @echo package ifneeded $(PROJECT) $(DOTVERSION) \ [list load [file join $$dir $(PRJLIBNAME)]] > $@ @for /d %d in ($(LIBDIR)\*) do \ @pushd %d &\ @$(TCLSH) $(LIBDIR)\lib\mkIndex.tcl -dir %d &\ @popd #--------------------------------------------------------------------- # Installation. (EDIT) # # You may need to modify this section to reflect the final distribution # of your files and possibly to generate documentation. # #--------------------------------------------------------------------- install-binaries: @echo Installing binaries to '$(SCRIPT_INSTALL_DIR)' @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)" @$(CPY) $(PRJLIB) "$(SCRIPT_INSTALL_DIR)" >NUL @if not exist "$(INCLUDE_INSTALL_DIR)" mkdir "$(INCLUDE_INSTALL_DIR)" @echo Installing header files to "$(INCLUDE_INSTALL_DIR)" @$(CPY) "$(GENERICDIR)\nsf.h" "$(INCLUDE_INSTALL_DIR)" @$(CPY) "$(GENERICDIR)\nsfInt.h" "$(INCLUDE_INSTALL_DIR)" @$(CPY) "$(STUBSDIR)\nsfDecls.h" "$(INCLUDE_INSTALL_DIR)" @$(CPY) "$(STUBSDIR)\nsfIntDecls.h" "$(INCLUDE_INSTALL_DIR)" @echo Installing package index in '$(SCRIPT_INSTALL_DIR)' @$(CPY) $(OUT_DIR)\pkgIndex.tcl "$(SCRIPT_INSTALL_DIR)" install-libraries: @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)' @echo Installing NX @if not exist "$(SCRIPT_INSTALL_DIR)"\nx mkdir "$(SCRIPT_INSTALL_DIR)"\nx @$(CPY) $(LIBDIR)\nx\*.tcl "$(SCRIPT_INSTALL_DIR)"\nx @echo Installing serialize @if not exist "$(SCRIPT_INSTALL_DIR)\serialize" mkdir "$(SCRIPT_INSTALL_DIR)\serialize" @$(CPY) $(LIBDIR)\serialize\*.tcl "$(SCRIPT_INSTALL_DIR)\serialize" @echo Installing XOTcl2 @if not exist "$(SCRIPT_INSTALL_DIR)\xotcl" mkdir "$(SCRIPT_INSTALL_DIR)\xotcl" @$(CPY) $(LIBDIR)\xotcl\apps "$(SCRIPT_INSTALL_DIR)\xotcl\apps" /e @$(CPY) $(LIBDIR)\xotcl\library "$(SCRIPT_INSTALL_DIR)\xotcl\library" /e # @$(CPY) $(LIBDIR)\xotcl\xo* "$(SCRIPT_INSTALL_DIR)\xotcl" @echo Installing NX libs @if not exist "$(SCRIPT_INSTALL_DIR)\lib" mkdir "$(SCRIPT_INSTALL_DIR)\lib" @$(CPY) $(LIBDIR)\lib\*.tcl "$(SCRIPT_INSTALL_DIR)\lib" @type "$(LIBDIR)\pkgIndex.tcl" >> "$(SCRIPT_INSTALL_DIR)"\pkgIndex.tcl install-docs: @echo Installing documentation files to '$(DOC_INSTALL_DIR)' # @if exist $(DOCDIR) $(CPY) $(DOCDIR)\*.n "$(DOC_INSTALL_DIR)" #--------------------------------------------------------------------- # Clean up #--------------------------------------------------------------------- clean: @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR) @if exist $(WINDIR)\version.vc del $(WINDIR)\version.vc @if exist $(WINDIR)\versions.vc del $(WINDIR)\versions.vc @if exist $(WINDIR)\vercl.i del $(WINDIR)\vercl.i @if exist $(WINDIR)\vercl.x del $(WINDIR)\vercl.x @if exist $(WINDIR)\_junk.pch del $(WINDIR)\_junk.pch realclean: clean @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR) distclean: realclean @if exist $(WINDIR)\nmakehlp.exe del $(WINDIR)\nmakehlp.exe @if exist $(WINDIR)\nmakehlp.obj del $(WINDIR)\nmakehlp.obj ./nsf2.4.0/win/nmakehlp.c000644 000766 000024 00000042172 13774055457 015757 0ustar00neumannstaff000000 000000 /* * ---------------------------------------------------------------------------- * nmakehlp.c -- * * This is used to fix limitations within nmake and the environment. * * Copyright (c) 2002 by David Gravereaux. * Copyright (c) 2006 by Pat Thoyts * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * ---------------------------------------------------------------------------- */ #define _CRT_SECURE_NO_DEPRECATE #include #define NO_SHLWAPI_GDI #define NO_SHLWAPI_STREAM #define NO_SHLWAPI_REG #include #pragma comment (lib, "user32.lib") #pragma comment (lib, "kernel32.lib") #pragma comment (lib, "shlwapi.lib") #include #include /* * This library is required for x64 builds with _some_ versions of MSVC */ #if defined(_M_IA64) || defined(_M_AMD64) #if _MSC_VER >= 1400 && _MSC_VER < 1500 #pragma comment(lib, "bufferoverflowU") #endif #endif /* ISO hack for dumb VC++ */ #ifdef _MSC_VER #define snprintf _snprintf #endif /* protos */ static int CheckForCompilerFeature(const char *option); static int CheckForLinkerFeature(const char *option); static int IsIn(const char *string, const char *substring); static int SubstituteFile(const char *substs, const char *filename); static int QualifyPath(const char *path); static const char *GetVersionFromFile(const char *filename, const char *match, int numdots); static DWORD WINAPI ReadFromPipe(LPVOID args); /* globals */ #define CHUNK 25 #define STATICBUFFERSIZE 1000 typedef struct { HANDLE pipe; char buffer[STATICBUFFERSIZE]; } pipeinfo; pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'}; pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'}; /* * exitcodes: 0 == no, 1 == yes, 2 == error */ int main( int argc, char *argv[]) { char msg[300]; DWORD dwWritten; int chars; /* * Make sure children (cl.exe and link.exe) are kept quiet. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); /* * Make sure the compiler and linker aren't effected by the outside world. */ SetEnvironmentVariable("CL", ""); SetEnvironmentVariable("LINK", ""); if (argc > 1 && *argv[1] == '-') { switch (*(argv[1]+1)) { case 'c': if (argc != 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -c \n" "Tests for whether cl.exe supports an option\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return CheckForCompilerFeature(argv[2]); case 'l': if (argc != 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -l \n" "Tests for whether link.exe supports an option\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return CheckForLinkerFeature(argv[2]); case 'f': if (argc == 2) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -f \n" "Find a substring within another\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } else if (argc == 3) { /* * If the string is blank, there is no match. */ return 0; } else { return IsIn(argv[2], argv[3]); } case 's': if (argc == 2) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -s \n" "Perform a set of string map type substutitions on a file\n" "exitcodes: 0\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return SubstituteFile(argv[2], argv[3]); case 'V': if (argc != 4) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -V filename matchstring\n" "Extract a version from a file:\n" "eg: pkgIndex.tcl \"package ifneeded http\"", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 0; } printf("%s\n", GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0')); return 0; case 'Q': if (argc != 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -Q path\n" "Emit the fully qualified path\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return QualifyPath(argv[2]); } } chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -c|-f|-l|-Q|-s|-V ...\n" "This is a little helper app to equalize shell differences between WinNT and\n" "Win9x and get nmake.exe to accomplish its job.\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } static int CheckForCompilerFeature( const char *option) { STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; DWORD threadID; char msg[300]; BOOL ok; HANDLE hProcess, h, pipeThreads[2]; char cmdline[100]; hProcess = GetCurrentProcess(); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = INVALID_HANDLE_VALUE; ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = FALSE; /* * Create a non-inheritible pipe. */ CreatePipe(&Out.pipe, &h, &sa, 0); /* * Dupe the write side, make it inheritible, and close the original. */ DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); /* * Same as above, but for the error side. */ CreatePipe(&Err.pipe, &h, &sa, 0); DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); /* * Base command line. */ lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch "); /* * Append our option for testing */ lstrcat(cmdline, option); /* * Filename to compile, which exists, but is nothing and empty. */ lstrcat(cmdline, " .\\nul"); ok = CreateProcess( NULL, /* Module name. */ cmdline, /* Command line. */ NULL, /* Process handle not inheritable. */ NULL, /* Thread handle not inheritable. */ TRUE, /* yes, inherit handles. */ DETACHED_PROCESS, /* No console for you. */ NULL, /* Use parent's environment block. */ NULL, /* Use parent's starting directory. */ &si, /* Pointer to STARTUPINFO structure. */ &pi); /* Pointer to PROCESS_INFORMATION structure. */ if (ok == 0) { DWORD err = GetLastError(); int chars = snprintf(msg, sizeof(msg) - 1, "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], (300-chars), 0); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err, NULL); return 2; } /* * Close our references to the write handles that have now been inherited. */ CloseHandle(si.hStdOutput); CloseHandle(si.hStdError); WaitForInputIdle(pi.hProcess, 5000); CloseHandle(pi.hThread); /* * Start the pipe reader threads. */ pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); /* * Block waiting for the process to end. */ WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); /* * Wait for our pipe to get done reading, should it be a little slow. */ WaitForMultipleObjects(2, pipeThreads, TRUE, 500); CloseHandle(pipeThreads[0]); CloseHandle(pipeThreads[1]); /* * Look for the commandline warning code in both streams. * - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002. */ return !(strstr(Out.buffer, "D4002") != NULL || strstr(Err.buffer, "D4002") != NULL || strstr(Out.buffer, "D9002") != NULL || strstr(Err.buffer, "D9002") != NULL || strstr(Out.buffer, "D2021") != NULL || strstr(Err.buffer, "D2021") != NULL); } static int CheckForLinkerFeature( const char *option) { STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; DWORD threadID; char msg[300]; BOOL ok; HANDLE hProcess, h, pipeThreads[2]; char cmdline[100]; hProcess = GetCurrentProcess(); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = INVALID_HANDLE_VALUE; ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; /* * Create a non-inheritible pipe. */ CreatePipe(&Out.pipe, &h, &sa, 0); /* * Dupe the write side, make it inheritible, and close the original. */ DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); /* * Same as above, but for the error side. */ CreatePipe(&Err.pipe, &h, &sa, 0); DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); /* * Base command line. */ lstrcpy(cmdline, "link.exe -nologo "); /* * Append our option for testing. */ lstrcat(cmdline, option); ok = CreateProcess( NULL, /* Module name. */ cmdline, /* Command line. */ NULL, /* Process handle not inheritable. */ NULL, /* Thread handle not inheritable. */ TRUE, /* yes, inherit handles. */ DETACHED_PROCESS, /* No console for you. */ NULL, /* Use parent's environment block. */ NULL, /* Use parent's starting directory. */ &si, /* Pointer to STARTUPINFO structure. */ &pi); /* Pointer to PROCESS_INFORMATION structure. */ if (ok == 0) { DWORD err = GetLastError(); int chars = snprintf(msg, sizeof(msg) - 1, "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], (300-chars), 0); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err, NULL); return 2; } /* * Close our references to the write handles that have now been inherited. */ CloseHandle(si.hStdOutput); CloseHandle(si.hStdError); WaitForInputIdle(pi.hProcess, 5000); CloseHandle(pi.hThread); /* * Start the pipe reader threads. */ pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID); pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID); /* * Block waiting for the process to end. */ WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); /* * Wait for our pipe to get done reading, should it be a little slow. */ WaitForMultipleObjects(2, pipeThreads, TRUE, 500); CloseHandle(pipeThreads[0]); CloseHandle(pipeThreads[1]); /* * Look for the commandline warning code in the stderr stream. */ return !(strstr(Out.buffer, "LNK1117") != NULL || strstr(Err.buffer, "LNK1117") != NULL || strstr(Out.buffer, "LNK4044") != NULL || strstr(Err.buffer, "LNK4044") != NULL); } static DWORD WINAPI ReadFromPipe( LPVOID args) { pipeinfo *pi = (pipeinfo *) args; char *lastBuf = pi->buffer; DWORD dwRead; BOOL ok; again: if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) { CloseHandle(pi->pipe); return (DWORD)-1; } ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L); if (!ok || dwRead == 0) { CloseHandle(pi->pipe); return 0; } lastBuf += dwRead; goto again; return 0; /* makes the compiler happy */ } static int IsIn( const char *string, const char *substring) { return (strstr(string, substring) != NULL); } /* * GetVersionFromFile -- * Looks for a match string in a file and then returns the version * following the match where a version is anything acceptable to * package provide or package ifneeded. */ static const char * GetVersionFromFile( const char *filename, const char *match, int numdots) { size_t cbBuffer = 100; static char szBuffer[100]; char *szResult = NULL; FILE *fp = fopen(filename, "rt"); if (fp != NULL) { /* * Read data until we see our match string. */ while (fgets(szBuffer, cbBuffer, fp) != NULL) { LPSTR p, q; p = strstr(szBuffer, match); if (p != NULL) { /* * Skip to first digit after the match. */ p += strlen(match); while (*p && !isdigit(*p)) { ++p; } /* * Find ending whitespace. */ q = p; while (*q && (strchr("0123456789.ab", *q)) && ((!strchr(".ab", *q) && (!strchr("ab", q[-1])) || --numdots))) { ++q; } memcpy(szBuffer, p, q - p); szBuffer[q-p] = 0; szResult = szBuffer; break; } } fclose(fp); } return szResult; } /* * List helpers for the SubstituteFile function */ typedef struct list_item_t { struct list_item_t *nextPtr; char * key; char * value; } list_item_t; /* insert a list item into the list (list may be null) */ static list_item_t * list_insert(list_item_t **listPtrPtr, const char *key, const char *value) { list_item_t *itemPtr = malloc(sizeof(list_item_t)); if (itemPtr != NULL) { itemPtr->key = strdup(key); itemPtr->value = strdup(value); itemPtr->nextPtr = NULL; while(*listPtrPtr) { listPtrPtr = &(*listPtrPtr)->nextPtr; } *listPtrPtr = itemPtr; } return itemPtr; } static void list_free(list_item_t **listPtrPtr) { list_item_t *tmpPtr, *listPtr = *listPtrPtr; while (listPtr) { tmpPtr = listPtr; listPtr = listPtr->nextPtr; free(tmpPtr->key); free(tmpPtr->value); free(tmpPtr); } } /* * SubstituteFile -- * As windows doesn't provide anything useful like sed and it's unreliable * to use the tclsh you are building against (consider x-platform builds - * eg compiling AMD64 target from IX86) we provide a simple substitution * option here to handle autoconf style substitutions. * The substitution file is whitespace and line delimited. The file should * consist of lines matching the regular expression: * \s*\S+\s+\S*$ * * Usage is something like: * nmakehlp -S << $** > $@ * @PACKAGE_NAME@ $(PACKAGE_NAME) * @PACKAGE_VERSION@ $(PACKAGE_VERSION) * << */ static int SubstituteFile( const char *substitutions, const char *filename) { size_t cbBuffer = 1024; static char szBuffer[1024], szCopy[1024]; char *szResult = NULL; list_item_t *substPtr = NULL; FILE *fp, *sp; fp = fopen(filename, "rt"); if (fp != NULL) { /* * Build a list of substutitions from the first filename */ sp = fopen(substitutions, "rt"); if (sp != NULL) { while (fgets(szBuffer, cbBuffer, sp) != NULL) { char *ks, *ke, *vs, *ve; ks = szBuffer; while (ks && *ks && isspace(*ks)) ++ks; ke = ks; while (ke && *ke && !isspace(*ke)) ++ke; vs = ke; while (vs && *vs && isspace(*vs)) ++vs; ve = vs; while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve; *ke = 0, *ve = 0; list_insert(&substPtr, ks, vs); } fclose(sp); } /* debug: dump the list */ #ifdef _DEBUG { int n = 0; list_item_t *p = NULL; for (p = substPtr; p != NULL; p = p->nextPtr, ++n) { fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value); } } #endif /* * Run the substitutions over each line of the input */ while (fgets(szBuffer, cbBuffer, fp) != NULL) { list_item_t *p = NULL; for (p = substPtr; p != NULL; p = p->nextPtr) { char *m = strstr(szBuffer, p->key); if (m != NULL) { char *cp, *op, *sp; cp = szCopy; op = szBuffer; while (op != m) *cp++ = *op++; sp = p->value; while (sp && *sp) *cp++ = *sp++; op += strlen(p->key); while (*op) *cp++ = *op++; *cp = 0; memcpy(szBuffer, szCopy, sizeof(szCopy)); } } printf(szBuffer); } list_free(&substPtr); } fclose(fp); return 0; } /* * QualifyPath -- * * This composes the current working directory with a provided path * and returns the fully qualified and normalized path. * Mostly needed to setup paths for testing. */ static int QualifyPath( const char *szPath) { char szCwd[MAX_PATH + 1]; char szTmp[MAX_PATH + 1]; char *p; GetCurrentDirectory(MAX_PATH, szCwd); while ((p = strchr(szPath, '/')) && *p) *p = '\\'; PathCombine(szTmp, szCwd, szPath); PathCanonicalize(szCwd, szTmp); printf("%s\n", szCwd); return 0; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * indent-tabs-mode: t * tab-width: 8 * End: */ ./nsf2.4.0/win/rules.vc000644 000766 000024 00000153342 14274463622 015473 0ustar00neumannstaff000000 000000 #------------------------------------------------------------- -*- makefile -*- # rules.vc -- # # Part of the nmake based build system for Tcl and its extensions. # This file does all the hard work in terms of parsing build options, # compiler switches, defining common targets and macros. The Tcl makefile # directly includes this. Extensions include it via "rules-ext.vc". # # See TIP 477 (https://core.tcl.tk/tips/doc/trunk/tip/477.md) for # detailed documentation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # Copyright (c) 2001-2003 David Gravereaux. # Copyright (c) 2003-2008 Patrick Thoyts # Copyright (c) 2017 Ashok P. Nadkarni #------------------------------------------------------------------------------ !ifndef _RULES_VC _RULES_VC = 1 # The following macros define the version of the rules.vc nmake build system # For modifications that are not backward-compatible, you *must* change # the major version. RULES_VERSION_MAJOR = 1 RULES_VERSION_MINOR = 0 # The PROJECT macro must be defined by parent makefile. !if "$(PROJECT)" == "" !error *** Error: Macro PROJECT not defined! Please define it before including rules.vc !endif !if "$(PRJ_PACKAGE_TCLNAME)" == "" PRJ_PACKAGE_TCLNAME = $(PROJECT) !endif # Also special case Tcl and Tk to save some typing later DOING_TCL = 0 DOING_TK = 0 !if "$(PROJECT)" == "tcl" DOING_TCL = 1 !elseif "$(PROJECT)" == "tk" DOING_TK = 1 !endif !ifndef NEED_TK # Backwards compatibility !ifdef PROJECT_REQUIRES_TK NEED_TK = $(PROJECT_REQUIRES_TK) !else NEED_TK = 0 !endif !endif !ifndef NEED_TCL_SOURCE NEED_TCL_SOURCE = 0 !endif !ifdef NEED_TK_SOURCE !if $(NEED_TK_SOURCE) NEED_TK = 1 !endif !else NEED_TK_SOURCE = 0 !endif ################################################################ # Nmake is a pretty weak environment in syntax and capabilities # so this file is necessarily verbose. It's broken down into # the following parts. # # 0. Sanity check that compiler environment is set up and initialize # any built-in settings from the parent makefile # 1. First define the external tools used for compiling, copying etc. # as this is independent of everything else. # 2. Figure out our build structure in terms of the directory, whether # we are building Tcl or an extension, etc. # 3. Determine the compiler and linker versions # 4. Build the nmakehlp helper application # 5. Determine the supported compiler options and features # 6. Parse the OPTS macro value for user-specified build configuration # 7. Parse the STATS macro value for statistics instrumentation # 8. Parse the CHECKS macro for additional compilation checks # 9. Extract Tcl, and possibly Tk, version numbers from the headers # 10. Based on this selected configuration, construct the output # directory and file paths # 11. Construct the paths where the package is to be installed # 12. Set up the actual options passed to compiler and linker based # on the information gathered above. # 13. Define some standard build targets and implicit rules. These may # be optionally disabled by the parent makefile. # 14. (For extensions only.) Compare the configuration of the target # Tcl and the extensions and warn against discrepancies. # # One final note about the macro names used. They are as they are # for historical reasons. We would like legacy extensions to # continue to work with this make include file so be wary of # changing them for consistency or clarity. # 0. Sanity check compiler environment # Check to see we are configured to build with MSVC (MSDEVDIR, MSVCDIR or # VCINSTALLDIR) or with the MS Platform SDK (MSSDK or WindowsSDKDir) !if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(VCINSTALLDIR) && !defined(MSSDK) && !defined(WINDOWSSDKDIR) MSG = ^ Visual C++ compiler environment not initialized. !error $(MSG) !endif # We need to run from the directory the parent makefile is located in. # nmake does not tell us what makefile was used to invoke it so parent # makefile has to set the MAKEFILEVC macro or we just make a guess and # warn if we think that is not the case. !if "$(MAKEFILEVC)" == "" !if exist("$(PROJECT).vc") MAKEFILEVC = $(PROJECT).vc !elseif exist("makefile.vc") MAKEFILEVC = makefile.vc !endif !endif # "$(MAKEFILEVC)" == "" !if !exist("$(MAKEFILEVC)") MSG = ^ You must run nmake from the directory containing the project makefile.^ If you are doing that and getting this message, set the MAKEFILEVC^ macro to the name of the project makefile. !message WARNING: $(MSG) !endif ################################################################ # 1. Define external programs being used #---------------------------------------------------------- # Set the proper copy method to avoid overwrite questions # to the user when copying files and selecting the right # "delete all" method. #---------------------------------------------------------- RMDIR = rmdir /S /Q CPY = xcopy /i /y >NUL CPYDIR = xcopy /e /i /y >NUL COPY = copy /y >NUL MKDIR = mkdir ###################################################################### # 2. Figure out our build environment in terms of what we're building. # # (a) Tcl itself # (b) Tk # (c) a Tcl extension using libraries/includes from an *installed* Tcl # (d) a Tcl extension using libraries/includes from Tcl source directory # # This last is needed because some extensions still need # some Tcl interfaces that are not publicly exposed. # # The fragment will set the following macros: # ROOT - root of this module sources # COMPATDIR - source directory that holds compatibility sources # DOCDIR - source directory containing documentation files # GENERICDIR - platform-independent source directory # WINDIR - Windows-specific source directory # TESTDIR - directory containing test files # TOOLSDIR - directory containing build tools # _TCLDIR - root of the Tcl installation OR the Tcl sources. Not set # when building Tcl itself. # _INSTALLDIR - native form of the installation path. For Tcl # this will be the root of the Tcl installation. For extensions # this will be the lib directory under the root. # TCLINSTALL - set to 1 if _TCLDIR refers to # headers and libraries from an installed Tcl, and 0 if built against # Tcl sources. Not set when building Tcl itself. Yes, not very well # named. # _TCL_H - native path to the tcl.h file # # If Tk is involved, also sets the following # _TKDIR - native form Tk installation OR Tk source. Not set if building # Tk itself. # TKINSTALL - set 1 if _TKDIR refers to installed Tk and 0 if Tk sources # _TK_H - native path to the tk.h file # Root directory for sources and assumed subdirectories ROOT = $(MAKEDIR)\.. # The following paths CANNOT have spaces in them as they appear on the # left side of implicit rules. !ifndef COMPATDIR COMPATDIR = $(ROOT)\compat !endif !ifndef DOCDIR DOCDIR = $(ROOT)\doc !endif !ifndef GENERICDIR GENERICDIR = $(ROOT)\generic !endif !ifndef TOOLSDIR TOOLSDIR = $(ROOT)\tools !endif !ifndef TESTDIR TESTDIR = $(ROOT)\tests !endif !ifndef LIBDIR !if exist("$(ROOT)\library") LIBDIR = $(ROOT)\library !else LIBDIR = $(ROOT)\lib !endif !endif !ifndef DEMODIR !if exist("$(LIBDIR)\demos") DEMODIR = $(LIBDIR)\demos !else DEMODIR = $(ROOT)\demos !endif !endif # ifndef DEMODIR # Do NOT enclose WINDIR in a !ifndef because Windows always defines # WINDIR env var to point to c:\windows! # TBD - This is a potentially dangerous conflict, rename WINDIR to # something else WINDIR = $(ROOT)\win !ifndef RCDIR !if exist("$(WINDIR)\rc") RCDIR = $(WINDIR)\rc !else RCDIR = $(WINDIR) !endif !endif RCDIR = $(RCDIR:/=\) # The target directory where the built packages and binaries will be installed. # INSTALLDIR is the (optional) path specified by the user. # _INSTALLDIR is INSTALLDIR using the backslash separator syntax !ifdef INSTALLDIR ### Fix the path separators. _INSTALLDIR = $(INSTALLDIR:/=\) !else ### Assume the normal default. _INSTALLDIR = $(HOMEDRIVE)\Tcl !endif !if $(DOING_TCL) # BEGIN Case 2(a) - Building Tcl itself # Only need to define _TCL_H _TCL_H = ..\generic\tcl.h # END Case 2(a) - Building Tcl itself !elseif $(DOING_TK) # BEGIN Case 2(b) - Building Tk TCLINSTALL = 0 # Tk always builds against Tcl source, not an installed Tcl !if "$(TCLDIR)" == "" !if [echo TCLDIR = \> nmakehlp.out] \ || [nmakehlp -L generic\tcl.h >> nmakehlp.out] !error *** Could not locate Tcl source directory. !endif !include nmakehlp.out !endif # TCLDIR == "" _TCLDIR = $(TCLDIR:/=\) _TCL_H = $(_TCLDIR)\generic\tcl.h !if !exist("$(_TCL_H)") !error Could not locate tcl.h. Please set the TCLDIR macro to point to the Tcl *source* directory. !endif _TK_H = ..\generic\tk.h # END Case 2(b) - Building Tk !else # BEGIN Case 2(c) or (d) - Building an extension other than Tk # If command line has specified Tcl location through TCLDIR, use it # else default to the INSTALLDIR setting !if "$(TCLDIR)" != "" _TCLDIR = $(TCLDIR:/=\) !if exist("$(_TCLDIR)\include\tcl.h") # Case 2(c) with TCLDIR defined TCLINSTALL = 1 _TCL_H = $(_TCLDIR)\include\tcl.h !elseif exist("$(_TCLDIR)\generic\tcl.h") # Case 2(d) with TCLDIR defined TCLINSTALL = 0 _TCL_H = $(_TCLDIR)\generic\tcl.h !endif !else # # Case 2(c) for extensions with TCLDIR undefined # Need to locate Tcl depending on whether it needs Tcl source or not. # If we don't, check the INSTALLDIR for an installed Tcl first !if exist("$(_INSTALLDIR)\include\tcl.h") && !$(NEED_TCL_SOURCE) TCLINSTALL = 1 TCLDIR = $(_INSTALLDIR)\.. # NOTE: we will be resetting _INSTALLDIR to _INSTALLDIR/lib for extensions # later so the \.. accounts for the /lib _TCLDIR = $(_INSTALLDIR)\.. _TCL_H = $(_TCLDIR)\include\tcl.h !else # exist(...) && ! $(NEED_TCL_SOURCE) !if [echo _TCLDIR = \> nmakehlp.out] \ || [nmakehlp -L generic\tcl.h >> nmakehlp.out] !error *** Could not locate Tcl source directory. !endif !include nmakehlp.out TCLINSTALL = 0 TCLDIR = $(_TCLDIR) _TCL_H = $(_TCLDIR)\generic\tcl.h !endif # exist(...) && ! $(NEED_TCL_SOURCE) !endif # TCLDIR !ifndef _TCL_H MSG =^ Failed to find tcl.h. The TCLDIR macro is set incorrectly or is not set and default path does not contain tcl.h. !error $(MSG) !endif # Now do the same to locate Tk headers and libs if project requires Tk !if $(NEED_TK) !if "$(TKDIR)" != "" _TKDIR = $(TKDIR:/=\) !if exist("$(_TKDIR)\include\tk.h") TKINSTALL = 1 _TK_H = $(_TKDIR)\include\tk.h !elseif exist("$(_TKDIR)\generic\tk.h") TKINSTALL = 0 _TK_H = $(_TKDIR)\generic\tk.h !endif !else # TKDIR not defined # Need to locate Tcl depending on whether it needs Tcl source or not. # If we don't, check the INSTALLDIR for an installed Tcl first !if exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE) TKINSTALL = 1 # NOTE: we will be resetting _INSTALLDIR to _INSTALLDIR/lib for extensions # later so the \.. accounts for the /lib _TKDIR = $(_INSTALLDIR)\.. _TK_H = $(_TKDIR)\include\tk.h TKDIR = $(_TKDIR) !else # exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE) !if [echo _TKDIR = \> nmakehlp.out] \ || [nmakehlp -L generic\tk.h >> nmakehlp.out] !error *** Could not locate Tk source directory. !endif !include nmakehlp.out TKINSTALL = 0 TKDIR = $(_TKDIR) _TK_H = $(_TKDIR)\generic\tk.h !endif # exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE) !endif # TKDIR !ifndef _TK_H MSG =^ Failed to find tk.h. The TKDIR macro is set incorrectly or is not set and default path does not contain tk.h. !error $(MSG) !endif !endif # NEED_TK !if $(NEED_TCL_SOURCE) && $(TCLINSTALL) MSG = ^ *** Warning: This extension requires the source distribution of Tcl.^ *** Please set the TCLDIR macro to point to the Tcl sources. !error $(MSG) !endif !if $(NEED_TK_SOURCE) !if $(TKINSTALL) MSG = ^ *** Warning: This extension requires the source distribution of Tk.^ *** Please set the TKDIR macro to point to the Tk sources. !error $(MSG) !endif !endif # If INSTALLDIR set to tcl installation root dir then reset to the # lib dir for installing extensions !if exist("$(_INSTALLDIR)\include\tcl.h") _INSTALLDIR=$(_INSTALLDIR)\lib !endif # END Case 2(c) or (d) - Building an extension !endif # if $(DOING_TCL) ################################################################ # 3. Determine compiler version and architecture # In this section, we figure out the compiler version and the # architecture for which we are building. This sets the # following macros: # VCVERSION - the internal compiler version as 1200, 1400, 1910 etc. # This is also printed by the compiler in dotted form 19.10 etc. # VCVER - the "marketing version", for example Visual C++ 6 for internal # compiler version 1200. This is kept only for legacy reasons as it # does not make sense for recent Microsoft compilers. Only used for # output directory names. # ARCH - set to IX86 or AMD64 depending on 32- or 64-bit target # NATIVE_ARCH - set to IX86 or AMD64 for the host machine # MACHINE - same as $(ARCH) - legacy # _VC_MANIFEST_EMBED_{DLL,EXE} - commands for embedding a manifest if needed # CFG_ENCODING - set to an character encoding. # TBD - this is passed to compiler as TCL_CFGVAL_ENCODING but can't # see where it is used cc32 = $(CC) # built-in default. link32 = link lib32 = lib rc32 = $(RC) # built-in default. #---------------------------------------------------------------- # Figure out the compiler architecture and version by writing # the C macros to a file, preprocessing them with the C # preprocessor and reading back the created file _HASH=^# _VC_MANIFEST_EMBED_EXE= _VC_MANIFEST_EMBED_DLL= VCVER=0 !if ![echo VCVERSION=_MSC_VER > vercl.x] \ && ![echo $(_HASH)if defined(_M_IX86) >> vercl.x] \ && ![echo ARCH=IX86 >> vercl.x] \ && ![echo $(_HASH)elif defined(_M_AMD64) >> vercl.x] \ && ![echo ARCH=AMD64 >> vercl.x] \ && ![echo $(_HASH)endif >> vercl.x] \ && ![$(cc32) -nologo -TC -P vercl.x 2>NUL] !include vercl.i !if $(VCVERSION) < 1900 !if ![echo VCVER= ^\> vercl.vc] \ && ![set /a $(VCVERSION) / 100 - 6 >> vercl.vc] !include vercl.vc !endif !else # The simple calculation above does not apply to new Visual Studio releases # Keep the compiler version in its native form. VCVER = $(VCVERSION) !endif !endif !if ![del 2>NUL /q/f vercl.x vercl.i vercl.vc] !endif #---------------------------------------------------------------- # The MACHINE macro is used by legacy makefiles so set it as well !ifdef MACHINE !if "$(MACHINE)" == "x86" !undef MACHINE MACHINE = IX86 !elseif "$(MACHINE)" == "x64" !undef MACHINE MACHINE = AMD64 !endif !if "$(MACHINE)" != "$(ARCH)" !error Specified MACHINE macro $(MACHINE) does not match detected target architecture $(ARCH). !endif !else MACHINE=$(ARCH) !endif #------------------------------------------------------------ # Figure out the *host* architecture by reading the registry !if ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i x86] NATIVE_ARCH=IX86 !else NATIVE_ARCH=AMD64 !endif # Since MSVC8 we must deal with manifest resources. !if $(VCVERSION) >= 1400 _VC_MANIFEST_EMBED_EXE=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;1 _VC_MANIFEST_EMBED_DLL=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2 !endif !ifndef CFG_ENCODING CFG_ENCODING = \"cp1252\" !endif ################################################################ # 4. Build the nmakehlp program # This is a helper app we need to overcome nmake's limiting # environment. We will call out to it to get various bits of # information about supported compiler options etc. # # Tcl itself will always use the nmakehlp.c program which is # in its own source. This is the "master" copy and kept updated. # # Extensions built against an installed Tcl will use the installed # copy of Tcl's nmakehlp.c if there is one and their own version # otherwise. In the latter case, they would also be using their own # rules.vc. Note that older versions of Tcl do not install nmakehlp.c # or rules.vc. # # Extensions built against Tcl sources will use the one from the Tcl source. # # When building an extension using a sufficiently new version of Tcl, # rules-ext.vc will define NMAKEHLPC appropriately to point to the # copy of nmakehlp.c to be used. !ifndef NMAKEHLPC # Default to the one in the current directory (the extension's own nmakehlp.c) NMAKEHLPC = nmakehlp.c !if !$(DOING_TCL) !if $(TCLINSTALL) !if exist("$(_TCLDIR)\lib\nmake\nmakehlp.c") NMAKEHLPC = $(_TCLDIR)\lib\nmake\nmakehlp.c !endif !else # ! $(TCLINSTALL) !if exist("$(_TCLDIR)\win\nmakehlp.c") NMAKEHLPC = $(_TCLDIR)\win\nmakehlp.c !endif !endif # $(TCLINSTALL) !endif # !$(DOING_TCL) !endif # NMAKEHLPC # We always build nmakehlp even if it exists since we do not know # what source it was built from. !message *** Using $(NMAKEHLPC) !if [$(cc32) -nologo "$(NMAKEHLPC)" -link -subsystem:console > nul] !endif ################################################################ # 5. Test for compiler features # Visual C++ compiler options have changed over the years. Check # which options are supported by the compiler in use. # # The following macros are set: # OPTIMIZATIONS - the compiler flags to be used for optimized builds # DEBUGFLAGS - the compiler flags to be used for debug builds # LINKERFLAGS - Flags passed to the linker # # Note that these are the compiler settings *available*, not those # that will be *used*. The latter depends on the OPTS macro settings # which we have not yet parsed. # # Also note that some of the flags in OPTIMIZATIONS are not really # related to optimization. They are placed there only for legacy reasons # as some extensions expect them to be included in that macro. # -Op improves float consistency. Note only needed for older compilers # Newer compilers do not need or support this option. !if [nmakehlp -c -Op] FPOPTS = -Op !endif # Strict floating point semantics - present in newer compilers in lieu of -Op !if [nmakehlp -c -fp:strict] FPOPTS = $(FPOPTS) -fp:strict !endif !if "$(MACHINE)" == "IX86" ### test for pentium errata !if [nmakehlp -c -QI0f] !message *** Compiler has 'Pentium 0x0f fix' FPOPTS = $(FPOPTS) -QI0f !else !message *** Compiler does not have 'Pentium 0x0f fix' !endif !endif ### test for optimizations # /O2 optimization includes /Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy as per # documentation. Note we do NOT want /Gs as that inserts a _chkstk # stack probe at *every* function entry, not just those with more than # a page of stack allocation resulting in a performance hit. However, # /O2 documentation is misleading as its stack probes are simply the # default page size locals allocation probes and not what is implied # by an explicit /Gs option. OPTIMIZATIONS = $(FPOPTS) !if [nmakehlp -c -O2] !message *** Compiler has 'Optimizations' OPTIMIZING = 1 OPTIMIZATIONS = $(OPTIMIZATIONS) -O2 !else # Legacy, really. All modern compilers support this !message *** Compiler does not have 'Optimizations' OPTIMIZING = 0 !endif # Checks for buffer overflows in local arrays !if [nmakehlp -c -GS] OPTIMIZATIONS = $(OPTIMIZATIONS) -GS !endif # Link time optimization. Note that this option (potentially) makes # generated libraries only usable by the specific VC++ version that # created it. Requires /LTCG linker option !if [nmakehlp -c -GL] OPTIMIZATIONS = $(OPTIMIZATIONS) -GL CC_GL_OPT_ENABLED = 1 !else # In newer compilers -GL and -YX are incompatible. !if [nmakehlp -c -YX] OPTIMIZATIONS = $(OPTIMIZATIONS) -YX !endif !endif # [nmakehlp -c -GL] DEBUGFLAGS = $(FPOPTS) # Run time error checks. Not available or valid in a release, non-debug build # RTC is for modern compilers, -GZ is legacy !if [nmakehlp -c -RTC1] DEBUGFLAGS = $(DEBUGFLAGS) -RTC1 !elseif [nmakehlp -c -GZ] DEBUGFLAGS = $(DEBUGFLAGS) -GZ !endif #---------------------------------------------------------------- # Linker flags # LINKER_TESTFLAGS are for internal use when we call nmakehlp to test # if the linker supports a specific option. Without these flags link will # return "LNK1561: entry point must be defined" error compiling from VS-IDE: # They are not passed through to the actual application / extension # link rules. !ifndef LINKER_TESTFLAGS LINKER_TESTFLAGS = /DLL /NOENTRY /OUT:nmakehlp.out !endif LINKERFLAGS = # If compiler has enabled link time optimization, linker must too with -ltcg !ifdef CC_GL_OPT_ENABLED !if [nmakehlp -l -ltcg $(LINKER_TESTFLAGS)] LINKERFLAGS = $(LINKERFLAGS) -ltcg !endif !endif ######################################################################## # 6. Parse the OPTS macro to work out the requested build configuration. # Based on this, we will construct the actual switches to be passed to the # compiler and linker using the macros defined in the previous section. # The following macros are defined by this section based on OPTS # STATIC_BUILD - 0 -> Tcl is to be built as a shared library # 1 -> build as a static library and shell # TCL_THREADS - legacy but always 1 on Windows since winsock requires it. # DEBUG - 1 -> debug build, 0 -> release builds # SYMBOLS - 1 -> generate PDB's, 0 -> no PDB's # PROFILE - 1 -> generate profiling info, 0 -> no profiling # PGO - 1 -> profile based optimization, 0 -> no # MSVCRT - 1 -> link to dynamic C runtime even when building static Tcl build # 0 -> link to static C runtime for static Tcl build. # Does not impact shared Tcl builds (STATIC_BUILD == 0) # TCL_USE_STATIC_PACKAGES - 1 -> statically link the registry and dde extensions # in the Tcl shell. 0 -> keep them as shared libraries # Does not impact shared Tcl builds. # USE_THREAD_ALLOC - 1 -> Use a shared global free pool for allocation. # 0 -> Use the non-thread allocator. # UNCHECKED - 1 -> when doing a debug build with symbols, use the release # C runtime, 0 -> use the debug C runtime. # USE_STUBS - 1 -> compile to use stubs interfaces, 0 -> direct linking # CONFIG_CHECK - 1 -> check current build configuration against Tcl # configuration (ignored for Tcl itself) # Further, LINKERFLAGS are modified based on above. # Default values for all the above STATIC_BUILD = 0 TCL_THREADS = 1 DEBUG = 0 SYMBOLS = 0 PROFILE = 0 PGO = 0 MSVCRT = 1 TCL_USE_STATIC_PACKAGES = 0 USE_THREAD_ALLOC = 1 UNCHECKED = 0 CONFIG_CHECK = 1 !if $(DOING_TCL) USE_STUBS = 0 !else USE_STUBS = 1 !endif # If OPTS is not empty AND does not contain "none" which turns off all OPTS # set the above macros based on OPTS content !if "$(OPTS)" != "" && ![nmakehlp -f "$(OPTS)" "none"] # OPTS are specified, parse them !if [nmakehlp -f $(OPTS) "static"] !message *** Doing static STATIC_BUILD = 1 !endif !if [nmakehlp -f $(OPTS) "nostubs"] !message *** Not using stubs USE_STUBS = 0 !endif !if [nmakehlp -f $(OPTS) "nomsvcrt"] !message *** Doing nomsvcrt MSVCRT = 0 !else !if [nmakehlp -f $(OPTS) "msvcrt"] !message *** Doing msvcrt MSVCRT = 1 !else !if !$(STATIC_BUILD) MSVCRT = 1 !else MSVCRT = 0 !endif !endif !endif # [nmakehlp -f $(OPTS) "nomsvcrt"] !if [nmakehlp -f $(OPTS) "staticpkg"] && $(STATIC_BUILD) !message *** Doing staticpkg TCL_USE_STATIC_PACKAGES = 1 !else TCL_USE_STATIC_PACKAGES = 0 !endif !if [nmakehlp -f $(OPTS) "nothreads"] !message *** Compile explicitly for non-threaded tcl TCL_THREADS = 0 USE_THREAD_ALLOC= 0 !else TCL_THREADS = 1 USE_THREAD_ALLOC= 1 !endif !if [nmakehlp -f $(OPTS) "symbols"] !message *** Doing symbols DEBUG = 1 !else DEBUG = 0 !endif !if [nmakehlp -f $(OPTS) "pdbs"] !message *** Doing pdbs SYMBOLS = 1 !else SYMBOLS = 0 !endif !if [nmakehlp -f $(OPTS) "profile"] !message *** Doing profile PROFILE = 1 !else PROFILE = 0 !endif !if [nmakehlp -f $(OPTS) "pgi"] !message *** Doing profile guided optimization instrumentation PGO = 1 !elseif [nmakehlp -f $(OPTS) "pgo"] !message *** Doing profile guided optimization PGO = 2 !else PGO = 0 !endif !if [nmakehlp -f $(OPTS) "loimpact"] !message *** Warning: ignoring option "loimpact" - deprecated on modern Windows. !endif # TBD - should get rid of this option !if [nmakehlp -f $(OPTS) "thrdalloc"] !message *** Doing thrdalloc USE_THREAD_ALLOC = 1 !endif !if [nmakehlp -f $(OPTS) "tclalloc"] USE_THREAD_ALLOC = 0 !endif !if [nmakehlp -f $(OPTS) "unchecked"] !message *** Doing unchecked UNCHECKED = 1 !else UNCHECKED = 0 !endif !if [nmakehlp -f $(OPTS) "noconfigcheck"] CONFIG_CHECK = 1 !else CONFIG_CHECK = 0 !endif !endif # "$(OPTS)" != "" && ... parsing of OPTS # Set linker flags based on above !if $(PGO) > 1 !if [nmakehlp -l -ltcg:pgoptimize $(LINKER_TESTFLAGS)] LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pgoptimize !else MSG=^ This compiler does not support profile guided optimization. !error $(MSG) !endif !elseif $(PGO) > 0 !if [nmakehlp -l -ltcg:pginstrument $(LINKER_TESTFLAGS)] LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pginstrument !else MSG=^ This compiler does not support profile guided optimization. !error $(MSG) !endif !endif ################################################################ # 7. Parse the STATS macro to configure code instrumentation # The following macros are set by this section: # TCL_MEM_DEBUG - 1 -> enables memory allocation instrumentation # 0 -> disables # TCL_COMPILE_DEBUG - 1 -> enables byte compiler logging # 0 -> disables # Default both are off TCL_MEM_DEBUG = 0 TCL_COMPILE_DEBUG = 0 !if "$(STATS)" != "" && ![nmakehlp -f "$(STATS)" "none"] !if [nmakehlp -f $(STATS) "memdbg"] !message *** Doing memdbg TCL_MEM_DEBUG = 1 !else TCL_MEM_DEBUG = 0 !endif !if [nmakehlp -f $(STATS) "compdbg"] !message *** Doing compdbg TCL_COMPILE_DEBUG = 1 !else TCL_COMPILE_DEBUG = 0 !endif !endif #################################################################### # 8. Parse the CHECKS macro to configure additional compiler checks # The following macros are set by this section: # WARNINGS - compiler switches that control the warnings level # TCL_NO_DEPRECATED - 1 -> disable support for deprecated functions # 0 -> enable deprecated functions # Defaults - Permit deprecated functions and warning level 3 TCL_NO_DEPRECATED = 0 WARNINGS = -W3 !if "$(CHECKS)" != "" && ![nmakehlp -f "$(CHECKS)" "none"] !if [nmakehlp -f $(CHECKS) "nodep"] !message *** Doing nodep check TCL_NO_DEPRECATED = 1 !endif !if [nmakehlp -f $(CHECKS) "fullwarn"] !message *** Doing full warnings check WARNINGS = -W4 !if [nmakehlp -l -warn:3 $(LINKER_TESTFLAGS)] LINKERFLAGS = $(LINKERFLAGS) -warn:3 !endif !endif !if [nmakehlp -f $(CHECKS) "64bit"] && [nmakehlp -c -Wp64] !message *** Doing 64bit portability warnings WARNINGS = $(WARNINGS) -Wp64 !endif !endif ################################################################ # 9. Extract various version numbers # For Tcl and Tk, version numbers are extracted from tcl.h and tk.h # respectively. For extensions, versions are extracted from the # configure.in or configure.ac from the TEA configuration if it # exists, and unset otherwise. # Sets the following macros: # TCL_MAJOR_VERSION # TCL_MINOR_VERSION # TCL_PATCH_LEVEL # TCL_VERSION # TK_MAJOR_VERSION # TK_MINOR_VERSION # TK_PATCH_LEVEL # TK_VERSION # DOTVERSION - set as (for example) 2.5 # VERSION - set as (for example 25) #-------------------------------------------------------------- !message >>> $(_TCL_H) !if [echo REM = This file is generated from rules.vc > versions.vc] !endif !if [echo TCL_MAJOR_VERSION = \>> versions.vc] \ && [nmakehlp -V "$(_TCL_H)" "define TCL_MAJOR_VERSION" >> versions.vc] !endif !if [echo TCL_MINOR_VERSION = \>> versions.vc] \ && [nmakehlp -V "$(_TCL_H)" TCL_MINOR_VERSION >> versions.vc] !endif !if [echo TCL_PATCH_LEVEL = \>> versions.vc] \ && [nmakehlp -V "$(_TCL_H)" TCL_PATCH_LEVEL >> versions.vc] !endif !if defined(_TK_H) !if [echo TK_MAJOR_VERSION = \>> versions.vc] \ && [nmakehlp -V $(_TK_H) TK_MAJOR_VERSION >> versions.vc] !endif !if [echo TK_MINOR_VERSION = \>> versions.vc] \ && [nmakehlp -V $(_TK_H) TK_MINOR_VERSION >> versions.vc] !endif !if [echo TK_PATCH_LEVEL = \>> versions.vc] \ && [nmakehlp -V $(_TK_H) TK_PATCH_LEVEL >> versions.vc] !endif !endif # _TK_H !include versions.vc TCL_VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION) TCL_DOTVERSION = $(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION) !if defined(_TK_H) TK_VERSION = $(TK_MAJOR_VERSION)$(TK_MINOR_VERSION) TK_DOTVERSION = $(TK_MAJOR_VERSION).$(TK_MINOR_VERSION) !endif # Set DOTVERSION and VERSION !if $(DOING_TCL) DOTVERSION = $(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION) VERSION = $(TCL_VERSION) !elseif $(DOING_TK) DOTVERSION = $(TK_DOTVERSION) VERSION = $(TK_VERSION) !else # Doing a non-Tk extension # If parent makefile has not defined DOTVERSION, try to get it from TEA # first from a configure.in file, and then from configure.ac !ifndef DOTVERSION !if [echo DOTVERSION = \> versions.vc] \ || [nmakehlp -V $(ROOT)\configure.in ^[$(PROJECT)^] >> versions.vc] !if [echo DOTVERSION = \> versions.vc] \ || [nmakehlp -V $(ROOT)\configure.ac ^[$(PROJECT)^] >> versions.vc] !error *** Could not figure out extension version. Please define DOTVERSION in parent makefile before including rules.vc. !endif !endif !include versions.vc !endif # DOTVERSION VERSION = $(DOTVERSION:.=) !endif # $(DOING_TCL) ... etc. ################################################################ # 10. Construct output directory and file paths # Figure-out how to name our intermediate and output directories. # In order to avoid inadvertent mixing of object files built using # different compilers, build configurations etc., # # Naming convention (suffixes): # t = full thread support. # s = static library (as opposed to an import library) # g = linked to the debug enabled C run-time. # x = special static build when it links to the dynamic C run-time. # # The following macros are set in this section: # SUFX - the suffix to use for binaries based on above naming convention # BUILDDIRTOP - the toplevel default output directory # is of the form {Release,Debug}[_AMD64][_COMPILERVERSION] # TMP_DIR - directory where object files are created # OUT_DIR - directory where output executables are created # Both TMP_DIR and OUT_DIR are defaulted only if not defined by the # parent makefile (or command line). The default values are # based on BUILDDIRTOP. # STUBPREFIX - name of the stubs library for this project # PRJIMPLIB - output path of the generated project import library # PRJLIBNAME - name of generated project library # PRJLIB - output path of generated project library # PRJSTUBLIBNAME - name of the generated project stubs library # PRJSTUBLIB - output path of the generated project stubs library # RESFILE - output resource file (only if not static build) SUFX = tsgx !if $(DEBUG) BUILDDIRTOP = Debug !else BUILDDIRTOP = Release !endif !if "$(MACHINE)" != "IX86" BUILDDIRTOP =$(BUILDDIRTOP)_$(MACHINE) !endif !if $(VCVER) > 6 BUILDDIRTOP =$(BUILDDIRTOP)_VC$(VCVER) !endif !if !$(DEBUG) || $(DEBUG) && $(UNCHECKED) SUFX = $(SUFX:g=) !endif TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_ThreadedDynamicStaticX !if !$(STATIC_BUILD) TMP_DIRFULL = $(TMP_DIRFULL:Static=) SUFX = $(SUFX:s=) EXT = dll TMP_DIRFULL = $(TMP_DIRFULL:X=) SUFX = $(SUFX:x=) !else TMP_DIRFULL = $(TMP_DIRFULL:Dynamic=) EXT = lib !if !$(MSVCRT) TMP_DIRFULL = $(TMP_DIRFULL:X=) SUFX = $(SUFX:x=) !endif !endif !if !$(TCL_THREADS) TMP_DIRFULL = $(TMP_DIRFULL:Threaded=) SUFX = $(SUFX:t=) !endif !ifndef TMP_DIR TMP_DIR = $(TMP_DIRFULL) !ifndef OUT_DIR OUT_DIR = .\$(BUILDDIRTOP) !endif !else !ifndef OUT_DIR OUT_DIR = $(TMP_DIR) !endif !endif # Relative paths -> absolute !if [echo OUT_DIR = \> nmakehlp.out] \ || [nmakehlp -Q "$(OUT_DIR)" >> nmakehlp.out] !error *** Could not fully qualify path OUT_DIR=$(OUT_DIR) !endif !if [echo TMP_DIR = \>> nmakehlp.out] \ || [nmakehlp -Q "$(TMP_DIR)" >> nmakehlp.out] !error *** Could not fully qualify path TMP_DIR=$(TMP_DIR) !endif !include nmakehlp.out # The name of the stubs library for the project being built STUBPREFIX = $(PROJECT)stub # Set up paths to various Tcl executables and libraries needed by extensions !if $(DOING_TCL) TCLSHNAME = $(PROJECT)sh$(TCL_VERSION)$(SUFX).exe TCLSH = $(OUT_DIR)\$(TCLSHNAME) TCLIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib TCLLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT) TCLLIB = $(OUT_DIR)\$(TCLLIBNAME) TCLSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib TCLSTUBLIB = $(OUT_DIR)\$(TCLSTUBLIBNAME) TCL_INCLUDES = -I"$(WINDIR)" -I"$(GENERICDIR)" !else # ! $(DOING_TCL) !if $(TCLINSTALL) # Building against an installed Tcl # When building extensions, we need to locate tclsh. Depending on version # of Tcl we are building against, this may or may not have a "t" suffix. # Try various possibilities in turn. TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX:t=).exe !if !exist("$(TCLSH)") TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)t$(SUFX:t=).exe !endif TCLSTUBLIB = $(_TCLDIR)\lib\tclstub$(TCL_VERSION).lib TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX:t=).lib # When building extensions, may be linking against Tcl that does not add # "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility. !if !exist("$(TCLIMPLIB)") TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)t$(SUFX:t=).lib !endif TCL_LIBRARY = $(_TCLDIR)\lib TCLREGLIB = $(_TCLDIR)\lib\tclreg13$(SUFX:t=).lib TCLDDELIB = $(_TCLDIR)\lib\tcldde14$(SUFX:t=).lib TCLTOOLSDIR = \must\have\tcl\sources\to\build\this\target TCL_INCLUDES = -I"$(_TCLDIR)\include" !else # Building against Tcl sources TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX:t=).exe !if !exist($(TCLSH)) TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)t$(SUFX:t=).exe !endif TCLSTUBLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub$(TCL_VERSION).lib TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX:t=).lib # When building extensions, may be linking against Tcl that does not add # "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility. !if !exist("$(TCLIMPLIB)") TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)t$(SUFX:t=).lib !endif TCL_LIBRARY = $(_TCLDIR)\library TCLREGLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclreg13$(SUFX:t=).lib TCLDDELIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcldde14$(SUFX:t=).lib TCLTOOLSDIR = $(_TCLDIR)\tools TCL_INCLUDES = -I"$(_TCLDIR)\generic" -I"$(_TCLDIR)\win" !endif # TCLINSTALL tcllibs = "$(TCLSTUBLIB)" "$(TCLIMPLIB)" !endif # $(DOING_TCL) # We need a tclsh that will run on the host machine as part of the build. # IX86 runs on all architectures. !ifndef TCLSH_NATIVE !if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)" TCLSH_NATIVE = $(TCLSH) !else !error You must explicitly set TCLSH_NATIVE for cross-compilation !endif !endif # Do the same for Tk and Tk extensions that require the Tk libraries !if $(DOING_TK) || $(NEED_TK) WISHNAMEPREFIX = wish WISHNAME = $(WISHNAMEPREFIX)$(TK_VERSION)$(SUFX).exe TKLIBNAME = $(PROJECT)$(TK_VERSION)$(SUFX).$(EXT) TKSTUBLIBNAME = tkstub$(TK_VERSION).lib TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX).lib !if $(DOING_TK) WISH = $(OUT_DIR)\$(WISHNAME) TKSTUBLIB = $(OUT_DIR)\$(TKSTUBLIBNAME) TKIMPLIB = $(OUT_DIR)\$(TKIMPLIBNAME) TKLIB = $(OUT_DIR)\$(TKLIBNAME) TK_INCLUDES = -I"$(WINDIR)" -I"$(GENERICDIR)" !else # effectively NEED_TK !if $(TKINSTALL) # Building against installed Tk WISH = $(_TKDIR)\bin\$(WISHNAME) TKSTUBLIB = $(_TKDIR)\lib\$(TKSTUBLIBNAME) TKIMPLIB = $(_TKDIR)\lib\$(TKIMPLIBNAME) TK_INCLUDES = -I"$(_TKDIR)\include" !else # Building against Tk sources WISH = $(_TKDIR)\win\$(BUILDDIRTOP)\$(WISHNAME) TKSTUBLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKSTUBLIBNAME) TKIMPLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKIMPLIBNAME) TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib" !endif # TKINSTALL tklibs = "$(TKSTUBLIB)" "$(TKIMPLIB)" !endif # $(DOING_TK) !endif # $(DOING_TK) || $(NEED_TK) # Various output paths PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib PRJLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT) PRJLIB = $(OUT_DIR)\$(PRJLIBNAME) PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME) # If extension parent makefile has not defined a resource definition file, # we will generate one from standard template. !if !$(DOING_TCL) && !$(DOING_TK) && !$(STATIC_BUILD) !ifdef RCFILE RESFILE = $(TMP_DIR)\$(RCFILE:.rc=.res) !else RESFILE = $(TMP_DIR)\$(PROJECT).res !endif !endif ################################################################### # 11. Construct the paths for the installation directories # The following macros get defined in this section: # LIB_INSTALL_DIR - where libraries should be installed # BIN_INSTALL_DIR - where the executables should be installed # DOC_INSTALL_DIR - where documentation should be installed # SCRIPT_INSTALL_DIR - where scripts should be installed # INCLUDE_INSTALL_DIR - where C include files should be installed # DEMO_INSTALL_DIR - where demos should be installed # PRJ_INSTALL_DIR - where package will be installed (not set for tcl and tk) !if $(DOING_TCL) || $(DOING_TK) LIB_INSTALL_DIR = $(_INSTALLDIR)\lib BIN_INSTALL_DIR = $(_INSTALLDIR)\bin DOC_INSTALL_DIR = $(_INSTALLDIR)\doc !if $(DOING_TCL) SCRIPT_INSTALL_DIR = $(_INSTALLDIR)\lib\$(PROJECT)$(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION) !else # DOING_TK SCRIPT_INSTALL_DIR = $(_INSTALLDIR)\lib\$(PROJECT)$(TK_MAJOR_VERSION).$(TK_MINOR_VERSION) !endif DEMO_INSTALL_DIR = $(SCRIPT_INSTALL_DIR)\demos INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\include !else # extension other than Tk PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION) LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR) BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR) DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR) SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR) DEMO_INSTALL_DIR = $(PRJ_INSTALL_DIR)\demos INCLUDE_INSTALL_DIR = $(_TCLDIR)\include !endif ################################################################### # 12. Set up actual options to be passed to the compiler and linker # Now we have all the information we need, set up the actual flags and # options that we will pass to the compiler and linker. The main # makefile should use these in combination with whatever other flags # and switches are specific to it. # The following macros are defined, names are for historical compatibility: # OPTDEFINES - /Dxxx C macro flags based on user-specified OPTS # COMPILERFLAGS - /Dxxx C macro flags independent of any configuration opttions # crt - Compiler switch that selects the appropriate C runtime # cdebug - Compiler switches related to debug AND optimizations # cwarn - Compiler switches that set warning levels # cflags - complete compiler switches (subsumes cdebug and cwarn) # ldebug - Linker switches controlling debug information and optimization # lflags - complete linker switches (subsumes ldebug) except subsystem type # dlllflags - complete linker switches to build DLLs (subsumes lflags) # conlflags - complete linker switches for console program (subsumes lflags) # guilflags - complete linker switches for GUI program (subsumes lflags) # baselibs - minimum Windows libraries required. Parent makefile can # define PRJ_LIBS before including rules.rc if additional libs are needed OPTDEFINES = -DTCL_CFGVAL_ENCODING=$(CFG_ENCODING) -DSTDC_HEADERS !if $(TCL_MEM_DEBUG) OPTDEFINES = $(OPTDEFINES) -DTCL_MEM_DEBUG !endif !if $(TCL_COMPILE_DEBUG) OPTDEFINES = $(OPTDEFINES) -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS !endif !if $(TCL_THREADS) OPTDEFINES = $(OPTDEFINES) -DTCL_THREADS=1 !if $(USE_THREAD_ALLOC) OPTDEFINES = $(OPTDEFINES) -DUSE_THREAD_ALLOC=1 !endif !endif !if $(STATIC_BUILD) OPTDEFINES = $(OPTDEFINES) -DSTATIC_BUILD !endif !if $(TCL_NO_DEPRECATED) OPTDEFINES = $(OPTDEFINES) -DTCL_NO_DEPRECATED !endif !if $(USE_STUBS) # Note we do not define USE_TCL_STUBS even when building tk since some # test targets in tk do not use stubs !if ! $(DOING_TCL) USE_STUBS_DEFS = -DUSE_TCL_STUBS -DUSE_TCLOO_STUBS !if $(NEED_TK) USE_STUBS_DEFS = $(USE_STUBS_DEFS) -DUSE_TK_STUBS !endif !endif !endif # USE_STUBS !if !$(DEBUG) OPTDEFINES = $(OPTDEFINES) -DNDEBUG !if $(OPTIMIZING) OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_OPTIMIZED !endif !endif !if $(PROFILE) OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_PROFILED !endif !if "$(MACHINE)" == "AMD64" OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DO64BIT !endif !if $(VCVERSION) < 1300 OPTDEFINES = $(OPTDEFINES) -DNO_STRTOI64 !endif # _ATL_XP_TARGETING - Newer SDK's need this to build for XP COMPILERFLAGS = /D_ATL_XP_TARGETING # Following is primarily for the benefit of extensions. Tcl 8.5 builds # Tcl without /DUNICODE, while 8.6 builds with it defined. When building # an extension, it is advisable (but not mandated) to use the same Windows # API as the Tcl build. This is accordingly defaulted below. A particular # extension can override this by pre-defining USE_WIDECHAR_API. !ifndef USE_WIDECHAR_API !if $(TCL_VERSION) > 85 USE_WIDECHAR_API = 1 !else USE_WIDECHAR_API = 0 !endif !endif !if $(USE_WIDECHAR_API) COMPILERFLAGS = $(COMPILERFLAGS) /DUNICODE /D_UNICODE !endif # Like the TEA system only set this non empty for non-Tk extensions # Note: some extensions use PACKAGE_NAME and others use PACKAGE_TCLNAME # so we pass both !if !$(DOING_TCL) && !$(DOING_TK) PKGNAMEFLAGS = -DPACKAGE_NAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \ -DPACKAGE_TCLNAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \ -DPACKAGE_VERSION="\"$(DOTVERSION)\"" \ -DMODULE_SCOPE=extern !endif # crt picks the C run time based on selected OPTS !if $(MSVCRT) !if $(DEBUG) && !$(UNCHECKED) crt = -MDd !else crt = -MD !endif !else !if $(DEBUG) && !$(UNCHECKED) crt = -MTd !else crt = -MT !endif !endif # cdebug includes compiler options for debugging as well as optimization. !if $(DEBUG) # In debugging mode, optimizations need to be disabled cdebug = -Zi -Od $(DEBUGFLAGS) !else cdebug = $(OPTIMIZATIONS) !if $(SYMBOLS) cdebug = $(cdebug) -Zi !endif !endif # $(DEBUG) # cwarn includes default warning levels. cwarn = $(WARNINGS) !if "$(MACHINE)" == "AMD64" # Disable pointer<->int warnings related to cast between different sizes # There are a gadzillion of these due to use of ClientData and # clutter up compiler # output increasing chance of a real warning getting lost. So disable them. # Eventually some day, Tcl will be 64-bit clean. cwarn = $(cwarn) -wd4311 -wd4312 !endif ### Common compiler options that are architecture specific !if "$(MACHINE)" == "ARM" carch = -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE !else carch = !endif !if $(DEBUG) # Turn warnings into errors cwarn = $(cwarn) -WX !endif INCLUDES = $(TCL_INCLUDES) $(TK_INCLUDES) $(PRJ_INCLUDES) !if !$(DOING_TCL) && !$(DOING_TK) INCLUDES = $(INCLUDES) -I"$(GENERICDIR)" -I"$(WINDIR)" -I"$(COMPATDIR)" !endif # These flags are defined roughly in the order of the pre-reform # rules.vc/makefile.vc to help visually compare that the pre- and # post-reform build logs # cflags contains generic flags used for building practically all object files cflags = -nologo -c $(COMPILERFLAGS) $(carch) $(cwarn) -Fp$(TMP_DIR)^\ $(cdebug) # appcflags contains $(cflags) and flags for building the application # object files (e.g. tclsh, or wish) pkgcflags contains $(cflags) plus # flags used for building shared object files The two differ in the # BUILD_$(PROJECT) macro which should be defined only for the shared # library *implementation* and not for its caller interface appcflags = $(cflags) $(crt) $(INCLUDES) $(TCL_DEFINES) $(PRJ_DEFINES) $(OPTDEFINES) $(USE_STUBS_DEFS) appcflags_nostubs = $(cflags) $(crt) $(INCLUDES) $(TCL_DEFINES) $(PRJ_DEFINES) $(OPTDEFINES) pkgcflags = $(appcflags) $(PKGNAMEFLAGS) -DBUILD_$(PROJECT) pkgcflags_nostubs = $(appcflags_nostubs) $(PKGNAMEFLAGS) -DBUILD_$(PROJECT) # stubscflags contains $(cflags) plus flags used for building a stubs # library for the package. Note: -DSTATIC_BUILD is defined in # $(OPTDEFINES) only if the OPTS configuration indicates a static # library. However the stubs library is ALWAYS static hence included # here irrespective of the OPTS setting. # # TBD - tclvfs has a comment that stubs libs should not be compiled with -GL # without stating why. Tcl itself compiled stubs libs with this flag. # so we do not remove it from cflags. -GL may prevent extensions # compiled with one VC version to fail to link against stubs library # compiled with another VC version. Check for this and fix accordingly. stubscflags = $(cflags) $(PKGNAMEFLAGS) $(PRJ_DEFINES) $(OPTDEFINES) -Zl -DSTATIC_BUILD $(INCLUDES) # Link flags !if $(DEBUG) ldebug = -debug -debugtype:cv !else ldebug = -release -opt:ref -opt:icf,3 !if $(SYMBOLS) ldebug = $(ldebug) -debug -debugtype:cv !endif !endif # Note: Profiling is currently only possible with the Visual Studio Enterprise !if $(PROFILE) ldebug= $(ldebug) -profile !endif ### Declarations common to all linker versions lflags = -nologo -machine:$(MACHINE) $(LINKERFLAGS) $(ldebug) !if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900 lflags = $(lflags) -nodefaultlib:libucrt.lib !endif # Old linkers (Visual C++ 6 in particular) will link for fast loading # on Win98. Since we do not support Win98 any more, we specify nowin98 # as recommended for NT and later. However, this is only required by # IX86 on older compilers and only needed if we are not doing a static build. !if "$(MACHINE)" == "IX86" && !$(STATIC_BUILD) !if [nmakehlp -l -opt:nowin98 $(LINKER_TESTFLAGS)] # Align sections for PE size savings. lflags = $(lflags) -opt:nowin98 !endif !endif dlllflags = $(lflags) -dll conlflags = $(lflags) -subsystem:console guilflags = $(lflags) -subsystem:windows # Libraries that are required for every image. # Extensions should define any additional libraries with $(PRJ_LIBS) winlibs = kernel32.lib advapi32.lib !if $(NEED_TK) winlibs = $(winlibs) gdi32.lib user32.lib uxtheme.lib !endif # Avoid 'unresolved external symbol __security_cookie' errors. # c.f. http://support.microsoft.com/?id=894573 !if "$(MACHINE)" == "AMD64" !if $(VCVERSION) > 1399 && $(VCVERSION) < 1500 winlibs = $(winlibs) bufferoverflowU.lib !endif !endif baselibs = $(winlibs) $(PRJ_LIBS) !if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900 baselibs = $(baselibs) ucrt.lib !endif ################################################################ # 13. Define standard commands, common make targets and implicit rules CCPKGCMD = $(cc32) $(pkgcflags) -Fo$(TMP_DIR)^\ CCAPPCMD = $(cc32) $(appcflags) -Fo$(TMP_DIR)^\ CCSTUBSCMD = $(cc32) $(stubscflags) -Fo$(TMP_DIR)^\ LIBCMD = $(lib32) -nologo $(LINKERFLAGS) -out:$@ DLLCMD = $(link32) $(dlllflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs) CONEXECMD = $(link32) $(conlflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs) GUIEXECMD = $(link32) $(guilflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs) RESCMD = $(rc32) -fo $@ -r -i "$(GENERICDIR)" -i "$(TMP_DIR)" \ $(TCL_INCLUDES) \ -DDEBUG=$(DEBUG) -d UNCHECKED=$(UNCHECKED) \ -DCOMMAVERSION=$(DOTVERSION:.=,),0 \ -DDOTVERSION=\"$(DOTVERSION)\" \ -DVERSION=\"$(VERSION)\" \ -DSUFX=\"$(SUFX)\" \ -DPROJECT=\"$(PROJECT)\" \ -DPRJLIBNAME=\"$(PRJLIBNAME)\" !ifndef DEFAULT_BUILD_TARGET DEFAULT_BUILD_TARGET = $(PROJECT) !endif default-target: $(DEFAULT_BUILD_TARGET) default-pkgindex: @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \ [list load [file join $$dir $(PRJLIBNAME)]] > $(OUT_DIR)\pkgIndex.tcl default-pkgindex-tea: @if exist $(ROOT)\pkgIndex.tcl.in nmakehlp -s << $(ROOT)\pkgIndex.tcl.in > $(OUT_DIR)\pkgIndex.tcl @PACKAGE_VERSION@ $(DOTVERSION) @PACKAGE_NAME@ $(PRJ_PACKAGE_TCLNAME) @PACKAGE_TCLNAME@ $(PRJ_PACKAGE_TCLNAME) @PKG_LIB_FILE@ $(PRJLIBNAME) << default-install: default-install-binaries default-install-libraries default-install-binaries: $(PRJLIB) @echo Installing binaries to '$(SCRIPT_INSTALL_DIR)' @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)" @$(CPY) $(PRJLIB) "$(SCRIPT_INSTALL_DIR)" >NUL default-install-libraries: $(OUT_DIR)\pkgIndex.tcl @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)' @if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)" @echo Installing package index in '$(SCRIPT_INSTALL_DIR)' @$(CPY) $(OUT_DIR)\pkgIndex.tcl $(SCRIPT_INSTALL_DIR) default-install-stubs: @echo Installing stubs library to '$(SCRIPT_INSTALL_DIR)' @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)" @$(CPY) $(PRJSTUBLIB) "$(SCRIPT_INSTALL_DIR)" >NUL default-install-docs-html: @echo Installing documentation files to '$(DOC_INSTALL_DIR)' @if not exist "$(DOC_INSTALL_DIR)" mkdir "$(DOC_INSTALL_DIR)" @if exist $(DOCDIR) for %f in ("$(DOCDIR)\*.html" "$(DOCDIR)\*.css" "$(DOCDIR)\*.png") do @$(COPY) %f "$(DOC_INSTALL_DIR)" default-install-docs-n: @echo Installing documentation files to '$(DOC_INSTALL_DIR)' @if not exist "$(DOC_INSTALL_DIR)" mkdir "$(DOC_INSTALL_DIR)" @if exist $(DOCDIR) for %f in ("$(DOCDIR)\*.n") do @$(COPY) %f "$(DOC_INSTALL_DIR)" default-install-demos: @echo Installing demos to '$(DEMO_INSTALL_DIR)' @if not exist "$(DEMO_INSTALL_DIR)" mkdir "$(DEMO_INSTALL_DIR)" @if exist $(DEMODIR) $(CPYDIR) "$(DEMODIR)" "$(DEMO_INSTALL_DIR)" default-clean: @echo Cleaning $(TMP_DIR)\* ... @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR) @echo Cleaning $(WINDIR)\nmakehlp.obj, nmakehlp.exe ... @if exist $(WINDIR)\nmakehlp.obj del $(WINDIR)\nmakehlp.obj @if exist $(WINDIR)\nmakehlp.exe del $(WINDIR)\nmakehlp.exe @if exist $(WINDIR)\nmakehlp.out del $(WINDIR)\nmakehlp.out @echo Cleaning $(WINDIR)\nmhlp-out.txt ... @if exist $(WINDIR)\nmhlp-out.txt del $(WINDIR)\nmhlp-out.txt @echo Cleaning $(WINDIR)\_junk.pch ... @if exist $(WINDIR)\_junk.pch del $(WINDIR)\_junk.pch @echo Cleaning $(WINDIR)\vercl.x, vercl.i ... @if exist $(WINDIR)\vercl.x del $(WINDIR)\vercl.x @if exist $(WINDIR)\vercl.i del $(WINDIR)\vercl.i @echo Cleaning $(WINDIR)\versions.vc, version.vc ... @if exist $(WINDIR)\versions.vc del $(WINDIR)\versions.vc @if exist $(WINDIR)\version.vc del $(WINDIR)\version.vc default-hose: default-clean @echo Hosing $(OUT_DIR)\* ... @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR) # Only for backward compatibility default-distclean: default-hose default-setup: @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR) @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR) !if "$(TESTPAT)" != "" TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT) !endif default-test: default-setup $(PROJECT) @set TCLLIBPATH=$(OUT_DIR:\=/) @if exist $(LIBDIR) for %f in ("$(LIBDIR)\*.tcl") do @$(COPY) %f "$(OUT_DIR)" cd "$(TESTDIR)" && $(DEBUGGER) $(TCLSH) all.tcl $(TESTFLAGS) default-shell: default-setup $(PROJECT) @set TCLLIBPATH=$(OUT_DIR:\=/) @if exist $(LIBDIR) for %f in ("$(LIBDIR)\*.tcl") do @$(COPY) %f "$(OUT_DIR)" $(DEBUGGER) $(TCLSH) # Generation of Windows version resource !ifdef RCFILE # Note: don't use $** in below rule because there may be other dependencies # and only the "master" rc must be passed to the resource compiler $(TMP_DIR)\$(PROJECT).res: $(RCDIR)\$(PROJECT).rc $(RESCMD) $(RCDIR)\$(PROJECT).rc !else # If parent makefile has not defined a resource definition file, # we will generate one from standard template. $(TMP_DIR)\$(PROJECT).res: $(TMP_DIR)\$(PROJECT).rc $(TMP_DIR)\$(PROJECT).rc: @$(COPY) << $(TMP_DIR)\$(PROJECT).rc #include VS_VERSION_INFO VERSIONINFO FILEVERSION COMMAVERSION PRODUCTVERSION COMMAVERSION FILEFLAGSMASK 0x3fL #ifdef DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "Tcl extension " PROJECT VALUE "OriginalFilename", PRJLIBNAME VALUE "FileVersion", DOTVERSION VALUE "ProductName", "Package " PROJECT " for Tcl" VALUE "ProductVersion", DOTVERSION END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END << !endif # ifdef RCFILE !ifndef DISABLE_IMPLICIT_RULES DISABLE_IMPLICIT_RULES = 0 !endif !if !$(DISABLE_IMPLICIT_RULES) # Implicit rule definitions - only for building library objects. For stubs and # main application, the master makefile should define explicit rules. {$(ROOT)}.c{$(TMP_DIR)}.obj:: $(CCPKGCMD) @<< $< << {$(WINDIR)}.c{$(TMP_DIR)}.obj:: $(CCPKGCMD) @<< $< << {$(GENERICDIR)}.c{$(TMP_DIR)}.obj:: $(CCPKGCMD) @<< $< << {$(COMPATDIR)}.c{$(TMP_DIR)}.obj:: $(CCPKGCMD) @<< $< << {$(RCDIR)}.rc{$(TMP_DIR)}.res: $(RESCMD) $< {$(WINDIR)}.rc{$(TMP_DIR)}.res: $(RESCMD) $< {$(TMP_DIR)}.rc{$(TMP_DIR)}.res: $(RESCMD) $< .SUFFIXES: .SUFFIXES:.c .rc !endif ################################################################ # 14. Sanity check selected options against Tcl build options # When building an extension, certain configuration options should # match the ones used when Tcl was built. Here we check and # warn on a mismatch. !if ! $(DOING_TCL) !if $(TCLINSTALL) # Building against an installed Tcl !if exist("$(_TCLDIR)\lib\nmake\tcl.nmake") TCLNMAKECONFIG = "$(_TCLDIR)\lib\nmake\tcl.nmake" !endif !else # ! $(TCLINSTALL) - building against Tcl source !if exist("$(OUT_DIR)\tcl.nmake") TCLNMAKECONFIG = "$(OUT_DIR)\tcl.nmake" !endif !endif # TCLINSTALL !if $(CONFIG_CHECK) !ifdef TCLNMAKECONFIG !include $(TCLNMAKECONFIG) !if defined(CORE_MACHINE) && "$(CORE_MACHINE)" != "$(MACHINE)" !error ERROR: Build target ($(MACHINE)) does not match the Tcl library architecture ($(CORE_MACHINE)). !endif !if defined(CORE_USE_THREAD_ALLOC) && $(CORE_USE_THREAD_ALLOC) != $(USE_THREAD_ALLOC) !message WARNING: Value of USE_THREAD_ALLOC ($(USE_THREAD_ALLOC)) does not match its Tcl core value ($(CORE_USE_THREAD_ALLOC)). !endif !if defined(CORE_DEBUG) && $(CORE_DEBUG) != $(DEBUG) !message WARNING: Value of DEBUG ($(DEBUG)) does not match its Tcl library configuration ($(DEBUG)). !endif !endif !endif # TCLNMAKECONFIG !endif # ! $(DOING_TCL) #---------------------------------------------------------- # Display stats being used. #---------------------------------------------------------- !if !$(DOING_TCL) !message *** Building against Tcl at '$(_TCLDIR)' !endif !if !$(DOING_TK) && $(NEED_TK) !message *** Building against Tk at '$(_TKDIR)' !endif !message *** Intermediate directory will be '$(TMP_DIR)' !message *** Output directory will be '$(OUT_DIR)' !message *** Installation, if selected, will be in '$(_INSTALLDIR)' !message *** Suffix for binaries will be '$(SUFX)' !message *** Compiler version $(VCVER). Target machine is $(MACHINE) !message *** Host architecture is $(NATIVE_ARCH) !endif # ifdef _RULES_VC ./nsf2.4.0/Makefile.in.rej000644 000766 000024 00000003426 14270240761 016024 0ustar00neumannstaff000000 000000 *************** *** 708,717 **** #======================================================================== pkgIndex.tcl: $(PKG_LIB_FILE) - @echo package ifneeded nsf $(PACKAGE_VERSION) \"load [list [file join \$$dir . $(PKG_LIB_FILE)] Nsf]\; package provide nsf $(PACKAGE_VERSION)\" > pkgIndex.tcl install-pkgIndex: - # @echo package ifneeded nsf $(PACKAGE_VERSION) [list load [file join \$$dir .. "$(PKG_LIB_FILE)"] Nsf] > "$(pkglibdir)/pkgIndex.tcl" #nxsh: tclAppInit.o $(PKG_OBJECTS) $(CONDITIONAL_STUB_OBJECTS) # $(CC) -rdynamic -o $@ tclAppInit.o \ --- 708,731 ---- #======================================================================== pkgIndex.tcl: $(PKG_LIB_FILE) + @echo "if {[package vsatisfies [package provide Tcl] 9]} {" > pkgIndex.tcl + @echo " package ifneeded nsf @PACKAGE_VERSION@ \\" >> pkgIndex.tcl + @echo " [list load [file join \$$dir @PKG_LIB_FILE9@] Nsf]" >> pkgIndex.tcl + @echo "} else {" >> pkgIndex.tcl + @echo " package ifneeded nsf @PACKAGE_VERSION@ \\" >> pkgIndex.tcl + @echo " [list load [file join \$$dir @PKG_LIB_FILE8@] Nsf]" >> pkgIndex.tcl + @echo "}" >> pkgIndex.tcl + @echo "package provide nsf $(PACKAGE_VERSION)" >> pkgIndex.tcl + install-pkgIndex: + @echo "if {[package vsatisfies [package provide Tcl] 9]} {" > pkgIndex.tcl + @echo " package ifneeded nsf @PACKAGE_VERSION@ \\" >> pkgIndex.tcl + @echo " [list load [file join \$$dir @PKG_LIB_FILE9@] Nsf]" >> pkgIndex.tcl + @echo "} else {" >> pkgIndex.tcl + @echo " package ifneeded nsf @PACKAGE_VERSION@ \\" >> pkgIndex.tcl + @echo " [list load [file join \$$dir @PKG_LIB_FILE8@] Nsf]" >> pkgIndex.tcl + @echo "}" >> pkgIndex.tcl #nxsh: tclAppInit.o $(PKG_OBJECTS) $(CONDITIONAL_STUB_OBJECTS) # $(CC) -rdynamic -o $@ tclAppInit.o \ ./nsf2.4.0/ChangeLog-2.0.0-2.1.0.log000644 000766 000024 00000144630 14275417765 016643 0ustar00neumannstaff000000 000000 2016-12-23 Gustaf Neumann * nsfmongo.c: Added explicit calls to mongoc_init() and mongoc_cleanup(). Documented use of configure flag "--disable-automatic-init-and-cleanup" to avoid crashes under macOS. [b7029a4] * nxsh.man: Improved wording. [a7ce921] * tk-*.tcl: Change package name in Tk example scripts: "nx::traits:XXX" -> "nx::trait::XXX"; add comment to Announcement. [71e1805] * linearization.test: extended regression test suite with a case reproducing a recently fixed crash. [bc72af7] * nsf-gridfs.test: Changes to README file requires a small adjustment on a test case, working on the README file. [65669db] * mongodb/configure.ac, mongodb/pkgIndex.add, nx-mongo.tcl: Bump version numbers: nsfmongo to 2.1, TEA to 3.10, nx::mongo to 2.1. [ad195da, 4028b98] 2016-12-22 Gustaf Neumann * nsfInt.h: Define NsfObjDispatch as Tcl_ObjCmdProc. [41e0544] * mongoAPI.decls, nsfmongo.c: Upgraded MongoDB and drivers to mongodb-c-driver 1.5.1, libbson 1.5.1 and MongoDB v3.4.0; added support for BSON type DECIMAL128. [ab21c85] 2016-12-21 Stefan Sobernig * configure, aclocal.m4: Re-generated autotools artifacts to reflect changes in configure.ac. [70e6617] * configure.ac: Fix bogus variable assignment. [cd18d47] 2016-12-18 Gustaf Neumann * nsf.c (PrecedenceOrder, MergeInheritanceLists): Fix occasional crash when deleting and recomputing precedence orders under multiple inheritance. One assumption in the precedence order computation is that the precedence orders of superclasses are computed before the precedence orders of the class itself. The check whether to perform this computation turned out too simple minded because it used to check this condition only on the current class, but not on its superclasses. [a1a7bac] * nsfInt.h: Use the same ISOBJ definition for both Tcl 8.5 and 8.6. This avoids another potential crash. [8eda332] * nsf.c (ParseContextExtendObjv): Make type conversion explicit. [6a4df82] * Makefile.in: Add make target lldbtest. [a42449a] 2016-12-17 Gustaf Neumann * nsf.c, nsfInt.h, nsfUtil.c: Avoid implicit type conversions [bdfa0fc, e8d2c80] * nsfmongo.c: Avoid implicit type conversions. [ebb54b9] * mongodb/configure.ac: Allow specification of --enable-assertions on the parent NSF project. [6e88221] 2016-12-16 Gustaf Neumann * testx.xotcl (filterGuards): When compiled without assertions, a test case was skipped, that created an object "b"; the subsequent test therefore produced different results when b happened to be created or recreated; avoid use of global modifier. [e7afc31] 2016-12-16 Stefan Sobernig * summary.tcl: Report NSF commit id along with NSF package version. [3232e56] * pkg.vc: Provide for incorporating the commit id at least for tarball builds under win/nmake. [d257d63, f6634af] supersede [5b7ad96]. 2016-12-16 Gustaf Neumann * shells.test: The shell test depends on console output which in turn varies according to build-time configuration options such as memcount. Deactivate this test file for NSF configurations with debug output. [4a0eb5e] * nsf.c (AliasRefetch): Don't add extra newlines to log lines. [a56620f] 2016-12-16 Stefan Sobernig * makefile.vc, pkg.vc: For the time being, set an empty commit id under Win. [5b7ad96] * configure.ac, configure: Align TEA versions. [6a77970] * nsfDebug.c, configure.ac: Provide for the commit id (if available) to be stored in the variable "::nsf::commit". [0ecc82c] 2016-12-15 Stefan Sobernig * README.release: Provide for and document publishing the doctools manpages to https://next-scripting.sourceforge.io/. * man.css: Updated to match doctools markup (tcllib 1.18+; new id and class names) and remove button-style from keywords and syntax elements. [9414504] 2016-12-15 Gustaf Neumann * nsf.c (CompiledLocalsLookup): Improve variable names and limit calls to strcmp. [438ba04] 2016-12-13 Stefan Sobernig * gentclAPI.tcl (methodDefinition): Deactivate docstring generation for now, as they are not actively used. [44ab715] 2016-12-12 Stefan Sobernig * configure.ac, configure (AC_INIT): Rather add link to SF ticketing as PACKAGE_BUGREPORT define. [d5c3562] 2016-12-12 Gustaf Neumann * nsf.c, nsfAPI.decls (NsfConfigureCmd): Remove configure options "trace" and "profile". [4b20700] 2016-12-11 Stefan Sobernig * win/makefile.vc: Set title for summary.tcl. [88f1605] * interp.test: Import auto_path from parent interp so that "package req" works as expected. [3e47756] * nsfInt.h, nsfError.c (NsfDStringVPrintf): The logic assumes _vsnprintf being used under MSVC. However, under Tcl 8.5.*, the mapping is missing from tclInt.h. Fill this gap. [295ac11] 2016-12-11 Gustaf Neumann * nsf.c (TclDeletesObject): Fix bug that sneaked-in in last commit. [7f016c4] (Nsf_DeleteNamespace): Remove unneeded code in cases, when compiled with NDEBUG. [af86f66] * nsf.c: Prefer boolean expressions, reduce number of implicit signed/unsigned conversions. [7c9627d] * nsfStack.c (NsfShowStack): Remove always false statement used for controlling output of showstack. [b44aabd] * Makefile.in: Remove duplicated flag "TCL_NO_DEPRECATED" [cfa9e21], make cppcheckcmd configurable. [15b9823] 2016-12-10 Gustaf Neumann * nsf.c: Address cmdflags conversion, prefer unsigned int over unsigned long. [2d51c0b] 2016-12-09 Stefan Sobernig * nsf.c (ProcDispatchFinalize): Silence compiler warning on ckfree. [641e77f] 2016-12-09 Stefan Sobernig * win/makefile.vc: Register missing test scripts. [5c55039] 2016-12-09 Gustaf Neumann * nsf.c (ProcDispatchFinalize, InvokeShadowedProc): Fix debug output when compiled without --enable-profile. [e2dfaca, b99c256] 2016-12-09 Stefan Sobernig * win/rules.vc: Remove artifact from OPTDEFINES. [a7d6bf4] * win/rules.vc: Avoid type-cast warnings under 64-bit MSVC (MSVC > 1300) toolchains due to compiler flags missing from Tcl headers and from rules' OPTDEFINES. Reported as http://core.tcl.tk/tclconfig/tktview?name=ab69a602bf. [ccc0e58] 2016-12-09 Gustaf Neumann * nsf.c (ProcDispatchFinalize): Move result reporting of nsf::procs into ProcDispatchFinalize(). This fixes the result value reporting and timings for nsf::procs. [1723e95] 2016-12-07 Gustaf Neumann * nsf.c (NsfProcStub): Make sure that stub proc is used when "-deprecated" is set. * nsf.tcl: Use "Debug" severity for -debug messages. [4befd49] 2016-12-02 Stefan Sobernig * nsf.c (GetObjectFromObj, TclDeletesObject): Remove two earlier fixes to deal with ::nsf::object::alloc failing under cmd deletion/recreation. The issue has been tackled more generally by a Tcl-side fix. Background: Since 2005 (commit fcb9ab1df3a9b2d1), in Tcl the cmdEpoch state in delete traces and delete callbacks has been compromised. Bumping the epoch of the cmd under deletion before executing the traces and callbacks had the potential of caching the cmd under in Tcl_Objs beyond its deletion (at least in our code path). In July 2017 for 8.7a (commit 54fac92610d3bdd9), this potential realized by removing a guard expression on CMD_IS_DELETED in the Tcl_Obj cache invalidation logic, which had protected from such invalid caches as a side effect. As of today (8.7a, commit 71fa1f9c91), the underlying timing problem of epoch bumping has been resolved. [f314d0a] reverts [bab0e88, 75a78fb, 646eda3] 2016-11-23 Stefan Sobernig * nsf.c (NsfMethodAliasCmd): Tcl 8.7 is more picky about typePtr and intrep being in line. We need to NULL the typePtr explicitly. TclFreeIntRep does so for us as good Tcl citizens, rather than setting bodyObj->typePtr == NULL directly. [438e614] 2016-11-11 Stefan Sobernig * nx.tcl (VariableSlot->setCheckInstVar): Use method parameter 'value' rather than object variable 'default'. [361fa32] * nx.tcl, parameters.test (Object->object variable): Support for substdefault has been entirely missing so far. Added basic tests. [7bcc1f1] 2016-11-03 Stefan Sobernig * interceptor-slot.test: Adding a first test case. [71f9dc8] 2016-11-03 Gustaf Neumann * nsf.c (ObjectDispatchFinalize): Address potential crash when a filter calls a filter which calls unknown. [641d41d] * nsfInt.h: Prefer lowercase "U" suffix to improve readability. [4b4a734] 2016-11-02 Stefan Sobernig * xotcl2.tcl (Class->unknown): Use ::nsf::current explicitly to avoid NX/XOTcl2 self hickups. [a147560] 2016-10-28 Gustaf Neumann * Documentation (tk-ludo.tcl): Regenerated documentation. [c8cc440] * tk-ludo.tcl, nx-shell.tcl: Remove useless expr statements. [f691059] 2016-10-27 Stefan Sobernig * xotcl2.tcl (Class->unknown): Fix regressions due to uplevel mambo-jumbo. [020d3d6] (Class->unknown): Make sure that Class->unknown bypasses filter and mixin frames. [9dcea26] 2016-10-26 Stefan Sobernig * nsf.c (ExitHandler): Re-locate clearing history from finalize to ExitHandler. [59b4e8c] 2016-10-22 Stefan Sobernig * nsf.c (NsfFinalizeCmd): Clear Tcl's history list explicitly before finalizing NSF. See also Tcl ticket 1ae12987cb. [6be629e] 2016-10-16 Stefan Sobernig * nx.tcl (nx::Class->unknown): Rewrite unknown message to include '?...?'. [371cc41] * nsfStack.c: Unify writing style. [114df8b] * nsfProfile.c: Fix typos in code comments. [5447fe0] * nsfFunPtrHashTable.c: Fix typos in code comments. [6e37cdb] 2016-10-15 Gustaf Neumann * nsfError.c: Cleanup: remove spurious blank in error message, fix typo in print string. [e0da9e0] 2016-10-15 Stefan Sobernig * nx.tcl: Commit missing unknown message change. [dafe310] 2016-10-15 Gustaf Neumann * nsf.h, nsfError.c: (NsfNoCurrentObjectError): Improve comment and signature. [5abaa15] Improve wording of other comments, keep comments within the limits of the header/trailer line. [5abaa15] 2016-10-14 Stefan Sobernig * Testsuite: Adjust the test suite for the latest rewording of the nx::Class unknown message. [2717622] * nsfError.c: Fixed typos and unified writing style in code comments. [f139db6] * nsfObj.c: Fix some typos and align writing style. [1ce1f6a] 2016-10-14 Gustaf Neumann * nsf.c: Fix typos in comments, align commenting style. [5ba5873] * nx.tcl: Make xotcl::Class->unknown hint more explicit and verbose. [4dda010] 2016-10-13 Stefan Sobernig * nsf.c: (ObjectSystemsCleanup): Remove interp resolvers explicitly before the physical cleanup round. [371e0e3] (DeleteProcsAndVars): Silence compiler warning and reduce variable scope (spotted with memtracking on). [7992ec4] 2016-10-12 Stefan Sobernig * shells.test: Add two tests on try/finally. [ce511c8] * nx-shell.tcl: Extend the exit wrapper to include Tcl 8.6 try [8f55f92] Make sure that the proper exit code is provided when leaving the -c stdin mode. [f83d0a1] 2016-10-12 Gustaf Neumann * shells.test: Add two more tests of plain tclsh. [0c79f62] Remove superfluous (and incorrect) tests. [3f7e49e] reverting [152c1d3] Extend regression test for shell with tests in [info nameofexecutable] rather than in nxsh [152c1d3] * nsf.c (NsfLog): Don't call Tcl eval operations from NsfLog() in phyical destroy round. 2016-10-12 Stefan Sobernig * shells.test: Add some more tests. [31727ed] * nx-shell.tcl (nx::shell2): Rewrote in-shell exit support to avoid Tcl's native exit and to unwind gracefully to avoid NSF refcount leaks on exit; bumped package number. [0956bd0] 2016-10-10 Gustaf Neumann * nsf.c, nsfInt.h: Improve sanity test in ISOBJ(): obj->bytes might only be NULL when type is given. [472a3c5] 2016-10-09 Stefan Sobernig * TEA (tcl.m4): Updated m4/tcl.m4 to most recent TEA version: 3.10, regenerated autotools artifacts. [4a30a3a] 2016-10-08 Gustaf Neumann * nsfUtil.c: Cleanup of strnstr() (when the clib function is not available). [a8b3805] * generic/*: Cleaning up white spaces (mostly strip trailing spaces, remove a few tabs). [77ba24e] Cleanup of type conversions. [1d1ca56] Reduce variable scopes. [fbd52e6] 2016-10-07 Gustaf Neumann * nsf.c: Cleanup of type conversions in first ~18000 lines. [4e70d6d] 2016-10-07 Stefan Sobernig * current.man (current.man): Extend doc on nx::current to include nx::current level [d49b5f9] 2016-10-07 Gustaf Neumann * nsf.c: Cleanup of type conversions in first ~6000 lines. [099e1ee] * nsf.c, nsfAPI.* (NsfCurrentCmd): New subcommand "nsf::current level", which returns an empty string when outside an NSF frame/level. [8465a13] (NsfCurrentCmd): Keep compatibility with traditional "nsf::current activelevel" by returning 1, if we are not on an NSF frame. [8465a13] reverting [dbd850e]. 2016-10-06 Gustaf Neumann * nsf.c (NsfCurrentCmd): Return from "nsf::current callinglevel" the value 0 (instead of 1), when it is called outside of an NSF frame, which has an NSF object associated. [dbd850e] 2016-10-05 Stefan Sobernig * nsf.c (UnsetTracedVars): Silence compiler warning under 8.5 by providing an explicit cast. [abfaf40] * Documentation (rosetta-single-inheritance.tcl):Add another Rosetta example: Inheritance/Single [c7738a3] (rosetta-multiple-inheritance.tcl): Fix typo L3 -> C3 [3617b69] (Object.man): Include missing doc in 'info lookup parameters' and 'info lookup syntax' [4bfe0ad] 2016-10-04 Stefan Sobernig * nsf.c: (ParamOptionParse): 'virtualobjectargs' and 'virtualclassargs' defaulted to ConvertViaCmd when parsed from Tcl spec; explicitly set ConvertToNothing to match the intended semantics and to avoid false warnings (e.g., missing type=virtualobjectargs type checker). [03b838a] (NsfParameterInfoCmd): Correct two typos in code comment. [6d563e2] 2016-10-02 Stefan Sobernig * Makefile.in: Register Rosetta examples. [ec6103a] 2016-10-02 Gustaf Neumann * nsf.c, nsf.h: Make NSF compilable with "-DTCL_NO_DEPRECATED". [9cce0c1] 2016-10-01 Stefan Sobernig * Documentation: Remove redundant Rosetta example implementations. [14d4d3a] (rosetta-multiple-inheritance.tcl): Added another Rosetta example: multiple inheritance. [92c1ac3] 2016-09-30 Stefan Sobernig * nsf.c (RemoveInstance): Fix typo and improve wording of nsf::log warning slightly. [8a106d9] * Documentation (Object.man): Correct the documentation bit on Object->copy. [4b2d241] (rosetta-clone.tcl): Added another Rosetta example: Polymorphic copy [922c0ab] 2016-09-29 Stefan Sobernig * nsf.c, methods.test (DispatchUnknownMethod): Make sure that arcane method names make it into proper unknown error messages incl. names representing invalid Tcl lists; tests included; checked by valgrind [4b78042] * Documentation (rosetta-add-variable.tcl): Adding yet another Rosetta example: Add object variable dynamically. [ed0f5cb] (rosetta-add-variable.tcl): Fix typo [e33e0a2] * shells.test: Adjust shell tests for latest changes to stacktrace formatting. [56f9658] triggered by [2c896da] 2016-09-28 Stefan Sobernig * Documentation: (rosetta-multiple-distinct.tcl, rosetta-tree.tcl): Improve output spec in Rosetta example. [8648ec7] (rosetta-multiple-distinct.tcl): Adding another Rosetta example: Multiple distinct objects. [cc85907] 2016-09-23 Gustaf Neumann * nsf.c: Add thread IDs to debug lines (in threaded builds). [e20e1c1] 2016-09-21 Stefan Sobernig * Testsuite: (tcl86.test): Make cmd-literal tests conditional on a (future) Tcl release: 8.6.7 [40ff115] (destroy.test): Adding a second UnsetTracedVars test, this time for the per-object namespace case. [2330f51] 2016-09-20 Stefan Sobernig * destroy.test: Add missing test on UnsetTracedVars. [c29e5d3] 2016-09-19 Stefan Sobernig * nsfCmdDefinitions.c (Nsf_CmdDefinitionRelease): Fix documentation [23581e9] * nx-shell.tcl (nx::shell2): Provide complete errorinfo, not just top-level line [2c896da] 2016-09-16 Gustaf Neumann * nsf.c (NsfFinalizeCmd): Remove manually mixinRegObjs during cleanup to silence sanity checking for object refcounts. [9395752] * nsfObj.c (NsfMixinregGet): Fix typo in comment. [73a82fc] 2016-09-15 Gustaf Neumann * nsf.c (NsfFinalizeCmd): Add pthread id to debug message [b36a57b] 2016-09-13 Stefan Sobernig * nsf.c (UnsetTracedVars): Provide for a two-pass deletion logic during object shutdown, to account for unset traces possibly reviving an object variable under deletion. This corresponds to a recent memleak fix to Tcl itself. See also Tcl Fossil ticket 4dbdd9af144dbdd9af14. [d710110] 2016-09-09 Stefan Sobernig * nx.tcl (VariableSlot->value=get): Substitute set for get, which is a tick faster. [bb688b8] * Documentation (rosetta-tree.tcl): Rosetta example: Tree traversal. [f769aa3] 2016-09-06 Stefan Sobernig * nx-shell.tcl (::nx::shell2): Harden nx::shell against inlined return statements. [da0791d] * Documentation (rosetta-tokenizer.tcl): Added first additional Rosetta example. [b689afd] * source-highlight-with-pp: Make src highlighter independent of Tcl version. [8e929f8] 2016-09-01 Stefan Sobernig * Makefile.in: Keep valgrind settings for the future. [0187626] * nsf.c (ObjectCmdMethodDispatch): Get refcounting on method-path lists right, fixing one actual (valgrind) and another potential Tcl_Obj leak. [6cb02ec] 2016-08-31 Stefan Sobernig * nsf.c (ParamDefsNames): Fix another Tcl_Obj leak and optimize code slightly, Tcl_Obj is only allocated once the string-matching operation succeeded. [253e9e6] (NsfForwardPrintError): Fix another instance of the NsfMethodNamePath leak. [0739b93] (NsfMethodName): Avoid unnecessary append operation between lists, previously leaking the source list Tcl_Obj. [8a650e1] (ArgumentParse): Addressing a series of Tcl_Obj leaks (valgrind). [2dbfbf4] 2016-08-22 Gustaf Neumann * nsf.c (AssertionAddProc): Removing dead assignment. [1e25f4b] 2016-08-14 Stefan Sobernig * nsf.c: (TopoSortSub): Make intended true/false comparisons based on int explicit. [ce32c79] (TopoSort): cleanup (pt. 3): re-factored TransitiveSubClasses() and DependentSubClasses() into one caller function of TopoSortSub(). [a9057d3] (TopoSort): cleanup (pt. 2): renamed TopoSort() to TopoSortSub() to match TopoSortSuper. [49bad0b] 2016-08-13 Stefan Sobernig * nsf.c (TopoSort): cleanup (pt. 1). [2caa518] 2016-08-10 Stefan Sobernig * nsf.c (GetNextArguments): Address CID 102646. [e982277] (NsfObjInfoObjectparameterMethod, NsfParamDefsFilter): Removed two unused functions: NsfObjInfoObjectparameterMethod() and NsfParamDefsFilter(). Makes CID 88775 obsolete.[308a912] (MakeProc): Address CID 88770. [566ca93] 2016-08-09 Gustaf Neumann * nsfError.c (NsfObjWrongArgs, NsfObjErrType): Remove occurrences of deprecated Tcl_AppendResult() in overall code. [299a221] (NsfPrintError): Avoid computing string length twice. [b8fe2d4] * nsfStubLib.c: Remove 2 occurrences of deprecated Tcl_AppendResult. [8e079b5] * nsf.c, nsfInt.h (NsfLog, RUNTIME_STATE): Small logging reform, renaming "debugLevel" to "logSeverity" and introduce logging messages which have a severity larger or equal than a given log severity; so; "nsf::configure debugLevel 0" will print everything, and "nsf::configure debugLevel 3" will print just error messages while omitting warnings etc. This is not a change in logging semantics, but removes some confusion at the C level. Therefore, the nsf::configure option "debugLevel" was not changed. 2016-08-07 Gustaf Neumann * nsf.c (ExitHandler): Address potential double freeing problem of runtime states. ExitHander should never be called twice on the same interp. Therefore, provide for deleting ExitHandler in the ExitProc, as well as for deleting ExitHandler and ThreadExitHandler in the ThreadExitProc. [4ff9a50] 2016-08-04 Gustaf Neumann * gentclAPI.tcl, nsfAPI.decls: Code generator was changed to create enum types instead of enum values for NSF API, use enum types in code. [aa5b3f4] 2016-08-04 Stefan Sobernig * nsf.c, nsfCmdDefinitions.c, nsfEnumerationType.c (ExitHandler, Nsf_CmdDefinitionRelease): Provide for releasing/deleting the hash table for cmd definitions. [843e576] (ExitHandler, Nsf_EnumerationTypeRelease): Provide for releasing/deleting the hash table for enumeration-type converters in ExitHandler. [843e576] * nsfFunPtrHashTable.c (FreeFunPtrEntry): Remove deletion handler for cmddef and enumeration-type hash entries, not needed currently. 2016-08-02 Gustaf Neumann * generic/**.c: Code cleanup (remove various code smells by adding const declarations, preferring boolean tests, avoid "for" loops without a block, don't pass non-initialized value in an array on index [0], reducing variable scope, preferring single returns statements in functions, don't use CONST unless defined by Tcl API. [8eecbe5] * nsf.c: Limit effects of namespace-imported classes. [3b5f62d] 2016-08-01 Stefan Sobernig * nsf.c (FilterSearchAgain): Avoid running into an invalid pointer access, when the physical deletion of "del" conflicts with following the next link in the cmdList in the loop's increment statement (only iff del == cmdList). Re-organized for into a while loop, to avoid otherwise redundant code. [0311e86] 2016-07-28 Stefan Sobernig * nsf.c (GetClassFromObj): Fix invalid memory access as indicated by valgrind. [a9448f8] 2016-07-27 Gustaf Neumann * nsf.c (InterpColonCmdResolver): Make intentions about clientData clear to static checker. [1663346] (NsfProcStubDeleteProc, NsfProcAdd): Use consistent comment styles. [e13bc9e] (NsfProcAdd, ListMethod, NsfParseArgsCmd): Move declarations to the begin of a code block, remove debug code. [abc4952] * nsfCmdDefinitions.c, nsfEnumerationType.c, nsfFunPtrHashTable.c: Remove commented code from the previous implementation. [7243f88] * Makefile.in: Add pre-8.7 Makefile.in (missed in last commit). [ae36129] 2016-07-26 Stefan Sobernig * nsf.c, nsfInt.h (NsfProcStubDeleteProc): Protect against potentially dangling namespace references from within ::nsf::procs::*. The wrapper cmd's namespace of an nsf::proc might already have been deleted when ::nsf::procs::* shuts down finally. This showed up during a Tcl_Exit (NSF's ExitHandler) as an invalid memory access via (dangling) namespace pointers as indicated by valgrind. [c39e939] 2016-07-26 Gustaf Neumann * generic/stubs8.7/: Let NSF compile against Tcl 8.7 (current trunk version of Tcl). [56d1814] 2016-07-25 Gustaf Neumann * nsf.c, tcl86.test: Continued work on cmd resolvers: Fix test, when OS specific cmd resolver is used from an NSF_CSC_CALL_IS_COMPILE frame; improved output from __db_show_obj: put results into one line instead of multiple lines; new debug function __db_get_obj: return into about a tcl_obj in form of a dict (in general, one should not rely on Tcl_Obj internals, especially when upgrading over major Tcl versions, but for testing/understanding behavior etc., such a command is helpful; extended regression test. [21686b8] 2016-07-21 Stefan Sobernig * tcl86.test: Revive and include test case on Bug 3418547. [f5b034e] 2016-07-21 Gustaf Neumann * tcl86.test: Add test for the global cmd literal sharing. [3dbd5a1] * nx.tcl: Adding "/obj/ info method disassemble" for disassembling methods. [ 3dbd5a1] 2016-07-17 Stefan Sobernig * nsf.c (NsfParseArgsCmd): Fix memory leak. [ae50486] 2016-07-16 Stefan Sobernig * nsf.c (SetInstVar): Correct book-keeping for NSF's memcount feature. [6a3890e] 2016-07-15 Stefan Sobernig * nsfCmdDefinitions.c (Register): Avoid inline comment style. [34c49c5] * nsf.c (NsfFinalizeCmd): Suppress cppcheck warning: adding explicit int cast. [9fc2766] * nsfError.c (NsfDStringVPrintf): Promote log statement to Tcl panic. [c7b7511] (NsfDStringVPrintf): Make log statement conditional on NDEBUG. [2a16d79] 2016-07-15 Gustaf Neumann * nsf.c (DispatchDestroyMethod): Handle cases of objects becoming deleted after the interp (which should not happen) more gracefully. [800c3a0] 2016-07-15 Stefan Sobernig * nsfError.c (NsfDStringVPrintf): Rephrase err message. [8d2096e] 2016-07-14 Stefan Sobernig * nsfError.c (NsfDStringVPrintf): Suppress cppcheck warning: unused variable assignment. [34e5bc1] * nsf.c (NsfParseArgsCmd): Suppress cppcheck warning: reduce variable scope. [8fd1f04] 2016-05-21 Gustaf Neumann * nsfmongo.c (NsfMongoRunCmd): return the result of ::mongo::run. [4dccd3f] 2016-05-04 Stefan Sobernig * Documentation: Link version numbering in man pages to autoconf tooling, similar to the NaviServer setup, update copyright dates in man pages where needed. [0228cdf] 2016-04-30 Stefan Sobernig * Documentation (nxsh.man): Update man page for nxsh, adding description of -c option. [30cf844] 2016-04-29 Stefan Sobernig * Testsuite (Makefile.in): Register shells.test. [be3c675] (shells.test): Some cleanup and adding basic test cases. [3ee0ac9] 2016-04-21 Stefan Sobernig * Shells (nxsh, xotclsh): Scripted shell reform which provides an alternative nx::shell impl (nx::shell2), used by all four shell scripts. nx::shell2 builds on Tcl's event loop, rather than while + update. This avoids blocking the Tk main window (update). In addition, nx::shell2 is closer to Tcl's native shells (e.g., no extra lines on enter, catches EOF). [2a5945f] 2016-04-19 Gustaf Neumann * nsfmongo.c, mongoAPI.*: Improved mongodb interface for json/bson parsing; rename function mongo::json to mongo::json::generate; introduce mongo::json::parse. [e3e8f37] 2016-04-08 Stefan Sobernig * Object.man: Fix doc on introspection for configure options. [4276fbd] 2016-04-04 Gustaf Neumann * nsf.c (ComputeParameterDefinition, ProcessMethodArguments): Cleanup up and improve debug statements. [96f4410] * nsfAPI.decls (__profile_get): Remove redundant spec line. [e365540] * nsf.tcl (volatile): Improve indentation. [a41b0fa] 2016-03-30 Gustaf Neumann * xotcl2.tcl: Added "-returns" flag to XOTcl's instprocs/procs, very similar to "-returns" in NX. Extended serializer to handle "-returns" flag and extended regression test, accordingly. [353fdf4] 2016-03-26 Gustaf Neumann * nx.tcl (setCheckedInstVar): Fix one case in interaction between get-trace and default value. [f6ddb05] 2016-03-25 Stefan Sobernig * Testsuite (library/pkgIndex.tcl): Make XOTcl tests runnable again from plain tarball/git checkout. [20e59a8] 2016-03-25 Gustaf Neumann * nx.tcl (setCheckedInstVar): Allow combination of "-trace get" with default value (was previously disallowed); extended regression tests. [7e20ec3] * nsfError.c (NsfDStringVPrintf): Minor cleanup. [4f44840] 2016-03-23 Stefan Sobernig * TEA (makefile.vc): Custom shell target. [842266c, da35de9] (makefile.vc): Add base-address support; see http://core.tcl.tk/tcl/tktview?name=0ef5e653. [3a06b2c] * nsfError.c (NsfDStringVPrintf): Improve documentation. [b75b19b] (NsfDStringVPrintf): Another attempt to sort out the vs*printf() mess between runtimes. [626a121] 2016-03-18 Stefan Sobernig * TEA: (makefile.vc): Update win compilation units. [a8c598f] * nsf.c (Nsf_ConvertToBoolean, NsfConfigureCmd, ArgumentDefaults) (NsfObjectSystemCreateCmd): Rename one more 'bool' identifier. In MSVC 14 (Visual Studio 2015) and newer, 'bool' is a proper type, not a typedef anymore. 'bool' cannot be used as identifier anymore; see C2632. [90b08e1,40e347d] 2016-03-18 Gustaf Neumann * nsfAPI.*, nsf.c (NsfParseArgsCmd): Add new command "nsf::parseargs" to parse an argument vector against a parameter definition and to set the resulting variables in the current scope; extended regression test. [546f8dd] * nsf.c, nsfStack.c, nsfProfile.c: Substitute Tcl_Time for "struct timeval" as well as Tcl_GetTime for gettimeofday in profiling code to improve portability; esp. Windows. [dc4e227] 2016-03-16 Gustaf Neumann * nsfInt.h: Newer versions of GCC 6 handle now as well nonnull asserts gracefully, so we can turn off its deactivation for GCC 6. [433266d] 2016-03-07 Gustaf Neumann * serializer.tcl: Fix serializing of info internals for XOTcl2. [f9f501f] 2016-03-05 Gustaf Neumann * nsfmongo.c: Reduce verbosity and apply white-space changes. [4ca97ca ] 2016-02-19 Stefan Sobernig * nsf.c (NSGetFreshNamespace, NsfDebugShowObj): Address two more GCC 6 pedantic warnings. [ab19daf] * nsfFunPtrHashTable.c, nsfCmdDefinitions.c, nsfEnumerationType.c: Re-factored new hashtable infrastructure (based on function-pointer keys) to support method-definitions (and future uses as well). [c01b411] 2016-02-15 Gustaf Neumann * nsfCmdDefinitions.c: Added Tcl_HashKeyType cmdPtrHashKeyType for command pointers. [760d5e6] 2016-02-12 Gustaf Neumann * nsf.c, nsfDebug.c: Move initializations after nonnull asserts. [67efaa6, acee8b7] 2016-02-11 Gustaf Neumann * nsf.c (NsfParamDefsVirtualFormat): Ease life of static checkers. [f382a52] 2016-02-10 Gustaf Neumann * nsf.c (GetAllInstances): Removed one more possible NULL comparison with a non-null value. [8e97011] 2016-02-03 Stefan Sobernig * Documentation (alias.man.inc, forward.man.inc, method.man.inc): Updating doc fragments on debug/deprecated methods. [f56a194] * methods.test, object-system.test: Adding some missing test on recently added introspection methods. [3c1482d] 2016-02-03 Gustaf Neumann * nsfProfile.c: (NsfProfileDeprecatedCall): Fix comment. [6d1f42a] 2016-02-03 Stefan Sobernig * Object.man, forward.man.inc, alias.man.inc, method.forward.inc, info.man.inc: Adding doc fragments for new info submethods, as well as deprecated and debug flags. [74410fa] 2016-02-01 Gustaf Neumann * serializer.tcl: Improve robustness of serializer, otherwise "::nx::Object::slot::__info" triggers an exception. [494410d] 2016-01-27 Gustaf Neumann * nsf.c (GetClassFromObj): Provide for refcounting before and after the call tp NsfCallObjectUnknownHandler. [e05bd93 ] 2016-01-26 Gustaf Neumann * nsf.c (Nsf_ConvertToClass, NsfRuntimeState): Let NSF create classes with ::nsf::object::unknown handler on the fly, when C functions are called with objects of type class. This is necessary for triggering creation attempts in trace via ::nsf::object::alloc /cls/ /obj/. [6c041dc] 2016-01-25 Gustaf Neumann * xotcl2.tcl, pkgIndex.tcl, serializer.tcl: Bump version number of XOTcl to 2.1. [52a6105] 2016-01-22 Gustaf Neumann * generic/*.c: Updated copyright notices, version number. [4fa580a] * accessor.tcl: Add editor hint. [5fe3bf0] * nsfUtil.c: Move assignment aster nonnull assertions. [a3fe572] * nsf.c (MixinInvalidateObjOrders, MixinSearchMethodByName): Turned all for-loops controlled over a nonnull value into while loops. [e5a42b6] * README: Update version numbers in README. [4468c69] * README.release: Fix description. [1a70aea] 2016-01-19 Gustaf Neumann * nsf.c, nsfAPI.*, nsfCmdPtr.c, nx.tcl, slottest.xotcl, accessor.test, cget.test, parameters.test: Slot trace reform incl. a redesign of slot interface of traces. Variables contain cmds and variable references to slot-specific methods with the same interface as slot-setters. When new flag -trace is set, a trace will be registered calling either: value=get /obj/ /variableName/; or value=set /obj/ /variableName/ /value/; or value=default /obj/ /variable/; on the slot. Updated regression test accordingly. [dadf28e] 2016-01-12 Stefan Sobernig * xotclsh.in, xowish.in: Make sure minor versions >2.1 are accepted. [286f946] * xotclsh.in, xowish.in: Use nx::shell. [4b92980] * nxsh.in, nxwish.in: Use nx::shell. [4bf0e8a] * nx-shell.tcl: (nx::shell): Started refactoring scripted shell environment into a single, package location (nx::shell) to ease sharing between nxsh & friends, as well as to facilitate implementingNX/XOTcl shells in wrapped applications (tclkits). [6c6f313] (nx::shell): Avoid polluting global namespace. [f1bfcbc] 2016-01-11 Gustaf Neumann * README.release: Update release hints. [2c69f59] 2016-01-08 Gustaf Neumann * nsf.c (NsfDStringEval): Make sure to reset prevPreventRecursionFlags to value before the call. [7ca41c6] (NsfDStringEval): Changed interface of to control behavior via bitflags (this is after all more readable than an argument list of "0" and "1"s); added optional recursion prevention for functions called via NsfDStringEval (handling NSF_EVAL_DEBUG, NSF_EVAL_LOG, NSF_EVAL_DEPRECATED); added regression tests for potential recursive calls. [e367957] * xotcl2.tcl: Added flags "-debug" and "-deprecated" to XOTcl 2 "instproc", "proc", "instforward" and "forward" methods. [ccca1a5] 2016-01-07 Gustaf Neumann * nsf-cmd.test: Add absolute path in returned proc definition to regression test. [a775d31] * nsf.tcl: Add result in debug exit calls. [2771c4c] 2016-01-05 Gustaf Neumann * nsf.c (ListMethod): Return fully qualified name for "::nsf::cmd::info definition" when called on plain procs. [fd0f246] 2015-12-30 Gustaf Neumann * nx.tcl, serializer.tcl: Generalize method serialization of forwarders. [8cbd921] 2015-12-29 Gustaf Neumann * nsf.h: Fix compilation when DTRACE but no PROFILE is activated. [74b39c5] * nsf.c, nsfProfile.c: Prefer boolean expressions in assert() statements. Make sure, we do not pass null values to nonnull arguments. [a529b8f, 22f4e55] * Makefile.in: Add etags target. [bce3456] 2015-12-25 Gustaf Neumann * nsf.c, nsfInt.h, nsfProfile.c, configure.ac: Substitute all remaining ObjectName and ClassName for variant with trailing "_", where appropriate; allow nsf::procs with zero arguments or plain arguments (when "-debug" is used); extended regression test; bump version number to 2.1. [a0faba2] * serializer.tcl: Provide for backward compatibility in method serializer. [c04d6db] 2015-12-22 Gustaf Neumann * nsfError.c (NsfDStringVPrintf): Fix potential memory corruption bug in NsfDStringVPrintf. [cf9bbe0] 2015-12-19 Gustaf Neumann * serializer.tcl: Added handling of "-debug" and "-deprecated" in serializer; allow export of nsfprocs via "exportMethods declaration" in order to keep otherwise excluded cmds in the result. Hardened serializer (use e.g. "::namespace" instead of "namespace" when there is a potential conflict with a method named "namespace", prefer nsf::directdispatch, etc.); extended regression test. [6a55e4e] * nx.tcl: Added flags "-debug" and "-deprecated" to further NX method-defining methods. [183cd0a] 2015-12-18 Gustaf Neumann * nx.tcl (nx::Class, nx::Object): Added flags "-debug" and "-deprecated" to "?object? method"; extended regression test. [2d609d0] (nx::Class, nx::Object): Added new introspection options; extended regression test: /cls/ info method debug /cls/ info method deprecated /obj/ info object method debug /obj/ info object method deprecated [53113de] * nsf.c, serializer.tcl, nsf-cmd.test: Handling "deprecated" and "debug" properties for nsf::proc (in "nsf::cmd::info definition /proc/" and serializer). [63fb7c1] 2015-12-17 Gustaf Neumann * nsf.c, nsf.tcl, nsfAPI.*, nsfProfile.c, nsfStack.c: New method properties nsf::method::property /obj/ /method/ debug ?0|1? nsf::method::property /obj/ /method/ deprecated ?0|1? [8854eef] 2015-12-13 Gustaf Neumann * nsf.c, nsfAPI.*, nx.tcl (nx::Object): New introspection method "/obj/ info baseclass"; extended regression test. [5a162b0] (nx::Object, nx::Class): new introspection methods "/obj/ info object method callprotection /m/" and "/cls/ info method callprotection /m/"; extended regression test. [07b40a4] 2015-12-12 Gustaf Neumann * serializer.tcl: Fix ::Serializer->methodSerialize when called for per-object methods. [2f76d3a] * next-migration.txt: Fix editing bug in documentation. [c105770] 2015-11-30 Gustaf Neumann * generic/*, gentclAPI.tcl: New macros NSF_nonnull_assert() and nonnull_assert(). Background: The unreleased gcc6 with "-pedantic" complaints since recently about asserts, in which nonnull conditions implied by nonnull declarations are explicitly tested, and spits out warnings like "warning: nonnull argument [...] compared to NULL". The new macros turns off asserts, when gcc6 is used. [16a0288] * nsf.c, nsfAPI.*, nsfInt.h, nsfProfile.c, nsfShadow.c: Profile trace enhancements, add optional argument "-builtins" to "nsf::__profile_trace" to trace a selected list of built-ins. Every element of the list passed to "-builtins" might contain a cmd name and optionally a maximum number of arguments to be shown ,typically 0 or 1. Generalized NsfReplaceCommand* logic to become more general usable (e.g. for the builtins mechanism of nsf::__profile_trace). [19c8474] 2015-11-27 Gustaf Neumann * nsfProfile.c: Remove redundant prototype. [f1ac62f] * nsf.c, nsfInt.h, nsfProfile.c, nsfAPI.*: Use standard logging for "nsf::__profile_trace -verbose true" by using the standard logging mechanism, we can redefining "::nsf::log" to output e.g. trace in a GUI. Add argument "-dontsave" to nsf::__profile_trace to avoid saving trace in memory. Refactor trace and debug output to deliver lists. This makes it easier to postprocess the results from Tcl. [55c89d7] * nsf.h: Place arguments of preprocessor macros into parentheses. [6953255] 2015-11-23 Gustaf Neumann * nsfInt.h (NsfObjectSystem): Silence cppcheck 1.71. [a792884] 2015-11-08 Gustaf Neumann * nsf.c (ParameterMethodDispatch, NsfNSCopyVarsCmd, NsfOConfigureMethod): Keep Tcl error messages, when Tcl_ObjSetVar2 fails. [74d126b] (AutonameIncr, NsfOConfigureMethod, ParameterMethodDispatch): Handle result of Tcl_ObjSetVar2() in all cases. [2d42793] (NsfOConfigureMethod, NsfOCgetMethod): Don't swallow errors triggered from variable write traces in configure. [a709e3e] 2015-11-06 Gustaf Neumann * nx.tcl, xotcl2.tcl: Fixed a bug that disallowed the combination of valuecmd and valuechangedcmd for a single property (many thanks to Zoran for pointing this out). [3946480] * nsf.c (Nsf_ThreadExitProc, ArgumentDefaults): White-space changes. [dbe0bb3] 2015-11-05 Gustaf Neumann * parameters.test: Whitespace change. [aca62da] 2015-10-16 Stefan Sobernig * mkIndex.tcl: In certain build situations, we might still run under Tcl 8.4 because it comes as a legacy OS battery. Tcl modules are >= 8.5 only. [b137911] 2015-10-01 Gustaf Neumann * nsf.c, nsfAPI.*, nx.tcl, serializer.tcl: New command "nsf::method::forward::property" in analogy to "nsf::method::property" for reading+writing introspection of forwarders (important for serializer, when different target objects are specified, to map the per-object forwarder); extended regression test; bumped version number of serializer to 2.1. [f31c1a0] 2015-09-27 Gustaf Neumann * nsf.c, nsfInt.h: Reduce implicit conversions, write body of if-statements as blocks, whitespace changes, prefer boolean expressions, add likely/unlikely hints. [afbb465] 2015-09-26 Gustaf Neumann * generic/*.c: Prefer boolean expressions, reduce implicit conversions, write body of if-statements as blocks, whitespace changes, update licenses. [2e1a88e] 2015-09-21 Gustaf Neumann * Makefile.in, autogen.sh, configure.ac: Support building NSF from some other directory than the root directory; raise no error, when NSF is built with mongo + profile enabled. [1c9684a] 2015-08-11 Gustaf Neumann * nsf.c (NSDeleteChild, DispatchDestroyMethod): Improve robustness of destroy: in case an error happened in a destroy method in implicit delete operations, a crash was possible, since the state of the object to be delete was somewhat unclear: it might or might not have been deleted. Now, the object is explicitly kept longer around to allow proper handling. [19058de] * nx.tcl: Don't raise an error, but add warning in cases, slot data is inconsistent. [71a3245] 2015-07-29 Gustaf Neumann * nsf.c (ObjectSystemsCheckSystemMethod): Don't define variables inside a block. [9e1cdbe] (NextGetArguments): Address coverty CID 102646, second attempt. [f3ca6a1] (ObjectDispatch): Address covertiy CID 88773. [f90a7fa] * gentclAPI.tcl, nsfAPI.h: Revert overeager part of the change. Remove logically dead code as flagged by Coverity. Move assignments after assertions in generated code. [cad3e31,ec070e9,0e247f6] 2015-07-29 Stefan Sobernig * README.release: Adding details how to upload Coverity builds. [6d4bc2b] 2015-07-29 Gustaf Neumann * nsf.c (FilterInvalidateObjOrders): Remove expressions which were always true. [bd4d7d0] (FilterInvalidateObjOrders): Turn for() loop into a repeat-until loop, since in first iteration, the loop controlling expression was always true. [33aa1b2] (CleanupDestroyClass): Address coverty CID 88774. [6adb5d9] (NsfOResidualargsMethod): Address CID 88776. [1a7f8ba] 2015-07-28 Stefan Sobernig * README.release: Adding Coverity instructions. [b43b9e2] 2015-07-28 Gustaf Neumann * nsf.c: Move dereferencing of members after assertions. [00186f9] * nsf.c (NsfRelationClassMixinsSet): Move assertion after assignment. [9f90d6b] (NSDeleteChild): Fix potential bug on Tcl-triggered cmd-delete operations, where destroy returns non-TCL_OK and name of the object could not be retrieved anymore in error message. [92d76b8] (ParameterMethodDispatch): Attempt to make Coverty happy (CID 88769). [a4eaf4e] (FreeAllNsfObjectsAndClasses): Remove test, since it is covered already by assertions. [accdf4b] * nsf.c, nsfInt.h (NsfParamDefs): Removed NsfParamDefs.slotObj and single occurrence for memory-management since it is not used for the time being [08dedac] (NsfProcClientData, MethodDispatch, ObjectDispatch): Write body-blocks of if on separate lines; change variable name "validCscPtr" to "isValidCsc", since it is a boolean and not a ptr Tcl coding guidelines; prefer explicit comparisons. [6c7bb9b] 2015-07-28 Stefan Sobernig * nsf.c (MethodDispatch): Fix compiler warning on typecast mismatch. [4e2b21c] * nsfObj.c (MixinregSetFromAny): Re-arrange control flow as to match other uses in the code base (CID 88777). [1527180] 2015-07-27 Stefan Sobernig * nsf.c (ResolveMethodName): Guard against potential null pointer dereference (CID 88771). [ca7f760] (FreeAllNsfObjectsAndClasses): Remove unneeded NULL check as dereferencing already occurred before; check for NULL earlier (CID 88780). [2638eb9] 2015-07-23 Stefan Sobernig * nsfObj.c (MixinregSetFromAny): Fix crash through explicit null dereferencing when an invalid list string-rep is provided as mixinreg (CID 88777); added tests [207a8f5] * nsf.c (MakeProc): Silence false-positive warning, due to missing returns_nonnull annotation (CID 88770). [a757c1a] 2015-07-17 Stefan Sobernig * nsf.c: (ConvertViaCmd, ConvertToObjpattern, GetSlotObject): Check return values of GetObjectFromObj explicitly (CID 88763, 88764, 88765). [8357e61] (ObjectSystemsCheckSystemMethod): Mark TCL_ERROR path as unlikely. [c0e1053] (ObjectSystemsCheckSystemMethod): Re-order control flow to remove otherwise dead IF-branch (CID 88768). [1eaf0a3] (NsfMethodPropertyCmd): Dropped option 'slotobj' as it is obsolete. Also fixes CID 88767. [6c9eb2e] (ListMethod): Make sure that 'info method exists' returns 0 for (plain) NX objects; added some tests. [0b1ac7f] (ListCmdParams): Removed logically dead code (CID 88779). [c2e5725] * Documentation (info.man.inc): Make empty-string ambiguity explicit for 'info method *'. [497451f] 2015-07-16 Stefan Sobernig * nsfStack.c (NsfShowStack): Removed logically dead code. CID 88766. [caee18f] 2015-04-07 Gustaf Neumann * nsfInt.h: Fix compilation when compiled without --enable-profile. [6c58e11] 2015-04-06 Gustaf Neumann * gentclAPI.tcl, nsf.c, nsfProfile.c: Improve profiling support and added profile support for undispatched methods (i.e. implemented via CallDirectly). New function for controlling profile trace "nsf:__profile_trace -enable /bool/ ?-verbose /bool/?". [c5f2227] 2015-04-03 Stefan Sobernig * nsfDebug.c, nsfInt.h, nsf-cmd.test: Silence varargs warning -Wgnu-zero-variadic-macro-arguments under clang --std=c99 -pedantic, tested under gcc, clang 3.6, and MSVC; added tests. [714726d] 2015-04-01 Gustaf Neumann * nsf.c, nsfError.c, nsfProfile.c: Changed trace facility to append to a variable to minimize interactions for results and return codes, which happen via nsf::log; added more convenient function for adding to DStrings: Nsf_DStringPrintf; renamed NsfDStringPrintf to NsfDStringVPrintf; replaced complex macros for tracing by functions. [453ad27] 2015-03-31 Gustaf Neumann * nsf.c, nsfAPI.*, nsfInt.h, nsfProfile.c: Added experimental "nsf::configure trace" feature, which can be enabled when compiled with profile support. trace turns on automatically profile. [e1c25b4] 2015-01-22 Gustaf Neumann * nsf.c, nsfDebug.c, nsfStack.c: Improve cleanness of compilation when "-pedantic" is used. [bf951b5] 2015-01-05 Gustaf Neumann * nsf.c, nsfDebug.c, nsfObj.c: Assignments after assertions. [658c5ca] * Makefile.in: Add -DNDEBUG=1 to flags passed to cppcheck, since cppcheck reports checked cases as warnings. [efb84f6] 2015-01-02 Gustaf Neumann * generic/*.c: Prefer const over CONST unless Tcl API. [dbd95b0] 2015-01-01 Gustaf Neumann * Documentation: Strip old content from announce file. [5bdfdb7] 2014-12-13 Gustaf Neumann * gentclAPI.tcl, nsfAPI.h, mongoAPI.h: Use same definition for ObjCmds as in Tcl; prefer "const" over "CONST" unless in Tcl interface. [62beaf1] * Documentation (doc/example-scripts/*): Regenerate doc pages with asciidoc 8.6.9, fix paths. [24cb8f4] * nsf.c, nsf.h (NsfLog): Align log levels with NaviServer/AOLserver. [6b00c4e] 2014-12-11 Gustaf Neumann * nsf.c, nsfmongo.c: Fix all complaints from clang static analyzer 3.6. [919f731] 2014-12-06 Gustaf Neumann * Documentation (next-migration.txt, next-tutorial.txt): Update date in documentation. [d725e5e] * Makefile.in: Make sure to rm .o files in stub directory. [4f7f7c1] * mktar.sh: Make sure to omit macOS hidden file from tarballs. [9fe4a51] 2014-12-04 Gustaf Neumann * generic/*.c: Prefer boolean expression in tests over expressions of other types. [24571ae] 2014-12-01 Gustaf Neumann * aolstub.c, nsf.c, nsfEnumerationType.c, nsfInt.h: Add const declarations, improve compilation with --std=c99 -pedantic. [9e00fd1] * nsfInt.h, nsfUtil.c, nsfmongo.c: Make compilation clean with clang 3.6. [81a1f96] * nsf.c, nsfStack.c: Make compilation clean under clang 3.6. [1173a57] 2014-11-25 Gustaf Neumann * nsf.decls: Add NsfArgumentError() to stub interface, since this might be used by C packages using the interface generator. [9e8610b] * nsfmongo.c: Add mong::json to the interface, bump version number for mongo interface to 0.4. [9e8610b] 2014-10-29 Stefan Sobernig * Documentation (doc/*.man, man-princexml.css): Fix PDF rendering and man markup. [83b89fe] ./nsf2.4.0/deploy_key.enc000644 000766 000024 00000006460 13454166031 016034 0ustar00neumannstaff000000 000000 Vk /&-\j^jh(ĥd iqx69!;R #aŤ$է?tɵXK!IaDpu4h;5* cA#$󝰍FL*!Pc'PCö\~0-WS}Vzb5^ejƬBvsx!^uO"%{_%9,ˊuB~THpi5]BZ©ER{ ےSA-ɈQdXfg .8 B|RPX]ՕLG잢}gMwUh\HG\FoA"ꯆ{Y kUyGq:jE-|>)+BnY T) źeZ/"T,urPذ[sqKV۳>ñ2Nc)KZ?e0steqpz, dvX޷ T!OI~8ifeb$B'>޲Y )cK&!OW4a3ASYln9bt^eE<ҁ}L"fReT䔻9lis[iBj +-M` 8?+夛7S ctAXǀ0&@."b UܚX]g]Q w"̝Vg q#2'xԋIQe2gz~e٤#|ڀ{l8Or _c:\0!A[t7w] 8-VztuN@g 粼MЧr| i/zቃRx/ Ľ9uNy.U-A$-E}xN utn>3qClOfu(컯 r\cֽ/Jhnq0C#54P -Dj_`aa` ki]$b]4>$zh詸rC~.pWT短8;٥sܡ*"Ջ0>$&9ZϠe 2G=pD :s yᢪWx3Ճ\h ef,yF"i#Lm֋ EnA3\Oe[cʙPK*p sTTGRXg*IW^RDCUTu|rXYcѨTcId}07aE5g,e1Q?4NqoJWVRevtLSp_r 4#j Pdb*c2pJDPD9򦏩mWp݄f vUle(zyU)Qq2+a 6>ݘח}8I Wn p6E1, 0Jy0>9S4rH!kq<*-QԯKJmX;3)Bx1: l-my.DaoЧ#%]\s60`~?qW5q/d.Hyo8|]Arm"' 40@Ǻ?]<;] öe 9!k"yZe?'r-,F$Z7yNDU}Jg2.PK2ڻU][3P:am<ɮM`۫K\1l:CE*g,YKag][n/m0t14ȕSezp$x?⚡1#&/CQj^ w5ݫ B*uGO\_#0c{ѽZFBrǺ5-as)qYY1 OQ 1*0I!s/P-/@*ri ~ѳf鱬%h;3B!ac~j=ʐh>@<`Ei?QEdVa% y}V:KNX&eL .`T^G| Լ4BZ /jE9q= :Fs.P,BKDp?(s NvG'5*@:>"q*~pLl@zSTtVkC˥Rz./nsf2.4.0/tests/doc.test000644 000766 000024 00000104013 13712264152 016002 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package require nx package require nx::test package require nx::doc namespace import -force ::nx::* namespace import -force ::nx::doc::* nx::test configure -count 1 # # some helper # proc lcompare {a b} { foreach x $a y $b { if {$a ne $b} {return -1} } return 1 } # -- # # Source the "Document Comment" backend # package require nx::doc::dc Test case scanning { set lines { "# @package o" 1 "#@package o" 1 "bla" 0 "# @object o" 1 "# 1 2 3" 1 "#" 1 "# " 1 " # " 1 "\t#\t \t" 1 "# 345" 1 "# @tag1 part1" 1 "bla; # no comment" 0 "" 0 "\t\t" 0 "### # # # # @object o # ####" 1 "# # # # # 345" 1 "# # # @tag1 part1" 1 "bla; # # # # # no comment" 0 " " 0 } set ::prj [@project new -name _PROJECT_] foreach {::line ::result} $lines { ? {lassign [$::prj analyze_line $::line] is_comment text; set is_comment} $::result "processor analyze_line '$::line'" } set script { # @package o # 1 2 3 bla bla # @object o # 1 2 3 # # 345 # @tag1 part1 # @tag2 part2 bla; # no comment bla bla bla ### # # # # @object o # #### # 1 2 3 # # # # # # 345 # # # @tag1 part1 # @tag2 part2 bla; # # # # # no comment } set blocks {1 {{ @package o} { 1 2 3}} 5 {{ @object o} { 1 2 3} {} { 345} { @tag1 part1} { @tag2 part2}} 17 {{ @object o # ####} { 1 2 3} {} { 345} { @tag1 part1} { @tag2 part2}}} ? [list ::lcompare [$::prj comment_blocks $script] $blocks] 1 } Test case parsing { set ::prj [@project new -name _PROJECT_] namespace import -force ::nx::doc::CommentBlockParser # # TODO: Add tests for doc-parsing state machine. # set block { {@command ::cc} } set ::cbp [CommentBlockParser process $block] ? [list $::cbp status ? COMPLETED] 1 set block { {} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? COMPLETED] 0 ? [list $cbp status ? STYLEVIOLATION] 1 # # For now, a valid comment block must start with a non-space line # (i.e., a tag or text line, depending on the section: context # vs. description) # set block { {} {@command ::cc} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? STYLEVIOLATION] 1 set block { {command ::cc} {} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? STYLEVIOLATION] 1 set block { {@command ::cc} {some description} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? STYLEVIOLATION] 1 set block { {@command ::cc} {} {} {} {@see ::o} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? STYLEVIOLATION] 0 ? [list $cbp status ? COMPLETED] 1 set block { {@command ::cc} {} {some description} {some description2} {} {} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? STYLEVIOLATION] 0 # Note: We do allow description blocks with intermediate space # lines, for now. set block { {@command ::cc} {} {some description} {some description2} {} {an erroreneous description line, for now} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? STYLEVIOLATION] 0 # # TODO: Do not enforce space line between the context and immediate # part block (when description is skipped)? # # OR: For absolutely object::qualifying parts (e.g., outside of an initblock), # do we need sequences of _two_ (or more) tag lines, e.g. # # -- # @object Foo # @param attr1 # -- # # THEN, we can only discriminate between the context and an # immediate part section by requiring a space line! # # Alternatively, we can use the @see like syntax for object::qualifying: # @param ::Foo#attr1 (I have a preference for this option). set block { {@command ::cc} {@see someOtherEntity} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? STYLEVIOLATION] 1 # # TODO: Disallow space lines between parts? Check back with Javadoc spec. # set block { {@command ::cc} {} {@see SomeOtherEntity} {add a line of description} {} {} {@see SomeOtherEntity2} {} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? STYLEVIOLATION] 1 # # TODO: Should we enforce a mandatory space line between description and part block? # set block { {@command ::cc} {} {add a line of description} {a second line of description} {a third line of description} {@see entity3} {@see SomeOtherEntity2} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? STYLEVIOLATION] 1 set block { {@command ::cc} {} {add a line of description} {a second line of description} {a third line of description} {} {@see SomeOtherEntity2} {} {} {an erroreneous description line, for now} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? STYLEVIOLATION] 1 set block { {@command ::cc} {} {add a line of description} {a second line of description} {} {a third line of description} {} {@see SomeOtherEntity2} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? STYLEVIOLATION] 0 set block { {@object ::cc} {} {add a line of description} {a second line of description} {} {@see SomeOtherEntity2} {@xyz SomeOtherEntity2} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? INVALIDTAG] 1 set block { {@class ::cc} {} {add a line of description} {a second line of description} {} {@see SomeOtherEntity2} {@xyz SomeOtherEntity2} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? INVALIDTAG] 1 # # TODO: Where shall we allow the @author tag?! Re-activate # later, if necessary ... # if {0} { # # testing the doc object construction # set block { {@object ::o} {} {some more text} {and another line for the description} {} {@author stefan.sobernig@wu.ac.at} {@author gustaf.neumann@wu-wien.ac.at} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? COMPLETED] 1 set entity [$cbp current_entity] ? [list ::nsf::is object $entity] 1 ? [list $entity info has type ::nx::doc::@object] 1 ? [list $entity @author] "stefan.sobernig@wu.ac.at gustaf.neumann@wu-wien.ac.at"; ? [list $entity as_text] "some more text and another line for the description"; } set block { {@command ::c} {} {some text on the command} {} {@see ::o} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? COMPLETED] 1 set entity [$cbp current_entity] ? [list ::nsf::is object $entity] 1 ? [list $entity info has type ::nx::doc::@command] 1 ? [list $entity as_text] "some text on the command"; ? [list $entity @see] "::o"; set block { {@class ::C} {} {some text on the class entity} {} {@class-property attr1 Here! we check whether we can get a valid description block} {for text spanning multiple lines} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? COMPLETED] 1 set entity [$cbp current_entity] ? [list ::nsf::is object $entity] 1 ? [list $entity info has type ::nx::doc::@class] 1 ? [list $entity as_text] "some text on the class entity"; ? [list llength [$entity @property]] 1 ? [list [$entity @property] info has type ::nx::doc::@param] 1 ? [list [$entity @property] as_text] "Here! we check whether we can get a valid description block for text spanning multiple lines" } if {0} { Test case in-situ-basics { # # basic test for in-situ documentation (initblock) # # set script { package req nx namespace import -force ::nx::Class Class create ::Foo { # The class Foo defines the behavior for all Foo objects # # @author gustaf.neumann@wu-wien.ac.at # @author ssoberni@wu.ac.at # @.property attr1 # # This property 1 is wonderful # # @see ::nx::VariableSlot # @see ::nx::MetaSlot :property attr1 :property attr2 :property attr3 # @.method foo # # This describes the foo method # # @parameter a Provides a first value # @parameter b Provides a second value :method foo {a b} {;} } } # set prj [processor process -sandboxed -type eval $script] set prj [@project new -name _PROJECT_] set entity [@class id ::Foo] ? [list ::nsf::is object $entity] 1 ? [list $entity info has type ::nx::doc::@class] 1 ? [list $entity as_text] "The class Foo defines the behavior for all Foo objects"; ? [list $entity @author] "gustaf.neumann@wu-wien.ac.at ssoberni@wu.ac.at" # TODO: Fix the [@param id] programming scheme to allow (a) for # entities to be passed and the (b) documented structures set entity [@property id [@class id ::Foo] class attr1] ? [list ::nsf::is object $entity] 1 ? [list $entity info has type ::nx::doc::@property] 1 ? [list $entity @see] "::nx::VariableSlot ::nx::MetaSlot"; set entity [@method id ::Foo class foo] ? [list [@class id ::Foo] @method] $entity ? [list ::nsf::is object $entity] 1 ? [list $entity info has type ::nx::doc::@method] 1 ? [list $entity as_text] "This describes the foo method"; foreach p [$entity @parameter] expected { "Provides a first value" "Provides a second value" } { ? [list expr [list [$p as_text] eq $expected]] 1; } $prj destroy } # TODO: how to realize scanning and parsing for mixed ex- and # in-situ documentation? That is, how to differentiate between # absolutely and relatively qualified comment blocks in line-based # scanning phase (or later)? Test case mixed-mode-parsing { set script { package req nx namespace import -force ::nx::* # @class ::Bar # # The class Bar defines the behavior for all Bar objects # # @author gustaf.neumann@wu-wien.ac.at # @author ssoberni@wu.ac.at # @class.property {::Bar attr1} # # This property 1 is wonderful # # @see ::nx::VariableSlot # @see ::nx::MetaSlot # @class.class-method {::Bar foo} # # # This describes the foo method # # @parameter a Provides a first value # @parameter b Provides a second value # @class.object-method {::Bar foo} # # This describes the per-object foo method # # @parameter a Provides a first value # @parameter b Provides a second value namespace eval ::ns1 { ::nx::Object create ooo } Class create Bar { :property attr1 :property attr2 :property attr3 # @.method foo # # This describes the foo method in the initblock # # @parameter a Provides a first value # @parameter b Provides a second value :public method foo {a b} { # This describes the foo method in the method body # # @parameter a Provides a first value (refined) } :public class method foo {a b c} { # This describes the per-object foo method in the method body # # @parameter b Provides a second value (refined) # @parameter c Provides a third value (first time) } } } set prj [processor process -sandboxed -type eval $script] set entity [@class id ::Bar] ? [list ::nsf::is object $entity] 1 ? [list $entity info has type ::nx::doc::@class] 1 ? [list $entity as_text] "The class Bar defines the behavior for all Bar objects"; ? [list $entity @author] "gustaf.neumann@wu-wien.ac.at ssoberni@wu.ac.at" # TODO: Fix the [@param id] programming scheme to allow (a) for # entities to be passed and the (b) documented structures set entity [@property id [@class id ::Bar] class attr1] ? [list ::nsf::is object $entity] 1 ? [list $entity info has type ::nx::doc::@property] 1 ? [list $entity @see] "::nx::VariableSlot ::nx::MetaSlot"; set entity [@method id ::Bar class foo] ? [list [@class id ::Bar] @method] $entity ? [list ::nsf::is object $entity] 1 ? [list $entity info has type ::nx::doc::@method] 1 ? [list $entity as_text] "This describes the foo method in the method body"; foreach p [$entity @parameter] expected { "Provides a first value (refined)" "Provides a second value" } { ? [list expr [list [$p as_text] eq $expected]] 1; } set entity [@method id ::Bar object foo] ? [list [@class id ::Bar] @class-object-method] $entity ? [list ::nsf::is object $entity] 1 ? [list $entity info has type ::nx::doc::@method] 1 ? [list $entity as_text] "This describes the per-object foo method in the method body"; foreach p [$entity @parameter] expected { "Provides a first value" "Provides a second value (refined)" "Provides a third value (first time)" } { ? [list expr [list [$p as_text] eq $expected]] 1; } $prj destroy } Test case tag-notations-basics { # # Some tests on structured/navigatable tag notations # # adding support for parsing levels # -- @class.object.object {::D o1 o2} set block { {@..object o2 We have a tag notation sensitive to the parsing level} } set entity [[@ @class ::D] @object o1] set cbp [CommentBlockParser process -parsing_level 1 -partof_entity $entity $block] ? [list $cbp status ? LEVELMISMATCH] 1 set cbp [CommentBlockParser process -parsing_level 2 -partof_entity $entity $block] ? [list $cbp status ? COMPLETED] 1 set entity [$cbp current_entity] ? [list ::nsf::object::exists $entity] 1 ? [list $entity info has type ::nx::doc::@object] 1 ? [list $entity as_text] "We have a tag notation sensitive to the parsing level" set block { {@..object {o2 o3} We still look for balanced specs} } set entity [[@ @class ::D] @object o1] set cbp [CommentBlockParser process -parsing_level 2 -partof_entity $entity $block] ? [list $cbp status ? STYLEVIOLATION] 1 # This fails because we do not allow uninitialized/non-existing # entity objects (@object o) along the resolution path ... set block { {@class.object.property {::C o attr1} We have an invalid specification} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? INVALIDTAG] 1 # ? [list $cbp message] "The tag 'object' is not supported for the entity type '@class'" set block { {@class.method.property attr1 We have an imbalanced specification (the names are underspecified!)} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? STYLEVIOLATION] 1 ? [list $cbp message] "Imbalanced tag line spec: 'class method property' vs. 'attr1'" # For now, we do not verify and use a fixed scope of permissive tag # names. So, punctuation errors or typos are most probably reported # as imbalanced specs. In the mid-term run, this should rather # become an INVALIDTAG condition. set block { {@cla.ss.method.parameter {::C foo p1} We mistyped a tag fragment} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? STYLEVIOLATION] 1 ? [list $cbp message] "Imbalanced tag line spec: 'cla ss method parameter' vs. '::C foo p1'" set block { {@cla,ss.method.parameter {::C foo p1} We mistyped a tag fragment} } set cbp [CommentBlockParser process $block] ? [list $cbp status ? INVALIDTAG] 1 ? [list $cbp message] "The entity type '@cla,ss' is not available." } Test case tag-notations-extended { set script { # @class ::C # # The global description of ::C # # @property attr1 Here we can only provide a description block for object parameters # @class.object-method {::C sub} # # For now, we have to declare a family of sub methods explicitly # (allows for providing some overview, shared description) # @class.property {::C attr1} Here, we could also write '@class.class-property \{::C attr1\}', @property is a mere forwarder! In the context section, only one-liners are allowed! # @class.object.property {::C foo p1} A short description is ... # # .. is overruled by a long one ... # If addressing to a nested object, one strategy would be to use # @object and provide the object identifier (which reflects the # nesting, e.g. ::C::foo). However, we cannot distinguish between # namespace qualifiers denoting an object, class or owning # namespace! # # ISSUE: If specifying an axis ".object", we would have to define # a part property @object on @class and @object. However, @object # would be ambiguous now: It could be called in a freestanding # (absolute) manner AND in a contextualised manner (in an init # block). In the latter case, it would fail because we would have # to provide a FQ'ed name (which defeats the purpose of a nested = # contextualised notation). # # SO: for now, we introduce a part property child-object (and # child-class?) to discrimate between the two situations ... # # TODO: How to register this so created @object entity as nested # object with the doc entity represented the parent object? Class create C { # This is the initblock description of ::C which overwrites the # global description (see above) # @.property attr1 # # This is equivalent to writing "@class-property attr1" :property attr1 { # This description does not apply to the object parameter # "attr1" owned by the ::C class, rather it is a description # of the property slot object! How should we deal with this # situation? Should this level overwrite the top-level and # initblock descriptions? } # @.class-object-property attr2 Carries a short desc only :class property attr2 # @.method foo # # @parameter p1 set fooHandle [:public method foo {p1} { # Here goes some method-body-level description # # @parameter p1 The most specific level! return [current method]-$p1-[current] }] # @.object-method bar # # Before referring to its parts, an entity must exist; so # declare eagerly ... # @.class-object-method.parameter {bar p1} # # This extended form allows one to describe a method parameter with all # its structural features! set barHandle [:public class method bar {p1} { return [current method]-$p1-[current] }] # @.object foo 'foo' needs to be defined before referencing any of its parts! # @.object.property {foo p1} # # The first element in the name list is resolved into a fully # qualified (absolute) entity, based on the object owning the # initblock! Object create [current]::foo { # Adding a line for the first time (not processed in the initblock phase!) # @..property p1 # # This is equivalent to stating "@class-object-property p1" :property p1 } # @.class Foo X # # By providing a fully-qualified identifier ("::Foo") you leave the # context of the initblock-owning object, i.e. you would NOT refer to # a nested class object named "Foo" anymore! # @.class.property {Foo p1} # # This is equivalent to stating "@child-class.class-property {Foo p1}" # @.class.class-object-property {Foo p2} Y Class create [current]::Foo { # @..property p1 # # # This is equivalent to stating "@class-property p1"; or # '@class.object.property {::C Foo p1}' from the top-level. :property p1 # @..class-object-property p2 :class property p2 } # @.class-object-method.sub-method {sub foo} # # ISSUE: Should submethods be navigatable through "method" (i.e., # "@method.method.method ...") or "submethod" (i.e., # "@method.submethod.submethod ...")? ISSUE: Should it be sub* with # "-" (to correspond to "@class-object-method", "@class-method")? Also, we # could allow both (@sub-method is the property name, @method is a # forwarder in the context of an owning @method object!) # # @parameter p1 Some words on p1 :class alias "sub foo" $fooHandle # @.method sub # # The desc of the ensemble object 'sub' # # @sub-method bar Only description available here ... # ISSUE: Should the helper object "sub" be documentable in its own # right? This would be feasible with the dotted notation from # within and outside the init block, e.g. "@object sub" or # "@class.object {::C sub}" # # ISSUE: Is it correct to say the sub appears as per-object method # and so do its submethods? Or is it misleading to document it that # way? Having an "@class-object-submethod" would not make much sense to # me?! :alias "sub bar" $barHandle # @.class-object-method sub A brief desc # @.class-object-method {"sub foo2"} # # could allow both (@sub-method is the property name, @method is a # forwarder in the context of an owning @method object!) # # @parameter p1 Some words on p1 # @see anotherentity # @author ss@thinkersfoot.net :class alias "sub foo2" $fooHandle } } # # 1) process the top-level comments (PARSING LEVEL 0) # processor readin $script # --testing-- "@class ::C" set entity [@class id ::C] ? [list ::nsf::object::exists $entity] 1 ? [list $entity info has type ::nx::doc::@class] 1 ? [list $entity as_text] "The global description of ::C"; # --testing-- "@class.property {::C attr1}" set entity [@property id $entity class attr1] ? [list ::nsf::object::exists $entity] 1 ? [list $entity info has type ::nx::doc::@property] 1 ? [list $entity as_text] "Here, we could also write '@class.class-property {::C attr1}', @property is a mere forwarder! In the context section, only one-liners are allowed!" # --testing-- "@class.object.property {::C foo p1} A short description is ..." # set entity [@property id $entity class attr1] # set entity [@object id -partof_name ::C -scope child foo] # ? [list ::nsf::object::exists $entity] 1 # ? [list $entity info has type ::nx::doc::@object] 1 # ? [list $entity as_text] "" # set entity [@property id $entity object p1] # ? [list ::nsf::object::exists $entity] 1 # ? [list $entity info has type ::nx::doc::@property] 1 # ? [list $entity as_text] ".. is overruled by a long one ..." set entity [@object id ::C::foo] ? [list ::nsf::object::exists $entity] 0 set entity [@property id $entity class p1] ? [list ::nsf::object::exists $entity] 0 # ? [list $entity info has type ::nx::doc::@property] 1 # ? [list $entity as_text] ".. is overruled by a long one ..." # --testing-- @class-object-property attr2 (its non-existence) set entity [@property id [@class id ::C] object attr2] ? [list ::nsf::object::exists $entity] 0 # --testing-- @child-class Foo (its non-existence) set entity [@class id ::C::Foo] ? [list ::nsf::object::exists $entity] 0 # --testing -- @method foo (its non-existence) set entity [@method id ::C class foo] ? [list ::nsf::object::exists $entity] 0 # --testing-- @class-object-method.parameter {bar p1} (its non-existence) set entity [@parameter id [@method id ::C class bar] "" p1] ? [list ::nsf::object::exists $entity] 0 # --testing-- @child-object.property {foo p1} (its non-existence) set cl [@class id ::C::Foo] ? [list ::nsf::object::exists $entity] 0 set entity [@property id $cl class p1] ? [list ::nsf::object::exists $entity] 0 set entity [@property id $cl object p2] ? [list ::nsf::object::exists $entity] 0 # # 2) process the initblock comments (PARSING LEVEL 1) # puts stderr -----CMD------ ::nsf::configure keepcmds true eval $script ::nsf::configure keepcmds false lassign [processor readin \ -parsing_level 1 \ -docstring \ -tag @class \ -name ::C \ [::C eval {set :__cmd(__initblock)}]] _ processed_entities # a) existing, but modified ... set entity [@class id ::C] ? $_ $entity ? [list ::nsf::object::exists $entity] 1 ? [list $entity info has type ::nx::doc::@class] 1 ? [list $entity as_text] "This is the initblock description of ::C which overwrites the global description (see above)" set entity [@property id $entity class attr1] ? [list ::nsf::object::exists $entity] 1 ? [list $entity info has type ::nx::doc::@property] 1 ? [list $entity as_text] {This is equivalent to writing "@class-property attr1"} set entity [@object id ::C::foo] ? [list ::nsf::object::exists $entity] 1 ? [list $entity info has type ::nx::doc::@object] 1 ? [list $entity as_text] "'foo' needs to be defined before referencing any of its parts!"; # still empty! set entity [@property id $entity object p1] ? [list ::nsf::object::exists $entity] 1 ? [list $entity info has type ::nx::doc::@property] 1 ? [list $entity as_text] "The first element in the name list is resolved into a fully qualified (absolute) entity, based on the object owning the initblock!" # b) newly added ... # --testing-- @class-object-property attr2 set entity [@property id [@class id ::C] object attr2] ? [list ::nsf::object::exists $entity] 1 ? [list $entity info has type ::nx::doc::@property] 1 ? [list $entity as_text] "Carries a short desc only"; # --testing-- @child-class Foo # TODO: provide a check against fully-qualified names in part specifications set entity [@class id ::C::Foo] ? [list ::nsf::object::exists $entity] 1 ? [list $entity info has type ::nx::doc::@class] 1 ? [list $entity as_text] {By providing a fully-qualified identifier ("::Foo") you leave the context of the initblock owning object, i.e. you would NOT refer to a nested class object named "Foo" anymore!} set entity [@property id [@class id ::C] class p1] ? [list ::nsf::object::exists $entity] 0; # should be 0 at this stage! # --testing -- @method foo set entity [@method id ::C class foo] ? [list ::nsf::object::exists $entity] 1 ? [list $entity as_text] "" # --testing-- @class-object-method.parameter {bar p1} (its non-existence) It # still cannot exist as a documented entity, as the class method # has not been initialized before! set entity [@parameter id [@method id ::C class bar] "" p1] ? [list ::nsf::object::exists $entity] 0 # --testing-- @child-class.property {foo p1} (its non-existence) # --testing-- @child-class.object-property {foo p2} (its non-existence) set cl [@class id ::C::Foo] ? [list ::nsf::object::exists $cl] 1 set entity [@property id $cl class p1] ? [list ::nsf::object::exists $entity] 1 ? [list $entity as_text] {This is equivalent to stating "@child-class.class-property {Foo p1}"} set entity [@property id $cl object p2] ? [list ::nsf::object::exists $entity] 1 ? [list $entity as_text] "Y" set entity [@method id ::C class sub] ? [list ::nsf::object::exists $entity] 1 ? [list $entity as_text] "The desc of the ensemble object 'sub'" set entity [@method id ::C class sub::bar] ? [list ::nsf::object::exists $entity] 1 ? [list $entity as_text] "Only description available here ..." set entity [@method id ::C object sub] ? [list ::nsf::object::exists $entity] 1 ? [list $entity as_text] "A brief desc" set entity [@method id ::C object sub::foo2] ? [list ::nsf::object::exists $entity] 1 ? [list $entity info has type ::nx::doc::@method] 1 ? [list $entity as_text] "could allow both (@sub-method is the property name, @method is a forwarder in the context of an owning @method object!)" ? [list $entity @see] "anotherentity" # TODO: @author not supported for @method (fine so?) # ? [list $entity @author] "ss@thinkersfoot" set entity [@parameter id $entity "" p1] ? [list ::nsf::object::exists $entity] 1 ? [list $entity as_text] "Some words on p1" # # 3a) process the property initblocks and method bodies (PARSING LEVEL 2)! # set project [@project new -name "_%@"] $project sandbox [Sandbox new] processor process=@class $project [@class id ::C] # methods ... set entity [@method id ::C class foo] ? [list ::nsf::object::exists $entity] 1 ? [list $entity as_text] "Here goes some method-body-level description" set entity [@parameter id [@method id ::C class foo] "" p1] ? [list ::nsf::object::exists $entity] 1 ? [list $entity as_text] "The most specific level!" # attributes ... # attr1 set entity [@property id [@class id ::C] class attr1] ? [list ::nsf::object::exists $entity] 1 ? [list $entity info has type ::nx::doc::@property] 1 ? [list $entity as_text] {This description does not apply to the object parameter "attr1" owned by the ::C class, rather it is a description of the property slot object! How should we deal with this situation? Should this level overwrite the top-level and initblock descriptions?} # # 3b) nested objects/ classes (PARSING LEVEL 2)! # processor readin \ -docstring \ -parsing_level 2 \ -tag @object \ -name ::C::foo \ [::C::foo eval {set :__cmd(__initblock)}] processor process=@object $project [@object id ::C::foo] set entity [@object id ::C::foo] ? [list ::nsf::object::exists $entity] 1 ? [list $entity info has type ::nx::doc::@object] 1 ? [list $entity as_text] "Adding a line for the first time (not processed in the initblock phase!)"; # still empty! set entity [@property id $entity object p1] ? [list ::nsf::object::exists $entity] 1 ? [list $entity info has type ::nx::doc::@property] 1 ? [list $entity as_text] {This is equivalent to stating "@class-object-property p1"} processor readin \ -docstring \ -parsing_level 2 \ -tag @class \ -name ::C::Foo \ [::C::Foo eval {set :__cmd(__initblock)}] processor process=@class $project [@class id ::C::Foo] set cl [@class id ::C::Foo] ? [list ::nsf::object::exists $cl] 1 set entity [@property id $cl class p1] ? [list ::nsf::object::exists $entity] 1 ? [list $entity as_text] {This is equivalent to stating "@class-property p1"; or '@class.object.property {::C Foo p1}' from the top-level.} set entity [@property id $cl object p2] ? [list ::nsf::object::exists $entity] 1 ? [list $entity as_text] "" # # basic testing of "properties" (switch attributes) # ? [list $cl eval {set :@deprecated}] 0 ? [list $cl eval {set :@stashed}] 0 ? [list $cl eval {set :@c-implemented}] 0 ? [list $cl @deprecated] 1 ? [list $cl @stashed] 1 ? [list $cl @c-implemented] 1 ? [list $cl eval {set :@deprecated}] 1 ? [list $cl eval {set :@stashed}] 1 ? [list $cl eval {set :@c-implemented}] 1 set entity [@method id ::C class foo] ? [list $entity eval {set :@syshook}] 0 ? [list $entity @syshook] 1 ? [list $entity eval {set :@syshook}] 1 ? [list $entity @syshook 0] {wrong # args: should be "get obj prop"} ? [list $entity eval {set :@syshook 0}] 0 ? [list $entity @syshook] 1 } Test case switch-parts { set script { package req nx namespace import ::nx::* Class create Enil { # The class Enil defines the behavior for all Enil objects, # however, it is deprecated and will be removed from the # provided doc entities in the next iteration ... # # @author ssoberni@wu.ac.at # @deprecated # @.property attr1 # # This property 1 will be invisible in the generated doc # # @stashed :property attr1 # @.method foo # # This describes the foo method which is called from within the # nx-enabled Tcl engine # # @syshook :public method foo {a b} {;} :public method baz {} { # This method entity sets a couple of properties in series ... # # @property c-implemented syshook } } } set prj [processor process -sandboxed -type eval $script] set cl [@class id ::Enil] ? [list $cl eval {set :@deprecated}] 1 ? [list $cl @deprecated] 1 ? [list $cl eval {set :@c-implemented}] 0 ? [list $cl eval {set :@stashed}] 0 ? [list $cl @author] ssoberni@wu.ac.at set entity [@property id $cl class attr1] ? [list $entity eval {set :@deprecated}] 0 ? [list $entity eval {set :@stashed}] 1 ? [list $entity @stashed] 1 ? [list $entity eval {set :@c-implemented}] 0 set entity [@method id ::Enil class foo] ? [list $entity eval {set :@deprecated}] 0 ? [list $entity eval {set :@stashed}] 0 ? [list $entity eval {set :@c-implemented}] 0 ? [list $entity eval {set :@syshook}] 1 ? [list $entity @syshook] 1 set entity [@method id ::Enil class baz] ? [list $entity eval {set :@deprecated}] 0 ? [list $entity eval {set :@stashed}] 0 ? [list $entity eval {set :@c-implemented}] 1 ? [list $entity @c-implemented] 1 ? [list $entity eval {set :@syshook}] 1 ? [list $entity @syshook] 1 } } # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/accessor.test000644 000766 000024 00000004035 13746235520 017046 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package req nx::test nx::test configure -count 1 nx::test case setter-variants { nx::Class create C { :property {p1a 1} :property {p1b 1} { :public object method value=set {obj prop value} { nx::var::set $obj $prop [incr value] } } :property -accessor public {p2a 2} :property -accessor public {p2b 2} { :public object method value=set {obj prop value} { nx::var::set $obj $prop [incr value] } } :property -incremental {p3a 3} :property -incremental {p3b 3} { :public object method value=set {obj prop value} { nx::var::set $obj $prop [incr value] } } :create c1 } puts [C info method definition p1a] ? {c1 cget -p1a} 1 ? {c1 configure -p1a 1} "" puts [C info method definition p1b] ? {c1 cget -p1b} 2 ? {c1 configure -p1b 3} "" ? {c1 cget -p1b} 4 puts [C info method definition p2a] ? {c1 cget -p2a} 2 ? {c1 p2a get} 2 ? {c1 configure -p2a 2} "" ? {c1 p2a set 2} 2 ? {c1 p2a unset} "" ? {c1 cget -p2a} {can't read "p2a": no such variable} ? {c1 p2a unset} {can't unset "p2a": no such variable} ? {c1 p2a unset -nocomplain} "" puts [C info method definition p2b] ? {c1 cget -p2b} 3 ? {c1 p2b get} 3 ? {c1 configure -p2b 2} "" ? {c1 p2b set 2} 3 ? {c1 p2b unset} "" ? {c1 cget -p2b} {can't read "p2b": no such variable} puts [C info method definition p3a] ? {c1 cget -p3a} 3 ? {c1 p3a get} 3 ? {c1 configure -p3a 3} "" ? {c1 p3a get 3} {invalid argument '3', maybe too many arguments; should be "value=get ?-array? ?-notrace? /object/ /varName/"} ? {c1 p3a set 3} 3 ? {c1 p3a unset} "" ? {c1 cget -p3a} {can't read "p3a": no such variable} puts [C info method definition p3b] ? {c1 cget -p3b} 4 ? {c1 p3b get} 4 ? {c1 configure -p3b 4} "" ? {c1 p3b get} 5 ? {c1 p3b set 4} 5 ? {c1 p3b get} 5 ? {c1 p3b set 4} 5 ? {c1 p3b get} 5 ? {c1 p3b unset} "" ? {c1 cget -p3b} {can't read "p3b": no such variable} } ./nsf2.4.0/tests/linearization.test000644 000766 000024 00000012215 13462406127 020111 0ustar00neumannstaff000000 000000 package prefer latest package require nx::test proc direct-constraints {obj} { set constraints "" foreach c [$obj info precedence] { set sc [$c info superclasses] # add constraints to ensure that subclass is before superclass foreach super $sc { lappend constraints [list $c < $super] } # maintain order from superclass list if {[llength $sc] == 2} { lappend constraints [list [lindex $sc 0] < [lindex $sc 1]] } elseif {[llength $sc] > 2} { set first [lindex $sc 0] foreach class [lrange $sc 1 end] { lappend constraints [list $first < $class] set first $class } } } return $constraints } proc monotonicity-constraints {obj {linearizer ""}} { set constraints "" foreach c [$obj info precedence] { # compute for every class its own heritage and turn this into constraints if {$linearizer eq ""} { set sc [$c info heritage] } else { puts "call linearizer [list $linearizer $c]" set sc [$linearizer $c] } # maintain order from superclass list if {[llength $sc] == 2} { lappend constraints [list [lindex $sc 0] < [lindex $sc 1]] } elseif {[llength $sc] > 2} { set first [lindex $sc 0] foreach class [lrange $sc 1 end] { lappend constraints [list $first < $class] set first $class } } } return [lsort -unique $constraints] } proc local-order-constraints {obj} { # no class before its subclass set constraints "" foreach c [$obj info precedence] { # compute vor every class its subclasses set subclasses [$c info subclasses -closure] # subclasses must be before classes foreach sc $subclasses { lappend constraints [list $sc < $c] } } return [lsort -unique $constraints] } proc check-constraints {example rule kind list constraints} { #puts "check-constraints $example $rule $kind $list" foreach triple $constraints { lassign $triple x before y set larger [expr {[lsearch -exact $list $x] > [lsearch -exact $list $y]}] ? [list set _ $larger] 0 "$example $rule $kind violated $triple" } #puts "" } nx::test case boat { # # Boat example DHHM 94; # R. Ducournau, M. Habib, M. Huchard, and M.L. Mugnier. Proposal for a Monotonic Multiple Inheritance Linearization. # see: https://www2.lirmm.fr/~ducour/Publis/DHHM-oopsla94.pdf # nx::Class create boat ;# 8 nx::Class create dayboat -superclass boat ;# 6 nx::Class create wheelboat -superclass boat ;# 7 nx::Class create engineless -superclass dayboat ;# 3 nx::Class create pedalwheelboat -superclass {engineless wheelboat} ;# 2 nx::Class create smallmultihull -superclass dayboat ;# 5 nx::Class create smallcatamaran -superclass smallmultihull ;# 4 nx::Class create pedalo -superclass {pedalwheelboat smallcatamaran};# 1 dayboat public method max-distance {} {return 5m} wheelboat public method max-distance {} {return 100m} # If the linearization is known to be monotonic, the compiler can # choose to dispatch the call to max-distance directly to the method # defined on . This is known statically because no new # methods can be defined on max-distance - it is sealed - and # is always more specific than for instances # of . pedalo create o1 #? {o1 info precedence} {::pedalo ::pedalwheelboat ::engineless ::wheelboat ::smallcatamaran ::smallmultihull ::dayboat ::boat ::nx::Object} #? {o1 max-distance} 100m ? {o1 info precedence} {::pedalo ::pedalwheelboat ::engineless ::smallcatamaran ::smallmultihull ::dayboat ::wheelboat ::boat ::nx::Object} ? {o1 max-distance} 5m pedalwheelboat create pwb ? {pwb max-distance} 5m ? {pwb info precedence} "::pedalwheelboat ::engineless ::dayboat ::wheelboat ::boat ::nx::Object" smallcatamaran create smc ? {smc max-distance} 5m ? {smc info precedence} "::smallcatamaran ::smallmultihull ::dayboat ::boat ::nx::Object" set order [o1 info precedence] puts "${:case} nx: $order" check-constraints ${:case} nx direct $order [direct-constraints o1] check-constraints ${:case} nx monotonicty $order [monotonicity-constraints o1] check-constraints ${:case} nx local-order $order [local-order-constraints o1] } nx::test case boat-crash { # # This variant of the boat test case lead to problems in earlier # versions depending on the deletion order during the cleanup in the # test case. # nx::Class create boat ;# 8 nx::Class create dayboat -superclass boat ;# 6 nx::Class create wheelboat -superclass boat ;# 7 nx::Class create engineless -superclass dayboat ;# 3 nx::Class create pedalwheelboat -superclass {engineless wheelboat} ;# 2 nx::Class create smallmultihull -superclass dayboat ;# 5 nx::Class create smallcatamaran -superclass smallmultihull ;# 4 nx::Class create pedalo -superclass {pedalwheelboat smallcatamaran};# 1 ? {::smallcatamaran destroy} "" ? {::boat destroy} "" ? {::pedalo info heritage} {::pedalwheelboat ::engineless ::dayboat ::wheelboat ::nx::Object} ? {::pedalo destroy} "" ? {::pedalwheelboat info heritage} {::engineless ::dayboat ::wheelboat ::nx::Object} } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/nsf-cmd.test000644 000766 000024 00000062344 14274463622 016605 0ustar00neumannstaff000000 000000 package prefer latest package require nx::test set ::tcl86 [package vsatisfies [package req Tcl] 8.6-] nx::test case nsf-method-get-variants { # # Create a simple class # nx::Class create Person { :property name :public method foo {x:integer} {return foo-$x} :public method "string match" {pattern string} {return string-match-$string} :create p1 } # # A plain method # set ::handle [p1 info lookup method foo] ? {nsf::cmd::info args $::handle} x ? {nsf::cmd::info body $::handle} {return foo-$x} ? {nsf::cmd::info definition $::handle} {::Person public method foo x:integer {return foo-$x}} ? {nsf::cmd::info exists $::handle} 1 ? {nsf::cmd::info registrationhandle $::handle} ::nsf::classes::Person::foo ? {nsf::cmd::info definitionhandle $::handle} ::nsf::classes::Person::foo ? {nsf::cmd::info origin $::handle} "" ? {nsf::cmd::info parameter $::handle} x:integer ? {nsf::cmd::info syntax $::handle} "/x/" ? {nsf::cmd::info type $::handle} scripted ? {nsf::cmd::info precondition $::handle} "" ? {nsf::cmd::info postcondition $::handle} "" ? {nsf::cmd::info submethods $::handle} "" ? {nsf::cmd::info returns $::handle} "" # # An ensemble method # set ::handle [p1 info lookup method "string match"] ? {nsf::cmd::info args $::handle} "pattern string" ? {nsf::cmd::info body $::handle} {return string-match-$string} ? {nsf::cmd::info definition $::handle} {::Person public method {string match} {pattern string} {return string-match-$string}} ? {nsf::cmd::info exists $::handle} 1 ? {nsf::cmd::info registrationhandle $::handle} "::nsf::classes::Person::string match" ? {nsf::cmd::info definitionhandle $::handle} "::Person::slot::__string::match" ? {nsf::cmd::info origin $::handle} "" ? {nsf::cmd::info parameter $::handle} "pattern string" ? {nsf::cmd::info syntax $::handle} "/pattern/ /string/" ? {nsf::cmd::info type $::handle} scripted ? {nsf::cmd::info precondition $::handle} "" ? {nsf::cmd::info postcondition $::handle} "" ? {nsf::cmd::info submethods $::handle} "" ? {nsf::cmd::info returns $::handle} "" # alternative string reps for pattern list foreach char {\t \n \r \f \v} { ? [list p1 info lookup method "string${char}match"] [join [list {*}$::handle] $char] } # # An C-defined method inherited from nx::Object # set ::handle [p1 info lookup method configure] ? {nsf::cmd::info args $::handle} args ? {nsf::cmd::info body $::handle} "" ? {nsf::cmd::info definition $::handle} "::nx::Object public alias configure ::nsf::methods::object::configure" ? {nsf::cmd::info exists $::handle} 1 ? {nsf::cmd::info registrationhandle $::handle} ::nsf::classes::nx::Object::configure ? {nsf::cmd::info definitionhandle $::handle} ::nsf::classes::nx::Object::configure ? {nsf::cmd::info origin $::handle} ::nsf::methods::object::configure ? {nsf::cmd::info parameter $::handle} args:virtualobjectargs ? {nsf::cmd::info syntax $::handle} "?/arg .../?" ? {nsf::cmd::info type $::handle} alias ? {nsf::cmd::info precondition $::handle} "" ? {nsf::cmd::info postcondition $::handle} "" ? {nsf::cmd::info submethods $::handle} "" ? {nsf::cmd::info returns $::handle} "" # # An undefined method # set ::handle [p1 info lookup method exists] ? {nsf::cmd::info args $::handle} "" ? {nsf::cmd::info body $::handle} "" ? {nsf::cmd::info definition $::handle} "" ? {nsf::cmd::info exists $::handle} 0 ? {nsf::cmd::info registrationhandle $::handle} "" ? {nsf::cmd::info definitionhandle $::handle} "" ? {nsf::cmd::info origin $::handle} "" ? {nsf::cmd::info parameter $::handle} "" ? {nsf::cmd::info syntax $::handle} "" ? {nsf::cmd::info type $::handle} "" ? {nsf::cmd::info precondition $::handle} "" ? {nsf::cmd::info postcondition $::handle} "" ? {nsf::cmd::info submethods $::handle} "" ? {nsf::cmd::info returns $::handle} "" # # Define 2 nsf::procs: one, which requires the nsf argument parser, # and one, which does not. # nsf::proc ::foo {{-x 1} y:optional} {return $x-$y} nsf::proc ::bar {a b} {return $a-$b} # # An nsf::proc requiring nsf argument parser # set ::handle ::foo ? {nsf::cmd::info args $::handle} "x y" ? {nsf::cmd::info body $::handle} {return $x-$y} ? {nsf::cmd::info definition $::handle} {::nsf::proc ::foo {{-x 1} y:optional} {return $x-$y}} ? {nsf::cmd::info exists $::handle} 1 ? {nsf::cmd::info registrationhandle $::handle} "" ? {nsf::cmd::info definitionhandle $::handle} "" ? {nsf::cmd::info origin $::handle} "" ? {nsf::cmd::info parameter $::handle} "{-x 1} y:optional" ? {nsf::cmd::info syntax $::handle} {?-x /value/? ?/y/?} ? {nsf::cmd::info type $::handle} "nsfproc" ? {nsf::cmd::info precondition $::handle} "" ? {nsf::cmd::info postcondition $::handle} "" ? {nsf::cmd::info submethods $::handle} "" ? {nsf::cmd::info returns $::handle} "" # # define a nsf::proc with "-debug" and "-deprecated" # nsf::proc -deprecated -debug ::baz {{-x 1} y:optional} {return $x-$y} ? {nsf::cmd::info definition ::baz} {::nsf::proc -debug -deprecated ::baz {{-x 1} y:optional} {return $x-$y}} # # A simple Tcl proc # set ::handle ::bar ? {nsf::cmd::info args $::handle} "a b" ? {nsf::cmd::info body $::handle} {return $a-$b} ? {nsf::cmd::info definition $::handle} {::proc ::bar {a b} {return $a-$b}} ? {nsf::cmd::info exists $::handle} 1 ? {nsf::cmd::info registrationhandle $::handle} "" ? {nsf::cmd::info definitionhandle $::handle} "" ? {nsf::cmd::info origin $::handle} "" ? {nsf::cmd::info parameter $::handle} "a b" ? {nsf::cmd::info syntax $::handle} {/a/ /b/} ? {nsf::cmd::info type $::handle} "proc" ? {nsf::cmd::info precondition $::handle} "" ? {nsf::cmd::info postcondition $::handle} "" ? {nsf::cmd::info submethods $::handle} "" ? {nsf::cmd::info returns $::handle} "" ? {nsf::method::property ::nx::Object $handle debug 1} 1 ? {bar a b} "a-b" # # redefine bar with debug flag # nsf::proc -debug bar {a b} {return $a-$b} set ::handle ::bar ? {nsf::cmd::info args $::handle} "a b" ? {nsf::cmd::info body $::handle} {return $a-$b} ? {nsf::cmd::info definition $::handle} {::nsf::proc -debug ::bar {a b} {return $a-$b}} ? {nsf::cmd::info exists $::handle} 1 ? {nsf::cmd::info registrationhandle $::handle} "" ? {nsf::cmd::info definitionhandle $::handle} "" ? {nsf::cmd::info origin $::handle} "" ? {nsf::cmd::info parameter $::handle} "a b" ? {nsf::cmd::info syntax $::handle} {/a/ /b/} ? {nsf::cmd::info type $::handle} "nsfproc" ? {nsf::cmd::info precondition $::handle} "" ? {nsf::cmd::info postcondition $::handle} "" ? {nsf::cmd::info submethods $::handle} "" ? {nsf::cmd::info returns $::handle} "" ? {nsf::method::property ::nx::Object $handle debug 1} 1 ? {bar a b} "a-b" # # Define a proc with zero arguments # nsf::proc -debug zero {} {return 333} set ::handle ::zero ? {nsf::cmd::info args $::handle} "" ? {nsf::cmd::info body $::handle} {return 333} ? {nsf::cmd::info definition $::handle} {::nsf::proc -debug ::zero {} {return 333}} ? {nsf::cmd::info exists $::handle} 1 ? {nsf::cmd::info registrationhandle $::handle} "" ? {nsf::cmd::info definitionhandle $::handle} "" ? {nsf::cmd::info origin $::handle} "" ? {nsf::cmd::info parameter $::handle} "" ? {nsf::cmd::info syntax $::handle} {} ? {nsf::cmd::info type $::handle} "nsfproc" ? {nsf::cmd::info precondition $::handle} "" ? {nsf::cmd::info postcondition $::handle} "" ? {nsf::cmd::info submethods $::handle} "" ? {nsf::cmd::info returns $::handle} "" ? {nsf::method::property ::nx::Object $handle debug 1} 1 ? {zero} "333" # # A Tcl cmd implemented in C # set ::handle ::set ? {nsf::cmd::info args $::handle} "could not obtain parameter definition for method 'set'" ? {nsf::cmd::info body $::handle} {} ? {nsf::cmd::info definition $::handle} {} ? {nsf::cmd::info exists $::handle} 1 ? {nsf::cmd::info registrationhandle $::handle} "" ? {nsf::cmd::info definitionhandle $::handle} "" ? {nsf::cmd::info origin $::handle} "" ? {nsf::cmd::info parameter $::handle} "could not obtain parameter definition for method 'set'" ? {nsf::cmd::info syntax $::handle} "could not obtain parameter definition for method 'set'" ? {nsf::cmd::info type $::handle} "cmd" ? {nsf::cmd::info precondition $::handle} "" ? {nsf::cmd::info postcondition $::handle} "" ? {nsf::cmd::info submethods $::handle} "" ? {nsf::cmd::info returns $::handle} "" # # A Tcl cmd implemented in C with the nsf infrastructure (with parameter definitions) # set ::handle ::nsf::cmd::info ? {nsf::cmd::info args $::handle} "subcmd -context methodName pattern" ? {nsf::cmd::info body $::handle} {} ? {nsf::cmd::info definition $::handle} {} ? {nsf::cmd::info exists $::handle} 1 ? {nsf::cmd::info registrationhandle $::handle} "" ? {nsf::cmd::info definitionhandle $::handle} "" ? {nsf::cmd::info origin $::handle} "" ? {nsf::cmd::info parameter $::handle} "subcmd -context:object methodName pattern:optional" ? {nsf::cmd::info syntax $::handle} "args|body|definition|exists|registrationhandle|definitionhandle|origin|parameter|syntax|type|precondition|postcondition|submethods|returns|disassemble ?-context /object/? /methodName/ ?/pattern/?" ? {nsf::cmd::info type $::handle} "cmd" ? {nsf::cmd::info precondition $::handle} "" ? {nsf::cmd::info postcondition $::handle} "" ? {nsf::cmd::info submethods $::handle} "" ? {nsf::cmd::info returns $::handle} "" # # A plain NX object # set ::handle [nx::Object new] ? {nsf::cmd::info args $::handle} "" ? {nsf::cmd::info body $::handle} "" ? {nsf::cmd::info definition $::handle} "" ? {nsf::cmd::info exists $::handle} 0 ? {nsf::cmd::info registrationhandle $::handle} "" ? {nsf::cmd::info definitionhandle $::handle} "" ? {nsf::cmd::info origin $::handle} "" ? {nsf::cmd::info parameter $::handle} "" ? {nsf::cmd::info syntax $::handle} "" ? {nsf::cmd::info type $::handle} "cmd" ? {nsf::cmd::info precondition $::handle} "" ? {nsf::cmd::info postcondition $::handle} "" ? {nsf::cmd::info submethods $::handle} "" ? {nsf::cmd::info returns $::handle} "" # # A method handle for an ensemble # set ::handle [nx::Object info method registrationhandle "info"] ? {nsf::cmd::info args $::handle} "" ? {nsf::cmd::info body $::handle} "" ? {nsf::cmd::info definition $::handle} "::nx::Object public alias info ::nx::Object::slot::__info" ? {nsf::cmd::info exists $::handle} 1 ? {nsf::cmd::info registrationhandle $::handle} $::handle ? {nsf::cmd::info definitionhandle $::handle} $::handle ? {nsf::cmd::info origin $::handle} "::nx::Object::slot::__info" ? {nsf::cmd::info parameter $::handle} "" ? {nsf::cmd::info syntax $::handle} "" ? {nsf::cmd::info type $::handle} "alias" ? {nsf::cmd::info precondition $::handle} "" ? {nsf::cmd::info postcondition $::handle} "" ? {nsf::cmd::info submethods $::handle} [nx::Object info method submethods info] ? {nsf::cmd::info returns $::handle} "" } nx::test case nsf-method-property { ? {::nsf::object::exists ::TestMe} 0 ? {::nsf::method::property ::TestMe missing call-protected true} \ {expected object but got "::TestMe" for parameter "object"} ? {::nsf::method::forward::property ::TestMe missing verbose true} \ {expected object but got "::TestMe" for parameter "object"} nx::Class create ::TestMe ? {::nsf::method::property ::TestMe -per-object missing call-protected true} \ {cannot lookup object method 'missing' for ::TestMe} ? {::nsf::method::property ::TestMe missing call-protected true} \ {cannot lookup method 'missing' for ::TestMe} ? {::nsf::method::forward::property ::TestMe -per-object missing verbose true} \ {cannot lookup object method 'missing' for ::TestMe} ? {::nsf::method::forward::property ::TestMe missing verbose true} \ {cannot lookup method 'missing' for ::TestMe} } # # test error transparency of "-debug" option # nx::test case nsf-debug-error { nsf::proc foo {} { set exception [catch {bar} errorMsg options] if {$exception} { puts stderr O=$options puts stderr <<$::errorInfo>> set result [list $exception $errorMsg [string length $::errorInfo] $::errorCode] } else { set result "" } return $result } nsf::proc bar {} {return -code error -errorcode MyException "exception"} ? {foo} {1 exception 35 MyException} # # redefine bar with debug flag # nsf::proc -debug bar {} {return -code error -errorcode MyException "exception"} ? {foo} {1 exception 35 MyException} } # # test virtual arg resolution + filtering # nx::test case nsf-method-get-variants { nx::Class create Person { :property name :create p1 } set ::handle1 [p1 info lookup method configure] set ::handle2 [Person info lookup method create] set ::handle3 [Person info lookup method new] # # configure # ? {nsf::cmd::info syntax -context p1 $::handle1} \ "?-name /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?" ? {nsf::cmd::info parameter -context p1 $::handle1} \ "-name -object-mixins:mixinreg,slot=::nx::Object::slot::object-mixins,slotset,method=object-mixin,0..n -object-filters:filterreg,slot=::nx::Object::slot::object-filters,slotset,method=object-filter,0..n -class:class,alias,method=::nsf::methods::object::class __initblock:cmd,optional,nodashalnum" ? {nsf::cmd::info args -context p1 $::handle1} \ "name object-mixins object-filters class __initblock" # # filter on (virtual) arguments # ? {nsf::cmd::info parameter -context p1 $::handle1 na*} "-name" ? {nsf::cmd::info args -context p1 $::handle1 na*} "name" ? {nsf::cmd::info syntax -context p1 $::handle1 na*} "?-name /value/?" ? {nsf::cmd::info parameter -context p1 $::handle1 *a*} "-name -class:class,alias,method=::nsf::methods::object::class" ? {nsf::cmd::info args -context p1 $::handle1 *a*} "name class" ? {nsf::cmd::info syntax -context p1 $::handle1 *a*} "?-name /value/? ?-class /class/?" # # create # ? {nsf::cmd::info syntax -context Person $::handle2} \ "/objectName/ ?-name /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?" ? {nsf::cmd::info parameter -context Person $::handle2} \ "objectName -name -object-mixins:mixinreg,slot=::nx::Object::slot::object-mixins,slotset,method=object-mixin,0..n -object-filters:filterreg,slot=::nx::Object::slot::object-filters,slotset,method=object-filter,0..n -class:class,alias,method=::nsf::methods::object::class __initblock:cmd,optional,nodashalnum" ? {nsf::cmd::info args -context Person $::handle2} \ "objectName name object-mixins object-filters class __initblock" # # new # ? {nsf::cmd::info syntax -context Person $::handle3} \ "?-childof /value/? ?-name /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?" ? {nsf::cmd::info parameter -context Person $::handle3} \ "-childof -name -object-mixins:mixinreg,slot=::nx::Object::slot::object-mixins,slotset,method=object-mixin,0..n -object-filters:filterreg,slot=::nx::Object::slot::object-filters,slotset,method=object-filter,0..n -class:class,alias,method=::nsf::methods::object::class __initblock:cmd,optional,nodashalnum" ? {nsf::cmd::info args -context Person $::handle3} \ "-childof name object-mixins object-filters class __initblock" # # filter on (virtual) arguments # ? {nsf::cmd::info parameter -context Person $::handle3 na*} "-name" ? {nsf::cmd::info args -context Person $::handle3 na*} "name" ? {nsf::cmd::info syntax -context Person $::handle3 na*} "?-name /value/?" ? {nsf::cmd::info parameter -context Person $::handle3 *a*} "-name -class:class,alias,method=::nsf::methods::object::class" ? {nsf::cmd::info args -context Person $::handle3 *a*} "name class" ? {nsf::cmd::info syntax -context Person $::handle3 *a*} "?-name /value/? ?-class /class/?" ? {nsf::cmd::info args -context Person $::handle3 *il*} "-childof object-filters" # # Queries without context # ? {nsf::cmd::info parameter $::handle1} args:virtualobjectargs ? {nsf::cmd::info parameter $::handle2} "objectName args:virtualclassargs" ? {nsf::cmd::info parameter $::handle3} "-childof args:virtualclassargs" # # Test cases, where no instance was created yet (no internally # cached parameters) # nx::Class create Student { :property matnr } set ::handle4 [Student info lookup method create] ? {nsf::cmd::info syntax -context Student $::handle4} \ "/objectName/ ?-matnr /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?" } nx::test case nsf-config-array { ? {array exists ::nsf::config} 1 set opts [list development memcount memtrace profile dtrace assertions] foreach opt $opts { ? [list info exists ::nsf::config($opt)] 1 ? [list string is boolean $::nsf::config($opt)] 1 } } # # recursive debug calls # nx::test case nsf-debug-recursive { set ::count 0 set oldCall [nsf::cmd::info definition ::nsf::debug::call] nsf::proc -debug ::nsf::debug::call args { incr ::count #puts "MYDEBUG $args" } nsf::proc -debug foo {} {return 1} ? {foo} "1" ? {set ::count} 1 # restore original definition of ::nsf::debug::call eval $oldCall } # # recursive log calls # nx::test case nsf-log-recursive { # # First the case, where the log function calls another Tcl function # (which might be debugged) # set oldCall [nsf::cmd::info definition ::nsf::log] nsf::proc ::nsf::log args { incr ::count #puts "::nsf::log <$args> ... before foo" foo #puts "::nsf::log <$args> ... after foo" return } nsf::proc foo {} {return 1} nsf::proc bar {} {nsf::log notice hello} # # "foo" calls no nsf::log, but "bar" calls it once # set ::count 0 ? {foo} "1" ? {set ::count} 0 set ::count 0 ? {bar} "" ? {set ::count} 1 # # now we add the debug flag to foo, therefore, "foo" will call # "nsf::log", which might become an infinite recursion loop. # nsf::proc -debug foo {} {return 1} # # "foo" is has now "-debug" set, therefore, it calls the log function # set ::count 0 ? {foo} "1" ? {set ::count} 2 # # "bar" calls "log", which in turn calls a debugged function # set ::count 0 ? {bar} "" ? {set ::count} 3 # restore original definition of ::nsf::log eval $oldCall } nx::test case nsf-proc-rename-delete { namespace eval ::ns1 {} ? {info commands ::ns1::foo} "" ? {info commands ::nsf::procs::ns1::foo} "" ? {info procs ::ns1::foo} "" ? {info procs ::nsf::procs::ns1::foo} "" if {${::tcl86}} { ? {::ns1::foo -x ok} {TCL LOOKUP COMMAND ::ns1::foo} {invalid command name "::ns1::foo"} } else { ? {::ns1::foo -x ok} {invalid command name "::ns1::foo"} } nsf::proc ::ns1::foo { {-x:required} } { return 1-$x } ? {info commands ::ns1::foo} "::ns1::foo" ? {info commands ::nsf::procs::ns1::foo} "::nsf::procs::ns1::foo" ? {info procs ::ns1::foo} "" ? {info procs ::nsf::procs::ns1::foo} "::nsf::procs::ns1::foo" ? {::ns1::foo -x ok} "1-ok" rename ::ns1::foo "" ? {info commands ::ns1::foo} "" ? {info commands ::nsf::procs::ns1::foo} "" ? {info procs ::ns1::foo} "" ? {info procs ::nsf::procs::ns1::foo} "" if {${::tcl86}} { ? {::ns1::foo -x ok} {TCL LOOKUP COMMAND ::ns1::foo} {invalid command name "::ns1::foo"} } else { ? {::ns1::foo -x ok} {invalid command name "::ns1::foo"} } namespace eval ::ns1 {} } nx::test case nsf-proc-ns-delete { namespace eval ::ns1 {} ? {info commands ::ns1::foo} "" ? {info commands ::nsf::procs::ns1::foo} "" ? {info procs ::ns1::foo} "" ? {info procs ::nsf::procs::ns1::foo} "" if {${::tcl86}} { ? {::ns1::foo -x ok} {TCL LOOKUP COMMAND ::ns1::foo} {invalid command name "::ns1::foo"} } else { ? {::ns1::foo -x ok} {invalid command name "::ns1::foo"} } nsf::proc ::ns1::foo { {-x:required} } { return 1-$x } ? {info commands ::ns1::foo} "::ns1::foo" ? {info commands ::nsf::procs::ns1::foo} "::nsf::procs::ns1::foo" ? {info procs ::ns1::foo} "" ? {info procs ::nsf::procs::ns1::foo} "::nsf::procs::ns1::foo" ? {::ns1::foo -x ok} "1-ok" namespace delete ::ns1 ? {info commands ::ns1::foo} "" ? {info commands ::nsf::procs::ns1::foo} "" ? {info procs ::ns1::foo} "" ? {info procs ::nsf::procs::ns1::foo} "" if {${::tcl86}} { ? {::ns1::foo -x ok} {TCL LOOKUP COMMAND ::ns1::foo} {invalid command name "::ns1::foo"} } else { ? {::ns1::foo -x ok} {invalid command name "::ns1::foo"} } } nx::test case nsf-proc-rename-redefine { namespace eval ::ns1 {} nsf::proc ns1::foo { {-x:required} } { return 1-$x } ? {ns1::foo -x ok} 1-ok rename ns1::foo ns1::foo.orig nsf::proc ns1::foo { {-x:required} } { return 2-$x } ? {ns1::foo -x ok} 2-ok namespace delete ::ns1 } nx::test case nsf-proc-rename-redefine-call { namespace eval ::ns1 {} nsf::proc ns1::foo { {-x:required} } { return 1-$x } ? {ns1::foo -x ok} 1-ok rename ns1::foo ns1::foo.orig nsf::proc ns1::foo { {-x:required} } { return 2-$x } ? {ns1::foo -x ok} 2-ok ? {ns1::foo.orig -x ok} 1-ok; namespace delete ::ns1 } nx::test case nsf-proc-backstage-rename { namespace eval ::ns1 {} ? {info commands ::ns1::foo} "" ? {info commands ::nsf::procs::ns1::foo} "" ? {info procs ::ns1::foo} "" ? {info procs ::nsf::procs::ns1::foo} "" if {${::tcl86}} { ? {::ns1::foo -x ok} {TCL LOOKUP COMMAND ::ns1::foo} {invalid command name "::ns1::foo"} } else { ? {::ns1::foo -x ok} {invalid command name "::ns1::foo"} } nsf::proc ::ns1::foo { {-x:required} } { return 1-$x } ? {info commands ::ns1::foo} "::ns1::foo" ? {info commands ::nsf::procs::ns1::foo} "::nsf::procs::ns1::foo" ? {info procs ::ns1::foo} "" ? {info procs ::nsf::procs::ns1::foo} "::nsf::procs::ns1::foo" ? {::ns1::foo -x ok} "1-ok" rename ::nsf::procs::ns1::foo "" ? {info commands ::ns1::foo} "::ns1::foo" ? {info commands ::nsf::procs::ns1::foo} "" ? {info procs ::ns1::foo} "" ? {info procs ::nsf::procs::ns1::foo} "" ? {::ns1::foo -x ok} {cannot lookup command '::nsf::procs::ns1::foo'} rename ::ns1::foo "" ? {info commands ::ns1::foo} "" ? {info commands ::nsf::procs::ns1::foo} "" ? {info procs ::ns1::foo} "" ? {info procs ::nsf::procs::ns1::foo} "" if {${::tcl86}} { ? {::ns1::foo -x ok} {TCL LOOKUP COMMAND ::ns1::foo} {invalid command name "::ns1::foo"} } else { ? {::ns1::foo -x ok} {invalid command name "::ns1::foo"} } namespace eval ::ns1 {} } nx::test case nsf-proc-backstage-rename-2 { namespace eval ::ns1 {} ? {info commands ::ns1::foo} "" ? {info commands ::nsf::procs::ns1::foo} "" ? {info procs ::ns1::foo} "" ? {info procs ::nsf::procs::ns1::foo} "" if {${::tcl86}} { ? {::ns1::foo -x ok} {TCL LOOKUP COMMAND ::ns1::foo} {invalid command name "::ns1::foo"} } else { ? {::ns1::foo -x ok} {invalid command name "::ns1::foo"} } nsf::proc ::ns1::foo { {-x:required} } { return 1-$x } ? {info commands ::ns1::foo} "::ns1::foo" ? {info commands ::nsf::procs::ns1::foo} "::nsf::procs::ns1::foo" ? {info procs ::ns1::foo} "" ? {info procs ::nsf::procs::ns1::foo} "::nsf::procs::ns1::foo" ? {::ns1::foo -x ok} "1-ok" rename ::nsf::procs::ns1::foo "" nx::Object create ::nsf::procs::ns1::foo ? {info commands ::ns1::foo} "::ns1::foo" ? {info commands ::nsf::procs::ns1::foo} "::nsf::procs::ns1::foo" ? {info procs ::ns1::foo} "" ? {info procs ::nsf::procs::ns1::foo} "" ? {::ns1::foo -x ok} \ {command '::nsf::procs::ns1::foo' is not a proc} rename ::ns1::foo "" ? {info commands ::ns1::foo} "" ? {info commands ::nsf::procs::ns1::foo} "::nsf::procs::ns1::foo" ? {info procs ::ns1::foo} "" ? {info procs ::nsf::procs::ns1::foo} "" if {${::tcl86}} { ? {::ns1::foo -x ok} {TCL LOOKUP COMMAND ::ns1::foo} {invalid command name "::ns1::foo"} } else { ? {::ns1::foo -x ok} {invalid command name "::ns1::foo"} } namespace eval ::ns1 {} rename ::nsf::procs::ns1::foo "" } nx::test case nsf-proc-preexisting { namespace eval ::ns1 {} ? {info commands ::ns1::foo} "" ? {info commands ::nsf::procs::ns1::foo} "" proc ::nsf::procs::ns1::foo {x} { return 0-$x} ? {info commands ::ns1::foo} "" ? {info commands ::nsf::procs::ns1::foo} "::nsf::procs::ns1::foo" ? {nsf::proc ::ns1::foo { {-x:required} } { return 1-$x }} "" ? {::ns1::foo -x ok} "1-ok" namespace delete ::ns1 } nx::test case nsf-proc-preexisting-rename { namespace eval ::ns1 {} ? {info commands ::ns1::foo} "" ? {info commands ::nsf::procs::ns1::foo} "" proc ::nsf::procs::ns1::foo.orig {x} { return 0-$x} ? {info commands ::ns1::foo.orig} "" ? {info commands ::nsf::procs::ns1::foo.orig} "::nsf::procs::ns1::foo.orig" ? {nsf::proc ::ns1::foo { {-x:required} } { return 1-$x }} "" ? {::ns1::foo -x ok} "1-ok" if {${::tcl86}} { ? {rename ns1::foo ns1::foo.orig} {TCL OPERATION RENAME TARGET_EXISTS} {can't rename to "::nsf::procs::ns1::foo.orig": command already exists} } else { ? {rename ns1::foo ns1::foo.orig} {can't rename to "::nsf::procs::ns1::foo.orig": command already exists} } namespace delete ::ns1 } # - TO-DO: interp hide/expose # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/shells.test000644 000766 000024 00000010640 13712264152 016531 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx package require nx::test ## for now, we do not have scripted shells for Windows environments ## without a bash-like shell, so ... if {$tcl_platform(platform) eq "windows"} { return } # # When the compiler flags modify the console output, come of the shell # tests below will fail. One should introduce more detailed test # conditions like in tcl-test to deal with the more precisely. For the # time being, we skip here the full test when nsf was compiled with # memcount activated. # if {$::nsf::config(memcount) == 1} { return } nx::test case nxsh { set rootDir [file join {*}[lrange [file split [file normalize [info script]]] 0 end-2]] set nxsh [file join $rootDir nxsh] set run {puts $argc-[join $argv -]} ? [list file exists $nxsh] 1 ? [list file executable $nxsh] 1 ## stdin is in interactive mode (just a smoke test) ? [list exec $nxsh << "$run; exit"] "% 0-" ## stdin is ignored proc getFirstLine {cmd} { catch [list uplevel 1 $cmd] res opts set lines [split $res \n] return [string trim [lindex $lines 0]] } ? [list getFirstLine [list exec $nxsh NXSCRIPT.tcl << "$run; exit"]] \ "couldn't read file \"NXSCRIPT.tcl\": no such file or directory" ## noninteractive mode (-c) ? [list exec $nxsh -c "$run" NXSCRIPT.tcl] \ "1-NXSCRIPT.tcl" ? [list exec $nxsh -c << $run] "0-" ? [list exec $nxsh -c $run a b c] "3-a-b-c" set tmpfile [file join [::nsf::tmpdir] [pid]] ? [list getFirstLine [list exec $nxsh $tmpfile]] "couldn't read file \"$tmpfile\": no such file or directory" ? [list getFirstLine [list exec $nxsh $tmpfile a b c]] "couldn't read file \"$tmpfile\": no such file or directory" set ch [open $tmpfile w+] ? [list file exists $tmpfile] 1 ? [list file writable $tmpfile] 1 puts $ch $run catch {close $ch} ? [list exec $nxsh $tmpfile] "0-" ? [list exec $nxsh $tmpfile -c "yyy" a b c] "5--c-yyy-a-b-c" file delete -force $tmpfile # exit and exit codes ? [list exec [info nameofexecutable] << "exit 0"] "" ? [list exec [info nameofexecutable] << "exit 1"] "child process exited abnormally" ? [list exec [info nameofexecutable] << "package req nx;exit 0"] "" ? [list exec [info nameofexecutable] << "package req nx;exit 1"] "child process exited abnormally" ? [list exec -ignorestderr [info nameofexecutable] << "package req nx;nx::Object new {exit 0}"] "" ? [list exec -ignorestderr [info nameofexecutable] << "package req nx;nx::Object new {exit 1}"] "child process exited abnormally" ? [list exec $nxsh -c "exit 0"] "" ? [list exec $nxsh -c "exit 1"] "child process exited abnormally" ? [list exec $nxsh -c "exit 2"] "child process exited abnormally" ? [list exec $nxsh -c "exit 5"] "child process exited abnormally" ? [list catch [list exec $nxsh -c "exit 5"] ::res ::opts] "1" ? {set ::res} "child process exited abnormally" ? {lindex [dict get $::opts -errorcode] end} "5" unset ::res; unset ::opts ? [list exec $nxsh -c << "exit 0"] "" ? [list exec $nxsh -c << "exit 1"] "child process exited abnormally" ? [list exec $nxsh -c << "catch {exit 1}"] "child process exited abnormally" ? [list exec $nxsh -c << "catch {nx::Object eval {exit 1}}"] "child process exited abnormally" # just 8.6 or newer if {[info command yield] eq ""} return ? [list exec $nxsh -c << [list nx::Object eval {try { exit 6 } \ on break {} {;} \ on return {} {;} \ on error {} {;} \ finally {puts finalized}}]] "child process exited abnormally" ? [list exec $nxsh -c << [list nx::Object eval {try { error } \ on break {} {;} \ on return {} {;} \ on error {} {;} \ finally {puts finalized}}]] "finalized" ## avoid pollution of global namespace ## set tclsh [info nameofexecutable] ## set gvars1 [exec $tclsh << {puts [info vars]}] ## set gvars2 [exec $nxsh -c << {puts [info vars]}] ## ? [list expr [list [lsort $gvars1] eq [lsort $gvars2]]] 1 } puts exec=[info nameofexecutable] # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/method-require.test000644 000766 000024 00000010662 13462406127 020177 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx package require nx::test nx::test configure -count 10 nx::test case method-require { # # A few method-provides # # Some provides could be in e.g. nx.tcl, some could be loaded via # package require. We could as well think about an auto-indexer # producing these.... # nsf::method::provide append {::nsf::method::alias append -frame object ::append} nsf::method::provide lappend {::nsf::method::alias lappend -frame object ::lappend} nsf::method::provide set {::nsf::method::alias set -frame object ::set} nsf::method::provide tcl::set {::nsf::method::alias set -frame object ::set} nsf::method::provide exists {::nsf::method::alias exists ::nsf::methods::object::exists} nsf::method::provide foo {::nsf::method::create foo {x y} {return x=$x,y=$y}} # # Provide an example for an application defined method provider # nsf::proc ::get_mixin {object -per-object:switch mixinClass methodName} { ::nsf::mixin $object -per-object=${per-object} $mixinClass return [$mixinClass info method registrationhandle $methodName] } # use the method provider nsf::method::provide x {::get_mixin ::MIX x} { # here could be as well a package require, etc. ::nx::Class create ::MIX {:public method x {} {return x}} } # # Lets try it out: # nx::Class create C { :require method set :require method exists # required names can be different from registered names; if there # are multiple set methods, we could point to the right one ? [list [self] require method tcl::set] "::nsf::classes::C::set" # object methods ? [list [self] require object method lappend] "::C::lappend" # a scripted object method ? [list [self] require object method foo] "::C::foo" ? [list [self] require object method x] "::nsf::classes::MIX::x" ? [list [self] require method x] "::nsf::classes::MIX::x" # looks as well ok: ? [list [self] require namespace] "" } # # Try protected and public # ? {C require public method lappend} ::nsf::classes::C::lappend ? {::nsf::method::property C lappend call-protected} 0 ? {C require protected method lappend} ::nsf::classes::C::lappend ? {::nsf::method::property C lappend call-protected} 1 ? {C require protected object method set} ::C::set ? {::nsf::method::property C ::C::set call-protected} 1 # # call these methods # C create c1 ? {c1 set x 100} 100 ? {c1 exists x} 1 ? {C lappend some_list e1 e2} "e1 e2" ? {C foo 1 2} x=1,y=2 ? {C x} x # # Definitions directly on object # Object create o1 ? {o1 require object method set} ::o1::set ? {o1 require object method x} ::nsf::classes::MIX::x ? {o1 require public object method lappend} ::o1::lappend ? {::nsf::method::property o1 lappend call-protected} 0 ? {o1 require protected object method lappend} ::o1::lappend ? {::nsf::method::property o1 lappend call-protected} 1 } nx::test case parent-require { ::nx::Class public object method __unknown {name} { #puts stderr "***** __unknown called with <$name>" ::nx::Object create $name } ::nsf::object::unknown::add nx {::nx::Class __unknown} nx::Class create C ? {C create ::o::o} "::o::o" ? {::o info class} "::nx::Object" ? {::o::o info class} "::C" ? {::nx::Object create ::a::b} "::a::b" ? {::a info class} "::nx::Object" ? {::a::b info class} "::nx::Object" ? {C create ::1::2::3::4} "::1::2::3::4" ? {::1 info class} "::nx::Object" ? {::1::2 info class} "::nx::Object" ? {::1::2::3 info class} "::nx::Object" ? {::1::2::3::4 info class} "::C" } # # Test what happens if we try to redefine a "nonexistent" protected method. # nx::test case method-redefine-nonexistent { ? {nx::Class public method __alloc arg {return 1}} {refuse to overwrite protected method __alloc on ::nx::Class} ? {nx::Class public method __dealloc arg {return 1}} {refuse to overwrite protected method __dealloc on ::nx::Class} ? {nx::Class public method __recreate arg {return 1}} {refuse to overwrite protected method __recreate on ::nx::Class} } # # Test what happens if a class-specific method is registered and # called on an object. # nx::test case method-require-scope { nx::Object create o ::nsf::method::require o __alloc ? {o __alloc x} {method __alloc not dispatched on valid class} } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/varresolution.test000644 000766 000024 00000112266 13462406127 020164 0ustar00neumannstaff000000 000000 # -*- Tcl -*- # # testing var resolution # package prefer latest package require nx package require nx::test ::nx::configure defaultMethodCallProtection false ::nsf::method::alias ::nx::Object objeval -frame object ::eval ::nsf::method::alias ::nx::Object array -frame object ::array ::nsf::method::alias ::nx::Object lappend -frame object ::lappend ::nsf::method::alias ::nx::Object incr -frame object ::incr ::nsf::method::alias ::nx::Object set -frame object ::set ::nsf::method::alias ::nx::Object unset -frame object ::unset ########################################### # Basic tests for var resolution under # per-object namespaces ... ########################################### nx::test case globals set ::globalVar 1 nx::Object create o o require namespace ? {o info vars} "" ? {info exists ::globalVar} 1 ? {set ::globalVar} 1 ? {o eval {info exists :globalVar}} 0 ? {o array exists globalVar} 0 o array set globalVar {1 2} ? {o eval {info exists :globalVar}} 1 ? {o info vars} globalVar ? {o array exists globalVar} 1 ? {set ::globalVar} 1 ? {o set globalVar(1)} 2 o destroy unset ::globalVar ########################################### # scopes ########################################### nx::test case scopes nx::Object create o nx::Object create o2 {set :i 1} o objeval { # require a namespace within an objscoped frame; it is necessary to replace # vartables on the stack :require namespace global g ::nsf::var::import o2 i set x 1 set :y 2 set ::z 3 set [current]::X 4 set g 1 set :a(:b) 1 set :a(::c) 1 } ? {::nsf::var::import o2 j} \ "importvar cannot import variable 'j' into method scope; not called from a method frame" o object method foo {} {::nsf::var::import [current] :a} ? {o foo} "variable name \":a\" must not contain namespace separator or colon prefix" o object method foo {} {::nsf::var::import [current] ::a} ? {o foo} "variable name \"::a\" must not contain namespace separator or colon prefix" o object method foo {} {::nsf::var::import [current] a(:b)} ? {o foo} "can't make instance variable a(:b) on ::o: Variable cannot be an element in an array; use e.g. an alias." o object method foo {} {::nsf::var::import [current] {a(:b) ab}} ? {o foo} "" o object method foo {} {::nsf::var::exists [current] ::a} ? {o foo} "variable name \"::a\" must not contain namespace separator or colon prefix" o object method foo {} {::nsf::var::exists [current] a(:b)} ? {o foo} 1 o object method foo {} {::nsf::var::exists [current] a(::c)} ? {o foo} 1 set ::o::Y 5 ? {info vars ::x} "" ? {info exists ::z} 1 ? {set ::z} 3 ? {lsort [o info vars]} {X Y a g i x y} ? {o eval {info exists :x}} 1 ? {o eval {info exists :y}} 1 ? {o eval {info exists :z}} 0 ? {o eval {info exists :X}} 1 ? {o eval {info exists :Y}} 1 ? {o set y} 2 ? {set ::g} 1 o destroy o2 destroy unset ::z unset ::g # like the example above, but with the non-leaf initcmd nx::Object create o2 {set :i 1} nx::Object create o { :require namespace global g ::nsf::var::import o2 i set x 1 set :y 2 set ::z 3 set [current]::X 4 set g 1 } set ::o::Y 5 ? {info vars ::x} "" ? {info exists ::z} 1 ? {set ::z} 3 ? {lsort [o info vars]} {X Y y} ? {o eval {info exists :x}} 0 ? {o eval {info exists :y}} 1 ? {o eval {info exists :z}} 0 ? {o eval {info exists :X}} 1 ? {o eval {info exists :Y}} 1 ? {o set y} 2 ? {set ::g} 1 o destroy o2 destroy unset ::z unset ::g foreach v {::x ::z ::g} {unset -nocomplain $v} ########################################### # var exists tests ########################################### nx::test case exists { set y 1 nx::Object create o {set :x 1} o object method foo {} {info exists :x} o object method bar {} {info exists :y} ? {o eval {info exists :x}} 1 ? {o eval {info exists :y}} 0 ? {o eval {info exists x}} 0 ? {o foo} 1 ? {o bar} 0 ? {::nx::var exists o x} 1 ? {::nx::var exists o y} 0 ? {::nx::var exists o :x} {variable name ":x" must not contain namespace separator or colon prefix} ? {::nx::var exists o :y} {variable name ":y" must not contain namespace separator or colon prefix} ? {::nx::var set o y 2} 2 ? {::nx::var exists o y} 1 ? {::nx::var set o :y 2} {variable name ":y" must not contain namespace separator or colon prefix} } ########################################### # mix & match namespace and object interfaces ########################################### nx::test case namespaces nx::Object create o o require namespace o set x 1 ? {namespace eval ::o {set x}} 1 ? {::o set x} 1 ? {namespace eval ::o {set x 3}} 3 ? {::o set x} 3 ? {namespace eval ::o {info exists x}} 1 ? {::o unset x} "" ? {::nsf::var::exists o x} 0 ? {o eval {info exists :x}} 0 ? {info vars ::x} "" ? {namespace eval ::o {info exists x}} 0 o lappend y 3 ? {namespace eval ::o {llength y}} 1 ? {namespace eval ::o {unset y}} "" ? {o eval {info exists :y}} 0 o destroy ########################################### # array-specific tests ########################################### nx::test case namespaces-array nx::Object create o o require namespace ? {o array exists a} 0 ? {namespace eval ::o array exists a} 0 o array set a {1 2 3 4 5 6} ? {o array exists a} 1 ? {namespace eval ::o array exists a} 1 ? {namespace eval ::o array names a} [::o array names a] ? {namespace eval ::o array size a} [::o array size a] ? {o set a(1) 7} 7 ? {namespace eval ::o array get a 1} {1 7} ? {namespace eval ::o set a(1) 2} 2 ? {o array get a 1} {1 2} ? {::o unset a} "" ? {::o array unset a} "" ? {o array exists a} 0 ? {namespace eval ::o array exists a} 0 o destroy ########################################### # tests on namespace-qualified var names ########################################### nx::test case namespaced-var-names nx::Object create o o require namespace nx::Object create o::oo o::oo require namespace ? {::o set ::x 1} 1 ? {info exists ::x} [set ::x] ? {catch {unset ::x}} 0 ? {::o set ::o::x 1} 1 ? {o eval {info exists :x}} [::o set ::o::x] ? {namespace eval ::o unset x} "" ? {o eval {info exists x}} 0 # Note, relatively qualified var names (not prefixed with ::*) # are always resolved relative to the per-object namespace ? {catch {::o set o::x 1} msg} 1 ? {::o set oo::x 1} 1 ? {o::oo eval {info exists :x}} [::o set oo::x] ? {o unset oo::x} "" ? {o::oo eval {info exists :x}} 0 o destroy ########################################### # tests on namespace-qualified on objects # without namespaces ########################################### # the tests below fail. We could consider # to require namespaces on the fly in the future #nx::Object create o #? {::o set ::o::x 1} 1 #? {o exists x} [::o set ::o::x] #? {namespace eval ::o unset x} "" #? {o exists x} 0 #? {::o set o::x 1} 1 #? {o exists x} [::o set o::x] #? {namespace eval ::o unset x} "" #? {o exists x} 0 #o destroy ############################################### # tests for the compiled var resolver on Object ############################################### nx::test case var-resolver-object nx::Object create o o object method foo {x} {set :y 2; return ${:x},${:y}} o object method bar {} {return ${:x},${:y}} o set x 1 ? {o foo 1} "1,2" "create var y and fetch var x" ? {o bar} "1,2" "fetch two instance variables" ? {o info vars} "x y" # recreate object, check var caching; # we have to recreate bar, so no problem nx::Object create o o set x 1 o object method bar {} {return ${:x},${:y}} ? {catch {o bar}} "1" "compiled var y should not exist" o destroy ############################################### # tests for the compiled var resolver on Class ############################################### nx::test case var-resolver-class nx::Class create C {:property {x 1}} C create c1 C method foo {x} {set :y 2; return ${:x},${:y}} C method bar {} {return ${:x},${:y}} ? {c1 info vars} "x" ? {c1 foo 1} "1,2" "create var y and fetch var x" ? {c1 bar} "1,2" "fetch two instance variables" ? {c1 info vars} "x y" # recreate object, check var caching; # we do not have to recreate bar, compiled var persists, # change must be detected C create c1 #puts stderr "after recreate" ? {catch {c1 bar}} "1" "compiled var y should not exist" ? {c1 info vars} "x" c1 destroy C destroy ############################################### # tests for the compiled var resolver with eval ############################################### nx::test case compiled-var-resolver nx::Class create C {:property {x 1}} C create c1 C method foo {x} { set :y 2; eval "set :z 3" return ${:x},${:y},${:z} } ? {c1 info vars} "x" ? {c1 foo 1} "1,2,3" ? {c1 info vars} "x y z" C create c1 ? {c1 info vars} "x" C method foo {x} { set cmd set lappend cmd :y lappend cmd 100 eval $cmd return $x,${:y} } C method bar {} {return [info exists :x],[info exists :y]} C method bar2 {} {if {[info exists :x]} {set :x 1000}; return [info exists :x],[info exists :y]} ? {c1 foo 1} "1,100" ? {c1 bar} "1,1" ? {c1 bar2} "1,1" c1 unset x ? {c1 bar2} "0,1" c1 destroy C destroy ############################################### # tests with array ############################################### nx::Class create C C create c1 C method foo {} { array set :a {a 1 b 2 c 3} set :z 100 } ? {c1 info vars} "" c1 foo ? {lsort [c1 info vars]} {a z} ############################################### # tests for the var resolver ############################################### nx::test case var-resolver nx::Class create C C method bar0 {} {return ${:x}} C method bar1 {} {set a ${:x}; return [info exists :x],[info exists :y]} C method bar2 {} {return [info exists :x],[info exists :y]} C method foo {} { array set :a {a 1 b 2 c 3} set :z 100 } C create c1 c1 set x 100 ? {c1 bar0} 100 "single compiled local" ? {c1 bar1} 1,0 "lookup one compiled var and one non-existing" ? {c1 bar2} 1,0 "lookup one non compiled var and one non-existing" C create c2 ? {c2 bar2} 0,0 "lookup two one non-existing, first access to varTable" c1 foo ? {lsort [c1 info vars]} "a x z" "array variable set via resolver" ? {lsort [c1 array names a]} "a b c" "array looks ok" ############################################### # first tests for the cmd resolver ############################################### nx::Class create C C method bar {args} { #puts stderr "[current] bar called with [list $args]" return $args } C forward test %self bar C method foo {} { # this works lappend :r [:bar x 1] lappend :r [:test a b c] # these kind of works, but vars are nowhere.... :set x 1 :incr x 1 :incr x 1 return [lappend :r ${:x}] } C create c3 ? {c3 foo} "{x 1} {a b c} 3" ############################################### # refined tests for the var resolver under # Tcl namespaces parallelling XOTcl objects # (! not declared through require namespace !) # e.g., "info has namespace" reports 0 rather # than 1 as under "require namespace" ############################################### set ::w 1 array set ::tmpArray {key value} nx::Class create ::C ::nsf::method::alias ::C Set -frame object ::set ::nsf::method::alias ::C Unset -frame object ::unset ::C create ::c namespace eval ::c {} ? {namespace exists ::c} 1 ? {::nsf::object::exists ::c} 1 ? {::c info has namespace} 0 ? {::c Set w 2; expr {[::c Set w] == $::w}} 0 ? {::c Unset w; info exists ::w} 1 ? {::c Set tmpArray(key) value2; expr {[::c Set tmpArray(key)] == $::tmpArray(key)}} 0 ? {::c Unset tmpArray(key); info exists ::tmpArray(key)} 1 ::c destroy ::C destroy unset ::w unset ::tmpArray ################################################## # Testing aliases for eval with and without # -varscope flags and with a # required namespace and without ################################################## nx::test case eval-variants ::nsf::method::alias ::nx::Object objeval -frame object ::eval ::nsf::method::alias ::nx::Object softeval -frame method ::eval ::nsf::method::alias ::nx::Object softeval2 ::eval set G 1 nx::Object create o { set xxx 1 set :x 1 ? {info exists G} 1 } ? {o eval {info exists :x}} 1 ? {o eval {info exists :xxx}} 0 ? {info exists ::xxx} 0 unset -nocomplain ::xxx # eval does an objcope, all vars are instance variables; can access preexisting global vars o objeval { set aaa 1 set :a 1 ? {info exists G} 1 } ? {o eval {info exists :a}} 1 ? {o eval {info exists :aaa}} 1 ? {info exists ::aaa} 0 unset -nocomplain ::aaa # softeval (with -nonleaf) behaves like the initcmd and sets just # instance variables via resolver. o softeval { set bbb 1 set :b 1 ? {info exists G} 1 } ? {o eval {info exists :b}} 1 ? {o eval {info exists :bbb}} 0 ? {info vars ::bbb} "" unset -nocomplain ::bbb # softeval2 never sets instance variables o softeval2 { set zzz 1 set :z 1 ? {info exists G} 1 } ? {o eval {info exists :z}} 0 ? {o eval {info exists :zzz}} 0 ? {info vars ::zzz} ::zzz unset -nocomplain ::zzz ? {lsort [o info vars]} "a aaa b x" o destroy # now with an object namespace nx::Object create o o require namespace # objeval does an objcope, all vars are instance variables o objeval { set ccc 1 set :c 1 } ? {o eval {info exists :c}} 1 ? {o eval {info exists :ccc}} 1 # softeval behaves like the creation initcmd (just set dot vars) o softeval { set ddd 1 set :d 1 } ? {o eval {info exists :d}} 1 ? {o eval {info exists :ddd}} 0 # softeval2 never sets variables o softeval2 { set zzz 1 set :z 1 } ? {o eval {info exists :z}} 0 ? {o eval {info exists :zzz}} 0 ? {lsort [o info vars]} "c ccc d" o destroy ################################################################# # The same as above, but with some global vars. The global vars # should not influence the behavior on instance variables ################################################################# nx::test case with-global-vars foreach var {.x x xxx :a a aaa :b b bbb :c c ccc :d d ddd :z z zzz} {set $var 1} nx::Object create o { set xxx 1 set :x 1 } ? {o eval {info exists :x}} 1 ? {o eval {info exists :xxx}} 0 # objeval does an objcope, all vars are instance variables o objeval { set aaa 1 set :a 1 } ? {o eval {info exists :a}} 1 ? {o eval {info exists :aaa}} 1 # softeval should behave like the creation initcmd (just set dot vars) o softeval { set bbb 1 set :b 1 } ? {o eval {info exists :b}} 1 ? {o eval {info exists :bbb}} 0 # softeval2 never sets instance variables o softeval2 { set zzz 1 set :z 1 } ? {o eval {info exists :z}} 0 ? {o eval {info exists :zzz}} 0 ? {lsort [o info vars]} "a aaa b x" o destroy # now with namespace nx::Object create o o require namespace # eval does an objcope, all vars are instance variables o objeval { set ccc 1 set :c 1 } ? {o eval {info exists :c}} 1 ? {o eval {info exists :ccc}} 1 # softeval2 should behave like the creation initcmd (just set dot vars) o softeval { set ddd 1 set :d 1 } ? {o eval {info exists :d}} 1 ? {o eval {info exists :ddd}} 0 # softeval2 never sets variables o softeval2 { set zzz 1 set :z 1 } ? {o eval {info exists :z}} 0 ? {o eval {info exists :zzz}} 0 ? {lsort [o info vars]} "c ccc d" o destroy ################################################## # Test with proc scopes ################################################## nx::test case proc-scopes ::nsf::method::alias ::nx::Object objscoped-eval -frame object ::eval ::nsf::method::alias ::nx::Object nonleaf-eval -frame method ::eval ::nsf::method::alias ::nx::Object plain-eval ::eval proc foo-via-initcmd {} { foreach v {x xxx} {unset -nocomplain ::$v} set p 1 nx::Object create o { set xxx 1 set :x 1 set ::result G=[info exists G],p=[info exists p] } return [o eval {info exists :x}]-[o eval {info exists :xxx}]-[info exists x]-[info exists xxx]-[info exists ::x]-[info exists ::xxx]-$::result } proc foo {type} { foreach v {x xxx} {unset -nocomplain ::$v} set p 1 nx::Object create o o $type { set xxx 1 set :x 1 set ::result G=[info exists G],p=[info exists p] } return [o eval {info exists :x}]-[o eval {info exists :xxx}]-[info exists x]-[info exists xxx]-[info exists ::x]-[info exists ::xxx]-$::result } proc foo-tcl {what} { foreach v {x xxx} {unset -nocomplain ::$v} set p 1 set body { set xxx 1 set :x 1 set ::result G=[info exists G],p=[info exists p] } switch $what { eval {eval $body} ns-eval {namespace eval [namespace current] $body} } return [o eval {info exists :x}]-[o eval {info exists :xxx}]-[info exists x]-[info exists xxx]-[info exists ::x]-[info exists ::xxx]-$::result } set G 1 ? {foo-via-initcmd} 1-0-0-0-0-0-G=0,p=0 ? {foo nonleaf-eval} 1-0-0-0-0-0-G=0,p=0 ? {foo objscoped-eval} 1-1-0-0-0-0-G=0,p=0 ? {foo plain-eval} 0-0-0-1-0-0-G=0,p=1 ? {foo-tcl eval} 0-0-0-1-0-0-G=0,p=1 ? {foo-tcl ns-eval} 0-0-0-0-0-1-G=1,p=0 ################################################## # dotCmd tests ################################################## nx::test case dotcmd set C 0 proc bar {} {incr ::C} nx::Class create Foo { :method init {} {set :c 0} :method callDot1 {} {:bar} :method callDot2 {} {:bar} :method callDot3 {} {:bar; ::bar; :bar} :method bar {} {incr :c} } Foo create f1 f1 callDot1 ? {set ::C} 0 ? {f1 eval {set :c}} 1 # call via callback after 1 {f1 callDot2} after 10 {set ::X 1} vwait X # # Test vwait with colon variable and vwait method # nx::Object create o { set :x 0 :public object method foo {} {incr :x} :public object method vwait {varName} { if {[regexp {:[^:]*} $varName]} { error "invalid varName '$varName'; only plain or fully qualified variable names allowed" } if {[string match ::* $varName]} { ::vwait $varName } else { ::vwait :$varName } } # # Tcl vwait command with instance variable # after 10 {o foo} #puts stderr ===waiting vwait :x #puts stderr ===waiting-DONE # # vwait method # after 10 {o foo} #puts stderr ===waiting :vwait x #puts stderr ===waiting-DONE ? {o vwait :x} {invalid varName ':x'; only plain or fully qualified variable names allowed} } o destroy ? {set ::C} 0 ? {f1 eval {set :c}} 2 # call via callback, call :bar via .. from method after 1 {f1 callDot3} after 10 {set ::X 2} vwait X ? {set ::C} 1 ? {f1 eval {set :c}} 4 ################################################## # test for namespace resolver ################################################## nx::test case nsresolver namespace eval module { nx::Class create C nx::Class create M1 nx::Class create M2 C mixins set M1 ? {::nsf::relation::get C class-mixin} "::module::M1" C mixins add M2 ? {::nsf::relation::get C class-mixin} "::module::M2 ::module::M1" } ################################################## # test setting of instance variables for # objects with namespaces in and outside # of an eval (one case uses compiler) ################################################## nx::test case alias-dot-resolver-interp # outside of eval scope (interpreted) nx::Class create V { set :Z 1 set ZZZ 1 :method bar {z} { return $z } :object method bar {z} { return $z } :create v { set zzz 2 set :z 2 } } ? {lsort [V info vars]} {Z} ? {lsort [v info vars]} {z} # dot-resolver/ dot-dispatcher used in aliased proc nx::test case alias-dot-resolver { nx::Class create V { set :Z 1 set ZZZ 1 :method bar {z} { return $z } :object method bar {z} { return $z } :create v { set :z 2 set zzz 2 } } ? {lsort [V info vars]} {Z} ? {lsort [v info vars]} {z} } # # test [info vars] in eval method # nx::test case info-vars-in-eval { nx::Object create o ? {o eval { set x 1 expr {[info vars "x"] eq "x"} }} 1 } # # test for former crash when variable is used in connection with # prefixed variables # nx::test case tcl-variable-cmd { nx::Object create o { :public object method ? {varname} {info exists :$varname} :public object method bar args { variable :a set a 3 variable b set b 3 variable c 1 variable :d 1 :info vars } } ? {o bar} "" ? {o ? a} 0 ? {o ? b} 0 ? {o ? c} 0 ? {o ? d} 0 ? {lsort [o info vars]} "" o eval {set :a 1} ? {o ? a} 1 ? {lsort [o info vars]} a } nx::test case interactions { # SS: Adding an exemplary test destilled from the behavior observed # for AOLserver vs. NaviServer when introspecting object variables # by means of the colon-resolver interface. It exemplifies the (by now # resolved for good) interactions between: (a) the compiling and # non-compiling var resolvers and (b) compiled and non-compiled # script execution nx::Object create ::o { :public object method bar {} { # 1. creates a proc-local, compiled var "type" set type 1 # 2. at compile time: create a proc-local, compiled link-var ":type" info exists :type # 3. at (unoptimized) interpretation time: bypasses compiled link-var # ":type" (invokeStr instruction; a simple eval), does a var # lookup with ":type", handled by InterpColonVarResolver(); # CompiledLocalsLookup() receives the var name (i.e., ":type") # and finds the proc-local compiled var ":type" (actually a link # variable to the actual/real object variable). eval {info exists :type}; # Note! A [info exists :type] would have been optimized on the # bytecode fastpath (i.e., existsScalar instruction) and would # use the compiled-local link-var ":type" directly (without # visiting InterpColonVarResolver()!) } } ? {o bar} 0 # # document compile-time var resolver side effects: link variables # # At compile time, the compile-time var resolver looks up (and # creates) object variables for the colon-prefixed vars processed: # ":u" -> "u", ":v" -> "v"; hence, the resolver always returns a # Var structure! As a consequence, the compiler emits # colon-prefixed *link* variables (either in state "undefined" or # "defined", depending on providing a value or not) into the # compiled local array (e.g., ":u"), as proxies pointing to the # actual object variables (e.g., "u"). # # Consequences: These link vars are visible through introspection # sensible to created vars (rather than defined/undefined var # states) in compiled scripts ([info vars] vs. [info locals]). This # resembles [upvar]-created local link vars, yet it does not # intuitively compare with the [set]/[unset] behavior on # non-prefixed, ordinary variables from the angle of # introspection. Also, this constitutes an observable behavioral # difference between compiled and non-compiled scripts ... set script { # early probing: reflects the compiled-only, unexecuted state set _ [join [list {*}[lsort [info vars :*]] [info locals :*] \ [info exists :u] [::nsf::var::exists [::nsf::current] u] \ [info exists :v] [::nsf::var::exists [::nsf::current] v] \ [info exists :x] [::nsf::var::exists [::nsf::current] x]] "-"] catch {set :u} set :v 1 unset :x # late probing: reflects the (ideally) compiled, *executed* state append _ | [join [list {*}[lsort [info vars :*]] [info locals :*] \ [info exists :u] [::nsf::var::exists [::nsf::current] u] \ [info exists :v] [::nsf::var::exists [::nsf::current] v] \ [info exists :x] [::nsf::var::exists [::nsf::current] x]] "-"] return $_ } # compiled execution o public object method baz {} $script o eval {set :x 1; unset -nocomplain :v} ? {o baz} :u-:v-:x--0-0-0-0-1-1|:u-:v-:x--0-0-1-1-0-0 ; #:u-:v-:x--1-1-0-0-0-1-0-:u-:v-:x # non-compiled execution o eval {set :x 1; unset -nocomplain :v} ? [list o eval $script] -0-0-0-0-1-1|-0-0-1-1-0-0 # # testing interactions between the compile-time var resolver and ... # # ... [variable] # # background: the [variable] statement is compiled. During # compilation, our compile-time resolver is contacted, finds (and # eventually creates) an object variable "x". The compiler machinery # then creates a link-variable ":x" which is stored as a compiled # local, as usual. at the time of writing/testing, there are two # issues with this: # # ISSUE 1: In its non-compiled execution, [variable] sets the # AVOID_RESOLVERS flags, so our resolvers are not touched ... in its # compiled execution, AVOID_RESOLVERS is missing though (although # [variable] is compiled into a slow path execution, i.e., involves # a Tcl var lookup). Therefore, we get a link variable in the # compiled locals (and an undefined obj var). # this has some implications ... namespace eval ::ns1 { nx::Object create o { :public object method foo {} { set _ [join [list {*}[lsort [info vars :*]] [info locals :*] \ [info exists w] [::nsf::var::exists [::nsf::current] w] \ [info exists :x] [::nsf::var::exists [::nsf::current] x]] "-"] variable w; # -> intention: a variable "w" in the effective namespace (e.g., "::ns1::w") variable :x; # -> intention: a variable ":x" in the effective namespace (e.g., "::ns1:::x"!). append _ | [join [list {*}[lsort [info vars :*]] [info locals :*] \ [info exists w] [::nsf::var::exists [::nsf::current] w] \ [info exists :x] [::nsf::var::exists [::nsf::current] x]] "-"] return $_ } } ? {::ns1::o foo} ":x--0-0-0-0|:x--0-0-0-0" o eval { :public object method faz {} { set _ [join [list {*}[lsort [info vars :*]] [info locals :*] \ [namespace which -variable [namespace current]::w] \ [info exists [namespace current]::w] \ [info exists w] [::nsf::var::exists [::nsf::current] w] \ [namespace which -variable [namespace current]:::x] \ [info exists [namespace current]:::x] \ [info exists :x] [::nsf::var::exists [::nsf::current] x]] "-"] variable w 1; # -> intention: a variable "w" in the effective namespace (e.g., "::ns1::w") variable :x 2; # -> intention: a variable ":x" in the effective namespace (e.g., "::ns1:::x"!). append _ | [join [list {*}[lsort [info vars :*]] [info locals :*] \ [namespace which -variable [namespace current]::w] \ [info exists [namespace current]::w] \ [info exists w] [::nsf::var::exists [::nsf::current] w] \ [namespace which -variable [namespace current]:::x] \ [info exists [namespace current]:::x] [namespace eval [namespace current] {info exists :x}] \ [namespace eval [namespace current] {variable :x; info exists :x}] \ [info exists :x] [::nsf::var::exists [::nsf::current] x]] "-"] append _ | [join [list [expr {$w eq [namespace eval [namespace current] {variable w; set w}]}] \ [expr {${:x} eq [namespace eval [namespace current] {variable w; set :x}]}]] -] return $_ } } ? {::ns1::o faz} ":x--::ns1::w-0-0-0--0-0-0|:x--::ns1::w-1-1-0--0-1-1-1-0|1-1" # # ISSUE 2: Colon-prefixed variables become represented by linked # variables in the compiled local arrays during # compilation. However, linked variables are mutable (in contrast # to proc-local variables), that is, they can be changed to point # to another target variable. This target switch currently happens # between object variables and [variable] links which (due to # executing the compile-time var resolver because of lacking # AVOID_RESOLVERS) emits a "replacing" link var # # In the example below, there won't be an error exception # 'variable ":aaa" already exists', because ":aaa" is resolved on # the fly to "::ns1::o1.aaa" in a non-compiled execution and in a # compiled situation, the compiled-local link variable ":aaa" is # simply cleared and recreated to proxy a namespace variable. o eval { set :aaa 1 :public object method caz {} { set _ "[info exists :aaa]-${:aaa}-[set :aaa]" variable :aaa append _ "-[info exists :aaa]" set :aaa 2 append _ "-${:aaa}-[set :aaa]-[namespace eval [namespace current] {variable :aaa; set :aaa}]" unset :aaa append _ "-[info exists :aaa]-[namespace which -variable [namespace current]:::aaa]-[::nsf::var::exists [current] aaa]-[[current] eval {set :aaa}]" return $_ } } ? {::ns1::o caz} "1-1-1-0-2-2-2-0--1-1" # # In non-compiled executions, there is another form of interaction # between our var resolvers and [variable] in the sense of # switching references. A [variable] statement is then handled by # Tcl_VariableObjCmd() directly, our compile-time resolver is # never called, hence, no link variables are created. The # non-compiling resolver InterpColonVarResolver() is called to # duty from within Tcl_VariableObjCmd(), however, it fast-forwards # by signalling TCL_CONTINUE as [variable] requests # TCL_NAMESPACE_ONLY explicitly. # # While [variable] creates a local link var ":aaa", any later # referencing of :aaa is intercepted by InterpColonVarResolver() # and resolved to the obj var "aaa". The effects of this # interaction are probably counter-intuitive to standard # [variable] behavior. # # 1. There will not be a 'variable ":aaa" already exists' to # signal a naming conflict in the local naming scope, because the # symbolic name ":aaa" in a [set :aaa 1] and in a [variable :aaa # 1] is resolved differently (see above). # # 2. There is no way to refer to the local link var ":aaa" created # by [variable] in subsequent calls because the name will resolve # to an obj var "aaa". By calling [variable] in its setting mode, # you can still set namespace var values. ? {::ns1::o eval { set _ "[info exists :aaa]-${:aaa}-[set :aaa]" variable :aaa append _ "-[info exists :aaa]" set :aaa 2 append _ "-${:aaa}-[set :aaa]-[[current] eval {set :aaa}]-[namespace eval [namespace current] {variable :aaa; info exists :aaa}]" variable :aaa 5 unset :aaa append _ "-[info exists :aaa]-[namespace which -variable [namespace current]:::aaa]-[::nsf::var::exists [current] aaa]-[namespace eval [namespace current] {variable :aaa; info exists :aaa}]-[namespace eval [namespace current] {variable :aaa; set :aaa}]" return $_ }} "1-1-1-1-2-2-2-0-0--0-1-5" # ... [upvar] # # Exhibits the same interactions as [variable] due to creating # link variables by the compiling var resolver, namely the context # switching and effective disabling of the colon-prefixed # accessing of object state ... # nx::Object create p { :public object method foo {var} { set :x XXX set _ ${:x} upvar $var :x append _ -[join [list ${:x} [set :x] {*}[info vars :*] {*}[:info vars] \ [info exists :x] \ [[current] eval {info exists :x}]] "-"] unset :x append _ -[join [list {*}[info vars :*] {*}[:info vars] \ [info exists :x] [[current] eval {info exists :x}] \ [[current] eval {set :x}]] "-"] } :object method bar {var1 var2 var3 var4 var5 var6} { upvar $var1 xx $var2 :yy $var3 :zz $var4 q $var5 :el1 $var6 :el2 set _ [join [list {*}[lsort [:info vars]] {*}[lsort [info vars :*]] \ [info exists xx] $xx \ [info exists :yy] ${:yy} \ [info exists :zz] ${:zz} \ [info exists q] [[current] eval {info exists :q}]] -] incr :yy incr xx incr :zz incr q incr :el1 incr :el2 return $_ } :public object method baz {} { set :x 10 set y 20 set :z 30 unset -nocomplain :q set :arr(a) 40 set _ [:bar :x y :z :q :arr(a) :arr(b)] append _ -[join [list ${:x} $y ${:z} ${:q} [set :arr(a)] [set :arr(b)] [:info vars q]] -] } } ? {set y 1; p foo y} "XXX-1-1-:x-x-1-1-:x-x-0-1-XXX" ? {p baz} "arr-x-z-:el1-:el2-:yy-:zz-1-10-1-20-1-30-0-0-11-21-31-1-41-1-q" # # ... [namespace which] # # Similar to the compiled, slow-path [variable] instructions, # [namespace which] as implemented by NamespaceWhichCmd() in # tclNamesp.c lacks AVOID_RESOLVERS. Therefore, we end up in our # var resolver which resolves colon-prefixed vars to object # variables. Also, NamespaceWhichCmd() does not set any other # var-resolution flags (TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY) as # this would defeat its purpose. Anywyays, our resolver is # therefore completely blind when handling calls from [namespace # which]. # # This leads to the unexpected behavior in the test below: # [namespace which -variable :XXX] != [namespace which -variable # [namespace current]:::XXX] o eval { :public object method bar {} { set :XXX 1 return [join [list ${:XXX} [set :XXX] [namespace which -variable :XXX] \ [namespace which -variable [namespace current]:::XXX]] -] } } ? {::ns1::o bar} "1-1-:XXX-" } } nx::test case after-next { # # This test case tests, whether we can use e..g an instvar in an # mixin method after the next. In such cases, the frame flags have # to be altered from inactive mixin to active mixin (otherwise the # actual frame would be skipped in useActiveFrames below in :instvar). # nx::Class create FormPage { :property package_id :public method initialize_loaded_object {} {;} } nx::Class create WorkflowPage { :alias instvar :::nsf::methods::object::instvar :public method initialize_loaded_object {} { next :instvar package_id return $package_id } FormPage mixins add WorkflowPage FormPage create p1 -package_id 123 ? {p1 initialize_loaded_object} 123 } } nx::test case unconfigured-varresolver { # # Test robustness of varresolver for unconfigured objects # nx::Class create O { :public method configure args {;} :create ateh } ? {ateh eval {info exists :x}} 0 } # # Test variable resolver in respect to uplevel and apply # (lambda frames) # ::nx::test case var-resolver-uplevel-apply { nx::Object create o1 { set :a o1.a :public object method foo {} {return ${:a}} :public object method bar {} {o2 foo} :public object method bar2 {} {o2 foo2} } nx::Object create o2 { set :a o2.a set :cmd {set :a} :public object method foo {} {eval ${:cmd}} :public object method foo2 {} {uplevel ${:cmd}} :public object method foo3 {} {uplevel 2 ${:cmd}} :public object method bar {} {:foo} :public object method bar2 {} {:foo2} :public object method bar3a {} {:foo3} :public object method bar3 {} {:bar3a} } # # test cases for uplevel over multiple levels in the same object # ? {o2 foo} o2.a ? {o2 bar} o2.a ? {o2 bar2} o2.a ? {o2 bar3} o2.a # # test cases for uplevel over multiple levels in different objects # ? {o1 foo} o1.a ? {o1 bar} o2.a ? {o1 bar2} o1.a # # test cases for uplevel over apply # proc x {cmd} {uplevel $cmd} nx::Object create o3 { set :a o3.a :public object method set {var} {set :$var} :public object method foo-m {} {:set a} :public object method foo-r {} {::set :a} :public object method foo-m-u {} {x {:set a}} :public object method foo-r-u {} {x {::set :a}} :public object method foo-a-m {} {::apply [list {} {:set a} [self]]} :public object method foo-a-r {} {::apply [list {} {::set :a} [self]]} :public object method foo-a-m-u {} {::apply [list {} {x {:set a}} [self]]} :public object method foo-a-r-u {} {::apply [list {} {x {::set :a}} [self]]} } # # resolver and method should behave the same # ? {o3 foo-m} "o3.a" ? {o3 foo-r} "o3.a" # # resolver and method should behave the same, also when uplevel is used # ? {o3 foo-m-u} "o3.a" ? {o3 foo-r-u} "o3.a" # # resolver and method should behave the same, also when apply is used # ? {o3 foo-a-m} "o3.a" ? {o3 foo-a-r} "o3.a" # # resolver and method should behave the same, also when apply and # uplevel are used # ? {o3 foo-a-m-u} "o3.a" ? {o3 foo-a-r-u} "o3.a" } nx::test case compiled_colon_lookup { nx::Object create p { :object method bar {var3 var4 var5 var6} { upvar $var3 :zz $var4 q $var5 :el1 return ${:zz} } :public object method baz {} { set :z 30 unset -nocomplain :q set :arr(a) 40 return [:bar :z :q :arr(a) :arr(b)] } } # # the upvar construct causes a "slow" access path via the colon # var resolver. The first call will cause the creation of the # sorted lookup cache. # ? {p baz} 30 # # later calls use this cache # ? {p baz} 30 # # Now redefine the method containing the compiled locals with # an additional variable on the first position. In case the cache # would not be refreshed appropriately, the index would point to a # different variable and we would see wrong results here. # #puts stderr "=====redefine with an additional variable on the first position" p public object method baz {} { set :a 123 set :z 30 unset -nocomplain :q set :arr(a) 40 return [:bar :z :q :arr(a) :arr(b)] } ? {p baz} 30 ? {p baz} 30 } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/methods.test000644 000766 000024 00000167110 14164662012 016706 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx package require nx::test ::nx::configure defaultMethodCallProtection false nx::test case name-validity-checks { nx::Class create C # # Add some basic tests on valid/invalid method names. # ? {set ::h [nsf::method::create ::C "" {} {;}]} "invalid method name ''" ? {set ::h [nsf::method::create ::C {e1 m1} {} {;}]} "invalid method name 'e1 m1'" ? {set ::h [nsf::method::create ::C "e1\tm1" {} {;}]} "invalid method name 'e1\tm1'" ? {set ::h [nsf::method::create ::C {{e1 m1}} {} {;}]} "invalid method name '{e1 m1}'" ? {set ::h [nsf::method::create ::C ":" {} {;}]} {can't create procedure ":" in non-global namespace with name starting with ":"} # These are Tcl whitespace characters, which act as the separators in # Tcl list string reps: # # \u0009 \t TAB # \u000A \n NEWLINE # \u000B \v VERTICAL TAB # \u000C \f FORM FEED # \u000D \r CARRIAGE RETURN # \u0020 SPACE # ? {set ::h [nsf::method::create ::C " e1 " {} {;}]} "invalid method name ' e1 '" ? {set ::h [nsf::method::create ::C {" e1 "} {} {;}]} {invalid method name '" e1 "'} ? {set ::h [nsf::method::create ::C "\te1" {} {;}]} "invalid method name '\te1'" ? {set ::h [nsf::method::create ::C "e1\tm1" {} {;}]} "invalid method name 'e1\tm1'" ? {set ::h [nsf::method::create ::C "\ne1" {} {;}]} "invalid method name '\ne1'" ? {set ::h [nsf::method::create ::C "e1\nm1" {} {;}]} "invalid method name 'e1\nm1'" ? {set ::h [nsf::method::create ::C "\ve1" {} {;}]} "invalid method name '\ve1'" ? {set ::h [nsf::method::create ::C "e1\vm1" {} {;}]} "invalid method name 'e1\vm1'" ? {set ::h [nsf::method::create ::C "\fe1" {} {;}]} "invalid method name '\fe1'" ? {set ::h [nsf::method::create ::C "e1\fm1" {} {;}]} "invalid method name 'e1\fm1'" ? {set ::h [nsf::method::create ::C "\re1" {} {;}]} "invalid method name '\re1'" ? {set ::h [nsf::method::create ::C "e1\rm1" {} {;}]} "invalid method name 'e1\rm1'" # There is no tangible difference between a bareword and a one-element # list in Tcl (singleton list). So, there will remain exotique method # names including curly braces, along with other peculiar names, # e.g. those starting with #. ? {set ::h [nsf::method::create ::C {{{{{a}}}}} {} {;}]} {::nsf::classes::C::{{{{a}}}}} ? {set ::h [nsf::method::create ::C {#a} {} {;}]} {::nsf::classes::C::#a} # # In Tcl, the empty string is a valid command (proc) name, with # obscure effects (e.g., cannot be renamed, unless) . We disallow it as method name. # ? {set ::h [nsf::method::create ::C "" {} {;}]} "invalid method name ''" # But, we can safeguard against list elements containing Tcl # whitespace characters at any nesting level. ? {set ::h [nsf::method::create ::C {{{{{a b}}}}} {} {;}]} {invalid method name '{{{{a b}}}}'} } nx::test configure -count 10 nx::Class create C { # methods :method plain_method {} {return [current method]} :public method public_method {} {return [current method]} :protected method protected_method {} {return [current method]} # forwards :forward plain_forward %self plain_method :public forward public_forward %self public_method :protected forward protected_forward %self protected_method # setter :property plain_setter :property -accessor public public_setter :property -accessor protected protected_setter # alias :alias plain_alias [C info method registrationhandle plain_method] :public alias public_alias [C info method registrationhandle public_method] :protected alias protected_alias [C info method registrationhandle protected_method] # class-object :object method plain_object_method {} {return [current method]} :public object method public_object_method {} {return [current method]} :protected object method protected_object_method {} {return [current method]} :object forward plain_object_forward %self plain_object_method :public object forward public_object_forward %self public_object_method :protected object forward protected_object_forward %self protected_object_method :object property {plain_object_setter ""} :object property -accessor public {public_object_setter ""} :object property -accessor protected {protected_object_setter ""} :object alias plain_object_alias [:info object method registrationhandle plain_object_method] :public object alias public_object_alias [:info object method registrationhandle public_object_method] :protected object alias protected_object_alias [:info object method registrationhandle protected_object_method] } C create c1 { # methods :object method plain_object_method {} {return [current method]} :public object method public_object_method {} {return [current method]} :protected object method protected_object_method {} {return [current method]} # forwards :object forward plain_object_forward %self plain_object_method :public object forward public_object_forward %self public_object_method :protected object forward protected_object_forward %self protected_object_method # setter :object property {plain_object_setter ""} :object property -accessor public {public_object_setter ""} :object property -accessor protected protected_object_setter # alias :object alias plain_object_alias [:info object method registrationhandle plain_object_method] :public object alias public_object_alias [:info object method registrationhandle public_object_method] :protected object alias protected_object_alias [:info object method registrationhandle protected_object_method] } C property -accessor public s0 C property -accessor protected s1 ? {c1 s0 set 0} 0 ? {::nsf::dispatch c1 s1 set 1} 1 C object property -accessor public {s3 ""} ? {C s3 set 3} 3 nx::test case info-callprotection { ? {C info method callprotection plain_method} "public" ? {C info method callprotection protected_method} "protected" ? {C info method callprotection public_method} "public" ? {C info method callprotection plain_alias} "public" ? {C info method callprotection protected_alias} "protected" ? {C info method callprotection public_alias} "public" ? {C info method callprotection plain_forward} "public" ? {C info method callprotection protected_forward} "protected" ? {C info method callprotection public_forward} "public" ? {C info object method callprotection plain_object_method} "public" ? {C info object method callprotection protected_object_method} "protected" ? {C info object method callprotection public_object_method} "public" ? {C info object method callprotection plain_object_alias} "public" ? {C info object method callprotection protected_object_alias} "protected" ? {C info object method callprotection public_object_alias} "public" ? {C info object method callprotection plain_object_forward} "public" ? {C info object method callprotection protected_object_forward} "protected" ? {C info object method callprotection public_object_forward} "public" } # create a fresh object (different from c1) C create c2 # test scripted class level methods nx::test case scripted-class-level-methods { ? {c2 plain_method} "plain_method" ? {c2 public_method} "public_method" ? {catch {c2 protected_method}} 1 ? {::nsf::dispatch c2 protected_method} "protected_method" ? {info commands ::nsf::classes::C::public_method} ::nsf::classes::C::public_method } # class level forwards nx::test case class-level-forwards { ? {c2 plain_forward} "plain_method" ? {c2 public_forward} "public_method" ? {catch {c2 protected_forward}} 1 ? {::nsf::dispatch c2 protected_forward} "protected_method" } # class level setter nx::test case class-level-setter { ? {c2 plain_setter 1} {::c2: unable to dispatch method 'plain_setter'} #? {c2 plain_setter 1} 1 ? {c2 public_setter set 2} "2" ? {catch {c2 protected_setter set 3}} 1 ? {::nsf::dispatch c2 protected_setter set 4} "4" } # class level alias .... nx::test case class-level-alias { ? {c2 plain_alias} "plain_alias" ? {c2 public_alias} "public_alias" ? {catch {c2 protected_alias}} 1 ? {::nsf::dispatch c2 protected_alias} "protected_alias" } ########### # scripted class level methods nx::test case scripted-class-object-level { ? {C plain_object_method} "plain_object_method" ? {C public_object_method} "public_object_method" ? {catch {C protected_object_method}} 1 ? {::nsf::dispatch C protected_object_method} "protected_object_method" } # class level forwards nx::test case class-object-level-forwards { ? {C plain_object_forward} "plain_object_method" ? {C public_object_forward} "public_object_method" ? {catch {C protected_object_forward}} 1 ? {::nsf::dispatch C protected_object_forward} "protected_object_method" } # class level setter nx::test case class-object-level-setter { ? {C plain_object_setter 1} {method 'plain_object_setter' unknown for ::C; in order to create an instance of class ::C, consider using '::C create plain_object_setter ?...?'} #? {C plain_object_setter 1} "1" ? {C public_object_setter set 2} "2" ? {catch {C protected_object_setter set 3}} 1 ? {::nsf::dispatch C protected_object_setter set 4} "4" } # class level alias .... nx::test case class-object-level-alias { ? {C plain_object_alias} "plain_object_alias" ? {C public_object_alias} "public_object_alias" ? {catch {C protected_object_alias}} 1 ? {::nsf::dispatch C protected_object_alias} "protected_object_alias" } ########### # scripted object level methods nx::test case scripted-object-level-methods { ? {c1 plain_object_method} "plain_object_method" ? {c1 public_object_method} "public_object_method" ? {catch {c1 protected_object_method}} 1 ? {::nsf::dispatch c1 protected_object_method} "protected_object_method" ? {info commands ::c1::public_object_method} ::c1::public_object_method } # object level forwards nx::test case object-level-forwards { ? {c1 plain_object_forward} "plain_object_method" ? {c1 public_object_forward} "public_object_method" ? {catch {c1 protected_object_forward}} 1 ? {::nsf::dispatch c1 protected_object_forward} "protected_object_method" } # object level setter nx::test case object-level-setter { ? {c1 plain_object_setter 1} {::c1: unable to dispatch method 'plain_object_setter'} #? {c1 plain_object_setter 1} "1" ? {c1 public_object_setter set 2} "2" ? {catch {c1 protected_object_setter set 3}} 1 ? {::nsf::dispatch c1 protected_object_setter set 4} "4" } # object level alias .... nx::test case object-level-alias { ? {c1 plain_object_alias} "plain_object_alias" ? {c1 public_object_alias} "public_object_alias" ? {catch {c1 protected_object_alias}} 1 ? {::nsf::dispatch c1 protected_object_alias} "protected_object_alias" #? {lsort [c1 info object methods]} \ "plain_object_alias plain_object_forward plain_object_method public_object_alias public_object_forward public_object_method public_object_setter" ? {lsort [c1 info object methods]} \ "plain_object_alias plain_object_forward plain_object_method public_object_alias public_object_forward public_object_method public_object_setter" #? {lsort [C info methods]} \ "plain_object_alias plain_object_forward plain_object_method public_object_alias public_object_forward public_object_method public_object_setter s3" ? {lsort [C info object methods]} \ "plain_object_alias plain_object_forward plain_object_method public_object_alias public_object_forward public_object_method public_object_setter s3" } C destroy nx::test case colondispatch { nx::Object create ::o { #:public object method foo args {;} :public object method bar args {;} } ? {o :bar} "::o: method name ':bar' must not start with a colon" ? {o eval :bar} "" ? {o :foo} "::o: method name ':foo' must not start with a colon" ? {o eval :foo} "::o: unable to dispatch method 'foo'" } nx::test case colon-unknown { set o [nx::Object new { :object method foo {a b c args} { return [current method]-ok } ## Expansion to valid method calls (messages) :object method expand-nonempty-list-1 {} { {*}[list :foo 1 2 3 4 5 6]; } :object method expand-nonempty-list-2 {} { : {*}[list foo 1 2 3 4 5 6]; } :object method expand-self-call-1 {} { {*}[list :]; } :object method expand-self-call-2 {} { : {*}[list]; } ## (Non-)expansion & unknown :object method expand-unknown-1 {} { :{*}[list foo 1 2 3 4 5 6]; # no expansion, yielding invalid list as method name } :object method expand-unknown-2 {} { :{*}[list]; # no expansion, yielding invalid list as method name } :object method expand-unknown-3 {} { :{*}; # no expansion, yielding invalid list as method name } :object method expand-unknown-4 {} { :{*}{}; # no expansion, yielding invalid list as method name } :object method expand-unknown-5 {} { :{\}}; # yet another invalid list (no expansion op) } }] ? [list $o expand-nonempty-list-1] "foo-ok" ? [list $o expand-nonempty-list-2] "foo-ok" ? [list $o expand-self-call-1] $o ? [list $o expand-self-call-2] $o # # Keep unknown messages compatible with Tcl's 'invalid command' # messages in the cases below, e.g.: # # proc =foo {args} {;} ;# ={*}[list foo 1 2 3 4 5 6] # ? [list $o expand-unknown-1] "$o: unable to dispatch method '{*}foo 1 2 3 4 5 6'" ? [list $o expand-unknown-2] "$o: unable to dispatch method '{*}'" ? [list $o expand-unknown-3] "$o: unable to dispatch method '{*}'" ? [list $o expand-unknown-4] "$o: unable to dispatch method '{*}{}'" ? [list $o expand-unknown-5] "$o: unable to dispatch method '{\}}'" } nx::test case mixinguards { # define a Class C and mixin class M nx::Class create C nx::Class create M # register the mixin on C as an object mixin and define a mixinguard #C mixins set M #C mixins guard M {1 == 1} #? {C info mixin guard M} "1 == 1" #C mixins guard M {} #? {C info mixin guard M} "" # # set guard via converter # C mixins set {{M -guard {1 == 1}}} ? {C info mixins -guard} "{::M -guard {1 == 1}}" ? {C mixins get} "{::M -guard {1 == 1}}" # # set/clear guard via relation slot # C mixins set M ? {C mixins guard M {1 == 1}} "" ? {C mixins get} "{::M -guard {1 == 1}}" ? {C info mixins -guard} "{::M -guard {1 == 1}}" ? {C info mixins} "::M" ? {C mixins guard M ""} "" ? {C mixins get} "::M" ? {C info mixins -guard} "::M" # # now the same as object mixin and object mixin guard # # set guard via converter # C object mixins set {{M -guard {1 == 1}}} ? {C info object mixins -guard} "{::M -guard {1 == 1}}" ? {C info object mixins} "::M" ? {C object mixins get} "{::M -guard {1 == 1}}" # # set/clear guard via relation slot # C object mixins set M C object mixins guard M {1 == 1} ? {C object mixins get} "{::M -guard {1 == 1}}" ? {C info object mixins -guard} "{::M -guard {1 == 1}}" ? {C info object mixins} "::M" ? {C object mixins guard M {}} "" ? {C info object mixins -guard} "::M" } nx::test case mixin-via-objectparam { # add an object and class mixin via object-parameter and via slots foreach c {M1 M2 M3 M4 M5} {nx::Class create $c} nx::Class create C -mixin M1 -object-mixins M2 { :mixins add M3 :object mixins add M4 } ? {lsort [C info object mixins]} "::M2 ::M4" ? {lsort [C info mixins]} "::M1 ::M3" ? {lsort [C object mixins get]} "::M2 ::M4" ? {lsort [C mixins get]} "::M1 ::M3" ? {lsort [C object mixins]} {wrong # args: use "::C object mixins add|classes|clear|delete|get|guard|set"} ? {lsort [C mixins]} {wrong # args: use "::C mixins add|classes|clear|delete|get|guard|set"} ? {lsort [C mixins x]} {submethod x undefined for mixins: use "::C mixins add|classes|clear|delete|get|guard|set"} ? {catch {C mixin M5} errorMsg} 1 ? {lsort [C info mixins]} "::M1 ::M3" ? {catch {C object mixin M5} errorMsg} 1 ? {lsort [C info object mixins]} "::M2 ::M4" ? {C mixins set M5} ::M5 ? {lsort [C info mixins]} "::M5" ? {C object mixins set M5} "::M5" ? {lsort [C info object mixins]} "::M5" ? {C configure -mixin M1} "" ? {C cget -mixin} "::M1" ? {C configure -object-mixins M2} "" ? {C cget -object-mixin} "::M2" } # testing next via nonpos-args nx::test case next-from-nonpos-args { nx::Object create o { :object method bar {-y:required -x:required} { #puts stderr "+++ o x=$x, y=$y [current args] ... next [current nextmethod]" return [list x $x y $y [current args]] } } nx::Class create M { :method bar {-x:required -y:required} { #puts stderr "+++ M x=$x, y=$y [current args] ... next [current nextmethod]" return [list x $x y $y [current args] -- {*}[next]] } } o object mixins set M ? {o bar -x 13 -y 14} "x 13 y 14 {-x 13 -y 14} -- x 13 y 14 {-x 13 -y 14}" ? {o bar -y 14 -x 13} "x 13 y 14 {-y 14 -x 13} -- x 13 y 14 {-y 14 -x 13}" } # # test method property with protected/public # nx::test case property-method { nx::Class create C { set x [:property -accessor public a] ? [list set _ $x] "::nsf::classes::C::a" # property with default :property {b b1} :property -accessor public {c c1} :property -accessor protected {d d1} set X [:object property -accessor public A] ? [list set _ $X] "::C::A" # object property with default :object property {B B2} :object property -accessor public {C C2} :object property -accessor protected {D D2} } C create c1 -a 1 ? {c1 a get} 1 ? {c1 cget -b} b1 ? {c1 cget -c} c1 ? {c1 d} "::c1: unable to dispatch method 'd'" ? {C A set 2} 2 ? {C A get} 2 ? {C B} {method 'B' unknown for ::C; in order to create an instance of class ::C, consider using '::C create B ?...?'} #? {C B} B2 ? {C C get} C2 ? {C D} {method 'D' unknown for ::C; in order to create an instance of class ::C, consider using '::C create D ?...?'} nx::Object create o { set x [:object property -accessor public a] ? [list set _ $x] "::o::a" # property with default :object property {b b1} :object property -accessor public {c c1} :object property -accessor protected {d d1} } ? {o a set 2} 2 ? {o b} {::o: unable to dispatch method 'b'} #? {o b} b1 ? {o c get} c1 ? {o d} "::o: unable to dispatch method 'd'" } nx::test case subcmd { nx::Class create Foo { :method "Info filter guard" {filter} {return [current object]-[current method]} :method "Info filter methods" {-guards pattern:optional} {return [current object]-[current method]} :method "Info args" {} {return [current object]-[current method]} :method "Info foo" {} {return [current object]-[current method]} :object method "INFO filter guard" {a b} {return [current object]-[current method]} :object method "INFO filter methods" {-guards pattern:optional} {return [current object]-[current method]} } ? {Foo INFO filter guard 1 2} ::Foo-guard ? {Foo INFO filter methods a*} ::Foo-methods Foo create f1 { :object method "list length" {} {return [current object]-[current method]} :object method "list reverse" {} {return [current object]-[current method]} } ? {f1 Info filter guard x} "::f1-guard" ? {f1 Info filter methods} "::f1-methods" ? {f1 Info args} "::f1-args" ? {f1 Info foo} "::f1-foo" ? {f1 list length} "::f1-length" ? {f1 list reverse} "::f1-reverse" } package req nx::serializer nx::test case class-object-property { nx::Class create C { :object property -accessor public x :property -accessor public a:int :create c1 } ? {C x set 1} 1 ? {C x get} 1 ? {lsort [C info methods]} "a" ? {lsort [C info object methods]} "x" ? {c1 a set b} {expected integer but got "b" for parameter "value"} set s(C) [C serialize] set s(c1) [c1 serialize] # Destroy object and class c1 destroy C destroy ? {nsf::object::exists c1} 0 ? {nsf::object::exists C} 0 # create it from the serialized code eval $s(C) ? {nsf::object::exists C} 1 eval $s(c1) ? {nsf::object::exists c1} 1 # tests should work as again ? {C x get} 1 ? {lsort [C info methods]} "a" ? {lsort [C info object methods]} "x" ? {c1 a set b} {expected integer but got "b" for parameter "value"} } # # Test method deletion # nx::test configure -count 1 nx::test case methoddelete { nx::Class create C { :public method foo {x} {return $x} :public object method bar {x} {return $x} :create c1 } ? {::nsf::method::delete C x} "::C: instance method 'x' does not exist" ? {::nsf::method::delete C -per-object x} "::C: object specific method 'x' does not exist" ? {::nsf::method::delete C foo} "" ? {::nsf::method::delete C foo} "::C: instance method 'foo' does not exist" ? {::nsf::method::delete C bar} "::C: instance method 'bar' does not exist" ? {::nsf::method::delete C -per-object bar} "" ? {::nsf::method::delete C -per-object bar} "::C: object specific method 'bar' does not exist" } # # Test error message of method modifier # nx::test configure -count 1 nx::test case errormessage { nx::Class create C ? {C public method foo {x} {return $x}} "::nsf::classes::C::foo" ? {C public Object method bar {x} {return $x}} \ "'Object' is not a method defining method" ? {C protected Object method bar {x} {return $x}} \ "'Object' is not a method defining method" ? {C Object method bar {x} {return $x}} \ {method 'Object' unknown for ::C; in order to create an instance of class ::C, consider using '::C create Object ?...?'} #? {C public object Object method bar {x} {return $x}} "'Object' not allowed to be modified by 'class'" #? {C public object Object method bar {x} {return $x}} \ {'Object' is not a method defining method} } # # test dispatch without object # nx::test case dispatch-without-object { nx::Object create o { # property defines a setter, we need a current object :object property -accessor public {a v} # the other methods don't require them as strong :object forward b ::o2 bar :object method foo {} {return [nx::self]} :object alias x ::o::foo } nx::Object create o2 { :public object method bar {} {return [nx::self]} } # dispatch methods without current object ? ::o::a {wrong # args: use "::o ::o::a add|delete|exists|get|set|unset"} ? ::o::b "::o2" ? ::o::foo "no current object; command called outside the context of a Next Scripting method" ? ::o::x "no current object; x called outside the context of a Next Scripting method" # make a regular call, provide tcd->object with a value ? {::o x} "::o" # check, if missing object is still detected ? ::o::x "no current object; x called outside the context of a Next Scripting method" ? nx::self "no current object; command called outside the context of a Next Scripting method" } # # Test the current namespaces and resolution for # a) top-level methods # b) ensemble methods on level 1 # c) ensemble methods on level 2 # nx::test case scopes { nx::Object create o1 { :public object method foo {} {return [namespace current]-[namespace which info]} :public object method "info foo" {} {return [namespace current]-[namespace which info]} :public object method "info bar foo" {} {return [namespace current]-[namespace which info]} } ? {o1 foo} "::-::info" ? {o1 info foo} "::-::info" ? {o1 info bar foo} "::-::info" nx::Class create C { :public method foo {} {return [namespace current]-[namespace which info]} :public method "info foo" {} {return [namespace current]-[namespace which info]} :public method "info bar foo" {} {return [namespace current]-[namespace which info]} :create c1 } ? {c1 foo} "::-::info" ? {c1 info foo} "::-::info" ? {c1 info bar foo} "::-::info" } # # Test the current namespaces and resolution for methods # registered on an object in a certain namespace # a) top-level methods # b) ensemble methods on level 1 # c) ensemble methods on level 2 # nx::test case namespaced-scopes { namespace eval ::ns { nx::Object create o1 { :public object method foo {} {return [namespace current]-[namespace which info]} :public object method "info foo" {} {return [namespace current]-[namespace which info]} :public object method "info bar foo" {} {return [namespace current]-[namespace which info]} } nx::Class create C { :public method foo {} {return [namespace current]-[namespace which info]} :public method "info foo" {} {return [namespace current]-[namespace which info]} :public method "info bar foo" {} {return [namespace current]-[namespace which info]} :create c1 } } ? {ns::o1 foo} "::ns-::info" ? {ns::o1 info foo} "::ns-::info" ? {ns::o1 info bar foo} "::ns-::info" ? {ns::c1 foo} "::ns-::info" ? {ns::c1 info foo} "::ns-::info" ? {ns::c1 info bar foo} "::ns-::info" } # # Test the current namespaces and resolution for methods # registered on a sub object # a) top-level methods # b) ensemble methods on level 1 # c) ensemble methods on level 2 # nx::test case nested-scopes { nx::Object create o nx::Object create o::o1 { :public object method foo {} {return [namespace current]-[namespace which info]} :public object method "info foo" {} {return [namespace current]-[namespace which info]} :public object method "info bar foo" {} {return [namespace current]-[namespace which info]} } ? {o::o1 foo} "::o-::info" ? {o::o1 info foo} "::o-::info" ? {o::o1 info bar foo} "::o-::info" nx::Class create o::C { :public method foo {} {return [namespace current]-[namespace which info]} :public method "info foo" {} {return [namespace current]-[namespace which info]} :public method "info bar foo" {} {return [namespace current]-[namespace which info]} :create c1 } ? {c1 foo} "::o-::info" ? {c1 info foo} "::o-::info" ? {c1 info bar foo} "::o-::info" } # # Test deletion of object-specific methods/attributes via "delete # method" and "delete property" # # a) test attributes # b) test simple methods # c) test ensemble methods # nx::test case delete-per-object { nx::Object create o1 { :object property -accessor public a1 :object property -accessor public a2 :public object method foo {} {return [namespace current]-[namespace which info]} :public object method "info foo" {} {return [namespace current]-[namespace which info]} :public object method "info bar foo" {} {return [namespace current]-[namespace which info]} } ? {o1 info object methods -path} "{info foo} {info bar foo} foo a1 a2" ? {o1 info children} "::o1::info ::o1::per-object-slot" ? {o1 delete object method bar} "::o1: object specific method 'bar' does not exist" # For a1, we have a method and a property. We can delete the # method without the slot. ? {o1 delete object method a1} "" # After the deletion of the accessor, the slot exists still ? {o1::per-object-slot info children} "::o1::per-object-slot::a1 ::o1::per-object-slot::a2" # If we perform now a "delete object property a1", the slot will be removed. ? {o1 delete object property a1} "" ? {o1::per-object-slot info children} "::o1::per-object-slot::a2" # try to delete the property again: ? {o1 delete object property a1} "::o1: cannot delete object-specific property 'a1'" ? {o1 info object methods -path} "{info foo} {info bar foo} foo a2" ? {o1 delete object property a2} "" ? {o1 info object methods -path} "{info foo} {info bar foo} foo" ? {o1 delete object method foo} "" ? {o1 info object methods -path} "{info foo} {info bar foo}" ? {o1 delete object method "info foo"} "" ? {o1 info object methods -path} "{info bar foo}" ? {o1 delete object method "info bar foo"} "" ? {o1 info object methods -path} "" } # # Test deletion of per-object methods/attributes defined on classes # via the delete method # a) test attributes # b) test simple methods # c) test ensemble methods # nx::test case delete-per-object-on-class { nx::Class create C { :object property -accessor public a1 :public object method foo {} {return [namespace current]-[namespace which info]} :public object method "info foo" {} {return [namespace current]-[namespace which info]} :public object method "info bar foo" {} {return [namespace current]-[namespace which info]} :property -accessor public a2 } ? {C info object methods -path} "{info foo} {info bar foo} foo a1" ? {C info children} "::C::info ::C::slot ::C::per-object-slot" ? {C delete object method bar} "::C: object specific method 'bar' does not exist" ? {C delete object property a1} "" ? {C info object methods -path} "{info foo} {info bar foo} foo" ? {C delete object property a1} "::C: cannot delete object-specific property 'a1'" ? {C delete object method foo} "" ? {C info object methods -path} "{info foo} {info bar foo}" ? {C delete object method "info foo"} "" ? {C info object methods -path} "{info bar foo}" ? {C delete object method "info bar foo"} "" ? {C info object methods -path} "" ? {C info methods} "a2" ? {C info slots} "::C::slot::a2" } # # Test deletion of methods/attributes defined on classes via the # delete method # a) test attributes # b) test simple methods # c) test ensemble methods # nx::test case delete-class-level-method { nx::Class create C { :property -accessor public a1 :public method foo {} {return [namespace current]-[namespace which info]} :public method "info foo" {} {return [namespace current]-[namespace which info]} :public method "info bar foo" {} {return [namespace current]-[namespace which info]} } ? {C info methods -path} "{info foo} {info bar foo} foo a1" ? {C info children} "::C::slot" ? {C delete method bar} "::C: instance method 'bar' does not exist" ? {C delete property a1} "" ? {C info methods -path} "{info foo} {info bar foo} foo" ? {C delete property a1} "::C: cannot delete property 'a1'" ? {C delete method foo} "" ? {C info methods -path} "{info foo} {info bar foo}" ? {C delete method "info foo"} "" ? {C info methods -path} "{info bar foo}" ? {C delete method "info bar foo"} "" ? {C info methods -path} "" } nx::test case default-unknown-handler { nx::Object create o ? {o sakania} "::o: unable to dispatch method 'sakania'" ? {o yore dub} "::o: unable to dispatch method 'yore'" ? {o "yore dub"} "::o: unable to dispatch method 'yore dub'" } # # simple unknown tests; # ensemble unknown tests are in submethods.test # nx::test case test-simple-unknown { # # calling unknown with a plain "method" without arguments # ::nx::Class create A { :object method unknown args {? [list set _ $args] "hello"} } A hello # # calling unknown with a plain "method" with arguments # ::nx::Class create B { :object method unknown args {? [list set _ $args] "hello world"} } B hello world # # calling unknown with a method with spaces # ::nx::Class create C { :object method unknown args {? [list set _ $args] "{hello world}"} } C {hello world} } # # simple speed tests # ensemble unknown tests are in submethods.test # nx::test configure -count 1000 nx::test case speed-dispatch { # # define various forms of simple dispatches # ::nx::Object create o { :public object method foo {} {return ::o} :public object method bar00 {} {self} :public object method bar01 {} {:} :public object method bar02 {} {[self]} :public object method bar03 {} {[:]} :public object method bar04 {} {:foo} :public object method bar05 {} {: foo} #:public object method bar06 {} {my foo} :public object method bar07 {} {[self] foo} :public object method bar08 {} {: -system info object methods foo} #:public object method bar09 {} {my -system info object methods foo} } ? {o foo} ::o ? {o bar00} ::o {self} ? {o bar01} ::o {:} ? {o bar02} ::o {[self]} ? {o bar03} ::o {[:]} ? {o bar04} ::o ":foo" ? {o bar05} ::o ": foo" #? {o bar06} ::o "my foo" ? {o bar07} ::o "self foo" ? {o bar08} foo ": -system info" #? {o bar09} foo "my -system info" } nx::test configure -count 1 nx::test case fq-obj-dispatch { # # Capture the (current) dispatcher rules for fully-qualified # selectors which resolve to existing objects. # nx::Class create C { set :unknown 0 :public object method unknown {m args} { incr :unknown return unknown-$m } } nx::Class create D { set :defaultcalled 0 :public method defaultmethod args { [current class] eval [list incr :defaultcalled] } :create ::d } ? {::D eval {set :defaultcalled}} 0 ? {::d} 1 ? {C eval {set :unknown}} 0 ? {C ::d} "unknown-::d" ? {C eval {set :unknown}} 1 ? {::d} 2; # should not be 3! ? {C d} "unknown-d" ? {C eval {set :unknown}} 2 ? {::d} 3 # # nested-object selector, *not* pre-existing # ? {::nsf::object::exists ::d::c} 0 ? {C ::d::c} "unknown-::d::c" ? {C eval {set :unknown}} 3 ? {::nsf::object::exists ::d::c} 0 # # nested-object selector, pre-existing # ? {::nsf::object::exists ::d::dd} 0 D create ::d::dd ? {::nsf::object::exists ::d::dd} 1 ? {::D eval {set :defaultcalled}} 3 ? {::d::dd} 4 ? {C eval {set :unknown}} 3 ? {C ::d::dd} "unknown-::d::dd" ? {C eval {set :unknown}} 4 ? {C d::dd} "unknown-d::dd" ? {C eval {set :unknown}} 5 ? {::D eval {set :defaultcalled}} 4 # # namespaced selector, *not* pre-existing # namespace eval ::ns1 {} ? {::nsf::object::exists ::ns1::c} 0 ? {C ::ns1::c} "unknown-::ns1::c" ? {C eval {set :unknown}} 6 ? {::nsf::object::exists ::ns1::c} 0 # # namespaced selector, pre-existing # ? {::nsf::object::exists ::ns1::d} 0 D create ::ns1::d ? {::nsf::object::exists ::ns1::d} 1 ? {::D eval {set :defaultcalled}} 4 ? {::ns1::d} 5 ? {C eval {set :unknown}} 6 ? {C ::ns1::d} "unknown-::ns1::d" ? {C eval {set :unknown}} 7 ? {C ns1::d} "unknown-ns1::d" ? {C eval {set :unknown}} 8 ? {::D eval {set :defaultcalled}} 5 # # Is XOTcl's creation short-cut operative for nested-object # selectors, compliant with the XOTcl-specific unknown-(re)create # protocol? # package req XOTcl 2.0 ? {::nsf::object::exists ::X} 0 xotcl::Class ::X -instproc p1 {v} { [self class] incr [self proc] $v } -proc unknown args { my incr [self proc] next } -set unknown 0 -proc recreate args { my incr [self proc] next } -set recreate 0 ? {::nsf::object::exists ::X} 1 ? {::X exists p1} 0 ? {::X set unknown} 0 ? {xotcl::Object ::p} ::p ? {::nsf::object::exists ::p::child} 0 ? {::X ::p::child -p1 2} ::p::child ? {::nsf::object::exists ::p::child} 1 ? {::X set p1} 2 ? {::X set unknown} 1 ? {::X set recreate} 0 ? {::X ::p::child -p1 1} ::p::child ? {::X set p1} 3 ? {::X set unknown} 2 ? {::X set recreate} 1 } # # object copy # nx::test case object-copy { nsf::method::provide set {::nsf::method::alias set -frame object ::set} nx::Object create o { :public object method foo {} {return foo} :public object method "a b" {} {return "a b"} :public object method "a c" {} {return "a c"} :protected object method bar {} {return bar} :private object method baz {} {return baz} :public object forward fwd %self xxx :require public object method set } ? {lsort [::o info object methods -path]} "{a b} {a c} foo fwd set" ? {o a b} "a b" ? {o a c} "a c" ? {o set x 1} 1 ? {o eval {info exists :x}} 1 ? {o copy p} ::p ? {lsort [::p info object methods -path]} "{a b} {a c} foo fwd set" ? {p a b} "a b" ? {p a c} "a c" #package require nx::serializer #puts stderr [o serialize] #puts stderr [p serialize] ? {p eval {info exists :x}} 1 ? {p set x} 1 } # # class copy # nx::test case class-copy { nsf::method::provide set {::nsf::method::alias set -frame object ::set} nx::Class create C { :public method foo {} {return foo} :public method "a b" {} {return "a b"} :public method "a c" {} {return "a c"} :protected method bar {} {return bar} :private method baz {} {return baz} :public forward fwd %self xxx :require public method set :create c1 } ? {lsort [::C info methods -path]} "{a b} {a c} foo fwd set" ? {::c1 a b} "a b" ? {::c1 a c} "a c" ? {::c1 set x 1} 1 ? {::C copy ::D} ::D ? {lsort [::D info methods -path]} "{a b} {a c} foo fwd set" #package require nx::serializer #puts stderr [::C serialize] #puts stderr [::D serialize] ::D create d1 ? {::d1 a b} "a b" ? {::d1 a c} "a c" #puts stderr [::c1 serialize] #puts stderr [::d1 serialize] ? {::d1 set x 2} 2 } # # class copy with class object methods # nx::test case object+class-copy { nsf::method::provide set {::nsf::method::alias set -frame object ::set} nsf::method::provide exists {::nsf::method::alias exists ::nsf::methods::object::exists} nx::Class create C { :public method foo {} {return foo} :public method "a b" {} {return "a b"} :public method "a c" {} {return "a c"} :protected method bar {} {return bar} :private method baz {} {return baz} :public forward fwd %self xxx :require public method set :public object method ofoo {} {return foo} :public object method "oa b" {} {return "oa b"} :public object method "oa c" {} {return "oa c"} :protected object method obar {} {return bar} :private object method obaz {} {return baz} :public object forward ofwd %self xxx #TODO: the following line leads to a crash #:require public object method exists :require public object method set :create c1 } ? {lsort [::C info methods -path]} "{a b} {a c} foo fwd set" ? {lsort [::C info object methods -path]} "{oa b} {oa c} ofoo ofwd set" ? {::c1 a b} "a b" ? {::c1 a c} "a c" ? {::c1 set x 1} 1 ? {::C oa b} "oa b" ? {::C oa c} "oa c" ? {::C set y 100} "100" ? {::C copy ::D} ::D ? {lsort [::D info methods -path]} "{a b} {a c} foo fwd set" #? {lsort [::D info object methods -path]} "{oa b} {oa c} ofoo ofwd set" ? {::D oa b} "oa b" ? {::D oa c} "oa c" ? {::D set y} "100" ::D create d1 ? {::d1 a b} "a b" ? {::d1 a c} "a c" ? {::d1 set x 2} 2 } nx::test configure -count 10 # # class copy with class object methods # nx::test case object+class+property-copy { nsf::method::provide set {::nsf::method::alias set -frame object ::set} nsf::method::provide exists {::nsf::method::alias exists ::nsf::methods::object::exists} package require nx::serializer nx::Class create C { :public method foo {} {return foo} :public method "a b" {} {return "a b"} :public method "a c" {} {return "a c"} :protected method bar {} {return bar} :private method baz {} {return baz} :public forward fwd %self xxx :require public method set :property p :variable v 0 :public object method ofoo {} {return foo} :public object method "oa b" {} {return "oa b"} :public object method "oa c" {} {return "oa c"} :protected object method obar {} {return bar} :private object method obaz {} {return baz} :public object forward ofwd %self xxx :require public object method exists :require public object method set :object property op :object variable ov 0 :create c1 } ? {lsort [::C info methods -path]} "{a b} {a c} foo fwd set" ? {lsort [::C info object methods -path]} "exists {oa b} {oa c} ofoo ofwd set" ? {::c1 a b} "a b" ? {::c1 a c} "a c" ? {::c1 set x 1} 1 ? {::C oa b} "oa b" ? {::C oa c} "oa c" ? {::C set y 100} "100" ::nx::Object public method COPY {target} { set code [::Serializer deepSerialize -objmap [list [self] $target] [self]] #puts CODE=$code eval $code return $target } ? {::C copy ::D} ::D ? {::C COPY ::E} ::E ? {lsort [::D info methods -path]} "{a b} {a c} foo fwd set" ? {lsort [::D info object methods -path]} "exists {oa b} {oa c} ofoo ofwd set" ? {::D oa b} "oa b" ? {::D oa c} "oa c" ? {::D set y} "100" ? {::D create d1} ::d1 ? {::d1 a b} "a b" ? {::d1 a c} "a c" ? {::d1 set x 2} 2 ? {::E oa b} "oa b" ? {::E oa c} "oa c" ? {::E set y} "100" ? {::E create e1} ::e1 ? {::e1 a b} "a b" ? {::e1 a c} "a c" ? {::e1 set x 2} 2 } # # Check, if the execution namespace after the builtin or # serializer-based copy is correct. # nx::test case nx-copy-COPY-namespace { nx::Object create o1 nx::Object create o1::o { :public object method foo {} {namespace current} } nx::Object create o2 ::nx::Object public method COPY {target} { set code [::Serializer deepSerialize -objmap [list [self] $target] [self]] #puts CODE=$code eval $code return [$target eval self] } ? {o1::o foo} ::o1 ? {o1::o copy o2::o} ::o2::o ? {o1::o COPY o2::O} ::o2::O ? {o2::o foo} ::o2 ? {o2::O foo} ::o2 } nx::test case xotcl-COPY { package req XOTcl xotcl::Class create C C proc foo {} {return foo} C instproc bar {} {return bar} C set x 1 ::xotcl::Object instproc COPY {target} { set code [::Serializer deepSerialize -objmap [list [self] $target] [self]] #puts CODE=$code eval $code return $target } ? {C set x} 1 C copy D C COPY E ? {D set x} 1 ? {D foo} foo ? {D create d1} ::d1 ? {d1 bar} bar ? {E set x} 1 ? {E foo} foo ? {E create e1} ::e1 ? {e1 bar} bar } nx::test case xotcl-assertion-swallows-result { package req XOTcl xotcl::Class create Edge Edge instproc foo {} { my set xxx } Edge instproc bar {} { my set xxx } {} {{1 == 0}} Edge create e1 # base case ? {catch {e1 foo} errMsg} 1 ? {string match {can't read "xxx":*} $errMsg} 1 ? {catch {e1 bar} errMsg} 1 ? {string match {can't read "xxx":*} $errMsg} 1 # turn on assertion checking nsf::method::assertion e1 check all # still report error when invariant would not return error ? {catch {e1 foo} errMsg} 1 ? {string match {can't read "xxx":*} $errMsg} 1 # still report error when postcondition would return an error ? {catch {e1 bar} errMsg} 1 ? {string match {can't read "xxx":*} $errMsg} 1 } nx::test case uplevel+interceptor-transparency { # # A real-world case from OpenACS + from the database abstraction # layer. Since profiling is realized via mixin, and the db interface # requires heavy upleveling for SQL bind variables, we have complex # interaction between upleveling and interceptor transparency. In # earlier versions, the Profile mixin towards the end of this test # case lead to a problem with the variable scope (the interceptor # transparency was violated). # nx::Object create ns_cache { :public object method eval {script} { set rc [catch {:uplevel $script} result] return -code $rc $result } } nx::Class create DBI { :public method 1row {} { :uplevel {return $x} } } nx::Class create Profile { :public method 1row {} { next } } DBI create db nx::Class create C { :public method foo {} { set x 1 return [db 1row] } :public method bar {} { set x 2 return [ns_cache eval {db 1row}] } :create c1 } ? {c1 foo} 1 ? {c1 bar} 2 db object mixins set Profile ? {c1 foo} 1 ? {c1 bar} 2 } nx::test case uplevel+tcl-transparency { # # A real-world case from OpenACS + from the database abstraction # layer. Frequently, nsf based methods are called from tcl procs # (and tcl-upleveled code). In order to preserve interceptor # transparency (i.e. to be able to use a mixin on the tcl-called nsf # method), the uplevel method has to behave like tcl-uplevel when the # caller is a tcl method. # nx::Object create ns_cache { :public object method eval {script} { set rc [catch {:uplevel $script} result] return -code $rc $result } :public object method eval0 {script} { set rc [catch {uplevel $script} result] return -code $rc $result } } nx::Class create Profile { :public method eval {script} { next } :public method eval0 {script} { next } } proc db {cmd} { #nsf::__db_show_stack return [uplevel $cmd] } proc foo {} { set x 1 db {set x} } proc bar0 {} { set x 2 ns_cache eval0 {db {set x}} } proc bar {} { set x 2 ns_cache eval {db {set x}} } # foo is tcl, only ? foo 1 # The "bar" functions use the ns_cache interface, which is # nsf-based. The function "bar0" uses tcl uplevel, which is fine, # as long no interceptor is used. The function "bar0" uses the # uplevel method, which works also, when e.g. mixins are used on # ns_cache. ? bar0 2 ? bar 2 ns_cache object mixins set Profile # the version with tcl-uplevel should fail ? bar0 {can't read "x": no such variable} # the version with uplevel method should succeed ? bar 2 } nx::test case debug+deprecated { # # Check setting and introspection of method properties "debug" and # "deprecated" # nx::Class create C { :public method foo {} {return 1} :public method bar {} {return 1} :public object method ofoo {} {return 1} :public object method obar {} {return 1} } ? {nsf::method::property C foo debug} 0 ? {nsf::method::property C bar deprecated} 0 ? {nsf::method::property C -per-object ofoo debug} 0 ? {nsf::method::property C -per-object obar deprecated} 0 ? {C info method debug foo} 0 ? {C info method deprecated bar} 0 ? {C info object method debug ofoo} 0 ? {C info object method deprecated obar} 0 C eval { :public method -debug foo {} {return 1} :public method -deprecated bar {} {return 1} :public object method -debug ofoo {} {return 1} :public object method -deprecated obar {} {return 1} } ? {nsf::method::property C foo debug} 1 ? {nsf::method::property C bar deprecated} 1 ? {nsf::method::property C -per-object ofoo debug} 1 ? {nsf::method::property C -per-object obar deprecated} 1 ? {C info method debug foo} 1 ? {C info method deprecated bar} 1 ? {C info object method debug ofoo} 1 ? {C info object method deprecated obar} 1 } nx::test case eval-next { ? {nx::Object eval {::nsf::next}} "" ? {nx::Object eval {::nsf::current nextmethod}} "" nx::Object create ::o { :public object method foo {} { lappend _ [nx::Object eval {::nsf::current method}] lappend _ [nx::Object eval {::nsf::current callingmethod}] lappend _ [nx::Object eval {::nsf::current callingobject}] } ? [list set _ [:foo]] "eval foo ::o" } } # # Testing the behavior of :upvar (and implicitly of [current # callinglevel]) in different setups # # Setup 1: plain calls # Setup 2: when filters are used # Setup 3: when filters + guards are used # # Forall setups, we test on the tclsh toplevel and from a proc. # nx::test configure -count 1 nx::test case callinglevel-toplevel-setup1 nx::Class create AbstractFile { :public method filterCall {args} { next } } nx::Class create FsFile -superclass AbstractFile { :public method lstat {path var} { #puts stderr lstat-level=[info level]-calling-level-[current callinglevel] :upvar $var arrayVar file lstat $path arrayVar } } # # Setup 1 (without filter) # FsFile create f1 f1 lstat / a1 ? {expr {[array size a1] > 1}} 1 array unset a1 proc foo {} { FsFile create f2 f2 lstat / a2 array get a2 } ? {expr {[dict size [foo]] > 1}} 1 # # Setup 2 (with filter) # nx::test case callinglevel-toplevel-setup2 AbstractFile filters add filterCall f1 lstat / a1 ? {expr {[array size a1] > 1}} 1 array unset a1 ? {expr {[dict size [foo]] > 1}} 1 # # Setup 3 (with filter and guard) # nx::test case callinglevel-toplevel-setup3 AbstractFile filters guard filterCall { [current calledproc] eq "lstat" } f1 lstat / a1 ? {expr {[array size a1] > 1}} 1 array unset a1 ? {expr {[dict size [foo]] > 1}} 1 AbstractFile filters delete filterCall nx::test case callinglevels { nx::Object create objekt objekt public object method foo {} { current callinglevel } ? {uplevel #0 {objekt foo}} "#0" ? {uplevel #0 { namespace eval ::ns1 { namespace eval ns2 { objekt foo } } }} "#2" namespace delete ::ns1 ? {uplevel #0 {apply {{} {objekt foo}}}} "#1" ? {uplevel #0 { apply {{} { namespace eval ::ns1 { namespace eval ns2 { objekt foo } } }}}} "#1" namespace delete ::ns1 objekt public object method intercept args { list [current method] {*}[next] } objekt object filters set intercept ? {uplevel #0 {objekt foo}} "intercept #0" ? {uplevel #0 { namespace eval ::ns1 { namespace eval ns2 { objekt foo } } }} "intercept #2" namespace delete ::ns1 ? {uplevel #0 {apply {{} {objekt foo}}}} "intercept #1" ? {uplevel #0 { apply {{} { namespace eval ::ns1 { namespace eval ns2 { objekt foo } } }}}} "intercept #1" namespace delete ::ns1 objekt object mixins add [nx::Class new { :public method foo {args} { list [current method] {*}[next] } }] ? {uplevel #0 {objekt foo}} "intercept foo #0" ? {uplevel #0 { namespace eval ::ns1 { namespace eval ns2 { objekt foo } } }} "intercept foo #2" namespace delete ::ns1 ? {uplevel #0 {apply {{} {objekt foo}}}} "intercept foo #1" ? {uplevel #0 { apply {{} { namespace eval ::ns1 { namespace eval ns2 { objekt foo } } }}}} "intercept foo #1" namespace delete ::ns1 } nx::test case uplevel { nx::Object create objekt objekt public object method foo {} { :uplevel {return -level 0 #[info level]} } ? {uplevel #0 {objekt foo}} "#0" ? {uplevel #0 { namespace eval ::ns1 { namespace eval ns2 { objekt foo } } }} "#2" namespace delete ::ns1 ? {uplevel #0 {apply {{} {objekt foo}}}} "#1" ? {uplevel #0 { apply {{} { namespace eval ::ns1 { namespace eval ns2 { objekt foo } } }}}} "#1" namespace delete ::ns1 objekt public object method intercept args { if {[current calledmethod] eq "foo"} { list [current method] {*}[next] } else { next } } objekt object filters set intercept ? {uplevel #0 {objekt foo}} "intercept #0" ? {uplevel #0 { namespace eval ::ns1 { namespace eval ns2 { objekt foo } } }} "intercept #2" namespace delete ::ns1 ? {uplevel #0 {apply {{} {objekt foo}}}} "intercept #1" ? {uplevel #0 { apply {{} { namespace eval ::ns1 { namespace eval ns2 { objekt foo } } }}}} "intercept #1" namespace delete ::ns1 objekt object mixins add [nx::Class new { :public method foo {args} { list [current method] {*}[next] } }] ? {uplevel #0 {objekt foo}} "intercept foo #0" ? {uplevel #0 { namespace eval ::ns1 { namespace eval ns2 { objekt foo } } }} "intercept foo #2" namespace delete ::ns1 ? {uplevel #0 {apply {{} {objekt foo}}}} "intercept foo #1" ? {uplevel #0 { apply {{} { namespace eval ::ns1 { namespace eval ns2 { objekt foo } } }}}} "intercept foo #1" namespace delete ::ns1 set filters [objekt object filters clear] set mixins [objekt object mixins clear] unset -nocomplain ::_ objekt public object method foo {} { :uplevel {set FOO 1} } ? {uplevel #0 { lappend _ [info exists FOO]; objekt foo; lappend _ [info exists FOO][unset FOO]} } "0 1" unset -nocomplain ::_ ? {uplevel #0 { namespace eval ::ns1 { namespace eval ns2 { lappend _ [info exists FOO]; objekt foo; lappend _ [info exists FOO][unset FOO]; } } }} "0 1" namespace delete ::ns1 ? {uplevel #0 { namespace eval ::ns1 { apply {{} { lappend _ [info exists FOO]; namespace eval ns2 { objekt foo; } lappend _ [info exists FOO][unset FOO]; }} } }} "0 1" namespace delete ::ns1 objekt object filters set $filters objekt object mixins set $mixins ? {uplevel #0 { lappend _ [info exists FOO]; objekt foo; lappend _ [info exists FOO][unset FOO]} } "0 1" unset -nocomplain ::_ ? {uplevel #0 { namespace eval ::ns1 { namespace eval ns2 { lappend _ [info exists FOO]; objekt foo; lappend _ [info exists FOO][unset FOO]; } } }} "0 1" namespace delete ::ns1 ? {uplevel #0 { namespace eval ::ns1 { apply {{} { lappend _ [info exists FOO]; namespace eval ns2 { objekt foo; } lappend _ [info exists FOO][unset FOO]; }} } }} "0 1" namespace delete ::ns1 } nx::test case uplevel-method-signature { nx::Object create objekt objekt public object method foo {} { concat \ [:uplevel return -level 0 "#\[info level\]"] \ [uplevel [current callinglevel] return -level 0 "#\[info level\]"] } ? {uplevel #0 { apply {{} { namespace eval ::ns1 { namespace eval ns2 { objekt foo } } }}}} "#1 #1" objekt public object method foo {} { :uplevel } ? {uplevel #0 {objekt foo}} {wrong # args: should be "::objekt uplevel ?level? command ?arg ...?"} objekt public object method foo {} { :uplevel 1 } ? {uplevel #0 {objekt foo}} {invalid command name "1"} objekt public object method foo {} { :uplevel #1 } ? {uplevel #0 {objekt foo}} {} objekt public object method foo {} { :uplevel [list #1] } ? {uplevel #0 {objekt foo}} {invalid command name "#1"} objekt public object method foo {} { :uplevel 1 {return -level 0 #[info level]} } ? {uplevel #0 {objekt foo}} "#0" objekt public object method foo {} { :uplevel 1 return -level 0 "#\[info level\]" } ? {uplevel #0 {objekt foo}} "#0" objekt public object method foo {} { :uplevel #0 {return -level 0 #[info level]} } ? {uplevel #0 {objekt foo}} "#0" objekt public object method foo {} { :uplevel #0 return -level 0 "#\[info level\]" } ? {uplevel #0 {objekt foo}} "#0" # # (1) syntactically invalid level specifiers (no digit, no hash) in # the more-arg case resort to interpreting the arg as a command name. # (2) syntactically valid level specifiers (digit, hash), but that # point to nowhere, are reported as a bad level. # # Level-syntax validity is a moving target: see TIP 515 # https://core.tcl-lang.org/tips/doc/trunk/tip/515.md # # # ad (1) # objekt public object method foo {} { :uplevel a return -level 0 "#\[info level\]" } ? {uplevel #0 {objekt foo}} {invalid command name "a"} objekt public object method foo {} { :uplevel 1 return -level 0 "#\[info level\]" } ? {uplevel #0 {objekt foo}} "\#0" objekt public object method foo {} { :uplevel #0 return -level 0 "#\[info level\]" } ? {uplevel #0 {objekt foo}} "\#0" # # TODO: Should we concat at all, or limited to the objc > 3 case only? # objekt public object method foo {} { # concat interferes! :uplevel [list [list a b]] return -level 0 "#\[info level\]" } ? {uplevel #0 {objekt foo}} {invalid command name "a b"} objekt public object method foo {} { # concat interferes! :uplevel [list [list a b]] [list return -level 0 "#\[info level\]"] } ? {uplevel #0 {objekt foo}} {invalid command name "a b"} objekt public object method foo {} { # concat interferes! :uplevel [list a b] [list return -level 0 "#\[info level\]"] } ? {uplevel #0 {objekt foo}} {invalid command name "a"} objekt public object method foo {} { # concat interferes! :uplevel [list a b] return -level 0 "#\[info level\]" } ? {uplevel #0 {objekt foo}} {invalid command name "a"} # # ad (2) # objekt public object method foo {} { :uplevel #1000 return -level 0 "#\[info level\]" } ? {uplevel #0 {objekt foo}} {bad level "#1000"} objekt public object method foo {} { :uplevel 1000 return -level 0 "#\[info level\]" } ? {uplevel #0 {objekt foo}} {bad level "1000"} } nx::test case uplevel-default-level { # # This is to test the single-argument case of uplevel, which will # default to a computed level, internally. This should avoid # "nonsense-parsing" of the single argument for a level specifier # (with leading digit or hash). This is in line with changes to # uplevel in Tcl 8.7 (see also TIP 515). # # https://core.tcl-lang.org/tips/doc/trunk/tip/515.md # nx::Object create objekt objekt public object method foo {} { :uplevel [list 123456 arg] } ? {uplevel #0 { objekt foo }} {invalid command name "123456"} ? {uplevel #0 { proc 123456 {args} {return $args} set r [objekt foo] rename 123456 "" set r }} "arg" objekt public object method foo {} { :uplevel [list #123456 arg2] } ? {uplevel #0 { objekt foo }} {invalid command name "#123456"} ? {uplevel #0 { proc #123456 {args} {return $args} set r [objekt foo] rename #123456 "" set r }} "arg2" } nx::test case upvar-method-signature { Object create objekt objekt public object method foo {} { :upvar #1; } ? {uplevel #0 {objekt foo}} \ {wrong # args: should be "::objekt upvar ?level? otherVar localVar ?otherVar localVar ...?"} objekt public object method foo {} { :upvar 1; } ? {uplevel #0 {objekt foo}} \ {wrong # args: should be "::objekt upvar ?level? otherVar localVar ?otherVar localVar ...?"} objekt public object method foo {} { :upvar; } ? {uplevel #0 {objekt foo}} \ {wrong # args: should be "::objekt upvar ?level? otherVar localVar ?otherVar localVar ...?"} objekt public object method foo {} { :upvar x z; set z 5 } ? {uplevel #0 {objekt foo; set x}} 5 objekt public object method foo {} { :upvar #5 x z; } ? {uplevel #0 {objekt foo}} \ {bad level "#5"} objekt public object method foo {} { :upvar #5 x z y; set x 1 } ? {uplevel #0 {apply {{} {objekt foo; info exists "#5"}}}} 1 } nx::test case uplevel-backwards-compatibility { nx::Object create ::o1 proc a {args} { return [list a $args] } proc 1000 {args} { return [list 1000 $args] } ? {o1 eval {:uplevel 1000}} {1000 {}} ? {o1 eval {:uplevel 1000 a}} {bad level "1000"} ? {o1 eval {:uplevel 1000 a b}} {bad level "1000"} ? {o1 eval {:uplevel {1000 a}}} {1000 a} ? {o1 eval {:uplevel {1000 a b}}} {1000 {a b}} ? {o1 eval {:uplevel {1000 {a b}}}} {1000 {{a b}}} ? {o1 eval {:uplevel ::1000}} {1000 {}} ? {o1 eval {:uplevel ::1000 a}} {1000 a} ? {o1 eval {:uplevel ::1000 a b}} {1000 {a b}} ? {o1 eval {:uplevel {::1000 a}}} {1000 a} ? {o1 eval {:uplevel {::1000 a b}}} {1000 {a b}} ? {o1 eval {:uplevel {::1000 {a b}}}} {1000 {{a b}}} rename a "" rename 1000 "" } nx::test case alias-to-object { nsf::proc ::p {} {return p1} nx::Object create o1 { :public object method bar {} {return bar1} } nx::Class create C { :alias A1 ::p :alias A2 ::o1 :forward A3 ::o1 } # # We expect to see both, the alias to the proc and the alias to the # object. We expect same results with and without "-path" specified. # ? {lsort [C ::nsf::methods::class::info::methods -callprotection all]} {A1 A2 A3} ? {lsort [C ::nsf::methods::class::info::methods -callprotection all -path]} {A1 A2 A3} nx::Class create D { :method m {} {return m1} :method "e f" {} {return e1} :alias a ::o1 nx::Class create D::D1 nx::Object create D::d1 { :public object method foo {} {return foo} } :public object method om {} {return om1} :public object method "oe f" {} {return of1} :public object alias oa ::o1 :public object alias op ::p } ? {D op} "p1" ? {D om} "om1" ? {D oe f} "of1" ? {D oa bar} "bar1" # # Note that we use "d1" like a method although it is not listed as a # method (it was not registered via a method defining command). # ? {D d1 foo} "foo" ? {lsort [D ::nsf::methods::class::info::methods -callprotection all]} {a e m} ? {lsort [D ::nsf::methods::class::info::methods -callprotection all -path]} {a {e f} m} # # For per-object methods, we see a difference when "-path" is set or # not in the number of reported methods. # ? {lsort [D ::nsf::methods::object::info::methods -callprotection all]} {D1 d1 oa oe om op} ? {lsort [D ::nsf::methods::object::info::methods -callprotection all -path]} {oa {oe f} om op} rename ::p "" o1 destroy C destroy } # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/cget.test000644 000766 000024 00000023547 13565500032 016167 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package req nx package require nx::test # # The first test set checks just the basic behavior: # nx::test case cget-simple { nx::Class create Person { :property famnam:required :property {age:integer,required 0} :property {friends:0..n ""} :property sex # Create an instance of the class :create p1 -famnam hugo -age 25 } # # first, check basic provided values and defaults # ? {p1 cget -age} 25 ? {p1 cget -famnam} hugo ? {p1 cget -friends} "" # # a method property ? {p1 cget -class} ::Person # # error handling: # - wrong # args # - wrong parameter # - parameter without a value # ? {p1 cget} {wrong # of arguments: should be "cget /name/"} ? {p1 cget -foo} "cget: unknown configure parameter -foo" ? {p1 cget foo} "cget: parameter must start with a '-': foo" ? {p1 cget -sex} {can't read "sex": no such variable} # # Reconfigure the object # ? {p1 configure -famnam joe -age 27} "" # # check the new values # ? {p1 cget -age} 27 ? {p1 cget -famnam} joe # # configure without arguments # ? {p1 configure} "" ? {p1 info lookup syntax configure} {?-sex /value/? -famnam /value/ ?-age /integer/? ?-friends /value .../? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?} } # # The second test set checks redirection of configure / cget to slot # methods "set" and "get". # nx::test configure -count 1 nx::test case cget-via-slot { nx::Class create C { # Define a property with a "get" method :property bar1 { :public object method value=get { object property} { incr ::count(cget) nsf::var::set $object $property } } # Define a property with a "get" and "set" method :property bar2 { :public object method value=get { object property} { incr ::count(cget) nsf::var::set $object $property } :public object method value=set { object property value } { incr ::count(assign) nsf::var::set $object $property $value } } # Create an instance of the class :create p1 } # # configure without arguments # ? {p1 configure} "" ? {p1 info lookup syntax configure} {?-bar1 /value/? ?-bar2 /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?} # # test gettin/setting via slots # # just a getter: # array unset ::count ? {p1 configure -bar1 100} "" ? {array get ::count} "" ? {p1 cget -bar1} 100 ? {array get ::count} "cget 1" # a getter and a setter: # array unset ::count ? {p1 configure -bar2 100} "" ? {array get ::count} "assign 1" ? {p1 cget -bar2} 100 ? {array get ::count} "assign 1 cget 1" } # # The third test set checks method binding to parameter: # All cmds are supposed to return reasonable values. # nx::test case cget-parameter-methods { nx::Class create C { :property {foo:alias,method=m0 {1 2 3}} :property {{bar:forward,method=%self m1 a b c %method} bar1} :public method m0 {args} {set :m0 $args; return $args} :public method m1 {args} {set :m1 $args; return $args} :create c1 } package req nx::volatile # # class-level lookup # ? {C info lookup syntax configure} \ "?-mixins /mixinreg .../? ?-superclasses /class .../? ?-filters /filterreg .../? ?-volatile? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?" ? {C cget -superclasses} "::nx::Object" ? {C cget -superclass} "::nx::Object" ? {C cget -object-mixin} "" ? {C cget -mixin} "" ? {C cget -filter} "" ? {C cget -volatile} 0 #? {C cget -noinit} "" ? {C cget -class} "::nx::Class" # # object-level lookup # ? {c1 info lookup syntax configure} \ "?-foo /value/? ?-bar /value/? ?-volatile? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?" # # query all properties from base classes # ? {c1 cget -volatile} 0 #? {c1 cget -noinit} "" #? {c1 cget -mixin} "" ? {c1 cget -object-mixin} "" ? {c1 cget -class} ::C #? {c1 cget -filter} "" ? {c1 cget -object-filter} "" # # query alias and forward # ? {c1 eval {set :m0}} "{1 2 3}" ? {c1 eval {set :m1}} {a b c bar bar1} ? {c1 cget -foo} "" ? {c1 cget -bar} "a b c bar" } # # The fourth test set checks performance of "cget" and "configure". # nx::test configure -count 10000 nx::test case cget-performance { nx::Class create Person { :property famnam:required :property -accessor public {age:integer,required 0} :property {friends:0..n ""} :property sex # Define a property with a "get" and "set" method :property bar { :public object method value=get { object property } { nsf::var::set $object $property } :public object method value=set { object property value } { nsf::var::set $object $property $value } } # Create an instance of the class :create p1 -famnam hugo -age 25 -bar 101 } # # read properties # - built-in accessor # - cget # - dispatch of cget method with full path # - cget via slot method ? {p1 age get} 25 ? {p1 cget -age} 25 ? {p1 ::nsf::methods::object::cget -age} 25 ? {p1 cget -bar} 101 # # write properties: # - built-in accessor # - configure # - configure via slot method ? {p1 age set 27} 27 ? {p1 configure -age 27} "" ? {p1 configure -bar 102} "" } nx::test configure -count 1 nx::test case configure-trace-class { # # class case with no default # nx::Class create C C property -trace set p { :public object method value=set {obj var value} { ::nsf::var::set -notrace $obj $var [expr {$value + 1}] } } C create c1 ? {c1 eval {info exists :p}} 0 ? {c1 cget -p} {can't read "p": no such variable} ? {c1 configure -p 1} "" ? {c1 eval {info exists :p}} 1 ? {c1 cget -p} "2" # # class case with default # C property -trace set {q 100} { :public object method value=set {obj var value} { ::nsf::var::set -notrace $obj $var [expr {$value + 1}] } } C create c2 ? {c2 eval {info exists :q}} 1 ? {c2 cget -q} 100 ? {c2 configure -q 101} "" ? {c2 cget -q} "102" } nx::test case configure-trace-object { # # object case with no default # nx::Object create o ? {o eval {info exists :A}} 0 o object property -trace set A { :public object method value=set {obj var value} { ::nsf::var::set -notrace $obj $var [expr {$value + 1}] } } # puts [o info object variables A] # puts [o info variable parameter [o info object variables A]] # puts [[o info object slots A] getParameterSpec] ? {o eval {info exists :A}} 0 ? {o cget -A} {can't read "A": no such variable} ? {o configure -A 1} "" ? {o cget -A} "2" # # object case with default # ? {o eval {info exists :B}} 0 o object property -trace set {B 1000} { :public object method value=set {obj var value} { ::nsf::var::set -notrace $obj $var [expr {$value + 1}] } } ? {o eval {info exists :B}} 1 ? {o cget -B} 1000 ? {o configure -B 1001} "" ? {o cget -B} 1002 } nx::test case configure-trace-class-type { # # class case with type and no default # nx::Class create C C property -trace set p:integer { :public object method value=set {obj var value} { ::nsf::var::set -notrace $obj $var [expr {$value + 1}] } } C create c1 ? {c1 eval {info exists :p}} 0 ? {c1 cget -p} {can't read "p": no such variable} ? {c1 configure -p a} {expected integer but got "a" for parameter "-p"} ? {c1 eval {info exists :p}} 0 ? {c1 configure -p 1} "" ? {c1 eval {info exists :p}} 1 ? {c1 cget -p} "2" # # class case with type and default # ? {C property -trace set {q:integer aaa} { :public object method value=set {obj var value} { ::nsf::var::set -notrace $obj $var [expr {$value + 1}] } }} {expected integer but got "aaa" for parameter "q"} # slot should no exist ? {C info slots q} "" ? {C property -trace set {q:integer 99} { :public object method value=set {obj var value} { ::nsf::var::set -notrace $obj $var [expr {$value + 1}] } }} "" # slot should exist ? {C info slots q} "::C::slot::q" ? {C create c2 -q 111} ::c2 ? {c2 eval {info exists :q}} 1 ? {c2 cget -q} 112 ? {c2 configure -q 101} "" ? {c2 cget -q} "102" } nx::test case configure-trace-object-type { # # object case with no default # nx::Object create o ? {o eval {info exists :A}} 0 o object property -trace set A:integer { :public object method value=set {obj var value} { ::nsf::var::set -notrace $obj $var [expr {$value + 1}] } } # puts [o info object variables A] # puts [o info variable parameter [o info object variables A]] # puts [[o info object slots A] getParameterSpec] ? {o eval {info exists :A}} 0 ? {o cget -A} {can't read "A": no such variable} ? {o configure -A 1} "" ? {o cget -A} "2" ? {o configure -A x} {expected integer but got "x" for parameter "-A"} ? {o cget -A} "2" # # object case with default # ? {o eval {info exists :B}} 0 ? {o object property -trace set {B:integer x} { :public object method value=set {obj var value} { ::nsf::var::set -notrace $obj $var [expr {$value + 1}] } }} {expected integer but got "x" for parameter "B"} ? {o eval {info exists :B}} 0 ? {o info object slots B} "" ? {o object property -trace set {B:integer 1000} { :public object method value=set {obj var value} { ::nsf::var::set -notrace $obj $var [expr {$value + 1}] } }} {} ? {o info object slots B} {::o::per-object-slot::B} ? {o eval {info exists :B}} 1 ? {o cget -B} 1000 ? {o configure -B 1001} "" ? {o cget -B} 1002 ? {o configure -B x} {expected integer but got "x" for parameter "-B"} ? {o cget -B} 1002 } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/substdefault.test000644 000766 000024 00000025631 13462406127 017754 0ustar00neumannstaff000000 000000 # -*- tcl -*- package prefer latest package req nx::test # # The state of "substdefault" in object and method parameters: # # - general # * [self] is always set correctly # # - object-parameter: # # * class-defined properties: # # - When referring to instance variables, the user has no control # over the creation order of the variables. So, we cannot # recommend this praxis. Referring to global or namespaced # variables, this problem does not exist. # # - [current class] executed directly in a subtdefault does not # return currently an expected result. calling a method that # returns [current class] works. Defining methods to get # default values is therefore recommended. # # - method-parameter: # # * It is currently possible to refer to instance variables in the # default scope (without the nsf resolver, without namespace # prefixes) nx::test case substdefaultoptions-class { set ::X 123 nx::Class create D { :property {a {a $::X [set x 4] \t}} :property {b:substdefault {a $::X [set x 4] \t}} :property {c:substdefault=0b111 {a $::X [set x 4] \t}} :property {d:substdefault=0b100 {a $::X [set x 4] \t}} :property {e:substdefault=0b010 {a $::X [set x 4] \t}} :property {f:substdefault=0b001 {a $::X [set x 4] \t}} :property {g:substdefault=0b000 {a $::X [set x 4] \t}} :public method show {v} { return [set $v] } } ? {D create d1} ::d1 #? {::d1 eval :__object_configureparameter} "" ? {d1 show :a} {a $::X [set x 4] \t} "no substdefault" ? {d1 show :b} {a 123 4 } "substdefault no options" ? {d1 show :c} {a 123 4 } "substdefault 0b111 subst all" ? {d1 show :d} {a $::X [set x 4] } "substdefault 0b100 -novars -nocommands" ? {d1 show :e} {a 123 [set x 4] \t} "substdefault 0b010 -nocommands -nobackslashes" ? {d1 show :f} {a $::X 4 \t} "substdefault 0b001 -novars -nobackslashes" ? {d1 show :g} {a $::X [set x 4] \t} "substdefault 0b000 -nocommands -novars -nobackslashes" unset ::X } # # same test cases as above, buf for object cases # nx::test case substdefaultoptions-object-slot { set ::X 123 nx::Object create d1 { :object property {a {a $::X [set x 4] \t}} :object property {b:substdefault {a $::X [set x 4] \t}} :object property {c:substdefault=0b111 {a $::X [set x 4] \t}} :object property {d:substdefault=0b100 {a $::X [set x 4] \t}} :object property {e:substdefault=0b010 {a $::X [set x 4] \t}} :object property {f:substdefault=0b001 {a $::X [set x 4] \t}} :object property {g:substdefault=0b000 {a $::X [set x 4] \t}} :public object method show {v} { return [set $v] } } ? {d1 show :a} {a $::X [set x 4] \t} "no substdefault" ? {d1 show :b} {a 123 4 } "substdefault no options" ? {d1 show :c} {a 123 4 } "substdefault 0b111 subst all" ? {d1 show :d} {a $::X [set x 4] } "substdefault 0b100 -novars -nocommands" ? {d1 show :e} {a 123 [set x 4] \t} "substdefault 0b010 -nocommands -nobackslashes" ? {d1 show :f} {a $::X 4 \t} "substdefault 0b001 -novars -nobackslashes" ? {d1 show :g} {a $::X [set x 4] \t} "substdefault 0b000 -nocommands -novars -nobackslashes" unset ::X } nx::test case substdefaultoptions-object-noslot { set ::X 123 nx::Object create d1 { :object variable a {a $::X [set x 4] \t} :object variable b:substdefault {a $::X [set x 4] \t} :object variable c:substdefault=0b111 {a $::X [set x 4] \t} :object variable d:substdefault=0b100 {a $::X [set x 4] \t} :object variable e:substdefault=0b010 {a $::X [set x 4] \t} :object variable f:substdefault=0b001 {a $::X [set x 4] \t} :object variable g:substdefault=0b000 {a $::X [set x 4] \t} :public object method show {v} { return [set $v] } } ? {d1 show :a} {a $::X [set x 4] \t} "no substdefault" ? {d1 show :b} {a 123 4 } "substdefault no options" ? {d1 show :c} {a 123 4 } "substdefault 0b111 subst all" ? {d1 show :d} {a $::X [set x 4] } "substdefault 0b100 -novars -nocommands" ? {d1 show :e} {a 123 [set x 4] \t} "substdefault 0b010 -nocommands -nobackslashes" ? {d1 show :f} {a $::X 4 \t} "substdefault 0b001 -novars -nobackslashes" ? {d1 show :g} {a $::X [set x 4] \t} "substdefault 0b000 -nocommands -novars -nobackslashes" ? {d1 object variable x:int,substdefault 1} {} ? {d1 show :x} 1 unset ::X } ####################################################### # subst default tests for method properties ####################################################### nx::test case subst-default-method-parameters { nx::Class create D { :method "current" {x} { return [current $x] } :property -accessor public {c 1} :property {d 2} :property {e 3} :create d1 :public method bar { {-s:substdefault "[current]"} {-literal "[current]"} {-c:substdefault "[:c get]"} {-d:integer,substdefault "$d"} {-e:integer,substdefault "${:e}"} {-f:substdefault "[current class]"} {-g:substdefault "[:current class]"} } { return $s-$literal-$c-$d-$e-$f-$g } } # # Interesting is arg "-d", since it resolves without a further # namespace resolver to the name of the instance variable. This can # not easily avoided, but i do not see, why we would have to. # # UNEXPECTED: For the value of "f" i would expect ::D. # ? {d1 bar -c 1} {::d1-[current]-1-2-3-::nx::test-::D} "substdefault in method parameter" # # the reason that "$d" works is due to the fact, that the method # frame has to contain the instance variables. # D public method i {{-vars:substdefault "[info vars]"}} { set localVars [info vars] set locals [info locals] return [lsort $vars]-[lsort $localVars]-[lsort $locals] } ? {d1 i} "c d e-vars-localVars vars" # # Let us change the instance variables to make sure the resolving is # dynamic. # d1 configure -c 100 -d 200 -e 300 ? {d1 bar} {::d1-[current]-100-200-300-::nx::test-::D} "substdefault in method parameter" # # To summarize, we can address instance variables in substdefault # with little syntax, and as well global variables. For other kind # of variables, we can use a method, such as e.g. in the following # case, where we have some modules "my-module" whoch might have some # configuration variables (here X), and we define a method to access # it. # namespace eval ::my-module { set X 1001 } D public method file-scoped {x} { namespace eval ::my-module [list set $x ] } D public method m {{-x:substdefault "[:file-scoped X]"}} { return $x } ? {d1 m} "1001" } ####################################################### # subst default tests for object properties ####################################################### nx::test case subst-default-object-parameters { namespace eval ::my-module { set X 1001 } nx::Class create D { :object variable Y 1002 :property {a "[current]"} :property {b:substdefault "[current]"} :property {c:substdefault "[info vars]"} :property {d:substdefault "[:info vars]"} :create d1 :public method show {} { return ${:a}-${:b}-${:c}-${:d} } } # # The scope of "current" in the substdefault is "::d1", the same as # for method parameters. # ? {d1 show} {[current]-::d1--} nx::Class create C { :object variable Y 1002 :object property -accessor public {Z 1003} namespace eval [nsf::definitionnamespace] {set A 2000} :method file-scoped {x} { namespace eval ::my-module [list set $x ] } :method "object getvar" {x} { namespace eval [current class] [list set $x ] } :method "definitionnamespace" {x} { namespace eval [nsf::definitionnamespace] [list set $x ] } :public method "current_definitionnamespace" {} { return [nsf::definitionnamespace] } :method "current" {x} { return [current $x] } :property {e:substdefault "[:file-scoped X]"} :property {f:substdefault "[:object getvar Y]"} :property {g:substdefault "[current class]"} :property {h:substdefault "[:current class]"} :property {i:substdefault "[[:current class] Z get]"} :property {j:substdefault "[:definitionnamespace A]"} :create c1 :public method show {} { return ${:e}-${:f}-${:g}-${:h}-${:i}-${:j} } } # # One can use methods to access e.h. for method parameters. # UNEXPECTED: for "g" where i would expect "::C". # ? {c1 show} {1001-1002-::nx::Class-::C-1003-2000} ? {c1 current_definitionnamespace} {::} } ####################################################### # subst default tests for object properties ####################################################### nx::test case subst-default-object-parameters-in-extra-ns { namespace eval ::my-module { set X 1001 nx::Class create D { :object variable Y 1002 :property {a "[current]"} :property {b:substdefault "[current]"} :property {c:substdefault "[info vars]"} :property {d:substdefault "[:info vars]"} :create d1 :public method show {} { return ${:a}-${:b}-${:c}-${:d} } } # # The scope of "current" in the substdefault is "::d1", the same as # for method parameters. # ? {d1 show} {[current]-::my-module::d1--} ? {nsf::definitionnamespace} ::my-module nx::Class create C { :object variable Y 1002 :object property -accessor public {Z 1003} namespace eval [nsf::definitionnamespace] {set A 2000} :method file-scoped {x} { namespace eval ::my-module [list set $x ] } :method "object getvar" {x} { namespace eval [current class] [list set $x ] } :method "definitionnamespace" {x} { namespace eval [nsf::definitionnamespace] [list set $x ] } :public method "current_definitionnamespace" {} { return [nsf::definitionnamespace] } :method "current" {x} { return [current $x] } :property {e:substdefault "[:file-scoped X]"} :property {f:substdefault "[:object getvar Y]"} :property {g:substdefault "[current class]"} :property {h:substdefault "[:current class]"} :property {i:substdefault "[[:current class] Z get]"} :property {j:substdefault "[:definitionnamespace A]"} :create c1 :public method show {} { return ${:e}-${:f}-${:g}-${:h}-${:i}-${:j} } } # # One can use methods to access e.h. for method parameters. # UNEXPECTED: for "g" where i would expect "::C". # ? {c1 show} {1001-1002-::nx::Class-::my-module::C-1003-2000} ? {c1 current_definitionnamespace} {::my-module} } } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/summary.tcl000644 000766 000024 00000002446 13216734333 016546 0ustar00neumannstaff000000 000000 # -*- Tcl -*- # # This script computes the regression test summary displayed at the # end of the regression test. It aggreates the content of the test log # provided via arg "-testlog". array set opt {-title ""} array set opt $::argv if {[info exists opt(-testlog)]} { set f [open $opt(-testlog)]; set content [read $f]; close $f lassign {0 0 0 0 0.0} tests success failures files ms foreach l [split $content \n] { array set "" $l if {[info exists (tests)]} { incr tests $(tests) incr failures $(failure) incr success $(success) incr files 1 set ms [expr {$ms + $(ms)}] } } puts "\nRegression Test Summary of $opt(-title):" puts "\tEnvironment: Tcl $tcl_patchLevel, OS $tcl_platform(os) $tcl_platform(osVersion)\ machine $tcl_platform(machine) threaded [info exists tcl_platform(threaded)]." puts "\tNSF [package req nsf] (commit [::nsf::pkgconfig get commit]) performed $tests tests in $files files, success $success, failures $failures in [expr {$ms / 1000.0}] seconds" if {$failures == 0} { puts "\tCongratulations, all tests of $opt(-title) passed in your installation of NSF [package req nsf] (commit [::nsf::pkgconfig get commit])" } puts "" } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/mixinof.test000644 000766 000024 00000041756 13462406127 016726 0ustar00neumannstaff000000 000000 # -*- Tcl -*- # testing mixinof package prefer latest package require nx package require nx::test nx::test configure -count 100 ########################################### # testing simple per object mixins ########################################### nx::test case simple-pom { nx::Class create A nx::Object create o -object-mixins A ? {o object mixins get} ::A ? {o info object mixins} ::A ? {A info mixinof} ::o o destroy ? {A info mixinof} "" } ########################################### # testing transitive per object mixins ########################################### nx::test case transitive-pom { nx::Class create B nx::Class create C -superclass B nx::Class create M B mixins set M nx::Object create o -object-mixins C nx::Object create o1 -object-mixins B ? {C info mixinof} ::o ? {lsort [B info mixinof -closure]} "::o ::o1" ? {lsort [B info mixinof -closure ::o1]} "::o1" ? {lsort [B info mixinof -closure ::o*]} "::o ::o1" ? {lsort [C info mixinof -closure ::o*]} "::o" # A class is mixed into a per-object mixin class ? {lsort [M info mixinof -closure ::o*]} "::o ::o1" ? {lsort [M info mixinof -scope object]} "" } ########################################### # testing per object mixins with redefinition ########################################### nx::test case recreate-mixin-class { nx::Class create M {:method foo args {puts x;next}} nx::Object create o -object-mixins M ? {o info object mixins} ::M ? {o info precedence} "::M ::nx::Object" ? {o info lookup method foo} "::nsf::classes::M::foo" nx::Class create M {:method foo args next} ? {o info object mixins} ::M ? {o info precedence} "::M ::nx::Object" ? {o info lookup method foo} "::nsf::classes::M::foo" M destroy ? {o info object mixins} "" ? {o info precedence} "::nx::Object" ? {o info lookup method foo} "" } ########################################### # testing simple per class mixins ########################################### nx::test case pcm { nx::Class create A nx::Class create B -mixin A nx::Class create C -superclass B C create c1 ? {B mixins get} ::A ? {B info mixins} ::A ? {A info mixinof} ::B ? {c1 info precedence} "::A ::C ::B ::nx::Object" B destroy ? {A info mixinof} "" ? {c1 info precedence} "::C ::nx::Object" } ########################################### # testing simple per class mixins with guards ########################################### nx::test case pcm2 { nx::Class create M1 nx::Class create M2 nx::Class create X nx::Class create A -mixin {M1 M2 X} A mixins guard M1 "test" nx::Class create B -superclass A ? {A info mixins M2} ::M2 ? {A info mixins M*} "::M1 ::M2" ? {A info mixins -guards} "{::M1 -guard test} ::M2 ::X" ? {B info mixins} "" ? {B info mixins -closure} "::M1 ::M2 ::X" ? {B info mixins -closure M2} ::M2 ? {B info mixins -closure M*} "::M1 ::M2" ? {B info mixins -closure -guards} "{::M1 -guard test} ::M2 ::X" ? {B info mixins -closure -guards M1} "{::M1 -guard test}" ? {B info mixins -closure -guards M*} "{::M1 -guard test} ::M2" } ########################################### # testing transitive per class mixins ########################################### nx::test case trans-pcm1 { nx::Class create A nx::Class create B -mixin A nx::Class create C -superclass B A mixins set [nx::Class create M] A create a1 B create b1 C create c1 ? {B mixins get} ::A ? {B info mixins} ::A ? {A info mixinof -scope class} ::B ? {a1 info precedence} "::M ::A ::nx::Object" ? {b1 info precedence} "::M ::A ::B ::nx::Object" ? {c1 info precedence} "::M ::A ::C ::B ::nx::Object" ? {M info mixinof -scope class} "::A" # since M is an instmixin of A and A is a instmixin of B, # M is a instmixin of B as well, and of its subclasses ? {M info mixinof -scope class -closure} "::A ::B ::C" ? {A info mixinof -scope class} "::B" ? {A info mixinof -scope class -closure} "::B ::C" ? {B info mixinof -scope class} "" ? {B info mixinof -scope class -closure} "" # and now destroy mixins M destroy ? {a1 info precedence} "::A ::nx::Object" ? {b1 info precedence} "::A ::B ::nx::Object" ? {c1 info precedence} "::A ::C ::B ::nx::Object" B destroy ? {A info mixinof -scope class} "" ? {c1 info precedence} "::C ::nx::Object" } ########################################### # testing transitive per class mixins with subclasses ########################################### nx::test case trans-pcm2 { nx::Class create X nx::Class create D nx::Class create C -superclass D nx::Class create A -mixin C nx::Class create B -superclass A B create b1 # ::C and ::D come to ::A and B as mixins ? {A info heritage} "::C ::D ::nx::Object" ? {B info heritage} "::C ::D ::A ::nx::Object" ? {C info mixinof -scope class -closure} "::A ::B" ? {D info mixinof -scope class -closure} "::A ::B" ? {A info mixinof -scope class -closure} "" ? {B info mixinof -scope class -closure} "" ? {X info mixinof -scope class -closure} "" D mixins set X ? {C info mixinof -scope class -closure} "::A ::B" ? {D info mixinof -scope class -closure} "::A ::B" ? {A info mixinof -scope class -closure} "" ? {B info mixinof -scope class -closure} "" ? {X info mixinof -scope class -closure} "::D ::C ::A ::B" ? {b1 info precedence} "::C ::X ::D ::B ::A ::nx::Object" B create b2 ? {b2 info precedence} "::C ::X ::D ::B ::A ::nx::Object" } ########################################### # testing transitive per class mixins with subclasses ########################################### nx::test case trans-pcm3 { nx::Class create A3 -superclass [nx::Class create A2 -superclass [nx::Class create A1]] nx::Class create B3 -superclass [nx::Class create B2 -superclass [nx::Class create B1 -superclass [nx::Class create B0]]] nx::Class create C3 -superclass [nx::Class create C2 -superclass [nx::Class create C1]] A2 mixins set B2 B1 mixins set C2 ? {A1 info mixinof -scope class -closure} "" ? {A2 info mixinof -scope class -closure} "" ? {A3 info mixinof -scope class -closure} "" ? {A1 info heritage} "::nx::Object" ? {A2 info heritage} "::B2 ::C2 ::C1 ::B1 ::B0 ::A1 ::nx::Object" ? {A3 info heritage} "::B2 ::C2 ::C1 ::B1 ::B0 ::A2 ::A1 ::nx::Object" ? {B0 info mixinof -scope class -closure} "::A2 ::A3" ? {B1 info mixinof -scope class -closure} "::A2 ::A3" ? {B2 info mixinof -scope class -closure} "::A2 ::A3" ? {B3 info mixinof -scope class -closure} "" ? {C1 info mixinof -scope class -closure} "::B1 ::B2 ::B3 ::A2 ::A3" ? {C2 info mixinof -scope class -closure} "::B1 ::B2 ::B3 ::A2 ::A3" ? {C3 info mixinof -scope class -closure} "" } ########################################### # testing transitive per class mixins with destroy ########################################### nx::test case pcm-trans-destroy-A { nx::Class create A -mixin [nx::Class create M] nx::Class create B -mixin A nx::Class create C -superclass B A create a1 B create b1 C create c1 ? {B mixins get} ::A ? {B info mixins} ::A ? {A info mixinof -scope class} ::B ? {a1 info precedence} "::M ::A ::nx::Object" ? {b1 info precedence} "::M ::A ::B ::nx::Object" ? {c1 info precedence} "::M ::A ::C ::B ::nx::Object" # and now destroy A A destroy ? {a1 info precedence} "::nx::Object" ? {b1 info precedence} "::B ::nx::Object" ? {c1 info precedence} "::C ::B ::nx::Object" ? {M info mixinof} "" ? {M info mixinof -closure} "" B destroy ? {M info mixinof -scope class} "" ? {c1 info precedence} "::C ::nx::Object" } ########################################### # testing transitive per class mixins with destroy ########################################### nx::test case pcm-trans-destroy-B { nx::Class create A -mixin [nx::Class create M] nx::Class create B -mixin A nx::Class create C -superclass B A create a1 B create b1 C create c1 ? {B mixins get} ::A ? {B info mixins} ::A ? {A info mixinof -scope class} ::B ? {a1 info precedence} "::M ::A ::nx::Object" ? {b1 info precedence} "::M ::A ::B ::nx::Object" ? {c1 info precedence} "::M ::A ::C ::B ::nx::Object" B destroy ? {a1 info precedence} "::M ::A ::nx::Object" ? {b1 info precedence} "::nx::Object" ? {c1 info precedence} "::C ::nx::Object" ? {M info mixinof -scope class} "::A" ? {M info mixinof -scope class -closure} "::A" ? {A info mixinof -scope class} "" } ########################################### # testing simple per class mixins with redefinition ########################################### nx::test case pcm-redefine { nx::Class create A nx::Class create B -mixin A nx::Class create C -superclass B C create c1 ? {B mixins get} ::A ? {B info mixins} ::A ? {A info mixinof -scope class} ::B ? {c1 info precedence} "::A ::C ::B ::nx::Object" ? {B info superclasses -closure} "::nx::Object" ? {C info superclasses -closure} "::B ::nx::Object" ? {B info heritage} "::A ::nx::Object" ? {C info heritage} "::A ::B ::nx::Object" nx::Class create B -mixin A ? {B info superclasses -closure} "::nx::Object" ? {C info superclasses -closure} "::nx::Object" ? {B info heritage} "::A ::nx::Object" ? {C info heritage} "::nx::Object" ? {B mixins get} ::A ? {B info mixins} ::A ? {A info mixinof} ::B ? {c1 info precedence} "::C ::nx::Object" B destroy ? {A info mixinof} "" ? {c1 info precedence} "::C ::nx::Object" } ########################################### # testing simple per class mixins with # redefinition and softrecreate ########################################### nx::test case pcm-redefine-soft { ::nsf::configure softrecreate true nx::Class create A nx::Class create B -mixin A nx::Class create C -superclass B C create c1 ? {B mixins get} ::A ? {B info mixins} ::A ? {A info mixinof -scope class} ::B ? {c1 info precedence} "::A ::C ::B ::nx::Object" ? {B info superclasses -closure} "::nx::Object" ? {C info superclasses -closure} "::B ::nx::Object" ? {B info heritage} "::A ::nx::Object" ? {C info heritage} "::A ::B ::nx::Object" nx::Class create B -mixin A ? {B info superclasses -closure} "::nx::Object" ? {C info superclasses -closure} "::B ::nx::Object" ? {B info heritage} "::A ::nx::Object" ? {C info heritage} "::A ::B ::nx::Object" ? {B info mixins} ::A ? {A info mixinof -scope class} ::B ? {c1 info precedence} "::A ::C ::B ::nx::Object" B destroy ? {A info mixinof -scope class} "" ? {c1 info precedence} "::C ::nx::Object" } ########################################### # test of recreate with same superclass, # with softrecreate off ########################################### nx::test case precedence { ::nsf::configure softrecreate false nx::Class create O nx::Class create A -superclass O nx::Class create B -superclass A B create b1 A create a1 O create o1 ? {A info superclasses} "::O" ? {B info heritage} "::A ::O ::nx::Object" ? {list [A info subclasses] [B info subclasses] [O info subclasses]} "::B {} ::A" ? {list [A info superclasses] [B info superclasses] [O info superclasses]} "::O ::A ::nx::Object" ? {list [a1 info class] [b1 info class] [o1 info class]} "::A ::B ::O" ? {o1 info precedence} "::O ::nx::Object" ? {a1 info precedence} "::A ::O ::nx::Object" ? {b1 info precedence} "::B ::A ::O ::nx::Object" # we recreate the class new, with the same superclass nx::Class create A -superclass O ? {A info superclasses} "::O" ? {B info heritage} "::nx::Object" ? {list [A info subclasses] [B info subclasses] [O info subclasses]} "{} {} ::A" ? {list [A info superclasses] [B info superclasses] [O info superclasses]} "::O ::nx::Object ::nx::Object" ? {list [a1 info class] [b1 info class] [o1 info class]} "::nx::Object ::B ::O" ? {o1 info precedence} "::O ::nx::Object" ? {a1 info precedence} "::nx::Object" ? {b1 info precedence} "::B ::nx::Object" } ########################################### # test of recreate with different superclass # with softrecreate on ########################################### nx::test case alternate-precedence { ::nsf::configure softrecreate false nx::Class create O nx::Class create A -superclass O nx::Class create B -superclass A B create b1 A create a1 O create o1 ? {A info superclasses} "::O" ? {B info heritage} "::A ::O ::nx::Object" ? {list [A info subclasses] [B info subclasses] [O info subclasses]} "::B {} ::A" ? {list [A info superclasses] [B info superclasses] [O info superclasses]} "::O ::A ::nx::Object" ? {list [a1 info class] [b1 info class] [o1 info class]} "::A ::B ::O" ? {o1 info precedence} "::O ::nx::Object" ? {a1 info precedence} "::A ::O ::nx::Object" ? {b1 info precedence} "::B ::A ::O ::nx::Object" # we recreate the class new, with a different superclass nx::Class create A ? {A info superclasses} "::nx::Object" ? {B info heritage} "::nx::Object" ? {list [A info subclasses] [B info subclasses] [O info subclasses]} "{} {} {}" ? {list [A info superclasses] [B info superclasses] [O info superclasses]} "::nx::Object ::nx::Object ::nx::Object" ? {list [a1 info class] [b1 info class] [o1 info class]} "::nx::Object ::B ::O" ? {o1 info precedence} "::O ::nx::Object" ? {a1 info precedence} "::nx::Object" ? {b1 info precedence} "::B ::nx::Object" } ########################################### # test of recreate with same superclass, # with softrecreate on ########################################### nx::test case recreate-precedence { ::nsf::configure softrecreate true nx::Class create O nx::Class create A -superclass O nx::Class create B -superclass A B create b1 A create a1 O create o1 ? {A info superclasses} "::O" ? {B info heritage} "::A ::O ::nx::Object" ? {list [A info subclasses] [B info subclasses] [O info subclasses]} "::B {} ::A" ? {list [A info superclasses] [B info superclasses] [O info superclasses]} "::O ::A ::nx::Object" ? {list [a1 info class] [b1 info class] [o1 info class]} "::A ::B ::O" ? {o1 info precedence} "::O ::nx::Object" ? {a1 info precedence} "::A ::O ::nx::Object" ? {b1 info precedence} "::B ::A ::O ::nx::Object" # we recreate the class new, with the same superclass nx::Class create A -superclass O ? {A info superclasses} "::O" ? {B info heritage} "::A ::O ::nx::Object" ? {list [A info subclasses] [B info subclasses] [O info subclasses]} "::B {} ::A" ? {list [A info superclasses] [B info superclasses] [O info superclasses]} "::O ::A ::nx::Object" ? {list [a1 info class] [b1 info class] [o1 info class]} "::A ::B ::O" ? {o1 info precedence} "::O ::nx::Object" ? {a1 info precedence} "::A ::O ::nx::Object" ? {b1 info precedence} "::B ::A ::O ::nx::Object" } ########################################### # test of recreate with different superclass # with softrecreate on ########################################### nx::test case recreate-alternate-precedence { ::nsf::configure softrecreate true nx::Class create O nx::Class create A -superclass O nx::Class create B -superclass A B create b1 A create a1 O create o1 ? {B info heritage} "::A ::O ::nx::Object" ? {list [A info subclasses] [B info subclasses] [O info subclasses]} "::B {} ::A" ? {list [A info superclasses] [B info superclasses] [O info superclasses]} "::O ::A ::nx::Object" ? {list [a1 info class] [b1 info class] [o1 info class]} "::A ::B ::O" ? {o1 info precedence} "::O ::nx::Object" ? {a1 info precedence} "::A ::O ::nx::Object" ? {b1 info precedence} "::B ::A ::O ::nx::Object" # we recreate the class new, with a different superclass nx::Class create A ? {A info superclasses} "::nx::Object" ? {B info heritage} "::A ::nx::Object" ? {B info heritage} "::A ::nx::Object" ? {list [A info subclasses] [B info subclasses] [O info subclasses]} "::B {} {}" ? {list [A info superclasses] [B info superclasses] [O info superclasses]} "::nx::Object ::A ::nx::Object" ? {list [a1 info class] [b1 info class] [o1 info class]} "::A ::B ::O" ? {o1 info precedence} "::O ::nx::Object" ? {a1 info precedence} "::A ::nx::Object" ? {b1 info precedence} "::B ::A ::nx::Object" } ########################################### # testing simple per object mixins ########################################### nx::test case nx-mixinof { nx::Class create M nx::Class create A nx::Class create C C create c1 -object-mixins A C create c2 nx::Class create C2 -mixin A C2 create c22 ? {c1 object mixins get} ::A ? {c1 info object mixins} ::A ? {lsort [A info mixinof]} "::C2 ::c1" ? {M info mixinof} "" C mixins set M #? {M info mixinof -scope object} "::c1 ::c2" ? {M info mixinof -scope object} "" ? {M info mixinof -scope class} "::C" ? {M info mixinof -scope all} "::C" ? {M info mixinof} "::C" ? {lsort [A info mixinof]} "::C2 ::c1" ? {A info mixinof -scope object} "::c1" ? {A info mixinof -scope class} "::C2" c1 destroy ? {A info mixinof} "::C2" ? {M info mixinof} "::C" C destroy ? {M info mixinof} "" } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/interp.test000644 000766 000024 00000047360 13462406127 016553 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package req nx::test proc traceStderr args { puts ">>> traceStderr HA! $args" } nx::test case hidden-cmds { global i # # Create a slave interp for testing # set i [interp create] # # Some baseline # $i eval { proc foo {} {;} } $i hide foo ? {$i eval [list info commands ::nx::Object]} "" $i eval [list set ::auto_path $::auto_path] $i eval [list package req nx] ? {$i eval [list info commands ::nx::Object]} ::nx::Object # # Tcl's hiding mechanism only applies to objects/classes in the # top-level namespace. So any non-globally namespaced ones and # nested objects are not concerned ... # $i eval {nx::Object create ::o { :public object method baz {} { return KO } :public object method destroy {} { # # sets a global variable for tracing the processing of the # app-level destructor! # set ::[namespace tail [current object]] [current class] next } }} $i eval {nx::Class create ::C { :public method destroy {} { # # sets a global variable for tracing the processing of the # app-level destructor! # set ::[namespace tail [current object]] [current class] next } :public method bar {} { return OK } }} $i eval {nx::Class create ::M { :public method foo {} { return [current object]-[:info class]-[current class] } }} ? {$i eval {info commands ::o}} ::o ? {$i eval {info commands ::C}} ::C ? {$i eval {info commands ::M}} ::M # # [interp hide] performs a partial and widely silent deletion # (Tcl_HideCommand(); note, while the idea resembles that of a # non-deleting rename, there is no C-level trace available!). The # object's Tcl_command cmdEpoch counter is increased. However, # hiding does not prune the command structure, nor does is the cmd's # client data touched. It is merely re-assigned to another, # interp-wide hash table. The object's command is no valid dispatch # target anymore ... # ? {interp hidden $i} "foo" $i hide o ? {interp hidden $i} "foo o" ? {$i eval ::o} "invalid command name \"::o\"" ? {$i eval {info commands ::o}} "" ? {interp eval $i {::C create ::c}} ::c # set some relationships to test later ... ? {interp eval $i {::C mixins add ::M}} ::M ? {interp eval $i {::C object mixins add ::M}} ::M $i hide C ? {interp eval $i {::C create ::c2}} {invalid command name "::C"} # # However, the object structure is effectively preserved within the # object system and object relations are intact, e.g., the object is # still reported as an instance of a class. # ? {$i eval {nx::Object info instances ::o}} "::o" ? {interp invokehidden $i o ::nsf::methods::object::info::class} "::nx::Object" ? {interp invokehidden $i o info class} "::nx::Object" ? {interp eval $i {c info class}} ::C ? {interp invokehidden $i C info instances ::c} ::c ? {interp invokehidden $i C info mixins} ::M # Note, for all introspections that do *not* try to convert the # Tcl_Obj into an object or a class, but treat it as a pattern (or # the like) we are fine ... ? {$i eval {M info mixinof ::C}} "::C ::C" ? {$i eval {M info mixinof -scope class ::C}} "::C" ? {$i eval {M info mixinof -scope object ::C}} "::C" # dispatch to object-provided method (with the object being hidden) ? {interp eval $i {c bar}} OK # dispatch to class-provided methods (with the class being hidden) ? {interp eval $i {c bar}} OK # dispatch to mixed-in methods (which do basic introspection on the hidden object) ... ? {interp invokehidden $i C foo} ::C-::nx::Class-::M ? {interp eval $i {c foo}} ::c-::C-::M # # 1) Implicit destruction (through NSF's exit handler) # # An important characteristic of a hidden cmd is that it is cleaned # up later than ordinary, exposed (and namespaced) commands; see # DeleteInterpProc(). Hidden commands are processed during a interp # shutdown *after* the exit handler returned! # # For testing, we shutdown the NSF object systems in our slave # interp by using nsf::finalize; to do some smoke testing of the # cleanup results. As for the cleanup procedre, this is equivalent # to: interp delete $i $i eval {nsf::finalize -keepvars} # The destructor of e.g. object o sets a global variable with the # object name. The following test checks therefore, whether the # destructor was executed. # ? {$i eval { info exists ::o }} 1 ? {$i eval {interp hidden}} foo ? {$i eval {info commands ::o}} "" ? {$i eval {info commands ::C}} "" # # Were the app-level destructors called effectively? # ? {$i eval { info exists ::o }} 1 ? {$i eval { set ::o }} "" ? {$i eval { info exists ::c }} 1 ? {$i eval { set ::c }} ::C interp delete $i } # # Explicit destruction # nx::test case hidden-cmds+explicit-delete { global i set i [interp create] $i eval [list set ::auto_path $::auto_path] $i eval { package req nx nx::Object create ::o2 { :public object method destroy {} { next return ok } }} ? {$i eval {interp hidden}} "" ? {$i eval {info commands ::o2}} ::o2 ? {$i eval {nx::Object info instances ::o2}} ::o2 ? {$i eval {nsf::object::exists ::o2}} 1 $i hide o2 ? {$i eval {interp hidden}} o2 ? {$i eval {info commands ::o2}} "" ? {$i eval {nx::Object info instances ::o2}} ::o2 ? {$i eval {nsf::object::exists ::o2}} 0 ? {interp invokehidden $i o2 destroy} "ok" ? {$i eval {interp hidden}} "" ? {$i eval {nx::Object info instances ::o2}} "" ? {$i eval {info commands ::o2}} "" ? {$i eval {nsf::object::exists ::o2}} 0 } # # hide and re-expose # nx::test case hide-and-re-expose { global i set i [interp create] $i eval [list set ::auto_path $::auto_path] $i eval { package req nx nx::Object create ::o { :public object method destroy {} { incr ::[namespace tail [current]] return OK } :public object method foo {} { return [list [current object] [current class] [:info class] [[current] info class]] } } interp hide {} o } # Check hidden state ? {interp eval $i {interp hidden}} "o" ? {interp eval $i {info commands ::o}} "" ? {interp eval $i {nx::Object info instances ::o}} ::o ? {interp eval $i {nsf::object::exists ::o}} 0 interp expose $i o # Check re-exposed state ? {interp eval $i {interp hidden}} "" ? {interp eval $i {info commands ::o}} "::o" ? {interp eval $i {nx::Object info instances ::o}} ::o ? {interp eval $i {nsf::object::exists ::o}} 1 # # Is the object "alive"? # ? {$i eval {::o foo}} {::o {} ::nx::Object ::nx::Object} $i eval {nsf::finalize -keepvars} # Was the destructor called? ? {interp eval $i {info exists ::o}} 1 ? {interp eval $i {set ::o}} 1 # Check cleaned-up state ? {interp eval $i {interp hidden}} "" ? {interp eval $i {info commands ::o}} "" interp delete $i } # # hide/re-expose with "command renaming" # nx::test case command-renaming { global i set i [interp create] $i eval [list set ::auto_path $::auto_path] $i eval { package req nx nx::Object create ::o { :public object method destroy {} { incr ::[namespace tail [current]] return OK } :public object method foo {} { catch {[current] info class} msg return [list [current object] [current class] [:info class] $msg] } } interp hide {} o O } # Check hidden state -> object command renamed ? {interp eval $i {interp hidden}} "O" ? {interp eval $i {info commands ::o}} "" ? {interp eval $i {nx::Object info instances ::o}} ::o ? {interp eval $i {nsf::object::exists ::o}} 0 ? {interp invokehidden $i O foo} \ {::o {} ::nx::Object {invalid command name "::o"}} interp expose $i O OO ? {interp eval $i {OO foo}} \ {::o {} ::nx::Object {invalid command name "::o"}} ? {interp eval $i {interp hidden}} "" ? {interp eval $i {info commands ::o}} "" ? {interp eval $i {info commands ::OO}} ::OO ? {interp eval $i {nx::Object info instances ::o}} ::o ? {interp eval $i {nx::Object info instances ::OO}} ::o ;# should be ""? ? {interp eval $i {nsf::object::exists ::o}} 0 ? {interp eval $i {nsf::object::exists ::OO}} 1 $i eval {nsf::finalize -keepvars} # Was the destructor called? ? {interp eval $i {info exists ::o}} 1 ? {interp eval $i {set ::o}} 1 ? {interp eval $i {interp hidden}} {} ? {interp eval $i {info commands ::o}} {} interp delete $i } # # Rename namespaced object to global one and hide ... # nx::test case namespaced-object { global i set i [interp create] $i eval [list set ::auto_path $::auto_path] $i eval { package req nx namespace eval ::ns1 { nx::Object create o { :public object method destroy {} { incr ::[namespace tail [current]] return OK } } } } ? {$i hide ::ns1::o} \ {cannot use namespace qualifiers in hidden command token (rename)} $i eval {::rename ::ns1::o ::X} ? {interp eval $i {interp hidden}} {} ? {interp eval $i {info commands ::X}} {::X} ? {interp eval $i {nx::Object info instances ::X}} {::X} ? {interp eval $i {nsf::object::exists ::X}} 1 $i eval {interp hide {} X} ? {interp eval $i {interp hidden}} "X" ? {interp eval $i {info commands ::X}} {} ? {interp eval $i {nx::Object info instances ::X}} {::X} ? {interp eval $i {nsf::object::exists ::X}} 0 $i eval {nsf::finalize -keepvars} ? {interp eval $i {info exists ::X}} 1 ? {interp eval $i {set ::X}} 1 interp delete $i } # # Deletion order # nx::test case deletion-order { global i set i [interp create] $i eval [list set ::auto_path $::auto_path] $i eval { package req nx nx::Object create ::o { :public object method destroy {} { incr ::[namespace tail [current]] interp invokehidden {} C destroy next } } nx::Class create ::C { :public object method destroy {} { incr ::[namespace tail [current]] next } } } $i hide o $i hide C $i eval {nsf::finalize -keepvars} ? {interp eval $i {info exists ::C}} 1 ? {interp eval $i {set ::C}} 1 ? {interp eval $i {info exists ::o}} 1 ? {interp eval $i {set ::o}} 1 interp delete $i } # # Some stumbling blocks in destructors: [error] in app-level destroy # nx::test case error-in-destroy-1 { global i set i [interp create] $i eval [list set ::auto_path $::auto_path] $i eval { package req nx nx::Object create ::o { :public object method destroy {} { error BAFF! } } interp hide {} o } ? {interp eval $i {::rename ::o ""}} \ {can't delete "::o": command doesn't exist} ? {interp invokehidden $i o destroy} "BAFF!" ? {interp eval $i {interp hidden}} "o" ? {interp eval $i {info commands ::o}} "" ? {interp eval $i {nx::Object info instances ::o}} "::o" ? {interp eval $i {nsf::object::exists ::o}} 0 $i eval {nsf::finalize} ? {interp eval $i {interp hidden}} "" ? {interp eval $i {info commands ::o}} "" interp delete $i } # # Some stumbling blocks in destructors: [interp hide] in app-level # destroy # nx::test case error-in-destroy-2 { global i set i [interp create] $i eval [list set ::auto_path $::auto_path] $i eval { package req nx proc ::bar {} { interp hide {} bar; return 1 } nx::Object create ::o { :public object method destroy {} { # # Would not be an issue in safe interps, as [interp hide] & # friends are disallowed ... # set res [catch {interp hide {} o} msg] # # TODO: a simple, uncaught 'interp hide {} o' leads to a lookup issue # and weird error handling; however, the cleanup is not # affected ... # next return OK } } } ? {interp eval $i {::bar}} 1 ? {interp eval $i {::o destroy}} OK ? {interp eval $i {interp hidden}} "bar" ? {interp eval $i {info commands ::o}} "" ? {interp eval $i {nx::Object info instances ::o}} "" ? {interp eval $i {nsf::object::exists ::o}} 0 interp delete $i } # # Some stumbling blocks in destructors: [interp hide] in app-level destroy # nx::test case error-in-destroy-3 { global i set i [interp create] $i eval [list set ::auto_path $::auto_path] $i eval { package req nx nx::Object create ::o { :public object method destroy {} { catch {::rename [current] ""} msg next return $msg } } interp hide {} o } ? {interp eval $i {::o destroy}} {invalid command name "::o"} ? {interp invokehidden $i o destroy} \ {can't delete "::o": command doesn't exist} ? {interp eval $i {interp hidden}} "" ? {interp eval $i {nx::Object info instances ::o}} "" ? {interp eval $i {info commands ::o}} "" ? {interp eval $i {nsf::object::exists ::o}} 0 interp delete $i } # # see NsfProcAliasMethod(): # Tcl_Command_cmdEpoch(tcd->aliasedCmd) # nx::test case hidden-procs-as-aliases { # # 1) hide alias proc targets # global i set i [interp create] $i eval [list set ::auto_path $::auto_path] $i eval { package req nx ::proc ::FOO args {return OK} nx::Object create o { :public object alias foo ::FOO } } ? {$i eval {o foo}} OK ? {$i hidden} "" $i hide FOO ? {$i hidden} FOO # # For now, we do not allow one to dispatch to hidden proc targets # through their method aliases as this would counteract the idea of # hiding cmds from a (safe) slave interp. As the NSF aliasing works # unrestrictedly in child (safe) interps (as opposed to [interp # invokehidden]), this would derail the essentials of the hiding # mechanism. # ? {$i eval {o foo}} {target "::FOO" of alias foo apparently disappeared} # # When exposing it again (e.g., from the master interp), we can # dispatch again; note this is currently limited to the exposing # under the original command name (!) # $i expose FOO ? {$i hidden} "" ? {$i eval {o foo}} OK $i hide FOO ? {$i hidden} FOO # # Limitation: Currently, exposing a hidden target command under a # *different* name will not re-establish the alias. This is due to # the way NsfProcAliasMethod() is currently implemented: Rebinding # an epoched cmd (which holds for renamed as well as # hidden/re-exposed cmds) is currently based on the command name # stored in the ::nsf::alias array. This metadata store is not # maintained during [interp hide|expose] operations. Using a # pointer-based (reverse) lookup based on tcd->aliasedCmd would be # possible (I did it testwise), but then we would have to revise the # current behavior of NsfProcAliasMethod() for target proc # renamings also. A non-deleting [rename] currently also interrupts # an alias binding. See the relevant tests on [rename ::foo ::foo2] # in tests/alias.test. To be consistent, and because [interp # hide|expose] is a two-step [rename], technically, we keep the # current behavior. # $i expose FOO OOF ? {$i hidden} "" ? {$i eval {o foo}} {target "::FOO" of alias foo apparently disappeared} # # Due to the alias-specific lookup scheme (::nsf::alias), we could fix # the alias manually after a command-renaming hide|expose operation: # ? {$i eval {info exists ::nsf::alias(::o,foo,1)}} 1 ? {$i eval {set ::nsf::alias(::o,foo,1)}} "::FOO" ? {$i eval {set ::nsf::alias(::o,foo,1) ::OOF}} "::OOF" ? {$i eval {info commands ::OOF}} ::OOF ? {$i eval {o foo}} OK interp delete $i unset i } nx::test case hidden-objects-as-aliases { # # 2) hide alias object targets # global i set i [interp create] $i eval [list set ::auto_path $::auto_path] $i eval { package req nx nx::Object create x { :public object method foo {} {return OK} } nx::Object create dongo { :public object alias bar ::x } } # # Objects as intermediary aliases are transparent when being # hidden|exposed; hiding and exposing them (under differing command # names) do not affect the dispatch behavior; this is due to the # ensemble dispatch strategy ... # ? {$i hidden} "" ? {$i eval {dongo bar foo}} OK $i hide x ? {$i hidden} x #? {$i eval {dongo bar foo}} OK ? {$i eval {dongo bar foo}} {target "::x" of alias bar apparently disappeared} ? {$i eval {x foo}} {invalid command name "x"} ? {$i invokehidden x foo} OK $i expose x ? {$i hidden} "" ? {$i eval {dongo bar foo}} OK ? {$i eval {x foo}} OK $i hide x X ? {$i hidden} X #? {$i eval {dongo bar foo}} OK ? {$i eval {dongo bar foo}} {target "::x" of alias bar apparently disappeared} ? {$i eval {X foo}} {invalid command name "X"} ? {$i invokehidden X foo} OK $i expose X XX ? {$i hidden} "" #? {$i eval {dongo bar foo}} OK ? {$i eval {dongo bar foo}} {target "::x" of alias bar apparently disappeared} ? {$i eval {XX foo}} OK # # Hiding of leaf methods (e.g., ::o::foo) is not an issue because # hiding|exposing is limited to global commands # ? {$i hide ::o::foo} "cannot use namespace qualifiers in hidden command token (rename)" interp delete $i unset i } # # MixinSearchProc() # nx::test case hidden-mixins-procsearch { global i set i [interp create] $i eval [list set ::auto_path $::auto_path] $i eval { package req nx nx::Object create x { :public object method foo {} {return OK} } nx::Class create M { :public method foo {} { return <[current class]>[next]<[current class]> } } x object mixins set M } ? {$i eval {x foo}} <::M>OK<::M> # # Hiding M as a command should not affect *existing* mixin # relations! # $i hide M ? {$i hidden} M ? {$i eval {x foo}} <::M>OK<::M> "with hidden mixin" $i expose M ? {$i hidden} "" ? {$i eval {x foo}} <::M>OK<::M> "with re-exposed mixin" $i hide M m ? {$i eval {x foo}} <::M>OK<::M> "with hidden mixin (renamed command)" $i expose m MM ? {$i eval {x foo}} <::M>OK<::M> "with re-exposed mixin (renamed command)" # # However, modifying mixin axes is hindered, because of # the underlying relation machinery (::nsf::relation, # RelationSlot->add(), etc.) is relying on exposed command names # (i.e., command and object look-ups based on # Tcl_GetCommandFromToken(), GetObjectFromString() usage). # $i hide MM M $i eval {nx::Class create ::M2} ? {$i eval {x object mixins add M2}} {mixin: expected a class as mixin but got "::M"} ? {$i invokehidden M mixins add M2} {expected object but got "::M" for parameter "object"} interp delete $i unset i } # # MixinComputeOrderFullList() & friends (due to # CmdListRemoveDeleted() # nx::test case hidden-mixins-mixinlists { global i set i [interp create] $i eval [list set ::auto_path $::auto_path] $i eval { package req nx nx::Object create o nx::Class create M1 nx::Class create M2 nx::Class create M3 o object mixins set {M1 M2} } ? {$i eval {o info precedence}} "::M1 ::M2 ::nx::Object" ? {$i eval {o info object mixins}} {::M1 ::M2} ? {$i hidden} "" $i hide M1 ? {$i hidden} M1 $i eval {M2 mixins add M3} ? {$i eval {o info precedence}} "::M1 ::M3 ::M2 ::nx::Object" # # Now, have the mixin list invalidated; The next time we request the list, # the mixin assembly machinery will have to deal with the hidden # mixin; and properly include it. # # We need to destroy one mixin explicitly (or add one as a per-class # mixin, or the like), as the mixin modification API would stumble # over the hidden mixin object ... # $i eval {::M2 destroy} ? {$i eval {o info precedence}} "::M1 ::nx::Object" ? {$i eval {o info object mixins}} "::M1" ? {$i invokehidden M1 info mixinof} "::o" interp delete $i unset i } nx::test case nsf-interp-basics { global i set i [::nsf::interp create] ? {$i eval {info commands ::nsf::is}} "::nsf::is" ? {interp issafe $i} 0 ? {::nsf::interp create zzz} "zzz" set i [::nsf::interp create -safe] ? {$i eval {info commands ::nsf::is}} "::nsf::is" ? {interp issafe $i} 1 } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/class-method.test000644 000766 000024 00000010036 14164660676 017636 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx::test # # The first test series without the convenience layer # nx::test case class-methods-0 { nx::Class create M1 nx::Class create C { ? {::C public class method foo {} {return foo}} "'class' is not a method defining method" :public object method f args {next} } ? {::C class mixins set M1} \ "method 'class' unknown for ::C; in order to create an instance of class ::C, consider using '::C create class ?...?'" ? {::C class filter f} \ "method 'class' unknown for ::C; in order to create an instance of class ::C, consider using '::C create class ?...?'" ? {lsort [::C info object methods]} "f" ? {lsort [::C info]} \ "valid submethods of ::C info: baseclass children class filters has heritage info instances lookup method methods mixinof mixins name object parent precedence slots subclasses superclasses variable variables vars" } # # require the convenience layer # and make it verbose # package require nx::class-method nx::configure class-method-warning on nx::test case class-methods-1 { nx::Class create M1 nx::Class create ::C { :public class method foo {} {return [:pm1]} :public class method f args {next} :protected class method pm1 args {return pm1} :public class alias a ::C::pm1 :public class forward fwd %self pm1 :private class method priv args {return priv} :class method pm2 args {return pm2} :class property -accessor public p :class variable v1 1 :class variable -incremental v2:integer 1 # # public, protected, private # alias, forward # } ? {::C info object methods} "v2 p foo fwd a f" ? {lsort [::C info object methods -callprotection protected]} "pm1 pm2" ? {lsort [::C info object methods -callprotection private]} "priv" ? {::C class info methods} "v2 p foo fwd a f" ? {lsort [::C class info methods -callprotection protected]} "pm1 pm2" ? {lsort [::C class info methods -callprotection private]} "priv" ? {::C class info variables} "::C::per-object-slot::v2 ::C::per-object-slot::p" ? {::C info object variables} "::C::per-object-slot::v2 ::C::per-object-slot::p" ? {::C class info slots} "::C::per-object-slot::v2 ::C::per-object-slot::p" ? {::C pm1} \ "method 'pm1' unknown for ::C; in order to create an instance of class ::C, consider using '::C create pm1 ?...?'" ? {::C foo} "pm1" ? {::C a} "pm1" ? {::C fwd} "pm1" ? {::C class mixins set M1} ::M1 ? {::C class info mixins} ::M1 ? {::C class mixins set ""} "" ? {::C class info mixins} "" ? {::C class filters set f} f ? {::C class info filters} f ? {::C class filters set ""} "" ? {::C class info filters} "" ? {lsort [::C info object methods]} "a f foo fwd p v2" ? {lsort [::C info]} \ "valid submethods of ::C info: baseclass children class filters has heritage info instances lookup method methods mixinof mixins name object parent precedence slots subclasses superclasses variable variables vars" } # # delete class method, class property, class variable # nx::test case class-methods-2 { nx::Class create ::C { :public class method foo {} {return foo} :class property -accessor public p :class variable -incremental v1:integer 1 } ? {C class info methods} "p foo v1" ? {C class info variables} "::C::per-object-slot::p ::C::per-object-slot::v1" ? {C class delete method foo} "" ? {C class info methods} "p v1" ? {C class info variables} "::C::per-object-slot::p ::C::per-object-slot::v1" ? {C class delete property p} "" ? {C class info methods} "v1" ? {C class info variables} "::C::per-object-slot::v1" ? {C class delete variable v1} "" ? {C class info methods} "" ? {C class info variables} "" } # # require method # nx::test case class-methods-2 { nsf::method::provide set {::nsf::method::alias set -frame object ::set} nx::Class create ::C { :require class method set } ? {C class info methods} "set" ? {C info object methods} "set" } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/double-alias.test000644 000766 000024 00000016144 13230243321 017573 0ustar00neumannstaff000000 000000 package prefer latest package require nx::test nx::test case alias-redefine-method1 { # # redefine an object method by an alias pointing to an alias # proc ::foo args {;} nx::Object create o ? {::o public object method BAR {} {;}} ::o::BAR ? {::nsf::method::alias ::o bar ::foo} ::o::bar ? {info commands ::o::bar} ::o::bar "::o::bar exists" ? {info commands ::o::BAR} ::o::BAR "a command ::o::BAR exists" ? {::nsf::method::alias o BAR ::o::bar} ::o::BAR "redefine an object method with an alias (pointing to an alias) 87a2" } nx::test case alias-redefine-method2 { # # redefine an object method by an alias pointing to an object method # proc ::foo args {;} nx::Object create o ? {::o public object method BAR {} {;}} ::o::BAR ? {::o public object method FOO {} {;}} ::o::FOO ? {info commands ::o::FOO} ::o::FOO "a command ::o::FOO exists" ? {info commands ::o::BAR} ::o::BAR "a command ::o::BAR exists" ? {::nsf::method::alias o BAR ::o::FOO} ::o::BAR "redefine an object method with an alias (pointing to a method) 87a2" } nx::test case alias-double-alias-proc { proc ::foo args {;} nx::Object create o ? {info commands ::o::FOO} "" "a command ::o::FOO' does not exist" ? {info commands ::o::BAR} "" "a command ::o::BAR does not exist" ? {::nsf::method::alias o FOO ::foo} ::o::FOO "define an object alias based on existing ::foo" ? {::nsf::method::alias o BAR ::o::FOO} ::o::BAR "define an object alias based on alias based on existing ::o::FOO" } nx::test case alias-double-alias-define { # # same as alias-double-reference-proc, but method instead of proc as target of o::FOO # proc ::foo args {;} nx::Object create o ? {::nsf::method::alias ::o bar ::foo} ::o::bar ? {info commands ::o::bar} ::o::bar "::o::bar exists" ? {info commands ::o::FOO} "" "a command ::o::FOO' does not exists" ? {info commands ::o::BAR} "" "a command ::o::BAR does not exist" ? {::nsf::method::alias o FOO ::o::bar} ::o::FOO "define an object alias based on existing ::o::bar" ? {::nsf::method::alias o BAR ::o::FOO} ::o::BAR "define an object alias based on alias based on existing (?) ::o::bar" } nx::test case alias-double-alias-redefine { # # same as alias-double-reference-define, but redefined instead of new definition # proc ::foo args {;} nx::Object create o ? {::nsf::method::alias ::o FOO ::foo} ::o::FOO ? {::nsf::method::alias ::o bar ::foo} ::o::bar ? {info commands ::o::bar} ::o::bar "::o::bar exists" ? {info commands ::o::FOO} ::o::FOO "a command ::o::FOO' exists" ? {info commands ::o::BAR} "" "a command ::o::BAR does not exist" ? {::nsf::method::alias o FOO ::o::bar} ::o::FOO "redefine an object alias based on existing ::o::bar" ? {::nsf::method::alias o BAR ::o::FOO} ::o::BAR "define an object alias based on alias based on existing ::o::FOO" } nx::test case alias-double-alias-redefine0 { # # same as alias-double-reference-define, but redefined second cmd instead of new definition # proc ::foo args {;} nx::Object create o ? {::o public object method BAR {} {;}} ::o::BAR ? {::nsf::method::alias ::o bar ::foo} ::o::bar ? {info commands ::o::bar} ::o::bar "::o::bar exists" ? {info commands ::o::FOO} "" "a command ::o::FOO' does not exist" ? {info commands ::o::BAR} ::o::BAR "a command ::o::BAR exists" ? {::nsf::method::alias o FOO ::foo} ::o::FOO "define an object alias based on existing ::foo" ? {::nsf::method::alias o BAR ::o::FOO} ::o::BAR "redefine an object alias based on alias based on existing ::o::FOO 87a2" } nx::test case alias-double-alias-redefine1 { # # same as alias-double-reference-define, but redefined second cmd instead of new definition # proc ::foo args {;} nx::Object create o ? {::o public object method BAR {} {;}} ::o::BAR ? {::nsf::method::alias ::o bar ::foo} ::o::bar ? {info commands ::o::bar} ::o::bar "::o::bar exists" ? {info commands ::o::FOO} "" "a command ::o::FOO' does not exist" ? {info commands ::o::BAR} ::o::BAR "a command ::o::BAR exists" ? {::nsf::method::alias o FOO ::o::bar} ::o::FOO "define an object alias based on existing ::o::bar" ? {::nsf::method::alias o BAR ::o::FOO} ::o::BAR "redefine an object alias based on alias based on existing ::o::FOO 87a2" } nx::test case alias-double-alias-redefine2 { # # same as alias-double-reference-define, but redefined twice instead of new definition # proc ::foo args {;} nx::Object create o ? {::nsf::method::alias ::o FOO ::foo} ::o::FOO ? {::o public object method BAR {} {;}} ::o::BAR ? {::nsf::method::alias ::o bar ::foo} ::o::bar ? {info commands ::o::bar} ::o::bar "::o::bar exists" ? {info commands ::o::FOO} ::o::FOO "a command ::o::FOO' exists" ? {info commands ::o::BAR} ::o::BAR "a command ::o::BAR exists" ? {::nsf::method::alias o FOO ::o::bar} ::o::FOO "redefine an object alias based on existing ::o::bar" ? {::nsf::method::alias o BAR ::o::FOO} ::o::BAR "redefine an object alias based on alias based on existing ::o::FOO 87a2" } nx::test case alias-double-alias-object-method-redefine { proc ::foo args {;} nx::Object create o ? {::nsf::method::alias ::o FOO ::foo} ::o::FOO ? {::o public object method bar {} {;}} ::o::bar ? {info commands ::o::bar} ::o::bar "handle ::o::bar exists" ? {info commands ::o::FOO} ::o::FOO "a command ::o::FOO' exists" ? {info commands ::o::BAR} "" "a command ::o::BAR does not exist" ? {::nsf::method::alias o FOO ::o::bar} ::o::FOO "redefine an object alias based on existing (?) ::o::bar" ? {::nsf::method::alias o BAR ::o::FOO} ::o::BAR "define an object alias based on alias based on existing ::o::FOO" ? {info exists ::nsf::alias(::o,FOO,1)} 1 ? {info exists ::nsf::alias(::o,BAR,1)} 1 o public object method bar {} {} ? {info exists ::nsf::alias(::o,FOO,1)} 1 ? {info exists ::nsf::alias(::o,BAR,1)} 1 } nx::test case alias-double-alias-object-method-redefine2 { proc ::foo args {;} nx::Object create o ? {::nsf::method::alias ::o FOO ::foo} ::o::FOO ? {::o public object method BAR {} {;}} ::o::BAR ? {::o public object method bar {} {;}} ::o::bar ? {info commands ::o::bar} ::o::bar "handle ::o::bar exists" ? {info commands ::o::FOO} ::o::FOO "a command ::o::FOO' exists" ? {info commands ::o::BAR} ::o::BAR "a command ::o::BAR does not exist" ? {::nsf::method::alias o FOO ::o::bar} ::o::FOO "redefine an object alias based on existing (?) ::o::bar" ? {::nsf::method::alias o BAR ::o::FOO} ::o::BAR "redefine an object alias based on alias based on existing ::o::FOO 87a2" } ./nsf2.4.0/tests/cmdresolution.test000644 000766 000024 00000005042 13462406127 020130 0ustar00neumannstaff000000 000000 # -*- Tcl -*- # # testing cmd resolution # package prefer latest package require nx package require XOTcl package require nx::test # # Tests leading to bug-report concerning shared cmd literals in the # global literal pool: https://core.tcl-lang.org/tcl/tktview?name=d4e7780ca1 # ::nx::test case cmd-resolver-1 { namespace eval ::xowiki {} nx::Class create ::xowiki::C { :public method foo {} {return [self]} :create c1 } # # By calling foo, the body of this method is compiled, and the cmd # literal "self" is resolved against "nx::self" in the namespace # "::xowiki". # ? {c1 foo} ::c1 xotcl::Class create xowiki::Link xowiki::Link instproc init {} { #namespace which self catch {set c [self class]} errorMsg #nsf::__db_show_obj self set class [self class] } # When creating an instance of the xotcl class "xowiki::Link", the # constructor "init" is compiled. In this step the command literal # "self" in the constructor has to be resolved against the # underlying object system (here xotcl::self) without interacting # with "nx::self" from above. ? {xowiki::Link create l1} ::l1 # xowiki::Link ::nsf::methods::class::info::method disassemble init } ::nx::test case cmd-resolver-2 { namespace eval ::xowiki {} # # This test is similar to cmd-resolver-1, be we test now for "self" # and "next" # nx::Class create xowiki::C1 { :public method foo {x y} {set s [self]; return $x-$y-C1} } nx::Class create xowiki::C2 -superclass xowiki::C1 { :public method foo {x y} {return [next [list $x $y]]} } # # During the execution of the command below, "next" and "self" are # added to the global command literal pool for the namespace # "xowiki". # ? {[xowiki::C2 new] foo 1 2} 1-2-C1 # # Create similar classes for XOTcl # xotcl::Class create xowiki::X1 xowiki::X1 instproc foo {x y} { return $x-$y-[self class] } xotcl::Class create xowiki::X2 -superclass xowiki::X1 xowiki::X2 instproc foo {x y} { return [next $x $y] } # # Bytecompile and execute the "foo" methods containing the cmd # literals "self" and "next" in the xotcl classes # ? {[xowiki::X2 new] foo 1 2} 1-2-::xowiki::X1 # # Any kind of shimmering in the global literal pool would no help, # since C2 still needs the nx variants of "self" and "next". # ? {[xowiki::C2 new] foo 1 2} 1-2-C1 # xowiki::Link ::nsf::methods::class::info::method disassemble init } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/tcl86.test000644 000766 000024 00000023310 14274463622 016204 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx package require nx::test # just 8.6 or newer if {[info command yield] eq ""} return # # Test coroutine / yield # nx::test case number-generator { nx::Object create ::numbers { # set instance variable used in coroutine set :delta 2 :public object method ++ {} { yield set i 0 while 1 { yield $i incr i ${:delta} } } } # create coroutine coroutine nextNumber ::numbers ++ set ::j 0 # use coroutine for {set i 0} {$i < 10} {incr i} { incr ::j [nextNumber] } # remove coroutine rename nextNumber {} ? {set ::j} 90 } # # Test coroutine / yield # nx::test case enumerator1 { # # enumerator with yield in a single class # nx::Class create Enumerator { :property members:0..n :public method yielder {} { yield [info coroutine] foreach m ${:members} { yield $m } return -level 2 -code break } :public method next {} {${:coro}} :method init {} { :require namespace set :coro [coroutine [self]::coro [self] yielder] } } # # Some application class using the enumerator (just used for easy # testing) # nx::Class create Foo { :public method sum {} { set sum 0 set e [Enumerator new -members {1 2 3}] while 1 { incr sum [$e next] } return $sum } :create f1 } ? {f1 sum} 6 } nx::test case enumerator2 { # # Define separate classes for Yielder and Enumerator # nx::Class create Yielder { :property {block ";"} :variable continuation "" # # make apply available as a method # :public alias apply ::apply # # The method "yielder" is the working horse for next. We need this # since the interface of Tcl's coroutines is based on a separate # cmd for continuation in the coroutine. The block can be # configured by application classes. # :public method yielder {} { yield [info coroutine] eval ${:block} return -level 2 -code break } # # The method "next" simply forwards to the continuation # :public method next {} {${:continuation}} # # The method "each" is based on the method "next" and applies the # value returned by next to the lambda expression # :public method each {var body} { while 1 { uplevel [list set $var [:next]] uplevel $body } } # # When a yielder is generated, we create automatically a coroutine # for it. The coroutine is placed under the current object, this # ensures simple cleanup (but is most probably not the fastest # variant, since we have to require a namespace). # :method init {} { :require namespace set :continuation [coroutine [self]::coro [self] yielder] } } # # The class "Enumerator" provides some application logic for the # class "Yielder". We use here a list of elements as base # representation. # nx::Class create Enumerator -superclass Yielder { :property members:0..n :property {block { foreach m ${:members} { yield $m } }} } # # Some application class using the enumerator (just used for easy # testing) # nx::Class create Foo { # test Enumerator.next :public method sum {} { set sum 0 set e [Enumerator new -members {1 2 3}] while 1 { incr sum [$e next] } return $sum } :public method set {var} { set :$var } # test Enumerator.each :public method concat {} { set string "-" set i 0 set e [Enumerator new -members {a be bu}] $e each x { append string $x-([incr i])- } return $string } :create f1 } ? {f1 sum} 6 ? {f1 concat} "-a-(1)-be-(2)-bu-(3)-" # # Define a class ATeam that uses "Enumerator", refines the method # "each" and adds another method "concat" # nx::Class create ATeam -superclass Enumerator { # # Overload "each" to show overloading. Here, we simply capitalize # the members in the "each" method. # :public method each {var body} { while 1 { set value [string totitle [:next]] uplevel [list set $var $value] uplevel $body } } # Define some arbitrary method using ATeam.each :public method concat {} { set string "-" :each x { append string $x- } return $string } } ATeam create a1 -members {alice bob caesar} ? {a1 concat } "-Alice-Bob-Caesar-" } # # apply # nx::test case apply { # Register apply as an alias ::nx::Object public alias apply ::apply ::nx::Object create o { # Set an object variable set :delta 100 # Define a standard map function based on apply :public object method map {lambda values} { set result {} foreach value $values { lappend result [:apply $lambda $value] } return $result } :object method foo {x} {return $x-$x} } # Two examples from the apply man page ? {o map {x {return [string length $x]:$x}} {a bb ccc dddd}} \ "1:a 2:bb 3:ccc 4:dddd" ? {o map {x {expr {$x**2 + 3*$x - 2}}} {-4 -3 -2 -1 0 1 2 3 4}} \ "2 -2 -4 -4 -2 2 8 16 26" ## Test case accessing object specific variable #? {o map {x {::nsf::__db_show_stack; return [expr {$x * ${:delta}}]}} {-4 -3 -2 -1 0 1 2 3 4}} \ # "-400 -300 -200 -100 0 100 200 300 400" # Test case accessing object specific variable ? {o map {x {expr {$x * ${:delta}}}} {-4 -3 -2 -1 0 1 2 3 4}} \ "-400 -300 -200 -100 0 100 200 300 400" # Test case calling own method via apply ? {o map {x {:foo $x}} {hello world}} \ "hello-hello world-world" } # # The corrected cmd-literal semantics regarding cmd resolvers will # only be released starting from and including 8.6.7. # if {![package vsatisfies [package req Tcl] 8.6.7]} {return} set tcl87 [package vsatisfies [package req Tcl] 8.7-] nx::test case bug-3418547 { # # See https://core.tcl-lang.org/tcl/tktview?name=3418547fff # ? {info commands "::@"} "" proc getType {x} {dict get [::nsf::__db_get_obj @] type} ? {getType @} "" ;# "@" has no type ? {namespace which @} "" if {!$::tcl87} { ? {getType @} "cmdName" ;# "@" is of type "cmdName" } ? {@} {invalid command name "@"} ? {getType @} "bytecode" ;# "@" is of type "bytecode" # # 1) Provide @ for interp resolver in NX root namespace # proc ::nx::@ {} { return ::nx::@ } nx::Object create ::o { :public object method foo {} { @; # Should resolve against ::nx::@ (by interp resolver) } } ? {getType @} "bytecode" ;# "@" is still of type "bytecode" ::o foo ? {getType @} "bytecode" ;# "@" is still of type "bytecode" (byte code compilation should not leak) ? {::o foo} ::nx::@ ;# "@" is resolved in the nx context, therefore, we get nx::@ # # 2) Provide alternative @ # proc ::@ {} { return ::@ } ? {info commands ::@} "::@" ? {::@} ::@ ? {getType @} "bytecode" ;# "@" is still of type "bytecode" set x [@] ;# execute "@" in an nx environment ("eval" of the test case) ? {getType @} "cmdName" ;# "@" is of type "cmdName" ? [list $x] ::nx::@ ? @ ::@ ;# proc "?" interprets "@" as a script and turns "@" ;# into type "bytecode". The proc leaves the nx context ;# by using a "namespace eval", therefore, we see ::@ ? {getType @} "bytecode" ;# "@" is of type "bytecode" ? {namespace eval :: @} ::@ ;# exercise the same "namespace eval" as described above ? {namespace eval :: ::@} ::@ ;# the same with the global namespace qualifier ? {getType @} "bytecode" ;# "@" is of type "bytecode" ? {getType ::@} "bytecode" ;# "::@" is of type "bytecode" ? {namespace origin @} ::@ ;# "namespace origin" converts literal "@" from "bytecode" to "cmdName" ? {getType @} "cmdName" ? {namespace origin ::@} ::@ ? {getType @} "cmdName" ? {getType ::@} "cmdName" ? {@} ::@ ;# the result is still the same as everywhere, since we are in an nx context XXX } # # Without nx context # nx::test case bug-3418547-no-context proc getType {x} {dict get [::nsf::__db_get_obj @] type} # delete the commands rename @ "" rename ::nx::@ "" ? {info commands "::@"} "" ? {getType @} "" ? {namespace which @} "" if {!$::tcl87} { ? {getType @} "cmdName" } ? {@} {invalid command name "@"} # # 1) Provide proc @ # proc ::@ {} { return ::@ } ? {@} ::@ if {!$::tcl87} { ? {getType @} "cmdName" } # # 2) Provide @ for interp resolver in NX root namespace # proc ::nx::@ {} { return ::nx::@ } set r [@] ;# "@" is not executed in an nx environment (no testcase eval), therefore, resolved globally ? {set r} ::@ if {!$::tcl87} { ? {getType @} "cmdName" } nx::Object create ::o { :public object method foo {} { @ ; # resolve against ::nx::@ (via interp resolver) } } set r [::o foo] ? {set r} ::nx::@ if {!$::tcl87} { ? {getType @} "cmdName" } ? {::o foo} ::nx::@ set r [@] ;# "@" is not executed in an nx environment (no testcase eval), therefore, resolves globally ? {set r} ::@ ? {@} ::@ ;# "@" is executed in an "namespace eval ::", therefore, no nx context # cleanup rename ::nx::@ "" rename @ "" # # Try to reconstruct test case of Tcl's resolver.test 1.6 # nx::test case resolver-1.6 proc ::@@ {} {return ::@@} proc ::nx::@ {} { return ::nx::@ } nx::Object create ::o { :public object method foo {} { @ ; # resolve against ::nx::@ (via interp resolver) } } set r [::o foo] ? {set r} ::nx::@ interp alias {} ::nx::@ {} ::@@ # call the new aliased definition ? {::nx::@} ::@@ # see consistent results from method foo set r [::o foo] ? {set r} ::@@ ./nsf2.4.0/tests/contains.test000644 000766 000024 00000011654 14274463622 017072 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx set ::tcl86 [package vsatisfies [package req Tcl] 8.6-] # # Intentionally, we do not want to make a "namespace import" in this # test file. Run this file via a pure tclsh! # namespace path nx # Don't use test, since both, package test and contains redefine "new", # so we have a conflict.... proc ? {cmd expected {msg ""}} { #puts "??? $cmd" set r [uplevel $cmd] if {$msg eq ""} {set msg $cmd} if {$r ne $expected} { puts stderr "ERROR $msg returned '$r' ne '$expected'" error "FAILED $msg returned '$r' ne '$expected'" } else { puts stderr "OK $msg" } } # # We define here a few attributes of type method, such we can add # arbitrary "-" calls # Class create Tree { :property label :property contains:alias :property foo:alias :public method foo {arg} {set :x $arg} } set y [Tree new -foo hu] ? [list $y eval {set :x}] hu # # actually, the intention was to define an xotcl-like -contains # set x [Tree create 1 -label 1 -contains { ? {self} ::1 ? {namespace current} ::1 Tree create 1.1 -label 1.1 Tree create 1.2 -label 1.2 -contains { ? {self} ::1::1.2 ? {namespace current} ::1::1.2 Tree create 1.2.1 -label 1.2.1 Tree create 1.2.2 -label 1.2.2 -contains { Tree create 1.2.2.1 -label 1.2.2.1 ? {self} ::1::1.2::1.2.2 } Tree create 1.2.3 -label 1.2.3 } Tree create 1.3 -label 1.3 }] set x [Tree create t -contains { ? {Tree create branch} ::t::branch ? {Tree new} ::t::__#1 }] # # error and errorcode propagation from within contains # Class create Arbre ? {catch {Arbre create root { :contains { Arbre create level1 { :contains { Arbre level2 } } } }} msg opts; set msg} "method 'level2' unknown for ::Arbre; in order to create an instance of class ::Arbre, consider using '::Arbre create level2 ?...?'" Class create Arbre ? {catch {Arbre create root { :contains { Arbre create level1 { :contains { return -code error -errorcode MYERR } } } }} msg opts; dict get $opts -errorcode} "MYERR" # # Test resolving next without namespace import/path # namespace path "" # make sure, we have no "::next" defined or globally imported ? {info command ::next} "" nx::Class create C { :public method foo {} {next; return 12} :create c1 } ? {c1 foo} 12 ? {c1 foo} 12 C create c2 { set :s [self] set :c [current] :public object method bar {} {return "[set :s]-[set :c]"} } ? {c2 bar} "::c2-::c2" # # Test potential crash, when methodNamePath is computed without a # stack frame # C public method foo {{-new 0} name value} { return $value} catch {c1 foo -name a b} errMsg ? {set errMsg} \ {invalid argument 'b', maybe too many arguments; should be "::c1 foo ?-new /value/? /name/ /value/"} # Test resolving of implicit namespaces in relationcmds (here # superclass) in the nx namespace. namespace path "" namespace eval ::nx { #puts stderr =====1 set c [Class create C -superclass Class { :object method foo {} {;} }] ? {set c} ::C # recreate set c [Class create C -superclass Class ] ? {set c} ::C #puts stderr =====3 } # # Forget and reload nx # #puts ====NX-[package versions nx]-[set auto_path] package forget nx package req nx #puts ====XOTCL-[package versions XOTcl]-[set auto_path] package require XOTcl 2.0 package forget XOTcl package require XOTcl 2.0 ######################################################################## # # Test that we do not allow one to mix object systems within the intrinsic # classes of an object. Otherwise we would have problems with the # recreate "C0 create c0". On a recreate of c0 the object system for # C0 is ::xotcl, therefore, we try to call recreate. In the C0 class # hierarchy is from nx and contains no "recreate" method. ? {catch {::xotcl::Class create C0 -superclass ::nx::Object} errorMsg} 1 ? {set ::errorMsg} {class "::C0" has a different object system as class "::nx::Object"} ::nx::Class create C1 -superclass ::nx::Object # trigger the call of "cleanup" to work via method dispatch ::xotcl::Object create o1 o1 proc cleanup {} {puts stderr "CLEANUP"; return} #C0 create c0 #C0 create c0 C1 create c1 C1 create c1 c1 destroy C1 destroy ? {nx::Object create o} ::o ? {o contains { nx::Object create p}} ::o::p ? {catch {o contains { return -code error -errorcode {FOO bar baz} somethingwrong}} errorMsg} 1 set ::errorinfo $::errorInfo set ::errorcode $::errorCode ? {set ::errorMsg} {somethingwrong} if {$::tcl86} { set r {somethingwrong while executing "o contains { return -code error -errorcode {FOO bar baz} somethingwrong}"} } else { set r {somethingwrong ::o ::nx::Object->contains invoked from within "o contains { return -code error -errorcode {FOO bar baz} somethingwrong}"} } ? {set ::errorinfo} $r ? {set ::errorcode} {FOO bar baz} puts stderr "====EXIT [info script]" # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/tcloo.test000644 000766 000024 00000022015 13712264152 016356 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package req nx package req nx::test # # export | unexport # # TclOO provides a bulk declarator to export (i.e., make # visible and accessible) and to unexport (i.e., make invisible and # inaccessible) method features of an object, a class, or a class # hierarchy. Note that export and unexport go beyond applying mere # visibility/accessibility modifiers; it is also about extending or # reducing the public method interface of an object along the # linearization path (or of derived, intermediary classes in an # inheritance hierarchy). This export|unexport can be realized by # assembling some NSF building blocks: method call protection, # selective next forwarding, ... # # Internally, exporting a TclOO method means adding to its C-level # rep's flags PUBLIC_METHOD; unexporting consists of withdrawing it # (again). An unexported, non-public TclOO method can only me invoked # upon through a self send (i.e., the my command). This corresponds # somewhat to NSF's call protection property. In addition, [export] or # [unexport] extends the method record of an object (or class) type in # case the method to be exported or to be unexported has not yet been # defined (on the exporting or unexporting object or class). These # "extension methods", however, are mere method stubs, they do not # contain a method implementation (a proc). Without any invokable # method impl, they are skipped during method dispatch (as in an # implicit next call). Using the method stubs, the public interface # (i.e., the interface dispatchable through an object's Tcl_command) # can be extended or shrunk by selectively enabling or disabling # shadowed (inherited) method implementations along the instande-of or # the inheritance relationships. Exported or unexported, yet # unimplemented methods are treated as unknowns. # # Below is a prototype implementation of the export|unexport feature # for NSF/Nx. The realization is complete as testable through the # respective TclOO test cases in oo.test, test cases 4.1-4.6. The # export|unexport stub methods are fully reported by NSF/Nx method # introspection, as they are in TclOO. nsf::proc methodExport {current {-perObject:switch false} {-callProtected:switch false} args} { set scope [expr {$perObject?"object":"class"}] foreach m $args { set methodHandle [::nsf::dispatch $current \ ::nsf::methods::${scope}::info::method registrationhandle $m] if {$methodHandle eq ""} { set methodHandle [::nsf::method::create $current {*}[expr {$perObject?"-per-object":""}] $m args { if {[::nsf::current nextmethod] eq ""} { return -code error "[::nsf::current]: unable to dispatch method '[::nsf::current method]'" } ::nsf::next }] } ::nsf::method::property $current $methodHandle call-protected $callProtected } return } nx::Object public method export args { methodExport [::nsf::current] -perObject {*}$args } nx::Class public method export args { methodExport [::nsf::current] {*}$args } nx::Object public method unexport args { methodExport [::nsf::current] -perObject -callProtected {*}$args } nx::Class public method unexport args { methodExport [::nsf::current] -callProtected {*}$args } nx::Class create ExportUnexportUtil { :public method class {what args} { if {$what in {export unexport}} { return [::nsf::dispatch [current] ::nsf::classes::nx::Object::$what {*}$args] } ::nsf::next } } nx::Class mixins add ExportUnexportUtil nx::test case export { # # Exporting existing, non-inherited method (see TclOO tests, # oo.test, oo-4.1) # set o [nx::Object new] $o object method Foo {} { return [::nsf::current method]} ? [list $o Foo] "$o: unable to dispatch method 'Foo'" ? [list $o eval {:Foo}] Foo $o export Foo ? [list $o Foo] "Foo" ? [list $o eval {:Foo}] Foo # # A solitary, preemptive [export]: In TclOO, [::oo::define export] # creates a method record entry which does not have any # implementation (body) attached and which is deprived of its property of # a PUBLIC_METHOD. This non-implemented, body-less method (if not # succeeded by an implemented one) will be reported as unknown # method (see e.g. TclOO tests, oo.test, oo-4.3) # # As we actually simulate the TclOO non-implemented method record # entries by full-fledged NSF methods, with a specific body (a next # call), we need to handle the solitary case, i.e., the case when # there is no method implementation available. We do so by # inspecting whether there is a next method to be called; if not, we # throw an unknown error. # ? [list $o bar] "$o: unable to dispatch method 'bar'" "bar is neither defined, nor declared exported" $o export bar ? [list $o bar] "$o: unable to dispatch method 'bar'" "bar is exported, yet not defined anywhere" ? [list $o eval {:bar}] "$o: unable to dispatch method 'bar'" "bar is exported, yet not defined anywhere (self send)" # # Exporting a per-class method from one of the class' instances (see # TclOO tests, oo.test, oo-4.4) # Class create testClass { # protected (non-exported) by default :method Good {} { return ok } :method Fine {} { return OK } :method Finest {} {return ko } :create testObject } ? {testObject Good} "::testObject: unable to dispatch method 'Good'" ? {testObject eval {:Good}} ok testObject export Good ? {testObject Good} ok # # Exporting a per-class method from within the class # ? {testObject Fine} "::testObject: unable to dispatch method 'Fine'" ? {testObject eval {:Fine}} OK testClass export Fine ? {testObject Fine} OK ? {testObject eval {:Fine}} OK # # Exporting a per-class method by a subclass # Class create anotherTestClass -superclass testClass { :create anotherTestObject } ? {anotherTestObject Finest} "::anotherTestObject: unable to dispatch method 'Finest'" anotherTestClass export Finest ? {anotherTestObject Finest} ko # # export creates ordinary methods, to be replaced by subsequent # once, see TclOO tests, oo.test, oo-4.5 # nx::Object create bran { :export foo :public object method foo {} {return ok} } ? {bran foo} ok bran eval { :unexport foo } ? {bran foo} "::bran: unable to dispatch method 'foo'" } nx::test case unexport { # A solitary, preemptive [unexport]: see description for the # corresponding [export] case set p [Object new] ? [list $p bar] "$p: unable to dispatch method 'bar'" $p unexport bar ? [list $p bar] "$p: unable to dispatch method 'bar'" ? [list $p eval {:bar}] "$p: unable to dispatch method 'bar'" # # unexport existing, non-inherited method (see TclOO tests: # oo.test/oo-4.2) # set o [nx::Object new] $o public object method foo {} { return [::nsf::current method]} ? [list $o foo] foo ? [list $o eval {:foo}] foo $o unexport foo ? [list $o foo] "$o: unable to dispatch method 'foo'" "foo was made 'protected'" ? [list $o eval {:foo}] foo "foo is still available for self sends" # # unexport any (e.g., inherited) methods # Class create C { :public method foo {} {return ok} } set c [C new] ? [list $c foo] ok ? [list $c eval {:foo}] ok $c unexport foo ? [list $c foo] "$c: unable to dispatch method 'foo'" "created a protected dummy" ? [list $c eval {:foo}] ok "foo is still available for self sends (through a next send in the dummy)" # # unexport existing method at the class level # C eval { :public method bar {} {return OK} :public method baz {} {return ko} } ? [list $c bar] OK ? [list $c eval {:bar}] OK C unexport bar ? [list $c bar] "$c: unable to dispatch method 'bar'" "created a protected dummy" ? [list $c eval {:bar}] OK "bar is still available for self sends (through a next send in the dummy)" # # unexport any (e.g., an inherited) method at the class level # nx::Class create D -superclass C set d [D new] ? [list $d bar] "$d: unable to dispatch method 'bar'" "shielded by protected dummy at the level of class C" ? [list $d eval {:bar}] OK ? [list $d baz] ko D unexport baz ? [list $d baz] "$d: unable to dispatch method 'baz'" ? [list $d eval {:baz}] ko # # unexport creates ordinary methods, to be fully replaced by subsequent # method declarations, see TclOO tests, oo.test, oo-4.6 # Class create testClass2 { :unexport foo :public method foo {} {return ok} } ? {[testClass2 new] foo} ok # # https://rosettacode.org/wiki/Abstract_type # nx::Class create AbstractQueue { :method enqueue item { error "not implemented" } :method dequeue {} { error "not implemented" } :class unexport create new } ? {AbstractQueue new} {method 'new' unknown for ::AbstractQueue; in order to create an instance of class ::AbstractQueue, consider using '::AbstractQueue create new ?...?'} ? {AbstractQueue create aQueue} {method 'create' unknown for ::AbstractQueue; in order to create an instance of class ::AbstractQueue, consider using '::AbstractQueue create create ?...?'} } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/protected.test000644 000766 000024 00000070730 13527046152 017240 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx package require nx::test nx::test configure -count 1 nx::test case call-protected { nx::Class create C { :public alias SET ::set :public method foo {} {return [current method]} :public method bar {} {return [current method]} :public method bar-foo {} { c1 foo } :public method bar-SET {} { c1 SET x 1 } } C create c1 C create c2 ? {c1 SET x 1} {1} ? {c1 foo} {foo} ? {c1 bar-SET} {1} ? {c1 bar-foo} {foo} ::nsf::method::property C SET call-protected true ? {c1 SET x 1} {::c1: unable to dispatch method 'SET'} ? {nx::dispatch c1 SET x 2} {2} "dispatch of protected methods works" ? {c1 foo} {foo} ? {c1 bar} {bar} ? {c1 bar-SET} {1} ? {c1 bar-foo} {foo} ? {c2 bar-SET} {::c1: unable to dispatch method 'SET'} ? {c2 bar-foo} {foo} ::nsf::method::property C foo call-protected true ? {c1 SET x 1} {::c1: unable to dispatch method 'SET'} ? {nx::dispatch c1 SET x 2} {2} "dispatch of protected methods works" ? {c1 bar} {bar} "other method work" ? {c1 foo} {::c1: unable to dispatch method 'foo'} ? {c1 bar-SET} {1} "internal call of protected C implementend method" ? {c1 bar-foo} {foo} "internal call of protected Tcl implemented method" ? {c2 bar-SET} {::c1: unable to dispatch method 'SET'} ? {c2 bar-foo} {::c1: unable to dispatch method 'foo'} # unset call protected ? {::nsf::method::property C SET call-protected} 1 ::nsf::method::property C SET call-protected false ? {::nsf::method::property C SET call-protected} 0 ? {::nsf::method::property C foo call-protected} 1 ::nsf::method::property C foo call-protected false ? {::nsf::method::property C foo call-protected} 0 ? {c1 SET x 3} 3 ? {nx::dispatch c1 SET x 2} {2} ? {c1 foo} {foo} ? {c1 bar} {bar} ? {c1 bar-SET} {1} ? {c1 bar-foo} {foo} ? {c2 bar-SET} 1 ? {c2 bar-foo} {foo} # define a protected method C protected method foo {} {return [current method]} ? {::nsf::method::property C SET call-protected} 0 ? {c1 SET x 3} 3 ? {nx::dispatch c1 SET x 4} {4} ? {c1 foo} {::c1: unable to dispatch method 'foo'} ? {c1 bar} {bar} ? {c1 bar-SET} {1} ? {c1 bar-foo} foo ? {c2 bar-SET} 1 ? {c2 bar-foo} {::c1: unable to dispatch method 'foo'} } # # Check protection + filter # # Allow to call methods as filters even if these are protected or # private. # nx::test case protected+filter { nx::Class create C { :method f1 args { next } :private method f2 args { next } :public method foo {} { return foo} } C create c1 ? {c1 foo} foo # add a protected filter c1 object filters add f1 ? {c1 foo} foo # add a private filter c1 object filters add f2 ? {c1 foo} foo } nx::test case redefined-protected { nx::Class create C { :public alias SET ::set :public method foo {} {return [current method]} } # # Define SET and foo as redefined-protected # ? {::nsf::method::property C SET redefine-protected true} 1 ? {::nsf::method::property C foo redefine-protected true} 1 ? {C method SET {a b c} {...}} \ {refuse to overwrite protected method 'SET'; derive e.g. a subclass!} \ "redefine method SET" ? {C method foo {a b c} {...}} \ {refuse to overwrite protected method 'foo'; derive e.g. a subclass!} \ "redefine method foo" # check a predefined protection ? {::nx::Class method create {a b c} {...}} \ {refuse to overwrite protected method 'create'; derive e.g. a subclass!} \ "redefine method create" # try to redefine predefined protected method via alias ? {::nsf::method::alias nx::Class create ::set} \ {refuse to overwrite protected method 'create'; derive e.g. a subclass!} \ "redefine alias create" # try to redefine via forward ? {C forward SET ::set} \ {refuse to overwrite protected method 'SET'; derive e.g. a subclass!} \ "redefine forward SET" # try to redefine via setter ? {C property -accessor public SET} \ {refuse to overwrite protected method 'SET'; derive e.g. a subclass!} \ "redefine property SET" # redefine-protect object specific method nx::Object create o o object method foo {} {return 13} ::nsf::method::property o foo redefine-protected true ? {o object method foo {} {return 14}} \ {refuse to overwrite protected method 'foo'; derive e.g. a subclass!} } # # Use case for private: # Hide "helper methods of e.g. mixin" # nx::test case private-helper { nx::Class create B { :public method bar {} {return "B.bar [next]"} :public method baz {} {return "B.baz [next]"} :create b1 { :public object method baz {} {return "b1.baz [next]"} } } nx::Class create C -superclass B { :public method bar {} {return "C.bar [next]"} :public method baz {} {return "C.baz [next]"} :create c1 { :public object method baz {} {return "c1.baz [next]"} } } # Behavior without mixin with private methods ? {b1 bar} "B.bar " ? {b1 baz} "b1.baz B.baz " ? {c1 bar} "C.bar B.bar " ? {c1 baz} "c1.baz C.baz B.baz " # # Define a mixin with helper methods "bar" and "baz". The helper # methods are defined as private to avoid interference. # nx::Class create M { :public method foo {} {: -local bar} :private method bar {} {: -local baz} :private method baz {} {return "M.baz"} } # Behavior with mixin . THe private helper methods are "invisible" # for invocation and next path. B mixins add M ? {b1 bar} "B.bar " ? {b1 baz} "b1.baz B.baz " ? {c1 bar} "C.bar B.bar " ? {c1 baz} "c1.baz C.baz B.baz " ? {b1 foo} "M.baz" ? {c1 foo} "M.baz" } # # Use case for private: # Hide "helper object specific helper methods" # nx::test case object-private-helper { nx::Class create B { :public method bar {} {return "B.bar [next]"} :public method baz {} {return "B.baz [next]"} :create b1 { :public object method foo {} {: -local bar} :private object method bar {} {: -local baz} :private object method baz {} {return "b1.baz"} } } nx::Class create C -superclass B { :public method bar {} {return "C.bar [next]"} :public method baz {} {return "C.baz [next]"} :create c1 { :public object method foo {} {: -local bar} :private object method bar {} {: -local baz} :private object method baz {} {return "c1.baz"} } } # Behavior of per-object helper methods, which are invisible for # invocation through "bar" and "baz" ? {b1 bar} "B.bar " ? {b1 baz} "B.baz " ? {b1 foo} "b1.baz" ? {c1 bar} "C.bar B.bar " ? {c1 baz} "C.baz B.baz " ? {c1 foo} "c1.baz" # # Define a mixin class which shadows "bar" and "baz". The behavior # of the object-methods with its private methods is not affected. # nx::Class create M { :public method bar {} {return "M.bar [next]"} :public method baz {} {return "M.baz [next]"} } B mixins add M ? {b1 bar} "M.bar B.bar " ? {b1 baz} "M.baz B.baz " ? {b1 foo} "b1.baz" ? {c1 bar} "M.bar C.bar B.bar " ? {c1 baz} "M.baz C.baz B.baz " ? {c1 foo} "c1.baz" } # # Check local + filter # nx::test case local+filter { nx::Class create C { :method f1 args { return "f1 [next]" } :public method foo {} { return "C.foo [: -local bar]"} :private method bar {} { return "bar"} :public method baz {} { return "C.baz [next]"} } nx::Class create D -superclass C { :public method baz {} { return "D.baz [next]"} } D create d1 ? {d1 baz} "D.baz C.baz " ? {d1 foo} "C.foo bar" ? {d1 bar} "::d1: unable to dispatch method 'bar'" # add a filter; be sure that we still can call the private -local # method d1 object filters add f1 ? {d1 baz} "f1 D.baz C.baz " ? {d1 foo} "f1 C.foo f1 bar" ? {d1 bar} "::d1: unable to dispatch method 'bar'" # remove the filter d1 object filters set "" # define call to private method via method handle C public method foo {} { return "C.foo [[self] [C info method registrationhandle bar]]"} # the behavior without filter, should be like above ? {d1 baz} "D.baz C.baz " ? {d1 foo} "C.foo bar" ? {d1 bar} "::d1: unable to dispatch method 'bar'" # add a filter; be sure that we still can call the private method d1 object filters add f1 ? {d1 baz} "f1 D.baz C.baz " ? {d1 foo} "f1 C.foo f1 bar" ? {d1 bar} "::d1: unable to dispatch method 'bar'" } # # test private # nx::test case private { nx::Class create B { :private method p1 {} {return B.p1} :private method p2 {} {return B.p2} :public method p3 {} {return B.p3} :public method p4 {} {return B.p4} :create b1 } nx::Class create C -superclass B { :private method p1 {} {return "C.p1 [next]"} :public method p2 {} {return "C.p2 [next]"} :private method p3 {} {return "C.p3 [next]"} :public method p4 {} {return "C.p4 [next]"} :create c1 } nx::Class create D -superclass C { :public method p1 {} {return "D.p1 [next]"} :public method p2 {} {return "D.p2 [next]"} :public method p3 {} {return "D.p3 [next]"} :public method p4 {} {return "D.p4 [next]"} :create d1 } # check introspection and "-callprotection" filter ? {lsort [C info methods]} "p2 p4" ? {lsort [C info methods -callprotection all]} "p1 p2 p3 p4" ? {lsort [C info methods -callprotection public]} "p2 p4" ? {lsort [C info methods -callprotection protected]} "" ? {lsort [C info methods -callprotection private]} "p1 p3" # called shadowed # C.p1 private B.p1 private # C.p2 public B.p2 private # C.p3 private B.p3 public # C.p4 public B.p4 public ? {c1 p1} "::c1: unable to dispatch method 'p1'" ? {c1 p2} "C.p2 " ? {c1 p3} "B.p3" ? {c1 p4} "C.p4 B.p4" # called shadowed shadowed # D.p1 public C.p1 private B.p1 private # D.p2 public C.p2 public B.p2 private # D.p3 public C.p3 private B.p3 public # D.p4 public C.p4 public B.p4 public ? {d1 p1} "D.p1 " ? {d1 p2} "D.p2 C.p2 " ? {d1 p3} "D.p3 B.p3" ? {d1 p4} "D.p4 C.p4 B.p4" # add on B calls to local C eval { :public method q1 {} {: -local p1} :public method q3 {} {: -local p3} } # all chains start with C, since local resolve works ? {c1 q1} "C.p1 " ? {c1 q3} "C.p3 B.p3" # calls via method handles allows us to dispatch private methods, # results like "-local" resolves above ? {c1 [C info method registrationhandle p1]} "C.p1 " ? {c1 [C info method registrationhandle p3]} "C.p3 B.p3" # calls via method handles allows us to dispatch private methods, # results like "-local" resolves above ? {nx::dispatch c1 [C info method registrationhandle p1]} "C.p1 " ? {nx::dispatch c1 [C info method registrationhandle p3]} "C.p3 B.p3" # we can't call the private method via dispatch, since the private # methods are removed from the search for methods ? {nx::dispatch c1 p1} "::c1: unable to dispatch method 'p1'" ? {nx::dispatch c1 p3} "B.p3" # via dispatch, the local flag uses (as always) the context of the # currently executing class, which is not provided below ? {nx::dispatch c1 -local p1} "::c1: unable to dispatch method 'p1'" } # # test ": -local" on classes # nx::test case class-my-local { nx::Class create Base { :private method baz {a b} { expr {$a + $b} } :public method foo {a b} {: -local baz $a $b} } nx::Class create Sub -superclass Base { :public method bar {a b} {: -local baz $a $b} :private method baz {a b} { expr {$a * $b} } :create s1 } ? {s1 foo 3 4} 7 ? {s1 bar 3 4} 12 ? {s1 baz 3 4} {::s1: unable to dispatch method 'baz'} } # # test ": -local" on objects # nx::test case object-my-local { nx::Class create M { :public method foo {} {return "M [next]"} :public method foo2 {} {return "M2 [next]"} } nx::Object create o1 { :protected object method foo {} {return o1} :public object method foo2 {} {:foo} :public object method bar {} {: -local foo} } ? {o1 foo} {::o1: unable to dispatch method 'foo'} ? {o1 bar} o1 ? {o1 foo2} o1 o1 object mixins add M ? {o1 foo} "M o1" ? {o1 bar} "o1" ? {o1 foo2} "M2 M o1" } # # test "my" + path instead of ": -local" on classes # nx::test case my+handle-instead-of-my-local { nx::Class create Base { :private method privateMethod {a b} { expr {$a + $b} } :public method foo {a b} {: [Base info method registrationhandle privateMethod] $a $b} } nx::Class create Sub -superclass Base { :public method bar {a b} {: [Sub info method registrationhandle privateMethod] $a $b} :private method privateMethod {a b} { expr {$a * $b} } :create s1 } ? {s1 foo 3 4} 7 ? {s1 bar 3 4} 12 } # # test object::dispatch instead of ": -local" on classes # nx::test case dispatch-instead-of-my-local { nx::Class create Base { :private method privateMethod {a b} { expr {$a + $b} } :public method foo {a b} { dispatch [self] [Base info method registrationhandle privateMethod] $a $b } } nx::Class create Sub -superclass Base { :public method bar {a b} { dispatch [self] [Sub info method registrationhandle privateMethod] $a $b } :private method privateMethod {a b} { expr {$a * $b} } :create s1 } ? {s1 foo 3 4} 7 ? {s1 bar 3 4} 12 } # # Test -system flag on dispatch with explicit receiver # nx::test case system-flag { # # create an object, which overloads some system behavior # nx::Object create o1 { :public object method info {} {return "overloads system info"} :public object method destroy {} {return "overloads system destroy"} :public object method "object method" args {return "overloads method 'object method'"} :object variable v 1 } ? {o1 info} "overloads system info" ? {o1 ::nx::Object::slot::__info::vars} "v" ? {o1 [nx::Object info method definitionhandle "info vars"]} "v" #? {o1 -system info vars} "v" ? {nx::dispatch o1 -system info vars} "v" #? {o1 -system} "no method name specified" ? {o1 object method foo {} {return foo}} "overloads method 'object method'" ? {nx::dispatch o1 -system public object method foo {} {return foo}} "::o1::foo" ? {o1 destroy} "overloads system destroy" ? {nsf::object::exists o1} 1 ? {nx::dispatch o1 -system destroy} "" ? {nsf::object::exists o1} 0 # # create a class, which overloads some system behavior # nx::Class create C { :public method info {} {return "overloads system info"} :public method destroy {} {return "overloads system destroy"} :variable v 1 :create c1 } ? {c1 info} "overloads system info" ? {c1 ::nx::Object::slot::__info::vars} "v" ? {c1 [nx::Object info method definitionhandle "info vars"]} "v" #? {c1 -system info vars} "v" ? {nx::dispatch c1 -system info vars} "v" ? {c1 destroy} "overloads system destroy" ? {nsf::object::exists c1} 1 #? {c1 -system destroy} "" ? {nx::dispatch c1 -system destroy} "" ? {nsf::object::exists c1} 0 } # # Check my-local + private + next # # Never call a private method via "next", but allow "next" from # private methods # nx::test case class-my-local+next { nx::Class create Base { :private method baz {a b} { expr {$a + $b} } :protected method baz2 {a b} { expr {$a + $b} } :public method foo {a b} {: -local baz $a $b} :create b1 } # we can call Base.baz only through Base.foo ? {b1 foo 4 5} 9 ? {b1 baz 4 5} {::b1: unable to dispatch method 'baz'} # Define and register a mixin class, where method "foo" is calling a # private method via ": -local" nx::Class create Mix { :private method baz {a b} { expr {$a ** $b} } :public method foo {a b} {: -local baz $a $b} } b1 object mixins add Mix # we can call Mix.baz only through Mix.foo ? {b1 foo 4 5} 1024 ? {b1 baz 4 5} {::b1: unable to dispatch method 'baz'} # # the private method has a next # nx::Class create Intermediate -superclass Base { :private method baz {a b} { next } :private method baz2 {a b} { next } :public method foo {a b} {: -local baz $a $b} :public method foo2 {a b} {: -local baz2 $a $b} :create i1 } # next in the private method reaches a private method, which is ignored ? {i1 foo 4 5} "" ? {i1 baz 4 5} {::i1: unable to dispatch method 'baz'} # next in the private method reaches a non-private method, which is honored ? {i1 foo2 4 5} 9 nx::Class create Sub -superclass Intermediate { :public method bar {a b} {: -local baz $a $b} :private method baz {a b} { expr {$a * $b} } :create s1 } # next in the private method reaches a private method, which is ignored ? {s1 foo 4 5} "" ? {s1 baz 4 5} {::s1: unable to dispatch method 'baz'} # next in the private method reaches a non-private method, which is honored ? {s1 foo2 4 5} 9 ? {s1 bar 4 5} 20 # add per-class mixin Sub mixins add Mix # foo is shadowed in the mixin and calls the mixin-private method ? {s1 foo 4 5} 1024 ? {s1 baz 4 5} {::s1: unable to dispatch method 'baz'} # next in the private method reaches a non-private method, which is honored ? {s1 foo2 4 5} 9 ? {s1 bar 4 5} 20 } # # Test setting / clearing private and protected flags # nx::test case call-protected-flags { Class create C C protected method foo {} {return foo} ? {::nsf::method::property C foo call-protected} 1 ? {::nsf::method::property C foo call-private} 0 ? {C info method definition foo} "::C protected method foo {} {return foo}" C public method foo {} {return foo} ? {::nsf::method::property C foo call-protected} 0 ? {::nsf::method::property C foo call-private} 0 ? {C info method definition foo} "::C public method foo {} {return foo}" C private method foo {} {return foo} ? {::nsf::method::property C foo call-protected} 1 ? {::nsf::method::property C foo call-private} 1 ? {C info method definition foo} "::C private method foo {} {return foo}" ? {::nsf::method::property C foo call-private false} 0 ? {::nsf::method::property C foo call-protected} 1 ? {::nsf::method::property C foo call-private} 0 ? {::nsf::method::property C foo call-private true} 1 ? {::nsf::method::property C foo call-protected} 1 ? {::nsf::method::property C foo call-private} 1 ? {::nsf::method::property C foo call-protected false} 0 ? {::nsf::method::property C foo call-protected} 0 ? {::nsf::method::property C foo call-private} 0 } # # private subobjects # nx::test case private-subobject { nx::Object create obj { :public object method foo {} {return foo-[self]} nx::Object create [self]::child { :public object method bar {} {return bar-[self]} } } ? {obj child bar} "bar-::obj::child" ? {obj foo} "foo-::obj" ? {obj info object methods} "child foo" ? {::nsf::method::property obj foo call-private 1} 1 ? {obj child bar} "bar-::obj::child" ? {obj foo} {::obj: unable to dispatch method 'foo'} ? {obj info object methods} "child" ? {::nsf::method::property obj child call-private 1} 1 ? {obj child bar} {::obj: unable to dispatch method 'child'} ? {obj foo} {::obj: unable to dispatch method 'foo'} ? {obj info object methods} "" ? {::nsf::method::property obj foo call-protected 0} 0 ? {obj child bar} {::obj: unable to dispatch method 'child'} ? {obj foo} "foo-::obj" ? {obj info object methods} "foo" ? {::nsf::method::property obj child call-protected 0} 0 ? {obj child bar} "bar-::obj::child" ? {obj foo} "foo-::obj" ? {obj info object methods} "child foo" } # # Test protected and private object properties # nx::test case protected-priv-class-property { nx::Class create C { :property -accessor public {a a1} :property -accessor protected {b b1} :property -accessor private {c c1} :property -accessor private {d:integer 1} :public method foo {p} {return [: $p get]} :public method bar {p} {return [: -local $p get]} :public method baz {p v} {return [: -local $p set $v]} :create c1 } # call properties directly ? {c1 a get} a1 ? {c1 b get} {::c1: unable to dispatch method 'b'} ? {c1 c get} {::c1: unable to dispatch method 'c'} # call properties via method ? {c1 foo a} a1 ? {c1 foo b} b1 ? {c1 foo c} {::c1: unable to dispatch method 'c'} # call properties via method via "-local" dispatch ? {c1 bar a} a1 ? {c1 bar b} b1 ? {c1 bar c} {c1} ? {lsort [c1 info vars]} "__private a b" ? {c1 eval {lsort [array names :__private]}} "::C,c ::C,d" # Private property with value constraint ? {c1 bar d} {1} ? {c1 baz d 2} {2} ? {c1 bar d} {2} ? {c1 baz d x} {expected integer but got "x" for parameter "value"} # # Define a private property with the same name as the private # property in the superclass; define a public per-object property # with the same name. The call "d1 c" resolves to the per-object # property, the private properties are accessed via methods. # The values of the private properties do not conflict. # nx::Class create D -superclass C { :property -accessor private {c c1d} :public method bard {p} {return [: -local $p get]} :create d1 { :object property -accessor public {c c1o} } } ? {d1 bar c} c1 ? {d1 bard c} c1d ? {d1 c get} c1o # # Define a public property with the same name as the private # property in the superclass; define private per-object property # with the same name. The call "d1 c" resolves to the public # property on D, the private properties are accessed via methods. # The values of the private properties do not conflict. # nx::Class create D -superclass C { :property -accessor public {c c1d} :public method bard {p} {return [: -local $p get]} :create d1 { :object property -accessor private {c c1o} :public object method bard1 {p} {return [: -local $p get]} } } ? {d1 bar c} c1 ? {d1 bard c} c1d ? {d1 bard1 c} c1o ? {d1 c get} c1d } # # Test properties in class hierarchy, where a subclass defines a # private property with the same name as a property in a superclass. # nx::test case private-shadows-public-property { nx::Class create C { :property -accessor public {x c} } nx::Class create D -superclass C { :property -accessor private {x d} :public method bar-d {p} {return [: -local $p get]} } nx::Class create E -superclass D { :property -accessor private {x e} :public method bar-e {p} {return [: -local $p get]} } E create e1 ? {e1 x get} c ? {e1 bar-d x} d ? {e1 bar-e x} e } # # Test protected and private class properties # nx::test case protected-priv-object-property { nx::Object create o { :object property -accessor public {a a1} :object property -accessor protected {b b1} :object property -accessor private {c c1} :object property -accessor private {d:integer 1} :public object method foo {p} {return [: $p get]} :public object method bar {p} {return [: -local $p get]} :public object method baz {p v} {return [: -local $p set $v]} } ? {o a get} a1 ? {o b get} {::o: unable to dispatch method 'b'} ? {o c get} {::o: unable to dispatch method 'c'} ? {o foo a} a1 ? {o foo b} b1 ? {o foo c} {::o: unable to dispatch method 'c'} ? {o bar a} a1 ? {o bar b} b1 ? {o bar c} {c1} #? {lsort [o info vars]} "____C.c ____C.d a b" ? {lsort [o info vars]} "__private a b" ? {o eval {lsort [array names :__private]}} "::o,c ::o,d" ? {o bar d} {1} ? {o baz d 2} {2} ? {o bar d} {2} ? {o baz d x} {expected integer but got "x" for parameter "value"} } # # Test protected and private class object properties # nx::test case protected-priv-class-object-property { nx::Class create C { :object property -accessor public {a a1} :object property -accessor protected {b b1} :object property -accessor private {c c1} :object property -accessor private {d:integer 1} :public object method foo {p} {return [: $p get]} :public object method bar {p} {return [: -local $p get]} :public object method baz {p v} {return [: -local $p set $v]} } ? {C a get} a1 ? {C b get} {method 'b' unknown for ::C; in order to create an instance of class ::C, consider using '::C create b ?...?'} ? {C c get} {method 'c' unknown for ::C; in order to create an instance of class ::C, consider using '::C create c ?...?'} ? {C foo a} a1 ? {C foo b} b1 ? {C foo c} {method 'c' unknown for ::C; in order to create an instance of class ::C, consider using '::C create c ?...?'} ? {C bar a} a1 ? {C bar b} b1 ? {C bar c} {c1} #? {lsort [o info vars]} "____C.c ____C.d a b" ? {lsort [C info vars]} "__private a b" ? {C eval {lsort [array names :__private]}} "::C,c ::C,d" ? {C bar d} {1} ? {C baz d 2} {2} ? {C bar d} {2} ? {C baz d x} {expected integer but got "x" for parameter "value"} ? {C public object property {d:integer 1}} {'property' is not a method defining method} ? {C protected object property {d:integer 1}} {'property' is not a method defining method} ? {C private object property {d:integer 1}} {'property' is not a method defining method} } nx::test case protected-ensembles { set ::o [nx::Object new { set ::foo2faa [:protected object method "foo2 faa" {} {return protected}] ? [list set _ [:foo2 faa]] "protected" set ::foo2baz [:public object method "foo2 baz" {} {:foo2 faa}] ? [list set _ [:foo2 baz]] "protected" :object method m1 {} {:foo2 faa} ? [list set _ [:m1]] "protected" :object method m2 {} {apply {{} {:foo2 faa}}} ? [list set _ [:m2]] "protected" set ::foo2biz [:public object method "foo2 biz" {} {apply {{} {:foo2 faa}}}] ? [list set _ [:foo2 biz]] "protected" }] ? {$::o foo2 faa fee} "unable to dispatch sub-method \"faa\" of $::o foo2; valid are: foo2 baz, foo2 biz" set C [nx::Class new { set ::foo2faa [:protected method "foo2 faa" {} {return protected}] set ::foo2baz [:public method "foo2 baz" {} {:foo2 faa}] set c [:new { ? [list set _ [:foo2 faa]] "protected" }] ? [list set _ [$c foo2 baz]] "protected" :public method m1 {} {:foo2 faa} ? [list set _ [$c m1]] "protected" :public method m2 {} {apply {{} {:foo2 faa}}} ? [list set _ [$c m2]] "protected" set ::foo2biz [:public method "foo2 biz" {} {apply {{} {:foo2 faa}}}] ? [list set _ [$c foo2 biz]] "protected" ? [list $c foo2 faa] "unable to dispatch sub-method \"faa\" of $c foo2; valid are: foo2 baz, foo2 biz" set mixin [nx::Class new { :public method m3 {} { :foo2 faa } :public method "foo2 fee" {} { :foo2 faa } :public method "foo2 faa" {} { next } }] $c object mixins add $mixin ? [list set _ [$c m3]] "protected" ? [list set _ [$c foo2 fee]] "protected" ? [list set _ [$c foo2 faa]] "protected" $c object mixins clear ? [list $c foo2 faa] "unable to dispatch sub-method \"faa\" of $c foo2; valid are: foo2 baz, foo2 biz" }] # ensemble set ::o [nx::Object new { set ::foo2faa [:protected object method "foo2 faa fee" {} {return protected}] ? [list set _ [:foo2 faa fee]] "protected" set ::foo2baz [:public object method "foo2 baz" {} {:foo2 faa fee}] ? [list set _ [:foo2 baz]] "protected" :object method m1 {} {:foo2 faa fee} ? [list set _ [:m1]] "protected" :object method m2 {} {apply {{} {:foo2 faa fee}}} ? [list set _ [:m2]] "protected" set ::foo2biz [:public object method "foo2 biz" {} {apply {{} {:foo2 faa fee}}}] ? [list set _ [:foo2 biz]] "protected" }] ? {$::o foo2 faa fee} "unable to dispatch sub-method \"fee\" of $::o foo2 faa; valid are: " set ::C [nx::Class new { set ::foo2faa [:protected method "foo2 faa fim" {} {return protected}] set ::foo2baz [:public method "foo2 baz" {} {:foo2 faa fim}] set c [:new { ? [list set _ [:foo2 faa fim]] "protected" }] ? [list set _ [$c foo2 baz]] "protected" :public method m1 {} {:foo2 faa fim} ? [list set _ [$c m1]] "protected" :public method m2 {} {apply {{} {:foo2 faa fim}}} ? [list set _ [$c m2]] "protected" set ::foo2biz [:public method "foo2 biz" {} {apply {{} {:foo2 faa fim}}}] ? [list set _ [$c foo2 biz]] "protected" ? [list $c foo2 faa fim] "unable to dispatch sub-method \"fim\" of $c foo2 faa; valid are: " set mixin [nx::Class new { :public method m3 {} { :foo2 faa fim } :public method "foo2 fee fuu" {} { :foo2 faa fim } :public method "foo2 faa fim" {} { next } }] $c object mixins add $mixin ? [list set _ [$c m3]] "protected" ? [list set _ [$c foo2 fee fuu]] "protected" ? [list set _ [$c foo2 faa fim]] "protected" $c object mixins clear ? [list $c foo2 faa fim] "unable to dispatch sub-method \"fim\" of $c foo2 faa; valid are: " }] } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/info-method.test000644 000766 000024 00000131000 14164660341 017444 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package req nx ::nx::configure defaultMethodCallProtection false package require nx::test # # Test info superclasses with closure and patterns (with and without # wildcards, prefixed or not, success or not). # nx::test case info-superclass { nx::Class create C nx::Class create D -superclass C # no patterns ? {D info superclasses} "::C" ? {D info superclasses -closure} "::C ::nx::Object" # fully qualified pattern, no wild-card characters, success ? {D info superclasses ::C} "::C" ? {D info superclasses -closure ::C} "::C" # unprefixed pattern, no wild-card characters, success ? {D info superclasses C} "::C" ? {D info superclasses -closure C} "::C" # fully qualified pattern, no wild-card characters, no success ? {D info superclasses ::D} "" ? {D info superclasses -closure ::D} "" ? {D info superclasses ::Dx} "" ? {D info superclasses -closure ::Dx} "" # unprefixed pattern, no wild-card characters, no success ? {D info superclasses D} "" ? {D info superclasses -closure D} "" ? {D info superclasses Dx} "" ? {D info superclasses -closure Dx} "" # fully qualified pattern, wild-card characters, success ? {D info superclasses ::*} "::C" ? {D info superclasses -closure ::C*} "::C" ? {D info superclasses -closure ::*} "::C ::nx::Object" ? {D info superclasses -closure ::nx*} "::nx::Object" # unprefixed pattern, wild-card characters, success ? {D info superclasses C*} "::C" ? {D info superclasses -closure *} "::C ::nx::Object" ? {D info superclasses -closure nx*} "::nx::Object" # fully qualified pattern, wild-card characters, no success ? {D info superclasses ::*D} "" ? {D info superclasses -closure ::*D} "" # unprefixed pattern, wild-card characters, no success ? {D info superclasses C*x} "" ? {D info superclasses -closure C*x} "" } # # Test "info method", base cases # nx::test case info-method-base { nx::Object create o { :object alias set ::set } nx::Class create C { :method m {x} {return proc-[self proc]} :object method mpo {} {return instproc-[self proc]} # :method m-with-assertions {} {return proc-[self proc]} -precondition 1 -postcondition 2 :forward addOne expr 1 + :object forward add1 expr 1 + :object forward fpo ::o :property -accessor public s :object property -accessor public spo :alias a ::set :object alias apo ::puts } C create c1 ? {lsort [C info methods -callprotection all]} "a addOne m s" #? {lsort [C info methods]} "a addOne s" foreach m [lsort [C info methods -callprotection all]] { ? [subst -nocommands {lsort [c1 info lookup methods $m]}] $m } ? {C info method definition a} "::C public alias a ::set" ? {c1 info lookup method a} "::nsf::classes::C::a" ? {c1 info lookup method addOne} "::nsf::classes::C::addOne" ? {c1 info lookup method m} "::nsf::classes::C::m" ? {c1 info lookup method s} "::nsf::classes::C::s" c1 object method foo {} {puts foo} ? {c1 info object method definition foo} "::c1 public object method foo {} {puts foo}" ? {c1 info lookup method foo} "::c1::foo" ? {C info method registrationhandle m} "::nsf::classes::C::m" ? {C info object method registrationhandle mpo} "::C::mpo" ? {C info method definition m} {::C public method m x {return proc-[self proc]}} ? {C info object method definition mpo} {::C public object method mpo {} {return instproc-[self proc]}} # if {$::nsf::config(assertions)} { # ? {C info method definition m-with-assertions} \ # {::C public method m-with-assertions {} {return proc-[self proc]} -precondition 1 -postcondition 2} # } else { # ? {C info method definition m-with-assertions} \ # {::C public method m-with-assertions {} {return proc-[self proc]}} # } ? {C info method parameters m} {x} ? {nx::Class info method parameters method} \ {-debug:switch -deprecated:switch name arguments:parameter,0..* -checkalways:switch -returns body} ? {nx::Class info method parameters alias} \ {-debug:switch -deprecated:switch methodName -returns {-frame default} cmd} # raises currently an error ? {catch {C info method parameters a}} 1 ? {C info method definition addOne} "::C public forward addOne expr 1 +" ? {C info object method definition add1} "::C public object forward add1 expr 1 +" ? {C info object method definition fpo} "::C public object forward fpo ::o" ? {C info method definition s} "::C public forward s -prefix value= ::C::slot::s %1 %self s" ? {C info object method definition spo} "::C public object forward spo -prefix value= ::C::per-object-slot::spo %1 %self spo" ? {C info method definition a} "::C public alias a ::set" ? {C info object method definition apo} "::C public object alias apo ::puts" ? {::nx::Object info lookup methods -source application} "" ? {::nx::Class info lookup methods -source application} "" set object_methods "cget configure contains copy delete destroy eval info move object private protected public require" set class_methods "alias cget configure contains copy create delete destroy eval filters forward info method mixins move new object private property protected public require variable" ? {lsort [::nx::Object info lookup methods -source system]} $class_methods ? {lsort [::nx::Class info lookup methods -source system]} $class_methods ? {lsort [::nx::Object info lookup methods -source all]} $class_methods ? {lsort [::nx::Class info lookup methods -source all]} $class_methods ? {lsort [::nx::Object info lookup methods]} $class_methods ? {lsort [::nx::Class info lookup methods]} $class_methods ? {lsort [C info lookup methods -source application]} "add1 apo fpo mpo spo" ? {lsort [c1 info lookup methods -source application]} "a addOne foo m s" ? {lsort [C info lookup methods -source system]} $class_methods ? {lsort [c1 info lookup methods -source system]} $object_methods ::nx::configure defaultMethodCallProtection true # # the subsequent tests assume defaultMethodCallProtection == true # ? {::nx::configure defaultMethodCallProtection} true ::nx::Class create MC -superclass ::nx::Class { :protected method bar1 args {;} :method bar2 args {;} :public method foo args {;} :public object method foo args {;} } ? {lsort [MC info methods -type scripted -callprotection public]} "foo" ? {lsort [MC info methods -type scripted -callprotection protected]} "bar1 bar2" ? {lsort [MC info methods -type scripted -callprotection all]} "bar1 bar2 foo" ::nsf::method::property ::MC foo call-protected true ::nsf::method::property ::MC bar2 call-protected false ? {lsort [MC info methods -type scripted -callprotection public]} "bar2" ? {lsort [MC info methods -type scripted -callprotection protected]} "bar1 foo" ? {lsort [MC info methods -type scripted -callprotection all]} "bar1 bar2 foo" ::nx::configure defaultMethodCallProtection false } # # Test visibility of obj-objects # nx::test case visibility-sub-objects { ::nx::Object create o { ::nx::Object create [::nx::self]::sub { :object method foo {} {;} } :public object alias soAlias ::o::sub } # # per default, we see the alias and the subobject # ? {o info object methods} "soAlias sub" ? {o info object method type soAlias} "alias" # the subobject can be hidden via private (see protection.test) } # # Test visibility of aliased Objects # nx::test case visibility-aliased-object { ::nx::Object create ::I ::nx::Class create C { :public alias i ::I :create c1 } # # We see always the alias to the object # ? {C info methods i} "i" ? {c1 info lookup methods i} "i" ? {C info methods *i} "i" ? {c1 info lookup methods *i} "i" } #package require nx::test # # Introspect the returns method property through the "info method" # API chunk ... # set checkFlag [::nsf::configure checkresults] set dmcFlag [::nx::configure defaultMethodCallProtection] # # Make sure that return-value checking is active for the current # interp ... # ::nsf::configure checkresults true # # Neutralize the defaultMethodCallProtection for the scope of these tests # ::nx::configure defaultMethodCallProtection false nx::test case method-returns { # # A test object covering basic cases, adopted from returns.test # nx::Class create C { # scripted method without paramdefs for in-parameters :method bar-ok1 {a b} -returns integer {return 1} # scripted method with paramdefs for in-parameters :method bar-nok {a b:integer} -returns integer {return a} # alias to tcl-cmd (no param defs for in-parameters) :alias incr -returns integer -frame object ::incr :forward ++ -returns integer ::expr 1 + :public object method instances {} -returns object,1..n {:info instances} :create c1 { :public object method foo {} -returns integer {;} :public object method "bar baz" {} -returns integer {;} :public object method "bar boo" {} -returns integer {;} } } ? {C info method returns bar-ok1} "integer" ? {C info method returns bar-nok} "integer" ? {C info method returns incr} "integer" ? {C info method returns ++} "integer" ? {C info object method returns instances} "object,1..n" ? {c1 info object method returns foo} "integer" ? {c1 info object method returns "bar baz"} "integer" ? {c1 info object method returns "bar boo"} "integer" # # Ensemble object ... # ? {c1 info object method returns bar} "" # # Non-existing method ... # ? {c1 info object method returns baf} "" # # Non-existing submethod ... # ? {c1 info object method returns "bar baf"} "" } nx::test case method-definition-with-returns { # # A test object covering basic cases, adopted from returns.test # nx::Class create C { # scripted method without paramdefs for in-parameters :method bar-ok1 {a b} -returns integer {;} # scripted method with paramdefs for in-parameters :method bar-nok {a b:integer} -returns integer {;} # alias to tcl-cmd (no param defs for in-parameters) :alias incr -returns integer -frame object ::incr :forward ++ -returns integer ::expr 1 + :public object method instances {} -returns object,1..n {;} :create c1 { :public object method foo {} -returns integer {;} :object method "bar baz" {} -returns integer {;} } } ? {C info method definition bar-ok1} "::C public method bar-ok1 {a b} -returns integer {;}" ? {C info method definition bar-nok} \ "::C public method bar-nok {a b:integer} -returns integer {;}" ? {C info method definition incr} "::C public alias incr -frame object -returns integer ::incr" ? {C info method definition ++} "::C public forward ++ -returns integer ::expr 1 +" ? {C info object method definition instances} \ "::C public object method instances {} -returns object,1..n {;}" ? {c1 info object method definition foo} "::c1 public object method foo {} -returns integer {;}" ? {c1 info object method definition "bar baz"} "::c1 public object method {bar baz} {} -returns integer {;}" } nx::test case copy-with-returns { nx::Class create C { # scripted method without paramdefs for in-parameters :method bar-ok1 {a b} -returns integer {;} # scripted method with paramdefs for in-parameters :method bar-nok {a b:integer} -returns integer {;} # alias to tcl-cmd (no param defs for in-parameters) :alias incr -returns integer -frame object ::incr :forward ++ -returns integer ::expr 1 + :public object method instances {} -returns object,1..n {;} :create c1 { :public object method foo {} -returns integer {;} :object method "bar baz" {} -returns integer {;} } } c1 copy c2 ? {c2 info object method returns foo} [c1 info object method returns foo] ? {c2 info object method definition foo} [lreplace [c1 info object method definition foo] 0 0 ::c2] ? {c2 info object method returns "bar baz"} [c1 info object method returns "bar baz"] ? {c2 info object method definition "bar baz"} [lreplace [c1 info object method definition "bar baz"] 0 0 ::c2] ? {c2 info object method returns "bar boo"} [c1 info object method returns "bar boo"] C copy CC ? {CC info method returns bar-ok1} [C info method returns bar-ok1] ? {CC info method definition bar-ok1} [lreplace [C info method definition bar-ok1] 0 0 ::CC] ? {CC info method returns bar-nok} [C info method returns bar-nok] ? {CC info method definition bar-nok} [lreplace [C info method definition bar-nok] 0 0 ::CC] # # TODO: Add/re-activate tests for copying aliases and forwards once # handled by NsfNSCopyCmdsCmd properly! # # ? {CC info method returns incr} [C info method returns incr] # ? {CC info method returns ++} [C info method returns ++] ? {CC info object method returns instances} [C info object method returns instances] ? {CC info object method definition instances} [lreplace [C info object method definition instances] 0 0 ::CC] } # # TODO: Add tests for about returns + setter / returns + nsf::proc, if applicable ... # ::nsf::configure checkresults $checkFlag ::nx::configure defaultMethodCallProtection $dmcFlag # -- nx::test case callable { # define the same method for Object and Class ::nx::Object method bar {} {return Object.bar} ::nx::Class method bar {} {return Class.bar} ::nx::Object create o ? {o info lookup method bar} "::nsf::classes::nx::Object::bar" ? {o info lookup methods bar} bar ? {o bar} Object.bar o object mixins set ::nx::Class ? {o info precedence} "::nx::Class ::nx::Object" ? {o info lookup method bar} "::nsf::classes::nx::Class::bar" ? {o info lookup methods bar} bar ? {o info lookup methods create} "" ? {o info lookup method create} "" ? {o bar} Class.bar ? {o object method foo {} {return o.foo}} "::o::foo" ? {o object alias is ::nsf::is} "::o::is" #? {o object property x} {variable definition for 'x' (without value and accessor) is useless} ? {o object property x} "" ? {o object property -accessor public x} "::o::x" ? {lsort [o info object methods]} "foo is x" #? {o object property A} {variable definition for 'A' (without value and accessor) is useless} ? {o object property A} "" ? {o object property -accessor public A} ::o::A ? {o object forward fwd ::set} ::o::fwd ? {lsort [o info object methods]} "A foo fwd is x" o object method f args ::nx::next ? {o info lookup methods create} "" ? {o info lookup methods configure} configure ? {o info lookup method configure} "::nsf::classes::nx::Object::configure" ? {o object filters set f} "f" ? {o object filters guard f { 1 == 1 }} "" ? {o info object filters -guards} {{f -guard { 1 == 1 }}} ? {o object filters guard f} " 1 == 1 " o object filters set "" nx::Class create Foo ? {Foo method f args ::nx::next} "::nsf::classes::Foo::f" ? {Foo method f2 args ::nx::next} "::nsf::classes::Foo::f2" ? {Foo filters set {f f2}} "f f2" ? {Foo info filters} "f f2" ? {Foo filters guard f {2 == 2}} "" ? {Foo info filters -guards f} "{f -guard {2 == 2}}" ? {Foo info filters -guards f2} "f2" ? {Foo info filters -guards} "{f -guard {2 == 2}} f2" ? {Foo filters set {}} "" ? {Foo object method f args ::nx::next} "::Foo::f" ? {Foo object method f2 args ::nx::next} "::Foo::f2" ? {Foo object filters set {f f2}} "f f2" ? {Foo info object filters} "f f2" ? {Foo object filters guard f {2 == 2}} "" ? {Foo object filters guard f} "2 == 2" ? {Foo info object filters -guards f} "{f -guard {2 == 2}}" ? {Foo info object filters -guards f2} "f2" ? {Foo info object filters -guards} "{f -guard {2 == 2}} f2" ? {Foo object filters set {}} "" Foo destroy nx::Class create Fly o object mixins add Fly ? {o info object mixins} "::Fly ::nx::Class" ? {o object mixins guard ::Fly {1}} "" ? {o info object mixins -guards} "{::Fly -guard 1} ::nx::Class" ? {o info object mixins -guards Fly} "{::Fly -guard 1}" o object mixins delete ::Fly ? {o info object mixins} "::nx::Class" nx::Class create Foo Foo mixins add ::nx::Class Foo mixins add Fly ? {Foo info mixins} "::Fly ::nx::Class" ? {Foo mixins guard ::Fly {1}} "" ? {Foo info mixins -guards} "{::Fly -guard 1} ::nx::Class" ? {Foo info mixins -guards Fly} "{::Fly -guard 1}" Foo mixins delete ::Fly ? {Foo info mixins} "::nx::Class" Foo object mixins add ::nx::Class Foo object mixins add Fly ? {Foo info object mixins} "::Fly ::nx::Class" ? {Foo object mixins guard ::Fly {1}} "" ? {Foo info object mixins -guards} "{::Fly -guard 1} ::nx::Class" ? {Foo info object mixins -guards Fly} "{::Fly -guard 1}" Foo object mixins delete ::Fly ? {Foo info object mixins} "::nx::Class" ? {Foo info lookup methods create} "create" ? {Foo info lookup method create} "::nsf::classes::nx::Class::create" ? {o object mixins set ""} "" } # # test info slot objects / info lookup slots # nx::test case info-slots { nx::Class create C { :property a :property {b 1} } nx::Class create D -superclass C { :property {b 2} :property c :object property -accessor public {a2 ""} :method "sub foo" args {;} :create d1 { :object property -accessor public {a3 ""} } } ? {C info slots} "::C::slot::a ::C::slot::b" ? {D info slots} "::D::slot::b ::D::slot::c" ? {D info slots -closure -source application} "::D::slot::b ::D::slot::c ::C::slot::a" ? {d1 info lookup slots -source application} "::d1::per-object-slot::a3 ::D::slot::b ::D::slot::c ::C::slot::a" ? {D info object slots} "::D::per-object-slot::a2" ? {d1 info object slots} "::d1::per-object-slot::a3" ? {C info object slots} "" } # # test info slot objects / info lookup slots # nx::test case slots { nx::Class create C { :property a :property {b 1} :property -accessor private {x 100} :object property -accessor private {y 100} } nx::Class create D -superclass C { :property {b 2} :property c :object property -accessor public a2 :method "sub foo" args {;} :create d1 } ? {lsort [D info lookup slots]} "::D::per-object-slot::a2 ::nx::Class::slot::filters ::nx::Class::slot::mixins ::nx::Class::slot::superclasses ::nx::Object::slot::__initblock ::nx::Object::slot::class ::nx::Object::slot::object-filters ::nx::Object::slot::object-mixins" ? {D info lookup slots superclasses} "::nx::Class::slot::superclasses" ? {D info lookup slots ::nx::Class::slot::superclasses} "::nx::Class::slot::superclasses" ? {D info lookup slots a2} "::D::per-object-slot::a2" ? {D info lookup slots ::D::per-object-slot::a2} "::D::per-object-slot::a2" ? {d1 info lookup slots b} "::D::slot::b" ? {d1 info lookup slots ::D::slot::b} "::D::slot::b" C create c1 ? {c1 info precedence} "::C ::nx::Object" ? {C info heritage} "::nx::Object" ? {C info slots -closure -source application} "::C::slot::____C.x ::C::slot::a ::C::slot::b" ? {lsort [C info slots -closure]} \ "::C::slot::____C.x ::C::slot::a ::C::slot::b ::nx::Object::slot::__initblock ::nx::Object::slot::class ::nx::Object::slot::object-filters ::nx::Object::slot::object-mixins" ? {C info slots} "::C::slot::____C.x ::C::slot::a ::C::slot::b" ? {C info slots x} "::C::slot::____C.x" ? {C info slots ::C::slot::____C.x} "::C::slot::____C.x" ? {C info lookup slots y} "::C::per-object-slot::____C.y" ? {C info lookup slots ::C::per-object-slot::____C.y} "::C::per-object-slot::____C.y" # Test patterns for "info slots" # Partial name, no metachars ? {C info slots -closure object-mixins} "::nx::Object::slot::object-mixins" # Partial name with metachars ? {lsort [C info slots -closure *in*]} \ "::nx::Object::slot::__initblock ::nx::Object::slot::object-mixins" # Fully qualified name, no metachars ? {C info slots -closure ::nx::Object::slot::object-mixins} "::nx::Object::slot::object-mixins" # Fully qualified name, with metachars # The following command returns the same as "C info slots" ? {C info slots -closure ::C::*} "::C::slot::____C.x ::C::slot::a ::C::slot::b" # The following command returns the slots of D inherited from # C. Slot "b" is shadowed by D. ? {D info slots -closure ::C::*} "::C::slot::____C.x ::C::slot::a" # Test patterns for "info lookup slots" # Partial name, no metachars ? {c1 info lookup slots object-mixins} "::nx::Object::slot::object-mixins" # Partial name with metachars ? {lsort [c1 info lookup slots *in*]} \ "::nx::Object::slot::__initblock ::nx::Object::slot::object-mixins" # Fully qualified name, no metachars ? {c1 info lookup slots ::nx::Object::slot::object-mixins} "::nx::Object::slot::object-mixins" # Fully qualified name, with metachars ? {c1 info lookup slots ::C::*} "::C::slot::____C.x ::C::slot::a ::C::slot::b" D create d1 ? {D info slots} "::D::slot::b ::D::slot::c" ? {D info slots -closure -source application} "::D::slot::b ::D::slot::c ::C::slot::____C.x ::C::slot::a" ? {::nx::Object info method parameters info} "" ? {d1 info precedence} "::D ::C ::nx::Object" ? {lsort [d1 info lookup slots]} \ "::C::slot::____C.x ::C::slot::a ::D::slot::b ::D::slot::c ::nx::Object::slot::__initblock ::nx::Object::slot::class ::nx::Object::slot::object-filters ::nx::Object::slot::object-mixins" # Fully qualified name, with metachars # The following command returns the slots of D inherited from # C. Slot "b" is shadowed by D. ? {d1 info lookup slots ::C::*} "::C::slot::____C.x ::C::slot::a" } # # test info submethod and method handles for submethods # nx::test case info-submethod { nx::Object create o { :object method "foo a" {} {return a} :object method "foo b" {x:int y:upper} {return b} } nx::Object create o2 nx::Class create C { :method "bar a" {} {return a} :method "bar b" {x:int y:upper} {return b} :method "bar baz x" {x:int y:upper} {return x} :method "bar baz y" {x:int y:upper} {return y} :object method "foo x" {z:int} {return z} :object method "foo y" {z:int} {return z} } # query definition on submethod ? {o info object method definition "foo b"} {::o public object method {foo b} {x:int y:upper} {return b}} # query definition on submethod with handle ? {o info object method definition "::o::foo b"} {::o public object method {foo b} {x:int y:upper} {return b}} # query definition on submethod with handle ? {o info object method definition "::o::foo b"} {::o public object method {foo b} {x:int y:upper} {return b}} # query definition on submethod with handle called on different object ? {o2 info object method definition "::o::foo b"} {::o public object method {foo b} {x:int y:upper} {return b}} # query definition on handle of ensemble object called on different object ? {o2 info object method definition "::o::foo::b"} {::o::foo public object method b {x:int y:upper} {return b}} # query definition on submethod with handle called on class ? {o2 info object method definition "::o::foo b"} {::o public object method {foo b} {x:int y:upper} {return b}} # query definition on handle of ensemble object called on class ? {o2 info object method definition "::o::foo::b"} {::o::foo public object method b {x:int y:upper} {return b}} # query definition on submethod of class ? {::nx::Object info method definition "info lookup methods"} \ {::nx::Object public alias {info lookup methods} ::nsf::methods::object::info::lookupmethods} # query definition on submethod of class with handle ? {o info object method definition "::nsf::classes::nx::Object::info lookup methods"} \ {::nx::Object public alias {info lookup methods} ::nsf::methods::object::info::lookupmethods} # query definition on handle of ensemble object of class ? {o info object method definition "::nx::Object::slot::__info::lookup::methods"} \ {::nx::Object::slot::__info::lookup public object alias methods ::nsf::methods::object::info::lookupmethods} ? {lsort [o info object method submethods dummy]} "" ? {lsort [o info object method submethods foo]} "a b" ? {lsort [o info object method submethods "foo a"]} "" ? {lsort [C info method submethods "bar"]} "a b baz" ? {lsort [C info method submethods "bar a"]} "" ? {lsort [C info method submethods "bar baz"]} "x y" ? {lsort [C info method submethods "bar baz y"]} "" ? {lsort [C info object method submethods "foo"]} "x y" ? {lsort [C info object method submethods "foo x"]} "" # # method handles for ensemble methods # ? {C info method registrationhandle "bar"} {::nsf::classes::C::bar} ? {C info method registrationhandle "bar a"} {::nsf::classes::C::bar a} ? {C info method registrationhandle "bar baz y"} {::nsf::classes::C::bar baz y} # # test whether the handles for ensemble methods work # ? {C info method exists "bar"} 1 ? {C info method exists [C info method registrationhandle "bar"]} 1 ? {C info method parameters [C info method registrationhandle "bar"]} "" ? {C info method exists "bar b"} 1 ? {C info method exists [C info method registrationhandle "bar b"]} 1 ? {C info method parameters [C info method registrationhandle "bar b"]} "x:int y:upper" ? {C info method parameters [C info method registrationhandle "bar baz y"]} "x:int y:upper" # # check methods paths as method specifications # ? {C info method definition "bar b"} {::C public method {bar b} {x:int y:upper} {return b}} ? {C info method definition "::nsf::classes::C::bar b"} {::C public method {bar b} {x:int y:upper} {return b}} ? {o2 info object method definition "::nsf::classes::C::bar b"} {::C public method {bar b} {x:int y:upper} {return b}} # # test class modifier on handles # ? {C info object method registrationhandle "foo"} {::C::foo} ? {C info object method registrationhandle "foo x"} {::C::foo x} # # info method definition with method paths # ? {C info object method definition "::C::foo x"} {::C public object method {foo x} z:int {return z}} ? {C info method definition "::C::foo x"} {::C public object method {foo x} z:int {return z}} ? {o2 info object method definition "::C::foo x"} {::C public object method {foo x} z:int {return z}} ? {C info method definition "bar baz y"} \ {::C public method {bar baz y} {x:int y:upper} {return y}} ? {C info method definition "::nsf::classes::C::bar baz y"} \ {::C public method {bar baz y} {x:int y:upper} {return y}} # # test "info method parameters" # ? {nx::Object info method parameters "info lookup methods"} \ "-callprotection -incontext:switch -type -nomixins:switch -path:switch -source pattern:optional" ? {nx::Object info method syntax "info lookup methods"} \ "/cls/ info lookup methods ?-callprotection all|public|protected|private? ?-incontext? ?-type all|scripted|builtin|alias|forwarder|object|setter|nsfproc? ?-nomixins? ?-path? ?-source all|application|system? ?/pattern/?" ? {o info object method parameters "foo b"} "x:int y:upper" ? {nx::Object info method parameters ::nx::Object::slot::__info::lookup::methods} \ "-callprotection -incontext:switch -type -nomixins:switch -path:switch -source pattern:optional" ? {o info object method parameters "::o::foo::b"} "x:int y:upper" ? {nx::Object info method registrationhandle "info"} "::nsf::classes::nx::Object::info" ? {nx::Object info method registrationhandle "info lookup methods"} \ "::nsf::classes::nx::Object::info lookup methods" ? {nx::Object info method registrationhandle "::nsf::classes::nx::Object::info lookup methods"} \ "::nsf::classes::nx::Object::info lookup methods" ? {o info object method registrationhandle "foo b"} "::o::foo b" } # # test info slot parameter|parametersyntax # nx::test case info-slot-parametersyntax { nx::Class create C { :property a :property {b 1} } nx::Class create D -superclass C { :property {b 2} :property c :object property -accessor public a2 :method "sub foo" args {;} } C new ? {C info lookup syntax create} "/objectName/ ?-a /value/? ?-b /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?" ? {C info lookup syntax create a} "?-a /value/?" ? {C info lookup parameters create } "objectName -a {-b 1} -object-mixins:mixinreg,slot=::nx::Object::slot::object-mixins,slotset,method=object-mixin,0..n -object-filters:filterreg,slot=::nx::Object::slot::object-filters,slotset,method=object-filter,0..n -class:class,alias,method=::nsf::methods::object::class __initblock:cmd,optional,nodashalnum" #? {C info parameter list} "-a -b -noinit -object-mixins -class -object-filters __initblock" #? {C info lookup args create} "methodName a b noinit object-mixin class object-filter __initblock" ? {lsort [C info slots -closure]} "::C::slot::a ::C::slot::b ::nx::Object::slot::__initblock ::nx::Object::slot::class ::nx::Object::slot::object-filters ::nx::Object::slot::object-mixins" ? {C info lookup parameters create b} "{-b 1}" ? {D info lookup parameters create b} "{-b 2}" ? {D info slots -closure b} "::D::slot::b" ? {D info slots -closure a} "::C::slot::a" ? {D info slots -closure class} "::nx::Object::slot::class" # ? {D info parameter list} "-b -c -a -noinit -object-mixins -object-filters -class __initblock" # ? {D info parameter names} "b c a noinit object-mixins object-filters class __initblock" } # # test "info methods -path" # nx::test case info-methods-path { # # test case on base class # ? {::nx::Object info methods "info"} "info" ? {::nx::Object info methods -path "info"} "" ? {lsort [::nx::Object info methods -path "info lookup *"]} \ "{info lookup filter} {info lookup filters} {info lookup method} {info lookup methods} {info lookup mixins} {info lookup parameters} {info lookup slots} {info lookup syntax} {info lookup variables}" ? {lsort [::nx::Object info methods -path "info *parameter*"]} \ "{info lookup parameters} {info object method parameters} {info variable parameter}" ? {lsort [::nx::Object info methods "slots"]} "" ? {lsort [::nx::Object info methods "*slots*"]} "" ? {lsort [::nx::Object info methods -path "*slot*"]} \ "{info lookup slots} {info object slots}" ? {lsort [::nx::Object info methods -path "*filter*"]} \ "{info lookup filter} {info lookup filters} {info object filters} {object filters}" ::nx::Class create C { :public method "string length" {s} {puts length} :public method "string reverse" {s} {puts reverse} :public method foo {} {puts foo} :protected method "a b c" {} {puts "a b c"} :protected method "a b d" {} {puts "a b d"} :public method "a c" {d c} {puts "a c"} :create c1 } nx::Class create D -superclass C { :public method "string length" {s} {puts length} :public method "string compress" {s} {puts compress} :create d1 } ? {lsort [C info methods -path -callprotection all]} \ "{a b c} {a b d} {a c} foo {string length} {string reverse}" ? {lsort [C info methods -path]} \ "{a c} foo {string length} {string reverse}" # # lookup ensemble methods # ? {lsort [c1 info lookup methods -path "string *"]} \ "{string length} {string reverse}" # # lookup ensemble methods combined from multiple classes # ? {lsort [d1 info lookup methods -path "string *"]} \ "{string compress} {string length} {string reverse}" # # search for ensemble method # ? {lsort [d1 info lookup method "string length"]} "::nsf::classes::D::string length" ? {lsort [d1 info lookup method "string reverse"]} "::nsf::classes::C::string reverse" } # # Test parameter syntax for a methods and cmds # nx::test case parametersyntax { # a true method ? {::nx::Class info method syntax method} \ "/cls/ method ?-debug? ?-deprecated? /name/ /arguments/ ?-checkalways? ?-returns /value/? /body/" # a forwarder to ::nsf::relation; definition comes via array ::nsf::parametersyntax ? {::nx::Class info method syntax mixins} "/cls/ mixins add /class/|classes ?/pattern/?|clear|delete /class/|get|guard /class/ /?expr?/|set /class .../" ? {::nx::Class info method syntax ::nx::next} "/cls/ next ?/arguments/?" ? {::nx::Class info method syntax ::nsf::xotclnext} "/cls/ xotclnext ?--noArgs? ?/arg .../?" } # # Test info heritage, base cases # nx::test case info-heritage { Class create A Class create B -superclass A Class create BB -superclass B Class create C -superclass A Class create CC -superclass C Class create D -superclass A Class create M1 Class create M2 -superclass A ? {A info heritage} "::nx::Object" ? {B info heritage} "::A ::nx::Object" ? {M1 info heritage} "::nx::Object" ? {M2 info heritage} "::A ::nx::Object" B mixins add M1 ? {A info heritage} "::nx::Object" ? {B info heritage} "::M1 ::A ::nx::Object" ? {B info mixins -closure} "::M1" B mixins set M2 ? {A info heritage} "::nx::Object" ? {B info heritage} "::M2 ::A ::nx::Object" ? {B info mixins -closure} "::M2" B mixins set A ? {A info heritage} "::nx::Object" ? {B info heritage} "::A ::nx::Object" B mixins set C ? {A info heritage} "::nx::Object" ? {B info heritage} "::C ::A ::nx::Object" B mixins set "" ? {BB info heritage} "::B ::A ::nx::Object" BB mixins set CC ? {BB info heritage} "::CC ::C ::B ::A ::nx::Object" BB mixins set "" ? {BB info heritage} "::B ::A ::nx::Object" } # # Test transitive per-class mixins # nx::test case info-heritage-transitive { Class create O Class create A -superclass O Class create B -superclass A Class create C -superclass A Class create D -superclass A # transitive case C mixins set D B mixins set C ? {C info heritage} "::D ::A ::O ::nx::Object" ? {D info heritage} "::A ::O ::nx::Object" ? {B info heritage} "::D ::C ::A ::O ::nx::Object" # reset C mixins set "" B mixins set "" ? {B info heritage} "::A ::O ::nx::Object" ? {C info heritage} "::A ::O ::nx::Object" ? {D info heritage} "::A ::O ::nx::Object" # transitve different order B mixins set C C mixins set D ? {B info heritage} "::D ::C ::A ::O ::nx::Object" ? {C info heritage} "::D ::A ::O ::nx::Object" ? {D info heritage} "::A ::O ::nx::Object" # reset C mixins set "" B mixins set "" ? {B info heritage} "::A ::O ::nx::Object" ? {C info heritage} "::A ::O ::nx::Object" ? {D info heritage} "::A ::O ::nx::Object" } # # Test circular mixins # nx::test case info-heritage-circular { Class create O Class create A -superclass O Class create B -superclass A Class create BB -superclass B Class create C -superclass A Class create CC -superclass C Class create D -superclass A Class create M3 Class create M2 -superclass A Class create M # circular case ? {B mixins set C} "::C" ? {C mixins get} "" #? {C mixins set B} "classes dependent on ::C contain a cycle" #? {C mixins get} "" ;# make sure, the mixin list of C was reset ? {C mixins set B} "::B" ? {C mixins get} "::B" ? {B info heritage} "::C ::A ::O ::nx::Object" ? {C info heritage} "::B ::A ::O ::nx::Object" #? {C info heritage} "::A ::O ::nx::Object" ? {D info heritage} "::A ::O ::nx::Object" # reset C mixins set "" B mixins set "" ? {B info heritage} "::A ::O ::nx::Object" ? {C info heritage} "::A ::O ::nx::Object" ? {D info heritage} "::A ::O ::nx::Object" # indirect circular case B mixins set C ? {C mixins get} "" ? {C mixins set BB} "::BB" #? {C mixins set BB} "classes dependent on ::C contain a cycle" #? {C mixins get} "" ? {B info heritage} "::BB ::C ::A ::O ::nx::Object" ? {C info heritage} "::BB ::B ::A ::O ::nx::Object" #? {B info heritage} "::C ::A ::O ::nx::Object" #? {C info heritage} "::A ::O ::nx::Object" ? {D info heritage} "::A ::O ::nx::Object" # reset C mixins set "" B mixins set "" ? {B info heritage} "::A ::O ::nx::Object" ? {C info heritage} "::A ::O ::nx::Object" ? {D info heritage} "::A ::O ::nx::Object" ? {M3 mixins set B} ::B ? {A info heritage} "::O ::nx::Object" ? {B info heritage} "::A ::O ::nx::Object" ? {M3 info heritage} "::B ::A ::O ::nx::Object" ? {A mixins set M3} "::M3" ? {A info heritage} "::B ::M3 ::O ::nx::Object" ? {B info heritage} "::M3 ::A ::O ::nx::Object" #? {A mixins set M3} "classes dependent on ::A contain a cycle" #? {A info heritage} "::O ::nx::Object" #? {B info heritage} "::A ::O ::nx::Object" ? {M3 create m1} ::m1 ? {m1 info precedence} "::B ::A ::O ::M3 ::nx::Object" ? {M3 info heritage} "::B ::A ::O ::nx::Object" ? {B mixins set M3} ::M3 ? {B info heritage} "::M3 ::A ::O ::nx::Object" #? {B mixins set M3} {classes dependent on ::B contain a cycle} #? {B info heritage} "::A ::O ::nx::Object" } # # Mixin the same class twice, once per-class and one per-object. # nx::test case info-heritage-simple-multimix { Class create Agent Class create MovementTest Class create MovementLog Agent mixins set MovementTest Agent create a1 ? {Agent info heritage} "::MovementTest ::nx::Object" ? {a1 info precedence} "::MovementTest ::Agent ::nx::Object" a1 object mixins set {MovementTest MovementLog} ? {Agent info heritage} "::MovementTest ::nx::Object" ? {a1 info precedence} "::MovementTest ::MovementLog ::Agent ::nx::Object" } # # Mixin several classes at several class levels and on the object # level # nx::test case info-heritage-multimix { Class create A Class create B -superclass A Class create M1 Class create M2 Class create M3 Class create M4 B create b1 ? {B info heritage} "::A ::nx::Object" ? {b1 info precedence} "::B ::A ::nx::Object" ? {b1 info precedence ::M*} "" A mixins set {M1 M2} ? {B info heritage} "::M1 ::M2 ::A ::nx::Object" ? {b1 info precedence} "::M1 ::M2 ::B ::A ::nx::Object" ? {b1 info precedence ::M*} "::M1 ::M2" ? {b1 info precedence ::X*} "" b1 object mixins set {M1 M1 M4} ? {b1 info precedence} "::M1 ::M4 ::M2 ::B ::A ::nx::Object" ? {b1 info object mixins} "::M1 ::M4" B mixins set {M3 M1 M1 M4} ? {B info heritage} "::M3 ::M1 ::M4 ::M2 ::A ::nx::Object" ? {b1 info precedence} "::M1 ::M4 ::M3 ::M2 ::B ::A ::nx::Object" } # # per-object mixin with implied classes # nx::test case info-heritage-multimix { Class create A Class create B -superclass A Class create C Class create PCM -superclass A C create c1 ? {c1 info precedence} "::C ::nx::Object" # ::A is an implied class c1 object mixins set B ? {c1 info precedence} "::B ::A ::C ::nx::Object" ? {c1 info lookup mixins} "::B ::A" # ::A is as well implied by ::PCM C mixins set PCM ? {C info heritage} "::PCM ::A ::nx::Object" ? {C info mixins} "::PCM" ? {C info mixins -order} "" ;# ???? why no warning ? {C info mixins -heritage} "::PCM ::A" ? {C info mixins -closure} "::PCM" # ::A is not ordered after ::B but after ::PCM ? {c1 info precedence} "::B ::PCM ::A ::C ::nx::Object" ? {c1 info lookup mixins} "::B ::PCM ::A" } # # transitive per-class mixins with implied classes # nx::test case info-heritage-transitive-pcm { Class create A Class create B -superclass A Class create C -superclass B Class create PCMA -superclass A Class create PCMB -superclass PCMA Class create PCMC -superclass PCMB Class create TPCMA Class create TPCMB -superclass TPCMA C create c1 ? {C info heritage} "::B ::A ::nx::Object" ? {c1 info precedence} "::C ::B ::A ::nx::Object" B mixins set PCMB # heritage includes implied classes ? {C info heritage} "::PCMB ::PCMA ::B ::A ::nx::Object" # precedence includes implied classes from mixins or intrinsic # classes ? {c1 info precedence} "::PCMB ::PCMA ::C ::B ::A ::nx::Object" # just the classes mixed explicitly into this class ? {B info mixins} "::PCMB" ? {C info mixins} "" # the classes mixed transitive into this class; This answer the # question, what classes were mixed in explicitly into the mixin # hierarchy by the application program ? {B info mixins -closure} "::PCMB" # since C is a specialization of B, it includes transitively B's closure ? {C info mixins -closure} "::PCMB" # the explicit and implicit mixins ? {B info mixins -heritage} "::PCMB ::PCMA ::A" # since C is a specialization of B, it inherits the classes from B ? {C info mixins -heritage} "::PCMB ::PCMA ::A" PCMB mixins set TPCMB # heritage includes implied classes ? {C info heritage} "::TPCMB ::TPCMA ::PCMB ::PCMA ::B ::A ::nx::Object" # precedence includes implied classes from mixins or intrinsic # classes ? {c1 info precedence} "::TPCMB ::TPCMA ::PCMB ::PCMA ::C ::B ::A ::nx::Object" # just the classes mixed explicitly into this class ? {B info mixins} "::PCMB" ? {C info mixins} "" # the classes mixed transitive into this class ? {B info mixins -closure} "::PCMB ::TPCMB" # since C is a specialization of B, it includes transitively B's closure ? {C info mixins -closure} "::PCMB ::TPCMB" # the explicit and implicit mixins ? {B info mixins -heritage} "::TPCMB ::TPCMA ::PCMB ::PCMA ::A" # since C is a specialization of B, it inherits the classes from B ? {C info mixins -heritage} "::TPCMB ::TPCMA ::PCMB ::PCMA ::A" C mixins set PCMC # heritage includes implied classes ? {C info heritage} "::PCMC ::TPCMB ::TPCMA ::PCMB ::PCMA ::B ::A ::nx::Object" # precedence includes implied classes from mixins or intrinsic # classes ? {c1 info precedence} "::PCMC ::TPCMB ::TPCMA ::PCMB ::PCMA ::C ::B ::A ::nx::Object" # just the classes mixed explicitly into this class ? {B info mixins} "::PCMB" ? {C info mixins} "::PCMC" # the classes mixed transitive into this class ? {B info mixins -closure} "::PCMB ::TPCMB" ? {C info mixins -closure} "::PCMC ::TPCMB ::PCMB" # the explicit and implicit mixins ? {B info mixins -heritage} "::TPCMB ::TPCMA ::PCMB ::PCMA ::A" ? {C info mixins -heritage} "::PCMC ::TPCMB ::TPCMA ::PCMB ::PCMA ::A" } # # ::nsf::method::ishandle # nx::test case method-isregistered { ? {::nsf::method::registered c} "" ? {::nsf::method::registered info} "" ? {::nsf::method::registered ::info} "" Class create C { :method bar {} {return bar} set h1 [:info method registrationhandle bar] ? [list set _ $h1] "::nsf::classes::C::bar" ? [list [self] info method registrationhandle bar] "::nsf::classes::C::bar" ? [list ::nsf::method::registered $h1] ::C :object method bar {} {return bar} set h2 [:info object method registrationhandle bar] ? [list [self] info object method registrationhandle bar] "::C::bar" ? [list ::nsf::method::registered $h2] ::C } Object create o { :object method bar {} {return bar} set h1 [:info object method registrationhandle bar] ? [list set _ $h1] "::o::bar" ? [list [self] info object method registrationhandle bar] "::o::bar" ? [list ::nsf::method::registered $h1] ::o } } # # Testing "... info method origin ..." (in contrast to "... info method # handle ..."). "origin" always points to the definition handle, # "handle" alone is the registration handle. # nx::test case method-origin { nx::Class create C ? {set implHandle [C public method "foo bar" {x} {;}]} "::C::slot::__foo::bar" ? {set regHandle [C info method registrationhandle "foo bar"]} "::nsf::classes::C::foo bar" ? {set origin [C info method definitionhandle "foo bar"]} "::C::slot::__foo::bar" ? {set implHandle [C public object method "foo bar" {x} {;}]} "::C::foo::bar" ? {set regHandle [C info object method registrationhandle "foo bar"]} "::C::foo bar" ? {set origin [C info object method definitionhandle "foo bar"]} "::C::foo::bar" Object create o ? {set implHandle [o public object method "foo bar" {x} {;}]} "::o::foo::bar" ? {set regHandle [o info object method registrationhandle "foo bar"]} "::o::foo bar" ? {set origin [o info object method definitionhandle "foo bar"]} "::o::foo::bar" } # # test "info methods -closure" # nx::test case info-methods-closure { nx::Class create C { :public method c1 {} {...} :method c2 {} {...} } nx::Class create D -superclass C { :public method c1 {} {...} :public method d1 {} {...} :method d2 {} {...} } nx::Class create M { :public method m1 {} {...} :method m2 {} {...} } ? {D info methods} "c1 d1 d2" # # info methods -closure lists instance methods # ? {D info methods -closure *2} "d2 c2" ? {D info methods -closure -source application} "c1 d1 d2 c2" D mixins set M # # Check as well methods inherited from per-class mixins # ? {D info methods} "c1 d1 d2" ? {D info methods -closure *2} "m2 d2 c2" ? {D info methods -closure -source application} "m1 m2 c1 d1 d2 c2" } # # Test error messages within an ensemble call # nx::test case error-in-ensemble { ? {nx::Object info method definition foo 1} {wrong # args: should be "definition name"} ? {nx::Object info subclasses I R G H} {invalid argument 'R', maybe too many arguments; should be "::nx::Object info subclasses ?-closure? ?-dependent? ?/pattern/?"} } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/alias.test000644 000766 000024 00000060045 13712264152 016334 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx package require nx::test #::nx::configure defaultMethodCallProtection false nx::test configure -count 10 nx::test case alias-preliminaries { # The system methods of nx::VariableSlot are either alias or forwarders ? {lsort [::nx::VariableSlot info methods -type alias]} {value=get value=set} ? {::nx::VariableSlot info method definition value=get} \ "::nx::VariableSlot public alias value=get ::nsf::var::get" # define an alias and retrieve its definition set cmd "::nx::Object public alias set ::set" eval $cmd ? {nx::Object info method definition set} $cmd # define an alias and retrieve its definition set cmd "::nx::Object public alias set -frame method ::set" eval $cmd ? {nx::Object info method definition set} $cmd # define an alias and retrieve its definition set cmd "::nx::Object public alias set -frame object ::set" eval $cmd ? {nx::Object info method definition set} $cmd proc ::foo {} {return foo} ? {nx::Object alias foo -frame object ::foo} \ "cannot use -frame object|method in alias for scripted command '::foo'" ? {nx::Object alias foo -frame method ::foo} \ "cannot use -frame object|method in alias for scripted command '::foo'" ? {nx::Object alias foo -frame default ::foo} "::nsf::classes::nx::Object::foo" } nx::test case alias-simple { # define an alias and retrieve its definition nx::Class create Base { :public method foo {{-x 1}} {return $x} } nx::Class create Foo ? {::nsf::method::alias ::Foo foo ::nsf::classes::Base::foo} "::nsf::classes::Foo::foo" ? {Foo info method definition foo} "::Foo public alias foo ::nsf::classes::Base::foo" Foo create f1 ? {f1 foo} 1 ? {f1 foo -x 2} 2 ? {Foo info methods -type alias} "foo" ? {Base info methods -type scripted} {foo} ? {Foo info methods -type scripted} {} ? {Foo info methods -type alias} {foo} Base public method foo {} {} #WITH_IMPORT_REFS #? {Foo info methods -type alias} "" ? {Base info methods -type scripted} {} ? {Foo info methods -type scripted} {} #WITH_IMPORT_REFS #? {Foo info method definition foo} "" ? {Foo info method definition foo} "::Foo public alias foo ::nsf::classes::Base::foo" Base public method foo {{-x 1}} {return $x} ::nsf::method::alias ::Foo foo ::nsf::classes::Base::foo ? {Base info methods -type scripted} {foo} "defined again" ? {Foo info methods -type alias} {foo} "aliased again" Foo public method foo {} {} ? {Base info methods -type scripted} {foo} "still defined" ? {Foo info methods -type alias} {} "removed" } nx::test case alias-chaining { # # chaining aliases # nx::Class create T nx::Class create S T create t S create s T public method foo args { return [current class]->[current method] } ::nsf::method::alias T FOO ::nsf::classes::T::foo ? {t foo} ::T->foo ? {t FOO} ::T->FOO ? {lsort [T info methods]} {FOO foo} T method foo {} {} #WITH_IMPORT_REFS #? {lsort [T info methods]} {} "alias is deleted" ? {lsort [T info methods]} {FOO} "alias is deleted" # puts stderr "double indirection" T public method foo args { return [current class]->[current method] } ::nsf::method::alias T FOO ::nsf::classes::T::foo ::nsf::method::alias S BAR ::nsf::classes::T::FOO ? {T info methods -type alias} "FOO" ? {T info method definition FOO} "::T public alias FOO ::nsf::classes::T::foo" ? {lsort [T info methods]} {FOO foo} ? {S info methods} {BAR} T method FOO {} {} ? {T info methods} {foo} ? {S info methods} {BAR} ? {s BAR} ::S->BAR ? {t foo} ::T->foo ? {S info method definition BAR} "::S public alias BAR ::nsf::classes::T::FOO" T public method foo {} {} ? {T info methods} {} #WITH_IMPORT_REFS #? {S info methods} {} ? {S info methods} {BAR} T public method foo args { return [current class]->[current method] } ::nsf::method::alias T FOO ::nsf::classes::T::foo ::nsf::method::alias S BAR ::nsf::classes::T::FOO ? {lsort [T info methods]} {FOO foo} ? {S info methods} {BAR} T public method foo {} {} #WITH_IMPORT_REFS #? {S info methods} {} ? {S info methods} {BAR} #WITH_IMPORT_REFS #? {T info methods} {} ? {T info methods} {FOO} T public method foo args { return [current class]->[current method] } T public object method bar args { return [current class]->[current method] } ::nsf::method::alias T -per-object FOO ::nsf::classes::T::foo ::nsf::method::alias T -per-object BAR ::T::FOO ::nsf::method::alias T -per-object ZAP ::T::BAR #WITH_IMPORT_REFS #? {T info methods} {foo} ? {T info methods} {foo FOO} ? {lsort [T info object methods -type alias]} {BAR FOO ZAP} ? {lsort [T info object methods]} {BAR FOO ZAP bar} ? {t foo} ::T->foo ? {T info object method definition ZAP} {::T public object alias ZAP ::T::BAR} ? {T FOO} ->FOO ? {T BAR} ->BAR ? {T ZAP} ->ZAP ? {T bar} ->bar T object method FOO {} {} #WITH_IMPORT_REFS #? {T info methods} {foo} ? {T info methods} {foo FOO} ? {lsort [T info object methods]} {BAR ZAP bar} ? {T BAR} ->BAR ? {T ZAP} ->ZAP rename ::T::BAR "" #WITH_IMPORT_REFS #? {T info methods} {foo} ? {T info methods} {foo FOO} ? {lsort [T info object methods]} {ZAP bar} ? {T ZAP} ->ZAP; # is ok, still pointing to 'foo' #WITH_IMPORT_REFS #? {T info methods} {foo} ? {T info methods} {foo FOO} ? {lsort [T info object methods]} {ZAP bar} ? {T ZAP} ->ZAP T public method foo {} {} #WITH_IMPORT_REFS #? {T info methods} {} ? {T info methods} {FOO} #WITH_IMPORT_REFS #? {lsort [T info object methods]} {bar} ? {lsort [T info object methods]} {ZAP bar} } nx::test case alias-per-object { nx::Class create T { :public object method bar args { return [current class]->[current method] } :create t } proc ::foo args { return [current class]->[current method] } # # per-object methods as per-object aliases # T public object method m1 args { return [current class]->[current method] } ::nsf::method::alias T -per-object M1 ::T::m1 ::nsf::method::alias T -per-object M11 ::T::M1 ? {lsort [T info object methods]} {M1 M11 bar m1} ? {T m1} ->m1 ? {T M1} ->M1 ? {T M11} ->M11 T object method M1 {} {} ? {lsort [T info object methods]} {M11 bar m1} ? {T m1} ->m1 ? {T M11} ->M11 T object method m1 {} {} #WITH_IMPORT_REFS #? {lsort [T info object methods]} {bar} ? {lsort [T info object methods]} {M11 bar} # # a proc as alias # proc foo args { return [current class]->[current method] } ::nsf::method::alias T FOO1 ::foo ::nsf::method::alias T -per-object FOO2 ::foo # # ! per-object alias referenced as per-class alias ! # ::nsf::method::alias T BAR ::T::FOO2 #WITH_IMPORT_REFS #? {lsort [T info object methods]} {FOO2 bar} ? {lsort [T info object methods]} {FOO2 M11 bar} ? {lsort [T info methods]} {BAR FOO1} ? {T FOO2} ->FOO2 ? {t FOO1} ::T->FOO1 ? {t BAR} ::T->BAR # # delete proc # rename ::foo "" #WITH_IMPORT_REFS #? {lsort [T info object methods]} {bar} ? {lsort [T info object methods]} {FOO2 M11 bar} #WITH_IMPORT_REFS #? {lsort [T info methods]} {} ? {lsort [T info methods]} {BAR FOO1} } # namespaced procs + namespace deletion nx::test case alias-namespaced { nx::Class create T { :public object method bar args { return [current class]->[current method] } :create t } namespace eval ::ns1 { proc foo args { return [current class]->[current method] } proc bar args { return [uplevel 1 {set _}] } proc bar2 args { upvar 1 _ __; return $__} } ::nsf::method::alias T FOO ::ns1::foo ::nsf::method::alias T BAR ::ns1::bar ::nsf::method::alias T BAR2 ::ns1::bar2 ? {lsort [T info methods]} {BAR BAR2 FOO} set ::_ GOTYA ? {t FOO} ::T->FOO ? {t BAR} GOTYA ? {t BAR2} GOTYA namespace delete ::ns1 ? {info procs ::ns1::*} {} #WITH_IMPORT_REFS #? {lsort [T info methods]} {} ? {lsort [T info methods]} {BAR BAR2 FOO} # per-object namespaces nx::Class create U U create u ? {namespace exists ::U} 0 U public object method zap args { return [current class]->[current method] } ::nsf::method::alias ::U -per-object ZAP ::U::zap U require namespace ? {namespace exists ::U} 1 U public object method bar args { return [current class]->[current method] } ::nsf::method::alias U -per-object BAR ::U::bar ? {lsort [U info object methods]} {BAR ZAP bar zap} ? {U BAR} ->BAR ? {U ZAP} ->ZAP namespace delete ::U ? {namespace exists ::U} 0 ? {lsort [U info object methods]} {} ? {U info lookup methods BAR} "" ? {U info lookup methods ZAP} "" ::U destroy } # dot-resolver/ dot-dispatcher used in aliased proc nx::test case alias-dot-resolver { nx::Class create V { set :z 1 :public method bar {z} { return $z } :public object method bar {z} { return $z } :create v { set :z 2 } } ? {lsort [V info vars]} {z} ? {lsort [V info vars]} {z} ? {lsort [v info vars]} {z} proc ::foo args { return [:bar ${:z}]-[set :z]-[:bar [set :z]] } ::nsf::method::alias V FOO1 ::foo ::nsf::method::alias V -per-object FOO2 ::foo ? {lsort [V info object methods]} {FOO2 bar} ? {lsort [V info methods]} {FOO1 bar} ? {V FOO2} 1-1-1 ? {v FOO1} 2-2-2 V public method FOO1 {} {} ? {lsort [V info methods]} {bar} rename ::foo "" #WITH_IMPORT_REFS #? {lsort [V info object methods]} {bar} ? {lsort [V info object methods]} {FOO2 bar} } nx::test case alias-store # # Tests for the ::nsf::method::alias store, used for introspection for # aliases. The alias store (an associative variable) is mostly # necessary for the direct aliases (e.g. aliases to C implemented # tcl commands), for which we have no stubs at the place where the # alias was registered. # # # structure of the ::nsf::method::alias store: # ,, -> # nx::Object create o nx::Class create C ? {o public object method bar args {;}} ::o::bar ? {o info object methods bar} bar ? {info commands ::o::bar} ::o::bar "a command ::o::bar exists" ? {info vars ::nsf::alias} ::nsf::alias ? {array exists ::nsf::alias} 1 proc ::foo args {;} ? {::nsf::method::alias ::o FOO ::foo} ::o::FOO ? {::nsf::method::alias ::C FOO ::foo} ::nsf::classes::C::FOO ? {info commands ::o::FOO} ::o::FOO ? {info commands ::nsf::classes::C::FOO} ::nsf::classes::C::FOO ? {info exists ::nsf::alias(::o,FOO,1)} 1 ? {info exists ::nsf::alias(::C,FOO,0)} 1 ? {array get ::nsf::alias ::o,FOO,1} "::o,FOO,1 ::foo" ? {array get ::nsf::alias ::C,FOO,0} "::C,FOO,0 ::foo" ? {o info object method definition FOO} "::o public object alias FOO ::foo" ? {C info method definition FOO} "::C public alias FOO ::foo" ? {::nsf::method::alias o FOO ::o::bar} ::o::FOO "redefine alias ::o::FOO" ? {info exists ::nsf::alias(::o,FOO,1)} 1 ? {array get ::nsf::alias ::o,FOO,1} "::o,FOO,1 ::o::bar" ? {o info object method definition FOO} "::o public object alias FOO ::o::bar" # AliasDelete in RemoveObjectMethod o public object method FOO {} {} ? {info exists ::nsf::alias(::o,FOO,1)} 0 ? {array get ::nsf::alias ::o,FOO,1} "" ? {o info object method definition FOO} "" # AliasDelete in RemoveClassMethod C public method FOO {} {} ? {info exists ::nsf::alias(::C,FOO,0)} 0 ? {array get ::nsf::alias ::C,FOO,0} "" ? {C info method definition FOO} "" ? {info commands ::foo} ::foo "the target command ::foo exists" ? {::nsf::method::alias ::o BAR ::foo} ::o::BAR ? {::nsf::method::alias ::C BAR ::foo} ::nsf::classes::C::BAR # AliasDelete in AddObjectMethod ? {info exists ::nsf::alias(::o,BAR,1)} 1 "delete alias via redefinition of an object method (alias exists still)" ? {info commands ::o::BAR} ::o::BAR ? {info commands ::BAR} "" ? {::o public object method BAR {} {;}} ::o::BAR ? {o info object methods BAR} BAR ? {info commands ::o::BAR} ::o::BAR "a command ::o::BAR exists" ? {info commands ::BAR} "" ? {info exists ::nsf::alias(::o,BAR,1)} 0 "::o::BAR is not an alias" # AliasDelete in AddInstanceMethod ? {info exists ::nsf::alias(::C,BAR,0)} 1 "delete alias via redefinition of a an instance method" ::C public method BAR {} {;} ? {info exists ::nsf::alias(::C,BAR,0)} 0 ? {info commands ::o::BAR} ::o::BAR "a command ::o::BAR does not exist" # AliasDelete in aliasCmdDeleteProc ::nsf::method::alias o FOO ::foo ? {info exists ::nsf::alias(::o,FOO,1)} 1 "delete alias via deleting the aliased proc via Tcl" rename ::foo "" #WITH_IMPORT_REFS #? {info exists ::nsf::alias(::o,FOO,1)} 0 ? {info exists ::nsf::alias(::o,FOO,1)} 1 ? {info commands ::o::bar} ::o::bar "::o::bar does not exist" ? {info commands ::o::FOO} ::o::FOO "a command ::o::FOO' exists" ? {info commands ::o::BAR} ::o::BAR "a command ::o::BAR does not exist" ? {::nsf::method::alias o FOO ::o::bar} ::o::FOO "redefine an object alias based on existing (?) ::o::bar" ? {::nsf::method::alias o BAR ::o::FOO} ::o::BAR "define an object alias based on alias based on existing (?) ::o::bar" ? {info exists ::nsf::alias(::o,FOO,1)} 1 ? {info exists ::nsf::alias(::o,BAR,1)} 1 o public object method bar {} {} #WITH_IMPORT_REFS #? {info exists ::nsf::alias(::o,FOO,1)} 0 ? {info exists ::nsf::alias(::o,FOO,1)} 1 #WITH_IMPORT_REFS #? {info exists ::nsf::alias(::o,BAR,1)} 0 ? {info exists ::nsf::alias(::o,BAR,1)} 1 # # pulling the rug out from the proc-alias deletion mechanism # proc ::foo args {;} ::nsf::method::alias C FOO ::foo ? {info exists ::nsf::alias(::C,FOO,0)} 1 unset ::nsf::alias(::C,FOO,0) ? {info exists ::nsf::alias(::C,FOO,0)} 0 ? {C info method definition FOO} "" ? {C info methods -type alias} FOO rename ::foo "" #WITH_IMPORT_REFS #? {C info methods -type alias} "" ? {C info methods -type alias} "FOO" ? {info exists ::nsf::alias(::C,FOO,0)} 0 ? {C info method definition FOO} "" # # test renaming of Tcl proc (actually sensed by the alias, though not # reflected by the alias definition store) # a) is this acceptable? # b) sync ::nsf::method::alias upon "info method definition" calls? is this feasible, # e.g. through rename traces? # C create c proc ::foo args { return [current]->[current method]} ? {info exists ::nsf::alias(::C,FOO,0)} 0 ::nsf::method::alias C FOO ::foo ::nsf::method::alias C FOO2 ::foo ? {info exists ::nsf::alias(::C,FOO,0)} 1 ? {lsort [C info methods -type alias]} {FOO FOO2} # Rename target, such that alias points to an invalid item # Note that removing the target works differently (makes cleanup) # rename ::foo "" rename ::foo ::foo2 ? {info exists ::nsf::alias(::C,FOO,0)} 1 ? {lsort [C info methods -type alias]} {FOO FOO2} ? {c FOO} {target "::foo" of alias FOO apparently disappeared} ? {C info method definition FOO} "::C public alias FOO ::foo" unset ::nsf::alias(::C,FOO,0) ? {c FOO} {could not obtain alias definition for ::C FOO.} ? {c FOO2} {target "::foo" of alias FOO2 apparently disappeared} rename ::foo2 ::foo ? {c FOO} {could not obtain alias definition for ::C FOO.} ? {c FOO2} {::c->FOO2} # # Check resolving of namespace imported classes # and when a class is aliased via "interp alias" # nx::test case class-resolve { namespace eval ::ns1 { nx::Class create A {:public method foo {} {::nx::current class}} nx::Class create B {:public method foo {} {::nx::current class}} namespace export A } namespace eval ::ns2 { # namespace import Class A from namespace ns1 namespace import ::ns1::A ? {A create a1} ::ns2::a1 ? {nx::Class create C -superclass A} ::ns2::C ? {C create c1} ::ns2::c1 ? {c1 foo} ::ns1::A # "import" Class B from namespace ns1 via interp-alias interp alias {} ::ns2::B {} ::ns1::B ? {B create b1} ::ns2::b1 ? {b1 foo} ::ns1::B ? {nx::Class create D -superclass B} ::ns2::D ? {D create d1} ::ns2::d1 ? {d1 foo} ::ns1::B } } nx::test configure -count 10 nx::test case proc-alias { nx::Class create C { :public method foo {} {upvar x y; info exists y} :public method bar {} {set x 1; :foo} :public alias bar_ [:info method registrationhandle bar] :public alias foo_ [:info method registrationhandle foo] :public method bar2 {} {set x 1; :foo_} :create c1 } nx::Class create D { :public method foo {} {:upvar x y; info exists y} :public method bar {} {set x 1; :foo} :public alias foo_ [:info method registrationhandle foo] :public alias bar_ [:info method registrationhandle bar] :public method bar2 {} {set x 1; :foo_} :create d1 } nx::Class create M { :public method foo args next :public method bar args next :public method foo_ args next :public method bar_ args next :public method bar_ args next } ? {c1 bar} 1 ? {c1 bar_} 1 ? {c1 bar2} 1 ? {d1 bar} 1 ? {d1 bar_} 1 ? {d1 bar2} 1 c1 object mixins add M ? {c1 bar} 0 ;# upvar reaches into to mixin method ? {c1 bar_} 0 ;# upvar reaches into to mixin method ? {c1 bar2} 0 ;# upvar reaches into to mixin method d1 object mixins add M ? {d1 bar} 1 ? {d1 bar_} 1 ? {d1 bar2} 1 } proc foo {:a :b} { set :c 1 return ${:a} } foo 1 2 proc bar {:a :b} { set :b 1 set :x 47 return [info exists :d]-${:a}-${:x} } proc baz {} { set :z 3 return ${:z} } nx::test configure -count 10 nx::test case proc-alias-compile { nx::Object create o { set :a 100 set :d 1001 #:method foo {-:a:integer :b :c:optional} { # puts stderr ${:a},${:b},${:c} #} :public object alias foo ::foo :public object alias bar ::bar :public object alias baz ::baz } # # by calling "foo" outside the object/method context, we get a # byte-code without the compiled-local handler, colon-vars are not # recognized, :a refers to the argument ? {foo 1 2} 1 ? {lsort [o info vars]} "a d" ? {o foo 1 2} 1 ? {lsort [o info vars]} "a d" # # by calling "bar" the first time as a method, we get a byte-code with # the compiled-local handler, colon-vars are recognized, colon vars # from the argument vector have precedence over instance variables. ? {o bar 2 3} 1-2-47 ? {lsort [o info vars]} "a d x" ? {o baz} 3 ? {lsort [o info vars]} "a d x z" # # by calling "bar" outside the proc context, the compiled-var-fetch # has no object to refer to, the variable is unknown. ? {bar 3 4} 0-3-47 # the variable in the test scope does not influence result set :d 200 ? {bar 3 4} 0-3-47 } # # test redefinition of a target proc # nx::test configure -count 1 nx::test case alias-proc-refetch { # # initial definition # proc target {} {return 1} nx::Object create o {:public object alias foo ::target} ? {o foo} 1 # # redefinition # proc ::target {} {return 2} ? {o foo} 2 } # # test registration of a pre-compiled proc # nx::test configure -count 1 nx::test case alias-precompiled-proc { nx::Class create C { :public method vars {} { set result [list] foreach v [lsort [:info vars]] {lappend result $v [set :$v]} return $result } :create c1 } ? {c1 vars} {} proc ::foo {x} {set :a $x} proc ::bar {x} {set :b $x} # # force bytecode compilation of ::foo # ? {::foo 1} 1 # # Register an already used tcl proc. Byte compilation happened # without nsf context. If the byte code is not invalidated, the # compiled var resolver would not kick in, we would not be able to # set an instance variable. ::nsf::method::alias ::C foo ::foo ? {c1 foo 2} 2 ? {c1 vars} {a 2} # # Register an unused tcl proc. Byte compilation happens within nsf # context, compiled var resolver works as expected. ::nsf::method::alias ::C bar ::bar ? {c1 bar 2} 2 ? {c1 vars} {a 2 b 2} # Call proc from outside nx; does not set the variable, and does not # crash; seems ok, but could warn. ? {::bar 3} 3 ? {c1 vars} {a 2 b 2} # call proc from method context; it sets the variable, # maybe questionable, but not horrible c1 public object method baz {} {::bar 4} ? {c1 baz} 4 ? {c1 vars} {a 2 b 4} } # # Testing aliases to objects and reference counting. # Check the effects via MEM_COUNT... # nx::test case refcount-object-alias-recreate1 { # # alias recreate with the same object # nx::Object create ::x # per-object aliases nx::Object create ::o { :object alias X ::x ? {o info object method definition X} "::o protected object alias X ::x" :object alias X ::x ? {o info object method definition X} "::o protected object alias X ::x" } # per-class aliases nx::Class create ::C { :alias A1 ::x ? {C info method definition A1} "::C protected alias A1 ::x" :alias A1 ::x ? {C info method definition A1} "::C protected alias A1 ::x" :object alias A2 ::x ? {C info object method definition A2} "::C protected object alias A2 ::x" :object alias A2 ::x ? {C info object method definition A2} "::C protected object alias A2 ::x" } } nx::test case refcount-object-alias-recreate2 { # # alias recreate with a proc # nx::Object create ::x ::proc ::y {} {} nx::Object create ::o { :object alias X ::x ? {o info object method definition X} "::o protected object alias X ::x" :object alias X ::y ? {o info object method definition X} "::o protected object alias X ::y" } } nx::test case refount-destroy-delete1 { nx::Object create ::x nx::Object create ::o {:object alias X ::x} ? {o info object method definition X} "::o protected object alias X ::x" # destroy the object, make sure it does not exist anymore ? {x destroy} "" ? {nsf::object::exists x} 0 # The alias lookup does still work ? {o info object method definition X} "::o protected object alias X ::x" # Create the referenced object new nx::Object create ::x # Recreation of the alias, must free refcount to the old object ? {::o object alias X ::x} "::o::X" # Recreate the object. On recreation, the object is not freed, # therefore we test the reference counter is already set, and must # nor be incremented nx::Object create ::x ? {::o object alias X ::x} "::o::X" } nx::test case refount-destroy-delete2 { nx::Object create ::o nx::Object create ::baff nx::Object create ::baff::child ::o object alias X ::baff::child ? {nsf::object::exists ::baff::child} 1 ? {o info object method definition X} "::o protected object alias X ::baff::child" nx::Object create ::baff ? {nsf::object::exists ::baff::child} 0 # The alias lookup does still work ? {o info object method definition X} "::o protected object alias X ::baff::child" # Create the child new nx::Object create ::baff::child ? {nsf::object::exists ::baff::child} 1 # Recreation of the alias, must free refcount to the old object ? {::o object alias X ::baff::child} "::o::X" } # # Testing cylcic alias # nx::test case cyclic-alias { nx::Object create o { set handle [:public object method foo {} {return 1}] # we can define currently the recursive definition ? [list [:] public object alias foo $handle] "::o::foo" } # at run time, we get an exception #puts stderr ====== ? {o foo} {target "::o::foo" of alias foo apparently disappeared} # test indirect case set handle1 [o public object method foo {} {return 1}] set handle2 [o public object alias bar $handle1] set handle3 [o public object alias foo $handle2] ? {o foo} {target "::o::bar" of alias foo apparently disappeared} } # # Test namespace of aliased methods coming from different namespaces # nx::test case proc-alias-target-namespace { proc foo {} { set :foo 1 namespace current } namespace eval ns1 { proc bar {} { set :bar 1 namespace current } } namespace eval ns2 { nx::Object create o { :public object alias foo ::foo :public object alias bar ::ns1::bar :public object method baz {} {namespace current} } } namespace eval ns3 { nx::Object create o set handle [o public object method FOO {} {namespace current}] ::ns2::o public object alias FOO $handle } # # The following tests show, that the defining namespace of the # target method prevails always # ? {ns2::o foo} :: "alias to a global Tcl proc" ? {ns2::o bar} ::ns1 "alias to a namespaced Tcl proc" ? {ns2::o baz} ::ns2 "a method defined locally in ns2::o" ? {ns2::o FOO} ::ns3 "alias to method defined in ::ns3" } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/volatile.test000644 000766 000024 00000005417 14045312057 017062 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package req nx::test package prefer latest package req XOTcl 2.0 package req nx::volatile ::nsf::method::require ::nx::Object volatile # # Wrapper to call a command in a proc/method # proc bar {args} { set c [{*}$args] set empty [expr {[info command $c] eq ""}] ? [list set _ $empty] 0 "bar: $c destroyed too early" return $c } # # Create NX objects with volatile through the wrapper # proc foon {} { #puts stderr ====2 set c [bar C create c1 -volatile {:object method destroy {} {#puts "[self] destroy";next}}] ? [list info command $c] "" "foon: $c destroyed too late" #puts stderr ====3 set c [bar C new -volatile {:object method destroy {} {#puts "[self] destroy";next}}] ? [list info command $c] "" "foon: $c destroyed too late" } # # Create XOTcl objects with volatile through the wrapper # proc foox {} { #puts stderr ====1 set c [bar XC c1 -volatile -proc destroy {} {#puts "[self] destroy";next}] ? [list info command $c] "" "foox: $c destroyed too late" #puts stderr ====2 set c [bar XC create c1 -volatile -proc destroy {} {#puts "[self] destroy";next}] ? [list info command $c] "" "foox: $c destroyed too late" #puts stderr ====3 set c [bar XC new -volatile -proc destroy {} {#puts "[self] destroy";next}] ? [list info command $c] "" "foox: $c destroyed too late" } # # Producer classes in NX and XOTcl # ::nx::Class create C ::xotcl::Class create XC # # Create a NX class using foox, foon, and bar as methods # nx::Class create D { # # call volatile in nsf method bar # :method bar {args} [info body ::bar] :public method foox {} [string map [list bar :bar] [info body ::foox]] :public method foon {} [string map [list bar :bar] [info body ::foon]] # # call volatile in tcl proc bar # :public method foox2 {} [info body ::foox] :public method foon2 {} [info body ::foon] } D create d1 nx::test case methods-methods { d1 foox d1 foon } nx::test case methods-procs { d1 foox2 d1 foon2 } # # Call just in tcl procs # nx::test case procs-procs { ::foox ::foon } nx::test case self-context-volatile { xotcl::Class create C xotcl::Class create M M instproc configure args { next } C instproc destroy-after-run {} { my volatile set o2 [xotcl::Object new -volatile] xotcl::Object instmixin ::M set o3 [xotcl::Object new -volatile] xotcl::Object instmixin {} ? [info commands [self]] [self] ? [info commands $o2] $o2 ? [info commands $o3] $o3 return [list [self] $o2 $o3] } set c [C new] lassign [$c destroy-after-run] obj1 obj2 obj3 ? [list info commands $obj1] "" ? [list info commands $obj2] "" ? [list info commands $obj3] "" } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/disposition.test000644 000766 000024 00000123467 13712264152 017617 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package req nx package require nx::test # # test cases for disposition "alias" and "forward" # nx::test case basics { Class create C { :object property {inst "::__%&singleton"} :method foo {x} { #puts stderr [current method] set :[current method] $x } :method bar {} {;} :protected method baz {y} { #puts stderr [current method] set :my[current method] $y } # # some testing helpers # :public object method setObjectParams {spec} { :protected method __object_configureparameter {} [list return $spec] ::nsf::parameter::cache::classinvalidate [current] } :setObjectParams "" :public object method new args { return [:create ${:inst} {*}$args] } } foreach paramType {forward alias} { # # Restricted to object parameters only? # set msg "parameter option '$paramType' not allowed" ? [list C method m1 -foo:$paramType {;}] $msg ? [list C method m1 foo:$paramType {;}] $msg # # Not applicable in parametercheck # ? [list ::nsf::is $paramType $msg] "invalid value constraints \"$paramType\": parameter option '$paramType' not allowed" } # # Do aliases and forwarder set instance variables? They should not. # C setObjectParams -baz:alias ? {[C new -baz BAZ] eval {info exists :baz}} 0 C setObjectParams {{{-baz:forward,method=%self %method}}} ? {[C new -baz BAZ] eval {info exists :baz}} 0 # # Note, currently alias/forward disposition operate on public and # protected target methods alike. Is this intended? For example, # providing access through the parameter interface to protected # methods etc. (at the instantiation site only) ? Or, are they # expected to be public ... # ### objectparameter are from the intentions public: the typical ### use-case is that someone wants to configure an object to be ### created, before the object exists.... # # 1) Positional object parameters + alias/forward disposition? # # # Passing a single argument to a positional alias # C setObjectParams foo:alias ? {C new FOO} "::__%&singleton" ? {C new {FOO FAA}} "::__%&singleton" ### ### Whenever a value is provided (default value or actual value) the ### parameter is evaluated. ### C setObjectParams {{foo:alias ""}} ? {C new} "::__%&singleton" C setObjectParams {{-foo:alias "fooDefault"}} ? {[C new] eval {set :foo}} "fooDefault" # # What about multi-argument vectors? # C eval { :method multi-2 {x y} { set :[current method] [current args] } :method multi-escape {x} { set :[current method] $x } :method multi-args {args} { set :[current method] $args } } # # Parameters are limited to a single value by the object parameter. # C setObjectParams {{-multi-2:alias}} ? {[C new -multi-2 {X Y}] eval {set :multi-2}} \ "wrong # args: should be \"multi-2 x y\"" # # Passing multiple arguments as a list # C setObjectParams {{-multi-escape:alias}} ? {[C new -multi-escape [list X Y]] eval {set :multi-escape}} \ [list X Y] # # Passing multiple arguments as a list, passed to a args argument # list. # C setObjectParams {{-multi-args:alias}} ? {[C new -multi-args [list X Y]] eval {set :multi-args}} \ [list [list X Y]] # # As used, all parameters receive currently 0 or 1 # argument. The same is true for disposition "alias" an # "forward". One could consider to unbox a parameter list via a # parameter option "expand" (like {*}) for alias|forward parameter # specs, e.g.: # {-multi-2:alias,expand} # {-multi-2:forward,method=...,expand} # # Without the sketched extension, one could use eval in a forwarder. # C setObjectParams {{{-multi-2:forward,method=eval %self %method}}} ? {[C new -multi-2 {X Y}] eval {set :multi-2}} \ "X Y" # # In the positional case, why is FOO not passed on as arg value to # the target method? # C setObjectParams {{{foo:forward,method=%self %method}}} ? {C new FOO} "::__%&singleton" ? {[C new FOO] eval {set :foo}} "FOO" # # Naming of the parameter spec element "method": It fits the alias # disposition, but is a little irritating in the context of a # forward. One would expect forwardspec or simply "spec" (as this is # used in the docs, the error messages etc.), e.g.: # # {foo:forward,spec=%self %method} # # 'spec' would also work for 'alias' as it is more general (the spec # of an alias is the method name ...) # #### well, "spec" is not nice for alias, and potentially confusing #### with the parameter spec (the full parameter definition). # # Passing non-positional arguments to target methods (at least # forwarder ones)? # C method multi-mix {-x y args} { set :[current method] --x-$x--y-$y--args-$args } C setObjectParams {{{-multi-mix:forward,method=eval %self %method}}} ? {[C new -multi-mix [list -x X Y Z 1 2]] eval {set :multi-mix}} \ "--x-X--y-Y--args-Z 1 2" # # Aliased methods with nonpos arguments are rendered entirely # useless by the single-value limitation (see also above): # C method single-np {-x:required} { set :[current method] --x-$x } C setObjectParams {{-single-np:alias}} ? {[C new -single-np [list -x]] eval {set :single-np}} \ "value for parameter '-x' expected" ? {[C new -single-np [list -x X]] eval {set :single-np}} \ "invalid non-positional argument '-x X', valid are: -x; should be \"::__%&singleton single-np -x /value/\"" # # INTERACTIONS with other parameter types # # There are two validation points: # 1) the object parameter validation on the initial argument set # 2) the target method validation on the (mangled) argument set # # ... they can deviate from each other, to a point of direct # conflict # # # Allowed built-in value types (according to feature matrix in # parameters.test) # set msg {expected $mtype but got \"$testvalue\" for parameter \"x\"} dict set types boolean [list testvalue f mtype object msg $msg] dict set types integer [list testvalue 81 mtype punct msg $msg] dict set types object [list testvalue ::C mtype integer msg $msg ] dict set types class [list testvalue ::C mtype boolean msg $msg] dict set types object,type=::nx::Class \ [list testvalue ::C mtype object,type=::C \ msg "expected object of type ::C but got \"::C\"\ for parameter \"x\""] # for aliases ... dict for {t tdict} $types { dict with tdict { ::C public method foo [list x:$t] { set :[current method] $x } ::C setObjectParams [list [list -foo:alias,$t]] ? "::nsf::is $t \[\[::C new -foo $testvalue\] eval {set :foo}\]" 1 "check: -foo:alias,$t" } } ::C public method baz {x} { return $x } dict for {t tdict} $types { dict with tdict { ::C public method foo [list x:$mtype] { set :[current method] $x } ::C setObjectParams [list [list -foo:alias,$t]] ? "::nsf::is $t \[\[::C new -foo $testvalue\] eval {set :foo}\]" \ [subst $msg] } } # # TODO: update the matrix in parameters.test (feature matrix) # ### ### The question is, what happens with the matrix. The matrix is in ### some respects not complete (no disposition) and contains old ### namings (e.g. allowempty, multiple) and contains types removed ### some time ago (such as e.g. "relation"). ### # # define a user defined parameter type # ::nx::methodParameterSlot object method type=mytype {name value} { if {$value < 1 || $value > 3} { error "Value '$value' of parameter $name is not between 1 and 3" } } array set script {alias "method=baz" forward "method=%self %method"} foreach disposition [list alias forward] { C setObjectParams [list [list -foo:$disposition,switch]] ? {C new} "parameter invocation types cannot be used with option 'switch'" \ "switch not allowed for $disposition" C setObjectParams [list [list -baz:$disposition,mytype,$script($disposition)]] ? {C new -baz 1} "::__%&singleton" \ "disposition $disposition, user defined type, valid value" C setObjectParams [list [list -baz:$disposition,mytype,$script($disposition)]] ? {C new -baz 0} "Value '0' of parameter baz is not between 1 and 3" \ "disposition $disposition, user defined type, invalid value" C setObjectParams [list [list -foo:$disposition,xxx]] ? {C new} "::__%&singleton" \ "disposition $disposition, unknown user defined type - just a warning" C setObjectParams [list [list -foo:$disposition,type=::C]] ? {C new} "parameter option 'type=' only allowed for parameter types 'object' and 'class'" # # The 'arg=...' option should not be used, consider using 'method=...' # C setObjectParams [list [list -foo:$disposition,arg=BOOM]] ? {C new} "parameter option 'arg=' only allowed for user-defined converter" } # # The option 'method=...' applies to disposition types only # C setObjectParams [list [list -foo:initcmd,method=BOOM]] ? {C new} "parameter option 'method=' only allowed for parameter types 'alias', 'forward' and 'slotset'" C setObjectParams [list [list -foo:alias,forward]] ? {C new} "parameter option 'forward' not valid in this option combination" C setObjectParams [list [list -foo:forward,alias]] ? {C new} "parameter option 'alias' not valid in this option combination" C setObjectParams [list [list -foo:alias,initcmd]] ? {C new} "parameter option 'initcmd' not valid in this option combination" C setObjectParams [list [list -foo:forward,initcmd]] ? {C new} "parameter option 'initcmd' not valid in this option combination" } nx::test case dispo-multiplicities { Class create S { :public object method setObjectParams {spec} { :protected method __object_configureparameter {} [list return $spec] ::nsf::parameter::cache::classinvalidate [current] } #:object method __object_configureparameter {} { # return ${:objectparams} #} :public method foo {args} { set :foo $args return $args } } # # On multiplicity classes ... # # ... implying a Tcl list value: 1..*, 0..* # ... implying a Tcl word value: 1..1, 0..1 # S setObjectParams {-foo:alias,1..*,boolean} S method foo {x:0..1,boolean} { set :foo $x } ? {[S new -foo [list f f]] eval {info exists :foo}} \ "expected boolean but got \"f f\" for parameter \"x\"" S setObjectParams {-foo:alias,1..*,integer} S method foo {x:1..1,integer} { set :foo $x } ? {[S new -foo [list a 1]] eval {info exists :foo}} \ "invalid value in \"a 1\": expected integer but got \"a\" for parameter \"-foo\"" ? {[S new -foo [list 0 1]] eval {info exists :foo}} \ "expected integer but got \"0 1\" for parameter \"x\"" ? {[S new -foo [list]] eval {info exists :foo}} \ "invalid value for parameter '-foo': list is not allowed to be empty" ? {[S new -foo 5] eval {info exists :foo}} 1 ? {[S new -foo f] eval {info exists :foo}} \ "invalid value in \"f\": expected integer but got \"f\" for parameter \"-foo\"" S setObjectParams {-foo:alias,0..*,false} S method foo {x:0..1,false} { set :foo $x } ? {[S new -foo [list a 1]] eval {info exists :foo}} \ "invalid value in \"a 1\": expected false but got \"a\" for parameter \"-foo\"" ? {[S new -foo [list f 0]] eval {info exists :foo}} \ "expected false but got \"f 0\" for parameter \"x\"" ? {[S new -foo [list t]] eval {info exists :foo}} \ "invalid value in \"t\": expected false but got \"t\" for parameter \"-foo\"" ? {[S new -foo [list f]] eval {info exists :foo}} 1 ? {[S new -foo [list]] eval {info exists :foo}} 1 } nx::test case dispo-returns { Class create R { :public object method setObjectParams {spec} { :protected method __object_configureparameter {} [list return $spec] ::nsf::parameter::cache::classinvalidate [current] } } # # Alias/forward dispositions are unavailable as parameter types of return checkers # set methods(raz) [R public object method raz {} {;}] foreach dispoSpec { alias,noarg alias,method=xxx {forward,method=%self xxx} initcmd } { ::nsf::method::property R $methods(raz) returns $dispoSpec set trueSpec [lindex $dispoSpec 0] ? {R raz} "invalid value constraints \"$dispoSpec\": parameter option '$trueSpec' not allowed" } # # Interactions between disposition types and the return value checkers # ::nsf::configure checkresults true # -- R setObjectParams -foo:alias,true set methods(foo) [R public method foo {x:true} -returns false { set :foo $x }] ? {[R new] foo t} "expected false but got \"t\" as return value" R setObjectParams [list -foo:alias,true bar:alias,false] ::nsf::method::property R $methods(foo) returns boolean set methods(bar) [R public method bar {y:false} -returns true { set :bar $y }] ? {[R new -foo t f] eval {info exists :bar}} "expected true but got \"f\" as return value" R setObjectParams [list -foo:alias,true bar:alias,false \ [list baz:alias,wideinteger,substdefault {[expr {2 ** 63 - 1}]}]] ::nsf::method::property R $methods(bar) returns boolean set methods(baz) [R public method baz {z:wideinteger} -returns int32 { set :baz $z }] ? {[R new -foo t f [expr {2 ** 31}]] eval {info exists :foo}} 1 ? {[R new -foo t f] eval {info exists :baz}} "expected int32 but got \"[expr {2 ** 63 - 1}]\" as return value" ? {[R new -foo t f] eval {info exists :baz}} "expected int32 but got \"[expr {2 ** 63 - 1}]\" as return value" ::nsf::method::property R $methods(baz) returns wideinteger ? {string is wideinteger [[R new -foo t f] eval {set :baz}]} 1 } nx::test case dispo-callstack { Class create Callee { :public object method setObjectParams {spec} { :protected method __object_configureparameter {} [list return $spec] ::nsf::parameter::cache::classinvalidate [current] } } # # uplevel, upvar (with alias and forward) # Callee public method call {{-level 2} x} { # # The callstack positioning corresponds to the one of # alias/forward target methods in general: # Level -1 -> C-level frame # Level -2 -> Actual caller frame # # Note: Like any aliased methods, target methods of alias # parameters do not have full callstack transparency (e.g., in a # direct call to the target method, level -1 would resolve to the # caller frame) # # ::nsf::__db_show_stack uplevel $level [list set ix $x] upvar $level $x _ incr _ } foreach dispoSpec { {-ah:alias,method=call {call:alias X}} {{{-ah:forward,method=%self call}} {{call:forward,method=%self %method} X}} {{{-ah:forward,method=uplevel %self call -level 1}} {{call:forward,method=uplevel %self %method -level 1} X}} } { Callee setObjectParams $dispoSpec namespace eval __ { ? {info exists X} 0 ? {info exists ix} 0 ? {Callee new; info exists ix} 1 ? {set X} 1 ? {Callee new; info exists X} 1 ? {Callee new; set X} 3 ? {Callee new; set ix} X ? {Callee new -ah X X; set ix} X ? {set X} 6 ? {info exists Y} 0 ? {Callee new -ah X Y; set Y} 1 ? {set X} 7 ? {set ix} Y } namespace delete __ } # # TODO: Test missing elements for method declarations: # /cls/ public class {} {} ... # # / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / # Test the ACTIVE/INACTIVE transparency for the method-variants of # uplevel|upvar # Callee public object method run {} { set self [self] set objparams [:__object_configureparameter] # # The ? helper by default performs a [namespace eval] in the :: # namespace, so the uplevel|upvar would happen in a different, # non-testable callstack branch. Therefore, we have to build the # tests around this limitation (for now) # ? [list set _ [info exists X]] 0 ? [list set _ [info exists ix]] 0 $self new ? [list set _ [info exists ix]] 1 "after 1. uplevel/upvar calls ('$objparams')" ? [list set _ [set X]] 1 "after 1. uplevel/upvar calls ('$objparams')" $self new ? [list set _ [info exists X]] 1 "after 2. uplevel/upvar calls ('$objparams')" $self new ? [list set _ [set X]] 3 "after 3. uplevel/upvar calls ('$objparams')" $self new ? [list set _ [set ix]] X "after 4. uplevel/upvar calls ('$objparams')" $self new -ah X X; ? [list set _ [set ix]] X "after 5. uplevel/upvar calls ('$objparams')" ? [list set _ [set X]] 6 "after 5. uplevel/upvar calls ('$objparams')" ? [list set _ [info exists Y]] 0 $self new -ah X Y; ? [list set _ [set Y]] 1 "after 6. uplevel/upvar calls ('$objparams')" ? [list set _ [set X]] 7 "after 6. uplevel/upvar calls ('$objparams')" ? [list set _ [set ix]] Y } # {{{-ah:forward,method=uplevel %self call -level 1}} {{call:forward,method=uplevel %self %method -level 1} X}} # # a) NSF/Nx methods upvar() and uplevel() # Callee public method call {x} { :uplevel [list set ix $x] :upvar $x _ incr _ } foreach dispoSpec { {-ah:alias,method=call {call:alias X}} {{{-ah:forward,method=%self call}} {{call:forward,method=%self %method} X}} } { Callee setObjectParams $dispoSpec Callee run } # # b) [current callinglevel] # # ... with [uplevel [current callinglevel]] being equivalent to # using NSF/Nx methods upvar() and uplevel() directly. # Callee public method call {x} { # ::nsf::__db_show_stack uplevel [current callinglevel] [list set ix $x] upvar [current callinglevel] $x _ incr _ } foreach dispoSpec { {-ah:alias,method=call {call:alias X}} {{{-ah:forward,method=%self call}} {{call:forward,method=%self %method} X}} } { Callee setObjectParams $dispoSpec Callee run } # # c) [current activelevel] # # ... Currently, in the current testing scenario, there is no # effective difference between #activelevel and #callinglevel, both # skip INACTIVE frames. Callee mixins set [Class new {:public method call args { next }}] foreach dispoSpec { {-ah:alias,method=call {call:alias X}} {{{-ah:forward,method=%self call}} {{call:forward,method=%self %method} X}} } { Callee setObjectParams $dispoSpec Callee run } Callee public method call {x} { uplevel [current activelevel] [list set ix $x] upvar [current activelevel] $x _ incr _ } foreach dispoSpec { {-ah:alias,method=call {call:alias X}} {{{-ah:forward,method=%self call}} {{call:forward,method=%self %method} X}} } { Callee setObjectParams $dispoSpec Callee run } } nx::test case alias-noarg { Class create C { :public object method setObjectParams {spec} { :protected method __object_configureparameter {} [list return $spec] ::nsf::parameter::cache::classinvalidate [current] } :public method foo {args} { set :foo $args return $args } :public method bar {args} { set :bar $args return $args } } # # nopos arg with noargs, given # C setObjectParams {-bar:alias,noarg} C create c1 -bar ? {c1 eval {info exists :bar}} 1 ? {c1 eval {info exists :x}} 0 # # nopos arg with noargs, not given # C setObjectParams {-bar:alias,noarg} C create c1 ? {c1 eval {info exists :bar}} 0 # # pos arg with noargs # C setObjectParams {foo:alias,noarg} C create c1 ? {c1 eval {info exists :foo}} 1 # # initcmd with default # C setObjectParams {{__init:cmd :foo}} C create c1 ? {c1 eval {info exists :foo}} 1 # # pos arg with noargs and nonposarg with noargs, given # C setObjectParams {foo:alias,noarg -bar:alias,noarg} C create c1 -bar ? {c1 eval {info exists :bar}} 1 ? {c1 eval {info exists :foo}} 1 ? {c1 eval {info exists :x}} 0 # # optional initcmd, like in nx # C setObjectParams {initcmd:cmd,optional} C create c1 {set :x 1} ? {c1 eval {info exists :x}} 1 # # using a default value for initcmd # C setObjectParams {{initcmd:cmd ""}} C create c1 {set :x 1} C create c2 ? {c1 eval {info exists :x}} 1 ? {c2 eval {info exists :x}} 0 # # optional initcmd + non-consuming (nrargs==0) posarg, provided # initcmd # C setObjectParams {foo:alias,noarg initcmd:cmd,optional} C create c1 {set :x 1} ? {c1 eval {info exists :x}} 1 ? {c1 eval {info exists :foo}} 1 ? {c1 eval {info exists :bar}} 0 # # optional initcmd + non-consuming (nrargs==0) posarg, no value for # initcmd # C setObjectParams {foo:alias,noarg initcmd:cmd,optional} C create c1 ? {c1 eval {info exists :x}} 0 ? {c1 eval {info exists :foo}} 1 ? {c1 eval {info exists :bar}} 0 # # initcmd with default + non-consuming (nrargs==0) posarg, no value # for initcmd # C setObjectParams {foo:alias,noarg {initcmd:cmd ""}} C create c1 ? {c1 eval {info exists :x}} 0 ? {c1 eval {info exists :foo}} 1 ? {c1 eval {info exists :bar}} 0 # # non-consuming alias, nonpos alias with noarg, initcmd provided # C setObjectParams {foo:alias,noarg -bar:alias,noarg initcmd:cmd,optional} C create c1 {set :x 1} ? {c1 eval {info exists :foo}} 1 ? {c1 eval {info exists :bar}} 0 ? {c1 eval {info exists :x}} 1 # # non-consuming alias, nonpos alias with noarg, nonpos called, initcmd provided # C setObjectParams {foo:alias,noarg -bar:alias,noarg initcmd:cmd,optional} C create c1 -bar {set :x 1} ? {c1 eval {info exists :foo}} 1 ? {c1 eval {info exists :bar}} 1 ? {c1 eval {info exists :x}} 1 # # non-consuming alias, nonpos alias with noarg, no initcmd provided # C setObjectParams {foo:alias,noarg -bar:alias,noarg initcmd:cmd,optional} C create c1 ? {c1 eval {info exists :foo}} 1 ? {c1 eval {info exists :bar}} 0 ? {c1 eval {info exists :x}} 0 # # non-consuming alias, nonpos alias with noarg, nonpos called, no # initcmd provided # C setObjectParams {foo:alias,noarg -bar:alias,noarg initcmd:cmd,optional} C create c1 -bar ? {c1 eval {info exists :foo}} 1 ? {c1 eval {info exists :bar}} 1 ? {c1 eval {info exists :x}} 0 } # # check inticmd + noarg (should not be allowed) # nx::test case alias-noarg { Class create C { :public object method setObjectParams {spec} { :protected method __object_configureparameter {} [list return $spec] ::nsf::parameter::cache::classinvalidate [current] } } C setObjectParams {initcmd:cmd,noarg} ? {C create c1} {parameter option "noarg" only allowed for parameter type "alias"} } # # check alias + args # nx::test case alias-args { Class create C { :public object method setObjectParams {spec} { :protected method __object_configureparameter {} [list return $spec] ::nsf::parameter::cache::classinvalidate [current] } :public method Residualargs args { #puts stderr "aliased RESIDUALARGS <[llength $args]>" #puts stderr "....... <$args>" set :args $args } :public method residualargs args { #puts stderr "residualargs <$args>" } } C copy D # TODO: check the meaning of these C setObjectParams {args} D setObjectParams {-a args} # Configure object parameters to call method Residualargs with # option args when args is used C setObjectParams {args:alias,method=Residualargs,args} D setObjectParams {-a args:alias,method=Residualargs,args} # If no residual args are provided, the method residualargs is not # called. This is the same rule as for all other consuming object # parameter dispatches ? {C create c1} {::c1} ? {c1 eval {info exists :args}} 0 ? {D create c1} {::c1} ? {c1 eval {info exists :args}} 0 # Residual args are provided, the method residualargs is # called. ? {C create c1 1 2 3} {::c1} ? {c1 eval {info exists :args}} 1 ? {c1 eval {set :args}} {1 2 3} ? {D create c1 1 2 3} {::c1} ? {c1 eval {info exists :args}} 1 ? {c1 eval {set :args}} {1 2 3} # # Provide a default for args. # C setObjectParams {{args:alias,method=Residualargs,args {hello world}}} # use the default ? {C create c1} {::c1} ? {c1 eval {info exists :args}} 1 ? {c1 eval {set :args}} {hello world} # override the default ? {C create c1 a b c} {::c1} ? {c1 eval {info exists :args}} 1 ? {c1 eval {set :args}} {a b c} # # don't allow other types for parameter option "args" # C setObjectParams {{args:alias,int,method=Residualargs,args {hello world}}} ? {C create c1} {refuse to redefine parameter type of 'args' from type 'integer' to type 'args'} ? {nsf::is object c1} 0 C setObjectParams {{args:int,alias,method=Residualargs,args {hello world}}} ? {C create c1} {refuse to redefine parameter type of 'args' from type 'integer' to type 'args'} ? {nsf::is object c1} 0 # # don't allow multiplicity settings for parameter option "args" # C setObjectParams {{args:alias,method=Residualargs,0..n,args {hello world}}} ? {C create c1} {multiplicity settings for variable argument parameter "args" not allowed} ? {nsf::is object c1} 0 C setObjectParams {args:alias,method=Residualargs,args,1..n} ? {C create c1} {multiplicity settings for variable argument parameter "args" not allowed} ? {nsf::is object c1} 0 # # make sure, parameter with parameter option "args" is used in last parameter # C setObjectParams {a:alias,method=Residualargs,args -b:integer} ? {C create c1 hello world} {parameter option "args" invalid for parameter "a"; only allowed for last parameter} ? {nsf::is object c1} 0 } nx::test case alias-init { Class create C { :public object method setObjectParams {spec} { :protected method __object_configureparameter {} [list return $spec] ::nsf::parameter::cache::classinvalidate [current] } :method init {} { incr :y } } # call init between -a and -b C setObjectParams {-a init:alias,noarg -b:integer} ? {C create c1} {::c1} # "init" should be called only once ? {c1 eval {set :y}} 1 } nx::test case submethods-via-aliasparams { # # Could move to submethods.test? # Class create C { :public object method setObjectParams {spec} { :protected method __object_configureparameter {} [list return $spec] ::nsf::parameter::cache::classinvalidate [current] } } # A depth-1 submethod ... C public method "FOO foo" {} { # next append :msg "[::nsf::current]--[::nsf::current methodpath]--[::nsf::current method]" } # A depth-2 submethod ... C public method "BAR BOO buu" {} { append :msg "[::nsf::current]--[::nsf::current methodpath]--[::nsf::current method]" } # // Ordinary dispatch // # The message send below expands into the following callstack # structure (when viewed at from within foo(), N is the anonymous # call site) # # N+3 |:CscFrame @Type(ENSEMBLE) | <-- foo (leaf) # N+2 |:CscFrame @Call(ENSEMBLE) | <-- FOO (root) # N+1 |:TclFrame| e.g. cmd, [namespace eval], [apply] ? { [C create c1] FOO foo; # N c1 eval {set :msg} } "::c1--FOO foo--foo" # # Submethod levels greater than 1 turn into intermittent frames: # N+4 |:CscFrame @Type(ENSEMBLE) | <-- buu (leaf) # N+3 |:CscFrame @Type(ENSEMBLE) @Call(ENSEMBLE)| <-- BOO (intermittent) # N+2 |:CscFrame @Call(ENSEMBLE) | <-- BAR (root) # N+1 |:TclFrame| # ? { [C create c3] BAR BOO buu; # N c3 eval {set :msg} } "::c3--BAR BOO buu--buu" # // Parameter (alias) dispatch // # # In contrast to an ordinary dispatch, a parameter dispatch results # in a different callstack structure, due to the interfering # configure(): # # N+5 |:CscFrame @Type(ENSEMBLE)| <-- foo (leaf) # N+4 |:CscFrame @Call(ENSEMBLE)| <-- FOO (root) # N+3 |:CscFrame @INACTIVE| <-- (INNER configure() frame) # N+2 |:ObjFrame| <-- ::c2 (OUTER configure() frame) # N+1 |:TclFrame| C setObjectParams [list FOO:alias] ? { [C create c2 foo] eval {set :msg}; # N } "::c2--FOO foo--foo" # # 1) Interleaving @Type(INACTIVE) frames through indirection # # a) Ahead of the ensemble "root" frame (i.e., indirection at the # level the receiver object) # Class create M1 { :public method FOO args { next } } C mixins set M1 # N+4 |:CscFrame @Type(ENSEMBLE) | <-- foo (leaf) # N+3 |:CscFrame @Call(ENSEMBLE) | <-- FOO (root) # N+2 |:CscFrame @INACTIVE| <-- M1.FOO # N+1 |:TclFrame| C setObjectParams [list] ? { [C create c1] FOO foo; # N c1 eval {set :msg} } "::c1--FOO foo--foo" # N+6 |:CscFrame @Type(ENSEMBLE)| <-- foo (leaf) # N+5 |:CscFrame @Call(ENSEMBLE)| <-- FOO (root) # N+4 |:CscFrame @INACTIVE| <-- M1.FOO # N+3 |:CscFrame @INACTIVE| <-- (INNER configure() frame) # N+2 |:ObjFrame| <-- ::c2 (OUTER configure() frame) # N+1 |:TclFrame| C setObjectParams [list FOO:alias] ? { [C create c2 foo] eval {set :msg}; # N } "::c2--FOO foo--foo" # ... the filter variant ... C mixins set {} C public method intercept args { next } C filters set intercept # N+4 |:CscFrame @Type(ENSEMBLE) | <-- foo (leaf) # N+3 |:CscFrame @Call(ENSEMBLE) | <-- FOO (root) # N+2 |:CscFrame @INACTIVE| <-- intercept # N+1 |:TclFrame| C setObjectParams [list] ? { [C create c1] FOO foo; # N c1 eval {set :msg} } "::c1--FOO foo--foo" # N+6 |:CscFrame @Type(ENSEMBLE)| <-- foo (leaf) # N+5 |:CscFrame @Call(ENSEMBLE)| <-- FOO (root) # N+4 |:CscFrame @INACTIVE| <-- intercept # N+3 |:CscFrame @INACTIVE| <-- (INNER configure() frame) # N+2 |:ObjFrame| <-- ::c2 (OUTER configure() frame) # N+1 |:TclFrame| C setObjectParams [list FOO:alias] ? { [C create c2 foo] eval {set :msg}; # N } "::c2--FOO foo--foo" C filters set "" # / / / / / / / / / / / / / / / / / / / / / / / / / / / / / # b) Between root and intermittent or in-between the set of # intermittent frames (i.e., indirection at the level of # container/ensemble objects) # NOTE: Filters and mixins registered for the container object do # not interleave in ensemble dispatches ... the dispatch lookup # (along the next path) always starts at the top-level # (calling) object. As a result, there are no intermediate frames to # be expected ... Class create M2 { :public method foo args { return "[current class]--[next]" } } C::slot::__FOO object mixins set M2 ? {C::slot::__FOO foo} "::M2--::C::slot::__FOO--foo--foo" C::slot::__FOO eval {unset :msg} C setObjectParams [list] ? { [C create c1] FOO foo; # N c1 eval {set :msg} } "::c1--FOO foo--foo" C::slot::__FOO object mixins set {} C::slot::__FOO public object method intercept {} { return "[current]--[next]" } C::slot::__FOO object filters set intercept ? {C::slot::__FOO foo} "::C::slot::__FOO--::C::slot::__FOO--foo--foo" C setObjectParams [list] ? { [C create c1] FOO foo; # N c1 eval {set :msg} } "::c1--FOO foo--foo" # -- Class create M2 { :public method "FOO foo" args { append :msg "(1)--[current nextmethod]" next #puts stderr ++++++++++++++++++ append :msg "--(3)--[current class]--[current methodpath]--[current]" #puts stderr ++++++++++++++++++ } } C mixins set M2 # N+4 |:CscFrame @Type(ENSEMBLE) | <-- C.FOO.foo (leaf) # N+2 |:CscFrame @Call(ENSEMBLE) | <-- C.FOO (root) # N+3 |:CscFrame @INACTIVE @Type(ENSEMBLE)| <-- M2.FOO.foo # N+2 |:CscFrame @INACTIVE @Call(ENSEMBLE) | <-- M2.FOO # N+1 |:TclFrame| C setObjectParams [list] ? { #puts stderr "/ / / / / / / / / / / " [C create c1] FOO foo; # N #puts stderr "/ / / / / / / / / / / " c1 eval {set :msg} } "(1)--::c1--FOO foo--foo--(3)--::M2--FOO foo--::c1" C mixins set {} } nx::test case dispo-configure-transparency { Class create C { :public object method setObjectParams {spec} { :protected method __object_configureparameter {} [list return $spec] ::nsf::parameter::cache::classinvalidate [current] } } ::proc foo {} { error [::nsf::current]-[::nsf::current methodpath]-[::nsf::current method] } # ::nsf::method::alias C FOO ::foo ? {[C create c] FOO} "::c-FOO-FOO" C setObjectParams [list [list FOO:alias,noarg ""]] ? {C create c} "::c-FOO-FOO" C public method "show me" {} { set :msg [::nsf::current]-[::nsf::current methodpath] } C setObjectParams [list -show:alias] ? {[C create c -show me] eval {info exists :msg}} 1 ? {[C create c -show me] eval {set :msg}} "::c-show me" # # ... with mixin indirection # # ... at the calling object level / configure() ... Class create M { :public method configure args { next; } :public method foo args { next; } :public method FOO args { error [::nsf::current]-[::nsf::current methodpath] } } C setObjectParams [list [list FOO:alias,noarg ""]] C mixins add M ? {C create c} "::c-FOO" C mixins set {} # ... at the called object level Object create ::callee { ::nsf::object::property [self] perobjectdispatch true :public object method foo {} { error [::nsf::current]-[::nsf::current methodpath] } } ::nsf::method::alias C FOO ::callee C setObjectParams [list [list FOO:alias,noarg ""]] ? {C create c} "::c" "Defaultmethod of callee is invoked ..." C setObjectParams [list [list FOO:alias "foo"]] ? {C create c} "::callee-FOO foo" "foo leaf method is selected ..." ::callee object mixins add M ? {C create c} "::callee-FOO foo" "With mixin ..." # # ... at the calling object level / ensemble path # # This scenario effectively stacks additional call frames to be # traversed by CallStackMethodPath(). However, these frames precede # the first ensemble frame, that's why they are skipped by # CallStackMethodPath(). M eval { :public method FOO args { puts stderr "!!!!! FOO MIXIN ...." next; } } ? {C create c} "::callee-FOO foo" "With mixin ..." # # ... with filter indirection: tbd # } nx::test case dispo-object-targets { Object create obj ::nsf::object::property obj perobjectdispatch true Class create C Class create T { :public object method setObjectParams {spec} { :protected method __object_configureparameter {} [list return $spec] ::nsf::parameter::cache::classinvalidate [current] } } # # 1. Behavioural baseline: An alias method binding an object # set methods(z) [::nsf::method::alias T z ::obj] ? {[T new] z} ::obj "Aliased dispatch to defaultmethod" ? {[T new] z uff} "::obj: unable to dispatch method 'uff'" \ "Aliased dispatch to unknown method (default unknown handler)" Class create UnknownHandler { :method unknown {callInfo args} { # # callInfo is a Tcl list. For ensemble dispatches, it contains # the complete message: delegator ; for # ordinary dispatches, the list has a single element: # # methodpath [current methodpath] # puts stderr "CALLINFO='$callInfo' args=$args" switch [llength $callInfo] { 1 { error "UNKNOWNMETHOD-$callInfo" } default { set delegator [lindex $callInfo 0] set unknownMethod [lindex $callInfo end] set path [lrange $callInfo 1 end-1] error "CURRENT-[current]-DELEGATOR-$delegator-UNKNOWNMETHOD-$unknownMethod-PATH-$path" } } } } ::obj object mixins set UnknownHandler ? {[T create t] z uff} "CURRENT-::obj-DELEGATOR-::t-UNKNOWNMETHOD-uff-PATH-z" \ "Aliased dispatch to unknown method (custom unknown handler)" set x [UnknownHandler create handledObj] ::nsf::object::property handledObj perobjectdispatch true set methods(ix) [::nsf::method::alias ::obj ix $x] ? {[T create t] z ix baff} "CURRENT-$x-DELEGATOR-::obj-UNKNOWNMETHOD-baff-PATH-z ix" \ "Aliased dispatch to unknown method (custom unknown handler)" # # 2. Obj targets via alias disposition parameters # # # a) direct dispatch (non-aliased) with fully qualified selector (::*) # ::obj object mixins set {} T setObjectParams x:alias,method=::obj ? {T create t XXX} "::t: unable to dispatch method '::obj'" "FQ dispatch with default unknown handler" ::T mixins set UnknownHandler ? {T create t XXX} "UNKNOWNMETHOD-::obj" "FQ dispatch with custom unknown handler" # # b) calls to the defaultmethod of the aliased object # UnknownHandler method defaultmethod {} { set :defaultmethod 1 } ::obj object mixins set UnknownHandler T setObjectParams [list [list z:alias,noarg ""]] ? {T create t; ::obj eval {info exists :defaultmethod}} 1 \ "Calling defaultmethod via alias+noarg combo with empty default" T setObjectParams [list [list z:alias,noarg "XXX"]] ? {T create t; ::obj eval {info exists :defaultmethod}} 1 \ "Calling defaultmethod via alias+noarg nonempty with \ default combo (default is not passed)" # # b) intermediary object aliases, non-fully qualified selector # T setObjectParams [list [list z:alias,noarg ""]] ? {T create tt} ::tt "sending the msg: tt->z()" # # ISSUE: positional objparam + alias + noarg -> what's the point? # noarg & ?z? are irritating, ?z? should not be printed! # ? {T create t XXX} "invalid argument 'XXX', maybe too many arguments; should be \"::t configure ?/z/?\"" ::obj object mixins set {} T setObjectParams [list z:alias] ? {T create tt YYY} "::obj: unable to dispatch method 'YYY'" "sending the msg: tt->z(::obj)->YYY()" ::obj object mixins set UnknownHandler ? {T create tt YYY} "CURRENT-::obj-DELEGATOR-::tt-UNKNOWNMETHOD-YYY-PATH-z" \ "sending the msg: tt->z(::obj)->YYY()" ::obj object mixins set {} T setObjectParams [list -z:alias] ? {T create tt -z YYY} "::obj: unable to dispatch method 'YYY'" "sending the msg: tt->z(::obj)->YYY()" ::obj object mixins set UnknownHandler ? {T create tt -z YYY} "CURRENT-::obj-DELEGATOR-::tt-UNKNOWNMETHOD-YYY-PATH-z" \ "sending the msg: tt->z(::obj)->YYY()" # # [current methodpath] & empty selector strings: # ::obj object mixins set {} T setObjectParams [list z:alias] ? {T create tt ""} "::obj: unable to dispatch method ''" "sending the msg: tt->z->{}()" ::obj object mixins set UnknownHandler ? {T create tt ""} "CURRENT-::obj-DELEGATOR-::tt-UNKNOWNMETHOD--PATH-z" "sending the msg: tt->z->{}()" T setObjectParams [list -z:alias] ? {T create tt -z ""} "CURRENT-::obj-DELEGATOR-::tt-UNKNOWNMETHOD--PATH-z" "sending the msg: tt->z()" # # Dispatch with a method handle # ::T mixins set {} ? [list [T create t] $methods(z) XXX] \ "CURRENT-::obj-DELEGATOR-::t-UNKNOWNMETHOD-XXX-PATH-::nsf::classes::T::z" T setObjectParams x:alias,method=$methods(z) ? {T create t XXX} "CURRENT-::obj-DELEGATOR-::t-UNKNOWNMETHOD-XXX-PATH-::nsf::classes::T::z" \ "Non-object FQ selector with default unknown handler" ::T mixins set UnknownHandler ? {T create t XXX} "CURRENT-::obj-DELEGATOR-::t-UNKNOWNMETHOD-XXX-PATH-::nsf::classes::T::z" \ "Non-object FQ selector with custom unknown handler" # # A Tcl proc is allowed?! # proc ::baz {x} { set :baz $x } T setObjectParams x:alias,method=::baz ? {[T create t XXX] eval {info exists :baz}} 1 ? {[T create t XXX] eval {set :baz}} XXX # # TBD: nested objects # # # TBD: object-system methods # } # # check xotcl with residual args # nx::test case xotcl-residualargs { package prefer latest puts stderr "XOTcl loaded: [package req XOTcl 2.0]" ? {::xotcl::Class create XD -set x 1} "::XD" #? {c1 eval {info exists :args}} 0 ? {XD __object_configureparameter} "-instfilter:filterreg,alias,0..n -superclass:alias,0..n -instmixin:mixinreg,alias,0..n {-__default_metaclass ::xotcl::Class} {-__default_superclass ::xotcl::Object} -mixin:mixinreg,alias,0..n -filter:filterreg,alias,0..n -class:class,alias args:alias,method=residualargs,args" # # test passing arguments to init # ::XD instproc init args { set :args $args } ::XD create x1 1 2 3 -set x 1 ? {x1 exists x} 1 ? {x1 exists args} 1 ? {x1 set args} {1 2 3} } nx::test configure -count 1000 nx::test case xotcl-residualargs2 { ::xotcl::Class create XC -parameter {a b c} ::XC instproc init args {set :x $args; incr :y} ? {XC create xc1 -a 1} ::xc1 ? {XC create xc2 x y -a 1} ::xc2 ::nx::Class create C { :property a :property b :property c :method init args {set :x $args; incr :y} } ? {C create c1 -a 1} ::c1 ? {xc2 eval {info exists :a}} 1 ? {xc2 eval {set :x}} {x y} ? {xc2 eval {set :y}} 1 ? {c1 eval {info exists :a}} 1 ? {c1 eval {set :y}} 1 } nx::test case xotcl-residualargs-upleveling { # # Test callstack resolution for upvar/uplevel in # parameter-dispatched methods under residualargs() ... # package prefer latest package req XOTcl 2.0 xotcl::Class C -proc onTheFly {name args} { ? [list set _ [info exists ix]] 0 ? [list set _ [info exists Y]] 0 set c [[self] $name {*}$args] ? [list set _ [info exists ix]] 1 ? [list set _ [set ix]] Y ? [list set _ [info exists Y]] 1 ? [list set _ [set Y]] 1 return $c } -instproc call {x} { # ::nsf::__db_show_stack my uplevel [list set ix $x] my upvar $x _ incr _ } -instproc call2 {x} { # ::nsf::__db_show_stack uplevel [self callinglevel] [list set ix $x] upvar [self callinglevel] $x _ incr _ } C onTheFly c1 -call Y C onTheFly c1 -call2 Y } # TODO: what todo with object parameter inspection for names with # alias, forward... "names" do not always correspond with vars set. nx::test case class-configure-default { # Background: when class is created, it is created with a "default" # superclass of "::nx::Object". This is defined in the slot for # superclass in nx.tcl nx::Class create P ? {P info superclasses} ::nx::Object # # When we pass the superclass a different value, this is certainly used. # nx::Class create Q -superclass P ? {Q info superclasses} ::P # # When we call configure on the superclass, we do not want the # default to be used to reset it to ::nx::Object. Therefore, the # configure uses the default for parameters with METHOD_INVOCATION # only, when the object is not yet initialized. # Q configure ? {Q info superclasses} ::P } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/parameters.test000644 000766 000024 00000334106 14172621270 017407 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx package require nx::test #::nx::configure defaultMethodCallProtection false set objectFilter "-object-filters:filterreg,slot=::nx::Object::slot::object-filters,slotset,method=object-filter,0..n" set objectMixin "-object-mixins:mixinreg,slot=::nx::Object::slot::object-mixins,slotset,method=object-mixin,0..n" set initBlock "__initblock:cmd,optional,nodashalnum" set filter "-filters:filterreg,slot=::nx::Class::slot::filters,slotset,method=class-filter,0..n" set ::trailer "$objectMixin $objectFilter -class:class,alias,method=::nsf::methods::object::class $initBlock" nx::test case dummy { ? {::namespace current} :: set o [Object create o] ? {::nsf::object::exists ::o} 1 } ? {::nsf::object::exists ::o} 0 # # simple test case for parameter passing # nx::test case syntax { ::nx::Class create C ? {::nsf::method::alias C} \ {required argument 'methodName' is missing, should be: ::nsf::method::alias /object/ ?-per-object? /methodName/ ?-frame method|object|default? ?-protection call-protected|redefine-protected|none? /cmdName/} ? {::nsf::method::alias C foo ::set} "::nsf::classes::C::foo" ? {::nsf::method::alias C foo ::set 1} \ {invalid argument '1', maybe too many arguments; should be "::nsf::method::alias /object/ ?-per-object? /methodName/ ?-frame method|object|default? ?-protection call-protected|redefine-protected|none? /cmdName/"} ? {C eval {:property x -class D}} {invalid argument 'D', maybe too many arguments; should be "::C property ?-accessor /value/? ?-class /value/? ?-configurable /boolean/? ?-incremental? ?-trace /value/? /spec/ ?/initblock/?"} "Test whether the colon prefix is suppressed" } ####################################################### # parametercheck ####################################################### nx::test configure -count 1000 nx::test case parametercheck { nx::Object create o1 nx::Class create C { :property a :property {b:boolean} :property {c 1} } C create c1 nx::Class create M c1 object mixins set M ? {::nsf::object::exists o1} 1 ? {::nsf::object::exists o1000} 0 ? {::nsf::is class C} 1 ? {C info has type ::nx::Class} 1 ? {::nsf::is baseclass ::nx::Object} 1 #? {::nx::Object info is baseclass} 1 ? {::nsf::is baseclass C} 0 #? {C info is baseclass} 0 ? {::nsf::is class ::nx::Object} 1 ? {::nsf::is ::nx::Object class} {invalid value constraints "::nx::Object"} ? {::nsf::is object o1} 1 ? {::nsf::is object o1} 1 ? {::nsf::is object o1000} 0 ? {::nsf::is -complain object o1000} {expected object but got "o1000"} ? {::nsf::is integer 1} 1 ? {::nsf::is object,type=::C c1} 1 ? {::nsf::is -complain object,type=::C o} {expected object but got "o"} ? {::nsf::is object,type=::C o} 0 ? {c1 info has mixin ::M} 1 ? {c1 info has mixin ::M1} {expected class but got "::M1" for parameter "class"} ? {c1 info has type C} 1 ? {c1 info has type C1} {expected class but got "C1" for parameter "class"} ? {c1 ::nsf::methods::object::info::hastype C} 1 ? {::nsf::dispatch c1 ::nsf::methods::object::info::hastype C} 1 ? {::nsf::is object o1} 1 ? {::nsf::is object o100} 0 ? {::nsf::is integer 1} 1 ? {::nsf::is object,type=::C c1} 1 ? {::nsf::is object,type=::C o} 0 # test built-in converter via ::nsf::is ? {::nsf::is boolean 1} 1 ? {::nsf::is boolean on} 1 ? {::nsf::is boolean true} 1 ? {::nsf::is boolean t} 1 ? {::nsf::is boolean f} 1 ? {::nsf::is boolean a} 0 ? {::nsf::is integer 0x0} 1 ? {::nsf::is integer 0xy} 0 # built in converter, but not allowed ? {::nsf::is switch 1} {invalid value constraints "switch": invalid parameter type "switch" for argument "value"; type "switch" only allowed for non-positional arguments} ? {::nsf::is superclass M} {invalid value constraints "superclass"} # don't allow convert; # well we have to allow it, since "-returns" uses the same mechanism #? {::nsf::is integer,convert 1} {invalid value constraints "integer,convert"} # tcl checker ? {::nsf::is upper ABC} 1 ? {::nsf::is upper Abc} 0 ? {::nsf::is lower Abc} 0 ? {::nsf::is lower abc} 1 #? {::nsf::is type c1 C} 1 #? {::nsf::is type o C} 0 #? {::nsf::is object o -type C} 0 #? {::nsf::is object o -hasmixin C} 0 # scripted checker ? {::nsf::is metaclass ::nx::Class} 1 ? {::nsf::is metaclass ::nx::Object} 0 ? {::nsf::is -complain class o1} {expected class but got "o1"} ? {::nsf::is class o1} 0 ? {::nsf::is -complain class nx::test} 1 ? {::nsf::is -complain object,1..* [list o1 nx::test]} 1 ? {::nsf::is -complain integer,1..* [list 1 2 3]} 1 ? {::nsf::is -complain integer,1..* [list 1 2 3 a]} \ {invalid value in "1 2 3 a": expected integer but got "a"} ? {::nsf::is -complain object,type=::C c1} 1 ? {::nsf::is -complain object,type=::C o} \ {expected object but got "o"} \ "object, but different type" ? {::nsf::is -complain object,type=::C c} \ {expected object but got "c"} \ "no object" ? {::nsf::is -complain object,type=::nx::Object c1} 1 "general type" # do not allow "currently unknown" user defined types in parametercheck ? {::nsf::is -complain in1 aaa} {invalid value constraints "in1"} ? {::nsf::is -complain lower c} 1 "lowercase char" ? {::nsf::is -complain lower abc} 1 "lowercase chars" ? {::nsf::is -complain lower Abc} {expected lower but got "Abc"} ? {string is lower abc} 1 "tcl command 'string is lower'" ? {::nsf::is -complain {i:integer 1} 2} {invalid value constraints "i:integer 1"} } nx::test configure -count 10 nx::test case multiple-method-checkers { nx::Object create o { :public object method foo {} { ::nsf::is metaclass ::XYZ ::nsf::is metaclass ::nx::Object } :public object method bar {} { ::nsf::is metaclass ::XYZ ::nsf::is metaclass ::XYZ } :public object method bar2 {} { ::nsf::is metaclass ::nx::Object ::nsf::is metaclass ::nx::Object } } ? {o foo} 0 ? {o bar} 0 ? {::nsf::is metaclass ::XYZ} 0 ? {::nsf::is metaclass ::nx::Object} 0 ? {o foo} 0 ? {o bar2} 0 } ####################################################### # param manager ####################################################### nx::test configure -count 10000 nx::test case param-manager { nx::Object create ::paramManager { :object method type=sex {name value} { return "agamous" } } ? {::nsf::is -complain sex,slot=::paramManager female} "1" } ####################################################### # cononical feature table ####################################################### # # parameter options # required # optional # multivalued # noarg # arg= # substdefault: if no value given, subst on default (result is substituted value); # susbt cmd can use variable resolvers, # works for scripted/c-methods and obj-parm, # automatically set by "$slot toParameterSpec" if default contains "[" ... "]". # # initcmd: evaluate body in an xotcl nonleaf frame, called via configure # (example: last arg on create) # alias,forward call specified method in an xotcl nonleaf frame, called via configure; # specified value is the first argument unless "noarg" is used # (example: -noinit). # # parameter type multivalued required noarg type= arg= parametercheck methodParm objectParm # initcmd NO YES NO NO NO NO NO/POSSIBLE YES # alias,forward NO YES YES NO YES NO NO/POSSIBLE YES # # relation NO YES NO NO YES NO NO YES # stringtype YES YES NO NO NO YES YES YES # # switch NO NO NO NO NO NO YES NO # integer YES YES NO NO NO YES YES YES # boolean YES YES NO NO NO YES YES YES # object YES YES NO YES NO YES YES YES # class YES YES NO YES NO YES YES YES # # userdefined YES YES NO NO YES YES YES YES # # tclObj + converterArg (alnum..xdigit) Attribute ... -type alnum # object + converterArg (some class, e.g. ::C) Attribute ... -type ::C Attribute -type object -arg ::C # class + converterArg (some metaclass, e.g. ::M) Attribute -type class -arg ::M # # #::xotcl::Slot { # {name "[namespace tail [::xotcl::self]]"} # {methodname} # {domain "[lindex [regexp -inline {^(.*)::slot::[^:]+$} [::xotcl::self]] 1]"} # {defaultmethods {get assign}} # {manager "[::xotcl::self]"} # {multivalued false} # {per-object false} # {required false} # default # type # } -- No instances # # ::xotcl::RelationSlot -superclass ::xotcl::Slot { # {multivalued true} # {type relation} # {elementtype ::nx::Class} # } -- sample instances: class superclass, mixin filter # # ::nx::VariableSlot -superclass ::xotcl::Slot { # {value_check once} # defaultcmd # valuecmd # valuechangedcmd # arg # } -- typical object parameters # # MethodParameterSlot -attributes {type required multivalued noarg arg} # -- typical method parameters ####################################################### # objectparameter ####################################################### nx::test configure -count 10 nx::test case objectparameter { nx::Class create C { :property a :property {b:boolean} :property {c 1} } C create c1 ? {C eval :__object_configureparameter} \ "-mixins:mixinreg,slot=::nx::Class::slot::mixins,slotset,method=class-mixin,0..n {-superclasses:class,alias,method=::nsf::methods::class::superclass,1..n ::nx::Object} -filters:filterreg,slot=::nx::Class::slot::filters,slotset,method=class-filter,0..n -object-mixins:mixinreg,slot=::nx::Object::slot::object-mixins,slotset,method=object-mixin,0..n -object-filters:filterreg,slot=::nx::Object::slot::object-filters,slotset,method=object-filter,0..n -class:class,alias,method=::nsf::methods::object::class __initblock:cmd,optional,nodashalnum" #### TODO: remove or add #? {c1 eval :__object_configureparameter} \ # "::c1: unable to dispatch method '__objectparameter'" } ####################################################### # reclass to nx::Object, no need to do anything on caching ####################################################### nx::test case reclass { nx::Class create C { :property a :property {b:boolean} :property {c 1} } C create c1 ? {c1 info lookup slots -source application} "::C::slot::a ::C::slot::b ::C::slot::c" nsf::relation::set c1 class nx::Object ? {c1 info lookup slots -source application} "" nx::Class create D -superclass C {:property d:required} D create d1 -d 100 ? {d1 info lookup slots -source application} \ "::D::slot::d ::C::slot::a ::C::slot::b ::C::slot::c" ? {d1 eval :__object_configureparameter} \ "-d:required -a -b:boolean {-c 1} $::trailer" } ####################################################### # Add mixin ####################################################### nx::test case objparam-mixins { nx::Class create C { :property a :property {b:boolean} :property {c 1} } nx::Class create D -superclass C { :property d:required } D create d1 -d 100 nx::Class create M { :property m1 :property m2 :property b } nx::Class create M2 { :property b2 } D mixins set M ? {d1 eval :__object_configureparameter} \ "-b -m1 -m2 -d:required -a {-c 1} $::trailer" \ "mixin added" M mixins set M2 ? {d1 eval :__object_configureparameter} \ "-b2 -b -m1 -m2 -d:required -a {-c 1} $::trailer" \ "transitive mixin added" D mixins set "" #we should have again the old interface ? {d1 eval :__object_configureparameter} \ "-d:required -a -b:boolean {-c 1} $::trailer" C mixins set M ? {d1 eval :__object_configureparameter} \ "-b2 -b -m1 -m2 -d:required -a {-c 1} $::trailer" \ "mixin added" C mixins set "" #we should have again the old interface ? {d1 eval :__object_configureparameter} \ "-d:required -a -b:boolean {-c 1} $::trailer" } ####################################################### # test passed arguments ####################################################### nx::test case passed-arguments { nx::Class create C { :property a :property b:boolean :property {c 1} } nx::Class create D -superclass C {:property d:required} ? {catch {D create d1 -d 123}} 0 "create d1 with required argument given" ? {catch {D create d1}} 1 "create d1 without required argument given" #puts stderr current=[namespace current] ? {D create d1} \ {required argument 'd' is missing, should be: ::d1 configure -d /value/ ?-a /value/? ?-b /boolean/? ?-c /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?} ? {D create d2 -d x -b a} \ {expected boolean but got "a" for parameter "-b"} \ "create d2 without required argument given" D create d1 -d 1 D public method foo {-b:boolean -r:required,int {-x:int aaa} {-object:object} {-class:class}} { #if {[info exists x]} {puts stderr x=$x} } ? {d1 foo} \ {required argument 'r' is missing, should be: ::d1 foo ?-b /boolean/? -r /integer/ ?-x /integer/? ?-object /object/? ?-class /class/?} \ "call method without a required argument" ? {d1 foo -r a} \ {expected integer but got "a" for parameter "-r"} \ "required argument is not integer" ? {d1 foo -r 1} \ {expected integer but got "aaa" for parameter "-x"} \ "default value is not of type integer" ? {d1 foo -r 1 -x 1 -object d1} \ "" \ "pass object" ? {d1 foo -r 1 -x 1 -object d11} \ {expected object but got "d11" for parameter "-object"} \ "pass non-existing object" ? {d1 foo -r 1 -x 1 -class D} \ "" \ "pass class" ? {d1 foo -r 1 -x 1 -class d1} \ {expected class but got "d1" for parameter "-class"} \ "pass object instead of class" ? {d1 foo -r 1 -x 1 -class D11} \ {expected class but got "D11" for parameter "-class"} \ "pass non-existing class" ? {D public method foo {a:double} {return $a}} \ {::nsf::classes::D::foo} \ "allow 'string is XXXX' for argument checking" ? {d1 foo 1} 1 "check int as double" ? {d1 foo 1.1} 1.1 "check double as double" ? {d1 foo 1.1a} {expected double but got "1.1a" for parameter "a"} "check non-double as double" ? {D info method parameters foo} a:double } ####################################################### # non required positional arguments ####################################################### nx::test case non-reg-args { nx::Class create D D create d1 D public method foo {a b:optional c:optional} { return "[info exists a]-[info exists b]-[info exists c]" } ? {d1 foo 1 2} "1-1-0" "omit optional argument" ? {d1 foo 1} "1-0-0" "omit optional arguments" # non required positional arguments and args D public method foo {a b:optional c:optional args} { return "[info exists a]-[info exists b]-[info exists c]-[info exists args]" } ? {d1 foo 1 2} "1-1-0-1" "omit optional argument" ? {d1 foo 1} "1-0-0-1" "omit optional arguments" } ####################################################### # multivalued arguments ####################################################### nx::test case multivalued { nx::Class create D D create d1 nx::Object create o D public method foo {m:integer,0..n} { return $m } ? {d1 foo ""} "" "empty list" ? {d1 foo 1} "1" "single value" ? {d1 foo {1 2}} "1 2" "multiple values" ? {d1 foo {1 a 2}} \ {invalid value in "1 a 2": expected integer but got "a" for parameter "m"} \ "multiple values with wrong value" D public method foo {m:object,0..n} { return $m } ? {d1 foo ""} "" "empty list" ? {d1 foo o} "o" "single value" ? {d1 foo {o d1 x}} \ {invalid value in "o d1 x": expected object but got "x" for parameter "m"} \ "multiple values" nx::Class create Foo { :property ints:integer,1..* } ? {Foo create foo -ints {1 2}} "::foo" ? {Foo create foo -ints {1 a 2}} {invalid value in "1 a 2": expected integer but got "a" for parameter "-ints"} # make slot incremental Foo property -incremental ints:integer,1..* # TODO? the following does not work. Should we revive it? #Foo::slot::ints eval { # set :incremental 1 # :reconfigure #} Foo create foo -ints {1 2} ? {foo ints add 0} "0 1 2" ? {foo ints add a} {expected integer but got "a" for parameter "value"} } ####################################################### # subst default tests ####################################################### nx::test case subst-default { nx::Class create D { :property -accessor public {c 1} :property {d 2} :create d1 :public method bar { {-s:substdefault "[current]"} {-literal "[current]"} {-c:substdefault "[:c get]"} {-d:integer,substdefault "$d"} } { return $s-$literal-$c-$d } } ? {d1 bar -c 1} {::d1-[current]-1-2} "substdefault in method parameter" set ::X 1001 nx::Class create Bar -superclass D { :property {s:substdefault "[current]"} :property {literal "[current]"} :property {c:substdefault "[:info class]"} :property {d "literal $d"} :property {e:substdefault {noliteral $::X}} } ? {Bar property -accessor public ss:switch} "::nsf::classes::Bar::ss" ? {Bar create bar1} ::bar1 #puts stderr [bar1 __objectparameter] ? {subst {[bar1 cget -s]-[bar1 cget -literal]-[bar1 cget -c]-[bar1 cget -d]-[bar1 cget -e]}} \ {::bar1-[current]-::Bar-literal $d-noliteral 1001} \ "substdefault in object parameter 1" ? {Bar create bar2} ::bar2 ? {subst {[bar2 cget -s]-[bar2 cget -literal]-[bar2 cget -c]-[bar2 cget -d]-[bar1 cget -e]}} \ {::bar2-[current]-::Bar-literal $d-noliteral 1001} \ "substdefault in object parameter 2" # Observation: # - substdefault for '$' in property defaults does not make much sense. # deactivated for now; otherwise we would need "\\" D public method bar { {-s:substdefault "[current]"} {-literal "[current]"} {-c:substdefault "[:c get]"} {-d:integer,substdefault "$d"} {-switch:switch} {-optflag} x y:integer {z 1} } { return $s-$literal-$c-$d } ? {D info method args bar} {s literal c d switch optflag x y z} "all args" ? {D info method parameters bar} \ {{-s:substdefault "[current]"} {-literal "[current]"} {-c:substdefault "[:c get]"} {-d:integer,substdefault "$d"} -switch:switch -optflag x y:integer {z 1}} \ "query method parameter" ? {D public method foo {s:switch} {return 1}} \ {invalid parameter type "switch" for argument "s"; type "switch" only allowed for non-positional arguments} D public method foo {a b {-c 1} {-d} x {-end 100}} { set result [list] foreach v [[current class] info method args [current method]] { lappend result $v [info exists $v] } return $result } ? {d1 foo 1 2 3} \ "a 1 b 1 c 1 d 0 x 1 end 1" \ "parse multiple groups of nonpos args" D public method foo {a b c {end 100}} { set result [list] foreach v [[current class] info method args [current method]] { lappend result $v [info exists $v] } return $result } ? {d1 foo 1 2 3} \ "a 1 b 1 c 1 end 1" \ "query arguments with default, no paramdefs needed" ####################################################### # Query method parameter ####################################################### ? {D info method parameters foo} \ "a b c {end 100}" \ "query instparams with default, no paramdefs needed" ? {nx::Class info method parameters method} \ "-debug:switch -deprecated:switch name arguments:parameter,0..* -checkalways:switch -returns body" \ "query instparams for scripted method 'method'" ? {nx::Object info method parameters ::nsf::method::forward} \ "object:object -per-object:switch method -default -earlybinding:switch -onerror -prefix -frame -verbose:switch target:optional args" \ "query parameter for C-defined cmd 'nsf::forward'" nx::Object require method autoname ? {nx::Object info method parameters autoname} \ "-instance:switch -reset:switch name" \ "query parameter for C-defined method 'autoname'" D method "a b" {x y} {return $x-$y} D object method "c d" {x y z} {return $x-$y} ? {D info method parameters "a b"} "x y" ? {D info object method parameters "c d"} "x y z" } ####################################################### # user defined parameter value checkers ####################################################### nx::test case user-value-checker { nx::Class create D {:property d} D create d1 # Create a user-defined value checker for method parameters, # without extra argument ::nx::methodParameterSlot object method type=mytype {name value} { if {$value < 1 || $value > 3} { error "value '$value' of parameter $name is not between 1 and 3" } } D public method foo {a:mytype} { return a=$a } d1 foo 1 ? {d1 foo 10} \ "value '10' of parameter a is not between 1 and 3" \ "value not between 1 and 3" D public method foo {a:unknowntype} { return $a } ? {d1 foo 10} \ "::nx::methodParameterSlot: unable to dispatch method 'type=unknowntype'" \ "missing type checker" # # Create a user-defined value-checker for method parameters, # with an extra argument # ::nx::methodParameterSlot object method type=in {name value arg} { if {$value ni [split $arg |]} { error "value '$value' of parameter $name not in permissible values $arg" } return $value } # # Trivial test case # D public method foo {a:in,arg=a|b|c} { return a=$a } ? {d1 foo a} "a=a" ? {d1 foo 10} \ "value '10' of parameter a not in permissible values a|b|c" \ "invalid value" # # Test case with positional and non-positional arguments, and default # D public method foo {a:in,arg=a|b|c b:in,arg=good|bad {-c:in,arg=a|b a}} { return a=$a,b=$b,c=$c } ? {d1 foo a good -c b} "a=a,b=good,c=b" ? {d1 foo a good} "a=a,b=good,c=a" ? {d1 foo b "very good"} \ "value 'very good' of parameter b not in permissible values good|bad" \ "invalid value (not included)" # # Create a user-defined value checker for method parameters, # without extra argument # ::nx::methodParameterSlot object method type=commaRange {name value arg} { lassign [split $arg ,] min max if {$value < $min || $value > $max} { error "value '$value' of parameter $name not between $min and $max" } return $value } D public method foo {a:commaRange,arg=1,,3} { return a=$a } ? {d1 foo 2} "a=2" ? {d1 foo 10} \ "value '10' of parameter a not between 1 and 3" \ "invalid value" # # two commas at the end # D public method foo {a:commaRange,arg=1,,} {return a=$a} ? {d1 foo 2} {value '2' of parameter a not between 1 and } # # one comma at the end # D public method foo {a:commaRange,arg=1,} {return a=$a} ? {d1 foo 2} {value '2' of parameter a not between 1 and } # # Classical range check # ::nx::methodParameterSlot object method type=range {name value arg} { lassign [split $arg -] min max if {$value < $min || $value > $max} { error "value '$value' of parameter $name not between $min and $max" } return $value } D public method foo {a:range,arg=1-3 {-b:range,arg=2-6 3} c:range,arg=5-10} { return a=$a,b=$b,c=$c } ? {d1 foo 2 -b 4 9} "a=2,b=4,c=9" ? {d1 foo 2 10} "a=2,b=3,c=10" ? {d1 foo 2 11} \ "value '11' of parameter c not between 5 and 10" \ "invalid value" # define type twice ? {D public method foo {a:int,range,arg=1-3} {return a=$a}} \ "parameter option 'range' unknown for parameter type 'integer'" \ "invalid value" # # handling of arg with spaces/arg as list # ::nx::methodParameterSlot public object method type=list {name value arg} { #puts $value/$arg return $value } # handling spaces in "arg" is not not particular nice D public method foo {{"-a:list,arg=2 6" 3} {"b:list,arg=5 10"}} { return a=$a,b=$b } ? {d1 foo -a 2 10} "a=2,b=10" } nx::test case value-checker-call-check { nx::Class create PV { :property -accessor public h:foo,arg=123 { :object method type=foo {prop value arg} { incr ::counter(h) return } } :property -accessor public hs:0..*,foo { :object method type=foo {prop value} { incr ::counter(hs) return } } } ? {info exists ::counter(h)} 0 set pv1 [PV new -h 121] ? {set ::counter(h)} 1 $pv1 h set 212 ? {set ::counter(h)} 2 $pv1 configure -h 212 ? {set ::counter(h)} 3 unset -nocomplain ::counter(h) ? {info exists ::counter(hs)} 0 set pv2 [PV new -hs 121] ? {set ::counter(hs)} 1 $pv2 hs add 212 ? {set ::counter(hs)} 2 $pv1 configure -hs 313 ? {set ::counter(hs)} 3 unset -nocomplain ::counter(hs) } ####################################################### # testing object types in method parameters ####################################################### nx::test case mp-object-types { nx::Class create C nx::Class create D -superclass C {:property d} nx::Class create M nx::Class create M2 D create d1 -d 1 C create c1 -object-mixins M C create c2 -object-mixins {{M -guard true}} C create c3 -object-mixins {M ::M2} C create c4 -object-mixins {{M -guard 1} M2} C create c5 -object-mixins {M {M2 -guard 2}} nx::Object create o ? {c1 object mixins get} ::M ? {c1 object mixins guard ::M} "" ? {c2 object mixins get} {{::M -guard true}} ? {c2 object mixins classes} ::M ? {c2 object mixins guard ::M} "true" ? {c3 object mixins get} {::M ::M2} ? {c3 object mixins guard M} "" ? {c3 object mixins guard M2} "" ? {c4 object mixins get} {{::M -guard 1} ::M2} ? {c4 object mixins classes} {::M ::M2} ? {c4 object mixins classes M} ::M ? {c4 object mixins classes M1} "" ? {c4 object mixins guard M} "1" ? {c4 object mixins guard M2} "" ? {c5 object mixins get} {::M {::M2 -guard 2}} ? {c5 object mixins classes} {::M ::M2} ? {c5 object mixins classes M} {::M} ? {c5 object mixins classes M1} "" ? {c5 object mixins guard M} "" ? {c5 object mixins guard M2} "2" D public method foo-base {x:baseclass} {return $x} D public method foo-class {x:class} {return $x} D public method foo-object {x:object} {return $x} D public method foo-meta {x:metaclass} {return $x} D public method foo-type {x:object,type=::C} {return $x} ? {D info method parameters foo-base} "x:baseclass" ? {D info method parameters foo-type} "x:object,type=::C" ? {d1 foo-base ::nx::Object} "::nx::Object" ? {d1 foo-base C} \ {expected baseclass but got "C" for parameter "x"} \ "not a base class" ? {d1 foo-class D} "D" ? {d1 foo-class xxx} \ {expected class but got "xxx" for parameter "x"} \ "not a class" ? {d1 foo-class o} \ {expected class but got "o" for parameter "x"} \ "not a class" ? {d1 foo-meta ::nx::Class} "::nx::Class" ? {d1 foo-meta ::nx::Object} \ {expected metaclass but got "::nx::Object" for parameter "x"} \ "not a base class" ? {d1 foo-object o} "o" ? {d1 foo-object xxx} \ {expected object but got "xxx" for parameter "x"} \ "not an object" ? {d1 foo-type d1} "d1" ? {d1 foo-type c1} "c1" ? {d1 foo-type o} \ {expected object of type ::C but got "o" for parameter "x"} \ "o not of type ::C" } ####################################################### # substdefault ####################################################### nx::test case substdefault { nx::Class create S { :property {x 1} :property {y b} :property {z {1 2 3}} } S create s1 { :public object method foo {{y:substdefault ${:x}}} { return $y } :public object method bar {{y:integer,substdefault ${:x}}} { return $y } :public object method baz {{x:integer,substdefault ${:y}}} { return $x } :public object method boz {{x:integer,0..n,substdefault ${:z}}} { return $x } } ? {s1 foo} 1 ? {s1 foo 2} 2 ? {S object method foo {a:substdefault} {return 1}} \ {parameter option substdefault specified for parameter "a" without default value} ? {s1 bar} 1 ? {s1 bar 3} 3 ? {s1 bar a} {expected integer but got "a" for parameter "y"} ? {s1 baz} {expected integer but got "b" for parameter "x"} ? {s1 baz 20} 20 s1 configure -y 100 ? {s1 baz} 100 ? {s1 baz 101} 101 ? {s1 boz} {1 2 3} s1 configure -z {1 x 100} ? {s1 boz} {invalid value in "1 x 100": expected integer but got "x" for parameter "x"} ? {s1 boz {100 200}} {100 200} set ::aaa 100 ? {s1 public object method foo {{a:substdefault $::aaa}} {return $a}} ::s1::foo ? {s1 foo} 100 unset ::aaa ? {s1 foo} {can't read "::aaa": no such variable} ? {s1 public object method foo {{a:substdefault $aaa}} {return $a}} ::s1::foo ? {s1 foo} {can't read "aaa": no such variable} ? {s1 public object method foo {{a:substdefault [current]}} {return $a}} ::s1::foo ? {s1 foo} ::s1 "final test" } ####################################################### # testing substdefault for object parameters (per-class) ####################################################### nx::test case substdefault-objparam-perclass { nx::Class create Bar { # no substdefault given :property {s0 "[current]"} # explicit substdefault :property {s1:substdefault "[current]"} # unneeded double substdefault :property {s2:substdefault,substdefault "[current]"} # substdefault with incremental :property -incremental {s3:substdefault "[current]"} } ? {Bar create ::b} ::b "create object" ? {b cget -s0} {[current]} ? {b cget -s1} "::b" ? {b cget -s2} "::b" ? {b cget -s3} "::b" } ####################################################### # testing substdefault for object parameters (per-object) ####################################################### nx::test case substdefault-objparam-perobj { nx::Object create rab { # no substdefault given :object property {s0 "[current]"} # explicit substdefault :object property {s1:substdefault "[current]"} # unneeded double substdefault :object property {s2:substdefault,substdefault "[current]"} # substdefault with incremental :object property -incremental {s3:substdefault "[current]"} # no substdefault given :object variable s4 {[current]} # explicit substdefault :object variable s5:substdefault {[current]} # unneeded double substdefault :object variable s6:substdefault,substdefault {[current]} # substdefault with incremental :object variable -incremental s7:substdefault {[current]} } ? {rab cget -s0} {[current]} ? {rab cget -s1} "::rab" ? {rab cget -s2} "::rab" ? {rab cget -s3} "::rab" ? {rab eval {set :s4}} {[current]} ? {rab eval {set :s5}} "::rab" ? {rab eval {set :s6}} "::rab" ? {rab eval {set :s7}} "::rab" } # # Test call of configure within constructor # nx::test case parameter-alias-default { ::nsf::method::require nx::Object __configure nx::Class create C { :property {a ""} :property {b 1} :method init {} { :__configure -b 1 } :create c1 :create c2 -a 0 } ? {::c1 eval {set :a}} "" ? {::c1 eval {set :b}} 1 ? {::c2 eval {set :a}} 0 ? {::c2 eval {set :b}} 1 } ####################################################### # testing object types in object parameters ####################################################### nx::test case op-object-types { nx::Class create C nx::Class create D -superclass C {:property d} nx::Class create MC -superclass nx::Class MC create MC1 nx::Class create M D create d1 -d 1 C create c1 -object-mixins M nx::Object create o nx::Class create ParamTest { :property o:object :property c:class :property c1:class,type=::MC :property d:object,type=::C :property d1:object,type=C :property m:metaclass :property b:baseclass :property u:upper :property us:upper,1..* :property -incremental us2:upper,1..* :property {x:object,1..* {o}} } ? {ParamTest info lookup parameters create o} "-o:object" ? {ParamTest info lookup parameters create c} "-c:class" ? {ParamTest info lookup parameters create c1} "-c1:class,type=::MC" ? {ParamTest info lookup parameters create d} "-d:object,type=::C" ? {ParamTest info lookup parameters create d1} "-d1:object,type=::C" ? {ParamTest info lookup parameters create x} "{-x:object,1..* o}" ? {ParamTest info lookup parameters create u} "-u:upper,slot=::ParamTest::slot::u" ? {ParamTest info lookup parameters create us} "-us:upper,slot=::ParamTest::slot::us,1..*" ? {ParamTest create p -o o} ::p ? {ParamTest create p -o xxx} \ {expected object but got "xxx" for parameter "-o"} \ "not an object" ? {ParamTest create p -c C} ::p "class" ? {ParamTest create p -c o} \ {expected class but got "o" for parameter "-c"} \ "not a class" ? {ParamTest create p -c1 MC1} ::p "instance of meta-class MC" ? {ParamTest create p -c1 C} \ {expected class of type ::MC but got "C" for parameter "-c1"} \ "not an instance of meta-class MC" ? {ParamTest create p -d d1} ::p ? {ParamTest create p -d1 d1} ::p ? {ParamTest create p -d c1} ::p ? {ParamTest create p -d o} \ {expected object of type ::C but got "o" for parameter "-d"} \ "o not of type ::C" #? {ParamTest create p -mix c1} ::p #? {ParamTest create p -mix o} \ {expected object with mixin M but got "o" for parameter "mix"} \ "does not have mixin M" ? {ParamTest create p -u A} ::p ? {ParamTest create p -u c1} {expected upper but got "c1" for parameter "-u"} ? {ParamTest create p -us {A B c}} \ {invalid value in "A B c": expected upper but got "c" for parameter "-us"} ParamTest::slot::us eval { set :incremental 1 :reconfigure } ? {ParamTest create p -us {A B} -us2 {A B}} ::p ? {p us add C end} "A B C" ? {p us2 add C end} "A B C" ? {p configure -o o} \ "" \ "value is an object" ? {p configure -o xxx} \ {expected object but got "xxx" for parameter "-o"} \ "value is not an object" # # define multivalued property "os" via instance variables of the # slot object # ParamTest eval { #:property -accessor public os { # :type object # :multiplicity 1..n #} :property -accessor public os:object,1..n } ? {ParamTest info method definition os} "::ParamTest public forward os -prefix value= ::ParamTest::slot::os %1 %self os" ? {p os set o} \ "o" \ "value is a list of objects (1 element)" ? {p os set {o c1 d1}} \ "o c1 d1" \ "value is a list of objects (multiple elements)" ? {p os set {o xxx d1}} \ {invalid value in "o xxx d1": expected object but got "xxx" for parameter "value"} \ "list with invalid object" } ####################################################### # application specific multivalued converter ####################################################### nx::test case multivalued-app-converter { ::nx::methodParameterSlot public object method type=sex {name value args} { #puts stderr "[current] slot specific converter" switch -glob $value { m* {return m} f* {return f} default {error "expected sex but got $value"} } } nx::Class create C { :public method foo {s:sex,0..*,convert} {return $s} :public method bar {s:sex,0..*} {return $s} } C create c1 ? {c1 foo {male female mann frau}} "m f m f" ? {c1 bar {male female mann frau}} "male female mann frau" nx::Object create tmpObj tmpObj object method type=mType {name value arg:optional} { if {$value} { error "expected false but got $value" } # Note that this converter does NOT return a value; it converts all # values into empty strings. } ? {::nsf::is -complain mType,slot=::tmpObj,0..* {1 0}} \ {invalid value in "1 0": expected false but got 1} \ "fail on first value" ? {::nsf::is -complain mType,slot=::tmpObj,0..* {0 0 0}} 1 "all pass" ? {::nsf::is -complain mType,slot=::tmpObj,0..* {0 1}} \ {invalid value in "0 1": expected false but got 1} \ "fail o last value" } ####################################################### # application specific multivalued converter ####################################################### nx::test case shadowing-app-converter { nx::Object create mySlot { :public object method type=integer {name value arg:optional} { return [expr {$value + 1}] } } nx::Object create o { :public object method foo {x:integer,slot=::mySlot,convert} { return $x } } ? {::nsf::is -complain integer,slot=::mySlot 1} 1 ? {o foo 3} 4 } ####################################################### # allow empty values ####################################################### nx::test case allow-empty { nx::Object create o1 nx::Object create o2 nx::Object create o3 nx::Object create o { :public object method foo {x:integer,0..1 y:integer os:object,0..*} { return $x } } ? {o foo 1 2 {o1 o2}} 1 "all values specified" ? {o foo "" 2 {o1 o2}} "" "first is empty" ? {o foo 1 "" {o1 o2}} {expected integer but got "" for parameter "y"} "second is empty" ? {o foo 1 2 {}} 1 "empty list" ? {o info object method parameters foo} "x:integer,0..1 y:integer os:object,0..*" o public object method foo {x:integer,0..1 y:integer os:object,1..*} {return $x} ? {o foo 1 2 {o1 "" o2}} {invalid value in "o1 "" o2": expected object but got "" for parameter "os"} \ "list contains empty value" ? {o foo "" 2 {}} {invalid value for parameter 'os': list is not allowed to be empty} \ "empty int, empty list of objects" } ####################################################### # slot specific converter ####################################################### nx::test case slot-specific-converter { nx::Class create Person { :property -accessor public sex:sex,convert { :object method type=sex {name value} { #puts stderr "[self] slot specific converter" switch -glob $value { m* {return m} f* {return f} default {error "expected sex but got $value"} } } } :property -accessor public sexes:sex,0..*,convert { :object method type=sex {name value} { #puts stderr "[self] sexes slot specific converter" switch -glob $value { m* {return m} f* {return f} default {error "expected sex but got $value"} } } } } Person create p1 -sex male ? {p1 cget -sex} m ? {p1 sex get} m Person public method foo {s:sex,slot=::Person::slot::sex,convert} {return $s} ? {p1 foo male} m ? {p1 sex set male} m Person create p2 -sexes {male female} ? {p2 cget -sexes} {m f} ? {p2 sexes get} {m f} ? {p2 sexes add female} {f m f} ? {p2 sexes set {male female male}} {m f m} set count [nx::test cget -count] nx::test configure -count 1 ? {p2 sexes delete female} {m m} ? {p2 sexes delete female} {::p2: 'f' is not in variable 'sexes' (values are: 'm m')} ? {p2 sexes delete -nocomplain female} {m m} ? {p2 sexes delete -nocomplain male} {m} ? {p2 sexes get} {m} nx::test configure -count $count Person public method bar {s:sex,0..*,slot=::Person::slot::sexes,convert} {return $s} ? {p2 bar {female male female}} {f m f} } ####################################################### # test for setters with parameters os ####################################################### nx::test case setters { nx::Object create o nx::Class create C ? {::nsf::method::setter ::o :a} {invalid setter name ":a" (must not start with a dash or colon)} ? {::nsf::method::setter o a} "::o::a" ? {::nsf::method::setter C c} "::nsf::classes::C::c" ? {o info object method definition a} "::o public object setter a" ? {o info object method parameters a} "a" ? {o info object method args a} "a" ? {C info method definition c} "::C public setter c" ? {o a 1} "1" ? {::nsf::method::setter o a:integer} "::o::a" ? {::nsf::method::setter o ints:integer,1..*} "::o::ints" ? {::nsf::method::setter o o:object} "::o::o" ? {o info object method registrationhandle ints} "::o::ints" ? {o info object method definition ints} "::o public object setter ints:integer,1..*" ? {o info object method parameters ints} "ints:integer,1..*" ? {o info object method args ints} "ints" ? {o info object method registrationhandle o} "::o::o" ? {o info object method definition o} "::o public object setter o:object" ? {o info object method parameters o} "o:object" ? {o info object method args o} "o" ? {o a 2} 2 ? {o a hugo} {expected integer but got "hugo" for parameter "a"} ? {o ints {10 100 1000}} {10 100 1000} ? {o ints hugo} {invalid value in "hugo": expected integer but got "hugo" for parameter "ints"} ? {o o o} o ? {::nsf::method::setter o {d default}} {parameter specification for "d" is not allowed to have default "default"} ? {::nsf::method::setter o "d\ndefault"} {parameter specification for "d" is not allowed to have default "default"} ? {::nsf::method::setter o -x} {invalid setter name "-x" (must not start with a dash or colon)} } nx::test case setters-wrongargs { nx::Object create o ::nsf::method::setter o z ? {o z -10} -10 ? {o z} -10 ? {o z -1 0} {wrong # args should be "::o z ?value?"} } ####################################################### # test for slot-optimizer ####################################################### nx::test configure -count 1000 nx::test case slot-optimizer { nx::Class create C { :property -accessor public a :property -accessor public b:integer :property -accessor public c:integer,0..n } C create c1 ? {c1 a set 1} 1 ? {c1 b set 1} 1 ? {c1 c set 1} 1 } nx::test configure -count 10 nx::test case slot-nosetter { nx::Class create C { :property -accessor public a :property -accessor none b:integer :property -accessor none {c ""} } ? {C create c1 -a 1 -b 2} ::c1 ? {c1 info vars} "a b c" ? {c1 a set 100} 100 ? {c1 b 101} {::c1: unable to dispatch method 'b'} ? {c1 c 102} {::c1: unable to dispatch method 'c'} } nx::test configure -count 1000 nx::test case check-arguments { nx::Class create Foo { :public method noarg {} {return ""} :public method onearg {x} {return $x} :public method intarg {x:integer} {return $x} :public method intsarg {x:integer,1..*} {return $x} :public method boolarg {x:boolean} {return $x} :public method classarg {x:class} {return $x} :public method upperarg {x:upper} {return $x} :public method metaclassarg {x:metaclass} {return $x} :create f1 } ? {f1 noarg} "" ? {f1 onearg 1} 1 # built-in checker ? {f1 intarg 1} 1 ? {f1 intarg a} {expected integer but got "a" for parameter "x"} ? {f1 intsarg {10 11 12}} {10 11 12} ? {f1 intsarg {10 11 1a2}} {invalid value in "10 11 1a2": expected integer but got "1a2" for parameter "x"} ? {f1 boolarg 1} 1 ? {f1 boolarg a} {expected boolean but got "a" for parameter "x"} ? {f1 classarg ::Foo} ::Foo ? {f1 classarg f1} {expected class but got "f1" for parameter "x"} # tcl checker ? {f1 upperarg ABC} ABC ? {f1 upperarg abc} {expected upper but got "abc" for parameter "x"} # scripted checker ? {f1 metaclassarg ::nx::Class} ::nx::Class ? {f1 metaclassarg ::Foo} {expected metaclass but got "::Foo" for parameter "x"} } nx::test case copy-with-required { nx::Class create C { :property n:required } C create c1 -n 1 ? {c1 copy c2} "::c2" } # # basic slot trace tests # nx::test case slot-traces { # # basic tests for object slots # ::nx::Object create o { :object property -accessor public -trace default a { :public object method value=default {obj var} {return 4 } } :object property -accessor public -trace get b { :public object method value=get {obj var} { return 44 } } :object property -accessor public -trace set c { :public object method value=set {obj var value} { ::nsf::var::set $obj $var 999 } } } ? {o a get} 4 ? {o b get} 44 ? {o c set 5} 999 ? {::nsf::object::property o hasperobjectslots} 1 o copy o2 ? {o a get} 4 ? {o b get} 44 ? {o c set 5} 999 ? {::nsf::object::property o2 hasperobjectslots} 1 # # basic tests for class slots # ::nx::Class create C { :property -accessor public -trace default a { :public object method value=default {obj var} { return 4 } } :property -accessor public -trace get b { :public object method value=get {obj property} { return 44 } } :property -accessor public -trace set c { :public object method value=set {obj property value} { ::nsf::var::set $obj $property 999 } } :create c1 } ? {c1 a get} 4 ? {c1 b get} 44 ? {c1 c set 5} 999 c1 copy c2 ? {c2 a get} 4 ? {c2 b get} 44 ? {c2 c set 5} 999 C copy D D create d1 ? {d1 a get} 4 ? {d1 b get} 44 ? {d1 c set 5} 999 } nx::test case slot-trace-interaction { # # 1) Verify the controlled interactions between trace types # # per-object: # package req nx::serializer Object create o ? {o eval {info exists :a}} 0 ? {o object property -trace default {a 0} { }} "'-trace default' can't be used together with default value" ? {o eval {info exists :a}} 0 ? {o eval {info exists :b}} 0 ? {o object property -trace get {b:integer 123} { }} "" ? {o eval {info exists :b}} 1 ? {o object property -trace get {b:integer hello} { }} {expected integer but got "hello" for parameter "b"} ? {o eval {info exists :c}} 0 ? {o object property -trace {default get} c { }} "'-trace default' and '-trace get' can't be used together" ? {o eval {info exists :c}} 0 # # valuechangedcmd + default value are allowed # ? {o eval {info exists :a}} 0 o object property -accessor public -trace set {a 0} { :public object method value=set {obj var value} { ::nsf::var::set -notrace $obj $var [expr {$value + 1}] } } ? {o eval {info exists :a}} 1 ? {o a get} 0 ? {o a set 1} 2 ? {o a get} 2 ? {o a set 2} 3 ? {o eval {info exists :A}} 0 o object property -trace set {A 0} { :public object method value=set {obj var value} { ::nsf::var::set -notrace $obj $var [expr {$value + 1}] } } ? {o eval {info exists :A}} 1 ? {o cget -A} 0 ? {o configure -A 1} "" ? {o cget -A} 2 # per-class: Class create Klass ? {Klass property -trace default {a 0} { }} "'-trace default' can't be used together with default value" ? {Klass property -trace get {b 0} { }} "" ? {Klass property -trace {default get} c { }} "'-trace default' and '-trace get' can't be used together" Klass property -accessor public -trace set {a 0} { :public object method value=set {obj var value} { ::nsf::var::set -notrace $obj $var [expr {$value + 1}] } } Klass create k ? {k eval {info exists :a}} 1 ? {k a get} 0; # should be 1, reflecting the corresponding per-object case above ? {k a set 1} 2 ? {k a get} 2 ? {k a set 2} 3 # # 2) Have initcmd scripts escaped from C-level argument checking (in # the per-class check) # # a) against scalar checkers (as a simplistic case) Klass property -trace set b:boolean { :public object method value=set {obj property value} { return tr1e } } ? {catch {Klass create kk}} 0 # # b) Structured trace scripts, containing lists. Check for # brace balancedness ... # # Background: Script blocks passed as initcmds should not be # subjected to *any* argument checking. This was not guaranteed, # previously. As a result, for example, upon multivalued argument # checking (e.g., 0..n) the argument (i.e., the initcmd block) was # tentatively expanded into a Tcl list. This failed for initcmd # scripts which do not qualify as valid list structures (a condition # not to be enforced). # # Below, we introduce three tests capturing the unwanted # interaction, now fixed. Note: This issue only affects # class-wide initcmds, as in the per-object case, the initcmds are # evaluated right away and not fiddled through the parameter handling # infrastructure. ::nx::Class create CC { :property -trace default a:0..n { :public object method value=default {obj property} { return 4 } } :property -trace get b:0..n { :public object method value=get {obj property} { return 44 } } :property -accessor public -trace set c:0..n { :public object method value=set {obj property value} { ::nsf::var::set $obj $property 999 } } :create ::cc } ? {cc cget -a} 4 ? {cc cget -b} 44 ? {cc c set 5} 999 } ::nsf::configure checkarguments off nx::test case check-arguments-nocheck { nx::Class create Foo { :public method noarg {} {return ""} :public method onearg {x} {return $x} :public method intarg {x:integer} {return $x} :public method intsarg {x:integer,1..*} {return $x} :public method boolarg {x:boolean} {return $x} :public method classarg {x:class} {return $x} :public method upperarg {x:upper} {return $x} :public method metaclassarg {x:metaclass} {return $x} :create f1 } ? {f1 noarg} "" ? {f1 onearg 1} 1 # built-in checker ? {f1 intarg 1} 1 ? {f1 intarg a} a ? {f1 intsarg {10 11 12}} {10 11 12} ? {f1 intsarg {10 11 1a2}} {10 11 1a2} ? {f1 boolarg 1} 1 ? {f1 boolarg a} a ? {f1 classarg ::Foo} ::Foo ? {f1 classarg f1} f1 # tcl checker ? {f1 upperarg ABC} ABC ? {f1 upperarg abc} abc # scripted checker ? {f1 metaclassarg ::nx::Class} ::nx::Class ? {f1 metaclassarg ::Foo} ::Foo } nx::test configure -count 100 nx::test case checktype { nx::Object create o { :public object method f01 {} {::nsf::dispatch o ::nsf::methods::object::info::hastype ::nx::Object} :public object method f02 {} {::nsf::dispatch o ::nsf::methods::object::info::hastype nx::Object} :public object method f03 {} {::nsf::dispatch o ::nsf::methods::object::info::hastype nx::Object} :public object method f11 {} {::nsf::is object,type=::nx::Object o} :public object method f12 {} {::nsf::is object,type=nx::Object o} :public object method f13 {} {::nsf::is object,type=Object o} } ? {o f01} 1 ? {o f02} 1 ? {o f03} 1 ? {o f11} 1 ? {o f12} 1 #? {o f13} 0 } # # testing namespace resolution in type checkers # namespace eval foo { nx::Class create C { :create c1 :public method f21 {} {::nsf::dispatch c1 ::nsf::methods::object::info::hastype nx::Object} :public method f22 {} {::nsf::dispatch c1 ::nsf::methods::object::info::hastype C} :public method f31 {} {::nsf::is object,type=::nx::Object c1} :public method f32 {} {::nsf::is object,type=C c1} } nx::Object create o { :public object method f01 {} {::nsf::dispatch c1 ::nsf::methods::object::info::hastype ::nx::Object} :public object method f02 {} {::nsf::dispatch c1 ::nsf::methods::object::info::hastype nx::Object} :public object method f03 {} {::nsf::dispatch c1 ::nsf::methods::object::info::hastype nx::Object} :public object method f04 {} {::nsf::dispatch c1 ::nsf::methods::object::info::hastype foo::C} :public object method f05 {} {::nsf::dispatch c1 ::nsf::methods::object::info::hastype C} :public object method f11 {} {::nsf::is object,type=::nx::Object c1} :public object method f12 {} {::nsf::is object,type=nx::Object c1}; # resolves to ::foo::nx::Object :public object method f13 {} {::nsf::is object,type=Object c1}; # resolves to ::foo::Object :public object method f14 {} {::nsf::is object,type=C c1}; # resolves to ::foo::C :public object method f15 {} {::nsf::is object,type=[namespace which C] c1}; # ::foo::C } ? {o f01} 1 ? {o f02} 1 ? {o f03} 1 ? {o f04} 1 ? {o f05} 1 ? {o f11} 1 ? {o f12} 0 ? {o f13} 0 ? {o f14} 1 ? {o f15} 1 ? {c1 f21} 1 ? {c1 f22} 1 ? {c1 f31} 1 ? {c1 f32} 1 } nx::test case check-arguments { nx::Class create Foo { :method noarg {} {return ""} :method onearg {-x} {return $x} :method intarg {-x:integer} {return $x} :method intsarg {-x:integer,1..*} {return $x} :method boolarg {-x:boolean} {return $x} :method classarg {-x:class} {return $x} :method upperarg {-x:upper} {return $x} :method metaclassarg {-x:metaclass} {return $x} } ? {Foo info method syntax noarg} "/cls/ noarg" ? {Foo info method syntax onearg} "/cls/ onearg ?-x /value/?" ? {Foo info method syntax intarg} "/cls/ intarg ?-x /integer/?" ? {Foo info method syntax intsarg} "/cls/ intsarg ?-x /integer .../?" ? {Foo info method syntax boolarg} "/cls/ boolarg ?-x /boolean/?" ? {Foo info method syntax classarg} "/cls/ classarg ?-x /class/?" ? {Foo info method syntax upperarg} "/cls/ upperarg ?-x /upper/?" ? {Foo info method syntax metaclassarg} "/cls/ metaclassarg ?-x /metaclass/?" # return enumeration type ? {nx::Class info method syntax "info mixinof"} \ "/cls/ info mixinof ?-closure? ?-scope all|class|object? ?/pattern/?" } # # Check whether resetting via method "configure" changes values in the # initialized object state. # nx::test case don't-reset-to-defaults { nx::Class create C { :property -accessor public {a 1} :create c1 } ? {c1 cget -a} 1 # change the value from the default to a different value ? {c1 a set 2} 2 ? {c1 a get} 2 # call configure ... c1 __configure # ... and check, it did not reset the value to the default ? {c1 a get} 2 } nx::test case setter-under-coloncmd-and-interpvarresolver { # There are (at least) three forms of object-namespace alignment in # NSF: # 1. Same-named namespace (::omon) predates a same-named object # (::omon), the namespace is registered as per-object namespace with # the object upon object construction -> no NsColonVarResolver(), # InterpColonVarResolver() is responsible! # 2. an explicit per-object namespace creation using [:require # namespace] -> NsColonVarResolver() is put in place! # 3. nx::Object get per-object members (fields, methods) -> # NsColonVarResolver() is put in place! # # The following test covers scenario 1: Called from within # NsfSetterMethod(), SetInstVar() verifies, whether there is a # per-object namespace (objPtr->nsPtr); if so, TCL_NAMESPACE_ONLY is # set ... in this object/ns alignment scenario, # InterpColonVarResolver() (!) serves the var resolution request. It # effectively forward-passes the resolution request when sensing # TCL_NAMESPACE_ONLY by signalling TCL_CONTINUE. This is a consequence # of handling the "compiled [variable] vs. AVOID_RESOLVERS" case # InterpColonVarResolver(). As in colon-prefixed calls to the setter # method (via ColonCmd()), the colon prefix is present in the # name-carrying Tcl_Obj used to in SetInstVar(). As we set an object # frame context, we effectively end up with a colon-prefixed object # variable :( nx::Class create Omon ::nsf::method::setter Omon a1 namespace eval omon {} Omon create omon omon a1 "" ? {omon info vars a1} "a1" ? {omon info vars :a1} "" omon eval { :a1 "" ? [list [current] info vars a1] "a1" # Prior to the fix, [:info vars] would have returned ":a1" ? [list [current] info vars :a1] "" } } # # test required configure parameter # nx::test case req-param { ::nx::Class create C { :property y:required :property x:required :method init args {set ::_ "passed args '$args'"} } set ::_ "" ? {C create c2 -y 1 -x} {value for parameter '-x' expected} # Was the constructor called? Should not. ? {set ::_} "" # Did the object survive the error? Should not. ? {::nsf::is object c2} 0 set ::_ "" ? {C create c2} \ "required argument 'x' is missing, should be: ::c2 configure -x /value/ -y /value/ ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?" # Was the constructor called? Should not. ? {set ::_} "" # Did the object survive the error? Should not. ? {::nsf::is object c2} 0 # The following should run through without errors ? {C create c3 -y 1 -x 0} "::c3" ? {set ::_} "passed args ''" ? {c3 cget -x} "0" # # incremental property adding vs. required # nx::Class create D ? {D create d1} ::d1 ? {d1 configure} "" D property x:required ? {d1 info lookup syntax configure} \ "-x /value/ ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?" ? {d1 configure} \ "required argument 'x' is missing, should be: ::d1 configure -x /value/ ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?" ? {d1 configure -x 123} "" ? {d1 cget -x} 123 ? {d1 configure} "" } ::nsf::configure checkarguments on # # Test type any (or other typechecker) in combination with # substdefault via object parameter # nx::test case nsf-subdefault { nx::Class create C { :property {n1:substdefault "[namespace tail [::nsf::self]]"} :property {n2:substdefault,any "[namespace tail [::nsf::self]]"} :create c1 } ? {c1 cget -n1} c1 ? {c1 cget -n2} c1 } # # Test argument processing and namespace handling in nsf::procs # nx::test case nsf-proc { # # test inner namespace and handling of switches # nsf::proc ::nsf::mix {-per-object:switch -x:boolean} { return [namespace current]-${per-object}-[expr {[info exists x] ? $x : "NULL"}] } # # test handling of "-ad" flag # nsf::proc -ad ad_returnredirect { {-message {}} {-html:boolean} {-allow_complete_url:boolean} {-x:switch} target_url } { return [namespace current]-[lsort [info vars]]-$html_p-$allow_complete_url_p } # # test inner namespace and flag passing via -flag=$value notation # namespace eval ::ns1 { nsf::proc -ad foo {-s:boolean} {return [namespace current]-$s_p} nsf::proc bar {-s:switch} {return [namespace current]-[info exists s]} nsf::proc baz {-b:boolean arg} {return [namespace current]-[info exists b]-$arg} nsf::proc -ad pass0 {-s:boolean} {foo {*}[expr {$s_p ? "-s" : ""}]} nsf::proc -ad pass1 {-s:boolean} {foo -s=$s_p} } nx::test configure -count 1 ? {::nsf::mix} "::nsf-0-NULL" ? {::nsf::mix -per-object} "::nsf-1-NULL" ? {::nsf::mix -x true} "::nsf-0-true" ? {::nsf::mix -x false} "::nsf-0-false" ? {::nsf::mix -per-object=1} "::nsf-1-NULL" ? {::nsf::mix -per-object=0} "::nsf-0-NULL" ? {ad_returnredirect /url} "::-allow_complete_url_p html_p message target_url x-0-0" ? {ad_returnredirect -html /url} "::-allow_complete_url_p html_p message target_url x-1-0" ? {ad_returnredirect -html=0 /url} "::-allow_complete_url_p html_p message target_url x-0-0" ? {ad_returnredirect -html=a /url} {expected boolean but got "a" for parameter "-html"} ? {::ns1::foo} "::ns1-0" ? {::ns1::foo -s} "::ns1-1" ? {::ns1::foo -s=1} "::ns1-1" ? {::ns1::foo -s=0} "::ns1-0" ? {::ns1::foo -s -s=0} "::ns1-0" ? {::ns1::baz -b true -- -b} "::ns1-1--b" ? {info body ad_returnredirect} {::nsf::__unset_unknown_args return [namespace current]-[lsort [info vars]]-$html_p-$allow_complete_url_p } nx::test configure -count 1000 ? {::ns1::pass1} "::ns1-0" ? {::ns1::pass1 -s} "::ns1-1" ? {::ns1::pass0} "::ns1-0" ? {::ns1::pass0 -s} "::ns1-1" } # # Test argument processing and namespace handling in nsf::procs # nx::test case xotcl-list-notation { nx::test configure -count 1 package prefer latest package req XOTcl 2.0 xotcl::Class create CC -parameter {package_id parameter_declaration user_id} # first, without list notation ? {CC create cc -package_id 123 -parameter_declaration o -user_id 4} "::cc" ? {cc package_id} 123 ? {cc parameter_declaration} o ? {cc user_id} 4 # new with list notation ? {CC create cc -package_id 234 [list -parameter_declaration oo] -user_id 456} ::cc ? {cc package_id} 234 ? {cc parameter_declaration} oo ? {cc user_id} 456 xotcl::Class create KK -parameter {a b c d} # new with (alternative) list notation ? {KK create kk "-a\r234" "-b\n456" "-c\f543" "-d\nddd"} ::kk ? {kk a} 234 ? {kk b} 456 ? {kk c} 543 ? {kk d} ddd } # # Test parameter alias and parameter forwarder # nx::test case parameter-alias { nx::Class create C { :property {x:alias} :property {A:alias,method=bar} :property {{F:forward,method=%self foo %1 a b c %method}} :property {D def} :public method x args {set :x $args} :public method foo args {set :foo $args} :public method bar args {set :bar $args} :create c1 -F 123 -x x1 -A aha } ? {c1 eval {set :x}} "x1" ? {c1 eval {set :foo}} "123 a b c F" ? {c1 eval {set :bar}} "aha" ? {lsort [c1 info lookup methods -source application]} "bar foo x" } # # Test parameter alias and parameter forwarder with default value # nx::test case parameter-alias-default { nx::Class create C { :property {x1:alias "hugo"} :property {{F:forward,method=%self foo a %1 b c %method} "habicht"} :property {x2:alias,substdefault "[self]"} :public method x1 args {set :x1 $args} :public method x2 args {set :x2 $args} :public method foo args {set :foo $args} :create c1 } ? {c1 eval {set :x1}} "hugo" ? {c1 eval {set :foo}} "a habicht b c F" ? {c1 eval {set :x2}} "::c1" ? {lsort [c1 info lookup methods -source application]} "foo x1 x2" ? {lsort [C info slots]} "::C::slot::F ::C::slot::x1 ::C::slot::x2" ? {::C::slot::x1 getParameterSpec} {-x1:alias hugo} ? {::C::slot::x2 getParameterSpec} {-x2:alias,substdefault {[self]}} } # # Test interactions between per-object-mixins and objectparameters # (case without per-object property) # nx::test case parameter-object-mixin-dependency { nx::Class create C { :property a1 :create c1 } nx::Class create D -superclass C nx::Class create M1 {:property b1:required} nx::Class create M2 {:property b2:required} ? {c1 eval :__object_configureparameter} "-a1 $::trailer" c1 object mixins set M1 ? {c1 info precedence} "::M1 ::C ::nx::Object" ? {c1 eval :__object_configureparameter} "-b1:required -a1 $::trailer" # # Invalidate the object parameter and expect that the per-class # mixin does not harm # ::nsf::parameter::cache::classinvalidate C # # We have now "-b1:required" in the configure parameters. # # NSF checks, if the associated variable is already set, but # this does not work for aliases.... we could track whether or # not a required parameter was already provided, but that # requires most likely a more general handling. # ? {c1 configure -a1 x} \ "required argument 'b1' is missing, should be: ::c1 configure -b1 /value/ ?-a1 /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?" # # The object parameter based on the per-object-mixins must not be # stored in the class based cache. Therefore, creating a new object # must not require b1 ? {C create c2} ::c2 # # the same should hold for subclasses # ? {D create d1} ::d1 # # we have now per-object mixin of M1, we should have "-b1" but no # "-b2" # ? {c1 info object mixins} ::M1 ? {c1 cget -object-mixin} ::M1 ? {c1 info lookup parameters configure b*} "-b1:required" # # add one more mixin. # c1 object mixins add ::M2 ? {c1 info object mixins} {::M2 ::M1} ? {c1 cget -object-mixin} {::M2 ::M1} ? {c1 info lookup parameters configure b1} "-b1:required" ? {c1 info lookup parameters configure b2} "-b2:required" ? {lsort [c1 info lookup parameters configure b*]} "-b1:required -b2:required" # # drop the mixins, the b* properties should be gone. # c1 object mixins set "" ? {c1 info object mixins} {} ? {lsort [c1 info lookup parameters configure b*]} "" # # add M1 again # c1 object mixins add ::M1 ? {c1 info object mixins} {::M1} ? {c1 info lookup parameters configure b1} "-b1:required" ? {lsort [c1 info lookup parameters configure b*]} "-b1:required" # # We have the per-object cache; adding a per-object property should # flush the cache # c1 object property bo1 ? {lsort [c1 info lookup parameters configure b*]} "-b1:required -bo1" c1 object property bo2 ? {lsort [c1 info lookup parameters configure b*]} "-b1:required -bo1 -bo2" # # property deletion should invalidate the cache as well # c1 delete object property bo2 ? {lsort [c1 info lookup parameters configure b*]} "-b1:required -bo1" } # # Test interactions between per-object-mixins and objectparameters # (case with per-object property) # nx::test case parameter-object-mixin-dependency-object-property { nx::Class create C { :property a1 :create c1 { :object property a2 } } nx::Class create D -superclass C nx::Class create M {:property b1:required} c1 object mixins set M ? {c1 info precedence} "::M ::C ::nx::Object" ? {lsort [C info slots -closure]} \ "::C::slot::a1 ::nx::Object::slot::__initblock ::nx::Object::slot::class ::nx::Object::slot::object-filters ::nx::Object::slot::object-mixins" ? {c1 eval :__object_configureparameter} \ "-a2 -b1:required -a1 $::trailer" # # invalidate object parameter and expect that the per-class mixin # does not harm # ::nsf::parameter::cache::classinvalidate C ? {c1 __configure -a1 x} \ "required argument 'b1' is missing, should be: ::c1 configure ?-a2 /value/? -b1 /value/ ?-a1 /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?" ? {c1 info precedence} "::M ::C ::nx::Object" ? {lsort [C info slots -closure]} \ "::C::slot::a1 ::nx::Object::slot::__initblock ::nx::Object::slot::class ::nx::Object::slot::object-filters ::nx::Object::slot::object-mixins" ? {c1 eval :__object_configureparameter} "-a2 -b1:required -a1 $::trailer" # should not require b1 ? {C create c2} ::c2 } # # Test integer, wideinteger and bignums # nx::test configure -count 1000 nx::test case bignums { ::nx::Object create o { :public object method foo {x:int} { return $x } :public object method foo32 {x:int32} { return $x } :public object method bar {x:wideinteger} { return $x } :public object method baz {x:double} { return $x } } if {![string is integer [expr {2 ** 32}]]} { # # pre TIP 514 (< 8.7a2) # see https://core.tcl-lang.org/tips/doc/trunk/tip/514.md # # # In Tcl 8.5, "integer" means 32 bit integer # ? [list string is integer [expr {2 ** 31}]] 1 ? [list string is integer [expr {2 ** 32}]] 0 ? {o foo [expr {2 ** 16}]} "65536" ? {o foo [expr {2 ** 31}]} "2147483648" #? {o foo [expr {2 ** 32}]} {expected integer but got "4294967296" for parameter "x"} ? {o foo [expr {2 ** 32}]} "4294967296" ? [list string is integer [expr {2 ** 63}]] 0 ? [list string is integer [expr {2 ** 64}]] 0 #? {o foo [expr {2 ** 63}]} {expected integer but got "9223372036854775808" for parameter "x"} #? {o foo [expr {2 ** 64}]} {expected integer but got "18446744073709551616" for parameter "x"} ? {o foo [expr {2 ** 63}]} "9223372036854775808" ? {o foo [expr {2 ** 64}]} "18446744073709551616" ? {o foo [expr {2 ** 128}]} "340282366920938463463374607431768211456" ? {o foo [expr {wide(2 ** 63)}]} "-9223372036854775808" ? {o foo [expr {2.0}]} {expected integer but got "2.0" for parameter "x"} ? {o foo [expr {2.0 * 2}]} {expected integer but got "4.0" for parameter "x"} # # Note: In Tcl version less or equal 8.5.9 (to be precise, before # fossil check-in 769801ace1) there is a rounding issue for # doubles. It can be worked around by setting the tcl precision # level sufficiently high (see below). With check-in 769801ace1, or # with the 8.5.10 release version of Tcl, this work-around becomes # obsolete. # if {[::package vcompare [::info patchlevel] 8.5.9] < 1} { set ::nsf::savedTclPrecision $::tcl_precision set ::tcl_precision 17 } ? {o foo [expr {2.0 ** 128}]} {expected integer but got "3.4028236692093846e+38" for parameter "x"} ? {o foo [expr {(2 ** 128)*1.0}]} {expected integer but got "3.4028236692093846e+38" for parameter "x"} if {[info exists ::nsf::savedTclPrecision]} { set ::tcl_precision $::nsf::savedTclPrecision unset ::nsf::savedTclPrecision } ? {o foo32 [expr {2 ** 31}]} "2147483648" ? {o foo32 [expr {2 ** 32}]} {expected int32 but got "4294967296" for parameter "x"} # # In Tcl 8.5, "wideinteger" means 64 bit integer # ? [list string is wideinteger [expr {2 ** 63}]] 1 ? [list string is wideinteger [expr {2 ** 64}]] 0 ? {o bar [expr {2 ** 63}]} "9223372036854775808" ? {o bar [expr {2 ** 64}]} {expected wideinteger but got "18446744073709551616" for parameter "x"} ? [list string is wideinteger [expr {wide(2 ** 64)}]] 1 ? {o bar [expr {wide(2 ** 63)}]} "-9223372036854775808" ? {o bar [expr {wide(2 ** 64)}]} "0" # # In Tcl 8.5, "bignums" have to be checked with "double" # ? [list string is double [expr {2 ** 63}]] 1 ? [list string is double [expr {2 ** 64}]] 1 ? {o baz [expr {2 ** 63}]} "9223372036854775808" ? {o baz [expr {2 ** 64}]} "18446744073709551616" ? {o baz [expr {2 ** 128}]} "340282366920938463463374607431768211456" } else { # # post TIP 514 (>= 8.7a2) # see https://core.tcl-lang.org/tips/doc/trunk/tip/514.md # # [string is integer] is now equivalent to [string is entier], and # does not perform any representational range checks anymore. # # # [string is integer] means arbitrary-bit integers (equiv. to entier) # ? [list string is integer [expr {2 ** 31}]] 1 ? [list string is integer [expr {2 ** 32}]] 1 ? [list nsf::is int32 [expr {2 ** 32}]] 0 ? [list nsf::is int32 [expr {2 ** 32 - 1}]] 1 ? {o foo [expr {2 ** 16}]} "65536" ? {o foo [expr {2 ** 31}]} "2147483648" ? {o foo [expr {2 ** 32}]} "4294967296" ? [list string is integer [expr {2 ** 63 - 1}]] 1 ? [list string is integer [expr {2 ** 64}]] 1 ? [list nsf::is int32 [expr {2 ** 63 - 1}]] 0 ? {o foo [expr {2 ** 63}]} "9223372036854775808" ? {o foo [expr {2 ** 64}]} "18446744073709551616" ? {o foo [expr {2 ** 128}]} "340282366920938463463374607431768211456" ? {o foo [expr {wide(2 ** 63)}]} "-9223372036854775808" ? {o foo [expr {2.0}]} {expected integer but got "2.0" for parameter "x"} ? {o foo [expr {2.0 * 2}]} {expected integer but got "4.0" for parameter "x"} ? {o foo [expr {2.0 ** 128}]} {expected integer but got "3.4028236692093846e+38" for parameter "x"} ? {o foo [expr {(2 ** 128)*1.0}]} {expected integer but got "3.4028236692093846e+38" for parameter "x"} ? {o foo32 [expr {2 ** 31}]} "2147483648" ? {o foo32 [expr {2 ** 32}]} {expected int32 but got "4294967296" for parameter "x"} # [string is wide] is now more picky about the upper 64-bit int bound: 2^63-1, and not 2^63 ? [list string is wideinteger [expr {2 ** 63 - 1}]] 1 ? [list string is wideinteger [expr {2 ** 63}]] 0 ? {o bar [expr {2 ** 63 - 1}]} "9223372036854775807" ? {o bar [expr {2 ** 64}]} {expected wideinteger but got "18446744073709551616" for parameter "x"} ? [list string is wideinteger [expr {wide(2 ** 64)}]] 1 ? {o bar [expr {wide(2 ** 63)}]} "-9223372036854775808" ? {o bar [expr {wide(2 ** 64)}]} "0" # # [string is integer] will accept arbitrarily sized numeric # strings (no range check) # ? [list string is int [expr {2 ** 63}]] 1 ? [list string is int [expr {2 ** 64}]] 1 ? {o baz [expr {2 ** 63}]} "9223372036854775808" ? {o baz [expr {2 ** 64}]} "18446744073709551616" ? {o baz [expr {2 ** 128}]} "340282366920938463463374607431768211456" # # [string is double] will accept arbitrarily sized doubles (no # range check) # ? [list string is double [expr {2 ** 63 * 0.1}]] 1 ? [list string is double [expr {2 ** 64 * 0.1}]] 1 ? {o baz [expr {2 ** 63 * 0.1}]} "9.223372036854776e+17" ? {o baz [expr {2 ** 64 * 0.1}]} "1.8446744073709553e+18" ? {o baz [expr {2 ** 128 * 0.1}]} "3.402823669209385e+37" } } nx::test case reconfigure-perobj-default { nx::Object create o ? {o eval {info exists :a}} 0 o object property {a oldvalue} ? {o eval {info exists :a}} 1 ? {o cget -a} oldvalue # # By unsetting the var, upon recreating the property slot (or # calling reconfigure upon the property) we can trigger # a re-assignment of the default value. # o eval {unset :a} ? {o eval {info exists :a}} 0 # # re-assignment of the default is handled by init # o object property {a newvalue} ? {o eval {info exists :a}} 1 ? {o cget -a} newvalue o eval {unset :a} ? {o eval {info exists :a}} 0 [o info object slots a] configure -default anothervalue ? {o eval {info exists :a}} 0 # # re-assignment must be requested by a reconfigure call # [o info object slots a] reconfigure ? {o eval {info exists :a}} 1 ? {o cget -a} anothervalue } # # nx::Object parameters (specified e.g. via attributes) are defined to # configure fresh objects (therefore, the definition is on the class # level). Therefore, object-level object parameter do not fulfill # this purpose, since they can only be defined, *after* the object # is created. # # In general, object parameters have creational aspects (providing # configurations for the object creation, such as e.g. defaults, and # configurations) and object-lifetime aspects (valid through the # lifetime of objects, such as e.g. setters/checkers). # # nx::Object-level attributes cannot be used for the creational aspects # of object parameters. # # Strengths of object-level parameters: # - same interface as class-level attributes # - can use same meta-data mechanisms as for class-level attributes # (e.g. database types, property name in the database, persistence # information, ...) # - can use same setters/checkers as for class-level attributes # - can use as well incremental as for class-level attributes # # Shortcomings of object-level parameters: # - no nice introspection: # "info parameter ...." is defined on cls, not on obj # - default handling is not the same as for classes level attributes # (we have already some special mechanisms to set instance # attributes, if they do not exist) # - object-level parameters cannot be used in a "configure" # of the object, since configure allows the same signature # as on object creation, all object parameters are cached # on the class level # - Since configure does not include object-level parameters, # positional object level parameters do not make sense, since they # cannot be called. # # test object level property and variable # nx::test case object-level-variable { nx::Object create ::enterprise { # just to get a reference value for the timing ? [list [self] eval {set :dummy 1}] "1" # set 2 variables, one via variable, one via property ? [list [self] object variable -nocomplain captain1 "James Kirk"] "" ? [list [self] object property -nocomplain [list captain2 "Jean Luc"]] "" # in both cases, we expect instance variables ? [list [self] eval {set :captain1}] "James Kirk" ? [list [self] eval {set :captain2}] "Jean Luc" # just for the property, we have accessors ? [list [self] info lookup method captain1] "" ? [list [self] info lookup method captain2] "" # set variable with a value checker ? [list [self] object variable -nocomplain x1:int 1] "" ? [list [self] object property -nocomplain [list x2:int 2]] "" # set variable with a value checker and an invalid value ? [list [self] object variable y1:int a] {expected integer but got "a"} ? [list [self] object property [list y2:int b]] {expected integer but got "b" for parameter "y2"} # set variable again, without -nocomplain ? [list [self] object variable x1:int 1] {object ::enterprise has already an instance variable named 'x1'} ? [list [self] object property [list x2:int 2]] {object ::enterprise has already an instance variable named 'x2'} # set variable with a value checker, multiple ? [list [self] object variable -nocomplain xm1:int,1..n {1 2 3}] "" ? [list [self] object property -nocomplain [list xm2:int,1..n {1 2 3}]] "" # in both cases, we expect instance variables ? [list [self] eval {set :xm1}] "1 2 3" ? [list [self] eval {set :xm2}] "1 2 3" # set variable with a value checker, multiple with invalid value ? [list [self] object variable -nocomplain xm1:int,1..n {1 2a 3}] \ {invalid value in "1 2a 3": expected integer but got "2a"} ? [list [self] object property -nocomplain [list xm2:int,1..n {1 2a 3}]] \ {invalid value in "1 2a 3": expected integer but got "2a" for parameter "xm2"} # useless definition ? [list [self] object variable dummy:int] \ {variable definition for 'dummy' (without value and accessor) is useless} # # define an application specific converter # ::nx::ObjectParameterSlot method type=range {name value arg} { lassign [split $arg -] min max if {$value < $min || $value > $max} { error "value '$value' of parameter $name not between $min and $max" } return $value } # # Test usage of application specific converter in "variable" and # "property"; invalid value ? [list [self] object variable -nocomplain r1:range,arg=1-10 11] \ {value '11' of parameter value not between 1 and 10} ? [list [self] object property -nocomplain [list r2:range,arg=1-10 11]] \ {value '11' of parameter r2 not between 1 and 10} # valid value ? [list [self] object variable -nocomplain r1:range,arg=1-10 5] "" ? [list [self] object property -nocomplain [list r2:range,arg=1-10 5]] "" # testing incremental ? [list [self] object variable -incremental -nocomplain i:int,0..* {}] "::enterprise::i" ? [list [self] object property -incremental -nocomplain j:int,0..* {}] "::enterprise::j" :i add 1 :j add 1 ? [list [self] i get] "1" ? [list [self] j get] "1" :i add 2 :j add 2 ? [list [self] i get] "2 1" ? [list [self] j get] "2 1" ? [list [self] i add a] {expected integer but got "a" for parameter "value"} ? [list [self] j add a] {expected integer but got "a" for parameter "value"} } nx::Class create C { # set 2 class variables, one via variable, one via property ? [list [self] object variable -nocomplain v "v0"] "" ? [list [self] object property -nocomplain [list a "a0"]] "" # in both cases, we expect instance variables ? [list [self] eval {set :v}] "v0" ? [list [self] eval {set :a}] "a0" # check variable with value constraint ? [list [self] object variable -nocomplain x:int "0"] "" ? [list [self] object variable -nocomplain y:int "a0"] {expected integer but got "a0"} } } # # test class level property and variable # nx::test case class-level-variable { nx::Class create C { # define 2 class-level variables, one via variable, one via property :variable v v0 :property -accessor public {a a0} # create an instance :create c1 } # in both cases, we expect instance variables for c1 ? {lsort [c1 info vars]} {a v} ? {c1 eval {set :v}} "v0" ? {c1 eval {set :a}} "a0" # # We expect a specifiable object parameter for "a" but not for "v". # The parameter for v can be obtained via spec, but is not listed in # "info parameter syntax" or "info parameter definitions". # # ? {C info parameter list a} "-a" ? {C info lookup parameters create a} "{-a a0}" # ? {C info lookup syntax create a} "?-a /value/?" ? {C info lookup syntax create} "/objectName/ ?-a /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?" ? {C info lookup parameters create v} "" ? {[C info slots v] definition} "::C variable -accessor none v v0" # ? {C info parameter list v} "" # ? {C info configure parameter v} "" ? {C create c2 -a 10} ::c2 ? {C create c2 -v 10} \ {invalid non-positional argument '-v', valid are: -a, -object-mixins, -object-filters, -class; should be "::c2 configure ?-a /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?"} # # We expect a setter for "a" but not for "v". # ? {c1 info lookup method a} "::nsf::classes::C::a" ? {c1 info lookup method v} "" } # # test classes with single variable definitions, and illegal names # nx::test case single-variable { ? {nx::Class create C { :variable v 1 :create c1 }} ::C ? {c1 info vars} v ? {nx::Class create D { :variable :v 1 }} {leading colon in ':v' not allowed in parameter specification 'spec'} } # # test deletion of class level property and variable # nx::test case delete-class-level-variable-and-property { nx::Class create C { # define 2 class-level variables, one via variable, one via property :variable v v0 :property -accessor public {a a0} # create an instance :create c1 } # the instance of C will have the two variables set ... ? {lsort [c1 info vars]} {a v} # ... and we expect an object parameter for a but not for v ... ? {C info lookup parameters create a} "{-a a0}" ? {C info lookup parameters create v} "" # ... and we expect a setter for a but not for v ? {c1 info lookup method a} "::nsf::classes::C::a" ? {c1 info lookup method v} "" # if we delete a class-level property or variable, # the object parameter and setters for "a" will be gone C delete variable v C delete property a ? {C info lookup parameters create a} "" ? {c1 info lookup method a} "" # already created instance variables will continue to exist ? {lsort [c1 info vars]} {a v} # in newly created objects, neither a or v will exist ? {C create c2} ::c2 ? {lsort [c2 info vars]} {} } # # test deletion of class level property and variable # nx::test case delete-object-level-variable-and-property { nx::Object create o { # define 2 object-level variables, one via variable, one via property :object variable v v0 :object property -accessor public {a a0} } # the instance of C will have the two variables set ... ? {lsort [o info vars]} {a v} # ... and we expect a setter for a but not for v ? {o info lookup method a} "::o::a" ? {o info lookup method v} "" # nx::Object-level attributes and variables set und unset instance # variables. If we delete an object-level property or variable, # the setters for "a" will be unset. o delete object variable v o delete object property a ? {o info lookup method a} "" # Both instance variables are unset ? {lsort [o info vars]} {} } # # Testing object parameters of type "switch" # nx::test case object-parameter-switch { # Create a class with a property of type switch and an instance of # the class ? {::nx::Class create C { :property -accessor public foo:switch :create c1 }} "::C" # When the object parameter is not specified at creation time, the # default is false, an instance variable is set with this value ? {lsort [c1 info vars]} {foo} ? {c1 eval {set :foo}} {0} # nx::Object parameter of type "switch" are more tricky, since e.g. a # setter with 0 arguments is a getter. When a setter is built, it # uses the parameter type "boolean" instead. ? {C info methods} "foo" ? {c1 info lookup method foo} "::nsf::classes::C::foo" ? {c1 foo get} 0 ? {c1 foo set 1} 1 ? {c1 foo get} 1 # When the object parameter is specified, the instance variable has # a value of true (i.e. 1) C create c2 -foo ? {lsort [c2 info vars]} {foo} ? {c2 eval {set :foo}} {1} ? {c1 foo get} 1 # One can pass false (and other values) with the = notation as well C create c3 -foo=false ? {lsort [c3 info vars]} {foo} ? {c3 eval {set :foo}} {false} # In the inverted case, the switch has a default of "true". If the # switch is specified, the valus is "false" C property {foo2:switch 1} C create c4 ? {lsort [c4 info vars]} {foo foo2} ? {c4 eval {set :foo2}} {1} C create c5 -foo2 ? {lsort [c5 info vars]} {foo foo2} ? {c5 eval {set :foo2}} {0} # nx::Object case: variables of type "switch" are like variables of type # boolean, except that without the specified value argument # (variable foo below), it sets the variable to "false". ? {::nx::Object create o1 { :object variable foo:switch :object variable bar:switch 1 }} ::o1 ? {o1 eval {set :foo}} 0 "check value of switch variable without default" ? {o1 eval {set :bar}} 1 "check value of switch variable with default" } # # Test slots with configparameter true/false, accessor true/false # against "slot definitions" and "info parameter" # nx::test case class-info-slots-types { # # "/cls/ info slot ..." shows all slots, including variables # "/cls/ info parameter ..." shows the parameter available for object parameterization # nx::Class create C { # variable has no configure parameter and no accessor :variable v 100 } # "v" does NOT show up in "info configure parameters" ? {C info lookup parameters create v} "" # ? {C info parameter names} "noinit object-mixin class object-filter __initblock" # "v" does show up in "info slot ..." ? {C info slots} "::C::slot::v" ? {::C::slot::v definition} "::C variable -accessor none v 100" nx::Class create D { :property -accessor public {p0 200} :property -accessor none {p1 201} :property -accessor none {p2:noconfig 202} :property -accessor public {p3:noconfig 203} } # "p2" and "p3" do NOT show up in "info parameter" ? {D info lookup parameters create p*} "{-p0 200} {-p1 201}" # "p1" and "p2" do NOT show up in "info methods" ? {D info methods} "p0 p3" # all properties show up in "info slot" ? {D info slots} "::D::slot::p0 ::D::slot::p1 ::D::slot::p2 ::D::slot::p3" #? {D info slot definitions} "{::D property {p0 200}} {::D property -accessor none {p1 201}} {::D variable p2 202} {::D variable -accessor public p3 203}" #? {D info properties} "{p0 200} {p1 201} {p2:noconfig 202} {p3:noconfig 203}" } nx::test case object-info-slots-types { # # "/obj/ info slot ..." shows all slots, including variables # nx::Object create o1 { # plain object variable has no slot object :object variable v0 100 # In case we require an accessor or e.g. incremental, slot objects # are created; incremental implies accessor :object variable -accessor public v1 100 :object variable -incremental v2 100 } # only the variables with slots show up in "info slot ..." ? {o1 info object slots} "::o1::per-object-slot::v2 ::o1::per-object-slot::v1" ? {::o1::per-object-slot::v2 definition} "::o1 object variable -accessor public v2:1..n 100" ? {::o1::per-object-slot::v1 definition} "::o1 object variable -accessor public v1 100" nx::Object create o2 { :object property -accessor public {p0 200} :object property -accessor none {p1 201} :object property -accessor none {p2:noconfig 202} :object property -accessor public {p3:noconfig 203} } # "p1" and "p2" do NOT show up in "info methods" ? {o2 info object methods} "p0 p3" # all properties with slots show up in "info slot" ? {o2 info object slots} "::o2::per-object-slot::p0 ::o2::per-object-slot::p1 ::o2::per-object-slot::p3" ? {[o2 info object slots p0] definition} "::o2 object property -accessor public {p0 200}" ? {[o2 info object slots p1] definition} "::o2 object property -accessor none {p1 201}" ? {[o2 info object slots p3] definition} "::o2 object variable -accessor public p3 203" #? {o2 info properties} "{p0 200} {p1 201} {p3:noconfig 203}" } nx::test case noconfig-switch-interaction { catch {nx::Object new { :object property x:switch,noconfig; :configure -x=1}} msg opts ? [list string match "invalid non-positional argument '-x=1',*" [dict get $opts -errorinfo]] 1 catch {nx::Class new { :property y:switch,noconfig; :new -y=1}} msg opts ? [list string match "invalid non-positional argument '-y=1',*" [dict get $opts -errorinfo]] 1 } # # testing method properties # nx::test case properties { # simple properties #nx::Class create Foo -properties {a {b 1}} nx::Class create Foo { :property a :property {b 1} } ? {[Foo info slots a] definition} "::Foo property -accessor none a" ? {[Foo info slots b] definition} "::Foo property -accessor none {b 1}" #? {Foo info properties} "a {b 1}" # properties with value checker nx::Class create Foo { :property a:boolean :property {b:integer 1} } ? {[Foo info slots a] definition} "::Foo property -accessor none a:boolean" ? {[Foo info slots b] definition} "::Foo property -accessor none {b:integer 1}" # required/optional properties nx::Class create Foo { :property a:required :property b:boolean,required } ? {[Foo info slots a] definition} "::Foo property -accessor none a:required" ? {[Foo info slots b] definition} "::Foo property -accessor none b:boolean,required" # properties with multiplicity nx::Class create Foo { :property {ints:integer,0..n ""} :property objs:object,1..n :property obj:object,0..1 } ? {[Foo info slots objs] definition} "::Foo property -accessor none objs:object,1..n" ? {[Foo info slots ints] definition} "::Foo property -accessor none {ints:integer,0..n {}}" ? {[Foo info slots obj] definition} "::Foo property -accessor none obj:object,0..1" } # # The following test case sets a value of an instance variable via a # side-effect of an aliased parameter. Side-effects from aliased # parameters are discouraged, since the order of the evaluation should # not matter of a declarative evaluation of the argument vector. # # Note that the order, in which is the arguments are provided is not # significant for the evaluation order. # nx::test case side-effect-set-value { nx::Class create C { :public object method setObjectParams {spec} { :protected method __object_configureparameter {} [list return $spec] ::nsf::parameter::cache::classinvalidate [self] } :setObjectParams "" } C method second {arg} { set :first $arg } C setObjectParams {{-first "X"} -second:alias} ? {[C new -second Y] eval {set :first}} Y "side-effect overwrites default" C setObjectParams {-second:alias {-first "X"}} ? {[C new -second Y] eval {set :first}} Y "side-effect determines value" } nx::test case xotcl-configure-method { nx::test configure -count 1 package prefer latest package req XOTcl 2.0 # # attempt dispatch to unknown method # xotcl::Object create o ? {o configure -order 15} "::o: unable to dispatch method 'order' during '::o.order'" } # # Test forwarding to slot object, when set is overloaded # nx::test case forward-to-set { set ::slotcalls 0 nx::Class create Foo { :property -accessor public bar { :public object method value=set { object property value } { incr ::slotcalls 1 nsf::var::set $object $property $value } } } # call without default, without object parameter value set o [Foo new] ? [list $o eval {info exists :bar}] 0 ? {set ::slotcalls} 0 ? [list $o bar get] {can't read "bar": no such variable} # call without default, with object parameter value set o [Foo new -bar "test"] ? [list $o eval {info exists :bar}] 1 ? {set ::slotcalls} 1 ? [list $o bar get] "test" # test cases for default set ::slotcalls 0 nx::Class create Foo { :property -accessor public {baz 1} { :public object method value=set { object property value } { incr ::slotcalls 1 nsf::var::set $object $property $value } } } # call with default, without object parameter value set o [Foo new] ? [list $o eval {info exists :baz}] 1 ? {set ::slotcalls} 1 "baz without object parameter value" ? [list $o baz get] "1" # call with default, with object parameter value set o [Foo new -baz "test"] ? [list $o eval {info exists :baz}] 1 ? {set ::slotcalls} 2 "baz with object parameter value" ? [list $o baz get] "test" ? {Foo info method exists baz} 1 } # # Test forwarding to slot vs. accessor none # nx::test case forward-to-set2 { set ::slotcalls 0 ? {nx::Class create Foo { :property -accessor none bar { :public object method value=set { object property value } { incr ::slotcalls 1 nsf::var::set $object $property $value } }} } "::Foo" # call without default, without object parameter value ? {catch {Foo new}} 0 ? {set ::slotcalls} 0 # test cases for default nx::Class create Foo { :property -accessor none {baz 1} { :public object method value=set { object property value } { incr ::slotcalls 1 nsf::var::set $object $property $value } } } # call with default, without object parameter value ? {catch {Foo new}} 0 ? {set ::slotcalls} 1 # call with default, with object parameter value ? {catch {Foo new -baz "test"}} 0 ? {set ::slotcalls} 2 ? {Foo info method exists baz} 0 } # # Test slot initialize # nx::test case forward-to-incremental { set ::slotcalls 0 ? {nx::Class create Foo { :property bar { :public object method initialize { object property } { incr ::slotcalls 1 } }} } "::Foo" # initialize is supposed to be called regardless of some default ? {catch {Foo new}} 0 ? {set ::slotcalls} 1 } # # Test interaction of name of property with the Tcl command behavior. # Without the SlotContainerCmdResolver() the call to "list" in a # property named "list" leads to a call to the container object # ::Test2::slot::list instead of the intended ::list. # nx::test case slot-container-name-interaction { nx::Class create Test2 { :property -accessor public list { :public object method value=set { obj var val } { nsf::var::set $obj $var [list $obj $var $val] } :object method unknown { val obj var args } { return unknown } } } ? {Test2 create t2} ::t2 ? {t2 list set 3} {::t2 list 3} ? {t2 list get} {::t2 list 3} ? {t2 list this should call unknown} "unknown" } nx::test case object-level-defaults { # # In the scenario below, setCheckedInstVar is executed and performs # an ::nsf::is value check on the default value. However, given the # custom set method, the parameter option slotset is passed on # to ::nsf::is which (currently) does not accept it: # # 'invalid value constraints # "slot=::objekt::per-object-slot::a,slotset"' # nx::Object create o ? {o eval {info exists :a}} 0 ? {catch { o object variable -accessor public -initblock { :public object method value=set args { incr :assignCalled next } } a 1}} 0 ? {o eval {info exists :a}} 1 ? {o eval {info exists :assignCalled}} 0; # !!! should be 1 ? {o a get} 1 } nx::test case cmd-error-propagation { ? {nx::Object new { error "bow-wow" }} "bow-wow" ? {nx::Object new { :object method foo {} { error "bow-wow" } :foo }} "bow-wow" ? {nx::Object new { # Note: Creating a slot causes a destroy() to perform some cascading # operations which eventually reset the interp result at some # point. :object property x :object method foo {} { error "bow-wow" } :foo }} "bow-wow" ? {nx::Object new { :object method destroy {} { # This (inner) error message is swallowed and written to stderr # directly. The original (outer) error message is preserved. error "BOW-WOW" } :object method foo {} { error "bow-wow" } :foo }} "bow-wow" } # # test argument processing in nsf::proc with checkalways # nx::test case nsf-proc-checkalways { # # one proc with checkalways # nsf::proc p1 {-x:integer} { return $x} nsf::proc -checkalways p2 {-x:integer} { return $x} ? {p1 -x 100} 100 ? {p1 -x a100} {expected integer but got "a100" for parameter "-x"} ? {p2 -x 100} 100 ? {p2 -x a100} {expected integer but got "a100" for parameter "-x"} nsf::configure checkarguments off ? {p1 -x a100} a100 ? {p2 -x a100} {expected integer but got "a100" for parameter "-x"} nsf::configure checkarguments on } # # test argument processing in methods with checkalways # nx::test case nsf-method-checkalways { # # one method with checkalways # nx::Class create C { :public method m1 {-x:integer} { return $x} :public method m2 {-x:integer} -checkalways { return $x} :public object method om1 {-x:integer} { return $x} :public object method om2 {-x:integer} -checkalways { return $x} :create c1 } ? {c1 m1 -x 100} 100 ? {c1 m2 -x 100} 100 ? {c1 m1 -x a100} {expected integer but got "a100" for parameter "-x"} ? {c1 m2 -x a100} {expected integer but got "a100" for parameter "-x"} ? {C om1 -x 200} 200 ? {C om2 -x 200} 200 ? {C om1 -x a} {expected integer but got "a" for parameter "-x"} ? {C om2 -x a} {expected integer but got "a" for parameter "-x"} nsf::configure checkarguments off ? {c1 m1 -x a100} a100 ? {c1 m2 -x a100} {expected integer but got "a100" for parameter "-x"} ? {C om1 -x a} a ? {C om2 -x a} {expected integer but got "a" for parameter "-x"} nsf::configure checkarguments on } # # Test parameter::info with objects/classes and types # nx::test case parameter-get { nx::Class create C { :property foo:integer :property o:object,type=::nx::Object :property c:class :property m:metaclass } ? {C info lookup parameters create foo} "-foo:integer" ? {nsf::parameter::info type [C info lookup parameters create foo]} "integer" ? {C info lookup parameters create o} "-o:object,type=::nx::Object" ? {nsf::parameter::info type [C info lookup parameters create o]} "::nx::Object" ? {C info lookup parameters create c} "-c:class" ? {nsf::parameter::info type [C info lookup parameters create c]} "class" ? {C info lookup parameters create m} "-m:metaclass" ? {nsf::parameter::info type [C info lookup parameters create m]} "metaclass" } # # Test parameter passing on new (disambiguate between -childof as a # property and as a modifier) # nx::test case new-parameter-passing { nx::Class create C { :property childof } nx::Object create o proc isGlobalNew name {regexp {^::nsf::__#} $name} proc isONew name {regexp {^::o::__#} $name} ? {isGlobalNew [C new]} 1 ? {isONew [C new -childof o]} 1 ? {isGlobalNew [C new --]} 1 ? {isGlobalNew [C new -- -childof x]} 1 ? {isONew [C new -childof o -- -childof x]} 1 # # When the parameter is given twice, we get a warning, the second # one "wins" # ? {isONew [C new -childof o -childof xxx]} 0 # are the properties set correctly? set ::o1 [C new -childof o -- -childof x] ? {$::o1 cget -childof} x set ::o1 [C new -- -childof y] ? {$::o1 cget -childof} y } nx::test case value=changed { nx::Class create C { :property a { :public object method value=set {object property value} { incr ::slotset_$property nsf::var::set $object $property [expr {$value + 1}] } } :property -trace set b { :public object method value=set {object property value} { incr ::slotset_$property nsf::var::set -notrace $object $property [expr {$value + 1}] } } :property -accessor public -trace set c { :public object method value=set {object property value} { incr ::slotset_$property nsf::var::set -notrace $object $property [expr {$value + 1}] } } :public method foo {} { set :a 100 set :b 100 set :c 100 } } set ::slotset_a 0 set ::slotset_b 0 set ::slotset_c 0 ? {C create c1} ::c1 ? {set ::slotset_a} 0 ? {set ::slotset_b} 0 ? {set ::slotset_c} 0 c1 configure ? {set ::slotset_a} 0 ? {set ::slotset_b} 0 ? {set ::slotset_c} 0 c1 configure -a 1 -b 1 -c 1 ? {set ::slotset_a} 1 ? {set ::slotset_b} 1 ? {set ::slotset_c} 1 ? {c1 cget -a} 2 ? {c1 cget -b} 2 ? {c1 cget -c} 2 ? {c1 cget -a} 2 ? {c1 cget -b} 2 ? {c1 cget -c} 2 set ::slotset_a 0 set ::slotset_b 0 set ::slotset_c 0 c1 foo ? {set ::slotset_a} 0 ? {set ::slotset_b} 1 ? {set ::slotset_c} 1 ? {c1 cget -a} 100 ? {c1 cget -b} 101 ? {c1 cget -c} 101 set ::slotset_a 0 set ::slotset_b 0 set ::slotset_c 0 ? {c1 a set 200} {::c1: unable to dispatch method 'a'} ? {c1 b set 200} {::c1: unable to dispatch method 'b'} ? {c1 c set 200} 201 ? {set ::slotset_a} 0 ? {set ::slotset_b} 0 ? {set ::slotset_c} 1 } nx::test case trace-meta-slot { ::nx::MetaSlot create ::nsv::TraceVariableSlot -superclass ::nx::VariableSlot { :property {trace {get set}} :public method value=set {obj varName value} { incr ::trace_set #puts stderr "SET nsv_set $obj $varName $value" next } :public method value=get {obj varName} { incr ::trace_get #puts stderr "GET nsv_set $obj $varName" next } } set ::trace_set 0 set ::trace_get 0 nx::Class create Foo { :property -class ::nsv::TraceVariableSlot x :public method exists {var} { info exists :$var } :public method get {var} { set :$var } :public method foo {} { incr :x } :create ::f1 } # # Change the value of ::f1.x via configure # ? {set ::trace_set} 0 ? {set ::trace_get} 0 ? {::f1 configure -x "1"} "" ? {set ::trace_set} 2 ;# 2, since the next triggers the default setter, which has no "-notrace" ? {set ::trace_get} 0 ? {::f1 exists x} 1 ? {set ::trace_set} 2 ? {set ::trace_get} 1 ? {::f1 cget -x} "1" ? {set ::trace_set} 2 ? {set ::trace_get} 3 ;# 3, since the next triggers the default setter, which has no "-notrace" # # Change the value of ::f1.x via configure again # ? {::f1 configure -x 2} "" ? {::f1 cget -x} "2" # # Change the value of ::f1.x via variable changes # set ::trace_set 0 set ::trace_get 0 ? {::f1 foo} "3" ? {set ::trace_set} 1 ? {set ::trace_get} 1 ? {::f1 cget -x} "3" } # # test trace meta slot + default # nx::test case trace-meta-slot { ::nx::MetaSlot create ::nsv::TraceVariableSlot -superclass ::nx::VariableSlot { :property {trace {get set}} :public method value=set {obj varName value} { incr ::trace_set #puts stderr "SET nsv_set $obj $varName $value" next } :public method value=get {obj varName} { incr ::trace_get #puts stderr "GET nsv_set $obj $varName" next } } set ::trace_set 0 set ::trace_get 0 nx::Class create Foo { :property -class ::nsv::TraceVariableSlot {x 123} :property -class ::nsv::TraceVariableSlot {y 456} :public method exists {var} { info exists :$var } :public method vars {} { :info vars} :public method get {var} { set :$var } :public method foo {} { incr :x } :create ::f1 } # # State after creation # ? {set ::trace_set} 0 ? {set ::trace_get} 0 ? {lsort [::f1 vars]} "__initcmd x y" # # Change the value of ::f1.x via configure # ? {::f1 cget -x} "123" ? {set ::trace_set} 0 ? {set ::trace_get} 2 ;# since the next triggers the default setter, which has no "-notrace" set ::trace_set 0 set ::trace_get 0 # # Change the value of ::f1.x via configure # ? {::f1 configure -x 2} "" ? {set ::trace_set} 2 ;# since the next triggers the default setter, which has no "-notrace" ? {set ::trace_get} 0 ? {::f1 cget -x} "2" # # Change the value of ::f1.x via variable changes # set ::trace_set 0 set ::trace_get 0 ? {::f1 foo} "3" ? {set ::trace_set} 1 ? {set ::trace_get} 1 ? {::f1 cget -x} "3" } # # Testing nsf::parseargs # nx::test case parseargs { ? {nsf::parseargs {a:int} {1}; info exists a} "1" ? {nsf::parseargs {a:int} {1}; info exists b} "0" ? {nsf::parseargs {a:int} {a}} {expected integer but got "a" for parameter "a"} ? { nsf::parseargs {-foo:int {-bar:int 2} baz} {hi} list [info exists foo] [info exists bar] [info exists baz] } "0 1 1" ? { nsf::parseargs -asdict {-foo:int {-bar:int 2} baz} {hi} } "bar 2 baz hi" # # Test with empty list of actual arguments # ? {apply {{} {nsf::parseargs {} {}; llength [info vars]}}} 0 ? {apply {{} {nsf::parseargs {{x ""}} {}; info vars}}} x ? {apply {{} {nsf::parseargs {{x ""} {y ""}} {}; lsort [info vars]}}} {x y} ? {apply {{} {nsf::parseargs {{-a 1} {-b} {x ""} {y ""}} {}; lsort [info vars]}}} {a x y} ? {set bar} 2 ? {set baz} hi ? {apply {{} {nsf::parseargs a 1; info exists a}}} "1" ? {apply {{} {nsf::parseargs {a b} {1 2}; expr {[info exists a]+[info exists b]}}}} "2" ? {apply {{} {nsf::parseargs {a b args} {1 2 3 4}; expr {[info exists a]+[info exists b]+[info exists args]}}}} "3" ? {apply {{} {nsf::parseargs a 1; expr {"a" in [info vars]};}}} 1 # TODO: Are the below cases intended? #? {apply {{} {nsf::parseargs {a} {}; llength [info vars];}}} 0 #? {apply {{} {nsf::parseargs {} {1}; llength [info vars];}}} 0 } # # Testing name binding for type=/class/ converter # nx::test case type-converter-binding { # # Binding strategy: Unqualified names are qualified by the namespace # of the slot-owning object (domain). Resolution is lazy in the # sense that a qualified name is produced but not resolved upon slot # definition. # # set type [namespace qualifiers /obj/]::$type # # This has the same effect as (repeatedly) writing out # type=[namespace current]::$type, or similar, as part of a property # or variable spec. # namespace eval :: { namespace eval ns1 { namespace eval ns2 { nx::Class create A } nx::Class create A nx::Class create B { :property b1:object,type=A; # rewritten to ::ns1::A (not ::A as previously!). ? [list [:info slots b1] cget -type] ::ns1::A :property b2:object,type=ns2::A; # rewritten to ::ns1::ns2::A (not ::ns2::A as previously!). ? [list [:info slots b2] cget -type] ::ns1::ns2::A } } nx::Class create A { :property a1:object,type=B; # rewritten to ::B ? [list [:info slots a1] cget -type] ::B :property a2:object,type=ns1::B; # rewritten to ::ns1::B ? [list [:info slots a2] cget -type] ::ns1::B :property a3:object,type=::B; # untouched ? [list [:info slots a3] cget -type] ::B :property a4:object,type=[namespace qualifiers [namespace current]::]::B; # untouched, ::B ? [list [:info slots a4] cget -type] ::B :property a5:object,type=[namespace which B]; # untouched, "", will be dropped ? [list [:info slots a5] cget -type] {can't read "type": no such variable} } nx::Class create B } ? {catch {::ns1::B create b1 -b1 [::ns1::A new] -b2 [::ns1::ns2::A new]}} 0 } nx::test case substdefault-hardening { nx::Class create K { :object property {p2 "$x"} :property {p4 "$y"} :create k } ? {::K cget -p2} {$x} ? {::k cget -p4} {$y} ? {::K object property {p3:substdefault "[[set _ 1]"}} {substdefault: default '[[set _ 1]' is not a complete script} ? {::K property {p5:substdefault "[[set _ 2]"}} {substdefault: default '[[set _ 2]' is not a complete script} ::K property {p6:substdefault "[set _ 2]]"} ? {[::K new] cget -p6} {2]} ::K object property {p7:substdefault "[set _ 7]]"} ? {::K cget -p7} {7]} } nx::test case type-reform { namespace eval :: { ::nsf::proc foo {p2:object,type=C} { return [$p2 info class] } nx::Class create C nx::Object create o { :public object method foo {p1:object,type=C} { return [$p1 info class] } :public object method faa {p1:object,type=C} -returns object,type=C { return $p1 } } ::nsf::method::setter o s1:object,type=C ::nsf::method::setter C s2:object,type=C ::proc bar args { ::nsf::parseargs p1:object,type=C $args return [$p1 info class] } ::proc baz {a} { ::nsf::is object,type=C $a return [$a info class] } namespace eval ns1 { namespace eval ns2 { nx::Class create C nx::Class create A { :public method foo {p1:object,type=C} { return [$p1 info class] } :public method faa {p1:object,type=C} -returns object,type=C { return $p1 } } ::nsf::proc foo {p2:object,type=C} { return [$p2 info class] } ::proc bar args { ::nsf::parseargs p2:object,type=C $args return [$p2 info class] } ::proc baz {a} { ::nsf::is object,type=C $a return [$a info class] } ::nsf::method::setter A s3:object,type=C ::nsf::method::setter A -per-object s4:object,type=C } } } set ::C ::ns1::ns2::C ## In the intrep (param structure), unqualified names will be qualified; ? {::o foo [::C new]} ::C ? {[::o faa [::C new]] info class} ::C ? {[::o s1 [::C new]] info class} ::C ? {[[::C new] s2 [::C new]] info class} ::C $::C create ::c1 ? {[[::C new] s2 ::c1] info class} {expected object of type ::C but got "::c1" for parameter "s2"} ## the stringrep remains untouched (to allow for cloning, serializing ## method records more easily) ? {nsf::parameter::info type [::o info object method parameters foo p1]} C ? {[::ns1::ns2::A new] foo [$::C new]} $::C ? {nsf::parameter::info type [::ns1::ns2::A info method parameters foo p1]} C ? {[[::ns1::ns2::A new] faa [$::C new]] info class} $::C ? {[[::ns1::ns2::A new] s3 [$::C new]] info class} $::C ? {[::ns1::ns2::A s4 [$::C new]] info class} $::C ? {::ns1::ns2::foo [$::C new]} $::C ? {::foo [::C new]} ::C ? {::bar [::C new]} ::C ? {::baz [::C new]} ::C ? {::ns1::ns2::bar [$::C new]} $::C ? {::ns1::ns2::baz [$::C new]} $::C ## error msgs now contain the qualified type names ::C create ::c ? {[::ns1::ns2::A new] foo ::c} \ "expected object of type ::ns1::ns2::C but got \"::c\" for parameter \"p1\"" } # # Check per-object variable default value checking. # Every test can be performed only once due to the intended semantics # nx::test configure -count 1 nx::test case check-object-variables { ::nx::Object create o1 ? {::o1 object variable v01:int 1} {} ? {::o1 object variable v11:int a} {expected integer but got "a"} ? {::o1 object variable v02:object,type=nx::Object ::nx::Object} {} ? {::o1 object variable v12:object,type=nx::Object a} {expected object but got "a"} ? {::o1 object variable v03:upper A} {} ? {::o1 object variable v13:upper a} {expected upper but got "a"} ? {::o1 object variable v04:lower,1..n "a b c"} {} ? {::o1 object variable v14:lower,1..n "a B c"} {invalid value in "a B c": expected lower but got "B"} ? {::o1 object variable err:object,type:nx::Object ::nx::Object} {invalid value constraints "type:nx::Object"} } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/returns.test000644 000766 000024 00000025722 13462406127 016752 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx ::nx::configure defaultMethodCallProtection false package require nx::test # # The same tests are in this test suite, once with and once without # checking # # Make sure, checking is turned on # ::nsf::configure checkresult true nx::test configure -count 10000 nx::test case int-returns { nx::Class create C { # scripted method without paramdefs :method bar-ok1 {a b} {return 1} :method bar-ok2 {a b} {return $a} # scripted method with paramdefs :method bar-nok {a b:integer} {return a} # alias to tcl-cmd (no param defs) :alias incr -frame object ::incr :alias lappend -frame object ::lappend :create c1 } ::nsf::method::property C bar-ok1 returns integer ::nsf::method::property C bar-ok2 returns integer ::nsf::method::property C bar-nok returns integer ::nsf::method::property C incr returns integer ::nsf::method::property C lappend returns integer ? {c1 bar-ok1 1 2} 1 ? {c1 bar-ok2 1 2} 1 ? {c1 bar-nok 1 2} {expected integer but got "a" as return value} ? {c1 incr x} 1 ? {c1 incr x} 10002 ? {c1 lappend l e1} {expected integer but got "e1" as return value} # query the returns value ? {::nsf::method::property C lappend returns} integer # reset it to empty ? {::nsf::method::property C lappend returns ""} "" ? {::nsf::method::property C bar-ok1 returns ""} "" ? {::nsf::method::property C bar-ok2 returns ""} "" ? {::nsf::method::property C bar-nok returns ""} "" # no checking ? {c1 bar-ok1 1 2} 1 ? {c1 bar-ok2 1 2} 1 ? {c1 bar-nok 1 2} a ? {c1 lappend l e2} "e1 e2" # query returns "", if there is no returns checking ? {::nsf::method::property C lappend returns} "" ? {::nsf::method::property ::nx::Class method returns} "" } nx::test configure -count 10 nx::test case app-specific-returns { ::nx::methodParameterSlot object method type=range {name value arg} { lassign [split $arg -] min max if {$value < $min || $value > $max} { error "Value '$value' of parameter $name not between $min and $max" } return $value } nx::Class create C { :method bar-ok1 {a b} {return 1} :method bar-ok2 {a b} {return $a} :method bar-nok {a b:integer} {return a} :alias incr -frame object ::incr :alias lappend -frame object ::lappend :create c1 } ::nsf::method::property C bar-ok1 returns range,arg=1-3 ::nsf::method::property C bar-ok2 returns range,arg=1-3 ::nsf::method::property C bar-nok returns range,arg=1-3 ::nsf::method::property C incr returns range,arg=1-30 ::nsf::method::property C lappend returns range,arg=1-30 ? {c1 bar-ok1 1 2} 1 ? {c1 bar-ok2 1 2} 1 ? {c1 bar-nok 1 2} {Value 'a' of parameter return-value not between 1 and 3} ? {c1 incr x} 1 ? {c1 incr x} 12 ? {c1 lappend l e1} {Value 'e1' of parameter return-value not between 1 and 30} } nx::test configure -count 1000 nx::test case converting-returns { ::nx::methodParameterSlot object method type=sex {name value args} { #puts stderr "[current] slot specific converter" switch -glob $value { m* {return m} f* {return f} default {error "expected sex but got $value"} } } nx::Class create C { :method bar-ok1 {a b} {return male} :method bar-ok2 {a b} {return $a} :method bar-nok {a b:integer} {return $b} :alias set -frame object ::set :create c1 } ::nsf::method::property C bar-ok1 returns sex ::nsf::method::property C bar-ok2 returns sex ::nsf::method::property C bar-nok returns sex ::nsf::method::property C set returns sex ? {c1 bar-ok1 1 2} male ? {c1 bar-ok2 female 2} female ? {c1 bar-nok 1 6} {expected sex but got 6} ? {c1 set x male} male ? {c1 eval {set :x}} male ? {c1 set x} male ? {c1 set x hugo} {expected sex but got hugo} ::nsf::method::property C bar-ok1 returns sex,convert ::nsf::method::property C bar-ok2 returns sex,convert ::nsf::method::property C bar-nok returns sex,convert ::nsf::method::property C set returns sex,convert ? {c1 bar-ok1 1 2} m ? {c1 bar-ok2 female 2} f ? {c1 bar-nok 1 6} {expected sex but got 6} ? {c1 set x male} m ? {c1 eval {set :x}} male ? {c1 set x} m ? {c1 set x hugo} {expected sex but got hugo} } # # turn off result checking # ::nsf::configure checkresults false ::nx::test configure -count 1000 ::nx::test case int-returns-nocheck { nx::Class create C { # scripted method without paramdefs :method bar-ok1 {a b} {return 1} :method bar-ok2 {a b} {return $a} # scripted method with paramdefs :method bar-nok {a b:integer} {return a} # alias to tcl-cmd (no param defs) :alias incr -frame object ::incr :alias lappend -frame object ::lappend :create c1 } ::nsf::method::property C bar-ok1 returns integer ::nsf::method::property C bar-ok2 returns integer ::nsf::method::property C bar-nok returns integer ::nsf::method::property C incr returns integer ::nsf::method::property C lappend returns integer ? {c1 bar-ok1 1 2} 1 ? {c1 bar-ok2 1 2} 1 ? {c1 bar-nok 1 2} a ? {c1 incr x} 1 ? {c1 incr x} 1002 ? {c1 lappend l e1} e1 # query the returns value ? {::nsf::method::property C lappend returns} integer # reset it to empty ? {::nsf::method::property C lappend returns ""} "" c1 eval {set :l e1} # no checking on lappend ? {c1 lappend l e2} "e1 e2" # query returns "", if there is no returns checking ? {::nsf::method::property C lappend returns} "" ? {::nsf::method::property ::nx::Class method returns} "" } ::nx::test configure -count 10 ::nx::test case app-specific-returns-nocheck { ::nx::methodParameterSlot object method type=range {name value arg} { lassign [split $arg -] min max if {$value < $min || $value > $max} { error "Value '$value' of parameter $name not between $min and $max" } return $value } nx::Class create C { :method bar-ok1 {a b} {return 1} :method bar-ok2 {a b} {return $a} :method bar-nok {a b:integer} {return a} :alias incr -frame object ::incr :alias lappend -frame object ::lappend :create c1 } ::nsf::method::property C bar-ok1 returns range,arg=1-3 ::nsf::method::property C bar-ok2 returns range,arg=1-3 ::nsf::method::property C bar-nok returns range,arg=1-3 ::nsf::method::property C incr returns range,arg=1-30 ::nsf::method::property C lappend returns range,arg=1-30 ? {c1 bar-ok1 1 2} 1 ? {c1 bar-ok2 1 2} 1 ? {c1 bar-nok 1 2} a ? {c1 incr x} 1 ? {c1 incr x} 12 ? {c1 lappend l e1} e1 } ::nx::test configure -count 1000 ::nx::test case converting-returns-nocheck { ::nx::methodParameterSlot object method type=sex {name value args} { #puts stderr "[current] slot specific converter" switch -glob $value { m* {return m} f* {return f} default {error "expected sex but got $value"} } } nx::Class create C { :method bar-ok1 {a b} {return male} :method bar-ok2 {a b} {return $a} :method bar-nok {a b:integer} {return $b} :alias set -frame object ::set :create c1 } # # turn off checker # ::nsf::method::property C bar-ok1 returns sex ::nsf::method::property C bar-ok2 returns sex ::nsf::method::property C bar-nok returns sex ::nsf::method::property C set returns sex ? {c1 bar-ok1 1 2} male ? {c1 bar-ok2 female 2} female ? {c1 bar-nok 1 6} 6 ? {c1 set x male} male ? {c1 eval {set :x}} male ? {c1 set x} male ? {c1 set x hugo} hugo # # don't turn off converter # ::nsf::method::property C bar-ok1 returns sex,convert ::nsf::method::property C bar-ok2 returns sex,convert ::nsf::method::property C bar-nok returns sex,convert ::nsf::method::property C set returns sex,convert ? {c1 bar-ok1 1 2} m ? {c1 bar-ok2 female 2} f ? {c1 bar-nok 1 6} {expected sex but got 6} ? {c1 set x male} m ? {c1 eval {set :x}} male ? {c1 set x} m ? {c1 set x hugo} {expected sex but got hugo} } ::nsf::configure checkresults true ::nx::test case int-returns-sugar { nx::Class create C { # scripted method without paramdefs :method bar-ok1 {a b} -returns integer {return 1} :method bar-ok2 {a b} -returns integer {return $a} # scripted method with paramdefs :method bar-nok {a b:integer} -returns integer {return a} # alias to tcl-cmd (no param defs) :alias incr -returns integer -frame object ::incr :alias lappend -returns integer -frame object ::lappend :forward ++ -returns integer ::expr 1 + :forward | -returns integer ::append _ :public object method instances {} -returns object,1..n {:info instances} :create c1 } package req nx::serializer set s [C serialize] puts $s ? [list set _ [regsub -all returns $s returns s]] 8 "occurrences of returns" ? {c1 bar-ok1 1 2} 1 ? {c1 bar-ok2 1 2} 1 ? {c1 ++ 1000} 1001 ? {c1 | a} {expected integer but got "a" as return value} ? {::nsf::method::property ::C ::nsf::classes::C::bar-nok returns} integer ? {c1 bar-nok 1 2} {expected integer but got "a" as return value} ? {C instances} ::c1 ? {c1 incr x} 1 ? {c1 incr x} 1002 ? {c1 lappend l e1} {expected integer but got "e1" as return value} # query the returns value ? {::nsf::method::property C lappend returns} integer # reset it to empty ? {::nsf::method::property C lappend returns ""} "" ? {::nsf::method::property C bar-ok1 returns ""} "" ? {::nsf::method::property C bar-ok2 returns ""} "" ? {::nsf::method::property C bar-nok returns ""} "" ? {::nsf::method::property C ++ returns ""} "" ? {::nsf::method::property C | returns ""} "" # no checking ? {c1 bar-ok1 1 2} 1 ? {c1 bar-ok2 1 2} 1 ? {c1 bar-nok 1 2} a ? {c1 lappend l e2} "e1 e2" ? {c1 ++ 1000} 1001 ? {c1 | a} "a" # query returns "", if there is no returns checking ? {::nsf::method::property C lappend returns} "" ? {::nsf::method::property ::nx::Class method returns} "" } ::nx::test case empty-paramdefs-robustedness { ::nx::Object create ku { # 1: Create an empty or checker-free parameter spec :object method foo {} {;} ? [:info object method parameters foo] "" # 2: A call to ::nsf::method::property which might require NsfParamDefs ? [list ::nsf::method::property [::nx::current] foo returns] "" # 3: Check, if "info method parameter" still works ? [:info object method parameters foo] "" ? [list ::nsf::method::property [::nx::current] foo returns] "" # 4: Set methodproperty to some value and check again ::nsf::method::property [::nx::current] foo returns int ? [list ::nsf::method::property [::nx::current] foo returns] "int" ? [:info object method parameters foo] "" # 5: Reset methodproperty and query again ::nsf::method::property [::nx::current] foo returns "" ? [list ::nsf::method::property [::nx::current] foo returns] "" ? [:info object method parameters foo] "" } } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/info-variable.test000644 000766 000024 00000023405 13462406127 017762 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package req nx package req nx::test # parameter/variable info reform # # /cls/ info configure parameters ?pattern? -> list of params # /cls/ info configure syntax -> syntax output # # /cls/ info method parameters /methodname/ ?/pattern/? -> list of params # /cls/ info method syntax /methodname/ -> syntax output # /cls/ info variables ?/pattern/? -> list of variable handles # # /obj/ info object method parameters /methodname/ ?/pattern/? -> list of params # /obj/ info object method syntax /methodname/ -> syntax output # /obj/ info object variables ?/pattern/? -> list of variable handles # # /obj/ info lookup configure parameters ?/pattern/? -> list of params # /obj/ info lookup configure syntax -> syntax output # /obj/ info lookup variables ?/pattern/? -> list of variable handles # # Context-free: work on any object, would not need object. # /obj/ info parameter list|name|syntax /param/ -> value # /obj/ info variable definition|name|parameter /handle/ -> value # nx::test case configure-parameters { nx::Class create Person { :property name :property age:integer :public method foo {-force:switch age:integer {name ""}} {return $age} } ? {join [Person info lookup parameters create] \n} \ "objectName -age:integer -name -object-mixins:mixinreg,slot=::nx::Object::slot::object-mixins,slotset,method=object-mixin,0..n -object-filters:filterreg,slot=::nx::Object::slot::object-filters,slotset,method=object-filter,0..n -class:class,alias,method=::nsf::methods::object::class __initblock:cmd,optional,nodashalnum" ? {Person info lookup parameters create age} "-age:integer" ? {Person info lookup parameters create {*a[gs]*}} "-age:integer -class:class,alias,method=::nsf::methods::object::class" ? {Person info lookup syntax create} "/objectName/ ?-age /integer/? ?-name /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?" ? {Person info method parameters foo} {-force:switch age:integer {name ""}} ? {Person info method parameters foo force} "-force:switch" ? {Person info method parameters foo {*a[gm]*}} {age:integer {name ""}} ? {Person info method syntax foo} "/cls/ foo ?-force? /age/ ?/name/?" #? {Person info parameter syntax age:integer} "/age/" #? {Person info parameter syntax -force:switch} "?-force?" #? {Person info parameter name "a b"} "a" set emsg [join [list \ "wrong # of elements in parameter definition. " \ "Should be a list of 1 or 2 elements, but got: ''"] ""] foreach subcmd {default syntax type list name} { ? [list nsf::parameter::info $subcmd ""] $emsg } ? {nsf::parameter::info syntax age:integer} "/age/" ? {nsf::parameter::info syntax -force:switch} "?-force?" ? {nsf::parameter::info name "a b"} "a" ? {lmap p [Person info lookup parameters create] {nsf::parameter::info default $p}} "0 0 0 0 0 0 0" ? {lmap p [Person info method parameters foo] {nsf::parameter::info default $p}} "1 0 1" nx::Class create Bar { :property {p 9} } nx::Class create Foo -superclass Bar { :property a:integer :property {b:integer 123} :variable c 456 :variable d:lower abc :variable -accessor public e:lower efg :property -accessor private {p 19} :property -accessor protected q :property -incremental i :public method m {} {: -local p get} :create f1 } ? {lmap p [Foo info lookup parameters create] {nsf::parameter::info name $p}} \ "objectName i a b p object-mixins object-filters class __initblock" ? {lmap p [Foo info lookup parameters create] {nsf::parameter::info default $p}} \ "0 0 0 1 1 0 0 0 0" ? {lmap p [Foo info lookup parameters create] {nsf::parameter::info type $p}} \ "{} {} integer integer {} mixinreg filterreg class {}" ? {join [lsort [::Foo info slots]] \n} \ "::Foo::slot::____Foo.p ::Foo::slot::a ::Foo::slot::b ::Foo::slot::c ::Foo::slot::d ::Foo::slot::e ::Foo::slot::i ::Foo::slot::q" ? {::Foo info lookup parameters create ?} "-i:1..n -a:integer {-b:integer 123} {-p 9}" ? {::Foo::slot::b definition} "::Foo property -accessor none {b:integer 123}" ? {::Foo::slot::i definition} "::Foo property -accessor public -incremental i:1..n" ? {::Foo::slot::____Foo.p definition} "::Foo variable -accessor private p 19" ? {::Foo::slot::d definition} "::Foo variable -accessor none d:lower abc" ? {::Foo::slot::e definition} "::Foo variable -accessor public e:lower efg" ? {::Foo::slot::q definition} "::Foo variable -accessor protected q" ? {join [lsort [::f1 info lookup slots]] \n} \ "::Bar::slot::p ::Foo::slot::____Foo.p ::Foo::slot::a ::Foo::slot::b ::Foo::slot::c ::Foo::slot::d ::Foo::slot::e ::Foo::slot::i ::Foo::slot::q ::nx::Object::slot::__initblock ::nx::Object::slot::class ::nx::Object::slot::object-filters ::nx::Object::slot::object-mixins" # get the configure value from p and the value of the private property via m ? {f1 cget -p} 9 ? {f1 m} 19 ? {lsort [f1 info vars]} "__private b c d e p" #package require nx::serializer #puts stderr [::Foo::slot::____Foo.p serialize] ? {llength [::f1 info lookup variables]} 9 ? {join [lsort [::f1 info lookup variables]] \n} \ "::Bar::slot::p ::Foo::slot::____Foo.p ::Foo::slot::a ::Foo::slot::b ::Foo::slot::c ::Foo::slot::d ::Foo::slot::e ::Foo::slot::i ::Foo::slot::q" # One can get 2 values for "lookup variables p"; the private one an # the non-private, since both have the same name. this is necessary # to obtain e.g. the definition of the private slot. ? {lsort [::f1 info lookup variables p]} "::Bar::slot::p ::Foo::slot::____Foo.p" ? {llength [::Foo info variables]} 8 ? {join [lsort [::Foo info variables]] \n} \ "::Foo::slot::____Foo.p ::Foo::slot::a ::Foo::slot::b ::Foo::slot::c ::Foo::slot::d ::Foo::slot::e ::Foo::slot::i ::Foo::slot::q" ? {::Foo info variables p} "::Foo::slot::____Foo.p" ? {::Foo info slots p} "::Foo::slot::____Foo.p" set ::vs [lsort [::Foo info variables]] ? {join [lmap handle $::vs {::Foo info variable definition $handle}] \n} \ "::Foo variable -accessor private p 19 ::Foo property -accessor none a:integer ::Foo property -accessor none {b:integer 123} ::Foo variable -accessor none c 456 ::Foo variable -accessor none d:lower abc ::Foo variable -accessor public e:lower efg ::Foo property -accessor public -incremental i:1..n ::Foo variable -accessor protected q" set ::ps [lmap handle $::vs {::Foo info variable parameter $handle}] ? {join $::ps \n} \ "p 19 a:integer b:integer 123 c 456 d:lower abc e:lower efg i:1..n q" ? {lmap handle $::vs {::Foo info variable name $handle}} \ "__private(::Foo,p) a b c d e i q" ? {lmap handle $::ps {nsf::parameter::info name $handle}} \ "p a b c d e i q" ? {lmap handle $::ps {nsf::parameter::info default $handle}} \ "1 0 1 1 1 1 0 0" ? {lmap handle $::ps {nsf::parameter::info type $handle}} \ "{} integer integer {} lower lower {} {}" ? {nsf::parameter::info default "b:integer 123" ::var1} "1" ? {set ::var1} "123" ? {nsf::parameter::info default "b:integer 123" ::var2} "1" ? {set ::var2} "123" } nx::test case object-variables { nx::Class create Bar { :property {p 9} } nx::Class create Foo -superclass Bar { :property a:integer :property {b:integer 123} :variable c 456 :variable d:lower abc :variable -accessor public e:lower efg :property -accessor private {p 19} :property -accessor protected q :property -incremental i :public method m {} {: -local p} :create f1 } Foo create f2 { :object property oa:integer :object property {ob:integer 123} :object variable oc 456 ;# NO slot :object variable od:lower abc ;# NO slot :object variable -accessor public oe:lower efg :object property -incremental oi :object property -accessor private {op 19} :object property -accessor protected oq :public object method om {} {: -local p} } set ::ovs [lsort [::f2 info object variables]] ? {llength $::ovs} "6" ;# oc, od missing ? {join $::ovs "\n"} \ "::f2::per-object-slot::____f2.op ::f2::per-object-slot::oa ::f2::per-object-slot::ob ::f2::per-object-slot::oe ::f2::per-object-slot::oi ::f2::per-object-slot::oq" ? {join [lmap handle $::ovs {::f2 info variable definition $handle}] \n} \ "::f2 object variable -accessor private op 19 ::f2 object property -accessor none oa:integer ::f2 object property -accessor none {ob:integer 123} ::f2 object variable -accessor public oe:lower efg ::f2 object property -accessor public -incremental oi:1..n ::f2 object variable -accessor protected oq" ? {lmap handle $::ovs {::f2 info variable parameter $handle}} \ "{op 19} oa:integer {ob:integer 123} {oe:lower efg} oi:1..n oq" ? {lmap handle $::ovs {::f2 info variable name $handle}} \ "__private(::f2,op) oa ob oe oi oq" set ::ovs [lsort [::f2 info lookup variables]] ? {llength $::ovs} "15" ;# oc, od missing ? {join $::ovs "\n"} \ "::Bar::slot::p ::Foo::slot::____Foo.p ::Foo::slot::a ::Foo::slot::b ::Foo::slot::c ::Foo::slot::d ::Foo::slot::e ::Foo::slot::i ::Foo::slot::q ::f2::per-object-slot::____f2.op ::f2::per-object-slot::oa ::f2::per-object-slot::ob ::f2::per-object-slot::oe ::f2::per-object-slot::oi ::f2::per-object-slot::oq" # redefine property a on the object level ::f2 object property -accessor none a:integer set ::ovs [lsort [::f2 info lookup variables]] ? {llength $::ovs} "15" ;# oc, od missing ? {join $::ovs "\n"} \ "::Bar::slot::p ::Foo::slot::____Foo.p ::Foo::slot::b ::Foo::slot::c ::Foo::slot::d ::Foo::slot::e ::Foo::slot::i ::Foo::slot::q ::f2::per-object-slot::____f2.op ::f2::per-object-slot::a ::f2::per-object-slot::oa ::f2::per-object-slot::ob ::f2::per-object-slot::oe ::f2::per-object-slot::oi ::f2::per-object-slot::oq" } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/object-system.test000644 000766 000024 00000031512 14261265353 020034 0ustar00neumannstaff000000 000000 # -*- Tcl -*- # # Basic tests of the object system, should not require Class Test, # since even class Test might not work at that time. # proc ? {cmd expected {msg ""}} { #puts "??? $cmd" set r [uplevel $cmd] if {$msg eq ""} {set msg $cmd} if {$r ne $expected} { #puts stderr "ERROR $msg returned '$r' ne '$expected'" error "FAILED $msg returned\n'$r' ne\n'$expected'" } else { puts stderr "OK $msg" } } puts stderr "loaded Tcl version: $::tcl_version ($::tcl_patchLevel)" package req nsf puts stderr "loaded ::nsf::version $::nsf::version, ::nsf::patchLevel $::nsf::patchLevel" puts stderr "available versions of nsf: [package versions nsf]" ? {string first [nsf::pkgconfig get version] [nsf::pkgconfig get patchLevel]} 0 package require nx ::nsf::configure dtrace on ? {::nsf::configure objectsystems} {{::nx::Object ::nx::Class {-class.alloc {__alloc ::nsf::methods::class::alloc 1} -class.create create -class.dealloc {__dealloc ::nsf::methods::class::dealloc 1} -class.configureparameter __class_configureparameter -class.recreate {__recreate ::nsf::methods::class::recreate 1} -object.configure __configure -object.configureparameter __object_configureparameter -object.defaultmethod {defaultmethod ::nsf::methods::object::defaultmethod} -object.destroy destroy -object.init {init ::nsf::methods::object::init} -object.move move -object.unknown unknown}}} ? {::nsf::object::exists nx::Object} 1 ? {::nsf::object::property nx::Object initialized} 1 ? {::nsf::is class nx::Object} 1 ? {::nsf::is metaclass nx::Object} 0 ? {nx::Object info superclasses} "" ? {nx::Object info class} ::nx::Class ? {nx::Object info baseclass} ::nx::Object ? {nx::Object info baseclass} [lindex [::nx::Object info precedence] end] ? {::nsf::object::exists nx::Class} 1 ? {::nsf::is class nx::Class} 1 ? {::nsf::is metaclass nx::Class} 1 ? {nx::Class info superclasses} ::nx::Object ? {nx::Class info class} ::nx::Class ? {nx::Class info baseclass} ::nx::Object ? {nx::Class info baseclass} [lindex [::nx::Class info precedence] end] # # Minimal argument passing tests for early problem detection # nsf::proc p0 {arg} {return [list $arg]} nsf::proc p1 {arg:optional} {return [list [info exists arg]]} nsf::proc p2 {arg args} {return [list $arg $args]} nsf::proc p3 {arg:optional args} {return [list [info exists arg] $args]} nsf::proc p4 {-x args} {return [list [info exists x] $args]} nsf::proc p5 {-x arg:optional -y args} {return [list [info exists x] [info exists y] [info exists arg] $args]} ? {p0 a} a ? {p1 a} 1 ? {p1} 0 ? {p2 a b c} {a {b c}} ? {p2 a} {a {}} ? {p2 a b} {a b} ? {p3 a b} {1 b} ? {p3 a b c} {1 {b c}} ? {p3 a} {1 {}} ? {p3} {0 {}} ? {p4} {0 {}} ? {p4 -x 1} {1 {}} ? {p4 -x 1 2} {1 2} ? {p4 -- -x 1 2} {0 {-x 1 2}} ? {p4 --} {0 {}} ? {p4 -- --} {0 --} ? {p4 -y --} {0 {-y --}} ;# no -y parameter, so pushed into args ? {p5} {0 0 0 {}} ? {p5 -x 1} {1 0 0 {}} ? {p5 a} {0 0 1 {}} ? {p5 -y 1} {0 0 1 1} ;# "-y" is passed into arg, "1" into args ? {p5 -y 1 2} {0 0 1 {1 2}} ;# "-y" is passed into arg, "1 2" into args ? {p5 -x 1 2} {1 0 1 {}} ;# "2" is passed into arg, "1 2" into args ? {p5 -y --} {0 0 1 {}} ;# "--" is value of "y" # # Create objects and test its properties # nx::Object create o ? {::nsf::object::exists nx::Object} 1 ? {::nsf::is class o} 0 ? {::nsf::is metaclass o} 0 ? {o info class} ::nx::Object ? {o info baseclass} ::nx::Object ? {o info baseclass} [lindex [o info precedence] end] ? {nx::Object info instances o} ::o ? {nx::Object info instances ::o} ::o o destroy ? {nsf::object::exists ::o} 0 ? {nsf::object::exists o} 0 nx::Object create o2 { ? {::nsf::object::exists ::o2} 1 ? {::nsf::object::property ::o2 initialized} 0 } ? {::nsf::object::property ::o2 initialized} 1 nx::Class create C0 ? {::nsf::is class C0} 1 ? {::nsf::is metaclass C0} 0 ? {C0 info superclasses} ::nx::Object ? {C0 info class} ::nx::Class #? {lsort [Class info vars]} "__default_metaclass __default_superclass" nx::Class create M -superclass ::nx::Class ? {::nsf::object::exists M} 1 ? {::nsf::is class M} 1 ? {::nsf::is metaclass M} 1 ? {M info superclasses} ::nx::Class ? {M info class} ::nx::Class ? {M info baseclass} ::nx::Object ? {M info baseclass} [lindex [M info precedence] end] M create C ? {::nsf::object::exists C} 1 ? {::nsf::is class C} 1 ? {::nsf::is metaclass C} 0 ? {C info superclasses} ::nx::Object ? {C info class} ::M C create c1 ? {::nsf::object::exists c1} 1 ? {::nsf::is class c1} 0 ? {::nsf::is metaclass c1} 0 ? {c1 info class} ::C nx::Class create M2 -superclass M ? {::nsf::object::exists M2} 1 ? {::nsf::is class M2} 1 ? {::nsf::is metaclass M2} 1 ? {M2 info superclasses} ::M ? {M2 info class} ::nx::Class M2 create m2 ? {m2 info superclasses} ::nx::Object ? {m2 info class} ::M2 # destroy meta-class M, reclass meta-class instances to the base # meta-class and set subclass of M to the root meta-class M destroy ? {::nsf::object::exists C} 1 ? {::nsf::is class C} 1 ? {::nsf::is metaclass C} 0 ? {C info superclasses} ::nx::Object ? {C info class} ::nx::Class ? {::nsf::is metaclass M2} 1 ? {M2 info superclasses} ::nx::Class ? {m2 info superclasses} ::nx::Object ? {m2 info class} ::M2 # destroy class M, reclass class instances to the base class C destroy ? {::nsf::object::exists C} 0 ? {::nsf::object::exists ::C} 0 ? {::nsf::object::exists c1} 1 ? {::nsf::is object c1} 1 ? {::nsf::is class c1} 0 ? {::nsf::is metaclass c1} 0 ? {c1 info class} ::nx::Object # # tests for dispatching methods # nx::Object create o o public object method foo {} {return foo} o public object method bar1 {} {return bar1-[:foo]} o public object method bar2 {} {return bar2-[: foo]} o public object method bar4 {} {return bar4-[[self] foo]} o public object method bar5 {} {return [self]::bar5} o public object method bar6 {} {return [:]::bar6} o public object method bar7 {} {return bar7-[lsort [: -system info object methods bar7]]} # dispatch without colon names ? {o foo} foo "simple method dispatch" ? {o bar1} bar1-foo "colon-methodname dispatch" ? {o bar2} bar2-foo "colon cmd dispatch" #? {o bar3} bar3-foo "my dispatch" ? {o bar4} bar4-foo "self dispatch" ? {o bar5} ::o::bar5 "self cmd" ? {o bar6} ::o::bar6 "colon cmd" ? {o bar7} bar7-bar7 "colon cmd dispatch args" o destroy # basic attributes tests nx::Class create C { :property {x 1} :property {y 2} } ? {::nsf::object::exists C} 1 ? {::nsf::object::exists C::slot} 1 ? {C info children} ::C::slot #? {C::slot info vars} __parameter #? {C info attributes} {{x 1} {y 2}} ? {C info lookup parameters create x} {{-x 1}} ? {C info lookup parameters create y} {{-y 2}} ? {C copy X} ::X ? {::nsf::object::exists X} 1 ? {X info vars} "" ? {C info vars} "" ? {::nsf::object::exists X::slot} 1 ? {set c1 [C new]} "::nsf::__#1" ? {nsf::object::property $c1 autonamed} 1 ? {$c1 copy c2} "::c2" ? {nsf::object::property c2 autonamed} 0 # copy without new name ? {c2 copy} ::nsf::__#4 ? {set C [C copy]} ::nsf::__#6 ? {::nsf::object::exists ${C}::slot} 1 #? {X::slot info vars} __parameter ? {X info lookup parameters create ?} {{-x 1} {-y 2}} ? {X info lookup parameters create x} {{-x 1}} ? {X info lookup parameters create y} {{-y 2}} #? {X info properties} {{x 1} {y 2}} #? {X info properties -closure *a*} {volatile:alias,noarg class:class,alias,method=::nsf::methods::object::class} # actually, we want c1 to test below the recreation of c1 in another # object system ? {C create c1} ::c1 ? {C create c2 {:object method foo {} {;}}} ::c2 # # check low-level method creation on classes, and check C-level # "-flag=value" handling # nsf::method::create ::C m1 {} {;} ? {lsort [::C ::nsf::methods::class::info::methods]} {m1} nsf::method::create ::C -per-object=false m2 {} {;} ? {lsort [::C ::nsf::methods::class::info::methods]} {m1 m2} nsf::method::create ::C -per-object=true m3 {} {;} ? {lsort [::C ::nsf::methods::object::info::methods]} {m3} # # tests for the dispatch command # nx::Object create o o object method foo {} {return goo} o object method bar {x} {return goo-$x} # dispatch without colon names ::nsf::dispatch o eval set :x 1 ? {o info vars} x "simple dispatch has set variable x" ? {::nx::var set o x} 1 "simple dispatch has set variable x to 1" ? {::nsf::dispatch o foo} "goo" "simple dispatch with one arg works" ? {::nsf::dispatch o bar 1} "goo-1" "simple dispatch with two args works" o destroy # dispatch with colon names nx::Object create o {set :x 1} ::nsf::dispatch ::o ::incr x ? {o eval {set :x}} 1 "cmd dispatch without -frame object did not modify the instance variable" ::nsf::directdispatch ::o -frame object ::incr x ? {o eval {set :x}} 2 "cmd dispatch -frame object modifies the instance variable" ? {catch {::nsf::directdispatch ::o -frame object ::xxx x}} 1 "cmd dispatch with unknown command" o destroy nx::Object create o { :public object method foo {} { foreach var [list x1 y1 x2 y2 x3 y3] { lappend results $var [info exists :$var] } return $results } } ::nsf::directdispatch o ::eval {set x1 1; set :y1 1} ::nsf::directdispatch o -frame method ::eval {set x2 1; set :y2 1} ::nsf::directdispatch o -frame object ::eval {set x3 1; set :y3 1} ? {o foo} "x1 0 y1 0 x2 0 y2 1 x3 1 y3 1" o destroy # # Create objects via tcl ensembles # namespace eval k { nx::Class create s { :property j :method init {} {set :j} ;# the variable should be set } namespace export s namespace ensemble create } ? {k s create o -j X} ::o ::o destroy puts stderr ===MINI-OBJECTSYSTEM # test object system # create a minimal object system without internally dipatched methods ::nsf::objectsystem::create ::object ::class ? {::nsf::object::exists ::object} 1 ? {::nsf::is class ::object} 1 ? {::nsf::is metaclass ::object} 0 ? {::nsf::relation::get ::object class} ::class ? {::nsf::relation::get ::object superclass} "" ? {::nsf::object::exists ::class} 1 ? {::nsf::is class ::class} 1 ? {::nsf::is metaclass ::class} 1 ? {::nsf::relation::get ::class class} ::class ? {::nsf::relation::get ::class superclass} ::object # define non-standard methods to create/destroy objects and classes ::nsf::method::alias ::class + ::nsf::methods::class::create ::nsf::method::alias ::object - ::nsf::methods::object::destroy # create a class named C ::class + C ? {::nsf::object::exists ::C} 1 ? {::nsf::is class ::C} 1 ? {::nsf::is metaclass ::C} 0 ? {::nsf::relation::get ::C class} ::class ? {::nsf::relation::get ::C superclass} ::object # create an instance of C C + c1 ? {::nsf::object::exists ::c1} 1 ? {::nsf::is class ::c1} 0 ? {::nsf::is metaclass ::c1} 0 ? {::nsf::relation::get ::c1 class} ::C # destroy instance c1 - ? {::nsf::object::exists ::c1} 0 ? {::nsf::is class ::C} 1 # recreate an nx object with a namespace C + c2 # destroy class C - ? {::nsf::object::exists ::C} 0 ::nx::Class create ::C ? {catch {::C info has type ::UNKNOWN}} 1 ? {catch {::C info has type ::xyz::Bar}} 1 #? {catch {::nsf::is type ::CCCC ::nx::Object}} 1 ::C destroy # # Test protection against (most likely unintended) deletion of base # classes. # ? {catch {nx::Object destroy}} 1 ? {::nsf::object::exists nx::Object} 1 ? {catch {nx::Object create nx::Object}} 1 ? {::nsf::object::exists nx::Object} 1 ? {catch {nx::Object create nx::Class}} 1 ? {::nsf::object::exists nx::Class} 1 ? {catch {nx::Class create nx::Object}} 1 ? {catch {nx::Class create nx::Class}} 1 ? {catch {rename nx::Object ""}} 1 ? {::nsf::object::exists nx::Object} 1 ? {catch {rename nx::Object ""}} 1 ? {::nsf::object::exists nx::Object} 1 ? {catch {rename nx::Class ""}} 1 ? {::nsf::object::exists nx::Class} 1 # # Test overwriting of procs/methods # proc foo {} {;} # # Don't allow object to overwrite pre-existing proc/cmd, # which is not an object. # ? {catch {nx::Object create foo}} 1 rename foo "" nx::Object create foo { :object method bar {} {;} # # Don't allow subobject to overwrite object specific method # ? {catch {nx::Object create [self]::bar}} 1 } nx::Object create foo { nx::Object create [self]::bar # # Don't allow child-object to be overwritten by object specific cmd # ? {catch {:object forward bar somethingelse}} 1 ? {nsf::object::exists [self]::bar} 1 # # Don't allow child-object to be overwritten by object specific # scripted method # ? {catch {:object method bar {} {;}}} 1 ? {nsf::object::exists [self]::bar} 1 } foo destroy # # Test instances of diamond class structure. # # Leave class structure around until exit to test handling of # potentially duplicated entries during final cleanup # nx::Class create A nx::Class create B1 -superclass A nx::Class create B2 -superclass A nx::Class create C -superclass {B1 B2} ? {C create c1} ::c1 ? {A info instances -closure} ::c1 ::nsf::configure keepcmds 1 ::nx::Object create o {set :x 1} ? {o info vars} "x __cmd" ? {o eval {array get :__cmd}} "__initblock {set :x 1}" ::nsf::configure dtrace off puts stderr "===EXIT [info script]" # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/method-parameter.test000644 000766 000024 00000040423 13546145705 020506 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx package require nx::test # # simple method parameter tests # nx::test case method-params-0 { nsf::proc p0 {} {return 1} nsf::proc p1 {-x} {return [list [info exists x]]} ? {p0} 1 # the following error msg comes from Tcl ? {p0 -x} {wrong # args: should be "p0"} ? {p1} 0 ? {p1 -x} {value for parameter '-x' expected} ? {p1 -x 1} 1 ? {p1 -x 1 2} {invalid argument '2', maybe too many arguments; should be "p1 ?-x /value/?"} ? {p1 -x 1 -y} {invalid non-positional argument '-y', valid are: -x; should be "p1 ?-x /value/?"} ? {p1 a} {invalid argument 'a', maybe too many arguments; should be "p1 ?-x /value/?"} ? {p1 a -x} {invalid argument 'a', maybe too many arguments; should be "p1 ?-x /value/?"} ? {p1 --} 0 ? {p1 -y} {invalid non-positional argument '-y', valid are: -x; should be "p1 ?-x /value/?"} ? {p1 -y --} {invalid non-positional argument '-y', valid are: -x; should be "p1 ?-x /value/?"} # # should we really allow numeric nonpos arg names? # ? {nsf::proc p2 {1 -2 -3} {return [list ${1} [info exists 2] [info exists 3]]}} "" ? {p2 -4 -2 -3 -3 -2} "-4 1 1" ;# var 2 has value "-3", var 3 has value "-2" ? {p2 -4 -3 + -2 -1} "-4 1 1" ;# var 2 has value "-2", var 3 has value "+" ? {nsf::proc p3 {1 -2 -3 4} {return [list ${1} [info exists 2] [info exists 3] ${4}]}} "" ? {p3 -4 -3 -2 -1} "-4 0 1 -1" ;# var 1 has value "-4", var 4 has value "-1" } # # test behavior of parameter option nodashalnum # nx::test case nodashalnum { nsf::proc p2a {-x args} {return [list [info exists x] $args]} nsf::proc p2b {-x args:nodashalnum} {return [list [info exists x] $args]} ? {p2a -x -y} {1 {}} ;# "-y" is the value of "x" ? {p2b -x -y} {1 {}} ;# "-y" is the value of "x" ? {p2a -x 1 -y} {1 -y} ? {p2a -x 1 -100} {1 -100} ? {p2b -x 1 -y} {invalid non-positional argument '-y', valid are: -x; should be "p2b ?-x /value/? ?/arg .../?"} ? {p2b -x 1 -100} {1 -100} nsf::proc p3a {a -x -y b:nodashalnum -z} {return [list $a [info exists x] [info exists y] $b]} ? {p3a 100 -x 1 -y 1 200} {100 1 1 200} ? {p3a 100 -xx 1 -y 1 200} {invalid non-positional argument '-xx', valid are: -x, -y; should be "p3a /a/ ?-x /value/? ?-y /value/? /b/ ?-z /value/?"} } # # Testing the unknown handler # nx::test case unknown-handler { Class create C { :public method p1 {-x} {return [list [info exists x]]} :create c1 } ? {c1 p1 -x 1 -y} {invalid non-positional argument '-y', valid are: -x; should be "::c1 p1 ?-x /value/?"} proc ::nsf::argument::unknown {method arg args} { puts stderr "??? unknown nonpos-arg $arg in $method obj <$args>\n[info frame -1]\n" return "" } ? {c1 p1 -x 1 -y} {invalid non-positional argument '-y', valid are: -x; should be "::c1 p1 ?-x /value/?"} if {0} { proc ::nsf::argument::unknown {method arg args} { # nasty handler redefines method puts stderr "??? REDEFINE ::nsf::argument::unknown <$args> [info frame -1]" C public method p1 {-y} {return [list [info exists y]]} return "" } ? {c1 p1 -x 1 -y} {invalid non-positional argument '-y', valid are: -x; should be "::c1 p1 ?-x /value/?"} } } # # testing error message when flags are used within an ensemble # nx::test case flag-in-ensemble { nx::Class create C if {[::nsf::pkgconfig get development]} { set info {info baseclass, info children, info class, info filters, info has mixin, info has namespace, info has type, info heritage, info info, info instances, info lookup filter, info lookup filters, info lookup method, info lookup methods, info lookup mixins, info lookup parameters, info lookup slots, info lookup syntax, info lookup variables, info method args, info method body, info method callprotection, info method debug, info method definition, info method definitionhandle, info method deprecated, info method disassemble, info method exists, info method handle, info method origin, info method parameters, info method registrationhandle, info method returns, info method submethods, info method syntax, info method type, info methods, info mixinof, info mixins, info name, info object filters, info object method args, info object method body, info object method callprotection, info object method debug, info object method definition, info object method definitionhandle, info object method deprecated, info object method disassemble, info object method exists, info object method handle, info object method origin, info object method parameters, info object method registrationhandle, info object method returns, info object method submethods, info object method syntax, info object method type, info object methods, info object mixins, info object slots, info object variables, info parent, info precedence, info slots, info subclasses, info superclasses, info variable definition, info variable name, info variable parameter, info variables, info vars} } else { set info {info baseclass, info children, info class, info filters, info has mixin, info has namespace, info has type, info heritage, info info, info instances, info lookup filter, info lookup filters, info lookup method, info lookup methods, info lookup mixins, info lookup parameters, info lookup slots, info lookup syntax, info lookup variables, info method args, info method body, info method callprotection, info method debug, info method definition, info method definitionhandle, info method deprecated, info method exists, info method handle, info method origin, info method parameters, info method registrationhandle, info method returns, info method submethods, info method syntax, info method type, info methods, info mixinof, info mixins, info name, info object filters, info object method args, info object method body, info object method callprotection, info object method debug, info object method definition, info object method definitionhandle, info object method deprecated, info object method exists, info object method handle, info object method origin, info object method parameters, info object method registrationhandle, info object method returns, info object method submethods, info object method syntax, info object method type, info object methods, info object mixins, info object slots, info object variables, info parent, info precedence, info slots, info subclasses, info superclasses, info variable definition, info variable name, info variable parameter, info variables, info vars} } ? {C info superclasses} "::nx::Object" ? {C info -a superclass} "unable to dispatch sub-method \"-a\" of ::C info; valid are: $info" ? {C info -- superclass} "unable to dispatch sub-method \"--\" of ::C info; valid are: $info" ? {C info -- -a superclass} "unable to dispatch sub-method \"--\" of ::C info; valid are: $info" ? {C info -a -- superclass} "unable to dispatch sub-method \"-a\" of ::C info; valid are: $info" } # # Testing error messages in info subclasses, when too many arguments are # specified, or when wrong non-positional arguments are given. The # argument "pattern" in "info subclasses" has parameter option # "nodashalnum" set. # nx::test case info-subclass-error-messages { nx::Class create C nx::Class create D -superclass C nx::Class create E -superclass C # # no argument # ? {C info subclasses} "::E ::D" ? {C info subclasses --} "::E ::D" # # one argument # ? {C info subclasses a} "" # # The argument definition of "pattern" for subclass has # "nodashalnum" option, therefore, we can deduce that "-a" must be # a flag. OTOH, if "-a" is a proper value (e.g. value of a # variable), then the following command would be perfectly fine. # ? {C info subclasses -a} \ {invalid non-positional argument '-a', valid are: -closure, -dependent; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses -a --} \ {invalid non-positional argument '-a', valid are: -closure, -dependent; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses -- -a} "" ? {C info subclasses -1} "" ? {C info subclasses -- -1} "" ? {C info subclasses -1 --} \ {invalid argument '--', maybe too many arguments; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} # # two arguments # ? {C info subclasses a b} \ {invalid argument 'b', maybe too many arguments; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses -- a b} \ {invalid argument 'b', maybe too many arguments; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses a -- b} \ {invalid argument '--', maybe too many arguments; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses a b --} \ {invalid argument 'b', maybe too many arguments; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} # first flag ? {C info subclasses -a b} \ {invalid non-positional argument '-a', valid are: -closure, -dependent; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses -- -a b} \ {invalid argument 'b', maybe too many arguments; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses -a -- b} \ {invalid non-positional argument '-a', valid are: -closure, -dependent; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses -a b --} \ {invalid non-positional argument '-a', valid are: -closure, -dependent; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} # second flag ? {C info subclasses a -b} \ {invalid argument '-b', maybe too many arguments; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses -- a -b} \ {invalid argument '-b', maybe too many arguments; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses a -- -b} \ {invalid argument '--', maybe too many arguments; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses a -b --} \ {invalid argument '-b', maybe too many arguments; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} # both flag ? {C info subclasses -a -b} \ {invalid non-positional argument '-a', valid are: -closure, -dependent; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses -- -a -b} \ {invalid argument '-b', maybe too many arguments; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses -a -- -b} \ {invalid non-positional argument '-a', valid are: -closure, -dependent; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses -a -b --} \ {invalid non-positional argument '-a', valid are: -closure, -dependent; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} } # # Testing error messages in info superclasses, when too many arguments # are specified, or when wrong non-positional arguments are # given. The argument "pattern" in "info superclasses" has parameter option # "nodashalnum" NOT set. # nx::test case info-superclass-error-messages { nx::Class create C nx::Class create D -superclass C # # no argument # ? {D info superclasses} "::C" ? {D info superclasses --} "::C" # # one argument # ? {D info superclasses a} "" # # The argument definition of "pattern" for superclass has no # "nodashalnum" option, "-a" is treated like a pattern. # ? {D info superclasses -a} "" ? {D info superclasses -a --} \ {invalid argument '--', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} ? {D info superclasses -- -a} "" ? {D info superclasses -1} "" # # two arguments # ? {D info superclasses a b} \ {invalid argument 'b', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} ? {D info superclasses -- a b} \ {invalid argument 'b', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} ? {D info superclasses a -- b} \ {invalid argument '--', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} ? {D info superclasses a b --} \ {invalid argument 'b', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} # first flag ? {D info superclasses -a b} \ {invalid argument 'b', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} ? {D info superclasses -- -a b} \ {invalid argument 'b', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} ? {D info superclasses -a -- b} \ {invalid argument '--', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} ? {D info superclasses -a b --} \ {invalid argument 'b', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} # second flag ? {D info superclasses a -b} \ {invalid argument '-b', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} ? {D info superclasses -- a -b} \ {invalid argument '-b', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} ? {D info superclasses a -- -b} \ {invalid argument '--', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} ? {D info superclasses a -b --} \ {invalid argument '-b', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} # both flag ? {D info superclasses -a -b} \ {invalid argument '-b', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} ? {D info superclasses -- -a -b} \ {invalid argument '-b', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} ? {D info superclasses -a -- -b} \ {invalid argument '--', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} ? {D info superclasses -a -b --} \ {invalid argument '-b', maybe too many arguments; should be "::D info superclasses ?-closure? ?/pattern/?"} } # # Test interactions of parameter option nodashalnum in "pattern" # with values starting with a dash. # nx::test case info-with-dash-class-names { nx::Class create C nx::Class create -a -superclass C nx::Class create -b -superclass -a # # no argument # ? {C info subclasses} "::-a" ? {C info subclasses --} "::-a" ? {-b info superclasses} "::-a" ? {-b info superclasses --} "::-a" # # one argument # ? {C info subclasses -a} \ {invalid non-positional argument '-a', valid are: -closure, -dependent; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses -a --} \ {invalid non-positional argument '-a', valid are: -closure, -dependent; should be "::C info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {C info subclasses -- -a} "::-a" ? {-b info superclasses -a} "::-a" ? {-b info superclasses -a --} \ {invalid argument '--', maybe too many arguments; should be "::-b info superclasses ?-closure? ?/pattern/?"} ? {-b info superclasses -- -a} "::-a" } # # Test abbreviations # nx::test case abbrevs1 { nsf::proc x {-super -super11 -superclass -super12} { return [info exists super]-[info exists super11]-[info exists superclass]-[info exists super12] } ? {x -super 1} "1-0-0-0" ? {x -super1 1} "the provided argument -super1 is an abbreviation for -super11 and -super12" ? {x -superc 1} "0-0-1-0" ? {x -super12 1} "0-0-0-1" nsf::proc y {-aaa1 -aa1 -a1 -a} { return [info exists aaa1]-[info exists aa1]-[info exists a1]-[info exists a] } ? {y -a 1} "0-0-0-1" ? {y -aa 1} {invalid non-positional argument '-aa', valid are: -aaa1, -aa1, -a1, -a; should be "y ?-aaa1 /value/? ?-aa1 /value/? ?-a1 /value/? ?-a /value/?"} ? {y -aaa 1} "1-0-0-0" ? {y -aa1 1} "0-1-0-0" } # # leading dash and numbers # nx::test case abbrevs2 { nsf::proc x {-x y:integer} { return [info exists x]-$y } ? {x 1} "0-1" ? {x -1} "0--1" ? {x -- -1} "0--1" nsf::proc y {-1 y:integer} { return [info exists 1]-$y } ? {y 1} "0-1" ? {y -1} "value for parameter '-1' expected" ? {y -- -1} "0--1" } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/serialize.test000644 000766 000024 00000023176 13462406127 017240 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package req nx::test package req nx::serializer nx::test case serialize-target { # # Create object structure with a forwarder and a slot # Object create ::xxx { :object property -accessor public ref Object create [self]::b { [:info parent] ref set [Object create [self]::c] } } # # check forwarder target and domain+manager of slot. # ? {nsf::method::forward::property :::xxx -per-object ref target} "::xxx::per-object-slot::ref" ? {nsf::var::get ::xxx::per-object-slot::ref manager} "::xxx::per-object-slot::ref" ? {nsf::var::get ::xxx::per-object-slot::ref domain} "::xxx" #puts [xxx serialize -target XXX] # # Create a serialized object, which has the target mapped to # XXX. The target name has intentionally no leading colons, such # that the object can be instantiated in a different namespace. This # is for example useful when importing objects in OpenACS from a # different system, where one has to assure that the imported # objects do not clash with the already existing objects, but it has # as well certain dangers. # set code [xxx serialize -target XXX] # # Create the object with the new target # set result [eval $code] ? [list set _ $result] ::XXX::per-object-slot::ref # # The target object of the forwarder + the slot manager and domain are mapped as well. # Otherwise, we would trigger warnings during destroy # ? {nsf::method::forward::property ::XXX -per-object ref target} "XXX::per-object-slot::ref" ? {nsf::var::get ::XXX::per-object-slot::ref manager} "XXX::per-object-slot::ref" ? {nsf::var::get ::XXX::per-object-slot::ref domain} "XXX" } nx::test case deepSerialize-map-filter { Object create ::a { :object property -accessor public ref:object,type=[:info class] Object create [self]::b { [:info parent] ref set [Object create [self]::c] } } ? {::nsf::object::exists ::a} 1 ? {::nsf::object::exists ::a::b} 1 ? {::nsf::object::exists ::a::b::c} 1 ? {::a ref get} [[::a::b] info children] set script [::Serializer deepSerialize -map {::a::b ::x::y ::a ::x} ::a] # fix collateral damage (TODO: fixme, preprecate me, ...) set script [string map {::nsf::object::xlloc ::nsf::object::alloc} $script] ::a destroy ? {::nsf::object::exists ::a} 0 ? {::nsf::object::exists ::a::b} 0 ? {::nsf::object::exists ::a::b::c} 0 eval $script ? {::nsf::object::exists ::a} 0 ? {::nsf::object::exists ::a::b} 0 ? {::nsf::object::exists ::a::b::c} 0 ? {::nsf::object::exists ::x} 1 ? {::nsf::object::exists ::x::y} 1 ? {::nsf::object::exists ::x::y::c} 1 ? {::x ref get} [::x::y info children] Object create ::a ::x::y::c eval { :object variable parentRef [[:info parent] info parent] } set script [::a eval { ::Serializer deepSerialize -map [list ::x::y [self] ::x [self]] ::x::y::c }] ? {::x::y::c eval {set :parentRef}} ::x ? {::nsf::object::exists ::a::c} 0 eval $script ? {::nsf::object::exists ::a::c} 1 ? {::a::c eval {set :parentRef}} ::a } nx::test case deepSerialize-ignoreVarsRE-filter { nx::Class create C { :object property -accessor public x :object property -accessor public y :property -accessor public a:int :property -accessor public b:int :create c1 } ? {C x set 1} 1 ? {C x get} 1 ? {C y set 1} 1 ? {C y get} 1 ? {lsort [C info methods]} "a b" ? {lsort [C info object methods]} "x y" ? {c1 a set b} {expected integer but got "b" for parameter "value"} ? {c1 a set 1} 1 ? {c1 b set 1} 1 set c1(IgnoreNone1) [list [::Serializer deepSerialize c1] "a b"] set c1(IgnoreNone2) [list [::Serializer deepSerialize -ignoreVarsRE "" c1] "a b"] set c1(One) [list [::Serializer deepSerialize -ignoreVarsRE "a" c1] "b"] set c1(One2) [list [::Serializer deepSerialize -ignoreVarsRE {::a$} c1] "b"] set c1(IgnoreAll) [list [::Serializer deepSerialize -ignoreVarsRE "." c1] ""] set names {}; foreach s [C info slots] {lappend names [$s cget -name]} set c1(None2) [list [::Serializer deepSerialize -ignoreVarsRE [join $names |] c1] ""] c1 destroy foreach t [array names c1] { ? {nsf::object::exists c1} 0 lassign $c1($t) script res eval $script ? {nsf::object::exists c1} 1 ? {lsort [c1 info vars]} $res "Object c1 $t" c1 destroy } set C(IgnoreNone1) [list [::Serializer deepSerialize C] "x y"] set C(IgnoreNone2) [list [::Serializer deepSerialize -ignoreVarsRE "" C] "x y"] #set C(One) [list [::Serializer deepSerialize -ignoreVarsRE "x" C] "y"] set C(One2) [list [::Serializer deepSerialize -ignoreVarsRE {::x$} C] "y"] #set C(IgnoreAll) [list [::Serializer deepSerialize -ignoreVarsRE "." C] ""] set names {}; foreach s [C info object slots] {lappend names [$s cget -name]} #set C(None2) [list [::Serializer deepSerialize -ignoreVarsRE [join $names |] C] ""] C destroy foreach t [array names C] { ? {nsf::object::exists C} 0 lassign $C($t) script res #puts stderr "=====C($t)\n$script\n====" eval $script ? {nsf::object::exists C} 1 ? {lsort [C info vars]} $res "Class C $t" C destroy } } nx::test case deepSerialize-ignore-filter { Object create ::a { Object create [self]::b Object create [self]::c } ? {::nsf::object::exists ::a} 1 ? {::nsf::object::exists ::a::b} 1 ? {::nsf::object::exists ::a::c} 1 set script [::Serializer deepSerialize -ignore ::a::b ::a] ::a destroy ? {::nsf::object::exists ::a::c} 0 ? {::nsf::object::exists ::a::b} 0 ? {::nsf::object::exists ::a} 0 eval $script ? {::nsf::object::exists ::a} 1 ? {::nsf::object::exists ::a::b} 0 ? {::nsf::object::exists ::a::c} 1 set script [::Serializer deepSerialize -ignore ::a ::a] ::a destroy ? {::nsf::object::exists ::a} 0 eval $script ? {::nsf::object::exists ::a} 0 } nx::test case serialize-slotContainer { nx::Class create C { :object property x :property a } ? {::nsf::object::exists ::C::slot} 1 ? {::nsf::object::exists ::C::per-object-slot} 1 ? {::nx::isSlotContainer ::C::slot} 1 ? {::nx::isSlotContainer ::C::per-object-slot} 1 ? {::nsf::object::exists ::C::slot::a} 1 ? {::nsf::object::exists ::C::per-object-slot::x} 1 ? {::nsf::object::property ::C hasperobjectslots} 1 set script [C serialize] C destroy ? {::nsf::object::exists ::C} 0 eval $script ? {::nsf::object::exists ::C::slot} 1 ? {::nsf::object::exists ::C::per-object-slot} 1 ? {::nx::isSlotContainer ::C::slot} 1 ? {::nx::isSlotContainer ::C::per-object-slot} 1 ? {::nsf::object::exists ::C::slot::a} 1 ? {::nsf::object::exists ::C::per-object-slot::x} 1 ? {::nsf::object::property ::C hasperobjectslots} 1 } # # check whether ::nsf::object::properties keepcallerself and # perobjectdispatch for nx::Objects are handled correctly via serialize # nx::test case serialize-object-properties { # # Check on object o # nx::Object create o ::nsf::object::property ::o keepcallerself 1 ::nsf::object::property ::o perobjectdispatch 1 set script [o serialize] o destroy ? {::nsf::object::exists ::o} 0 eval $script ? {::nsf::object::property ::o keepcallerself} 1 ? {::nsf::object::property ::o perobjectdispatch} 1 # # Now the same for a class # nx::Class create C ::nsf::object::property ::C keepcallerself 1 ::nsf::object::property ::C perobjectdispatch 1 set script [C serialize] C destroy ? {::nsf::object::exists ::C} 0 eval $script ? {::nsf::object::property ::C keepcallerself} 1 ? {::nsf::object::property ::C perobjectdispatch} 1 } # # Check handling of method properties "debug" and "deprecated" # in serializer # nx::test case nx-serialize-debug-deprecated { # # Check on object o # nx::Object create o { :public object method -deprecated ofoo {} {return 1} :public object method -debug obar {} {return 1} :public object alias -deprecated -debug obaz ::nsf::is } ? {::nsf::method::property o ofoo deprecated} 1 ? {::nsf::method::property o ofoo debug} 0 ? {::nsf::method::property o obar deprecated} 0 ? {::nsf::method::property o obar debug} 1 ? {::nsf::method::property o obaz deprecated} 1 ? {::nsf::method::property o obaz debug} 1 set script [o serialize] o destroy ? {::nsf::object::exists ::o} 0 eval $script ? {::nsf::method::property o ofoo deprecated} 1 ? {::nsf::method::property o ofoo debug} 0 ? {::nsf::method::property o obar deprecated} 0 ? {::nsf::method::property o obar debug} 1 ? {::nsf::method::property o obaz deprecated} 1 ? {::nsf::method::property o obaz debug} 1 # # Now the same for a class # nx::Class create C { :public method -deprecated foo {} {return 1} :public method -debug bar {} {return 1} :public alias -deprecated -debug baz ::nsf::is } ? {::nsf::method::property C foo deprecated} 1 ? {::nsf::method::property C foo debug} 0 ? {::nsf::method::property C bar deprecated} 0 ? {::nsf::method::property C bar debug} 1 ? {::nsf::method::property C baz deprecated} 1 ? {::nsf::method::property C baz debug} 1 set script [C serialize] C destroy ? {::nsf::object::exists ::C} 0 eval $script ? {::nsf::method::property C foo deprecated} 1 ? {::nsf::method::property C foo debug} 0 ? {::nsf::method::property C bar deprecated} 0 ? {::nsf::method::property C bar debug} 1 ? {::nsf::method::property C baz deprecated} 1 ? {::nsf::method::property C baz debug} 1 } # # Check serializing of info internals # package require XOTcl package require xotcl::serializer nx::test case xotcl-info-internals { ? {catch {::Serializer methodSerialize ::xotcl::classInfo default ""}} 0 } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/msgcat.test000644 000766 000024 00000004270 13462406127 016521 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package req nx::test package req msgcat ::msgcat::mcset [::msgcat::mclocale] m1 [set ::msg1 "[namespace current] message1"] namespace eval ::foo { ::msgcat::mcset [::msgcat::mclocale] m1 [set ::msg2 "[namespace current] message2"] } namespace eval ::foo::bar { ::msgcat::mcset [::msgcat::mclocale] m1 [set ::msg3 "[namespace current] message3"] } namespace import ::msgcat::mc nx::Class create C { :require namespace ? [list set _ [mc m1]] $::msg1 :public method foo {} { return [mc m1] } :public object method bar {} { return [mc m1] } :property baz { :public object method value=get {args} { return [namespace current]-[mc m1] } } } ? {[::C new] foo} $::msg1 ? {::C bar} $::msg1 ? {[::C new] cget -baz} "::C::slot-$::msg1" namespace eval ::foo { nx::Class create C { :require namespace ? [list set _ [mc m1]] $::msg2 :public method foo {} { return [mc m1] } :public object method bar {} { return [mc m1] } :property baz { :public object method value=get {args} { return [namespace current]-[mc m1] } } } ? {[::foo::C new] foo} $::msg2 ? {::foo::C bar} $::msg2 ? {[::foo::C new] cget -baz} "::foo::C::slot-$::msg2" } namespace eval ::foo::bar { nx::Class create C { :require namespace ? [list set _ [mc m1]] $::msg3 :public method foo {} { return [mc m1] } :public object method bar {} { return [mc m1] } :property baz { :public object method value=get {args} { return [namespace current]-[mc m1] } } :property -accessor public baf { :public object method value=set {obj prop value} { ::msgcat::mcset [::msgcat::mclocale] $value [set ::msg4 "[namespace current] message4"] next } :public object method value=get {args} { mc [next] } } :create ::c } ? {[::foo::bar::C new] foo} $::msg3 ? {::foo::bar::C bar} $::msg3 ? {[::foo::bar::C new] cget -baz} "::foo::bar::C::slot-$::msg3" ::c baf set m1 ? {::c baf get} $::msg4 } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: # ./nsf2.4.0/tests/properties.test000644 000766 000024 00000111744 13510572374 017446 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package req nx::test # # make sure, the defaultAccessor is "none" # #puts stderr "*** default defaultAccessor '[nx::configure defaultAccessor]'" nx::configure defaultAccessor none ##################################################################### # class-level properties ##################################################################### # # Test class-level properties and variables without -incremental # nx::test case class-level { nx::Class create C { :property {a a1} :property -accessor public {b b1} :property -accessor protected {c c1} :property -accessor private {d d1} :property -accessor none {e e1} :variable va va1 :variable -accessor public vb vb1 :variable -accessor protected vc vc1 :variable -accessor private vd vd1 :variable -accessor none ve ve1 # a non-configurable property is a variable :property -accessor none -configurable false {vf vf1} :public method call-local {v} {: -local $v get} :create c1 } # # just the public properties are accessible via the configure interface # ? {c1 info lookup syntax configure} {?-e /value/? ?-a /value/? ?-b /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?} ? {lsort [C info slots]} "::C::slot::____C.d ::C::slot::____C.vd ::C::slot::a ::C::slot::b ::C::slot::c ::C::slot::e ::C::slot::va ::C::slot::vb ::C::slot::vc ::C::slot::ve ::C::slot::vf" ? {::C::slot::a definition} "::C property -accessor none {a a1}" ? {::C::slot::b definition} "::C property -accessor public {b b1}" ? {::C::slot::c definition} "::C variable -accessor protected c c1" ? {::C::slot::____C.d definition} "::C variable -accessor private d d1" ? {::C::slot::e definition} "::C property -accessor none {e e1}" ? {::C::slot::va definition} "::C variable -accessor none va va1" ? {::C::slot::vb definition} "::C variable -accessor public vb vb1" ? {::C::slot::vc definition} "::C variable -accessor protected vc vc1" ? {::C::slot::____C.vd definition} "::C variable -accessor private vd vd1" ? {::C::slot::ve definition} "::C variable -accessor none ve ve1" ? {::C::slot::vf definition} "::C variable -accessor none vf vf1" ? {c1 cget -a} a1 ? {c1 cget -b} b1 ? {c1 cget -c} "cget: unknown configure parameter -c" ? {c1 cget -d} "cget: unknown configure parameter -d" ? {c1 cget -va} "cget: unknown configure parameter -va" ? {c1 cget -vb} "cget: unknown configure parameter -vb" ? {c1 cget -vc} "cget: unknown configure parameter -vc" ? {c1 cget -vd} "cget: unknown configure parameter -vd" ? {c1 cget -ve} "cget: unknown configure parameter -ve" ? {c1 cget -vf} "cget: unknown configure parameter -vf" # # No incremental used, so "a" and "e" have no slots # ? {c1 info lookup method a} "" ? {c1 info lookup method b} "::nsf::classes::C::b" ? {c1 info lookup method c} "::nsf::classes::C::c" ? {c1 info lookup method d} "::nsf::classes::C::d" ? {c1 info lookup method e} "" ? {c1 info lookup method f} "" ? {c1 info lookup method va} "" ? {c1 info lookup method vb} "::nsf::classes::C::vb" ? {c1 info lookup method vc} "::nsf::classes::C::vc" ? {c1 info lookup method vd} "::nsf::classes::C::vd" ? {c1 info lookup method ve} "" ? {c1 info lookup method vf} "" # # Check protection of accessors # ? {nsf::method::property C b call-protected} 0 ? {nsf::method::property C c call-protected} 1 ? {nsf::method::property C d call-protected} 1 ? {nsf::method::property C vb call-protected} 0 ? {nsf::method::property C vc call-protected} 1 ? {nsf::method::property C vd call-protected} 1 ? {nsf::method::property C b call-private} 0 ? {nsf::method::property C c call-private} 0 ? {nsf::method::property C d call-private} 1 ? {nsf::method::property C vb call-private} 0 ? {nsf::method::property C vc call-private} 0 ? {nsf::method::property C vd call-private} 1 # # do we have variables set? # ? {c1 eval "info exists :a"} 1 ? {c1 eval "info exists :b"} 1 ? {c1 eval "info exists :c"} 1 ? {c1 eval "info exists :d"} 0 ? {c1 eval "info exists :va"} 1 ? {c1 eval "info exists :vb"} 1 ? {c1 eval "info exists :vc"} 1 ? {c1 eval "info exists :vd"} 0 ? {c1 eval "info exists :ve"} 1 ? {c1 eval "info exists :vf"} 1 # # can we call the accessor directly or via "eval" # ? {c1 a} {::c1: unable to dispatch method 'a'} ? {c1 b get} b1 ? {c1 c} {::c1: unable to dispatch method 'c'} ? {c1 d} {::c1: unable to dispatch method 'd'} ? {c1 eval ":a"} {::c1: unable to dispatch method 'a'} ? {c1 eval ":b get"} b1 ? {c1 eval ":c get"} c1 ? {c1 eval ":d"} {::c1: unable to dispatch method 'd'} ? {c1 va} {::c1: unable to dispatch method 'va'} ? {c1 vb get} vb1 ? {c1 vc} {::c1: unable to dispatch method 'vc'} ? {c1 vd} {::c1: unable to dispatch method 'vd'} ? {c1 eval ":va"} {::c1: unable to dispatch method 'va'} ? {c1 eval ":vb get"} vb1 ? {c1 eval ":vc get"} vc1 ? {c1 eval ":vd"} {::c1: unable to dispatch method 'vd'} # # check the behavior of "private" properties and variables # ? {c1 call-local d} d1 ? {c1 call-local vd} vd1 ? {lsort [c1 info vars]} "__private a b c e va vb vc ve vf" ? {c1 eval "array get :__private"} "::C,vd vd1 ::C,d d1" # # check incremental operations for properties (should fail in all # cases) # set unknowns "valid are: {assign definition destroy get getParameterSpec getPropertyDefinitionOptions onError parameter reconfigure setCheckedInstVar}" ? {c1 b add x} {property b of ::C is not multivalued} #? {c1 b add x} "method 'add' unknown for slot ::C::slot::b; $unknowns" ? {c1 c add x} {::c1: unable to dispatch method 'c'} ? {c1 eval {:c add x}} {property c of ::C is not multivalued} #? {c1 eval {:c add x}} "method 'add' unknown for slot ::C::slot::c; $unknowns" ? {c1 d add x} {::c1: unable to dispatch method 'd'} ? {c1 eval {:d add x}} {::c1: unable to dispatch method 'd'} ? {c1 e add x} {::c1: unable to dispatch method 'e'} # # check incremental operations for variables (should fail in all # cases) # ? {c1 va add x} {::c1: unable to dispatch method 'va'} ? {c1 vb add x} {property vb of ::C is not multivalued} #? {c1 vb add x} "method 'add' unknown for slot ::C::slot::vb; $unknowns" ? {c1 vc add x} {::c1: unable to dispatch method 'vc'} ? {c1 eval {:vc add x}} {property vc of ::C is not multivalued} #? {c1 eval {:vc add x}} "method 'add' unknown for slot ::C::slot::vc; $unknowns" ? {c1 vd add x} {::c1: unable to dispatch method 'vd'} ? {c1 eval {:vd add x}} {::c1: unable to dispatch method 'vd'} ? {c1 ve add x} {::c1: unable to dispatch method 've'} # # The accessor should be a setter due to incremental # ? {C info method definition b} {::C public forward b -prefix value= ::C::slot::b %1 %self b} # # check error message on a typo. The following command does a # recreate. # ? {C property -accessor proceted {b b1}} {accessor value 'proceted' invalid; might be one of public|protected|private or none} # # The accessor is deleted due to the error # ? {C info method definition b} {} } # # test class-level properties and variables with -incremental # nx::test case class-level-incremental { nx::Class create CC { :property -incremental {a a1} :property -accessor public -incremental {b b1} :property -accessor protected -incremental {c c1} :property -accessor private -incremental {d d1} :property -accessor none -incremental {e e1} :variable -incremental va va1 :variable -accessor public -incremental vb vb1 :variable -accessor protected -incremental vc vc1 :variable -accessor private -incremental vd vd1 :variable -accessor none -incremental ve ve1 :public method call-local {v} {: -local $v get} :public method add-local {var value} {: -local $var add $value} :create c1 } # # The use of "-incremental" implies multivalued # ? {c1 info lookup syntax configure} {?-e /value .../? ?-a /value .../? ?-b /value .../? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?} ? {c1 cget -a} a1 ? {c1 cget -b} b1 ? {c1 cget -c} "cget: unknown configure parameter -c" ? {c1 cget -d} "cget: unknown configure parameter -d" ? {c1 cget -va} "cget: unknown configure parameter -va" ? {c1 cget -vb} "cget: unknown configure parameter -vb" ? {c1 cget -vc} "cget: unknown configure parameter -vc" ? {c1 cget -vd} "cget: unknown configure parameter -vd" # # The use of "-incremental" implies an accessor # ? {c1 info lookup method a} "::nsf::classes::CC::a" ;# forcing accessor ? {c1 info lookup method b} "::nsf::classes::CC::b" ? {c1 info lookup method c} "::nsf::classes::CC::c" ? {c1 info lookup method d} "::nsf::classes::CC::d" ? {c1 info lookup method va} "::nsf::classes::CC::va" ;# forcing accessor ? {c1 info lookup method vb} "::nsf::classes::CC::vb" ? {c1 info lookup method vc} "::nsf::classes::CC::vc" ? {c1 info lookup method vd} "::nsf::classes::CC::vd" # # The use of "-incremental" implies an accessor, which is public # ? {nsf::method::property CC a call-protected} 0 ? {nsf::method::property CC b call-protected} 0 ? {nsf::method::property CC c call-protected} 1 ? {nsf::method::property CC d call-protected} 1 ? {nsf::method::property CC va call-protected} 0 ? {nsf::method::property CC vb call-protected} 0 ? {nsf::method::property CC vc call-protected} 1 ? {nsf::method::property CC vd call-protected} 1 ? {nsf::method::property CC a call-private} 0 ? {nsf::method::property CC b call-private} 0 ? {nsf::method::property CC c call-private} 0 ? {nsf::method::property CC d call-private} 1 ? {nsf::method::property CC va call-private} 0 ? {nsf::method::property CC vb call-private} 0 ? {nsf::method::property CC vc call-private} 0 ? {nsf::method::property CC vd call-private} 1 # # do we have variables set? # ? {c1 eval "info exists :a"} 1 ? {c1 eval "info exists :b"} 1 ? {c1 eval "info exists :c"} 1 ? {c1 eval "info exists :d"} 0 ? {c1 eval "info exists :va"} 1 ? {c1 eval "info exists :vb"} 1 ? {c1 eval "info exists :vc"} 1 ? {c1 eval "info exists :vd"} 0 # # can we call the accessor directly or via "eval" # ? {c1 a get} a1 ? {c1 b get} b1 ? {c1 c} {::c1: unable to dispatch method 'c'} ? {c1 d} {::c1: unable to dispatch method 'd'} ? {c1 eval ":a get"} a1 ? {c1 eval ":b get"} b1 ? {c1 eval ":c get"} c1 ? {c1 eval ":d"} {::c1: unable to dispatch method 'd'} ? {c1 va get} va1 ? {c1 vb get} vb1 ? {c1 vc} {::c1: unable to dispatch method 'vc'} ? {c1 vd} {::c1: unable to dispatch method 'vd'} ? {c1 eval ":va get"} va1 ? {c1 eval ":vb get"} vb1 ? {c1 eval ":vc get"} vc1 ? {c1 eval ":vd get"} {::c1: unable to dispatch method 'vd'} # # check the behavior of "private" properties and variables # ? {c1 call-local d} d1 ? {c1 call-local vd} vd1 ? {lsort [c1 info vars]} "__private a b c e va vb vc ve" ? {c1 eval "array get :__private"} "::CC,vd vd1 ::CC,d d1" # # check incremental operations for properties # ? {c1 a add x} {x a1} ? {c1 b add x} {x b1} ? {c1 c add x} {::c1: unable to dispatch method 'c'} ? {c1 eval {:c add x}} {x c1} ? {c1 d add x} {::c1: unable to dispatch method 'd'} ? {c1 eval {:d add x}} {::c1: unable to dispatch method 'd'} ? {c1 add-local d x} {x d1} ? {c1 e add x} {x e1} ? {c1 e delete x} {e1} ? {c1 e get} {e1} ? {c1 e delete -nocomplain x} {e1} ? {c1 e delete x} "::c1: 'x' is not in variable 'e' (values are: 'e1')" ? {c1 e delete -nocomplain e1} "" ? {c1 e get} "" ? {c1 e unset} "" ? {c1 e get} {can't read "e": no such variable} # # check incremental operations for variables # ? {c1 va add x} {x va1} ? {c1 vb add x} {x vb1} ? {c1 vc add x} {::c1: unable to dispatch method 'vc'} ? {c1 eval {:vc add x}} {x vc1} ? {c1 vd add x} {::c1: unable to dispatch method 'vd'} ? {c1 eval {:vd add x}} {::c1: unable to dispatch method 'vd'} ? {c1 add-local vd x} {x vd1} ? {c1 ve add x} {x ve1} ? {c1 ve delete x} {ve1} ? {c1 ve get} {ve1} ? {c1 ve delete -nocomplain x} {ve1} ? {c1 ve delete x} "::c1: 'x' is not in variable 've' (values are: 've1')" ? {c1 ve delete -nocomplain ve1} "" ? {c1 ve get} "" ? {c1 ve unset} "" ? {c1 ve get} {can't read "ve": no such variable} # # The accessor should be a forwarder due to incremental # ? {CC info method definition b} {::CC public forward b -prefix value= ::CC::slot::b %1 %self b} # # check error message # ? {CC property -accessor proceted -incremental {b b1}} {accessor value 'proceted' invalid; might be one of public|protected|private or none} # # The accessor is deleted due to the error # ? {CC info method definition b} {} } ##################################################################### # object-level properties ##################################################################### # # Test object-level properties and variables without -incremental # nx::test case object-level { nx::Object create o1 { :object property {a a1} :object property -accessor public {b b1} :object property -accessor protected {c c1} :object property -accessor private {d d1} :object property -accessor none {e e1} :object variable va va1 :object variable -accessor public vb vb1 :object variable -accessor protected vc vc1 :object variable -accessor private vd vd1 :object variable -accessor none ve ve1 :public object method call-local {v} {: -local $v get} } # # check the slot for "a" # ? {o1 info lookup slots a} ::o1::per-object-slot::a # # just the public properties are accessible via the configure interface # ? {o1 info lookup syntax configure} {?-e /value/? ?-a /value/? ?-b /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?} # # just the public properties are accessible via the cget interface # ? {o1 cget -a} a1 ? {o1 cget -b} b1 ? {o1 cget -c} {cget: unknown configure parameter -c} ? {o1 cget -d} {cget: unknown configure parameter -d} ? {o1 cget -va} {cget: unknown configure parameter -va} ? {o1 cget -vb} {cget: unknown configure parameter -vb} ? {o1 cget -vc} {cget: unknown configure parameter -vc} ? {o1 cget -vd} {cget: unknown configure parameter -vd} # # We do not have accessors in the default case and in the explicit "none" case. # ? {o1 info lookup method a} "" ? {o1 info lookup method b} "::o1::b" ? {o1 info lookup method c} "::o1::c" ? {o1 info lookup method d} "::o1::d" ? {o1 info lookup method e} "" ? {o1 info lookup method va} "" ? {o1 info lookup method vb} "::o1::vb" ? {o1 info lookup method vc} "::o1::vc" ? {o1 info lookup method vd} "::o1::vd" ? {o1 info lookup method ve} "" # # check public/protected/private settings # ? {nsf::method::property o1 b call-protected} 0 ? {nsf::method::property o1 c call-protected} 1 ? {nsf::method::property o1 d call-protected} 1 ? {nsf::method::property o1 vb call-protected} 0 ? {nsf::method::property o1 vc call-protected} 1 ? {nsf::method::property o1 vd call-protected} 1 ? {nsf::method::property o1 b call-private} 0 ? {nsf::method::property o1 c call-private} 0 ? {nsf::method::property o1 d call-private} 1 ? {nsf::method::property o1 vb call-private} 0 ? {nsf::method::property o1 vc call-private} 0 ? {nsf::method::property o1 vd call-private} 1 # # check if instance variables are created # ? {o1 eval "info exists :a"} 1 ? {o1 eval "info exists :b"} 1 ? {o1 eval "info exists :c"} 1 ? {o1 eval "info exists :d"} 0 ? {o1 eval "info exists :e"} 1 ? {o1 eval "info exists :va"} 1 ? {o1 eval "info exists :vb"} 1 ? {o1 eval "info exists :vc"} 1 ? {o1 eval "info exists :vd"} 0 ? {o1 eval "info exists :ve"} 1 # # check if we can dispatch accessors directly or via "eval" # ? {o1 a} {::o1: unable to dispatch method 'a'} ? {o1 b get} b1 ? {o1 c} {::o1: unable to dispatch method 'c'} ? {o1 d} {::o1: unable to dispatch method 'd'} ? {o1 eval ":a"} {::o1: unable to dispatch method 'a'} ? {o1 eval ":b get"} b1 ? {o1 eval ":c get"} c1 ? {o1 eval ":d"} {::o1: unable to dispatch method 'd'} ? {o1 va} {::o1: unable to dispatch method 'va'} ? {o1 vb get} vb1 ? {o1 vc} {::o1: unable to dispatch method 'vc'} ? {o1 vd} {::o1: unable to dispatch method 'vd'} ? {o1 eval ":va"} {::o1: unable to dispatch method 'va'} ? {o1 eval ":vb get"} vb1 ? {o1 eval ":vc get"} vc1 ? {o1 eval ":vd"} {::o1: unable to dispatch method 'vd'} # # check dispatch of private accessors and private variables # ? {o1 call-local d} d1 ? {o1 call-local vd} vd1 ? {lsort [o1 info vars]} "__private a b c e va vb vc ve" ? {o1 eval "array get :__private"} "::o1,d d1 ::o1,vd vd1" # # check error message # ? {o1 object property -accessor proceted {b b1}} {accessor value 'proceted' invalid; might be one of public|protected|private or none} } # # test object-level properties and variables with -incremental # nx::test case object-level-incremental { nx::Object create o1 { :object property -incremental {a a1} :object property -accessor public -incremental {b b1} :object property -accessor protected -incremental {c c1} :object property -accessor private -incremental {d d1} :object property -accessor none -incremental {e e1} :object variable -incremental va va1 :object variable -accessor public -incremental vb vb1 :object variable -accessor protected -incremental vc vc1 :object variable -accessor private -incremental vd vd1 :object variable -accessor none -incremental ve ve1 :public object method call-local {v} {: -local $v get} :public object method add-local {var value} {: -local $var add $value} } # # The use of "-incremental" implies multivalued # ? {o1 info lookup syntax configure} {?-e /value .../? ?-a /value .../? ?-b /value .../? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?} ? {o1 cget -a} a1 ? {o1 cget -b} b1 ? {o1 cget -c} {cget: unknown configure parameter -c} ? {o1 cget -d} {cget: unknown configure parameter -d} ? {o1 cget -va} {cget: unknown configure parameter -va} ? {o1 cget -vb} {cget: unknown configure parameter -vb} ? {o1 cget -vc} {cget: unknown configure parameter -vc} ? {o1 cget -vd} {cget: unknown configure parameter -vd} # # The use of "-incremental" implies an accessor # ? {o1 info lookup method a} "::o1::a" ;# forcing accessor ? {o1 info lookup method b} "::o1::b" ? {o1 info lookup method c} "::o1::c" ? {o1 info lookup method d} "::o1::d" ? {o1 info lookup method va} "::o1::va" ;# forcing accessor ? {o1 info lookup method vb} "::o1::vb" ? {o1 info lookup method vc} "::o1::vc" ? {o1 info lookup method vd} "::o1::vd" # # The use of "-incremental" implies an accessor, which is public # ? {nsf::method::property o1 a call-protected} 0 ? {nsf::method::property o1 b call-protected} 0 ? {nsf::method::property o1 c call-protected} 1 ? {nsf::method::property o1 d call-protected} 1 ? {nsf::method::property o1 va call-protected} 0 ? {nsf::method::property o1 vb call-protected} 0 ? {nsf::method::property o1 vc call-protected} 1 ? {nsf::method::property o1 vd call-protected} 1 ? {nsf::method::property o1 a call-private} 0 ? {nsf::method::property o1 b call-private} 0 ? {nsf::method::property o1 c call-private} 0 ? {nsf::method::property o1 d call-private} 1 ? {nsf::method::property o1 va call-private} 0 ? {nsf::method::property o1 vb call-private} 0 ? {nsf::method::property o1 vc call-private} 0 ? {nsf::method::property o1 vd call-private} 1 # # do we have variables set? # ? {o1 eval "info exists :a"} 1 ? {o1 eval "info exists :b"} 1 ? {o1 eval "info exists :c"} 1 ? {o1 eval "info exists :d"} 0 ? {o1 eval "info exists :va"} 1 ? {o1 eval "info exists :vb"} 1 ? {o1 eval "info exists :vc"} 1 ? {o1 eval "info exists :vd"} 0 # # can we call the accessor directly or via "eval" # ? {o1 a get} a1 ? {o1 b get} b1 ? {o1 c} {::o1: unable to dispatch method 'c'} ? {o1 d} {::o1: unable to dispatch method 'd'} ? {o1 eval ":a get"} a1 ? {o1 eval ":b get"} b1 ? {o1 eval ":c get"} c1 ? {o1 eval ":d"} {::o1: unable to dispatch method 'd'} ? {o1 va get} va1 ? {o1 vb get} vb1 ? {o1 vc} {::o1: unable to dispatch method 'vc'} ? {o1 vd} {::o1: unable to dispatch method 'vd'} ? {o1 eval ":va get"} va1 ? {o1 eval ":vb get"} vb1 ? {o1 eval ":vc get"} vc1 ? {o1 eval ":vd"} {::o1: unable to dispatch method 'vd'} # # check the behavior of "private" properties and variables # ? {o1 call-local d} d1 ? {o1 call-local vd} vd1 ? {lsort [o1 info vars]} "__private a b c e va vb vc ve" ? {o1 eval "array get :__private"} "::o1,d d1 ::o1,vd vd1" # # check incremental operations for properties # ? {o1 a add x} {x a1} ? {o1 b add x} {x b1} ? {o1 c add x} {::o1: unable to dispatch method 'c'} ? {o1 eval {:c add x}} {x c1} ? {o1 d add x} {::o1: unable to dispatch method 'd'} ? {o1 eval {:d add x}} {::o1: unable to dispatch method 'd'} ? {o1 add-local d x} {x d1} ? {o1 e add x} {x e1} # # check incremental operations for variables # ? {o1 va add x} {x va1} ? {o1 vb add x} {x vb1} ? {o1 vc add x} {::o1: unable to dispatch method 'vc'} ? {o1 eval {:vc add x}} {x vc1} ? {o1 vd add x} {::o1: unable to dispatch method 'vd'} ? {o1 eval {:vd add x}} {::o1: unable to dispatch method 'vd'} ? {o1 add-local vd x} {x vd1} ? {o1 ve add x} {x ve1} # # The accessor should be a forwarder due to incremental # ? {o1 info object method definition b} {::o1 public object forward b -prefix value= ::o1::per-object-slot::b %1 %self b} # # check error message # ? {o1 object property -accessor proceted {b b1}} {accessor value 'proceted' invalid; might be one of public|protected|private or none} # # The accessor is deleted due to the error # ? {o1 info object method definition b} {} } # # Tests for experimental "value add", "value assign" ... # # nx::test case property-value-incremental { # nx::Object create o1 { # :object property -incremental {a a1} # } # ? {o1 a add x} {x a1} # ? {o1 a assign {a1}} {a1} # nsf::configure debug 2 # ? {o1 a value add x } {x a1} # ? {o1 a value assign {a b c}} {a b c} # ? {o1 a value get } {a b c} # ? {o1 a value add x } {x a b c} # ? {o1 a value add z end} {x a b c z} # } # # Test interactions between multiplicity and incremental # nx::test case property-incremental-multiplicity { nx::Object create o1 { :object property -incremental a:integer,0..n :object property -incremental b:integer,1..n :object property -incremental c:integer,0..1 :object property -incremental d:integer,1..1 } ? {o1 info object slots a} "::o1::per-object-slot::a" ? {[o1 info object slots a] eval {set :multiplicity}} "0..n" ? {[o1 info object slots b] eval {set :multiplicity}} "1..n" ? {[o1 info object slots c] eval {set :multiplicity}} "0..n" ? {[o1 info object slots d] eval {set :multiplicity}} "1..n" ? {o1 info variable definition [o1 info object variables a]} \ "::o1 object property -accessor public -incremental a:integer,0..n" ? {o1 info variable definition [o1 info object variables b]} \ "::o1 object property -accessor public -incremental b:integer,1..n" ? {o1 info variable definition [o1 info object variables c]} \ "::o1 object property -accessor public -incremental c:integer,0..n" ? {o1 info variable definition [o1 info object variables d]} \ "::o1 object property -accessor public -incremental d:integer,1..n" ? {o1 a set {1 2 3}} {1 2 3} ? {o1 b set {1 2 3}} {1 2 3} ? {o1 a set ""} {} ? {o1 b set ""} {invalid value for parameter 'value': list is not allowed to be empty} ? {o1 c set ""} {} ? {o1 d set ""} {invalid value for parameter 'value': list is not allowed to be empty} } ##################################################################### # tests with class object ##################################################################### # # check performance of class-level configure and cget # nx::test case class-object-properties { nx::Class create C { :property {a a1} :variable va va1 :object property {b b1} :object variable vb b1 :create c1 } # # just the public properties are accessible via the configure interface # ? {c1 info lookup syntax configure} {?-a /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?} ? {c1 cget -a} a1 ? {c1 configure -a a2} "" ? {C info lookup syntax configure} {?-b /value/? ?-mixins /mixinreg .../? ?-superclasses /class .../? ?-filters /filterreg .../? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?} ? {C cget -b} b1 ? {C configure -b b2} "" ? {C cget -b} b2 } nx::test case exists-on-props { nx::Class create C { :object property {A A1} :property {a a1} :object property -accessor public {B B1} :property -accessor public {b b1} :object property -accessor public BB :property -accessor public bb :object property -accessor protected {C C1} :property -accessor protected {c c1} :object property -accessor private {D D1} :property -accessor private {d d1} :create c1 :public object method do {args} { : {*}$args } :public method do {args} { : {*}$args } :public object method doLocal {args} { : -local {*}$args } :public method doLocal {args} { : -local {*}$args } } ? {::C A exists} \ "method 'A' unknown for ::C; in order to create an instance of class ::C, consider using '::C create A ?...?'" ? {::c1 a exists} "::c1: unable to dispatch method 'a'" ? {::C B exists} 1 ? {::c1 b exists} 1 ? {::C B get} "B1" ? {::c1 b get} "b1" ? {::C BB exists} 0 ? {::c1 bb exists} 0 ? {::C do C exists} 1 ? {::C eval {info exists :C}} 1 ? {::c1 do c exists} 1 ? {::c1 eval {info exists :c}} 1 ? {::C do C unset} "" ? {::c1 do c unset} "" ? {::C do C exists} 0 ? {::C eval {info exists :C}} 0 ? {::c1 do c exists} 0 ? {::c1 eval {info exists :c}} 0 # interaction: exists + private ? {::C doLocal D exists} 1 ? {::c1 doLocal d exists} 1 ? {::C doLocal D unset} "" ? {::c1 doLocal d unset} "" ? {::C doLocal D exists} 0 ? {::c1 doLocal d exists} 0 ? {::C D exists} \ "method 'D' unknown for ::C; in order to create an instance of class ::C, consider using '::C create D ?...?'" ? {::c1 d exists} "::c1: unable to dispatch method 'd'" } ##################################################################### # performance tests ##################################################################### nx::test configure -count 10000 # # check performance of class-level configure and cget # nx::test case class-level-perf { nx::Class create C { :property {a a1} :property -accessor public {b b1} :property -accessor protected {c c1} :property -accessor private {d d1} :property -accessor none {e e1} :variable va va1 :variable -accessor public vb vb1 :variable -accessor protected vc vc1 :variable -accessor private vd vd1 :variable -accessor none ve ve1 :create c1 } nx::Class create D { :object property {cp 101} :property {a a1} :property -accessor public {b b1} :property -accessor protected {c c1} :property -accessor private {d d1} :property -accessor none {e e1} :variable va va1 :variable -accessor public vb vb1 :variable -accessor protected vc vc1 :variable -accessor private vd vd1 :variable -accessor none ve ve1 :create d1 } # # just the public properties are accessible via the configure interface # package require nx::volatile ? {c1 info lookup syntax configure} {?-e /value/? ?-a /value/? ?-b /value/? ?-volatile? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?} set e [C eval :__object_configureparameter] ? {C eval :__object_configureparameter} $e ? {c1 cget -a} a1 ? {c1 configure -a a2} "" ? {C configure -class ::nx::Class} "" ? {C cget -class} ::nx::Class ? {C cget -mixin} "" ? {C cget -filter} "" # ? {C cget -noinit} 0 ? {C cget -volatile} 0 # # check influence of class-level per-object properties # ? {d1 info lookup syntax configure} {?-e /value/? ?-a /value/? ?-b /value/? ?-volatile? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?} set e [D eval :__object_configureparameter] ? {D eval :__object_configureparameter} $e ? {d1 cget -a} a1 ? {d1 configure -a a2} "" ? {D configure -class ::nx::Class} "" ? {D cget -class} ::nx::Class ? {D cget -cp} 101 ? {D configure -cp 102} "" ? {D cget -cp} 102 } # # check performance of class-level configure and cget # nx::test case object-level-perf { nx::Object create o1 { :object property {a a1} :object property -accessor public {b b1} :object property -accessor protected {c c1} :object property -accessor private {d d1} :object property -accessor none {e e1} :object variable va va1 :object variable -accessor public vb vb1 :object variable -accessor protected vc vc1 :object variable -accessor private vd vd1 :object variable -accessor none ve ve1 } # # just the public properties are accessible via the configure interface # ? {o1 info lookup syntax configure} {?-e /value/? ?-a /value/? ?-b /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?} set e [o1 eval :__object_configureparameter] ? {o1 eval :__object_configureparameter} $e ? {o1 cget -a} a1 ? {o1 configure -a a2} "" ? {o1 b get} b1 ? {o1 b set b2} "b2" ? {o1 configure -class ::nx::Object} "" ? {o1 cget -class} ::nx::Object } nx::test case extend-parent-class-info { nx::Class create Foo nx::Class create Bar -superclass Foo ? {llength [Bar info lookup parameters create]} 5 # # extend the superclass, subclass should become aware of this # Foo property y ? {llength [Bar info lookup parameters create]} 6 } nx::test case extend-parent-class-info-cache { nx::Class create Foo nx::Class create Bar -superclass Foo ? {llength [Bar info lookup parameters create]} 5 # # Let Bar cache the objectparameters, and extend later the # superclass # Bar new Foo property y ? {llength [Bar info lookup parameters create]} 6 } nx::test case extend-parent-class-info-cache-configure { nx::Class create Foo nx::Class create Bar -superclass Foo ? {llength [Bar info lookup parameters create]} 5 # # Let Bar cache the objectparameters, and extend later the # superclass # Bar create b1 Foo property y # access objectparameter indirectly via configure ? {b1 configure -y 2} "" } nx::test case extend-class-mixin-info { nx::Class create Baz nx::Class create Foo -mixin Baz nx::Class create Bar -mixin Foo Bar create bar; # cache becomes hot! ? {llength [Bar info lookup parameters create]} 5 Foo property y ? {llength [Bar info lookup parameters create]} 6 Baz property z ? {llength [Bar info lookup parameters create]} 7 Baz delete property z ? {llength [Bar info lookup parameters create]} 6 Foo delete property y ? {llength [Bar info lookup parameters create]} 5 } nx::test case extend-class-mixin-configure { nx::Class create Baz nx::Class create Foo -mixin Baz nx::Class create Bar -mixin Foo Bar create bar; # cache becomes hot! Foo property y bar configure -y 1 ? {bar cget -y} 1 Baz property z bar configure -z 2 ? {bar cget -z} 2 bar configure -y 3 ? {bar cget -y} 3 Bar property w bar configure -w 4 ? {bar cget -w} 4 } nx::test case dynamic-transitive-mixin-info { nx::Class create Foo nx::Class create Bar nx::Class create Baz Bar create bar; # cache object parameters in class Bar Baz create baz; # cache object parameters in class Baz ? {llength [Bar info lookup parameters create]} 5 Foo property y ? {llength [Bar info lookup parameters create]} 5 Bar mixins add Foo ? {llength [Bar info lookup parameters create]} 6 ? {bar configure -y 1} "" ? {llength [Baz info lookup parameters create]} 5 Baz mixins add Bar ? {llength [Baz info lookup parameters create]} 6 Foo property z ? {llength [Baz info lookup parameters create]} 7 ? {baz configure -z 1} "" ? {bar configure -z 1} "" } nx::test configure -count 1 nx::test case indirect-transitive-mixin-info { nx::Class create M0 {:public method foo {} {return M}} nx::Class create M1 -superclass M0 nx::Class create M2 -superclass M1 nx::Class create C {:public method foo {} {return C}} nx::Class create D -superclass C C create c1 D create d1 M0 create m0 M1 create m1 M2 create m2 ? {lmap p [C info lookup parameters create] {nsf::parameter::info name $p}} \ "objectName object-mixins object-filters class __initblock" set base [llength [lmap p [C info lookup parameters create] {nsf::parameter::info name $p}]] ? [list set _ $base] 5 ? {llength [C info lookup parameters create]} $base ? {llength [D info lookup parameters create]} $base ? {llength [M0 info lookup parameters create]} $base ? {llength [M1 info lookup parameters create]} $base ? {llength [M2 info lookup parameters create]} $base M0 property x ? {llength [M0 info lookup parameters create]} [expr {$base + 1}] ? {llength [M1 info lookup parameters create]} [expr {$base + 1}] ? {llength [M2 info lookup parameters create]} [expr {$base + 1}] ? {c1 foo} C ? {d1 foo} C ? {c1 info precedence} "::C ::nx::Object" ? {d1 info precedence} "::D ::C ::nx::Object" ? {C info subclasses -dependent} "::C ::D" ? {C info subclasses -closure} "::C ::D" ? {M0 info subclasses -dependent} "::M0 ::M1 ::M2" ? {M0 info subclasses -closure} "::M0 ::M1 ::M2" #puts stderr =========C-mixin-add-M2 C mixins add M2 #puts stderr ========= ? {c1 foo} M ? {d1 foo} M ? {c1 info precedence} "::M2 ::M1 ::M0 ::C ::nx::Object" ? {d1 info precedence} "::M2 ::M1 ::M0 ::D ::C ::nx::Object" ? {C info heritage} "::M2 ::M1 ::M0 ::nx::Object" ? {D info heritage} "::M2 ::M1 ::M0 ::C ::nx::Object" ? {C info subclasses -dependent} "::C ::D" ? {C info subclasses -closure} "::C ::D" ? {M0 info subclasses -dependent} "::M0 ::M1 ::M2 ::C ::D" ? {M0 info subclasses -closure} "::M0 ::M1 ::M2" # Only M2 is a direct mixin, visible through "mixinof", # but query-able via transitive -closure operator ? {M2 info mixinof} "::C" ? {M2 info mixinof -closure} "::C ::D" ? {M1 info mixinof} "" ? {M1 info mixinof -closure} "::C ::D" ? {M0 info mixinof} "" ? {M0 info mixinof -closure} "::C ::D" ? {lmap p [C info lookup parameters create] {nsf::parameter::info name $p}} \ "objectName x object-mixins object-filters class __initblock" ? {llength [C info lookup parameters create]} [expr {$base + 1}] ? {llength [D info lookup parameters create]} [expr {$base + 1}] #puts stderr =========-M1-property M1 property y #puts stderr ========= ? {C info heritage} "::M2 ::M1 ::M0 ::nx::Object" #::nsf::parameter::cache::classinvalidate ::C ? {lmap p [C info lookup parameters create] {nsf::parameter::info name $p}} \ "objectName y x object-mixins object-filters class __initblock" ? {lmap p [M0 info lookup parameters create] {nsf::parameter::info name $p}} \ "objectName x object-mixins object-filters class __initblock" ? {lmap p [M1 info lookup parameters create] {nsf::parameter::info name $p}} \ "objectName y x object-mixins object-filters class __initblock" ? {llength [C info lookup parameters create]} [expr {$base + 2}] ? {llength [D info lookup parameters create]} [expr {$base + 2}] ? {llength [M0 info lookup parameters create]} [expr {$base + 1}] ? {llength [M1 info lookup parameters create]} [expr {$base + 2}] ? {llength [M2 info lookup parameters create]} [expr {$base + 2}] # clearning the mixin has to reset the orders of the instances of C and D #puts stderr =========C-mixin-clear C mixins clear #puts stderr ========= ? {c1 foo} C ? {d1 foo} C ? {c1 info precedence} "::C ::nx::Object" ? {d1 info precedence} "::D ::C ::nx::Object" } # # See bug report at: # https://groups.google.com/forum/#!topic/comp.lang.tcl/F9cn_Ah4js4 # nx::test case bug-clt-configurable-false-cget { nx::Class create D; D property -configurable false "nix"; D create d; # Provide for a shared parameter name Tcl_Obj, to enable intrep # sharing between "cget" and "configure". The original bug report # ran into the critical path using an interactive shell, with intrep # sharing occurring via literals. set flag "-nix"; catch {d cget $flag} catch {d configure $flag anix} msg opts ? [list string match "invalid non-positional argument '-nix', *" [dict get $opts -errorinfo]] 1 } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/interceptor-slot.test000644 000766 000024 00000047224 13462406127 020566 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx::test nx::Class create M { :method mfoo {} {puts [self proc]} } nx::Class create M2 nx::Class create C C create c1 # # test mixin method # nx::test case mixin-method { ? {C info lookup method mixins} "::nsf::classes::nx::Class::mixins" ? {C mixins set M} ::M ? {C info precedence} "::nx::Class ::nx::Object" ? {C mixins get} "::M" ? {C info mixins} "::M" ? {c1 info precedence} "::M ::C ::nx::Object" ? {C mixins add M2} "::M2 ::M" ? {c1 info precedence} "::M2 ::M ::C ::nx::Object" ? {C mixins delete M2} "::M" ? {c1 info precedence} "::M ::C ::nx::Object" ? {C mixins delete M} "" ? {C info mixins} "" ? {C mixins set ::M} "::M" ? {C mixins clear} "::M" ? {C info mixins} "" ? {C mixins add ::M} "::M" ? {C mixins set {}} "" ? {C info mixins} "" } # # test nsf::mixin interface # nx::test case nsf-mixin { ? {::nsf::mixin C ::M} "::M" ? {C info mixins} "::M" ? {::nsf::mixin C ::M2} "::M2 ::M" ? {C info mixins} "::M2 ::M" ? {::nsf::mixin C ""} "" ? {C info mixins} "" } # # per-object mixins # nx::test case per-object-mixins { ? {c1 info precedence} "::C ::nx::Object" ? {c1 object mixins add M} ::M ? {::nsf::relation::get c1 object-mixin} ::M ? {catch {c1 object mixin UNKNOWN}} 1 ? {::nsf::relation::get c1 object-mixin} "::M" # add again the same mixin ? {c1 object mixins add M} {::M} ? {c1 info precedence} "::M ::C ::nx::Object" ? {c1 object mixins add M2} "::M2 ::M" ? {c1 info precedence} "::M2 ::M ::C ::nx::Object" ? {c1 object mixins delete M} "::M2" ? {c1 info precedence} "::M2 ::C ::nx::Object" ? {c1 object mixins delete M2} "" ? {c1 info precedence} "::C ::nx::Object" ? {c1 object mixins add M} {::M} ? {c1 info object mixins} {::M} ? {c1 object mixins clear} {::M} ? {c1 info object mixins} {} } # # adding, removing per-object mixins for classes through relation # "object-mixin" # nx::test case object-mixin-relation { ? {::nsf::relation::set C object-mixin M} ::M ? {C info precedence} "::M ::nx::Class ::nx::Object" ? {C info object mixins} "::M" ? {::nsf::relation::set C object-mixin ""} "" ? {C info precedence} "::nx::Class ::nx::Object" } # # adding, removing per-object mixins for classes through slot # "object-mixin" # # C object-mixin M # ? {C info precedence} "::M ::nx::Class ::nx::Object" # ? {C info object mixins} "::M" # C object-mixin "" # ? {C info precedence} "::nx::Class ::nx::Object" # # add and remove object mixin for classes via modifier "object" and # "mixin" # nx::test case class+mixin { ? {C object mixins set M} ::M ? {C info precedence} "::M ::nx::Class ::nx::Object" ? {C info object mixins} "::M" ? {C object mixins set ""} "" ? {C info precedence} "::nx::Class ::nx::Object" } # # add and remove object mixin for classes via object mixin add # nx::test case class+mixin-add { ? {C object mixins add M} ::M ? {C info precedence} "::M ::nx::Class ::nx::Object" ? {C info object mixins} "::M" ? {C object mixins set ""} "" ? {C info precedence} "::nx::Class ::nx::Object" ? {C object mixins add M} ::M ? {C info precedence} "::M ::nx::Class ::nx::Object" ? {::nsf::relation::get C object-mixin} ::M ? {catch {C object mixins add UNKNOWN}} 1 ? {::nsf::relation::get C object-mixin} "::M" ? {C object mixins set ""} "" ? {C info precedence} "::nx::Class ::nx::Object" ? {C object mixins set M} ::M ? {C info precedence} "::M ::nx::Class ::nx::Object" # forwarder with get ? {C object mixins get} "::M" } nx::test case mixin-add { nx::Class create M1 { :method mfoo {} {puts [current method]} } nx::Class create M11 nx::Class create C1 ? {C1 info lookup method mixins} "::nsf::classes::nx::Class::mixins" C1 object mixins set M1 ? {C1 info precedence} "::M1 ::nx::Class ::nx::Object" C1 create c11 ? {c11 info precedence} "::C1 ::nx::Object" C1 object mixins add M11 ? {C1 info precedence} "::M11 ::M1 ::nx::Class ::nx::Object" Object create o -object-mixins M1 ? {o info precedence} "::M1 ::nx::Object" nx::Class create O O object mixins set M1 ? {O info precedence} "::M1 ::nx::Class ::nx::Object" nx::Class create O -object-mixins M1 ? {O info precedence} "::M1 ::nx::Class ::nx::Object" } nx::test case mixin-relation-invalid-value { nx::Class create C nx::Class create M # Double-escaping allows for injecting an invalid string rep of a Tcl # list into MixinregSetFromAny(). Other API facets (::nsf::mixin) # catch this through list ops at the script level. set ::str "\\\{ ::M" ? {lindex [subst $::str] 0} "unmatched open brace in list" ? {C mixins get} "" ? {C object mixins get} "" ? {::nsf::relation::set C class-mixin $::str} "unmatched open brace in list" ? {::nsf::relation::set C object-mixin $::str} "unmatched open brace in list" ? {C mixins get} "" ? {C object mixins get} "" # via slot interface ? {C mixins set $::str} "unmatched open brace in list" ? {C object mixins set $::str} "unmatched open brace in list" } nx::test case filter-relation { nx::Class create CC { :public method filterA args {next} :public method filterB args {next} :public object method filterC args {next} :create cc { :public object method filterD args {next} } } ? {::nsf::relation::get cc object-filter} "" ? {cc info object filters} "" ? {::nsf::relation::set cc object-filter filterA} filterA ? {cc info object filters} "filterA" ? {cc object filters set filterB} "filterB" ? {::nsf::relation::get cc object-filter} "filterB" ? {cc info object filters} "filterB" ? {cc object filters add filterD} "filterD filterB" ? {::nsf::relation::get cc object-filter} "filterD filterB" ? {cc info object filters} "filterD filterB" ? {cc object filters delete filterB} "filterD" ? {::nsf::relation::get cc object-filter} "filterD" ? {cc info object filters} "filterD" ? {catch {::nsf::relation::set cc object-filter UNKNOWN}} 1 ? {::nsf::relation::get cc object-filter} "filterD" ? {cc info object filters} "filterD" ? {::nsf::relation::get CC object-filter} "" ? {CC info object filters} "" ? {::nsf::relation::set CC object-filter filterC} "filterC" ? {::nsf::relation::get CC object-filter} "filterC" ? {CC info object filters} "filterC" ? {CC object filters clear} "filterC" ? {::nsf::relation::get CC object-filter} "" ? {CC info object filters} "" ? {::nsf::relation::get CC class-filter} "" ? {CC info filters} "" ? {::nsf::relation::set CC class-filter filterA} "filterA" ? {::nsf::relation::get CC class-filter} "filterA" ? {CC info filters} "filterA" ? {CC filters add filterB} "filterB filterA" ? {::nsf::relation::get CC class-filter} "filterB filterA" ? {CC info filters} "filterB filterA" ? {CC filters delete filterA} "filterB" ? {::nsf::relation::get CC class-filter} "filterB" ? {CC info filters} "filterB" ? {catch {::nsf::relation::set CC class-filter UNKNOWN}} 1 ? {::nsf::relation::get CC class-filter} "filterB" ? {CC info filters} "filterB" ? {CC filters clear} "filterB" ? {::nsf::relation::get CC class-filter} "" ? {CC info filters} "" } nx::test configure -count 3 nx::test case "filter-and-creation" { nx::Class create Foo { :method myfilter {args} { set i [::incr ::count] set s [self] set m [current calledmethod] #puts stderr "$i: $s.$m" #puts stderr "$i: procsearch before [$s procsearch info]" set r [next] #puts stderr "$i: $s.$m got ($r)" #puts stderr "$i: $s.$m procsearch after [$s info lookup method info]" return $r } # method for testing next to non-existing shadowed method :public method baz {} {next} } ? {Foo create ob} ::ob # make sure, no unknown handler exists #? {::ob info lookup method unknown} "::nsf::classes::nx::Object::unknown" ? {::ob info lookup method unknown} "" ? {ob bar} {::ob: unable to dispatch method 'bar'} ? {ob baz} {} # define a global unknown handler ::nx::Object protected method unknown {m args} { error "[::nsf::current object]: unable to dispatch method '$m'" } ? {ob bar} {::ob: unable to dispatch method 'bar'} ? {ob baz} {} Foo filters set myfilter # create through filter ? {Foo create ob} ::ob # unknown through filter ? {ob bar1} {::ob: unable to dispatch method 'bar1'} ? {ob baz} {} # deactivate nx unknown handler in case it exists ::nx::Object method unknown {} {} # create through filter ? {Foo create ob2} ::ob2 # unknown through filter ? {ob2 bar2} {::ob2: unable to dispatch method 'bar2'} ? {ob2 baz} {} # create with filter ? {Foo create ob3 -object-filters myfilter} ::ob3 } nx::test configure -count 1 # # Test the next-path with just intrinsic classes in cases where a # method handle is used for method dispatch # nx::test case intrinsic+method-handles { nx::Class create A {:public method foo {} {return "A [next]"}} nx::Class create B -superclass A {:public method foo {} {return "B [next]"}} nx::Class create C -superclass B {:public method foo {} {return "C [next]"}} C create c1 ? {c1 foo} "C B A " ? {c1 [C info method definitionhandle foo]} "C B A " ? {c1 [B info method definitionhandle foo]} "B A " ? {c1 [A info method definitionhandle foo]} "A " # we expect same results via dispatch with fully qualified names ? {nsf::dispatch c1 foo} "C B A " ? {nsf::dispatch c1 [C info method definitionhandle foo]} "C B A " ? {nsf::dispatch c1 [B info method definitionhandle foo]} "B A " ? {nsf::dispatch c1 [A info method definitionhandle foo]} "A " # # check, whether the context of "my -local" is correct # A public method bar {} {nsf::my -local foo} B public method bar {} {nsf::my -local foo} C public method bar {} {nsf::my -local foo} ? {c1 bar} "C B A " ? {c1 [C info method definitionhandle bar]} "C B A " ? {c1 [B info method definitionhandle bar]} "B A " ? {c1 [A info method definitionhandle bar]} "A " } # # Test the next-path with mixins in cases where a # method handle is used for method dispatch # nx::test case mixins+method-handles { # # Just mixins # nx::Class create A {:public method foo {} {return "A [next]"}} nx::Class create B {:public method foo {} {return "B [next]"}} nx::Class create C {:public method foo {} {return "C [next]"}} nx::Class create X -mixin {C B A} X create c1 ? {c1 foo} "C B A " ? {c1 [C info method definitionhandle foo]} "C B A " ? {c1 [B info method definitionhandle foo]} "B A " ? {c1 [A info method definitionhandle foo]} "A " # # Intrinsic classes and mixins # nx::Class create Y {:public method foo {} {return "Y [next]"}} nx::Class create Z -superclass Y {:public method foo {} {return "Z [next]"}} Z create c1 -object-mixins {C B A} ? {c1 foo} "C B A Z Y " ? {c1 [C info method definitionhandle foo]} "C B A Z Y " ? {c1 [B info method definitionhandle foo]} "B A Z Y " ? {c1 [A info method definitionhandle foo]} "A Z Y " ? {c1 [Z info method definitionhandle foo]} "Z Y " ? {c1 [Y info method definitionhandle foo]} "Y " # # check, whether the context of "my -local" is correct # A public method bar {} {nsf::my -local foo} B public method bar {} {nsf::my -local foo} C public method bar {} {nsf::my -local foo} Y public method bar {} {nsf::my -local foo} Z public method bar {} {nsf::my -local foo} ? {c1 bar} "C B A Z Y " ? {c1 [C info method definitionhandle bar]} "C B A Z Y " ? {c1 [B info method definitionhandle bar]} "B A Z Y " ? {c1 [A info method definitionhandle bar]} "A Z Y " ? {c1 [Z info method definitionhandle bar]} "Z Y " ? {c1 [Y info method definitionhandle bar]} "Y " } # # Test the next-path with mixins in cases where a # method handle is used for method dispatch # nx::test case mixins+method-handles+intrinsic { # # Just mixins # nx::Class create A {:public method foo {} {return "A [next]"}} nx::Class create B {:public method foo {} {return "B [next]"}} nx::Class create C {:public method foo {} {return "C [next]"}} nx::Class create X -mixin {C B A} { :public method foo {} {return "X [next]"} } X create c1 ? {c1 foo} "C B A X " ? {nsf::dispatch c1 -intrinsic foo} "X " # # Intrinsic classes and mixins # nx::Class create Y {:public method foo {} {return "Y [next]"}} nx::Class create Z -superclass Y {:public method foo {} {return "Z [next]"}} Z create c1 -object-mixins {C B A} ? {c1 foo} "C B A Z Y " ? {nsf::dispatch c1 -intrinsic foo} "Z Y " # # check, whether the context of "my -intrinsic" is correct # A public method bar {} {nsf::my -intrinsic foo} B public method bar {} {nsf::my -intrinsic foo} C public method bar {} {nsf::my -intrinsic foo} Y public method bar {} {nsf::my -intrinsic foo} Z public method bar {} {nsf::my -intrinsic foo} ? {c1 info precedence} "::C ::B ::A ::Z ::Y ::nx::Object" ? {c1 bar} "Z Y " ? {c1 [C info method definitionhandle bar]} "Z Y " ? {c1 [B info method definitionhandle bar]} "Z Y " ? {c1 [A info method definitionhandle bar]} "Z Y " ? {c1 [Z info method definitionhandle bar]} "Z Y " ? {c1 [Y info method definitionhandle bar]} "Z Y " # # check, whether the context of "nsf::dispatch [self] -intrinsic" is correct # A public method bar {} {nsf::dispatch [self] -intrinsic foo} B public method bar {} {nsf::dispatch [self] -intrinsic foo} C public method bar {} {nsf::dispatch [self] -intrinsic foo} Y public method bar {} {nsf::dispatch [self] -intrinsic foo} Z public method bar {} {nsf::dispatch [self] -intrinsic foo} ? {c1 bar} "Z Y " ? {c1 [C info method definitionhandle bar]} "Z Y " ? {c1 [B info method definitionhandle bar]} "Z Y " ? {c1 [A info method definitionhandle bar]} "Z Y " ? {c1 [Z info method definitionhandle bar]} "Z Y " ? {c1 [Y info method definitionhandle bar]} "Z Y " } # # Test filter guards (define filter and guard separtely) # nx::test case filter-guard-separately { # # Define a room with occupancy and methods for entering and leaving # nx::Class create Room { :property name :variable occupancy:integer 0 :public method enter {name} {incr ::occupancy} :public method leave {name} {incr ::occupancy -1} # # We are interested, what happens with the room, so we define a # logging filter.... # :method loggingFilter args { lappend ::_ [current calledmethod] next } # # ... and we register it. # :filters add loggingFilter } set ::_ {} ? {Room create r} ::r r enter Uwe r leave Uwe r configure -name "Office" ? {set ::_} "__object_configureparameter init enter leave configure" # # Hmm, we not so much interested on all these calls. Just the # "enter" and "leave" operations are fine. We could have certainly # as well mixin for these two methods, but the guards are more # general since the can as well trigger on arbitrary patterns. # Room filters guard loggingFilter { [current calledmethod] in {enter leave} } r destroy set ::_ {} ? {Room create r} ::r r enter Uwe r leave Uwe r configure -name "Office" ? {set ::_} "enter leave" r destroy # Now we define a subclass DangerRoom, which refines the filter by # logging into a "dangerRoomLog". We want here entries for all # operations. set ::_ {} set ::dangerRoomLog {} nx::Class create DangerRoom -superclass Room { :method loggingFilter args { lappend ::dangerRoomLog [current calledmethod] next } :filters add loggingFilter } ? {DangerRoom create d} ::d d enter Uwe d leave Uwe d configure -name "Safe Room" ? {set ::_} "enter leave" ? {expr [llength $::dangerRoomLog] > 2} 1 d destroy } # # Test filter guards (define filter together with guard) # nx::test case filter-guard-separately { # # Define a room with occupancy and methods for entering and leaving # nx::Class create Room { :property name :variable occupancy:integer 0 :public method enter {name} {incr ::occupancy} :public method leave {name} {incr ::occupancy -1} # # We are interested, what happens with the room, so we define a # logging filter.... # :method loggingFilter args { lappend ::_ [current calledmethod] next } # # ... and we register it together with a guard. # :filters add {loggingFilter -guard { [current calledmethod] in {enter leave} }} } set ::_ {} ? {Room create r} ::r r enter Uwe r leave Uwe r configure -name "Office" ? {set ::_} "enter leave" ? {r info lookup filters} "::nsf::classes::Room::loggingFilter" ? {r info lookup filters -guards} {{loggingFilter -guard { [current calledmethod] in {enter leave} }}} # Now we define a subclass DangerRoom, which refines the filter by # logging into a "dangerRoomLog". We want here entries for all # operations. set ::_ {} set ::dangerRoomLog {} nx::Class create DangerRoom -superclass Room { :method loggingFilter args { lappend ::dangerRoomLog [current calledmethod] next } :filters add loggingFilter } ? {DangerRoom create d} ::d d enter Uwe d leave Uwe d configure -name "Safe Room" ? {set ::_} "enter leave" ? {expr [llength $::dangerRoomLog] > 2} 1 ? {d info lookup filters} "::nsf::classes::DangerRoom::loggingFilter ::nsf::classes::Room::loggingFilter" d destroy } # # Test info lookup mixins (with guards) # nx::test case filter-guard-separately { nx::Class create M1 nx::Class create M2 nx::Class create M3 nx::Class create C nx::Class create D -superclass C D create d1 -object-mixins M1 ? {d1 info lookup mixins} ::M1 D mixins add {M2 -guard 1} ? {d1 info lookup mixins} "::M1 ::M2" C mixins add M3 ? {d1 info lookup mixins} "::M1 ::M2 ::M3" ? {d1 info lookup mixins -guards} "::M1 {::M2 -guard 1} ::M3" ? {d1 info lookup mixins -guards *2*} "{::M2 -guard 1}" d1 object mixins clear ? {d1 info lookup mixins} "::M2 ::M3" } # # Test potential confusion in case a class has a space in its name # when registering methods or mixins. # nx::test case space-in-classname { nx::Class create M1 { :public method foo {} {return "[next] [current class]"} } # # Define a class with a space in its name, containing a method. This # class will be used as a mixin class later on. # nx::Class create "M1 b" -superclass M1 { :public method foo {} {return next-[current class]} } nx::Class create C { :public method foo {} {return foo} :create c1 } # Test the base case ? {c1 foo} foo # Add spacy class as a mixin. Check, if the introspection returns # sensible values. ? {C mixins add "M1 b"} "{::M1 b}" ? {C info mixins} "{::M1 b}" ? {M1 info mixins} "" ? {M1 info mixinof} "" ? {"M1 b" info mixins} "" # check the result of the mixin class ? {c1 foo} "next-::M1 b" } nx::test case filtered-unknowns { package req XOTcl ? {info exists ::filtersCalled} 0 xotcl::Class create C xotcl::Object instproc f {args} { if {[self] eq "::C" && [lindex $args 0] eq "::c1111"} { lappend ::filtersCalled "[self proc] ([self calledproc])" } next } xotcl::Class instproc f2 {args} { if {[self] eq "::C" && [lindex $args 0] eq "::c1111"} { lappend ::filtersCalled "[self proc] ([self calledproc])" } next } ? {info commands ::c1111} "" ? {xotcl::Object instfilter f; xotcl::Class instfilter f2; C ::c1111} ::c1111 ? {info exists ::filtersCalled} 1 ? {set ::filtersCalled} {{f2 (unknown)} {f (unknown)}\ {f2 (create)} {f (create)}\ {f2 (alloc)} {f (alloc)}} xotcl::Object instfilter "" xotcl::Class instfilter "" unset -nocomplain ::filtersCalled } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/rac.test000644 000766 000024 00000031111 13565476341 016013 0ustar00neumannstaff000000 000000 # -*- Tcl -*- # # Exploratory tests on run-time assertion checking (RAC) # # stefan.sobernig@wu.ac.at # # Conceptual baseline is the Eiffel Spec (ECMA Standard 367, 2nd ed., # 2006) # # see # https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-367.pdf # package require nx::test nx::Class create Sensor { :property -accessor public {value:integer 1} } set invar [list {[regexp {^[0-9]$} ${:value}] == 1}] ::nsf::method::assertion Sensor class-invar $invar ? {::nsf::method::assertion Sensor class-invar} $invar # # Minimal object interface to ::nsf::method::assertion # # # TODO: This should not be ::nx::VariableSlot below, but # ::nx::ObjectParameterSlot mixes alias + slotset. # ::nx::VariableSlot create ::nx::Object::slot::object-invariant { :public object method get {obj prop} { ::nsf::method::assertion $obj object-invar } :public object method assign {obj prop value} { ::nsf::method::assertion $obj object-invar $value } } ::nx::VariableSlot create ::nx::Class::slot::invariant { :public object method get {cls prop} { ::nsf::method::assertion $cls class-invar } :public object method assign {cls prop value} { ::nsf::method::assertion $cls class-invar $value } } ? {Sensor cget -invariant} $invar ? {::nsf::method::assertion Sensor class-invar} $invar ? {Sensor configure -invariant ""} "" ? {Sensor cget -invariant} "" ? {::nsf::method::assertion Sensor class-invar} "" ? {Sensor configure -invariant $invar} "" ? {Sensor cget -invariant} $invar ? {::nsf::method::assertion Sensor class-invar} $invar Sensor create s1 ? {s1 cget -object-invariant} "" ? {s1 configure -object-invariant $invar} "" ? {s1 cget -object-invariant} $invar ? {s1 configure -object-invariant ""} "" # # TODO: re-position -pre-condition, to appear before the method # body. This would ease reading. # # # TODO: Why is there a firm requirement to provide a post-condition, # when defining a pre-condition (they are non-positional # parameters in NX)? # # --> because of XOTcl2 legacy interface? # i.e.: precondition:optional postcondition:optional # Sensor public method incrValue {} { incr :value } -precondition { {[set ::ARGS [nsf::current args]] eq "run {bar 1 2 3}"} {# pre-condition:} {${:value} > 0} } -postcondition { {[puts stderr POST=${:value}] eq ""} {# post-condition:} {${:value} > 1} } proc bar args { s1 incrValue } # # TODO: How to activate, deactivate RAC per object? Re-introduce check() method? # # s1 check pre ::nsf::method::assertion s1 check pre ? {bar 1 2 3} "2" # # TODO: ::nsf::current jumps the call stack, picks an arbitrary call # frame if the context provides for it. # ? {info exists ::ARGS} 1 ? {set ::ARGS} "run {bar 1 2 3}" # # TODO: Improve formatting of assertion messages, to make distinction # clear between assertion and underlying error. # catch {s1 incrValue} ::msg ? {set ::msg} {error in Assertion: {[set ::ARGS [nsf::current args]] eq "run {bar 1 2 3}"} in proc 'incrValue' can't find proc} ? {s1 value -1} -1 ? {s1 value 10} 10 ? {s1 value 1} 1 # s1 check all ::nsf::method::assertion s1 check all # # TODO: When INVAR assertions fail (upon entering an operation), the # object state is still modified effectively. Why? # # INVAR ? {s1 value -1} {assertion failed check: {[regexp {^[0-9]$} ${:value}] == 1} in proc 'value'} # s1 check {} ::nsf::method::assertion s1 check {} ? {s1 value} -1 # s1 check all ::nsf::method::assertion s1 check all ? {s1 value 10} {assertion failed check: {[regexp {^[0-9]$} ${:value}] == 1} in proc 'value'} # s1 check {} ::nsf::method::assertion s1 check {} ? {s1 value} 10 # PRE # s1 check pre ::nsf::method::assertion s1 check pre Sensor public method incrValue2 {} { incr :value } -precondition { {# pre-condition:} {${:value} == -1} } -postcondition {} ? {s1 incrValue2} {assertion failed check: {${:value} == -1} in proc 'incrValue2'} # # OK: old value (value before PRE RAC) is preserved # ? {s1 value} 10 # # What is the order when evaluating PRE/POST and INVAR assertions? # # ACTUAL: . -> PRE -> INVAR -> (BODY) -> POST -> INVAR -> . # # TODO: EXPECTED (ECMA-367 §8.23.26): # . -> INVAR -> PRE -> (BODY) -> INVAR -> POST -> . # set ::YYY [list] # s1 check all ::nsf::method::assertion s1 check all # # TODO: using [:*] calls within assertions distorts error # reporting (the * call frame is reported as error context -> proc # name = "lappend" in the examples below etc.) # Sensor configure -invariant { {[llength [lappend ::YYY "INVAR"]]} } Sensor public method incrValue2 {} { lappend ::YYY "BODY" ::nsf::method::assertion [self] check {} set r [incr :value] ::nsf::method::assertion [self] check all return $r } -precondition { {# pre-condition:} {[llength [lappend ::YYY "PRE"]]} } -postcondition { {# post-condition:} {[llength [lappend ::YYY "POST"]]} } ? {s1 incrValue2} 11 ? {set ::YYY} "PRE INVAR BODY POST INVAR" # # Are class invariants evaluated after instance creation? # see ECMA-367 §7.5 # set ::YYY [list] nx::Class create Account -invariant { {[llength [lappend ::YYY "Account"]]} {# sufficient_balance: } {${:balance} >= ${:minimumBalance}} } { :property -accessor public balance:integer :property -accessor public minimumBalance:integer :method init args { set :balance 9 set :minimumBalance 10 } } # # TODO: Irgh! a1 is effectively an invalid instance, class invars # should have been checked after create(); this is also inconvenient, # because once checking has been activated, the assertions are # reported as violated ... without directly blaming the creation # operation --> relevant for paper! # Account create a1 ? {a1 balance} 9 ? {a1 minimumBalance} 10 # a1 check instinvar ::nsf::method::assertion a1 check class-invar # # TODO: Should the default dispatch also trigger INVAR checks? # # - Against: ECMA semantics refer to qualified feature calls, with # the default method not being an externally visible feature, at # least in XOTcl. # # - In favor: In NX, however, it can be refined though not publicly # available (or?) Also, a convenient way to ask whether an object is # in a valid state ... # ? {a1} "::a1" ? {a1 balance} {assertion failed check: {${:balance} >= ${:minimumBalance}} in proc 'balance'} # # TODO: What about pre- and post-conditions for create() and/or # init(). This adds to the above ... # # - They should be evaluated upon creation (before an explicit "/inst/ # check pre|post" # # - How to specify them? a) There is no custom create() defined for # classes (only meta-classes) -> some pre|post notation for # configure? b) init() is not necessarily defined for a class ... # # - the assertion-checking semantics are different from ordinary method calls: # PRE (BODY) POST INVAR (no INVAR checking before PRE!) # # # How does the super/subclass relationship relate to ... # # - invariants? -(ECMA)-> include parent clauses: AND joining, # with parent clauses taking precedence # (in reverse linearization order; see # ECMA-367 §8.10.2) # set ::YYY [list] nx::Class create SavingsAccount -superclass Account -invariant { {[llength [lappend ::YYY [:info class]]]} {# minimum_deposit: } {${:minimumBalance} > 110} } SavingsAccount create sa1 ? {sa1 balance 99} 99 ? {sa1 minimumBalance 101} 101 # sa1 check instinvar ::nsf::method::assertion sa1 check class-invar # Should be: assertion labelled 'sufficient_balance' should be checked # before 'minimum_deposit' # # i.e.: # ? {sa1 balance} {assertion failed check: {[my balance] >= [my minimumBalance]} in proc 'balance'} # # TODO: inverse order of resolution of class INVARs # ? {sa1 balance} {assertion failed check: {${:minimumBalance} > 110} in proc 'balance'} ? {set ::YYY} "::SavingsAccount" # sa1 check {} # a1 check {} ::nsf::method::assertion a1 check {} ::nsf::method::assertion sa1 check {} # - pre-conditions? -(ECMA)-> require else (OR) ... weakening: OR # joining with parent clauses taking # precedence in reverse linearization # order (see ECMA-367 $8.10.5) # # (pre_1 or ... or pre_n) or else pre Account property -accessor public depositTransactions:integer Account public method deposit {sum:integer} { incr :depositTransactions incr :balance $sum } -precondition { {[llength [current class]]} {# trap :} {0} } -postcondition { {${:depositTransactions} > 1} } SavingsAccount public method deposit {sum:integer} { next } -precondition { {# max_deposits :} {${:depositTransactions} < 3} } -postcondition {} SavingsAccount create sa2 sa2 depositTransactions 2 # sa2 check pre ::nsf::method::assertion sa2 check pre # EXPECTED: trap OR max_deposits ? {sa2 deposit 50} {assertion failed check: {0} in proc 'deposit'}; # SHOULD ACTUALLY PASS because max_deposits is okay! ? {sa2 depositTransactions 3} 3 ? {sa2 deposit 60} {assertion failed check: {${:depositTransactions} < 3} in proc 'deposit'}; # FAILS because of max_deposits, but evaluation order should be inverse: ACCOUNT -> SAVINGSACCOUNT. # -- # TODO: Are method contracts enforced in shadowing methods, even without [next]? nx::Class create S { :public method foo {} { [:info class] eval [list lappend :TRACE "[current class]-[current proc]"] } -precondition { {[llength [[:info class] eval [list lappend :TRACE "::S-foo-PRE"]]]} } -postcondition { {[llength [[:info class] eval [list lappend :TRACE "::S-foo-POST"]]]} } } nx::Class create T -superclass S { :public method foo {} { [:info class] eval [list lappend :TRACE "[current class]-[current proc]"] # next; # invariants of super only fired when [next] is provided :/ } } T create t1; # -check all ::nsf::method::assertion t1 check all t1 foo ? {T eval {set :TRACE}} "::T-foo"; # SHOULD BE "::T-foo ::S-foo-PRE ::S-foo ::S-foo-POST", even without [next] # # - post-conditions? -(ECMA)-> ensure then (AND) ... strengthening: # in a convenience view, AND joining, # with parent clauses taking precedence # in reverse linearization order (see # ECMA-367 $8.10.5). More precisely, # parent posts only required iff # pre-conditions over the pre-state # (old) hold. # # (old pre_1 implies post_1) # and ... and # (old pre_n implies post_n) # and then post # T eval {unset :TRACE} nx::Class create T -superclass S { :public method foo {} { [:info class] eval [list lappend :TRACE "[current class]-[current proc]"] next } -precondition {} -postcondition { {[llength [[:info class] eval {lappend :TRACE "::T-foo-POST"}]]} } } T create t1; # -check post ::nsf::method::assertion t1 check post t1 foo ? {T eval {set :TRACE}} "::T-foo ::S-foo ::S-foo-POST ::T-foo-POST"; # SHOULD BE: ::T-foo ::S-foo ::S-foo-POST ::T-foo-POST ... seems OK, but only because next induces a correct order. T eval {unset :TRACE} # without [next] nx::Class create T -superclass S { :public method foo {} { [:info class] eval [list lappend :TRACE "[current class]-[current proc]"] # next } -precondition {} -postcondition { {[llength [[:info class] eval {lappend :TRACE "::T-foo-POST"}]]} } } T create t2 ::nsf::method::assertion t2 check post t2 foo ? {T eval {set :TRACE}} "::T-foo ::T-foo-POST"; # SHOULD BE: ::T-foo ::S-foo-POST ::T-foo-POST, even without [next] # # TODO: Provide access to method arguments in assertion expressions. # # TODO: Parameter checks should be performed before PRE (and before # INVAR) checks (see ECMA-367, §...) # # nx::Class create S { # :public method bar {p:integer} { # } -precondition { # {$p > -1} # } # } # # OK: Are assertions fired through the colon resolver (:/var/) and # upon cget/configure? # nx::Class create Z -invariant { {[::nsf::is integer ${:v}]} } { :property -accessor public {v 1} :create ::z1 } ? {z1 v 1} 1 ::nsf::method::assertion z1 check class-invar # # TODO: Why "in proc 'v'"? ... this is misleading, at least for an INVAR. # ? {z1 v "XXX"} {assertion failed check: {[::nsf::is integer ${:v}]} in proc 'v'} ? {z1 eval {set :v "XXX"}} {assertion failed check: {[::nsf::is integer ${:v}]} in proc 'eval'} ? {z1 configure -v "XXX"} {assertion failed check: {[::nsf::is integer ${:v}]} in proc 'configure'} # # TODO: v should still be 1, but is already 'XXX' (see above) # ::nsf::method::assertion z1 check {} ? {z1 v} XXX; # Why not '1'? ::nsf::method::assertion z1 check class-invar # ::nsf::method::assertion z1 check {} # ? {z1 v XXX} XXX # ::nsf::method::assertion z1 check class-invar ? {z1 cget -v} {assertion failed check: {[::nsf::is integer ${:v}]} in proc 'cget'} ::nsf::method::assertion z1 check {} # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/var-access.test000644 000766 000024 00000005147 13462406127 017276 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx ::nx::configure defaultMethodCallProtection false package require nx::test namespace eval ::nx::var1 { namespace ensemble create -map { exists ::nsf::var::exists import ::nsf::var::import set ::nsf::var::set } } ::nx::Object create ::nx::var2 { :object alias exists ::nsf::var::exists :object alias import ::nsf::var::import :object alias set ::nsf::var::set } nx::test case set+array { nx::Object create o1 # first set a scalar variable ? {nsf::var::set o1 x 100} "100" ? {nsf::var::set o1 x} "100" # now, set an array variable; "nsf::var::set -array" is a wrapper # around "array set" or "array get" ? {nsf::var::set -array o1 a {a 1 y 2}} "" ? {nsf::var::set -array o1 a} "y 2 a 1" # We have now a scalar and an array variable set. ? {lsort [o1 info vars]} "a x" # "x" is a variable, but not an array ? {nsf::var::exists o1 x} 1 ? {nsf::var::exists -array o1 x} 0 # "a" is a variable and an array ? {nsf::var::exists -array o1 a} 1 ? {nsf::var::exists o1 a} 1 # we unset the array ? {nsf::var::unset o1 a} "" ? {nsf::var::exists o1 a} 0 ? {nsf::var::exists -array o1 a} 0 # now, just the scalar is left ? {o1 info vars} "x" ? {nsf::var::exists o1 x} 1 ? {nsf::var::exists -array o1 x} 0 # we unset the scalar ? {nsf::var::unset o1 x} "" ? {nsf::var::exists o1 x} 0 ? {nsf::var::exists -array o1 x} 0 # unset on a non-existing variable ? {nsf::var::unset o1 x} {can't unset "x": no such variable} ? {nsf::var::unset -nocomplain o1 x} "" } nx::test configure -count 10000 nx::test case dummy { nx::Object create o { set :x 1 } nx::Object create p { set :y 1 :object method foo0 {} { incr :y } :object method foo1 {} { o eval {incr :x} } :object method foo2 {} { ::nsf::var::import o x incr x } :object method foo3 {} { ::nx::var1 import o x incr x } :object method foo4 {} { ::nx::var2 import o x incr x } } ? {::nsf::var::set o x} 1 ? {::nsf::var::exists o x} 1 ? {::nsf::var::exists o y} 0 ? {::nx::var1 set o x} 1 ? {::nx::var1 exists o x} 1 ? {::nx::var1 exists o y} 0 ? {::nx::var2 set o x} 1 ? {::nx::var2 exists o x} 1 ? {::nx::var2 exists o y} 0 ? {p foo0} 2 ? {p foo1} 2 ? {::nsf::var::set o x} 10002 ? {p foo2} 10003 ? {::nsf::var::set o x} 20003 ? {p foo3} 20004 ? {::nsf::var::set o x} 30004 ? {p foo4} 30005 ? {::nsf::var::set o x} 40005 } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/traits.test000644 000766 000024 00000003402 13462406127 016545 0ustar00neumannstaff000000 000000 package prefer latest package require nx::trait package require nx::test nx::test case basics { nx::Trait create t1 { :public method t1m1 {} {return t1.[current method]} :public method t1m2 {} {return t1.[current method]} # This trait requires a method "foo" :requiredMethods foo } nx::Trait create t2 { :public method "bar x" {} {return t2.[current methodpath]} :public method "bar y" {} {return t2.[current methodpath]} :public method foo {} {return t2.[current methodpath]} # This trait requires a method "t1m1" :requiredMethods t1m1 } nx::Trait create t3 { :public method "bar y" {} {return t3.[current methodpath]} :public method "bar z" {} {return t3.[current methodpath]} } nx::Class create C { :property {collection ""} :public method foo {} {return [current method]} :create c1 } ? {c1 foo} "foo" ? {C require trait t2} "trait t2 requires t1m1, which is not defined for ::C" ? {lsort [C info methods]} "foo" C require trait t1 ? {lsort [C info methods]} "foo t1m1 t1m2" ? {c1 foo} "foo" ? {C require trait t2} "" ? {lsort [C info methods]} "bar foo t1m1 t1m2" ? {lsort [C info methods -path]} "{bar x} {bar y} foo t1m1 t1m2" # trait t2 redefines t2, so we call that see its result here ? {c1 foo} "t2.foo" ? {c1 bar x} "t2.bar x" ? {c1 bar y} "t2.bar y" ? {C require trait t3} "" ? {lsort [C info methods]} "bar foo t1m1 t1m2" ? {lsort [C info methods -path]} "{bar x} {bar y} {bar z} foo t1m1 t1m2" # trait t3 redefines "bar y", so we call that see its result here ? {c1 foo} "t2.foo" ? {c1 bar x} "t2.bar x" ? {c1 bar y} "t3.bar y" ? {c1 bar z} "t3.bar z" } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/introspection.test000644 000766 000024 00000002403 13462406127 020137 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package req nx::test # # [::nsf::current calledclass] # nx::test case current-calledclass { Object create o { :public method foo {} { return [current calledclass] } } ? {o foo} "" Class create C { :public class method bar {} { return [current calledclass] } :public method foo {} { return [current calledclass] } } ? {[C new] foo} ::C ? {C bar} "" C eval { :public method intercept {} { return @[current calledclass]@ } :filter add intercept } ? {[C new] foo} @::C@ C eval { :filter {} :public method baz {} { return [current calledclass] } } Class create M { :public method baz {} { return [list [current calledclass] [next]] } } C mixins add M ? {[C new] baz} {::C ::C} } # # [::nsf::current calledclass] # nx::test case current-calledmethod { set body { return [list [current nextmethod] {*}[next]] } Object create o set mh [o public method foo {} $body] ? {o foo} {{}} Class create M set mh2 [M public method foo {} $body] M filters add foo o mixin M ? {o foo} [list $mh2 $mh {}] } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/destroy.test000644 000766 000024 00000104440 14274463622 016741 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package require nx package require nx::test set ::tcl86 [package vsatisfies [package req Tcl] 8.6-] nx::test configure -count 10 ::nx::configure defaultMethodCallProtection false ::nsf::method::alias ::nx::Object set -frame object ::set nx::Class create O -superclass nx::Object { :method init {} { set ::ObjectDestroy 0 set ::firstDestroy 0 } :method destroy {} { incr ::ObjectDestroy #[:info class] dealloc [current] next } } # # classical simple case # set case "simple destroy (1)" nx::test case simple-destroy-1 nx::Class create C -superclass O C method destroy {} {incr ::firstDestroy; puts stderr " *** [current] destroy"; next} C method foo {} { puts stderr "==== $::case [current]" :destroy puts stderr "AAAA [current] exists [::nsf::object::exists [current]]" :set x 1 puts stderr XXXX2 ? "[current] set x" 1 "$::case can still access [current]" puts stderr XXXX3 ? {::nsf::object::exists c1} 1 "$::case object still exists in proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 1 "ObjectDestroy called" } C create c1 c1 foo ? {::nsf::object::exists c1} 0 "$::case object deleted" ? "set ::firstDestroy" 1 "firstDestroy called" # # simple case, destroy does not propagate, c1 survives # set case "simple destroy (2), destroy blocks" nx::test case simple-destroy-2 nx::Class create C -superclass O C method destroy {} {incr ::firstDestroy; puts stderr " *** [current] destroy block"} C method foo {} { puts stderr "==== $::case [current]" :destroy puts stderr "AAAA [current] exists [::nsf::object::exists [current]]" :set x 1 ? "[current] set x" 1 "$::case can still access [current]" ? {::nsf::object::exists c1} 1 "$::case object still exists in proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 0 "ObjectDestroy called" } C create c1 c1 foo ? {::nsf::object::exists c1} 1 "$::case object deleted" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 0 "ObjectDestroy called" # # simple object recreate # set case "recreate" nx::test case recreate nx::Class create C -superclass O C method destroy {} {incr ::firstDestroy; puts stderr " *** [current] destroy"; next} C method foo {} { puts stderr "==== $::case [current]" [:info class] create [current] puts stderr "AAAA [current] exists [::nsf::object::exists [current]]" :set x 1 ? "[current] set x" 1 "$::case can still access [current]" ? {::nsf::object::exists c1} 1 "$::case object still exists in proc" ? "set ::firstDestroy" 0 "firstDestroy called" ? "set ::ObjectDestroy" 0 "ObjectDestroy called" } C create c1 c1 foo ? {::nsf::object::exists c1} 1 "$::case object deleted" ? "set ::firstDestroy" 0 "firstDestroy called" # # cmd rename to empty, xotcl provides its own rename and calls destroy # .. like simple case above # set case "cmd rename empty (1)" nx::test case rename-empty-1 nx::Object create o nx::Class create C -superclass O C method destroy {} {incr ::firstDestroy; puts stderr " *** [current] destroy"; next} C method foo {} { puts stderr "==== $::case [current]" rename [current] "" puts stderr "AAAA [current] exists [::nsf::object::exists [current]]" :set x 1 ? "[current] set x" 1 "$::case can still access [current]" ? {::nsf::object::exists c1} 1 "$::case object still exists in proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 1 "ObjectDestroy called" } C create c1 c1 foo ? {::nsf::object::exists c1} 0 "$::case object still exists after proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 1 "ObjectDestroy called" # # cmd rename to empty, xotcl provides its own rename and calls # destroy, but destroy does not propagate, c1 survives rename, since # this is the situation like above, as long xotcl's rename is used. # set case "cmd rename empty (2)" nx::test case rename-empty-2 nx::Class create C -superclass O C method destroy {} {incr ::firstDestroy; puts stderr " *** [current] destroy block"} C method foo {} { puts stderr "==== $::case [current]" rename [current] "" puts stderr "AAAA [current] exists [::nsf::object::exists [current]]" :set x 1 ? "[current] set x" 1 "$::case can still access [current]" ? {::nsf::object::exists c1} 1 "$::case object still exists in proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 0 "ObjectDestroy called" } C create c1 c1 foo #puts stderr ======[c1 set x] ? {::nsf::object::exists c1} 1 "$::case object still exists after proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 0 "ObjectDestroy called" # # cmd rename other xotcl object to current, # xotcl's rename invokes a move # set case "cmd rename object to current" nx::test case rename-to-current nx::Object create o nx::Class create C -superclass O C method destroy {} {incr ::firstDestroy; puts stderr " *** [current] destroy"; next} C method foo {} { puts stderr "==== $::case [current]" rename o [current] puts stderr "AAAA [current] exists [::nsf::object::exists [current]]" :set x 1 #? "[current] set x" 1 "$::case can still access [current]" if {$::tcl86} { ? "[current] set x" {TCL LOOKUP VARNAME x} "$::case cannot access [current]" } else { ? "[current] set x" {can't read "x": no such variable} "$::case cannot access [current]" } ? {::nsf::object::exists c1} 1 "$::case object still exists in proc" #? "set ::firstDestroy" 0 "firstDestroy called" #? "set ::ObjectDestroy" 0 "ObjectDestroy called" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 1 "ObjectDestroy called" } C create c1 c1 foo ? {::nsf::object::exists c1} 1 "$::case object still exists after proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 1 "ObjectDestroy called" # # cmd rename other proc to current object, # xotcl's rename invokes a move # set case "cmd rename proc to current" nx::test case rename-proc-to-current proc o args {} nx::Class create C -superclass O C method destroy {} {incr ::firstDestroy; puts stderr " *** [current] destroy"; next} C method foo {} { puts stderr "==== $::case [current]" set x [catch {rename o [current]}] ? "set _ $x" 1 "$::case tcl refuses to rename into an existing command" } C create c1 c1 foo ? {::nsf::object::exists c1} 1 "$::case object still exists after proc" ? "set ::firstDestroy" 0 "firstDestroy called" ? "set ::ObjectDestroy" 0 "ObjectDestroy called" rename o "" # # namespace delete: tcl delays delete until the namespace is not # active anymore. destroy is called after BBBB. Hypothesis: destroy is # called only when we are lucky, since C might be destroyed before c1 # by the namespace delete # set case "delete parent namespace (1)" nx::test case delete-parent-namespace namespace eval ::test { nx::Class create C -superclass O C method destroy {} {incr ::firstDestroy; puts stderr " *** [current] destroy"; next} C method foo {} { puts stderr "==== $::case [current]" namespace delete ::test puts stderr "AAAA [current] exists [::nsf::object::exists [current]]" :set x 1 # # If the following line is commented in, the namespace is deleted # here. Is there a bug with nsPtr->activationCount # #? "[current] set x" 1 "$::case can still access [current]" puts stderr "BBB" puts stderr "???? [current] exists [::nsf::object::exists [current]]" ? "::nsf::object::exists [current]" 0 ;# WHY? puts stderr "???? [current] exists [::nsf::object::exists [current]]" ? "set ::firstDestroy" 0 "firstDestroy called" ? "set ::ObjectDestroy" 0 "$::case destroy not yet called" } } test::C create test::c1 test::c1 foo ? {::nsf::object::exists test::c1} 0 "object still exists after proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 1 "destroy was called when popping stack frame" ? {::nsf::object::exists ::test::C} 0 "class still exists after proc" ? {namespace exists ::test::C} 0 "namespace ::test::C still exists after proc" ? {namespace exists ::test} 1 "parent ::test namespace still exists after proc" ? {namespace exists ::xotcl::classes::test::C} 0 "namespace ::xotcl::classes::test::C still exists after proc" # # namespace delete: tcl delays delete until the namespace is not # active anymore. destroy is called after BBBB, but does not # propagate. # set case "delete parent namespace (2)" nx::test case delete-parent-namespace-2 namespace eval ::test { ? {namespace exists test::C} 0 "exists test::C" nx::Class create C -superclass O C method destroy {} {incr ::firstDestroy; puts stderr " *** [current] destroy block"} C method foo {} { puts stderr "==== $::case [current]" namespace delete ::test puts stderr "AAAA [current] exists [::nsf::object::exists [current]]" :set x 1 # # If the following line is commented in, the namespace is deleted # here. Is there a bug with nsPtr->activationCount # #? "[current] set x" 1 "$::case can still access [current]" puts stderr "BBBB" puts stderr "???? [current] exists [::nsf::object::exists [current]]" ? "::nsf::object::exists [current]" 0 "$::case object still exists in proc";# WHY? puts stderr "???? [current] exists [::nsf::object::exists [current]]" ? "set ::firstDestroy" 0 "firstDestroy called" ? "set ::ObjectDestroy" 0 "ObjectDestroy called"; # NOT YET CALLED } } test::C create test::c1 test::c1 foo ? {::nsf::object::exists test::c1} 0 "$::case object still exists after proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 0 "ObjectDestroy called" ;# toplevel destroy was blocked # # controlled namespace delete: xotcl has its own namespace cleanup, # topological order should be always ok. however, the object o::c1 is # already deleted, while a method of it is executed # set case "delete parent object (1)" nx::test case delete-parent-object nx::Object create o nx::Class create C -superclass O C method destroy {} {incr ::firstDestroy; puts stderr " *** [current] destroy"; next} C method foo {} { puts stderr "==== $::case [current]" o destroy puts stderr "AAAA" # the following object::exists call has a problem in Tcl_GetCommandFromObj(), # which tries to access invalid memory puts stderr "AAAA [current] exists [::nsf::object::exists [current]]" :set x 1 #? "[current] set x" 1 "$::case can still access [current]" puts stderr "BBBB" ? {::nsf::object::exists ::o::c1} 0 "$::case object still exists in proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 1 "ObjectDestroy called" } C create o::c1 o::c1 foo ? {::nsf::object::exists ::o::c1} 0 "$::case object o::c1 still exists after proc" ? {::nsf::object::exists o} 0 "$::case object o still exists after proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 1 "ObjectDestroy called" # # controlled namespace delete: xotcl has its own namespace cleanup. # destroy does not delegate, but still o::c1 does not survive, since o # is deleted. # set case "delete parent object (2)" nx::test case delete-parent-object-2 nx::Object create o nx::Class create C -superclass O C method destroy {} {incr ::firstDestroy; puts stderr " *** [current] destroy block"} C method foo {} { puts stderr "==== $::case [current]" o destroy puts stderr "AAAA [current] exists [::nsf::object::exists [current]]" :set x 1 #? "[current] set x" 1 "$::case can still access [current]" puts stderr "BBB" ? {::nsf::object::exists ::o::c1} 0 "$::case object still exists in proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 0 "ObjectDestroy called" } C create o::c1 o::c1 foo ? {::nsf::object::exists ::o::c1} 0 "$::case object still exists after proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 0 "ObjectDestroy called" # # create another cmd with the current object's name. # XOTcl 1.6 crashed on this test. # set case "redefine current object as proc" nx::test case redefine-current-object-as-proc nx::Object create o nx::Class create C -superclass O C method destroy {} {incr ::firstDestroy; puts stderr " *** [current] destroy"; next} C method foo {} { puts stderr "==== $::case [current]" proc [current] {args} {puts HELLO} puts stderr "AAAA [current] exists [::nsf::object::exists [current]]" :set x 1 #? "[current] set x" 1 "$::case can still access [current]" puts stderr "BBB" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 1 "ObjectDestroy called" ? {::nsf::object::exists c1} 0 "$::case object still exists in proc" } C create c1 c1 foo ? {::nsf::object::exists c1} 0 "$::case object still exists after proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 1 "ObjectDestroy called" rename c1 "" # # delete the active class # set case "delete active class" nx::test case delete-active-class nx::Class create C -superclass O C method destroy {} {incr ::firstDestroy; puts stderr " *** [current] destroy"; next} C method foo {} { puts stderr "==== $::case [current]" C destroy puts stderr "AAAA [current] exists [::nsf::object::exists [current]]" :set x 1 #? "[current] set x" 1 "$::case can still access [current]" puts stderr "BBB" #? [:info class] ::xotcl::Object "object reclassed" ? [:info class] ::C "object reclassed?" ? "set ::firstDestroy" 0 "firstDestroy called" ? "set ::ObjectDestroy" 0 "ObjectDestroy called" ? {::nsf::object::exists c1} 1 "object still exists in proc" #? {::nsf::is class ::C} 0 "class still exists in proc" ? {::nsf::is class ::C} 1 "class still exists in proc" } C create c1 c1 foo ? {::nsf::object::exists c1} 1 "object still exists after proc" ? [c1 info class] ::nx::Object "after proc: object reclassed?" ? "set ::firstDestroy" 0 "firstDestroy called" ? "set ::ObjectDestroy" 0 "ObjectDestroy called" # # delete active object nested in class # set case "delete active object nested in class" nx::test case delete-active-object-nested-in-class nx::Class create C -superclass O C method destroy {} {incr ::firstDestroy; puts stderr " *** [current] destroy"; next} C method foo {} { puts stderr "==== $::case [current]" C destroy puts stderr "AAAA [current] exists [::nsf::object::exists [current]]" :set x 1 #? "[current] set x" 1 "$::case can still access [current]" puts stderr "BBB" #? "set ::firstDestroy" 0 "firstDestroy called" ? "set ::firstDestroy" 1 "firstDestroy called" #? "set ::ObjectDestroy" 0 "ObjectDestroy called" ? "set ::ObjectDestroy" 1 "ObjectDestroy called" ? [:info class] ::C "object reclassed" #? [:info class] ::xotcl::Object "object reclassed" ? {::nsf::object::exists ::C::c1} 1 "object still exists in proc" ? {::nsf::is class ::C} 1 "class still exists in proc" } C create ::C::c1 C::c1 foo #puts stderr ======[::nsf::object::exists ::C::c1] ? {::nsf::object::exists ::C::c1} 0 "object still exists after proc" ? {::nsf::is class ::C} 0 "class still exists after proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 1 "ObjectDestroy called" # nx::test case nesting-destroy { nx::Object create x nx::Object create x::y x destroy ? {::nsf::object::exists x} 0 "parent object gone" ? {::nsf::object::exists x::y} 0 "child object gone" } nx::test case deleting-aliased-object1 { nx::Object create o nx::Object create o2 # behave like an ensemble: aliased object has self of the caller ::nsf::object::property o2 perobjectdispatch 1 ::nsf::method::alias o a o2 ? {o a} ::o2 "call object via alias" ? {o info object method type a} alias ## the ensemble-object needs per-object methods o2 object method info args {:info {*}$args} o2 object method set args {:set {*}$args} ::nsf::object::property o2 keepcallerself 1 ? {o a info vars} "" "call info on aliased object" ? {o set x 10} 10 "set variable on object" ? {o info vars} x "query vars" ? {o a info vars} x "query vars via alias" ? {o a set x} 10 "set var via alias" o2 destroy #? {o a info vars} "Trying to dispatch deleted object via method 'a'" "1st call on deleted object" #? {o a info vars} "::o: unable to dispatch method 'a'" "2nd call on deleted object" ? {o a info vars} {target "o2" of alias a apparently disappeared} "1st call on deleted object" ? {o a info vars} {target "o2" of alias a apparently disappeared} "2nd call on deleted object" } nx::test case deleting-aliased-object2 { nx::Object create o nx::Object create o2 # The methods of the aliased object have their own self ::nsf::method::alias o a o2 ? {o a} ::o2 "call object via alias" ? {o info object method type a} alias # In order to avoid recursive calls, we have to provide the # selector for the method definitions in nx::Object o2 object method info args {: ::nsf::classes::nx::Object::info {*}$args} o2 object method set args {: ::nsf::classes::nx::Object::set {*}$args} ? {o a info vars} "" "call info on aliased object" ? {o set x 10} 10 "set variable on object o" ? {o info vars} x "query vars of o" ? {o a info vars} "" "query vars via alias (from o2)" ? {o a set y 1} 1 "set var via alias (on o2)" ? {o a info vars} y "query vars via alias (from o2)" o2 destroy #? {o a info vars} "Trying to dispatch deleted object via method 'a'" "1st call on deleted object" #? {o a info vars} "::o: unable to dispatch method 'a'" "2nd call on deleted object" ? {o a info vars} {target "o2" of alias a apparently disappeared} "1st call on deleted object" ? {o a info vars} {target "o2" of alias a apparently disappeared} "2nd call on deleted object" } set case "deleting object with alias to object" nx::test case deleting-object-with-alias-to-object nx::Object create o nx::Object create o3 ::nsf::method::alias o x o3 o destroy ? {::nsf::object::exists o} 0 "parent object gone" ? {::nsf::object::exists o3} 1 "aliased object still here" o3 destroy ? {::nsf::object::exists o3} 0 "aliased object destroyed" set case "create an alias, and delete cmd via aggregation" nx::test case create-alias-delete-via-aggregation nx::Object create o nx::Object create o3 ::nsf::method::alias o x o3 #o::x destroy o3 destroy ? {o x foo} {target "o3" of alias x apparently disappeared} #? {o x foo} {Trying to dispatch deleted object via method 'x'} ? {::nsf::object::exists o3} 0 "aliased object destroyed" o destroy # # create an alias, and recreate obj # nx::test case create-alias-and-recreate-obj { nx::Object create o nx::Object create o3 o object alias x o3 nx::Object create o3 o3 object method set args {: ::nsf::classes::nx::Object::set {*}$args} o x set a 13 ? {o x set a} 13 "aliased object works after recreate" } # # create an alias on the class level, double aliasing, delete aliased # object # nx::test case create-alias-on-class-delete-aliased-obj { nx::Class create C nx::Object create o nx::Object create o3 ::nsf::object::property o keepcallerself 1 ::nsf::object::property o3 keepcallerself 1 ::nsf::object::property o perobjectdispatch 1 ::nsf::object::property o3 perobjectdispatch 1 o object alias a o3 C alias b o o3 object method set args {: ::nsf::classes::nx::Object::set {*}$args} o object method set args {: ::nsf::classes::nx::Object::set {*}$args} C create c1 ? {c1 b set B 2} 2 "call 1st level" ? {c1 b a set A 3} 3 "call 2nd level" ? {c1 set B} 2 "call 1st level ok" ? {c1 set A} 3 "call 2nd level ok" o destroy #? {c1 b} "Trying to dispatch deleted object via method 'b'" "call via alias to deleted object" ? {c1 b} {target "o" of alias b apparently disappeared} "call via alias to deleted object" } # # create an alias on the class level, double aliasing, destroy class # nx::test case create-alias-on-class-destroy-class { nx::Class create C nx::Object create o nx::Object create o3 o object alias a o3 C alias b o C create c1 C destroy ? {::nsf::object::exists o} 1 "object o still here" ? {::nsf::object::exists o3} 1 "object o3 still here" } # # test cases where preexisting namespaces are re-used # nx::test case module { # create a namespace with an object/class in it namespace eval ::module { nx::Object create foo } # reuse the namespace for a class/object nx::Class create ::module ? {::nsf::is class ::module} 1 # delete the object/class ... and namespace ::module destroy ? {::nsf::is class ::module} 0 } nx::test case namespace-import { namespace eval ::module { nx::Class create Foo { :create foo } namespace export Foo foo } nx::Class create ::module { :create mod1 } ? {::nsf::is class ::module::Foo} 1 ? {::nsf::is class ::module::foo} 0 ? {::nsf::object::exists ::module::foo} 1 ? {::nsf::is class ::module} 1 nx::Object create ::o { :require namespace } namespace eval ::o {namespace import ::module::*} ? {::nsf::is class ::o::Foo} 1 ? {::nsf::object::exists ::o::foo} 1 # do not destroy namespace imported objects/classes ::o destroy ? {::nsf::is class ::o::Foo} 0 ? {::nsf::object::exists ::o::foo} 0 ? {::nsf::is class ::module::Foo} 1 ? {::nsf::object::exists ::module::foo} 1 ::module destroy } # to avoid CallDirectly, we could activate this line ::nx::Class create M {:method dealloc args {next}} nx::test case delete-parent-namespace-dealloc namespace eval ::test { nx::Class create C -superclass O C method destroy {} {incr ::firstDestroy; puts stderr " *** [current] destroy"; next} C method foo {} { puts stderr "==== $::case [current]" namespace delete ::test puts stderr "AAAA [current] exists [::nsf::object::exists [current]]" :set x 1 # # If the following line is commented in, the namespace is deleted # here. Is there a bug with nsPtr->activationCount # #? "[current] set x" 1 "$::case can still access [current]" puts stderr "???? [current] exists [::nsf::object::exists [current]]" ? "::nsf::object::exists [current]" 0 ;# WHY? puts stderr "???? [current] exists [::nsf::object::exists [current]]" ? "set ::firstDestroy" 0 "firstDestroy called" ? "set ::ObjectDestroy" 0 "$::case destroy not yet called" } } test::C create test::c1 test::c1 foo ? {::nsf::object::exists test::c1} 0 "object still exists after proc" ? "set ::firstDestroy" 1 "firstDestroy called" ? "set ::ObjectDestroy" 1 "destroy was called when popping stack frame" ? {::nsf::object::exists ::test::C} 0 "class still exists after proc" ? {namespace exists ::test::C} 0 "namespace ::test::C still exists after proc" ? {namespace exists ::test} 1 "parent ::test namespace still exists after proc" ? {namespace exists ::xotcl::classes::test::C} 0 "namespace ::xotcl::classes::test::C still exists after proc" nx::test case destroy-during-init { # create class nx::Class create Foo { :public method bar {} {return 1} :public method baz {} {return 2} } # create object Foo create f1 { :bar; :baz; :destroy } ? {info command f1} "" "explicit destroy of object" set c [nx::Class new { :public method bar {} {return 1} :public method baz {} {return 2} :new { :bar; :baz; :destroy } :destroy }] ? [list info command $c] "" "explicit destroy of class" package require nx::volatile ::nsf::method::require ::nx::Object volatile # create new class and object and cleanup everything set x [nx::Class new { :volatile :public method bar {} {return 1} :public method baz {} {return 2} :new { :volatile; :bar; :baz } }] ? [list info command $x] "" "destroy via volatile" set x [nx::Class new -volatile { :public method bar {} {return 1} :public method baz {} {return 2} :new { :volatile; :bar; :baz } }] ? [list info command $x] $x "destroy via volatile method" # create new class and object and cleanup everything + 2 filters ::nx::Object public method f1 args {next} ::nx::Object public method f2 args {next} ::nx::Object filters set {f1 f2} set x [nx::Class new { :volatile :public method bar {} {return 1} :public method baz {} {return 2} :new { :volatile; :bar; :baz } }] ? [list info command $x] "" "destroy via volatile + 2 filters" set x [nx::Class new -volatile { :public method bar {} {return 1} :public method baz {} {return 2} :new { :volatile; :bar; :baz } }] ? [list info command $x] $x "destroy via volatile method + 2 filters" ::nx::Object filters set "" } nx::test case nested-ordered-composite { # The following test case an explicit deletion/redefinition of an # toplevel object (o1) will cause the implicit deletion of a nested # object o1::o2. The object o2 has as well several included objects, # containing an "ordered composite". The deletion of the ordered # compostite causes the (explicit) deletion of its siblings (all # children of o1::o2). This is actually a stress test for the deletion # of o2's namespace, since the loop over its children will be # confronted with the deletion of indirectly deleted items (deleted by # the deletion of the ordered composite). nx::Class create C { :property os :public method destroy {} { #puts stderr "[self] destroy ${:os}" foreach o ${:os} { if {[::nsf::object::exists $o]} { #puts stderr "--D $o destroy" $o destroy } next } } } # # 10 siblings of oc1: # deletion order in bucket: 8 4 10 9 5 1 6 2 oc1 7 3 # oc1 deletes 7 and 3, fine # ... loop might run into an epoched cmd -> might crash # set c 0 for {set i 0} {$i < 10} {incr i} { set os [list] for {set j 0} {$j < 10} {incr j} {lappend os ::o1::o2::[incr c]} nx::Object create ::o1 nx::Object create ::o1::o2 foreach o $os {nx::Object create $o} C create ::o1::o2::oc1 -os $os ? {llength [o1 info children]} 1 ? {llength [o1::o2 info children]} 11 } ### 20 siblings of oc1 (has to be >12): # deletion order in bucket: 17 18 1 20 19 2 3 4 5 6 7 8 9 19 11 oc1 12 13 14 15 16 # oc1 deletes 12 13 14 15 16 # after destroy of oc1 # a) NextHashEntry(hSearch) returns valid looking hPtr # b) Tcl_GetHashValue(hPtr) returns garbage (uninitialized memory?) instead of cmd # --> might crash # set c 0 for {set i 0} {$i < 10} {incr i} { set os [list] for {set j 0} {$j < 20} {incr j} {lappend os ::o1::o2::[incr c]} nx::Object create ::o1 nx::Object create ::o1::o2 foreach o $os {nx::Object create $o} C create ::o1::o2::oc1 -os $os ? {llength [o1 info children]} 1 ? {llength [o1::o2 info children]} 21 } # similar to above, but this time partial deletes occur set c 0 for {set i 0} {$i < 10} {incr i} { set os [list] for {set j 0} {$j < 20} {incr j} {lappend os ::o1::o2::[incr c]} nx::Object create ::o1 nx::Object create ::o1::o2 foreach o $os {nx::Object create $o} C create ::o1::o2::ocX -os {} C create ::o1::o2::ocY -os $os ? {llength [o1 info children]} 1 ? {llength [o1::o2 info children]} 22 } } # # The following tests the deletion order triggering implicit # deletions. This caused a crash in nsf 2.0b2. # package req nx::serializer nx::test case class-object-property { nx::Class create C { :object property -accessor public x :property a:int } ? {::nsf::object::exists ::C} 1 ? {::nsf::object::exists ::C::slot} 1 set s(C) [C serialize] C destroy ? {::nsf::object::exists ::C} 0 ? {::nsf::object::exists ::C::slot} 0 eval $s(C) ? {::nsf::object::exists ::C} 1 ? {::nsf::object::exists ::C::slot} 1 C::slot destroy ? {::nsf::object::exists ::C} 1 ? {::nsf::object::exists ::C::slot} 0 C destroy ? {::nsf::object::exists ::C} 0 } nx::test case unset-traces-during-cleanup { global i set i [interp create] $i eval { package req nx nx::Object create o { set :x 100 # The following line is tricky: the trailing ";#" # is used to trim the undesirable extra arguments # from the trace command. ::trace add variable :x unset "[list set ::X ${:x}];#" } } ? {$i eval {info exists ::X}} 0 $i eval {::nsf::finalize -keepvars} ? {$i eval {info exists ::X}} 1 ? {$i eval {set ::X}} 100 interp delete $i unset i } nx::test case unset-traces-during-cleanup-with-destroy { # # Make sure that a very-late destroy (in the unset trace) does not # fire ... and does not cause any side effects. # global i set i [interp create] $i eval { package req nx nx::Object create o { :public object method destroy args { incr ::X next } set :x 100 # The following line is tricky: the trailing ";#" # is used to trim the undesirable extra arguments # from the trace command. ::trace add variable :x unset "[list ::incr ::X]; [list [self] destroy];#" } } ? {$i eval {info exists ::X}} 0 $i eval {::nsf::finalize -keepvars} ? {$i eval {info exists ::X}} 1 ? {$i eval {set ::X}} 2 interp delete $i unset i } nx::test case unset-traces-during-cleanup-with-destroy-2 { # # We are safe when trying to delete the base class/metaclass ... # global i set i [interp create] $i eval { package req nx nx::Object create o { set :x _ # The following line is tricky: the trailing ";#" # is used to trim the undesirable extra arguments # from the trace command. ::trace add variable :x unset "[list catch [list ::nx::Object destroy] msg1]; [list catch [list ::nx::Class destroy] msg2]; set ::MSG \[list \$msg1 \$msg2\];#" } } ? {$i eval {info exists ::MSG}} 0 $i eval {::nsf::finalize -keepvars} ? {$i eval {info exists ::MSG}} 1 ? {$i eval {set ::MSG}} [list "cannot destroy base class ::nx::Object" "cannot destroy base class ::nx::Class"] interp delete $i unset i } nx::test case unset-traces-during-cleanup-with-reset { # # Check for leaks ... # global i set i [interp create] $i eval { package req nx nx::Object create o { set :x 100 # The following line is tricky: the trailing ";#" # is used to trim the undesirable extra arguments # from the trace command. ::trace add variable :x unset "[list ::nsf::var::set [self] x ${:x}];#" } } ? {$i eval {::nsf::object::exists ::o}} 1 ? {$i eval {info commands ::o}} ::o $i eval {::nsf::finalize -keepvars} ? {$i eval {info commands ::o}} "" interp delete $i unset i } # # Test on UnsetTracedVars() under revived vars & unset traces # for per-object variable tables (no namespace involved). # nx::test case unset-traces-during-cleanup-with-reset-2 { global i set i [interp create] $i eval { package req nx set ::called(reset) 0 proc ::reset {obj var value} { # # ... revive object variable 'x' and add yet another unset trace # ::nsf::var::set $obj $var $value $obj eval [list ::trace add variable :$var unset \ "incr ::called(reset); ::reset $obj $var $value; #"] } nx::Object create ::o ::reset ::o x 100 } ? {$i eval {::nsf::object::exists ::o}} 1 ? {$i eval {info commands ::o}} ::o ? {$i eval {namespace exists ::o}} 0 ? {$i eval {set ::called(reset)}} 0 $i eval {::nsf::finalize -keepvars} ? {$i eval {info commands ::o}} "" ? {$i eval {namespace exists ::o}} 0 # ? {$i eval {set ::called(reset)}} 1; # unset trace, also re-registered, is only called once! interp delete $i unset i } # # Test on UnsetTracedVars() under revived vars & unset traces # for namespaced variable tables. # nx::test case unset-traces-during-cleanup-with-reset-3 { global i set i [interp create] $i eval { package req nx set ::called(reset) 0 proc ::reset {obj var value} { # # ... revive object variable 'x' and add yet another unset trace # ::set ${obj}::$var $value $obj eval [list ::trace add variable ${obj}::$var unset \ "incr ::called(reset); ::reset $obj $var $value; #"] } nx::Object create ::o { :require namespace } ::reset ::o x 100 } ? {$i eval {::nsf::object::exists ::o}} 1 ? {$i eval {info commands ::o}} ::o ? {$i eval {namespace exists ::o}} 1 ? {$i eval {set ::called(reset)}} 0 $i eval {::nsf::finalize -keepvars} ? {$i eval {info commands ::o}} "" ? {$i eval {namespace exists ::o}} 0 ? {$i eval {set ::called(reset)}} 1; # unset trace, also re-registered, is only called once! interp delete $i unset i } # # Exercise renaming of cmds which are used as methods # nx::test case rename-cached-method { # Create a class with a namespace nx::Class create A {:public object method foo args {}} # # Add a proc named "new" to the namespace of the class. # This is not recommended, but we can't avoid it. # proc ::A::new {} { return "something from A" } # # Call the proc via the method interface. After the call the cmd is # cached in the Tcl_Obj "new". # ? {A new} "something from A" # # Delete the proc. The rename command has to take care, that the # cached cmd has to be invalidated. # rename ::A::new "" # # We expect that the original method works again. # ? {string match ::nsf::__#* [A new]} 1 # # Now try the same with the internal namespace from nsf. Messing # around there is even less wanted, but still, we can't avoid this. # We make first a backup of the method. # rename ::nsf::classes::nx::Class::new ::nsf::classes::nx::Class::new.orig proc ::nsf::classes::nx::Class::new {} { return "something" } ? {A new} "something" # # Delete the proc and call "new" again # rename ::nsf::classes::nx::Class::new "" ? {A new} "method 'new' unknown for ::A; in order to create an instance of class ::A, consider using '::A create new ?...?'" # # Restore the original state # rename ::nsf::classes::nx::Class::new.orig ::nsf::classes::nx::Class::new # # We expect that the original method works again. # ? {string match ::nsf::__#* [A new]} 1 } # # Create a cyclical class dependency and delete it manually # nx::test case cyclical-dependency { nx::Object create o1 ? {nx::Class create o1::C} ::o1::C ? {nsf::relation::set o1 class o1::C} ::o1::C o1 destroy } # # Create a cyclical class dependency and let it be deleted on # object-system-cleanup # nx::Object create o1 nx::Class create o1::C nsf::relation::set o1 class o1::C # # Create a cyclical superclass dependency and delete it manually # nx::test case cyclical-dependency { nx::Class create C nx::Class create C::* ? {nsf::relation::set C superclass {C::* nx::Object}} "" C destroy } # # Create a cyclical superclass dependency and let it be deleted on # object-system-cleanup # nx::Class create C nx::Class create C::* nsf::relation::set C superclass {C::* nx::Object} puts "==== EXIT [info script]" # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/submethods.test000644 000766 000024 00000111732 14164660410 017417 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx::test ::nx::configure defaultMethodCallProtection false # # test, whether error message from a submethod contains method path # nx::test case info-errors { ? {::nx::Object info subclasses a b c} \ {invalid argument 'b', maybe too many arguments; should be "::nx::Object info subclasses ?-closure? ?-dependent? ?/pattern/?"} ? {::nx::Object info object mixins a b c} \ {invalid argument 'b', maybe too many arguments; should be "::nx::Object info object mixins ?-guards? ?/pattern/?"} } nx::test configure -count 10 nx::test case submethods { #Object method unknown {} {} Object create o1 ? {o1 foo} "::o1: unable to dispatch method 'foo'" # # test subcmd "tricky" names # - names called on ensemble objects from C (defaultmethod, unknown) # - names equal to helper methods of the ensemble object # Object create o { :object method "string length" x {return [current method]} :object method "string tolower" x {return [current method]} :object method "string info" x {return [current method]} :object method "foo a x" {} {return [current method]} :object method "foo a y" {} {return [current method]} :object method "foo a subcmdName" {} {return [current method]} :object method "foo a defaultmethod" {} {return [current method]} :object method "foo a unknown" args {return [current method]} :object method "foo b" {} {return [current method]} } Class create Foo { :method "bar m1" {a:integer -flag} {;} :method "bar m2" {x:integer -y:boolean} {;} :method "baz a m1" {x:integer -y:boolean} {return m1} :method "baz a m2" {x:integer -y:boolean} {;} :method "baz b" {} {;} } ? {o string length 1} length ? {o string tolower 2} tolower ? {o string toupper 2} \ {unable to dispatch sub-method "toupper" of ::o string; valid are: string info, string length, string tolower} ? {o string} "valid submethods of ::o string: info length tolower" ? {o foo a x} "x" ? {o foo a y} "y" ? {o foo a z} \ {unable to dispatch sub-method "z" of ::o foo a; valid are: foo a defaultmethod, foo a subcmdName, foo a unknown, foo a x, foo a y} ? {o info object method type string} object # the following is a problem, when string has subcmd "info" #? {o::string info class} ::nx::EnsembleObject ? {o string length aaa} "length" ? {o string info class} "info" ? {o string hugo} \ {unable to dispatch sub-method "hugo" of ::o string; valid are: string info, string length, string tolower} Foo create f1 ? {f1 baz a m1 10} m1 ? {f1 baz a m3 10} \ {unable to dispatch sub-method "m3" of ::f1 baz a; valid are: baz a m1, baz a m2} #unable to dispatch method baz a m3; valid subcommands of a: m1 m2 # } nx::test configure -count 1 nx::test case defaultmethod { Object create o { :object method "string length" x {return [current method]} :object method "string tolower" x {return [current method]} :object method "string info" x {return [current method]} :object method "foo a x" {} {return [current method]} :object method "foo a y" {} {return [current method]} :object method "foo a subcmdName" {} {return [current method]} :object method "foo a defaultmethod" {} {return [current method]} :object method "foo a unknown" args {return [current method]} :object method "foo b" {} {return [current method]} } Class create Foo { :method "bar m1" {a:integer -flag} {;} :method "bar m2" {x:integer -y:boolean} {;} :method "baz a m1" {x:integer -y:boolean} {return m1} :method "baz a m2" {x:integer -y:boolean} {;} :method "baz b" {} {;} :create f1 } ? {o string} "valid submethods of ::o string: info length tolower" ? {o foo} "valid submethods of ::o foo: a b" ? {f1 bar} "valid submethods of ::f1 bar: m1 m2" ? {f1 baz} "valid submethods of ::f1 baz: a b" ? {f1 baz a} "valid submethods of ::f1 baz a: m1 m2" } # # testing ensemble objects with next # nx::test configure -count 1 nx::test case ensemble-next { nx::Class create FOO { # reduced ensemble :method foo args {lappend :v "FOO.foo//[nx::current method] ([nx::current args])"} # expanded ensemble :method "l1 l2 l3a" {x} { lappend :v "FOO.l1 l2 l3a//[nx::current method] ([nx::current args])" } :method "l1 l2 l3b" {x} { lappend :v "FOO.l1 l2 l3b//[nx::current method] ([nx::current args])" } # uplevel :method "bar x" {varname} {upvar $varname v; return [info exists v]} :method "baz" {} { set hugo 1 return [:bar x hugo] } } nx::Class create M0 { :method "foo b x" {x} { lappend :v "M0.foo b x//[nx::current method] ([nx::current args])" nx::next } :method "foo b y" {x} { lappend :v "M0.foo b y//[nx::current method] ([nx::current args])" nx::next } :method "foo a" {x} { lappend :v "M0.foo a//[nx::current method] ([nx::current args])" nx::next } :method "l1 l2" {args} { lappend :v "l1 l2//[nx::current method] ([nx::current args])" nx::next } } nx::Class create M1 { :method "foo a" {x} { set :v [list "M1.foo a //[nx::current method] ([nx::current args])"] nx::next } :method "foo b x" {x} { set :v [list "M1.foo b x //[nx::current method] ([nx::current args])"] nx::next } :method "foo b y" {x} { set :v [list "M1.foo b y //[nx::current method] ([nx::current args])"] nx::next } :method "l1 l2 l3a" {x} { set :v [list "M1.l1 l2 l3a//[nx::current method] ([nx::current args])"] nx::next } :method "l1 l2 l3b" {x} { set :v [list "M1.l1 l2 l3b//[nx::current method] ([nx::current args])"] nx::next } } FOO mixins set {M1 M0} FOO create f1 # # The last list element shows handling of less deep ensembles # (longer arg list is passed) # ? {f1 foo a 1} "{M1.foo a //a (1)} {M0.foo a//a (1)} {FOO.foo//foo (a 1)}" ? {f1 foo b x 1} "{M1.foo b x //x (1)} {M0.foo b x//x (1)} {FOO.foo//foo (b x 1)}" ? {f1 foo b y 1} "{M1.foo b y //y (1)} {M0.foo b y//y (1)} {FOO.foo//foo (b y 1)}" # # The middle list element shows shrinking (less deep ensembles), the # last element shows expansion via mixin (deeper ensemble is reached # via next) # ? {f1 l1 l2 l3a 100} "{M1.l1 l2 l3a//l3a (100)} {l1 l2//l2 (l3a 100)} {FOO.l1 l2 l3a//l3a (100)}" } nx::test case ensemble-partial-next { nx::Class create M { :public method "info has namespace" {} { nx::next return sometimes } :public method "info has something else" {} { return something } :public method "info has something path" {} { return [::nsf::current methodpath] } :public method "info has something better" {} { nx::next return better } :public method foo {} { return [::nsf::current methodpath] } } nx::Object mixins add M nx::Object create o1 # call a submethod defined by a mixin, which does a next ? {o1 info has namespace} sometimes # call a submethod, which is not defined by the mixin ? {o1 info has type Object} 1 ? {o1 info has type M} 0 # call a submethod, which is nowhere defined ? {o1 info has typo M} \ {unable to dispatch sub-method "typo" of ::o1 info has; valid are: info has mixin, info has namespace, info has something better, info has something else, info has something path, info has type} # call a submethod, which is only defined in the mixin ? {o1 info has something else} something # call a submethod, which is only defined in the mixin, and which # does a next (which should not complain) ? {o1 info has something better} better # ensemble path excluding "wrong" is mixed in ? {o1 info has something wrong} \ {unable to dispatch sub-method "wrong" of ::o1 info has something; valid are: info has something better, info has something else, info has something path} # call defaultcmds on ensembles ? {lsort [o1 info has something]} "valid submethods of ::o1 info has something: better else path" # defaultcmd has to return also subcmds of other shadowed ensembles ? {lsort [o1 info has]} "valid submethods of ::o1 info has: mixin namespace something type" ? {lsort [o1 info]} \ "valid submethods of ::o1 info: baseclass children class has info lookup name object parent precedence variable vars" # returning methodpath in ensemble ? {o1 info has something path} "info has something path" # returning methodpath outside ensemble ? {o1 foo} "foo" } # # Check behavior of upvars in ensemble methods # nx::test case ensemble-upvar { nx::Class create FOO { :method "bar0 x" {varname} {upvar $varname v; return [info exists v]} :method "baz0" {} { set hugo 1 return [:bar0 x hugo] } :method "bar1 x" {varname} {:upvar $varname v; return [info exists v]} :method "baz1" {} { set hugo 1 return [:bar1 x hugo] } :create f1 } ? {f1 baz0} 0 ? {f1 baz1} 1 } # # Check behavior of next with arguments within an ensemble # nx::test case ensemble-next-with-args { nx::Object create o { :object method foo {x} {return $x} :object method "e1 sm" {x} {return $x} :object method "e2 sm1 sm2" {x} {return $x} :object method "e2 e2 e2" {x} {return $x} :object method "e1 e1 e1" args {return $args} } nx::Class create M { :method foo {} {next 1} :method "e1 sm" {} {next 2} :method "e2 sm1 sm2" {} {next 3} :method "e2 e2 e2" {} {next 4} :method "e1 e1 e1" args {next {e1 e1 e1}} } o object mixins add M # case without ensemble ? {o foo} 1 # ensemble depth 1, 1 arg ? {o e1 sm} 2 # ensemble depth 2, 1 arg ? {o e2 sm1 sm2} 3 # ensemble depth 2, 1 arg, same tcl-objs ? {o e2 e2 e2} 4 # ensemble depth 2, multiple args, same tcl-objs ? {o e1 e1 e1} {e1 e1 e1} } nx::test configure -count 1 nx::test case ensemble-next-with-colon-prefix namespace eval ::ns1 { nx::Object create obj { :public object method foo {} { return [:info class] } :public object method ifoo {} { [current] ::nsf::methods::object::info::lookupmethod info} } ? {obj info class} ::nx::Object ? {obj info lookup method info} ::nsf::classes::nx::Object::info ? {obj ifoo} ::nsf::classes::nx::Object::info ? {obj foo} ::nx::Object set infolookup ::nsf::methods::object::info::lookupmethod set infomethod ::nsf::methods::object::info::method ? [list obj $infolookup info] ::nsf::classes::nx::Object::info ? [list obj $infomethod type ::nsf::classes::nx::Object::info] alias obj object method info {} {;} ? [list obj $infolookup info] ::ns1::obj::info ? [list obj $infomethod type ::ns1::obj::info] scripted ? {obj ifoo} ::ns1::obj::info ? {obj foo} {wrong # args: should be ":info"} # Now we try to overwrite the object specific method with an object # named "info" ? {nx::Object create obj::info} "refuse to overwrite cmd ::ns1::obj::info; delete/rename it before overwriting" rename obj::info "" ? {nx::Object create obj::info} ::ns1::obj::info ? [list obj $infolookup info] ::ns1::obj::info ? [list obj $infomethod type ::ns1::obj::info] object ? {obj ifoo} ::ns1::obj::info # To some surprise, we can can still call info class! # This works, since we do here an "ensemble-next" #? {obj info class} ::nx::Object ? {obj info class} {::ns1::obj::info: unable to dispatch method 'class'} # The ensemble-next has in case of foo the leading colon on the # callstack (e.g. ":info"). Make sure that we can still call the # method via ensemle-next. #? {obj foo} ::nx::Object ? {obj foo} {::ns1::obj::info: unable to dispatch method 'class'} } # # Leaf next: Do not trigger unknown handling (see also # NextSearchAndInvoke()) # nx::test case leaf-next-in-submethods { nx::Object create container { set :x 0 :public object method "FOO bar" {} { incr :x; next; # a "leaf next" } :public object method intercept args { incr :x; next; # a "filter next" } :object filters set intercept :FOO bar # Rationale: A call count > 2 would indicate that the leaf next # triggers a further call into filter ... ? [list set _ ${:x}] 2 } } nx::test case object-unknown { # # object level ensemble # nx::Object create o1 { :object method "i o a" {} {return a} :object method "i o b" {} {return b} } ? {o1 i o x} {unable to dispatch sub-method "x" of ::o1 i o; valid are: i o a, i o b} # # object level ensemble on class # nx::Class create C { :public object alias "i o a" ::nsf::methods::class::info::heritage :public object alias "i o b" ::nsf::methods::class::info::heritage } ? {C i o x} {unable to dispatch sub-method "x" of ::C i o; valid are: i o a, i o b} ? {C i o x y} {unable to dispatch sub-method "x" of ::C i o; valid are: i o a, i o b} # # Emulate the "info" and "info object" ensembles on nx::Object and nx::Class # nx::Object public method "i o a" {} {return a} nx::Object public alias "i o b" ::nsf::methods::class::info::heritage nx::Class public alias "i a" ::nsf::methods::class::info::heritage nx::Class public alias "i b" ::nsf::methods::class::info::heritage nx::Class create D {} ? {D i p} {unable to dispatch sub-method "p" of ::D i; valid are: i a, i b, i o a, i o b} ? {D i o a} a ? {D i o x} {unable to dispatch sub-method "x" of ::D i o; valid are: i o a, i o b} ? {D i o x y} {unable to dispatch sub-method "x" of ::D i o; valid are: i o a, i o b} ::nsf::method::delete nx::Class i ::nsf::method::delete nx::Object i } nx::test case unknown-in-info { nx::Class create C catch {C info x y z} err ? [list string match {unable to dispatch sub-method "x" of ::C info; valid are:*} $err] 1 #C info object x y z catch {C info object x y z} err ? [list string match {unable to dispatch sub-method "x" of ::C info object; valid are:*} $err] 1; ## --> unable to dispatch sub-method "object" of ::C info; valid are: } nx::test case submethods-and-filters { # # submethods as filters? # #set h [C public method "BAR bar" args { # next #}] #C filter {{BAR bar}} } nx::test case submethods-current-introspection { # # [current] & [current class] # nx::Object create o o public object method "FOO foo" {} { return "-[current]-[current class]-" } ? {o FOO foo} -::o-- Class create C C public method "FOO foo" {} { return "-[current]-[current class]-" } C create c ? {c FOO foo} -::c-::C- C mixins set [Class create M1 { :public method "FOO foo" {} { return "-[current]-[current class][next]" } }] ? {c FOO foo} -::c-::M1-::c-::C- o object mixins set ::M1 ? {o FOO foo} -::o-::M1-::o-- o object mixins set {} C mixins set {} # # limit [current methodpath] to collect only ensemble methods? # o eval { :public object method faz {} {return [current methodpath]} ? [list set _ [:faz]] "faz" } # # [current callingmethod] & [current callingclass] # o eval { set body {expr {[:bar] eq "[current class]-[current]-[current methodpath]"}} :public object method "FOO foo" {} $body :public object method "BAR BUU boo" {} $body :public object method baz {} $body set calleeBody {return "[current callingclass]-[current callingobject]-[current callingmethod]"} :public object method bar {} $calleeBody } ? {o FOO foo} 1 "instance method ensemble 1" ? {o BAR BUU boo} 1 "instance method ensemble 2" ? {o baz} 1 "instance method" o eval { set calleeBody {return "[current callingclass]-[current callingobject]-[current callingmethod]"} :object method "a b" {} $calleeBody set body {expr {[:a b] eq "[current class]-[current]-[current methodpath]"}} :public object method "FOO foo" {} $body :public object method "BAR BUU boo" {} $body :public object method baz {} $body } ? {o FOO foo} 1 "object method ensemble 1" ? {o BAR BUU boo} 1 "object method ensemble 2" ? {o baz} 1 "object method" o eval { # TODO: :method "a b c" {} $calleeBody; FAILS -> "can't append to scripted" set calleeBody {return "[current callingclass]-[current callingobject]-[current callingmethod]"} :object method "x y z" {} $calleeBody; set body {expr {[:x y z] eq "[current class]-[current]-[current methodpath]"}} :public object method "FOO foo" {} $body :public object method "BAR BUU boo" {} $body :public object method baz {} $body } ? {o FOO foo} 1 "class level object method ensemble 1" ? {o BAR BUU boo} 1 "class level object method ensemble 2" ? {o baz} 1 "class level object method" # # Make sure that [current callingclass] works for submethods, as # expected # C eval { set body {expr {[:bar] eq "[current class]-[current]-[current methodpath]"}} :public method "FOO foo" {} $body :public method "BAR BUU boo" {} $body :public method baz {} $body :method bar {} { return "[current callingclass]-[current callingobject]-[current callingmethod]" } } set c [C new] ? [list $c FOO foo] 1 ? [list $c BAR BUU boo] 1 ? [list $c baz] 1 # # [current calledmethod] # [current calledclass] # # Note: In my reading, [current calledmethod] cannot be made aware # of the methodpath of a submethod call being intercepted. This is # due to the callstack structure at the time of executing the filter # stack which is entirely agnostic of the submethod dispatch (this # dispatch has not occurred yet). For the same reason, we cannot # record the method path in the filter stack structure. # # From the filter method's perspective, the submethod selectors # ("foo" and "BUU boo" below) are simply arguments provided to the # top-level method. They can only be processed as part of the # filter-local argv. Class create Z { :object property msg :method intercept args { [current class] eval [list set :msg [list [lrange [current methodpath] 1 end-1] \ [current calledmethod] \ [current calledclass] \ [current nextmethod]]] next } } set c [Z new] Z filters set intercept foreach selector [list "FOO foo" "BAR BUU boo" "baz"] { Z public method $selector {} {;} set root [lindex $selector 0] set mh [Z info method registrationhandle $root] $c {*}$selector ? [list set _ [join [Z cget -msg] -]] -$root-::Z-$mh } Z filters set {} } # # Test current args in ensemble methods # nx::test case current-args { nx::Class create C { :method foo {{-x 1} z:optional} {return [current args]} :method "bar foo" {{-x 1} z:optional} {return [current args]} :create c1 } ? {c1 foo} "" ? {c1 bar foo} "" ? {c1 foo -x 2} "-x 2" ? {c1 bar foo -x 2} "-x 2" } # # Test keepcallerself and perobjectdispatch with their respective # interactions for plain object dispatch and for object dispatch via # method interface # nx::test case per-object-dispatch { nx::Class create C { :public method foo {} {return foo-[self]} :public method baz {} {return [c1::1 baz]} :create c1 { :public object method bar {} {return bar-[self]} } } ? {c1 foo} "foo-::c1" ? {c1 bar} "bar-::c1" C create c1::1 { :public object method bar {} {return bar-[self]} :public object method baz {} {return baz-[self]} } # # Just the same as above # ? {c1::1 foo} "foo-::c1::1" ? {c1::1 bar} "bar-::c1::1" # if we specify anything special, then we have per-default # - keepcallerself false # - perobjectdispatch false ? {c1 1 foo} "foo-::c1::1" ? {c1 1 bar} "bar-::c1::1" ? {c1 baz} "baz-::c1::1" # just make setting explicit ::nsf::object::property ::c1::1 keepcallerself off ::nsf::object::property ::c1::1 perobjectdispatch off ? {c1 1 foo} "foo-::c1::1" ? {c1 1 bar} "bar-::c1::1" ? {c1 baz} "baz-::c1::1" # keepcallerself off - the self in the called method is the invoked object # perobjectdispatch on - the instance method is not callable ::nsf::object::property ::c1::1 keepcallerself off ::nsf::object::property ::c1::1 perobjectdispatch on ? {c1 1 foo} {::c1::1: unable to dispatch method 'foo'} ? {c1 1 bar} "bar-::c1::1" ? {c1 baz} "baz-::c1::1" # keepcallerself on - the self in the called method is the caller # perobjectdispatch on - the instance method is not callable ::nsf::object::property ::c1::1 keepcallerself on ::nsf::object::property ::c1::1 perobjectdispatch on ? {c1 1 foo} {::c1::1: unable to dispatch method 'foo'} ? {c1 1 bar} "bar-::c1" #### ignore keepcallerself via interface with explicit receiver intentionally ? {c1 baz} "baz-::c1::1" # keepcallerself on - the self in the called method is the caller # perobjectdispatch off - the instance method is callable ::nsf::object::property ::c1::1 keepcallerself on ::nsf::object::property ::c1::1 perobjectdispatch off ? {c1 1 foo} "foo-::c1" ? {c1 1 bar} "bar-::c1" #### ignore keepcallerself via interface with explicit receiver intentionally ? {c1 baz} "baz-::c1::1" } # # Test forwarding to child object, with respect to settings of the # object properties keepcallerself and allowmethoddispatch # nx::test configure -count 1000 nx::test case child-obj-delegation { nx::Object create obj { nx::Object create [self]::child { :public object method foo {} {return [self]} } :public object forward link1 {%[self]::child} :public object forward link2 :child :public object method link3 args {[self]::child {*}$args} :public object alias link4 [self]::child :public object forward link5 [self]::child } # # Default case # keepcallerself false # perobjectdispatch false # ::nsf::object::property obj::child keepcallerself false ::nsf::object::property obj::child perobjectdispatch false ? {obj link1 foo} {::obj::child} #? {obj link2 foo} {::obj: unable to dispatch method 'child'} ? {obj link2 foo} {::obj::child} ? {obj link3 foo} {::obj::child} ? {obj link4 foo} {::obj::child} ? {obj link5 foo} {::obj::child} ? {obj child foo} {::obj::child} #? {lsort [obj info object methods child]} {} #? {lsort [obj info object methods]} {link1 link2 link3 link4 link5} #? {lsort [obj info lookup methods child]} {} #? {lsort [obj info lookup methods child*]} {} ? {lsort [obj info object methods child]} {child} ? {lsort [obj info object methods]} {child link1 link2 link3 link4 link5} ? {lsort [obj info lookup methods child]} {child} ? {lsort [obj info lookup methods child*]} {child} # # turn on keepcallerself and perobjectdispatch # ::nsf::object::property obj::child keepcallerself true ::nsf::object::property obj::child perobjectdispatch true ? {obj link1 foo} {::obj::child} #? {obj link2 foo} {::obj: unable to dispatch method 'child'} ? {obj link2 foo} {::obj} ? {obj link3 foo} {::obj::child} ? {obj link4 foo} {::obj} ? {obj link5 foo} {::obj::child} ? {obj child foo} {::obj} #? {lsort [obj info object methods child]} {} #? {lsort [obj info object methods]} {link1 link2 link3 link4 link5} #? {lsort [obj info lookup methods child]} {} #? {lsort [obj info lookup methods child*]} {} ? {lsort [obj info object methods child]} {child} ? {lsort [obj info object methods]} {child link1 link2 link3 link4 link5} ? {lsort [obj info lookup methods child]} {child} ? {lsort [obj info lookup methods child*]} {child} # # just perobjectdispatch # ::nsf::object::property obj::child keepcallerself false ::nsf::object::property obj::child perobjectdispatch true ? {obj link1 foo} {::obj::child} ? {obj link2 foo} {::obj::child} ? {obj link3 foo} {::obj::child} ? {obj link4 foo} {::obj::child} ? {obj link5 foo} {::obj::child} ? {obj child foo} {::obj::child} ? {lsort [obj info object methods child]} {child} ? {lsort [obj info object methods]} {child link1 link2 link3 link4 link5} ? {lsort [obj info lookup methods child]} {child} ? {lsort [obj info lookup methods child*]} {child} # # just keepcallerself # ::nsf::object::property obj::child keepcallerself true ::nsf::object::property obj::child perobjectdispatch false ? {obj link1 foo} {::obj::child} #? {obj link2 foo} {::obj: unable to dispatch method 'foo'} ? {obj link2 foo} {::obj} ? {obj link3 foo} {::obj::child} #? {obj link4 foo} {::obj: unable to dispatch method 'foo'} ? {obj link4 foo} {::obj} ? {obj link5 foo} {::obj::child} #? {obj child foo} {::obj: unable to dispatch method 'foo'} ? {obj child foo} {::obj} ? {lsort [obj info object methods child]} {child} ? {lsort [obj info object methods]} {child link1 link2 link3 link4 link5} ? {lsort [obj info lookup methods child]} {child} ? {lsort [obj info lookup methods child*]} {child} } # # Examplify the current behavior of "keepcallerself" with and without # the setting of "perobjectdispatch" # nx::test configure -count 1 nx::test case keepcallerself { nx::Class create C {:public method foo {} {return C-[self]}} nx::Class create D {:public method foo {} {return D-[self]}} C create c1 { ::nsf::object::property [self] keepcallerself true :public object method bar {} {return c1-[self]} :public object method baz {} {return c1-[self]} } D create d1 { :public object method bar {} {return d1-[self]} :public object alias c1 ::c1 } # The normal dispatch ignores the keepcallerself completely ? {c1 bar} c1-::c1 ? {c1 foo} C-::c1 ? {c1 baz} c1-::c1 # The dispatch via object aliased method calls actually "d1 bar", # although c1 is in the dispatch path #? {d1 c1 bar} d1-::d1 #? {d1 c1 foo} D-::d1 #? {d1 c1 baz} "::d1: unable to dispatch method 'baz'" ? {d1 c1 bar} c1-::d1 ? {d1 c1 foo} C-::d1 ? {d1 c1 baz} c1-::d1 # The destroy destroys actually d1, not c1, although destroy is # dispatched originally on c1 ? {d1 c1 destroy} "" ? {nsf::object::exists d1} 0 ? {nsf::object::exists c1} 1 # So, keepcallerself is currently pretty useless, unless used in # combination with "perobjectdispatch", which we set in the # following test cases C create c1 { ::nsf::object::property [self] keepcallerself true ::nsf::object::property [self] perobjectdispatch true :public object method bar {} {return c1-[self]} :public object method baz {} {return c1-[self]} } D create d1 { :public object method bar {} {return d1-[self]} :public object alias c1 ::c1 } # The normal dispatch ignores the keepcallerself and # perobjectdispatch completely ? {c1 bar} c1-::c1 ? {c1 foo} C-::c1 ? {c1 baz} c1-::c1 # The dispatch via object aliased method calls actually "d1 bar", # although c1 is in the dispatch path ? {d1 c1 bar} c1-::d1 ? {d1 c1 foo} "::c1: unable to dispatch method 'foo'" ? {d1 c1 baz} c1-::d1 } nx::test case ensemble-vs-simple-method { ? {nx::Class create C} ::C ? {C public method foo {args} {return foo/1}} "::nsf::classes::C::foo" ? {C public method "foo x" {args} {return foo/2}} \ {refuse to overwrite method foo; delete/rename method first.} ? {C public method "foo x y" {args} {return foo/3}} \ {refuse to overwrite method foo; delete/rename method first.} ? {C public method "bar x" {args} {return bar/2}} {::C::slot::__bar::x} ? {C public method "bar x y" {args} {return foo/3}} \ {refuse to overwrite cmd ::C::slot::__bar::x; delete/rename it before overwriting} C create c1 ? {c1 foo x y z} "foo/1" ? {c1 bar x y z} "bar/2" ? {nx::Object create o1} ::o1 ? {o1 public object method foo {args} {return foo/1}} "::o1::foo" ? {o1 public object method "foo x" {args} {return foo/2}} \ {refuse to overwrite object method foo; delete/rename object method first.} ? {o1 public object method "foo x y" {args} {return foo/3}} \ {refuse to overwrite object method foo; delete/rename object method first.} ? {o1 public object method "bar x" {args} {return bar/2}} {::o1::bar::x} ? {o1 public object method "bar x y" {args} {return foo/3}} \ {refuse to overwrite cmd ::o1::bar::x; delete/rename it before overwriting} ? {o1 foo x y z} "foo/1" ? {o1 bar x y z} "bar/2" } nx::test case ensemble-next-vs-colon-dispatch { nx::Class create A { :method "x s" args { next return [current class] } } nx::Class create B -superclasses A { :public method "x s" args { return [list [current class] {*}[next]] } :create b } set sc "::B ::A" ? {b eval { :x s }} $sc ? {b eval { : x s }} $sc ? {b x s} $sc } nx::test case ensemble-callstack-introspection { set ::body { return [list [current nextmethod] [current isnextcall] {*}[next]] } nx::Class create A { set ::handle [:method "i s" args $::body] :create a } nx::Class create B -superclasses A { :public method "i s" args $::body :create b } ? {b eval { :i s }} {{::nsf::classes::A::i s} 0 {} 1} ? {::nsf::cmd::info args [lindex [b eval { :i s }] 0]} "args" ? {::nsf::cmd::info definitionhandle [lindex [b eval { :i s }] 0]} $::handle ? {::nsf::cmd::info body [lindex [b eval { :i s }] 0]} $::body ? {b i s} {{::nsf::classes::A::i s} 0 {} 1}; ? {::nsf::cmd::info args [lindex [b i s] 0]} "args" ? {::nsf::cmd::info definitionhandle [lindex [b i s] 0]} $::handle ? {::nsf::cmd::info body [lindex [b i s] 0]} $::body ? {a eval { :i s }} {{} 0} ? {a i s} {{} 0} unset -nocomplain ::handle unset -nocomplain ::body } ::nx::configure defaultMethodCallProtection true nx::test case ensemble-forwards { set C [nx::Class new { set handle [:forward "foo 1" join %method ""] ? [list info commands $handle] $handle set handle [:public forward "foo 2" join %method ""] ? [list info commands $handle] $handle set handle [:protected forward "foo 3" join %method ""] ? [list info commands $handle] $handle set handle [:private forward "foo 4" join %method ""] ? [list info commands $handle] $handle set handle [:object forward "foo 5" join %method ""] ? [list info commands $handle] $handle set handle [:public object forward "foo 6" join %method ""] ? [list info commands $handle] $handle set handle [:protected object forward "foo 7" join %method ""] ? [list info commands $handle] $handle set handle [:private object forward "foo 8" join %method ""] ? [list info commands $handle] $handle }] ? [list $C foo 6] "6" ? [list $C foo 5] "unable to dispatch sub-method \"5\" of $C foo; valid are: foo 6" ? [list $C eval {:foo 5}] "5" ? [list $C foo 7] "unable to dispatch sub-method \"7\" of $C foo; valid are: foo 6" ? [list $C eval {:foo 7}] "7" ? [list $C foo 8] "unable to dispatch sub-method \"8\" of $C foo; valid are: foo 6" ? [list $C eval {:foo 8}] "unable to dispatch sub-method \"8\" of $C foo; valid are: foo 6"; ? [list $C eval {: -local foo 8}] "8"; set c [$C new] ? [list $c foo 2] "2" ? [list $c foo 1] "unable to dispatch sub-method \"1\" of $c foo; valid are: foo 2" ? [list $c eval {:foo 1}] "1" ? [list $c foo 3] "unable to dispatch sub-method \"3\" of $c foo; valid are: foo 2" ? [list $c eval {:foo 3}] "3" ? [list $c foo 4] "unable to dispatch sub-method \"4\" of $c foo; valid are: foo 2" ? [list $c eval {:foo 4}] "unable to dispatch sub-method \"4\" of $c foo; valid are: foo 2"; ? [list $c eval {: -local foo 4}] "4"; } nx::test case ensemble-private-helper { nx::Class create B { :public method "bar 1" {} {return [list B.bar.1 {*}[next]]} :public method "baz 1" {} {return [list B.baz.1 {*}[next]]} :create b1 { :public object method foo {} {: -local bar 1} :public object method foo2 {} {:bar 1} :private object method "bar 1" {} {: -local baz 1} :private object method "baz 1" {} {return [list "b1.baz.1" {*}[next]]} } } nx::Class create C -superclass B { :public method "bar 1" {} {return [list C.bar.1 {*}[next]]} :public method "baz 1" {} {return [list C.baz.1 {*}[next]]} :create c1 { :public object method foo {} {: -local bar 1} :public object method foo2 {} {:bar 1} :private object method "bar 1" {} {: -local baz 1} :private object method "baz 1" {} {return [list "c1.baz.1" {*}[next]]} } } ? {b1 bar 1} "B.bar.1" ? {b1 baz 1} "B.baz.1" ? {b1 foo} "b1.baz.1 B.baz.1" ? {b1 foo2} "B.bar.1" ? {c1 bar 1} "C.bar.1 B.bar.1" ? {c1 baz 1} "C.baz.1 B.baz.1" ? {c1 foo} "c1.baz.1 C.baz.1 B.baz.1" ? {c1 foo2} "C.bar.1 B.bar.1" } nx::test case ensemble-private-local-checks { nx::Class create B { :public method "bar 1" {} {return [list B.bar.1 {*}[next]]} :public method "bar 2" {} {return [list B.bar.2 {*}[next]]} :public method FOO1 {} {: -local bar 1} :public method FOO2 {} {:bar 1} :public method "FOO3 FAR FIM" {} {: -local bar 1} :create b1 { :public object method foo {} {: -local bar 1} :public object method faa {} {: -local noop 2} :public object method fee1 {} {: -local bar 2} :public object method fee2 {} {: -local bar 3} :private object method "bar 1" {} {: -local baz 1} :private object method "baz 1" {} {return "b1.baz.1"} } } nx::Class create C -superclass B { :public method "bar 1" {} {return [list C.bar.1 {*}[next]]} :public method "baz 1" {} {return [list C.baz.1 {*}[next]]} :create c1 { :public object method foo {} {: -local bar 1} :public object method faa {} {: -local noop 2} :public object method fee1 {} {: -local bar 2} :public object method fee2 {} {: -local bar 3} :private object method "bar 1" {} {: -local baz 1} :private object method "baz 1" {} {return "c1.baz.1"} } } ? {b1 faa} "::b1: unable to dispatch method 'noop'" ? {b1 foo} "b1.baz.1" ? {b1 fee1} "B.bar.2" ? {b1 fee2} "unable to dispatch sub-method \"3\" of ::b1 bar; valid are: bar 1, bar 2" ? {b1 FOO1} "B.bar.1" ? {b1 FOO2} "B.bar.1" ? {b1 FOO3 FAR FIM} "B.bar.1" ? {c1 faa} "::c1: unable to dispatch method 'noop'" ? {c1 foo} "c1.baz.1" ? {c1 fee1} "B.bar.2" ? {c1 fee2} "unable to dispatch sub-method \"3\" of ::c1 bar; valid are: bar 1, bar 2" ? {c1 FOO1} "B.bar.1" ? {c1 FOO2} "C.bar.1 B.bar.1" ? {c1 FOO3 FAR FIM} "B.bar.1" } nx::test case ensemble-next-sackgasse { nx::Class create ::A { :public method "i o a" {} {return a} :public method "i o b" {} {return b} } nx::Class create B -superclasses A { :public method "i s" args { next ;# Should not trigger unknown! return [current class] } :create b } ? {b i o a} a ? {b i o b} b ? {b i s} "::B" } # # The tests below test for unknown ensemble methods in different configurations: # - w and w/o trailer (arguments beyond the unknown method name) # - at the top-level (i.e., pre-evaluated [catch {...}]) and at a nested # callframe level. # # NOTE: Don't nest the test cases below into an nx::test case, this # will not produce the second configuration (no top-level execution). # nx::Class create C { # "bar x y z" :public method "foo a b c" {} { return "ok" } :create c } # unknown at the ensemble root: 'foo' vs. 'bar' ? {c bar} {::c: unable to dispatch method 'bar'} ? [list return -level 0 [catch {c bar} msg; set msg]] {::c: unable to dispatch method 'bar'} # unknown at the 1st ensemble level w/o trailer : 'a' vs. 'x' ? {c foo x} {unable to dispatch sub-method "x" of ::c foo; valid are: foo a b c} ? [list return -level 0 [catch {c foo x} msg; set msg]] {unable to dispatch sub-method "x" of ::c foo; valid are: foo a b c} # unknown at the 1st ensemble level w/ trailer : 'a' vs. 'x' ? {c foo x b c} {unable to dispatch sub-method "x" of ::c foo; valid are: foo a b c} ? [list return -level 0 [catch {c foo x b c} msg; set msg]] {unable to dispatch sub-method "x" of ::c foo; valid are: foo a b c} # unknown at the 2nd ensemble level w/o trailer : 'b' vs. 'y' ? {c foo a y} {unable to dispatch sub-method "y" of ::c foo a; valid are: foo a b c} ## at the top-level (no caller frame"), the below crashed NSF as report on c.l.t.: ## see https://groups.google.com/forum/#!topic/comp.lang.tcl/wzh5uFKeKU8 ? [list return -level 0 [catch {c foo a y} msg; set msg]] {unable to dispatch sub-method "y" of ::c foo a; valid are: foo a b c} # unknown at the 2nd ensemble level w trailer : 'b' vs. 'y' ? {c foo a y c} {unable to dispatch sub-method "y" of ::c foo a; valid are: foo a b c} ? [list return -level 0 [catch {c foo a y c} msg; set msg]] {unable to dispatch sub-method "y" of ::c foo a; valid are: foo a b c} # unknown at the 3rd ensemble level w/o trailer : 'c' vs. 'z' ? {c foo a b z} {unable to dispatch sub-method "z" of ::c foo a b; valid are: foo a b c} ? [list return -level 0 [catch {c foo a b z} msg; set msg]] {unable to dispatch sub-method "z" of ::c foo a b; valid are: foo a b c} # unknown at the 3nd ensemble level w trailer : 'c' vs. 'z' ? {c foo a b z d} {unable to dispatch sub-method "z" of ::c foo a b; valid are: foo a b c} ? [list return -level 0 [catch {c foo a b z d} msg; set msg]] {unable to dispatch sub-method "z" of ::c foo a b; valid are: foo a b c} ? {c foo a b c} "ok" ? [list return -level 0 [catch {c foo a b c} msg; set msg]] "ok" ? {c foo a b c d} {wrong # args: should be "c"} ? [list return -level 0 [catch {c foo a b c d} msg; set msg]] {wrong # args: should be "c"} ::c destroy ::C destroy # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/forward.test000644 000766 000024 00000043377 14274463622 016727 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx package require nx::test set ::tcl86 [package vsatisfies [package req Tcl] 8.6-] ########################################### # trivial object delegation ########################################### nx::test case delegation { nx::Object create dog nx::Object create tail { :public object method wag args { return $args } :public object method nxwag args { return $args } } dog public object forward wag tail %proc dog public object forward nxwag tail %method ? {dog wag 100} 100 ? {dog nxwag 100} 100 } ########################################### # evaluating in scope ########################################### nx::test case inscope { nx::Class create X { :property {x 1} :public forward Incr -frame object incr } X create x1 -x 100 x1 Incr x x1 Incr x x1 Incr x ? {x1 cget -x} 103 } ########################################### # adding ########################################### nx::test case adding { nx::Object create obj { :public object forward addOne expr 1 + } ? {obj addOne 5} 6 } ########################################### # more arguments ########################################### nx::test case multiple-args { nx::Object create target { :public object method foo args {return $args} } nx::Object create obj { :public object forward foo target %proc %self a1 a2 } ? {obj foo x1 x2} [list ::obj a1 a2 x1 x2] obj public object forward foo target %proc %self %%self %%p ? {obj foo x1 x2} [list ::obj %self %p x1 x2] } ########################################### # mixin example ########################################### nx::test case mixin-via-forward { nx::Object create mixins { :object method unknown {m args} {return [concat [current] $m $args]} } nx::Object create obj { :public object forward Mixin mixins %1 %self } ? {obj Mixin add M1} [list ::mixins add ::obj M1] ? {catch {obj Mixin}} 1 obj public object forward Mixin mixins "%1 {Getter Setter}" %self ? {obj Mixin add M1} [list ::mixins add ::obj M1] ? {obj Mixin M1} [list ::mixins Setter ::obj M1] ? {obj Mixin} [list ::mixins Getter ::obj] } ########################################### # sketching extensibe info ########################################### nx::test case info-via-forward { nx::Object create Info { :public object method @mixin {o} { $o info mixin } :public object method @class {o} { ;# without prefix, doing here a [Info class] wod be wrong $o info class } :public object method @help {o} { ;# define a new subcommand for info foreach c [:info object methods] {lappend result [string range $c 1 end]} return $result } } nx::Object public forward Info -prefix @ Info %1 %self nx::Class create X { :create x1 } ? {x1 Info class} ::X ? {x1 Info help} [list help mixin class] } ########################################### # variations of placement of options ########################################### nx::test case incr { nx::Object create obj { set :x 1 :public object forward i1 -frame object incr x } ? {obj i1} 2 } ########################################### # introspeciton options ########################################### nx::test case introspection { nx::Class create C { :public forward Info -prefix @ Info %1 %self } ? {C info methods -type forwarder} Info C public forward XXXo x ? {lsort [C info methods -type forwarder]} [list Info XXXo] ? {C info methods -type forwarder X*} [list XXXo] ? {lsort [C info methods -type forwarder *o]} [list Info XXXo] # delete the forwarder C method XXXo {} {} ? {C info methods -type forwarder} [list Info] # get the definition of a instforwarder ? {C info method definition Info} [list ::C public forward Info -prefix @ Info %1 %self] # check introspection for objects nx::Object create obj { :public object forward i1 -frame object incr x :public object forward Mixin mixin %1 %self :public object forward foo target %proc %self %%self %%p :public object forward addOne expr 1 + } ? {lsort [obj info object methods -type forwarder]} "Mixin addOne foo i1" ? {obj info object method definition Mixin} "::obj public object forward Mixin mixin %1 %self" ? {obj info object method definition addOne} "::obj public object forward addOne expr 1 +" ? {obj info object method definition foo} "::obj public object forward foo target %proc %self %%self %%p" ? {obj info object method definition i1} "::obj public object forward i1 -frame object ::incr x" } ########################################### # test serializer ########################################### package require nx::serializer nx::test case serializer { nx::Object create obj { :object method test {} {puts "i am [current method]"} } set ::a [Serializer deepSerialize obj] #puts <<$::a>> eval $::a ? {set ::a} [Serializer deepSerialize obj] } ########################################### # test optional target cmd ########################################### nx::test case optional-target { nx::Object create obj { set :x 2 :public object forward append -frame object } ? {obj append x y z} 2yz nx::Object create n; nx::Object create n::x {:public object method current {} {current}} nx::Object create o o public object forward ::n::x ? {o x current} ::n::x } ########################################### # arg including instvar ########################################### nx::test case percent-cmd { nx::Object create obj { set :x 10 :public object forward x* expr {%:eval {set :x}} * } ? {obj x* 10} "100" } ########################################### # positional arguments ########################################### nx::test case positioning-args { nx::Object create obj obj public object forward @end-13 list {%@end 13} ? {obj @end-13 1 2 3 } [list 1 2 3 13] obj public object forward @-1-13 list {%@-1 13} ? {obj @-1-13 1 2 3 } [list 1 2 13 3] obj public object forward @1-13 list {%@1 13} ? {obj @1-13 1 2 3 } [list 13 1 2 3] ? {obj @1-13} [list 13] obj public object forward @2-13 list {%@2 13} ? {obj @2-13 1 2 3 } [list 1 13 2 3] obj public object forward @list 10 {%@0 list} {%@end 99} ? {obj @list} [list 10 99] ? {obj @list a b c} [list 10 a b c 99] obj public object forward @list {%@end 99} {%@0 list} 10 ? {obj @list} [list 10 99] ? {obj @list a b c} [list 10 a b c 99] obj public object forward @list {%@2 2} {%@1 1} {%@0 list} ? {obj @list} [list 1 2] ? {obj @list a b c} [list 1 2 a b c] obj public object forward @list x y z {%@0 list} {%@1 1} {%@2 2} ? {obj @list} [list 1 2 x y z] ? {obj @list a b c} [list 1 2 x y z a b c] obj public object forward @list x y z {%@2 2} {%@1 1} {%@0 list} ? {obj @list} [list x 1 y 2 z] ? {obj @list a b c} [list x 1 y 2 z a b c] # adding some test cases which cover the interactions # between %@POS and %1 substitutions # obj public object forward @end-13 list {%@end 13} %1 %self ? {obj @end-13 1 2 3 } [list 1 ::obj 2 3 13] obj public object forward @end-13 list %1 {%@end 13} %self ? {obj @end-13 1 2 3 } [list 1 ::obj 2 3 13] obj public object forward @end-13 list {%@end 13} %1 %1 %1 %self ? {obj @end-13 1 2 3 } [list 1 1 1 ::obj 2 3 13] obj public object forward @end-13 list {%@-1 13} %1 %self ? {obj @end-13 1 2 3 } [list 1 ::obj 2 13 3] obj public object forward @end-13 list {%@1 13} %1 %self ? {obj @end-13 1 2 3 } [list 13 1 ::obj 2 3] } nx::test case forwarder-basics { nx::Object create obj ## ## Particular role of first forwarder arg: (fully-qualified) target ## & methodName in one (provides shortcut notation) ## ? {obj info object methods foo} "" obj public object forward ::ns1::foo ? {obj info object methods foo} "foo" if {$::tcl86} { ? {obj foo X} {TCL LOOKUP COMMAND ::ns1::foo} "invalid target command" } else { ? {obj foo X} {invalid command name "::ns1::foo"} "invalid target command" } namespace eval ::ns1 {proc foo {p} {return $p}} ? {obj foo X} "X" obj public object forward ::ns1::foo %method %method ? {namespace eval ::ns1 { ::obj foo }} "foo" # make sure, old-style arguments don't get moved into argument # delegatee cmd (called target) ? {obj public object forward x1 -methodprefix @ -verbose %self X} \ "target '-methodprefix' must not start with a dash" ? {obj public object forward x2 -prefix @ -verbose %self X} \ "::obj::x2" ? {obj x2 a b c} "::obj: unable to dispatch method '@X'" ## ## argclindex ## obj public object forward foo list {%argclindex {A B C}} ? {obj foo} A ? {obj foo _} "B _" ? {obj foo _ _} "C _ _" ? {obj foo _ _ _ _} "forward: not enough elements in specified list of ARGC argument argclindex {A B C}" ## ## %1 + defaults ## ::nsf::configure debug 2 obj public object method FOO args {return [current method]-$args} obj public object method OOF args {return [current method]-$args} obj public object forward foo -verbose %self %1 ? {obj foo} {%1 requires argument; should be "foo arg ..."} obj public object forward foo -verbose %self {%1 FOO} ? {obj foo} "FOO-" ? {obj foo X} {::obj: unable to dispatch method 'X'} obj public object forward foo -verbose %self {%1 FOO OOF} ? {obj foo X} {::obj: unable to dispatch method 'X'} obj public object forward foo -verbose %self {%1 {FOO OOF}} ? {obj foo X} "OOF-X" ? {obj foo X Y} {::obj: unable to dispatch method 'X'} obj public object forward foo -verbose %self {%1 {FOO OOF}} {%1 {A B}} ? {obj foo} "FOO-A" obj public object forward foo -verbose %self {%1 {FOO OOF}} {%1 {A B}} ? {obj foo X} "OOF-B X" obj public object forward foo -verbose %self "%1\n{FOO\nOOF}" "%1\r{A\tB}" ? {obj foo X} "OOF-B X" ## ## -prefix; requires a 2nd arg! ## ## obj public object method _FOO args {return [current method]-$args} ## 1) 2nd arg is missing! Prefix is silently neglected ... obj public object forward FOO -prefix _ %self ? {obj FOO} {::obj} # 2) There is a 2nd arg, a method argument ? {obj FOO FOO X} "_FOO-X" "prefix, 2nd arg is method argument" # 3) There is a 2nd arg, a forwarder argument obj public object forward FOO -prefix _ %self %1 ? {obj FOO FOO X} "_FOO-X" "prefix, 2nd arg is forwarder argument" # 4) There is a 2nd arg, a forwarder argument provided through %1 obj public object forward FOO -prefix _ %self {%1 {FOO FOO}} ? {obj FOO X} "_FOO-X" "prefix, 2nd arg is forwarder argument provided through %1" } nx::test case positioning-arg-extended { nx::Object create obj obj public object forward foo list {%@end %self} ? {obj foo 1 2 3} [list 1 2 3 ::obj] obj public object forward foo list {%@end %method} ? {obj foo 1 2 3} [list 1 2 3 foo] obj public object forward foo list {%@end %%} ? {obj foo 1 2 3} [list 1 2 3 %] obj public object forward foo list {%obj foo} if {$::tcl86} { # Avoid crashes when system stack size is limited (with forwards # being more stack-hungry than, e.g., ordinary scripted methods). set limit [interp recursionlimit {}] interp recursionlimit {} 100 ? {obj foo 1 2 3} "TCL LIMIT STACK" "stack overflow" interp recursionlimit {} $limit } else { # see CheckCStack in Tcl 8.5: # https://core.tcl-lang.org/tcl/artifact?name=97fd3164833e9ef3&ln=3576 if {$::tcl_platform(platform) ne "windows" } { ? {obj foo 1 2 3} {too many nested evaluations (infinite loop?)} "stack overflow" } else { ? {obj foo 1 2 3} {out of stack space (infinite loop?)} "stack overflow" } } obj public object forward foo list {%apply {{x} {return $x}} A} ? {obj foo 1 2 3} [list A 1 2 3] ## positioning of "simple" cmd substitution works fine obj public object forward foo list {%@end %obj} ? {obj foo 1 2 3} [list 1 2 3 ::obj] "simple cmd substitution by position" ## lindex allows for omitting the index arg or passing {} as index value ... forward catches both cases nicely: obj public object forward foo list {%@{} %obj} ? {obj foo 1 2 3} "forward: invalid index specified in argument %@{} %obj" obj public object forward foo list {%@ %obj} ? {obj foo 1 2 3} "forward: invalid index specified in argument %@ %obj" ## ## resolving name conflicts between Tcl commands & predefined ## placeholder names -> use fully qualified names ## obj public object forward foo list {%@end %::proc} if {$::tcl86} { ? {obj foo 1 2 3} {TCL WRONGARGS} "provided wrong arguments for target command" } else { ? {obj foo 1 2 3} {wrong # args: should be "::proc name args body"} "provided wrong arguments for target command" } # the next test does not work unless called from nxsh, which imports ::nx::self # obj public object forward foo list {%@end %::self} #? {obj foo 1 2 3} [list 1 2 3 ::obj] obj public object forward foo list {%@end %::nx::self} ? {obj foo 1 2 3} [list 1 2 3 ::obj] "fully qualified self" obj public object forward foo list {%@end %::1} if {$::tcl86} { ? {obj foo 1 2 3} {TCL LOOKUP COMMAND ::1} "forward to non-existing object" } else { ? {obj foo 1 2 3} {invalid command name "::1"} "forward to non-existing object" } ## ## position prefixes are interpreted in a context-dependent manner: ## obj public object forward foo list {%@1 %@1} if {$::tcl86} { ? {obj foo 1 2 3} {TCL LOOKUP COMMAND @1} "forward to non-existing cmd" } else { ? {obj foo 1 2 3} {invalid command name "@1"} "forward to non-existing cmd" } if {![string length "ISSUES"]} { ## list protection makes this fail obj public object forward foo list {%@end {%argclindex {A B C D}}} ? {obj foo 1 2 3} [list 1 2 3 D] ## positioned "complex" cmd substitution (cmd + args) not working because of list protection obj public object forward foo list {%@end {%list 1}} ? {obj foo 1 2 3} [list 1 2 3 A] ## Why not %1 not working with positioning working? obj public object forward foo list {%@end %1} ? {obj foo 1 2 3} [list 1 2 3 1] ## ## Should this be caught somehow? How would this be treated when list protection would not interfere? ## obj public object forward foo list {%@1 {%@1 "x"}} ? {obj foo 1 2 3} "forward: invalid index specified in argument %@{} %obj" } } ############################################### # substitution depending on number of arguments ############################################### nx::test case num-args { nx::Object create obj { :public object forward f %self [list %argclindex [list a b c]] :object method a args {return [list [current method] $args]} :object method b args {return [list [current method] $args]} :object method c args {return [list [current method] $args]} } ? {obj f} [list a {}] ? {obj f 1 } [list b 1] ? {obj f 1 2} [list c {1 2}] ? {catch {obj f 1 2 3}} 1 } ############################################### # option earlybinding ############################################### nx::test case earlybinding { nx::Object create obj { #:public object forward s -earlybinding ::set ::X :public object forward s ::set ::X } ? {obj s 100} 100 ? {obj s} 100 nx::Object public method f args { next } nx::Class create NS nx::Class create NS::Main { :public object method m1 {} { :m2 } :public object method m2 {} { ? {namespace eval :: {nx::Object create toplevelObj1}} ::toplevelObj1 ? [list set _ [namespace current]] ::NS ? [list set _ [NS create m1]] ::NS::m1 NS filters set f ? [list set _ [NS create m2]] ::NS::m2 NS filters set "" namespace eval ::test { ? [list set _ [NS create m3]] ::test::m3 NS filters set f ? [list set _ [NS create m4]] ::test::m4 NS filters set "" } namespace eval test { ? [list set _ [NS create m5]] ::NS::test::m5 NS filters set f ? [list set _ [NS create m6]] ::NS::test::m6 NS filters set "" } } :public method i1 {} { :i2 } :public method i2 {} { ? {namespace eval :: {nx::Object create toplevelObj2}} ::toplevelObj2 ? [list set _ [namespace current]] ::NS ? [list set _ [NS create i1]] ::NS::i1 NS filters set f ? [list set _ [NS create i2]] ::NS::i2 NS filters set "" namespace eval ::test { ? [list set _ [NS create i3]] ::test::i3 NS filters set f ? [list set _ [NS create i4]] ::test::i4 NS filters set "" } namespace eval test { ? [list set _ [NS create i5]] ::NS::test::i5 NS filters set f ? [list set _ [NS create i6]] ::NS::test::i6 NS filters set "" } } } #puts ==== NS::Main m1 NS::Main create m m i1 #puts ==== ? [list set _ [NS create n1]] ::n1 NS filters set f ? [list set _ [NS create n2]] ::n2 NS filters set "" #puts ==== namespace eval test { ? [list set _ [NS create n1]] ::test::n1 ? [list set _ [NS create n3]] ::test::n3 NS filters set f ? [list set _ [NS create n4]] ::test::n4 NS filters set "" } } ########################################### # forward to expr + callstack ########################################### nx::test case callstack { nx::Object public forward expr -frame object nx::Class create C { :method xx {} {current} :public object method t {o expr} { return [$o expr $expr] } } C create c1 ? {c1 expr {[current]}} ::c1 ? {c1 expr {[current] eq "::c1"}} 1 ? {c1 expr {[:xx]}} ::c1 ? {c1 expr {[:info class]}} ::C ? {c1 expr {[:info has type C]}} 1 ? {c1 expr {[:info has type ::C]}} 1 ? {C t ::c1 {[current]}} ::c1 ? {C t ::c1 {[current] eq "::c1"}} 1 ? {C t ::c1 {[:xx]}} ::c1 ? {C t ::c1 {[:info class]}} ::C ? {C t ::c1 {[:info has type C]}} 1 ? {C t ::c1 {[:info has type ::C]}} 1 nx::Object method expr {} {} } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/tests/plain-object-method.test000644 000766 000024 00000006054 14164660541 021074 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require nx::test nx::test case plain-methods-0 { nx::Class create M1 nx::Object create o { ? {o public method foo {} {return foo}} "::o: unable to dispatch method 'method'" :public object method f args {next} } ? {o mixins set M1} "::o: unable to dispatch method 'mixins'" ? {o filters set f} "::o: unable to dispatch method 'filters'" ? {lsort [o info object methods]} "f" ? {lsort [o info]} "valid submethods of ::o info: baseclass children class has info lookup name object parent precedence variable vars" } # # require the convenience layer # and make it verbose # package require nx::plain-object-method nx::configure plain-object-method-warning on nx::test case plain-methods-1 { nx::Class create M1 nx::Object create o { :public method foo {} {return [:pm1]} :public method f args {next} :protected method pm1 args {return pm1} :public alias a ::o::pm1 :public forward fwd %self pm1 :private method priv args {return priv} :method pm2 args {return pm2} :property -accessor public p :variable v1 1 :variable -incremental v2:integer 1 } ? {o info methods} "v2 p foo fwd a f" ? {lsort [o info methods -callprotection protected]} "pm1 pm2" ? {lsort [o info methods -callprotection private]} "priv" ? {o info variables} "::o::per-object-slot::v2 ::o::per-object-slot::p" ? {o info object variables} "::o::per-object-slot::v2 ::o::per-object-slot::p" ? {o info slots} "::o::per-object-slot::v2 ::o::per-object-slot::p" ? {o pm1} "::o: unable to dispatch method 'pm1'" ? {o foo} "pm1" ? {o a} "pm1" ? {o fwd} "pm1" ? {o mixins set M1} ::M1 ? {o info mixins} ::M1 ? {o mixins set ""} "" ? {o info mixins} "" ? {o filters set f} f ? {o info filters} f ? {o filters set ""} "" ? {o info filters} "" ? {lsort [o info object methods]} "a f foo fwd p v2" ? {lsort [o info]} "valid submethods of ::o info: baseclass children class filters has info lookup method methods mixins name object parent precedence slots variable variables vars" } # # delete class method, class property, class variable # nx::test case plain-methods-2 { nx::Object create ::o { :public method foo {} {return foo} :property -accessor public p :variable -incremental v1:integer 1 } ? {o info methods} "p foo v1" ? {o info variables} "::o::per-object-slot::p ::o::per-object-slot::v1" ? {o delete method foo} "" ? {o info methods} "p v1" ? {o info variables} "::o::per-object-slot::p ::o::per-object-slot::v1" ? {o delete property p} "" ? {o info methods} "v1" ? {o info variables} "::o::per-object-slot::v1" ? {o delete variable v1} "" ? {o info methods} "" ? {o info variables} "" } # # require method # nx::test case plain-methods-3 { nsf::method::provide set {::nsf::method::alias set -frame object ::set} nx::Object create ::o { :require method set } ? {::o info methods} "set" ? {::o info object methods} "set" } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/ChangeLog-2.0b5-2.0.0.log000644 000766 000024 00000163371 14064565726 016733 0ustar00neumannstaff000000 000000 2014-10-28 Gustaf Neumann - Don't complain at final ObjectDeletion about object refcounts unless we are in development mode - adding .3 man pages to ease installation - adding .1 man pages to ease installation 2014-10-28 ssoberni - Effectively remove getstubs from makefile.vc - Apply stubs* resolution without getstubs to makefile.vc 2014-10-27 Gustaf Neumann - use newest versions, re-generated stub files - adjust genstubs target to subdir logic - handle nsfUtil.c from version-specific subdirectory - binor polishing 2014-10-27 ssoberni - NsfDStringPrintf(): Fix vargs processing under VC 12 2014-10-27 Gustaf Neumann - get rid of getstubs - provide actual pkgIndex files - keep an internal list of Tcl_Objs of type mixinrefs for classes used as mixins. This list is used for avoiding stale entries in cases the mixin class is destroyed. - remove redundant and different prototype 2014-10-27 ssoberni - Bump version numbers in nx.tcl and xotcl2.tcl; adjust license statements - Rearrange 'make getstubs' slightly, so that we do not require the stub files present in generic/* for the build machinery to work properly - Done revising license statements in generic/* 2014-10-27 Gustaf Neumann - fix a heisenbug probably showing sometimes up due to more aggressive Tcl_Obj sharing in newer versions of tcl 8.6 2014-10-27 ssoberni - Correct and unify licensing statements in header files - Fix copyright statements in stubs* files - Fix copyright dates 2014-10-26 ssoberni - Silence instructions, do not install xowish.in/ xotclsh.in - Bump version number in win build files - Trigger generation of pgk index scripts - Add EXTERN to calm VC12, add missing C files from makefile.vc 2014-10-25 ssoberni - Use correct slashing - Render file paths in a platform-independent manner - Make sure genstub.tcl is called in makefile.vc - Update nmakehlp (required for VC 12+) 2014-10-24 Gustaf Neumann - set the right version number to 2.0.0 - Make dtplite configurable in Makefile, e.g. make "DTPLITE=/usr/local/ns/bin/tclsh8.5 /usr/local/ns/bin/dtplite" man - regenerate documentation - bump version number to 2.0 (also in .man files) - add Changelog for 2.0 release - updated for mongo-c-driver 1.0.2 and MongoDB 2.6.5 - minor changes were necessary: MongogDB does not allow one to delete a capped collection, one has to use drop - white-space changes - move variable declaration to the front 2014-10-23 ssoberni - Fixing listings in shell-wrapper manpages - Fix a typo reported by lintian - Fix two more wordings lintian complained about - Revise manpages; add copyright notes 2014-10-22 Gustaf Neumann - reduce number of unused symbols - fix a possible double refcount increment for argument converter (e.g. for normalizing input values). This could lead too small memory leaks. 2014-10-22 ssoberni - Continue man corrections - Work on corrections for Object.man & friends, based on Thorsten's proof-reading - Remove an nxdoc artifact - Remove unneeded make variables - Revive nsfConfig.sh: The paths expanded during a configure run were broken, partly due to substituting obsolete variables 2014-10-21 ssoberni - Use revised interpreter directive throughout 2014-10-21 Gustaf Neumann - fix final refcounting bug: it was possible that classes contained in Tcl_Objs of type mixinreg were not freed, although their reference-counter became 0; now all test cases free all tcl_objs and referenced data structures allocated from nsf 2014-10-21 ssoberni - First solution to provide a multi-step resolution of a Tcl interpreter in our shell wrappers. Uses some bash scripting to walk a list of candidates: 1) interp in build directory, 2) interp in install directory, 3) tcl interp in PATH. Where appropriate (cases 2 & 3), restricts search to a specific tinterp version. By relying on a generic shebang line (/bin/sh) we do not run into package-dependency restrictions on Debian. So a win-win? 2014-10-21 Gustaf Neumann - fix (probably quite old) memory leak when parameter passing fails to reclaim temporary Tcl_Objs - fix memory leak with virtual parameters (resolved via args) with ref-counting 2014-10-21 ssoberni - Adding man pages for shell wrappers - Adjust file extension for nroff files to reflect man page section 2014-10-20 ssoberni - Fix the remaining shebangs - Fix shebang lines - Remove any nxdoc artifacts from repo, to ease Debian packaging (incl. binary js is not accepted by lintian 2014-10-20 Gustaf Neumann - fix execution with --enable-memcount=yes: second argument of NsfMemCountAlloc() and NsfMemCountFree() may be empty - don't put macro arguments between parens when these are used for concatenation - remove // comments 2014-10-19 Gustaf Neumann build system: - don't call genstubs from configure, since Debian does not seem to have genstubs.tcl installed. Now, we pre-generate the stub files for tcl8.5 and tcl8.6 and copy the "right" version depending on the configured version. - avoid old-style prototypes 2014-10-15 ssoberni - Done with basic princexml integration, improve Makefile integration - Provide first stylesheet based on HTML markup by doctools HTML backend - Integrating manpages into build setup 2014-10-14 ssoberni - Improve wording - Add a draft section on self-references - Improve wording in overview diagram of Class doc item - Working on overview diagram for Class doc item - Add to the overview diagram - Adding overview diagram to Object doc item - Cleanup namespace export statement - Reflect plural reform in all doc items 2014-10-10 ssoberni - Doc item on nx::configure - Doc item on nx::current - Doc item for nx::next 2014-10-10 Gustaf Neumann - minor cleanup of "//"-comments 2014-10-07 ssoberni - Add some documentation on 'info info' - Make 'info info' behaving as expected again 2014-10-06 ssoberni - Minuscule refactoring, have DispatchUnknownMethod() reset the interp unknown-state directly, rather than its clients. 2014-10-06 Gustaf Neumann nsf.c: - make types for bit operations unsigned (mostly flags) 2014-10-05 Gustaf Neumann nx.tcl: - simplify the info ensembles on nx::Object or nx::Class significantly, by making use if ensemble-next. - delete "info unknown", since this is not called. - extend regression test nsf.c: - implement a new approach to error reporting in ensembles: instead of trying to find the "right" place to report the best "error", compute the longest valid ensemble prefix from all the stack frames. 2014-09-29 Gustaf Neumann - make compilation clean again - improve safety of macro arguments 2014-09-29 ssoberni - Adding a test showing the yet to solve unknown-handling issue in info ensembles 2014-09-28 ssoberni - Work-in-progress on sanitizing unknown handling in ensembles 2014-09-28 Gustaf Neumann - remove useless distinction from the past - revise sanity check for tcl _objs in 8.6 once one: length field might be garbage - add alternative test for sanity checking of tcl_objs: when bytes not NULL, length must be 0 or higher 2014-09-27 Gustaf Neumann nsf.c: - remove redundant definition - reduce variable scope - make sure to follow nonnull assumptions - improve cppcheck flags nsf.h - In Tcl 8.6.1 it might be that a Tcl_Obj has length > 0 but bytes == NULL. We have to relax out tcl_obj-sanity test for this case to avoid false-positives from assertions() 2014-09-22 Gustaf Neumann - documentation update to reflect recent changes 2014-09-17 Gustaf Neumann documentation: - add current args to migration guide - fix cut&paste error: replace "current currentclass" by "current calledclass" nsf.c: - remove redundant null check for object and add assertion - remove duplicate entry for returns_nonnull - serializer: keep parameter properties in xotcl parameter lists 2014-08-08 ssoberni - Revise Object documentation, align with output from quant.tcl helper - Reflect recent parameter syntax change in corresponding test - Revise Class documentation, align with output from quant.tcl helper - Provide corrections for some syntax strings 2014-07-09 Gustaf Neumann - no need to "set nodashalnum for int types" - extended regression test 2014-06-23 Gustaf Neumann nsf.c: - provide error messages for ambiguous abbreviations - extend regression test (now 5460 tests) 2014-06-23 ssoberni Revised life-cycle section further 2014-06-23 Gustaf Neumann nsf.c: - dropped unused object::info::is - renamed ::nsf::methods::class::info::filtermethods -> ::nsf::methods::class::info::filters ::nsf::methods::object::info::filtermethods -> ::nsf::methods::object::info::filters ::nsf::methods::class::info::mixinclasses -> ::nsf::methods::class::info::mixins ::nsf::methods::object::info::mixinclasses -> ::nsf::methods::object::info::mixins 2014-06-23 ssoberni - Change overview illustration on object life cycle in Class.man - Adjust for changes in plural reform 2014-06-22 Gustaf Neumann nx.tcl: pluralism reform part 3 - introduced simple plural form "mixins" and "filters" for introspection - moved differentiated interface into slot methods. the slot methods "get" stay symmetrically to "set", but additional methods "classes" or "methods" are used like "guard" to obtain partial results of the mixin and filter specs - changed info methods /cls/ info mixin classes -> /cls/ info mixins /cls/ info filter methods -> /cls/ info filters /obj/ info object mixin classes -> /obj/ info object mixins /obj/ info object filter methods -> /obj/ info object filters - dropped /cls/ info mixin guard /cls/ info filter guard /obj/ info object mixin guard /obj/ info object filter guard - added /cls/ mixin classes /cls/ filter methods /obj/ object filter methods /obj/ object mixin classes 2014-06-21 Gustaf Neumann nx.tcl: - make all __* system methods in nx redefine-protected - let "nsf::configure objectsystem" return handles and protections as well 2014-06-20 Gustaf Neumann nx.tcl: pluralism reform part 2 - changed methods /cls/ info subclass -> /cls/ info subclasses /cls/ info superclass -> /cls/ info superclasses /cls/ mixin ... -> /cls/ mixins /cls/ filter ... -> /cls/ filters /cls/ object mixin ... -> /cls/ object mixins /cls/ object filter ... -> /cls/ object filters - changed configure parameters /cls/ configure -mixin -> /cls/ configure -mixins /cls/ configure -filter -> /cls/ configure -filters /obj/ configure -object-mixin -> /obj/ configure -object-mixins /obj/ configure -object-filter -> /obj/ configure -object-filters - added handling for calling relation slot with unknown sub method 2014-06-20 ssoberni - Revising lifecycle section; adding TODOs - Restructuring __* doc fragments to an life-cycle section 2014-06-19 Gustaf Neumann nsf.c: - allow abbreviated nonpos args - change name of relation slot "superclass" to "superclasses". (part of a planned change to use plural for setvalued parameters, "info superclasses" and similar changes for mixins/filters will probably follow) 2014-06-18 Gustaf Neumann nsf.c: - define means to protect "undefined" internally-directly called methods __alloc and __dealloc in nx. This is achieved mostly via an additional value in a method declaration in ::nsf::objectsystem::create. Example: -class.dealloc {__dealloc ::nsf::methods::class::dealloc 1} - extend regression test 2014-06-18 ssoberni - Adding missing doc fragments on __* methods for Object and Class 2014-06-17 Gustaf Neumann nsf.c: - relax the meaning of noleadingdash to allow negative numbers - rename noleadingdash to e.g. nodashalnum 2014-06-16 Gustaf Neumann - extend regression test - update parse context - remove debugging output - improve argument name 2014-06-15 Gustaf Neumann - extended regression test - cleanup, reduce verbosity - minor cleanup - allow one to configure verbosity in test sets genttclAPI.tcl: - added option "-flags", which can be used for every parameter. example: .... -flags NSF_ARG_NOLEADINGDASH .... - experimental: use NSF_ARG_NOLEADINGDASH for pattern "info subclass" to improve error messages. nsf.c: - checked, that all CallDirectly() cases, where method is dispatched (no direct call) are covered by the regression tests - avoid double memcpy() in dispatch recreate by using ObjectDispatch() rather than CallMethod() - removed memcpy() in call-directly for "create" - some more cleanup 2014-06-14 Gustaf Neumann nsf.c: parameter passing reform - don't pass full argument list for filtering methods calle further methods from C (such as new/create/... ) to allow processing of e.g. "--" in "new" to separate arguments to "new" cleanly from arguments passed to "create". Now we can use e.g. "C new -- -childof 123" in case class C has a property "childof". - extend c-generator to accept option "-objv0" to pass the original "objv[0]" to the called command. Since we had previously "allargs", we have to pass the objv[0] now differently - more thorough checking ISOBJ(someObj) macro for asserts (use "assert(ISOBJ(someObj))" instead of just "assert(someObj)") - extend regression test 2014-06-13 Gustaf Neumann - fix parse context initialization 2014-06-12 Gustaf Neumann - collecting arguments 2014-06-11 Gustaf Neumann - fix shutdown comparison - don't invalidate class-level param caches during shutdown - add assertions for class colorings 2014-06-11 ssoberni - Clarify usage of 'current methodpath' in defaultmethod of ensembles - Editing TODO - Add doc fragment on new - Adding missing info sub-method docs for Class, document -dependent flag, and method create 2014-06-11 Gustaf Neumann - simplify test - use 3-argument version of NsfMethodNamePath() 2014-06-11 ssoberni - Add basic test for unexpected-#-args error in ensembles - Adding to the state of the method-path introspection reform; introducing CallStackGetFrame() which can also be used to implement CallStackGetTopFrame 2014-06-10 Gustaf Neumann nsf.c: - fix name paths in error messages triggered from ArgumentParse() - move NsfMethodNamePath() out of NsfUnexpectedArgumentError() and NsfUnexpectedNonposArgumentError() - no need to call NsfMethodNamePath in NsfArgumentError() - move NsfMethodNamePath() out of NsfUnexpectedArgumentError() and NsfUnexpectedNonposArgumentError() - move NsfMethodNamePath() out of NsfObjWrongArgs() - added option "-dependent" to "info subclass" - extended regression test 2014-06-10 ssoberni - Working on info sub-methods for Class 2014-06-09 Gustaf Neumann - white-space change nsf.c - base MixinInvalidateObjOrders() on DependentSubClasses() and avoid the need of using a separate hash table for class-mixin handling. The new implementation is several times faster and improves the speed of the functions CleanupDestroyClass(), SuperclassAdd() and NsfRelationClassMixinsSet(). Adding a class-mixin to ::xotcl::Object in OpenACS is more than 4x faster. - remove obsolete function MixinResetOrderForInstances() - rename ResetOrderOfClassesUsedAsMixins() to ResetOrderOfObjectsUsingThisClassAsObjectMixin() - used consistently DependentSubClasses() instead of TransitiveSubClasses() for invalidations. - extend regression test 2014-06-08 Gustaf Neumann - fix a few more cases, where required accessor method "get" was missing - omit warnings, when value of "expected" looks like a non-positional parameter 2014-06-07 Gustaf Neumann nsf.c: - improve performance of MixinInvalidateObjOrders() by about 30% by recompiling the list of the dependent classes over and over again, since MixinInvalidateObjOrders() iterates over the full list already. - Document NsfRelationClassMixinsSet() and add nonnull declarations and the usual assertions() 2014-06-06 Gustaf Neumann - added experimental code feature CYCLIC_MIXIN_ERROR 2014-06-05 Gustaf Neumann nsf.c: - new function DependentSubClasses() to determine all classes that inherit from a given class. The result extend TransitiveSubClasses() by including class mixin relationships. - simplify NsfParameterCacheClassInvalidateCmd() by using the new function DependentSubClasses(). With the new implementation, NsfParameterCacheClassInvalidateCmd() is as efficient as before without to MostGeneralSuperclass optimization (but being complete now) when working on the root classes (and more efficient on subclasses). 2014-06-04 Gustaf Neumann - fixed error message for forward ... onerror and method paths. The command "C object mixin" returns now "::C object mixin add|clear|delete|get|guard|set" and not "::C mixin add|clear|delete|get|guard|set" as before. 2014-06-03 Gustaf Neumann - add ".add" file for mongodb interface - use cget interface - rename nsf::parameter:invalidate::classcache -> nsf::parameter::cache::classinvalidate nsf::parameter:invalidate::objectcache -> nsf::parameter::cache::objectinvalidate reasons: (a) remove single colon inside the name, (b) put verb to the end - use functions IsRootClass(), IsRootMetaClass() and IsBaseClass() to access object/class properties - add gcc attribute "pure" nsf.c: - cleanup of NsfParameterInvalidateClassCacheCmd(): performance improvements. After the fixing of indirect mixin validation, performance of invalidation went up by a factor of 5. At least, in some important cases (invalidation of rootclasses like nx::Object / xotcl::Object), we are again on the same level as before (actually slightly faster). 2014-06-02 Gustaf Neumann - reduce variable scopes - fix error message - add target for cppcheck with same arguments as for compilation 2014-06-02 ssoberni - Removing traces of nxdoc 2014-06-01 ssoberni - Fixing an example script for changes in getter/setter reform 2014-06-01 Gustaf Neumann - updated migration guide and tutorial to reflect recent changes - minor cleanup - improve spelling - update of TODO and regression test - adapt mixinof.test to the additional information - transform mixinof.test to newer style regression test with automated object deletion - add test file nsf-cmd.test - ignore generated .txt files nx.tcl: - removed /cls/ info configure parameters /cls/ info configure /cls/ info syntax Use e.g. "/cls/ info lookup parameters create" instead 2014-06-01 Gustaf Neumann - nsf.c: - Let "/cls/ info mixinof -closure" return as well implicit mixin classes to make it easier to determine class dependencies. Example: nx::Class create M0 nx::Class create M1 -superclass M0 nx::Class create M2 -superclass M1 nx::Class create C nx::Class create D -superclass C C mixin add M2 # M2 is mixed into C, and implicitly into D # # Since M2 is a subclass of M1, classes C and D depend as well # on M1 and M0, as seen in the heritage: ? {C info heritage} ":M2 ::M1 ::M0 ::nx::Object" ? {D info heritage} ":M2 ::M1 ::M0 ::C ::nx::Object" # previously, only "M2 info mixinof -closure" showed the # mixin relations, even with "-closure", while M1 and M0 did not. ? {M2 info mixinof -closure} "::C ::D" # now these show the same relations (in this example). ? {M1 info mixinof -closure} "::C ::D" ? {M0 info mixinof -closure} "::C ::D" 2014-06-01 Gustaf Neumann - handle ensembles in info nx::help - harden code mongodb: - upgrade to the newly released version 0.96 of the c-driver - replace deprecated function mongoc_collection_delete by mongoc_collection_remove - tested with MongoDB v2.6.1 2014-05-31 Gustaf Neumann - provide a minimal nx::help - provide contextObj when required argument is missing nsf.c: - added options to filter output from ::nsf::cmd::info parameter options (args, syntax, parameter) - deleted: - "/obj/ info lookup configure parameters ?pattern?" - "/obj/ info lookup configure syntax" - added: - "/obj/ info lookup parameters /methodName/ ?pattern?" - "/obj/ info lookup syntax /methodName/ ?pattern?" This covers as well - "/obj/ info lookup parameters configure|create|new|... ?pattern?" - extend regression test - remove dead code - white-space change - improve error message nsf.c, gentclAPI.tcl: - new argument types "virtualobjectargs" and "virtualclassargs" for context-specific argument resolutions: when a context object is provided, arguments of type "virtualobjectargs" are determined based on the slots applicable for the object (like "... lookup ..."), arguments of type "virtualclassargs" are resolved against a class. These types are used as follows: /obj/ configure /virtualobjectargs/ /cls/ create /name/ /virtualclassargs/ /cls/ recreate /name/ /virtualclassargs/ /cls/ new ?-childof /obj/? /virtualclassargs/ This new feature allows us to provide better error messages and to make much of the "... info ... configure parameter ..." infrastructure much less important. - For "virtualclassargs" we need the functionality to obtain from the C-Code based on a class the configure parameters applicable to objects of this class. - add argument "-context ..." to "cmd::info" to pass the context object (so far the only place where the context-object is used) - object system configuration parameters changes: new: -class.configureparameter new: -object.configureparameter removed: -class.objectparameter 2014-05-30 Gustaf Neumann nsf.c - renamed parameter::get -> parameter::info - renamed method::get -> cmd::info gentclAPI.tcl: - handle duplicated domains by folding these to a single definition nsf.c: - added command nsf::method::get. Rationale: provide a central place to obtain information about all kind of method handles, which might be - scripted and c-based methods - nsf::procs - plain Tcl procs - cmds (with and without parameter definitions) - make results of ListMethod() robust against missing information (e.g. plain tcl cmds, missing object registrations, etc.) - factor out common code for ListMethod call sites for per-object methods, instance methods and procs/cmds to ListMethodResolve() - return errors from failing converter registrations - extend regression test (new test set nsf-method.test) 2014-05-30 ssoberni - Done with first version of Class.man 2014-05-29 Gustaf Neumann - also drop class level "info configure" nx.tcl - drop short form "/obj/ info configure" for now - make output of "/obj/ info lookup configure syntax" equivalent to "/obj/ info configure" - updated TODOs - updated documentation - simplify slot parameter settings for object-mixins and object-filter lightly by omitting redundant method name - minor cleanup 2014-05-29 ssoberni - Some polishing of Object.man - Done with 'info method *' ensemble - Working on 'info object *' ensemble 2014-05-28 Gustaf Neumann - make error-checks as unlikely to succeed - we must replace ::get command with ::set commands for reestablishing relationships - return class of desired object in nsf::parameter::get when provided nsf.c: - extend nsf::parameter::get to obtained more detailed information for objects/classes/metaclasses/baseclasses and specified types - extend regression test 2014-05-28 ssoberni - Add doc fragment about 'info variable *' 2014-05-28 Gustaf Neumann nx.tcl - switch from "/obj/ info parameter" -> "nsf::parameter::get" to reduce potential semantic confusion of info options. "info parameter" was not object/class specific at all, but is just a syntax extractor nsf.c - force again literal "-guard" in a "mixinreg" type to avoid potential confusions - Base nsfRelationSet for mixins on cmds rather than TclObjs to avoid confusions and duplication of guard detection logic - Add interp to NsfMixinregGet() and NsfFilterregGet() to be able to return error messages - return more error message from mixinreg converter - provide at least minimal support for "funny class names" (i.e. containing spaces) - FinalObjectDeletion: don't enforce namespace = 1 for cases with weird namespace deletion order - extended regression test 2014-05-28 ssoberni - Amend doc of filter|mixin clear, re-instate -guard in filter|mixin set - Adding doc for the two new lookup sub-methods 2014-05-27 Gustaf Neumann - added methods "info lookup filters ?-guards? ?/pattern/?" and "info lookup methods *-guards? ?/pattern/?" - extended regression test - have "filter|mixin clear" return the list of former|removed filters|mixins. - disallow arguments for "... info configure" 2014-05-27 ssoberni - Complete info lookup doc - Adjust filter|mixin method for recent changes; working on info ensemble doc 2014-05-27 Gustaf Neumann - improve handling of space in object names nsfObj.c: - allow one to omit "-guard" within arguments to flag definition of a filter/mixin guard - extended regression test - name parameter option "slotset" instead of "slotassign" - use "mixin|filter clear" instead of "mixin|filter unset" 2014-05-26 Gustaf Neumann nsf.c: - fixed unary argument passing notation for "-nocomplain" of nsf::var and for 42 other options of other commands nx.tcl: - added flag -nocomplain to "/obj/ /prop/ unset ?-nocomplain?" - renamed nsf::relation to nsf::relation::set and added nsf::relation::get in accordance with nsf::var::get nsf.c: - added nsf::var::get and "::nx::var get" to provide selector based interface for variable reading (used in slot-method get of nx::VariableSlot) - cleanup of nx.tcl and TODO 2014-05-26 ssoberni - Updated doc fragments to reflect recent changes 2014-05-26 Gustaf Neumann nsf.c: - finish implementation of NsfForwardPrintError() - use NsfForwardPrintError() in ForwardArg() for all error messages traits: - define simple setter methods "requiredMethods" and "requiredVariables" to avoid to "set" these explicitly - fix compilation for OpenSolaris (e.g. OmniOS) 2014-05-25 Gustaf Neumann - fix compilation for OpenSolaris (e.g. OmniOS) 2014-05-23 Gustaf Neumann - cleaned up relation slot mixin variants nx.tcl: - reworked error message generation of slot-forwarder (list all available slot methods with prefix value=) xotcl2: - use xotcl::RelationSlot instead of nx::Relationslot in xotcl2 (we can more value=assign here). - fix load paths for sub-libs (e.g. mongodb) in regression test nx.tcl: - add slot method value=unset to nx::RelationSlot and nx::VariableSlot - extended regression test - added likely/unlikely to result == TCL_OK etc. xotcl2: - use value=set instead of value=assign - simplify "-parameter" implementation - add setters for "name", "domain", and "default" to xotcl::Attribute for backward compatibility mongodb: - by directing calls to the setter, it is now more complex to determine the true calling object for an converter, since the set operation might be routed though the slot object. It would be nice to have framework support for this. - fix 2 error messages - provide shorter tracebacks by using "return -code error ..." rather than "error ..." nsf.c: - fix one more subtle case of an error being swallowed: for xotcl, the constructor returns the list of residual arguments. In case there was an error, it was possible that the returned residual arguments overwrote the error message in the interp result 2014-05-23 ssoberni - Adjust variable doc for recent changes - Extending mixin/filter doc to cover guards - Adding filter doc fragment - Adjust mixin doc for recent changes - Adjusting property doc to reflect recent changes 2014-05-22 Gustaf Neumann - don't delete system slot ::xotcl::Attribute on cleanup nx.tcl, xotcl2.tcl: - use value=* as names for internally called and forwarder-called accessor methods - disallow "assign" for nx::variableSlots nsf.c: - rename default slot methods add/get to value=add/value=get - provide an error message, when referring to a non-existing slot object 2014-05-21 Gustaf Neumann nx.tcl: - use set/get/add as slot methods for get/configure/incremental operations - demangle slots for nx/xotcl2 further xotcl2: - use assign/get/add as slot methods for get/configure/incremental operations - use object system configuration for -slot.get and -slot.set - allow configuration of internally called "slot.get" and "slot.assign" methods via objectsystem::create 2014-05-20 Gustaf Neumann - enforce usage of "get" for all slots in nx - TODO: check, what in detail "parameter" in xtocl2 inherit from nx::variableslot (e.g. needsForwarder?) - enforce using "set" for filter/object-filter in slot operations (same as for mixins) nx.tcl: - remove setter methods from BootstrapVariableSlots - reducing interface of BootstrapVariableSlots by setting methods protected 2014-05-18 Gustaf Neumann - put test cases for all kind of mix setter / getter together in one test case - reduce verbosity nx.tcl: - add "set" as a method name for relation slots - implemented relation slot "mixin" and "object-mixin" via "slotassign" to disallow "/obj/ mixin /value/" and "/obj/ object mixin /value/" to use instead "/obj/ mixin set /value/" and "/obj/ object mixin set /value/" while keeping "configure" and "cget" working. This has the advantage that "/obj/ mixin set" does not try to replace the mixin chain by "set" - adapted regression test - TODO: check, if we need the explicit "slotassign"? isn't the presence of the slotObj sufficient? maybe "-forwardToSlot" in relationSlots? - TODO: demangle "slotassign" in "ObjectParameterSlot protected method getParameterOptions" and check interactions - TODO: to the same as -mixin and -object-mixin to -filter and -object-filter - TODO: clean up relation slot mixin variants - TODO: do we really like the fact that we have to write now "B mixin set M2" instead of "B mixin M2"? - TODO: should we disallow "B mixin" and enforce instead of "B mixin get" ? - TODO: we could as well allow "B mixin clear" instead of "B mixin set {}" - TODO: allow "set" for variable slots as well. Do we need "assign"? nsf.c: - allow parameter option "method=" for slotassign as well. rationale: this allows one to use the parameter "forwardername" to specify a different forwarder target method (e.g. in case of object-mixins). The method is used both in "configure" and "cget". - allow method name to consist of max two words in relation slots (e.g. "-methodname {mixin set}"} 2014-05-17 Gustaf Neumann - extend bagel example slightly - finalize dropping of setter methods for nx - show info line for every test case 2014-05-16 Gustaf Neumann - add flag "-onerror" to nsf::forward::method to handle errors during dispatch of a forwarder (not all error messages of forwarder are already transformed) - added log-level Info which prints always, e.g. for "-verbose" flag of forwarder - drop setter-rule from properties (use always forwarder) - drop "/obj/ /prop/" and "/obj/ /prop/ /value/" in favor of "/obj/ /prop/ get" and "/obj/ /prop/ assign /value/" to achieve better orthogonality with e.g. incremental properties 2014-05-14 Gustaf Neumann - replace empty-named arrays by dicts 2014-05-13 Gustaf Neumann - fix change of semantics when default multiplicity (1..1) is combined with lower bound preserving incremental (results in 1..n instead of 0..n previously) 2014-05-12 Gustaf Neumann - make sure that nsfDtrace.h has a newer timestamp than nsfDtrace.d - preserve lower bound of multiplicity when incremental is added - extend regression test - added more test cases for multiplicity and incremental nx.tcl: - Define method "value" as a slot forwarder to allow for calling value-less slot methods like e.g. "get" despite of the arity-based forward dispatcher. - extend regression test 2014-05-12 ssoberni - Adding doc fragment on mixin method 2014-05-12 Gustaf Neumann - remove over-eager nonnull declaration - remove done entries from TODO 2014-05-11 Gustaf Neumann - add fixes for tcl 8.6 - finish non-null handling for tcl 8.5 - continuing with nonnull assertions, various small cleanups 2014-05-10 Gustaf Neumann - complete nonnull assertion cleanup to 80% of nsf.c - complete nonnull assertion cleanup to 33% of nsf.c - improve source code documentation - simplify SuperclassAdd() - improve code documentation - complete nonnull assertion cleanup to 50% of nsf.c - simplify FilterInvalidateObjOrders() and FilterRemoveDependentFilterCmds() - complete nonnull assertion cleanup to 33% of nsf.c 2014-05-09 ssoberni - Add argument to last discussion item - Add another incremental TODO - Adding discussion items 2014-05-09 Gustaf Neumann - finishing checking of first 25% of nonnull assertions in nsf.c - added still more nonnull assertions 2014-05-09 ssoberni - Drafted a variable doc fragment, and revised the property's one to make the (subtle) difference clear 2014-05-09 Gustaf Neumann - added shortcut for MixinSearchProc when mixinOrder is NULL - work on nonnull 2014-05-08 Gustaf Neumann - let the c-code generator produce as well nonnull assertions - commenting item - made nsf::is using the "-strict" option when tcl's "string is" is called. 2014-05-08 ssoberni - Adding incremental doc to property doc fragment 2014-05-08 Gustaf Neumann - complete nonnull+assert adding in .c-files other than nsf.c 2014-05-08 ssoberni - Adding todo on multiplicities 2014-05-08 Gustaf Neumann - add asserts to nsfError.c - fixed all over-eager nonnull cases for optimizing with gcc and clang (works up to -O3 except gcc 4.9.0) 2014-05-07 Gustaf Neumann - added nonnull for args of type Tcl_Command and ClientData - add asserts for nonnull 2014-05-07 ssoberni - Starting documenting info ensemble 2014-05-06 Gustaf Neumann - provide nonnull statements for all functions in nsf.c - some more code cleanup - complete asserts due to nonnull 2014-05-05 Gustaf Neumann - update more copyright notices - update copyright notices - update copyright notice nsf.c: - simplify few inner code pieces based on assertions - add several more assertions based on nonnull specifications. - use nx rather than xotcl2 terminology in nsf::method::forward 2014-05-04 Gustaf Neumann - renamed "-methodprefix" to "-prefix" in nx, since the prefix can be applied as well applied to a cmd. 2014-05-04 ssoberni - Adding doc fragment about require method 2014-05-03 ssoberni - Adding a todo - nsf.c, NsfForwardMethod(): Make sure that a 2nd argument is available for prepending the methodprefix. Earlier, NSF crashed in case of a missing 2nd arg. - Added some basic tests on -methodprefix. 2014-05-03 Gustaf Neumann - use nonnull variable attributes for prototypes (nsf.h, nsfInt.h, nsf.c) nsf.c: - de-spaghetti precedence computations for multiple inheritance and improve documentation - get rid of // comments - stubsPtr can't be NULL there 2014-05-02 Gustaf Neumann - remove false alarm - deactivated "-onerror", since its semantics are expressible via try/catch, and there are no regression tests for xotcl and nx, and we could not find any script that uses this 2014-05-01 ssoberni - Adjusting forward doc, adding TODO - forward.test: Adding some tests 2014-05-01 Gustaf Neumann - use in forwarders "-frame object" instead of "-objframe" in nx for consistency with other calls (e.g. dispatch). Other values for "-frame" are not allowed. (btw, XOTcl has "-objscope") - move "checkalways for forwarders and aliases" to RFEs and comment it forwarders: - use for output of forward ... -verbose NsfLog(...NSF_LOG_NOTICE...) instead of fprintf() to make it redirect-able - RFE "provide %method" as keyword like %proc" was already implemented. Dropping %proc would break XOTcl2 compatibility. - adding a test case 2014-04-30 ssoberni - Continue working on forward doc, adding some tests - Adding some todos - Working on Object.man, in particular forward - library/nx/nx.tcl: Pulling out method contracts (pre- and postconditions) from NX for the time being. Corresponding tests have been commented out or, if applicable, turned into XOTcl2-specific tests. 2014-04-30 Gustaf Neumann - finalize autoconf quoting 2014-04-29 Gustaf Neumann - fix configure.ac quoting - stick closer to TEA conventions (keep tclconfig-sh in tclconfig directory) - remove obsolete version of install-sh, copy manifested version to mongodb library - fix more configure quoting 2014-04-18 ssoberni - Adding doc fragment on 'method' 2014-04-14 ssoberni - doc/Object.man: Adding documentation on alias (doc/alias.man.inc) and delete (doc/delete.man.inc) 2014-04-14 Gustaf Neumann small introspection reform: - Introspection for commands and arguments did not work for cmds defined in sub-packages (such as mongodb). We keep now this information in hash tables and maintain a slim interface for this. - fix generation of pkgIndex.tcl for mongodb 2014-04-08 ssoberni - Some more refactoring - Refactor the include file slightly, so that Object/Class-specific parameters etc. of a shared method documentation can be provided in the respective Object.man/Class.man files - Continue working in man pages, introducing a first shared section using [include] and [vset] 2014-04-06 Gustaf Neumann - tested with MongoDB v2.4.10 and J mongodb-c-driver 0.94.1 - moving .m4 files to subdirectory as recommended - update generated configure files - replace obsolete autoconf macros - replace obsolete autoconf macros - update to must recent build files (tcl.m4 and install-sh) from tcl source repository 2014-04-05 Gustaf Neumann build-process: - replace make.tcl by the much simpler mkIndex.tcl: * Does not use pkg_mkIndex * Does not load binary files (problem for cross compiling) * Requires package provide with constant in one line. 2014-04-03 Gustaf Neumann - reduce variable scope - remove redundant NULL tests - improve safety mof macro ObjStr() 2014-03-31 Gustaf Neumann - improve code documentation - add some more tests to the regression test suite 2014-03-29 ssoberni - generic/nsf.c: Avoiding excessive allocation/deallocation of temporary hash tables when invalidating per-class objparam caches in NsfParameterInvalidateClassCacheCmd(). 2014-03-29 Gustaf Neumann - extend regression test 2014-03-29 ssoberni - generic/nsf.c: Use GetAllClassMixinsOf() instead of TransitiveSubClasses() when invalidating per-class caches. Added two tests. 2014-03-28 Gustaf Neumann nsf.c: - remove obsolete code - invalidate parameter caches of subclasses on NsfParameterInvalidateClassCacheCmd unless during shutdown. Otherwise some classes might not become aware of properties added later to superclasses. - extended regression test 2014-03-25 ssoberni - Adding to Object.man: cget, configure, move, copy, ... 2014-03-23 Gustaf Neumann nx-mongo: - added command "::mongo::status /mongoConn/" - extended regression test 2014-03-22 Gustaf Neumann nsf.c: - fix case, where NsfDStringPrintf() failed (when print llength including \0 was 1 byte longer than print buffer) - make sure that the list kept for the cached parameter is just built from unshared objects; otherwise Tcl append will abort nx.tcl: - new package "nx::volatile" - don't define configure parameter "-volatile" per default; use "package req nx::volatile" instead - don't define per method "volatile" per default; use "::nsf::method::require ::nx::Object volatile" instead - get rid of -volatile in nx.tcl and serializer - update/extend regression test nsf.c: - fix case, where NsfDStringPrintf() failed (when print llength including \0 was 1 byte longer than print buffer) - added mongo::cursor::aggregate 2014-03-21 Gustaf Neumann - added mongo::collection::stats - extended regression test 2014-03-19 Gustaf Neumann nx-mongo: - fixed surprising compiler message "alignment of array elements is greater than element size" when using e.g. "bson_iter_t i[1]" - some c-code cleanup - tested with mongodb-c-driver 0.92.3 2014-03-17 ssoberni - Started working on an authoritative man page for nx::Object, still cleaning up and still tweaking the doctools markup 2014-03-15 Gustaf Neumann - mongodb's c-driver changed version number from 0.93.0 to 0.92.1; followed the change in README 2014-03-14 Gustaf Neumann - tested with mongodb-c-driver 0.93.0 2014-03-12 Gustaf Neumann - since mongoc_gridfs_get_files is supported since today by the mongo-c-driver, we do not need it private implementation any more. all dependencies on private header files are removed by now. 2014-03-09 Gustaf Neumann - adjust to newest version of mongo-c-driver - remove one dependency for private header file 2014-03-07 Gustaf Neumann - move close of the pseudo comment for syntax highlighter out of quoted block 2014-03-04 Gustaf Neumann xotcl2: - prevent strange error messages, when "abstract" is called with quotes in the argument list. 2014-03-02 Gustaf Neumann - represent BSON_TYPE_REGEX as pairs (regexp + options) in the Tcl representation to preserve regular expression options - update to newest version of mongo-c-driver and libbson from GitHub nx-mongo: - optional support for mongodb connection pools (compile time macro USE_CLIENT_POOL controls this, per default, this is on) - allow one to pass "-metadata" to gridfile::create to ease metadata attachment to grid-files - some convenience improvements in nx-mongo.tcl (ability to ignore attributes in "bson encode", ability to unset attributes in gridfs, ...) - bump version numbers of nsfmongo to 0.3 and nx-monogo to 0.5 2014-02-26 Gustaf Neumann nsf.c: - let [current methodpath] return full path (similar to -path option in "info methods" - handle collateral damage in regression test due to changed result of "current methodpath" - add traits.test to the regression tests nx::traits: - handle ensemble methods correctly (use full method path for resolution) - add new regression tests for traits nsf.c: - fix small memory leak in multiple inheritance code. - all regression tests rerun cleanly with --enable-memcount=yes 2014-02-25 Gustaf Neumann - raise an error, when an ensemble methods redefined a plain method - add incr/decr refcount for callInfoObj in unknown handling - deactivated suspicious assert() in NsfMethodNamePath() nsf.c: - change name of enumeratorConverterEntry to Nsf_EnumeratorConverterEntry, move it with NSF_ARG_* flags to tcl.h to make it available in derived modules using the converter - Added editor hints for a more uniform appearance - change configure flags from --with-mongodb to --with-mongoc=... and --with-bson nx-monogo: - Updated the mongo-c-driver and libbson to the actual tip version from GitHub (this is a significant change, since 10gen essentially changed the officially supported c-driver of MongoDB) - mongo-c-driver was more or less new-implementation, since structure and names changed in the mongo-c-driver substantially, several functions were added, several were dropped. The new interface supports now e.g. mongo URIs, and should be faster (by using collection objects instead of connection handles) - Although the low-level nsf interface changed significantly, the high-level (nx level) interface remained unaffected. - Configure has now --with-mongoc=... and --with-bson instead of --with-mongodb - New commands: mongo::collection::open /mongoConn/ /dbName/ /collectionName/ mongo::collection::close /collection/ mongo::gridfs::store_string /content/ /name/ /contentType/ - Make use of the new collection handle mongo::count /mongoConn/ /ns/ ... -> mongo::collection::count /collection/ ... mongo::index /mongoConn/ /ns/ ... -> mongo::collection::index /collection/ ... mongo::insert /mongoConn/ /ns/ ... -> mongo::collection::insert /collection/ ... mongo::query /mongoConn/ /ns/ ... -> mongo::collection::query /collection/ ... mongo::remove /mongoConn/ /ns/ ... -> mongo::collection::delete /collection/ ... mongo::update /mongoConn/ /ns/ ... -> mongo::collection::update /collection/ ... mongo::cursor::find /mongoConn/ /ns/ ... -> mongo::cursor::find /collection/ ... - nsf::mongo::connect receives now a mongoc_uri https://github.com/mongodb/mongo-c-driver/blob/master/doc/mongoc_uri.txt - The gridfs interface allows now to store multiple revisions of a file - The gridfs interface allows now upload files from a string - The gridfs interface allows one to refer to files by other attributes than just the filename (e.g. the mongo id). - Modified/new grid-file functions mongo::gridfile::create ?-source file|string? /gridfs/ /value/ /name/ /contentType/ mongo::gridfile::delete /gridfs/ /query/ mongo::gridfile::open /gridfs/ /query/ - Updated README - Updated regression test - Added editor hints for a more uniform appearance 2014-02-20 ssoberni - nx.tcl: Throw error exceptions using "return -code error", to exclude the unevaluated error cmd statement from the trace message - At two or three locations, we used to compute the method path using different helpers (CallStackMethodPath, NsfMethodNamePath) etc. I tried to unify this by revising NsfMethodNamePath to accommodate the different uses. - Besides, for required-argument checks, I included the method path (for ensemble invocations) into the error messages. 2014-02-17 Gustaf Neumann - improve performance of mongo->tcl conversion by using predefined global strings nx-mongo: - updated documentation (switch back to mongo-c-driver, but comment usage of tagged version v0.8.1) - added support for rep types (allow for mappings between certain instance variables such as arrays or dicts to customizable representations in MongoDB) - added nx-serialize to test cases (simple state persistence for nx objects) - added nx-rep to test cases (rep types for "array" and "dict") - provide datarootdir to get rid of warning during configure 2014-02-14 Gustaf Neumann - fix bug in interaction between up-level method from Tcl procs -nsf.c: - fix bug in interaction between uplevel method and interceptor transparency - extend regression test 2014-02-07 Gustaf Neumann - in case of multiple inheritance, make sure that all supporting classes haver already a precedence order defined 2014-02-04 Gustaf Neumann - implement simple persistent handle management based on per-thread objects - reduce verbosity for FreeUnsetTraceVariable - return TCL_OK, even when FreeUnsetTraceVariable() fails (warning stays) - improve worrying in comments - fix stub provisioning for Tcl 8.6.* - change macro name from XOTCL to NSF 2014-01-26 Gustaf Neumann nx: - allow copy of objects with required arguments - use ::nsf::object::alloc in "copy" method - don't depend on method "trace", use directdispatch instead - remove method "-noinit" (nsf::object::alloc makes it obsolete) - extend regression test - restore traces after object-serialize nsf.c: - when ::nsf::object::alloc is passed an empty name (2nd argument), behave like "new" method 2014-01-25 Gustaf Neumann - don't rely on the existence of a "trace" method nsf.c: - new command ::nsf::object::alloc /class/ /obj/ ?/script/? alloc an object and execute script in the context. Can be used to regenerate an object in a old state. serializer: - fixed loading of objects with required data in the blueprint (many thanks for david hopfmueller for reporting this) - make use of nsf::object::alloc (1 command instead of 1 create + 2 evals) - these changes improved loading time of blueprint by about 25% for OpenACS+xowiki 2014-01-21 Gustaf Neumann - make test for retrieving parsed parameters more safe 2014-01-08 Gustaf Neumann - update hint at end of build for NaviServer - strip trailing spaces - silence cppcheck 2014-01-07 Gustaf Neumann mongodb: - add flag "-puts" to method "show" of nx::mongo::Class to turnoff output to stdout - handle empty find operations for "find first" - added method pretty_variables to output available variables of a class in a similar style as in the definition - added low-level method "close" to nx::mongo 2014-01-01 Gustaf Neumann - Tcl's "package present" raises an error if the package is not present 2013-12-26 Gustaf Neumann - add more assertions - ensure computation of requires orders for recursive merges - make test more robust - strip trailing spaces - get rid of potentially uninitialized variables - make compilation more clean - add assertion for validity checking of precedence lists - improve error message - remove trailing space 2013-12-23 ssoberni - Fixing a mini-typo in nsf.c: unlinkely -> unlikely 2013-12-23 Gustaf Neumann - made linearization monotonic (for multiple inheritance) via single-inheritance linearization merging while preserving overall linearization rules - added flag NSF_LINEARIZER_TRACE - extended regression test - upgrade to mongo-c-driver to 0.8.1 - added new flag "-ttl" to mongo::index - there seems to be now a different mongo-c-driver to be the preferred one, the old one is renamed to mongo-c-driver-legacy - link against nsf-stublib - bump version number to 0.2 - don't try to load nx when building pkgindex for a binary package (.so or dylib) generic/nsfPointer.c: - add reference counter to avoid double-inits and double-frees in case the table of converters is used from multiple interpreters 2013-12-22 Gustaf Neumann - change base stub table from XOTcl to NSF. - improve wording of error messages. - add parameter parser and converter to stub tables - make converter usable from c-based packages compiled with subs activated 2013-11-12 Gustaf Neumann xotcl2: - fixed "... info defaults ..." and "... info instdefaults ..." emulation in XOTcl 2 - fixed error message - extended regression test - bumped revision of nsf/xotcl/nx to 2.0b6 2013-10-22 Gustaf Neumann - nsf: added switch "-checkalways" to nsf::method::create - nx: added switch "checkalways" to "method" and "object method" - extended regression test 2013-10-19 Gustaf Neumann - minor cleanup: * reduce variable scope * remove uncalled static function - added flag -checkalways to nsf::proc and nsf::asm::proc (for the latter just a placeholder for now). If the flag is used, it will cause argument testing independently from the "configure checkarguments" setting. To force argument checking always is useful e.g. for checking external values (e.g. in a web server) 2013-09-15 Gustaf Neumann - fix object method serializeExportedMethod: targetName might have been uninitialized 2013-08-27 ssoberni - Explored assertion support from an NX perspective, by reviewing the current implementation against Eiffel's RAC; along the way, I made ::nsf::current more robust when being used in assertions 2013-08-08 Gustaf Neumann - don't call postcondition, when the command/invariant have returned already an error nsf.c - fixed a bug where turning on assertions could swallow result-codes - extended regression test - fix potential crash when preconditions are empty - fix typo 2013-08-03 Gustaf Neumann - added sample script doc/example-scripts/tk-geo.tcl - minor cleanup of configure script - bump version number of mongo support to 0.2 2013-08-01 Gustaf Neumann mongodb: - integrated configuration of mongodb into top-level configfile option: --with-mongodb=MONGO_INCLUDE_DIR,MONGO_LIB_DIR - added regression test files for mongodb support (low-level (tcl-only) and high-level (nx based oo support)) - integrated mongodb-testfiles with "make test" - reduced verbosity of nx-mongo.tcl (added verbosity variable) 2013-07-31 Gustaf Neumann - added example scripts rosetta-sudoku.{tcl,html} and tk-ludo.{tcl,html} mongodb: - don't call NsfLog() in Nsfmongo_Exit, since interp-data might be already cleaned up - improve robustness - added flag for verbosity 2013-07-30 Gustaf Neumann mongodb: - updated to most recent version of c-driver (0.7.1) - adapted to nx 2.0b5 (use everywhere cget interface) - tested with mongodb 2.4.5 - updated locomotive example to use nx::callback 2013-07-16 Gustaf Neumann - updated TODO 2013-07-15 Gustaf Neumann - prepare for providing nx as a Tcl module (.tm file). this is just a preparation, since for testing, one cannot set up a path that prefers a local copy over a global installed one (the global tcl-site is preferred over the one specified in e.g. TCL8_5_TM_PATH) 2013-07-08 Gustaf Neumann - explore the usage of dict instead of anonymous array nsf.c: - don't use the default of a invocation parameter in "configure" when the object is already initialized. The default is in general only used when the parameter is not specified. We do not want e.g. superclass to be reset to ::nx::Object, when configure is called on a class without arguments. - extended regression test 2013-07-02 Gustaf Neumann - remove debug statement 2013-06-24 Gustaf Neumann - keep this single pkgIndex.tcl - keep packages versions from 2.0 and 1.0 disjoint ./nsf2.4.0/README.profile000644 000766 000024 00000011647 13717240347 015530 0ustar00neumannstaff000000 000000 Profiling with NSF ================== NSF offers the following built-in options for profiling, which apply to methods (all instance and per class methods of XOTcl, NX, ...) and to nsf::procs. Preliminaries: -------------- - make sure nsf is compiled with "--enable-profile" - if you are not sure, check the file config.log in the source directory, where nsf was compiled. You find a line looking like $ ./configure .... near to the top of the file. If the configure line does not contain "--enable-profile", run the configure command with "--enable-profile" added, then make clean; make; sudo make install - to check, if the version you are using is complied properly check the global Tcl array ::nsf::config, e.g. with $ nxsh % parray ::nsf::config Profiling: ---------- From nsf profiling supports 1) detailed profiling about a full run, or 2) selective profiling Dtrace: ------- Alternatively dtrace [2] can be used to obtain profiling information from nsf (and Tcl as well).... but this depends on the operating system support (Solaris heritage). ========================================================================================================= # # Sample script and helper procs to show, how profiling/tracing works # in NSF with the not widely advertised profiling support based on # # ::nsf::__profile # # Gustaf Neumann # package require nx # # Helper function for in-memory profiling # proc mini-profile {cmd} { if {[nsf::pkgconfig get profile]} { try { nsf::__profile_clear nsf::__profile_trace -enable true uplevel $cmd } on error {errorMsg} { error $errorMsg } finally { nsf::__profile_trace -enable false } # # The collected profile data contains: # # totalMicroSec: measured time since profile start # # overallTime: aggregated time from traces # # objectData list of lists, where every element contains # {object class method} aggregated_time number_of_calls # # methodData list of lists, where every element contains # {method class} {callerMethod callerClass} aggregated_time number_of_calls # # procData list of lists, where every element contains # {proc aggregated_time number_of_calls} # # trace new-line separated entries containing call, exit, and time # lassign [::nsf::__profile_get] totalMicroSec overallTime objectData methodData procData trace # Output profile data... or do something else with it... # puts "Profile Data:\n===================" foreach v {totalMicroSec overallTime objectData methodData procData trace} { set break [expr {$v eq "trace" ? "\n" : "\t"} ] puts "$v$break[set $v]" } puts "===================" } else { puts stderr "NSF is not compiled with profiling support" uplevel $cmd } } nsf::proc bar {x:integer} { return $x } nx::Class create C { # # Naive version of factorial # :public method fact {n} { if {$n < 2} { return 1 } else { return [expr {$n * [:fact [expr {$n-1}]]}] } } :public method foo {n} { bar 1 return [:fact $n] } } C create c1 ####################################################### # Plain run ####################################################### puts "factorial of 6 = [c1 foo 6]" ####################################################### # Run the same command with profiling, # collect the profile data in memory ####################################################### mini-profile {c1 foo 6} puts "\nTrace profiling information to output" puts "===================" nsf::__profile_trace -enable true -dontsave true -verbose 1 c1 foo 6 nsf::__profile_trace -enable false puts "===================" ####################################################### # Define custom logger to handle e.g. trace output ####################################################### proc ::nsf::log {level msg} { puts stderr "MY-logger: $level: $msg" } puts "\nTrace profiling information to output (with extra logger)" puts "===================" nsf::__profile_trace -enable true -dontsave true -verbose 1 c1 foo 6 nsf::__profile_trace -enable false puts "===================" ####################################################### # Selective profiling and tracing # Define custom debug commands ####################################################### proc ::nsf::debug::call {level objectInfo methodInfo arglist} { nsf::log Debug "MY call($level) - $objectInfo $methodInfo $arglist" } proc ::nsf::debug::exit {level objectInfo methodInfo result usec} { nsf::log Debug "MY exit($level) - $objectInfo $methodInfo $usec usec -> $result" } # # Select methods to be traced (could be also done with the # flag "-debug" in the source # ::nsf::method::property C fact debug true ::nsf::method::property C ::bar debug true puts "\nSelective profiling (with extra logger, debug, and custom debug messages)" puts "===================" c1 foo 6 puts "===================" ./nsf2.4.0/nxwish.in000644 000766 000024 00000001320 13030507001 015021 0ustar00neumannstaff000000 000000 #! /bin/sh # Lookup a Tcl interpreter \ INTERP="tclsh@TCL_VERSION@"; \ INTERPS="@NSF_COMPATIBLE_TCLSH@ @TCL_EXEC_PREFIX@/bin/$INTERP"; \ for interp in $INTERPS; \ do if [ -x $interp ]; then INTERP=$interp; break; \ fi; done; \ exec $INTERP "$0" ${1+"$@"} # -*- tcl -*- # # Tiny scripted replacement of a binary nxwish (former xowish). This # script can be used as interactive shell for testing or like a # regular shell with the #! markup in the first line of a script. It # is designed to work with multiple installed Tcl shells during # development. # package require Tk package require nx::shell 1.1 namespace import -force ::nx::* set exitCode [nx::shell run $argc $argv] exit $exitCode ./nsf2.4.0/ChangeLog-2.1.0-HEAD000644 000766 000024 00000115115 14275417766 016124 0ustar00neumannstaff000000 000000 2018-07-16 Stefan Sobernig * README.md: http -> https [skip ci] 2018-07-15 Gustaf Neumann bump version number to 2.2 update REAME file update copyright information improve markdown improve markdown change READE to markdown syntax improve markdown improve markdown use markdown syntax prefer new spelling of macOS updating mongodb interface for 2.2: - update to mongodb-c-driver 1.11.0 - reduce number of calls to deprecated driver functions as far as possible - improve cleanness of compilation (provde prototypes etc.) - bump version number to 2.2 prefer Tcl defined types over local prototypes 2018-07-13 Stefan Sobernig * nsfDebug.c, nsfInt.h (STRING_NEW, MEM_COUNT_ALLOC, MEM_COUNT_FREE): Fix compilation with --enable-memcount=yes. * configure, configure.ac, nx.tcl, pkgIndex.tcl, xotcl2.tcl, pkg.vc: Bump version to 2.2.0. Done with work on changelog and announcement. [skip ci] 2018-07-12 Stefan Sobernig Continued work on changelog and announcement. [skip ci] Continued work on changelog and announcement. [skip ci] 2018-07-10 Gustaf Neumann Fix buggy case when blueprints are used to update interpreters with preexisting objects and classes. There, it was possible that objects are turned into baseclass objects, when the application classes are deleted. 2018-07-06 Stefan Sobernig Continued work on changelog and announcement. [skip ci] 2018-07-04 Stefan Sobernig Continued work on changelog and announcement. [skip ci] Continued work on changelog and announcement. [skip ci] 2018-07-04 Gustaf Neumann improve spelling 2018-07-03 Stefan Sobernig Continued work on changelog and announcement. [skip ci] Continued work on changelog and announcement. [skip ci] 2018-07-02 Stefan Sobernig Continued work on changelog and announcement. [skip ci] Continued work on changelog and announcement [skip ci] * Adding changelog and announce file (WIP) for 2.2.0 [skip ci] * makefile.vc (CFLAGS): Also set -DHAVE_UINTPTR_T. * makefile.vc (CFLAGS): Add -DHAVE_INTPTR_T explicitly. 2018-07-02 Gustaf Neumann MSVC seems to be bad on const expressions add starmethod design study improve spelling fix typo 2018-07-01 Gustaf Neumann Improve comments, unify comment formatting and whitespace cleanup properly initialize resultObj in all cases remove dead assignments, initialize variables also on error paths make sure to initialize all variables also in error cases Reduce number of implicit type conversions Avoid use of macros mprove alignment of prototypes and function definitions 2018-06-29 Stefan Sobernig * nsf.c (ObjectCmdMethodDispatch, FindNextMethod): Balance book-keeping in memcounts for Tcl_Objs (technically, an unmatched decrement would suffice). * nsf.c (NsfProcDeleteProc): Fix freeing of colonLocalVarCache and balance book-kepping on memcounts for colonLocalVarCache. * nsf.c (ObjectCmdMethodDispatch): Silence static check of GCC 8.1 (-Wmaybe-uninitialized). [skip ci] * nsf.c (NsfCurrentCmd): Avoid (possible, but unlikely) null dereferencing, if CSC was missing [CID 294166]. * nsf.c (NsfDebugGetDict): Compute the remaining size to snprintf for each iteration [CID 294169]. [skip ci] 2018-06-29 Gustaf Neumann address CID 294171 and change construct for strpbrk 2018-06-29 Stefan Sobernig nsf.c (NsfDebugGetDict): Parametrize length computation; remove unneeded nul-termination. [skip ci] 2018-06-29 Gustaf Neumann minor cleanup reduce variable scope and minor cleanup 2018-06-28 Stefan Sobernig * nsf.c (NsfDebugGetDict): Make use of strncat more robust by setting the destingation length to the remainder of the output buffer. * nsf.c (ForwardArg): Provide a const'ed pointer to strpbrk, as required [CID 294162]. * nsf.c (ParamDefsFormat): Fix overrun in memcpy by correcting the destination-length argument [CID 294165]. * nsf.c: Fix all "-pedantic -ansi" errors. 2018-06-27 Stefan Sobernig * nsf.c (ParamDefsStore, NsfProcDeleteProc): Provide for counting a reference to the execNsPtr from the NsfProcContext structure. While I could not devise a script-level path to pull out the rug (execNsPtr) out from under NsfProcContext clients, I can only also not exclude the latter (from future C-level paths?). Better act defensively. * nsfInt.h (STRING_NEW): Silence GCC 8.1 warnings on truncation risk using strncpy; made me wonder whether STRING_NEW would not be more robust against mis-computations of the destination-buffer length by using snprintf (mainly because snprintf does not nul-pad the destination buffer and always nul-terminates the destination buffer)? 2018-06-26 Stefan Sobernig * parameters.test: Adding two test cases to cover previously missed code branches leading to leaking NsfMethodNamePath uses. 2018-06-25 Stefan Sobernig * nsf.c (ArgumentParse): Handle NsfMethodNamePath result correctly. * nsf.c (NsfSetterMethod): Handle NsfMethodNamePath result correctly. * nsf.c (ObjectCmdMethodDispatch): Close another Tcl_Obj leak incurred by not handling the result from NsfMethodNamePath. * nsf.c (FindNextMethod): Plumb another memleak (valgrind). The Tcl_Obj computed by NsfMethodNamePath must be refcount corrected. * nsf.c (AliasGet): Plumbing a memleak found by valgrind. The computed Tcl_Obj from AliasIndex must be refcount-managed explicitly, otherwise the path via AliasGet leaks it. 2018-06-20 Stefan Sobernig Fix makefile.vc syntax [skip travis] Re-code env variable dimension of build matrix Fix appveyor.yml syntax Necessary additions to build script and NMAKE/TEA artifacts appveyor.yml: Add TOOLCHAIN dimension to incorporate MSVC builds per-object-mixins.tcl: Fix an example script that got broken a long, long time ago. [skip ci] 2018-06-19 Stefan Sobernig Fix build.tcl pt. 2 [skip ci] Fix build.tcl [skip ci] Add nmake mode to build.tcl [skip ci] 2018-06-18 Stefan Sobernig Add allowed failures to Travis setup [skip appveyor] Set allowed failures on Tcl development branches; report failure on first failing build [skip travis] * nsf.c (ParamOptionParse), nsfInt.h: Provide for own MAX and MIN macros, the ones reused implicitly from Tcl's tommath have vanished in 8.7 branches; and are not provided otherwise, at least in MinGW settings. Fixes 8.7 builds for MinGW under Win. Fix descriptor syntax. Finally, got Windows builds (MinGW) working on Appveyor. Cleaning up build scripts. Trying to set HOME dir explicitly, 2nd try, sigh! [skip travis] Trying to set HOME dir explicitly [skip travis] Triangulate HOME dir [skip travis] Add debugging in build scripts [skip travis] Add debugging in build scripts [skip travis] Relocate env setup into build_script block [skip travis] Fix path setting [skip travis] Fix path setting [skip travis] Make sure that sh and bash are initialized the same. [skip travis] Turn on MORE debugging [skip travis] Turn on MORE debugging [skip travis] Turn on MORE debugging [skip travis] Turn on debugging [skip travis] Turn on debugging [skip travis] Add skip marker; correct path settings [skip travis] Try native MinGW pt. 4 Try native MinGW pt. 3 Try native MinGW pt. 2 Try native MinGW Avoid x-compilation Another try to fix build paths 2018-06-17 Stefan Sobernig Install gcc dependency on builders Fix mingw toolchain path Update appveyor.yml Prep build script to support MSYS2/MinGW builds under Windows 2018-06-04 Stefan Sobernig * nsf.c (ListSuperClasses): Fix refcounting for 8.5 non-threaded only, otherwise the patternString becomes unavailable once a preemptive decrement has been performed, leading to unexpected info results. * nx-test.tcl (run): Avoid use of [try], to render the test suite independent of the presence of 8.6 or tcllib's try. This may be reverted, once 8.5 support is dropped. 2018-06-01 Gustaf Neumann add COMPILE_NSF_STUBS to compile flags under windows make stublib initialization more robust and provide meaningful error message in case of misconfigurations 2018-05-30 Stefan Sobernig Turn on some debugging Add missing tclkit url First attempt at Appveyor integration (mingw64 only) Trying to get env variables right Make build script more verbose Fix env variables in build descriptor Provide first attempt at Travis build array and build script 2018-05-29 Stefan Sobernig Simplify descriptor, for the time being Add an initial Travis CI descriptor Add a TODO Makefile.in: Polishing 2018-05-23 Gustaf Neumann improve spelling use mongoc_iovec_t instead of struct iovec iov to improve cross-platform compatibility 2018-05-21 Gustaf Neumann improve comments 2018-05-17 Gustaf Neumann improve wording improve tcl idioms 2018-04-30 Gustaf Neumann remove duplicated word 2018-04-25 Gustaf Neumann fix duplicated words in code documentation fix double word in code documentation fix double worlds in code documentation 2018-04-15 Gustaf Neumann add destroy_on_cleanup similar to OpenACS to ease lifetime management of volatile objects 2018-04-14 Gustaf Neumann fixiing cut&paste error 2018-04-12 Gustaf Neumann white space changes - added class names into serialization syntax (__class). This change allows us to make better use of polymorphism with (e.g. embedded) class structures. Previously, it was necessary, that the called had to know the class of the serialized object, now it is as well possible to use as well specializations. - fix bug, where default value for properties lead to errors, when no property options where given. update version numbers of mongo's c-driver (older versions stopped working on macOS High Sierra) fix typo 2018-04-05 Gustaf Neumann fix typos fix typo 2018-03-28 Gustaf Neumann regenerated documentation fix typos 2018-03-23 Gustaf Neumann Remove unneeded ALLOC_ON_STACK 2018-03-11 Stefan Sobernig * nsf.c (ListMethod): Provide a disassemble implementation based on ::tcl::unsupported::disassemble. [::nsf::cmf::info disassemble] is generally available, the info ?object? method variants only in development mode. Implementation covers proc methods and ::nsf::procs. Along the way, prettify some code paths in ListMethod. 2018-03-08 Gustaf Neumann add const declarations, whitespace changes 2018-03-06 Stefan Sobernig * nsf.c (Nsf_Init): Mark the namespace "::nsf::classes" and its children using "NS_SUPPRESS_COMPILATION". In 8.6+, this guards any commands in these auxiliary namespaces to be picked up by the bytecode compiler (if accessed in an unintended manner). * nsf.c (ByteCompiled): Patch the proc command's namespace unconditionally, for 8.5 and 8.6. 2018-03-03 Gustaf Neumann avoid potentially dangerous call strcat(); remove unneeded assignment 2018-03-02 Gustaf Neumann whitespace changes break overlong lines polish and comment the execNs change for Tcl 8.5 Quickfix for Tcl 8.5 (needs still more investigation) 2018-02-25 Gustaf Neumann add const declarations, reduce variable scopes, break longish lines 2018-02-21 Stefan Sobernig Fix call example Leave some to-dos * dtrace/README: Updated instructions to cover SIP deactivation, minor corrections. Added one more D script (nsf_call-time.d). * nsfDTrace.h: Re-generated. * nsf.c (NsfConfigureCmd): Fix NSF_DTRACE=1 builds. * gentclAPI.tcl, nsfAPI.decls (createconverter): Support for "-global 1" flag that will cause the options array corresponding to an enumeration to become available as a global, properly Nsf_* prefixed symbol. Used for NsfConfigureCmd and the corresponding DTrace probe, for now. 2018-02-19 Gustaf Neumann add const and pure declarations 2018-02-19 Stefan Sobernig * source-doc-beautifier.tcl: Remove in-block range markers within test bodies to prettify the ADOC output. 2018-02-19 Gustaf Neumann adding const declarations, variable name cleanup more code cleanup: - reuduce number of returns before end of function - ease live for static checker - use more "const" declarations 2018-02-18 Gustaf Neumann add comment and improve linebreak - prefer bool over int - reduce number of gotos - reduce number of returns before end of function - reduce variable scopes - add "const" declaration - white-space changes 2018-02-17 Gustaf Neumann align prototypes with function definitions whitespace changes prefer bool over int, white space changes 2018-02-16 Gustaf Neumann More code cleanup - make nsf compilable with tcl 8.7.2 and TCL_NO_DEPRECATED turned on - prefer bool over int - reduce nr of returns before end of function - line bread overlong function definitions update genstub path to recent versions of Tcl releases 2018-02-14 Gustaf Neumann prefer boolean over int Reduce number of return statements beofre end of function cleanup: fix regression, prefer boolean over int, reduce number of returns before end of function ease life of colon cmd cachier Don't pass colon-prefixed method names from setter cmd to SetInstVar() to avoid potential shimmering. 2018-02-11 Gustaf Neumann - add Tcl_Obj caching to cget argument - redued usage of goto statements - reduced size of largish function introduce macro ObjTypeStr for commonly used idiom prefer boolean over int coloncmd reform (part 4): perform validation for per-object cases, provide more detailed statistics (when compiled with COLON_CMD_STATS) 2018-02-10 Gustaf Neumann Reduce memory consumption for cache by caching just cmds in non-volatile Tcl_Objs. Add optional statistics, when COLON_CMD_STATS is defined. simplify expression remove unneeded variable add NsfDList functions similar to Tcl_DString, but operating on void* instead of char and use it for ColonCmdCache data Simplify handling of "returns" object. no need to require paramdefs, when just returnsObj is needed coloncmd reform (part 3): keep a per-interp list of colon command cache entries to avoid memory leaks in cases the objects are converted 2018-02-09 Gustaf Neumann coloncmd reform (part 2): generalize code and apply for object specific commands as well coloncmd reform (part 1): improve dispatch of [:method ...] by up to 30% 2018-02-09 Stefan Sobernig * msgcat.test: Added a small collection of basic tests covering msgcat usage from within NSF/NX objects and classes. Tested successfully with mainline Tcl 8.6 and the TIP-490 branch "tip490-msgcat-oo-2". 2018-02-07 Gustaf Neumann whitespace changes 2018-02-06 Gustaf Neumann pass execNsPtr to byte-compiler (which might be different to procPtr->cmd->nsPtr) 2018-01-30 Stefan Sobernig * nsf.c (NextSearchAndInvoke): Relax the pre-conditions, objv can actually be NULL (see test cases). Besides, the assertion was not reflected by a corresponding nonnull constraints on the NextSearchAndInvoke prototype. 2018-01-27 Gustaf Neumann More code cleanup: - use Boolean type when appropriate - add missing comments More code cleanup: - use Boolean type when appropriate - reduce implicit conversions More code cleanup: - use Boolean type when appropriate - reduce implicit conversions More code cleanup: - use Boolean type when appropriate More code cleanup: - use Boolean type when appropriate More code cleanup: - use Boolean type when appropriate More code cleanup: - use Boolean type when appropriate More code cleanup: - move nonnull assertion to separate line - use Boolean type when appropriate 2018-01-26 Gustaf Neumann remove unused arguments Use Boolean type on more occasions Fix incorrect comments Fix mixture of Tcl result code and 0/1 integers Use Boolean type on more occasions Boolean type introduction - Define Boolean type in a cross compiler / cross platform compatible way (similar to NaviServer) - Include type in nsfInt (internal usage) but capable for pushing it to public usage later - Use Boolean type for the most obvious cases 2018-01-25 Gustaf Neumann improve type cleanness for clang 6.0 Align prototypes with function definitions and minor code cleanup - reduce number of return statements before end of function - reduce variable scopes write separate commands in different lines (esp. for control structures) align naming of variables in function prototypes and definitions mark unused arguments as UNUSED 2018-01-24 Gustaf Neumann make argument names more regular improve alignment of prototype names with function definitions fix typos Improve alignment of prototypes with function definitions improve regularity of variable names prefer meaningful name in function prototypes align names in .decls file with prototypes in the .c and .h files 2018-01-22 Gustaf Neumann Remove unused arguments remove unused argument Remove unused argument 2018-01-20 Gustaf Neumann minor cleanup (adjust comments, reduce variable scope) 2018-01-19 Stefan Sobernig nx-test.tcl (exit): Fix the return trampoline for [exit] during test runs 2018-01-19 Gustaf Neumann Fix overseen error in regression test 2018-01-19 Stefan Sobernig Fix another 86/85 glitch Make test suite working under 8.5, again. 2018-01-18 Gustaf Neumann extend regression test execution namespace reform: - add execution namespace to proc context instead of altering the namespace of the command - this fixes strange behavior of "info commands ::o::p", which might have returned "::p" - provide compatibility with Tcl 8.7a2 - extend regression test 2018-01-16 Gustaf Neumann get the "int" type from the Tcl_Obj directly, which will continue to work in Tcl 9.0 Provide compatibility with TIP #484 deactivate solution to the tcl87a2 problem for now, since we need a different solution with this for recursive aliases improve woring in comment remove shadowing variable reduce implicit conversions transitional fix for tcl87a2 problem 2018-01-15 Gustaf Neumann substdefault code cleanup extend regression test, make assumptions explicit 2018-01-14 Gustaf Neumann - remove stripping of substdefault from properties - add handling of extended substdefault options to per-object variables - improve default value checking for slot-less variables - transfor associated array into a dict - extend regression tests 2018-01-13 Gustaf Neumann delete pre-existing commands explicitly 2018-01-12 Gustaf Neumann - provide fully qualified names to Tcl_ProcObjCmd() to avoid potential problems in newer Tcl versions 2018-01-05 Gustaf Neumann - make it possible to use error code for cmd result comparison - add some NSF specific error code provide error hint for "invalid value constraints" errors add error message, when present Reduce number of strlen() operations whitespace changes Fold "substdefault" and "substdefaultoptions" into a single parameter option "substdefault" 2018-01-04 Stefan Sobernig * nsf.c (ParamOptionParse): Fixed typo in error msg. * nsf.c (NSCheckNamespace): Simplify resource management of a DString. * nsf.c (ParamSetFromAny2): Fix inline comment. * nsf.c (ParamOptionParse, ParamDefinitionParse, ParamDefsParse), parameters.test: Small "type=" converterArg reform. Provided additional parameter in param-parser machinery, to communicate a (namespace) qualifier into ParamOptionParse. This way, the unqualified type=* values are now expanded to qualified names (definition scope): method parameters, nsf::is, nsf::parseargs, setter methods. Type=* in object parameters are currently expanded at the slot level, could also be added. New tests were added, existing ones adjusted to reflect the new behavior. 2018-01-03 Gustaf Neumann - new command "tnsf::definitionnamespace" - experiment with command in regression test fix typo in comment - implement substdefaultoptions (for now, just providing the bitmask) - add substdefault.test - rename static function ParamParse() to ParamDefinitionParse() - break overlong lines 2018-01-02 Gustaf Neumann Silence gcc8 2018-01-01 Gustaf Neumann Use snprintf() instead of sprintf() to protect better against potential buffer overflows Remove old-style CompiledColonLocalsLookup and use colonLocalVarCache variant instead. 2017-12-31 Gustaf Neumann Fix leftover from the time, when we could call accessor methods without "get" 2017-12-31 Stefan Sobernig * nx.tcl, nx-mongo.tcl (parseParamSpec): Render target parameter non-positional, so that MetaSlot.parseParamSpec() becomes backward compatible. Adjusted callsites of parseParamSpec. 2017-12-30 Gustaf Neumann Add missing argument to parseParameterSpec Improve portability (restict length of literal strings <= 4095) Address literal limitation in ISO C99, that requires compilers to support only strings up to 4095 bytes. As a consequence, we have to split the compiled-in literal commands into two parts. deactivate two problematic tests for the time being to allow regression test to run 2017-12-29 Gustaf Neumann fix typos, updaty copyright years according to commits prefer boolean test, remove commented-out code 2017-12-24 Gustaf Neumann Fix typos 2017-12-21 Stefan Sobernig * nsf.c (ParamParse): Fix crash when ParamParse is called with an empty-string argument, e.g. nsf::parameter::info type "". Tests provided. Add another to-do item 2017-12-20 Stefan Sobernig Add to-do items * nsf.c (NsfParseArgsCmd): Fix another edge case (empty spec and/or empty argv), added more tests. See also TODO. * nsf.c (NsfParseArgsCmd): Fix nsf::parseargs for the case of Tcl-only params, otherwise, it crashes due to an uninitialized params structure. Added some tests. 2017-12-19 Stefan Sobernig * nsf.c (ParamDefsParse): Fix small typo "allowedOptinons" -> "allowedOptions" 2017-12-01 Stefan Sobernig * nx.tcl (Class.variable): Clean up a left-over. * nx.tcl (Class.variable()): Re-order the substdefault-handling block to render it more meaningful. Add to-do item * nx.tcl (substdefault): Unify and harden substdefault handling. Both, per-class and per-object substdefault should now behave similarly in absence of a pair of evaluation brackets. Also, an attempt is made to capture ill-formed input to subst earlier ([info complete]). An actual substdefault reform, however, must tackle the [subst] calls (-novariables?) and make the calls more robust (at the script and C level; [apply]-like?). Added some tests for documentation. 2017-11-30 Stefan Sobernig parameters.test: Simplify test case slightly. * nx.tcl (MetaSlot.parseParameterSpec): Refine handling of the type converter to expand unqualified names to the "nearer" namespace (i.e., namespace of the slot-owning object) rather than "". Along the way, intercept invalid type=* values earlier (empty string, "::"). Added some tests. * nsfDebug.c: Remove duplicate array entry. * nsfDebug.c (NsfInitPkgConfig): Provide NSF configuration data via the TIP 59 interface (::nsf::pkgconfig). 2017-11-18 Gustaf Neumann - silence static checker 2017-11-16 Gustaf Neumann Improve cleanness of compilation with Tcl 8.5 Remove unneeded function add const declaration 2017-11-15 Gustaf Neumann Don't allow bytearrays as name of non-pos args We try to address the problem, that the argument parser might add string reps to Tcl_Objs without string reps. This is in particular nasty for pure byte arrays in Tcl 8.6, which are defined as having no string. We do not want to change purtiy just by passing such values in arguments, 2017-11-09 Gustaf Neumann Adjust print format to recent changes 2017-11-08 Stefan Sobernig nsf.c, nsfInt.h, nsfObj.c: Make epoch counters unsigned ints, so doubling the number of possible epochs. * nsf.c: Unify cmd flags cast (unsigned long -> unsigned int) * nsf.c (ObjectCmdMethodDispatch): Simplify and cleanup condition expressions. nsf.c (ObjectCmdMethodDispatch), submethods.test: Enable private checking on ensembles, added test cases to capture the intended behavior behind -local and/or private for ensemble methods. 2017-10-24 Gustaf Neumann move GetObj() after tests of non-null asserts 2017-10-20 Gustaf Neumann Fix collateral damage of protection changes Move prototypes to begin of file Cleanup: Don't shadow variable names. Minor cleanup: remove commented code, add missing nonnull-assert, shorten overlong lines 2017-10-19 Stefan Sobernig * nsf.c (NsfMethodForwardCmd): Provide correct scoping condition when requesting a method handle for a submethod forwarder. Added basic tests. 2017-10-13 Stefan Sobernig * nsf.c, nsfStack.c: Bump copyright years. * nsf.c (ObjectCmdMethodDispatch), protected.test: For ensemble (submethod) dispatches, since ever, call protection had not been enforced at all. This commit enables call protection (protected) for ensembles and adds basic tests. * nsfStack.c (GetSelfObj): To allow one to resolve the self reference at arbitrary callstack levels, separate GetSelfObj into GetSelfObj (macro) for the topmost self and GetSelfObj2. 2017-10-06 Gustaf Neumann fix typo 2017-10-02 Stefan Sobernig * nsf.c (NsfCCreateMethod): During a shutdown, in a filter setting, objv is not necessarily populated. Prior to this fix, the following crashes on exit for "ObjStr(objv[1])": nx::Class create Klass Klass public object method expand args { return [[self] new {*}$args] } Klass object filters add expand Along the way, rendered the print-out more informative. 2017-09-19 Gustaf Neumann Add likely/unlikely for NSF_DURING_DELETE checks Code cleanup - remove calls to deprecated function Tcl_DStringTrunc - prefer boolean expressions to avoid signed conversions - add default statement to switch to ease life of static checkers 2017-09-06 Gustaf Neumann Add Valgrind/callgrind support Improve performance of ObjectSystemsCheckSystemMethod() by over 20% 2017-09-04 Gustaf Neumann Optimization for aliases Optimized AliasAdd() and AliasGet() by avoiding the usage of Tcl_SetVar2Ex() and Tcl_GetVar2Ex(). This change improves the performance of AliasAdd() by ~20% and AliasGet() by 10%. Strangely, Tcl does not provide an interface to the Tcl_Obj-based TclObjUnsetVar2(), which is used internally by Tcl_UnsetVar2()), such we could also avoid the latter. minor cleanup and optimizations Avoid call of strncmp() in common cases 2017-08-31 Gustaf Neumann Various Performance Improvements: - Add cache for compiled locals starting with a colon to avoid repeated linear searches - Reduce number of string comparisons in ParamOptionParse() - Factor out ProcContextRequire() - Extend regression test 2017-08-21 Gustaf Neumann Minor cleanup Remove first argument of MethodDispatch, which is apparently not needed Avoid mixed declarations and code Added experimental definition of NSF_CONSTANT_COMPILED_LOCAL_LOOKUP 2017-08-20 Stefan Sobernig * nsf.c (FindNextMethod): Provide revised, streamlined implementation of FindSelfNext as FindNextMethod. FindSelfNext is maintained, but unused for the time being. 2017-08-20 Gustaf Neumann Cleanup and Optimization - align code with documentation - remove dead code - minor optimization White space changes Reduce number of returns before end of function Whitespace changes, typos more macro definition after GNU definitions Remove redundant definition Remove dead assignment Add more tidy and checking compiler flags 2017-08-20 Stefan Sobernig * nsf.c (NsfCurrentCmd), nsfStack.c (CallStackNextFrameOfType): Render [current isnextcall] aware of ensembles. Extended submethods.test to cover [current isnextcall] within ensembles. 2017-08-18 Stefan Sobernig nsf.c (FindSelfNext): Render [current nextmethod] aware of ensembles. Added basic tests. 2017-08-15 Gustaf Neumann White-space changes 2017-08-09 Stefan Sobernig submethods.test: Clean up ensembles on top-level objects. 2017-08-09 Stefan Sobernig nx-test.tcl (nx::test case): As (ensemble) methods are currently not covered by the auto-cleanup feature of "nx::test case", I took care of not cleaning up the per-class ensemble slots while the alias is still available. This led to dangling aliases in cases such as: package req nx::test nx::Class create ::A nx::test case tmp { ::A public method "oo ps" {} {;}; # creates ::A::slot::__oo plus alias pointing to it. } A create a oo ps; # "target "::A::slot::__oo" of alias oo apparently disappeared" Along the way, modernized nx::test case a little (apply). 2017-08-09 Stefan Sobernig * nsf.c (GetNextArguments): Ensemble method names via the colon resolver were not cleansed for the colon, leading to a broken method lookup chain. Fix for SF Ticket #1. Added basic tests. 2017-08-07 Gustaf Neumann fix: remove failing assertion, Tcl handles leading colons in proc names 2017-06-18 Stefan Sobernig * nsf.c, forward.test (ForwardArg): Extend to recognize alternative element separators in list string reps (NsfHasTclSpace). * nsf.c, nsf-cmd.test (ObjectFindMethod): Extend to recognize all element separator chars (NsfHasTclSpace). * nsf.c, parameters.test (NsfMethodSetterCmd): Make list detection aware of all list separator chars (NsfHasTclSpace). * nsf.c, parameters.test (NsfOResidualargsMethod): Extend XOTcl's list-notation support to recognize all Tcl list separators (NsfHasTclSpace). 2017-06-14 Stefan Sobernig * nsf.c, nsfInt.h: Start housekeeping work on Tcl command/proc names vs. NSF method names to avoid conflicts between ensemle methods and e.g. whitespace-containing command names. Added helper macro NsfHasTclSpace and some first tests. To be continued. 2017-06-03 Gustaf Neumann Reduce variable scope 2017-05-31 Stefan Sobernig * nsf.c (NsfMethodPropertyCmd,NsfForwardPropertyCmd): Remove extra whitespace from error message. 2017-05-29 Stefan Sobernig * methods.test: Add basic tests on composite names under the default unknown handler. * nsf.c (DispatchUnknownMethod): Sanitize messages emitted by default unknown handler. Unless in the context of an ensemble object (NSF_KEEP_CALLER_SELF, NSF_PER_OBJECT_DISPATCH), make sure that the entire method name, incl. multi-word names, are fully reported. 2017-05-28 Gustaf Neumann Simplify code - Don't assume that CallStackGetTopFrame0() reurns != NULL - reduce variable scopes - reduce number of returns before function end 2017-04-29 Gustaf Neumann Make sure, paramPtr is always initialized 2017-04-22 Gustaf Neumann - Use more straightforward Tcl idiom to access first character of a string - Standardize spelling of names of products (Tcl, AOLserver, PostgreSQL) Use uniform spelling of "Tcl" Whitespace change: strip trailing spaces - Use uniform spelling of "Tcl" - Fix more spelling errors Use uniform spelling of "Tcl" 2017-04-21 Gustaf Neumann Improve spelling - provide means to debug invalid coding in Tcl_Objs 2017-03-03 Stefan Sobernig Fix wording in TODO Leave some TODOs to think about * nx.tcl (VariableSlot): Fix value=delete to actually accept and implement "-nocomplain". Added tests (missing so far entirely) and updated the man pages accordingly. 2017-03-03 Gustaf Neumann extend tutorial description 2017-03-02 Stefan Sobernig * nx.tcl, parameters.test (defineIncrementalOperations): Make sure value=add and value=delete actually run value checkers and, in case of "convert", pick up the conversion result. Added basic test. 2017-03-01 Stefan Sobernig * nsf.c (ArgumentCheck): Set parentheses correctly. * nx.tcl (makeIncrementalOperations, defineIncrementalOperations): Avoid repeated slot= entries in options. Fix a typo. * nsf.c (ArgumentCheck): Avoid double dispatching to value checkers (built-in and type=*) for "slotset" parameters. Previously, configure and then the value=set (value=add) method triggered one dispatch each. Now, the configure pass skips the check and shifts sole responsibility on the value=set/ value=add methods. Added basic test cases to parameters.test to capture the intended call semantics. 2017-03-01 Gustaf Neumann add properties tutorial to test set Add hands-on tutorial for properties - extend test case (since people use this as example) 2017-02-28 Gustaf Neumann Fix potential bug in forwarder code (it was possible, that a substituted %proc was freed too early) 2017-02-20 Stefan Sobernig Regenerated migration and tutorial, to account for recently fixed typos and fix markup generation * Makefile.in: Unify ASCIIDOC exec configuration. 2017-02-20 Gustaf Neumann adjust programming style Add test for regular expression matching Make sure to initialize nsf object fetched from mongo 2017-02-14 Gustaf Neumann - Use more modern returnstate handling based on options - extend regression test 2017-02-14 Stefan Sobernig * next-migration.txt: Address some typos (thx to Guenter Ernst for reporting). * contains.test: Add two test cases to document the recent fix on error and errorcode propagation in contains. 2017-02-14 Gustaf Neumann fix bug in method "contains": Propergate errorCode on catch 2017-01-18 Gustaf Neumann mongodb interface - add regular expression queries to conditions in NX 2017-01-18 Stefan Sobernig * makefile.vc: Change another directory location to respect the INSTALLDIR setting 2017-01-18 Gustaf Neumann - Copy changed structure - Don't't use ConvertToNothing but NULL in the terminating record, since the former is not available for extensions 2017-01-18 Stefan Sobernig * makefile.vc: Add missing header fils to install target and use STUBDIR to properly locate the generated API headers. 2017-01-14 Gustaf Neumann - include all enum values in case statements - use preprocessor variables more consistently - remove old-style function definitions - remove implicit conversion to 'unsigned int' from 'int' m - ISO C90 forbids mixed declarations and code - don't shadow local variable Reduce memory consumption via better aligning (esp on 64bit machines) 2017-01-13 Gustaf Neumann - don't shadow variables modify STRING_NEW such that - it is able to produce "const char *" - such that it uses ckalloc - provide clean compile for compilations with "-Wwrite-strings" - add const declarations - removed unneeded arguments - mark unused arguments as UNUSED 2017-01-13 Stefan Sobernig * nx-pp.tcl (State): Add "substdefault" to two property specs to fix markup generation for various token types (variables etc.). 2017-01-11 Stefan Sobernig * source-doc-beautifier.tcl: Allow to omit the built-in title line, to allow for custom doc and title preambles in example scripts ("-notile" flag). 2017-01-06 Gustaf Neumann - added a new configure option --enable-development=test (in addition to --enable-development or --disable-development) for activating more expensive runtime tests. --enable-development alone activates just assertion checking ./nsf2.4.0/valgrind.out000644 000766 000024 00000012232 14053235772 015537 0ustar00neumannstaff000000 000000 ==98378== Callgrind, a call-graph generating cache profiler ==98378== Copyright (C) 2002-2017, and GNU GPL'd, by Josef Weidendorfer et al. ==98378== Using Valgrind-3.17.0.GIT-lbmacos and LibVEX; rerun with -h for copyright info ==98378== Command: /usr/local/ns/bin/tclsh8.6 ./library/lib/mkIndex.tcl -dir ./library ==98378== ==98378== For interactive control, run 'callgrind_control -h'. --98378-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option --98378-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 2 times) UNKNOWN workq_ops option 1024 --98378-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 4 times) --98378-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 8 times) --98378-- WARNING: unhandled amd64-darwin syscall: unix:228 --98378-- You may be able to write your own handler. --98378-- Read the file README_MISSING_SYSCALL_OR_IOCTL. --98378-- Nevertheless we consider this a bug. Please report --98378-- it at http://valgrind.org/support/bug_reports.html. ==98378== ==98378== Process terminating with default action of signal 11 (SIGSEGV) ==98378== Access not within mapped region at address 0x20 ==98378== at 0x7FFF2056EEF4: ??? (in /dev/ttys000) ==98378== by 0x7FFF20706479: ??? (in /dev/ttys000) ==98378== by 0x7FFF20705492: ??? (in /dev/ttys000) ==98378== If you believe this happened as a result of a stack ==98378== overflow in your program's main thread (unlikely but ==98378== possible), you can try to increase the size of the ==98378== main thread stack using the --main-stacksize= flag. ==98378== The main thread stack size used in this run was 67104768. ==98378== ==98378== Events : Ir ==98378== Collected : 11420246 ==98378== ==98378== I refs: 11,420,246 ==98759== Callgrind, a call-graph generating cache profiler ==98759== Copyright (C) 2002-2017, and GNU GPL'd, by Josef Weidendorfer et al. ==98759== Using Valgrind-3.17.0.GIT-lbmacos and LibVEX; rerun with -h for copyright info ==98759== Command: /usr/local/ns/bin/tclsh8.6 ./library/lib/mkIndex.tcl -dir ./library ==98759== ==98759== For interactive control, run 'callgrind_control -h'. --98759-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option --98759-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 2 times) UNKNOWN workq_ops option 1024 --98759-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 4 times) --98759-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 8 times) --98759-- WARNING: unhandled amd64-darwin syscall: unix:228 --98759-- You may be able to write your own handler. --98759-- Read the file README_MISSING_SYSCALL_OR_IOCTL. --98759-- Nevertheless we consider this a bug. Please report --98759-- it at http://valgrind.org/support/bug_reports.html. ==98759== ==98759== Process terminating with default action of signal 11 (SIGSEGV) ==98759== Access not within mapped region at address 0x20 ==98759== at 0x7FFF2056EEF4: ??? (in /dev/ttys000) ==98759== by 0x7FFF20706479: ??? (in /dev/ttys000) ==98759== by 0x7FFF20705492: ??? (in /dev/ttys000) ==98759== If you believe this happened as a result of a stack ==98759== overflow in your program's main thread (unlikely but ==98759== possible), you can try to increase the size of the ==98759== main thread stack using the --main-stacksize= flag. ==98759== The main thread stack size used in this run was 67104768. ==98759== ==98759== Events : Ir ==98759== Collected : 11421262 ==98759== ==98759== I refs: 11,421,262 ==69187== Callgrind, a call-graph generating cache profiler ==69187== Copyright (C) 2002-2017, and GNU GPL'd, by Josef Weidendorfer et al. ==69187== Using Valgrind-3.17.0.GIT-lbmacos and LibVEX; rerun with -h for copyright info ==69187== Command: /usr/local/ns/bin/tclsh8.6 ./library/lib/mkIndex.tcl -dir ./library ==69187== ==69187== For interactive control, run 'callgrind_control -h'. --69187-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option --69187-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 2 times) UNKNOWN workq_ops option 1024 --69187-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 4 times) --69187-- UNKNOWN mach_msg unhandled MACH_SEND_TRAILER option (repeated 8 times) --69187-- WARNING: unhandled amd64-darwin syscall: unix:228 --69187-- You may be able to write your own handler. --69187-- Read the file README_MISSING_SYSCALL_OR_IOCTL. --69187-- Nevertheless we consider this a bug. Please report --69187-- it at http://valgrind.org/support/bug_reports.html. ==69187== ==69187== Process terminating with default action of signal 11 (SIGSEGV) ==69187== Access not within mapped region at address 0x20 ==69187== at 0x7FFF2056EEF4: ??? (in /dev/ttys000) ==69187== by 0x7FFF20706479: ??? (in /dev/ttys000) ==69187== by 0x7FFF20705492: ??? (in /dev/ttys000) ==69187== If you believe this happened as a result of a stack ==69187== overflow in your program's main thread (unlikely but ==69187== possible), you can try to increase the size of the ==69187== main thread stack using the --main-stacksize= flag. ==69187== The main thread stack size used in this run was 67104768. ==69187== ==69187== Events : Ir ==69187== Collected : 11419433 ==69187== ==69187== I refs: 11,419,433 ./nsf2.4.0/library/serialize/pkgIndex.tcl000644 000766 000024 00000000203 14276141440 021076 0ustar00neumannstaff000000 000000 package ifneeded nx::serializer 2.4.0 "[list source [file join $dir serializer.tcl]]; [list package provide nx::serializer 2.4.0]" ./nsf2.4.0/library/serialize/COPYRIGHT000644 000766 000024 00000005046 13322637370 020131 0ustar00neumannstaff000000 000000 /* * Next Scripting Framework * * Copyright (C) 1999-2018 Gustaf Neumann (a) (b) * Copyright (C) 1999-2007 Uwe Zdun (a) (b) * Copyright (C) 2007-2008 Martin Matuska (b) * Copyright (C) 2010-2014 Stefan Sobernig (b) * * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License * http://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * * This software is based upon MIT Object Tcl by David Wetherall and * Christopher J. Lindblad, that contains the following copyright * message: * * "Copyright 1993 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this * software and its documentation for any purpose is hereby granted * without fee, provided that the above copyright notice appear in * all copies and that both that copyright notice and this * permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity * pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about * the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty." */ ./nsf2.4.0/library/serialize/serializer.tcl000644 000766 000024 00000125657 14175065734 021534 0ustar00neumannstaff000000 000000 package require nx package require XOTcl 2.4 package provide nx::serializer 2.4.0 # For the time being, we require classical XOTcl. # TODO: separate into two packages (i.e. make one XOTcl specific # serializer package, and (a) load this package on a load of this # package (when ::xotcl::Object is defined), and (b) load it from # "xotcl*.tcl", when the serializer is alreaded loaded (e.g. via nx). namespace eval ::nx::serializer { namespace eval ::xotcl {} ;# just to make mk_pkgIndex happy namespace import -force ::xotcl::* ;# just needed for the time being for @ namespace import -force ::nx::* @ @File { description { This package provides the class Serializer, which can be used to generate a snapshot of the current state of the workspace in the form of XOTcl source code. } authors { Gustaf Neumann, Gustaf.Neumann@wu-wien.ac.at } } @ Serializer proc all { ?-ignoreVarsRE RE? "provide regular expression; matching vars are ignored" ?-ignore obj1 obj2 ...? "provide a list of objects to be omitted"} { Description { Serialize all objects and classes that are currently defined (except the specified omissions and the current Serializer object).

Examples:<@br> <@pre class='code'>Serializer all -ignoreVarsRE {::b$} Do not serialize any instance variable named b (of any object).

<@pre class='code'>Serializer all -ignoreVarsRE {^::o1::.*text.*$|^::o2::x$} Do not serialize any variable of c1 whose name contains the string "text" and do not serialze the variable x of o2.

<@pre class='code'>Serializer all -ignore obj1 obj2 ... do not serizalze the specified objects } return "script" } @ Serializer proc deepSerialize { ?-ignoreVarsRE RE? "provide regular expression; matching vars are ignored" ?-ignore obj1 obj2 ...? "provide a list of objects to be omitted" ?-map list? "translate object names in serialized code" objs "Objects to be serialized" } { Description { Serialize object with all child objects (deep operation) except the specified omissions. For the description of <@tt>ignore and <@tt>ignoreVarsRE see <@tt>Serizalizer all. <@tt>map can be used in addition to provide pairs of old-string and new-string (like in the Tcl command <@tt>string map). This option can be used to regenerate the serialized object under a different object or under a different name, or to translate relative object names in the serialized code.

Examples: <@pre class='code'>Serializer deepSerialize -map {::a::b ::x::y} ::a::b::c Serialize the object <@tt>c which is a child of <@tt>a::b; the object will be reinitialized as object <@tt>::x::y::c, all references <@tt>::a::b will be replaced by <@tt>::x::y.

<@pre class='code'>Serializer deepSerialize -map {::a::b [self]} ::a::b::c The serizalized object can be reinstantiated under some current object, under which the script is evaluated.

<@pre class='code'>Serializer deepSerialize -map {::a::b::c ${var} ::a::b::c} The serizalized object will be reinstantiated under a name specified by the variable <@tt>var<@tt> in the recreation context. } return "script" } @ Serializer proc methodSerialize { object "object or class" method "name of method" prefix "either empty or 'inst' (latter for instprocs)" } { Description { Serialize the specified method. In order to serialize an instproc, <@tt>prefix should be 'inst'; to serialze procs, it should be empty.

Examples: <@pre class='code'>Serializer methodSerialize Serializer deepSerialize "" This command serializes the proc <@tt>deepSerialize of the Class <@tt>Serializer.

<@pre class='code'>Serializer methodSerialize Serializer serialize inst This command serializes the instproc <@tt>serialize of the Class <@tt>Serializer.

} return {Script, which can be used to recreate the specified method} } @ Serializer proc exportMethods { list "list of methods of the form 'object proc|instproc methodname'" } { Description { This method can be used to specify methods that should be exported in every <@tt>Serializer all<@/tt>. The rationale behind this is that the serializer does not serialize objects from the namespaces of the basic object systems, which are used for the object system internals and volatile objects. TODO It is however often useful to define methods on ::xotcl::Class or ::xotcl::Objects, which should be exported. One can export procs, instprocs, forward and instforward

Example: <@pre class='code'> Serializer exportMethods { ::xotcl::Object instproc __split_arguments ::xotcl::Object instproc __make_doc ::xotcl::Object instproc ad_proc ::xotcl::Class instproc ad_instproc ::xotcl::Object forward expr }<@/pre> } } @ Serializer instproc serialize {entity "Object or Class"} { Description { Serialize the specified object or class. } return {Object or Class with all currently defined methods, variables, invariants, filters and mixins} } ########################################################################### # Serializer Class, independent from Object System ########################################################################### Class create Serializer { :property -accessor public ignoreVarsRE :public method ignore args { # Ignore the objects passed via args. # :skip is used for filtering only in the topological sort. foreach element $args { foreach o [Serializer allChildren $element] { set :skip($o) 1 } } } :public method objmap {map} { array set :objmap $map } :method init {} { # Never serialize the (volatile) serializer object :ignore [::nsf::current object] } :method warn msg { if {[info command ns_log] ne ""} { ns_log Warning "serializer: $msg" } else { puts stderr "Warning: serializer: $msg" } } :public method addPostCmd {cmd} { if {$cmd ne ""} {append :post_cmds $cmd "\n"} } :public method setObjectSystemSerializer {o serializer} { #puts stderr "set :serializer($o) $serializer" set :serializer($o) $serializer } :public method isExportedObject {o} { # Check, whether o is exported. For exported objects. # we export the object tree. set oo $o while {1} { if {[::nsf::var::exists [::nsf::current class] exportObjects($o)]} { return 1 } # we do this for object trees without object-less namespaces if {![::nsf::object::exists $o]} { return 0 } set o [::nsf::dispatch $o ::nsf::methods::object::info::parent] } } :public method getTargetName {sourceName} { # TODO: make more efficient; if {![string match ::* $sourceName]} { set sourceName ::$sourceName } set targetName $sourceName if {[array exists :objmap]} { foreach {source target} [array get :objmap] { #puts "[list regsub ^$source $targetName $target targetName]" regsub ^$source $targetName $target targetName } } #puts stderr "targetName of <$sourceName> = <$targetName>" return $targetName } :method topoSort {set all} { if {[array exists :s]} {array unset :s} if {[array exists :level]} {array unset :level} # TODO generalize? set ns_excluded(::ns) 1 foreach c $set { set ns [namespace qualifiers $c] if {!$all && [info exists ns_excluded($ns)] && ![:isExportedObject $c]} continue if {[info exists :skip($c)]} continue set :s($c) 1 } set stratum 0 while {1} { set set [array names :s] if {[llength $set] == 0} break incr stratum # :warn "$stratum set=$set" set :level($stratum) {} foreach c $set { set oss [set :serializer($c)] if {[$oss needsNothing $c [::nsf::current object]]} { lappend :level($stratum) $c } else { #puts stderr "$c needs something from $set" } } if {[set :level($stratum)] eq ""} { set :level($stratum) $set :warn "Cyclic dependency in $set" } foreach i [set :level($stratum)] {unset :s($i)} } } :public method needsOneOf list { foreach e $list {if {[info exists :s($e)]} {return 1}} return 0 } :public method serialize-objects {list all} { set :post_cmds "" :topoSort $list $all #foreach i [lsort [array names :level]] { :warn "$i: [set :level($i)]"} set result "" foreach l [lsort -integer [array names :level]] { foreach i [set :level($l)] { #:warn "serialize $i" #append result "# Stratum $l\n" set oss [set :serializer($i)] append result [$oss serialize $i [::nsf::current object]] \n } } foreach e $list { set namespace($e) 1 set namespace([namespace qualifiers $e]) 1 } # Handling of variable traces: traces might require a # different topological sort, which is hard to handle. # Similar as with filters, we deactivate the variable # traces during initialization. This happens by # (1) replacing the next's trace method by a no-op # (2) collecting variable traces through collect-var-traces # (3) re-activating the traces after variable initialization set exports "" set pre_cmds "" # delete ::ns from the namespace list, if it exists... catch {unset namespace(::ns)} foreach ns [array name namespace] { if {![namespace exists $ns]} continue if {![::nsf::object::exists $ns]} { append pre_cmds "namespace eval $ns {}\n" } elseif {$ns ne [namespace origin $ns] } { append pre_cmds "namespace eval $ns {}\n" } set exp [namespace eval $ns {::namespace export}] if {$exp ne ""} { append exports "namespace eval $ns {::namespace export $exp}" \n } } return $pre_cmds$result${:post_cmds}$exports } :public method deepSerialize {o} { # assumes $o to be fully qualified set instances [Serializer allChildren $o] foreach oss [ObjectSystemSerializer info instances] { $oss registerSerializer [::nsf::current object] $instances } :serialize-objects $instances 1 } ############################### # class object specific methods ############################### :public object method allChildren o { # return o and all its children fully qualified set set [::nsf::directdispatch $o -frame method ::nsf::current] foreach c [::nsf::directdispatch $o ::nsf::methods::object::info::children] { lappend set {*}[:allChildren $c] } return $set } :public object method exportMethods list { foreach {o p m} $list {set :exportMethods([list $o $p $m]) 1} } :public object method exportObjects list { foreach o $list {set :exportObjects($o) 1} } :public object method exportedMethods {} {array names :exportMethods} :public object method exportedObjects {} {array names :exportObjects} :public object method resetPattern {} {array unset :ignorePattern} :public object method addPattern {p} {set :ignorePattern($p) 1} :object method checkExportedMethods {} { foreach k [array names :exportMethods] { lassign $k o p m set ok 0 foreach p [array names :ignorePattern] { if {[string match $p $o]} { set ok 1; break } } if {!$ok} { error "method export is only for classes in\ [join [array names :ignorePattern] {, }] not for $o" } } } :object method checkExportedObject {} { foreach o [array names :exportObjects] { if {![::nsf::object::exists $o]} { :warn "Serializer exportObject: ignore non-existing object $o" unset :exportObjects($o) } else { # add all child objects foreach o [:allChildren $element] { set :exportObjects($o) 1 } } } } :public object method all {-ignoreVarsRE -ignore} { # # Remove objects which should not be included in the # blueprint. TODO: this is not the best place to do this, since # this the function is defined by OpenACS catch ::xo::at_cleanup # don't filter anything during serialization set filterstate [::nsf::configure filter off] set s [:new -childof [::nsf::current object]] if {[info exists ignoreVarsRE]} {$s ignoreVarsRE set $ignoreVarsRE} if {[info exists ignore]} {$s ignore $ignore} set r [subst { set ::nsf::__filterstate \[::nsf::configure filter off\] #::nx::Slot mixin add ::nx::Slot::Nocheck ::nsf::exithandler set [list [::nsf::exithandler get]] }] foreach option {debug softrecreate keepcmds checkresults checkarguments} { append r \t [list ::nsf::configure $option [::nsf::configure $option]] \n } :resetPattern # # export all nsf_procs # append r [:export_nsfprocs ::] # # export objects and classes # set instances [list] foreach oss [ObjectSystemSerializer info instances] { append r [$oss serialize-all-start $s] lappend instances {*}[$oss instances $s] } # provide error messages for invalid exports :checkExportedMethods # export the objects and classes #$s warn "export objects = [array names :exportObjects]" #$s warn "export objects = [array names :exportMethods]" append r [$s serialize-objects $instances 0] foreach oss [ObjectSystemSerializer info instances] { append r [$oss serialize-all-end $s] } $s destroy append r { #::nx::Slot mixin delete ::nx::Slot::Nocheck ::nsf::configure filter $::nsf::__filterstate unset ::nsf::__filterstate } ::nsf::configure filter $filterstate return $r } :public object method finalize_application_classes {oss} { # # Delete all the application objects and classes from the # specified object system. # set objs [$oss list_instances] #puts stderr "///// we have [llength $objs] $objs" #set objs [$Object info instances -closure] # # Delete first object but no classes, such that the destroy # methods can be executed in most cases. # foreach o $objs { if {![nsf::is object $o] || [nsf::is class $o]} { continue } catch {rename $o ""} errorMsg } # # Delete the surving classes. # set objs [$oss list_instances] #puts stderr "///// we have [llength $objs] $objs" foreach o $objs { set ns [namespace qualifiers $o] #puts stderr "DELETE class $o ns <$ns>" if {![nsf::is class $o] || [nsf::is metaclass $o] } { continue } catch {rename $o ""} errorMsg } # # Delete the metaclasses at the end. # set objs [$oss list_instances] #puts stderr "///// we have [llength $objs] $objs" foreach o $objs { set ns [namespace qualifiers $o] #puts stderr "DELETE class $o ns <$ns>" if {![nsf::is metaclass $o]} { continue } catch {rename $o ""} errorMsg } } :object method add_child_namespaces {ns} { if {$ns eq "::nsf"} return lappend :namespaces $ns foreach n [namespace children $ns] { :add_child_namespaces $n } } :public object method application_namespaces {ns} { set :namespaces "" :add_child_namespaces $ns return ${:namespaces} } :public object method export_nsfprocs {ns} { set result "" foreach n [:application_namespaces $ns] { foreach p [:info methods -type nsfproc ${n}::*] { append result [::nsf::cmd::info definition $p] \n } } return $result } :public object method methodSerialize {object method prefix} { foreach oss [ObjectSystemSerializer info instances] { if {[$oss responsibleSerializer $object]} { set result [$oss serializeExportedMethod $object $prefix $method [self]] break } } return $result } :public object method deepSerialize {-ignoreVarsRE -ignore -map -objmap args} { :resetPattern set s [:new -childof [::nsf::current object]] if {[info exists ignoreVarsRE]} {$s ignoreVarsRE set $ignoreVarsRE} if {[info exists ignore]} {$s ignore $ignore} if {[info exists objmap]} {$s objmap $objmap} foreach o $args { append r [$s deepSerialize [::nsf::directdispatch $o -frame method ::nsf::current]] } $s destroy if {[info exists map]} {return [string map $map $r]} return $r } # include Serializer in the serialized code :exportObjects [::nsf::current object] } ########################################################################### # Object System specific serializer ########################################################################### Class create ObjectSystemSerializer { :method init {} { # Include object system serializers and the meta-class in "Serializer all" Serializer exportObjects [::nsf::current class] Serializer exportObjects [::nsf::current object] } # reuse warn here as well :alias warn [Serializer info method registrationhandle warn] # # Methods to be executed at the begin and end of serialize all # :public method serialize-all-start {s} { :getExported return [:serializeExportedMethods $s] } :public method serialize-all-end {s} { set cmd "" foreach o [list ${:rootClass} ${:rootMetaClass}] { append cmd \ [:frameWorkCmd ::nsf::relation::get $o object-mixin] \ [:frameWorkCmd ::nsf::relation::get $o class-mixin] \ [:frameWorkCmd ::nsf::method::assertion $o object-invar] \ [:frameWorkCmd ::nsf::method::assertion $o class-invar] } #puts stderr "*** array unset [nsf::current object] alias_dependency // size [array size :alias_dependency]" array unset :alias_dependency return $cmd } # # Handle association between objects and responsible serializers # :public method responsibleSerializer {object} { return [::nsf::dispatch $object ::nsf::methods::object::info::hastype ${:rootClass}] } :public method registerSerializer {s instances} { # Communicate responsibility to serializer object $s foreach i $instances { if {![::nsf::dispatch $i ::nsf::methods::object::info::hastype ${:rootClass}]} continue $s setObjectSystemSerializer $i [::nsf::current object] } } :public method instances {s} { # # Compute all instances, for which we are responsible and # notify serializer object $s. # set instances [list] foreach i [${:rootClass} info instances -closure] { if {[:matchesIgnorePattern $i] && ![$s isExportedObject $i]} { continue } $s setObjectSystemSerializer $i [::nsf::current object] lappend instances $i } #:warn "[::nsf::current object] handles instances: $instances" return $instances } :public method list_instances {} { # # Compute all instances, for which we are responsible, just # ignoring content matching the matchpatterns # set instances [list] foreach i [${:rootClass} info instances -closure] { if {[:matchesIgnorePattern $i]} { continue } lappend instances $i } #:warn "[::nsf::current object] handles instances: $instances" return $instances } :public method getExported {} { # # get exported objects and methods from main Serializer for # which this object specific serializer is responsible # foreach k [Serializer exportedMethods] { lassign $k o p m if {![::nsf::object::exists $o]} { :warn "$o is not an object" } elseif {[::nsf::dispatch $o ::nsf::methods::object::info::hastype ${:rootClass}]} { set :exportMethods($k) 1 } } foreach o [Serializer exportedObjects] { if {![::nsf::object::exists $o]} { :warn "$o is not an object" } elseif {[nsf::dispatch $o ::nsf::methods::object::info::hastype ${:rootClass}]} { set :exportObjects($o) 1 } } foreach p [array names :ignorePattern] {Serializer addPattern $p} } ############################### # general method serialization ############################### :method classify {o} { if {[::nsf::dispatch $o ::nsf::methods::object::info::hastype ${:rootMetaClass}]} \ {return Class} {return Object} } :method collectVars {{-serializeSlot:boolean false} o s} { set setcmd [list] foreach v [lsort [$o info vars]] { if {![::nsf::var::exists $s ignoreVarsRE] || [::nsf::var::set $s ignoreVarsRE] eq "" || ![regexp [::nsf::var::set $s ignoreVarsRE] ${o}::$v]} { if {[::nsf::var::exists $o $v] == 0} { puts stderr "strange, [list $o info vars] returned $v, but it does not seem to exist" continue } if {[::nsf::var::exists -array $o $v]} { lappend setcmd [list array set :$v [::nsf::var::set -array $o $v]] } else { set value [::nsf::var::set $o $v] if {$serializeSlot && $v in {domain manager}} { # map the values for these variables in the slot set value [$s getTargetName $value] } lappend setcmd [list set :$v $value] } } } return $setcmd } :method frameWorkCmd {cmd o relation -unless} { set v [$cmd $o $relation] if {$v eq ""} {return ""} if {[info exists unless] && $v eq $unless} {return ""} regsub -all {::get$} $cmd ::set cmd return [list $cmd ${:targetName} $relation $v]\n } :method extraMethodProperties {o perObject m} { # # Preserve special method properties like "debug" and # "deprecated" for arbitrary kind of methods via # "nsf::method::property" calls. # set extra "" if {[::nsf::method::property $o {*}$perObject $m exists]} { if {[::nsf::method::property $o {*}$perObject $m debug]} { append extra "\n::nsf::method::property [list ${:targetName}] $perObject $m debug true" } if {[::nsf::method::property $o {*}$perObject $m deprecated]} { append extra "\n::nsf::method::property [list ${:targetName}] $perObject $m deprecated true" } } else { nsf::log warning "method <$o> <$perObject> <$m> does not exist" #catch {nsf::__db_show_stack} } return $extra } :method serializeExportedMethods {s} { set r "" foreach k [array names :exportMethods] { lassign $k o p m if {![:methodExists $o $p $m]} { :warn "Method does not exist: $o $p $m" continue } set :targetName [$s getTargetName $o] append methods($o) [:serializeExportedMethod $o $p $m $s]\n } foreach o [array names methods] {set ($o) 1} foreach o [list ${:rootClass} ${:rootMetaClass}] { if {[info exists ($o)]} {unset ($o)} } foreach o [concat ${:rootClass} ${:rootMetaClass} [array names ""]] { if {![info exists methods($o)]} continue append r \n $methods($o) } #puts stderr "[::nsf::current object] ... exportedMethods <$r\n>" return "$r\n" } ############################### # general object serialization ############################### :public method serialize {objectOrClass s} { set :targetName [$s getTargetName $objectOrClass] :[:classify $objectOrClass]-serialize $objectOrClass $s } :method matchesIgnorePattern {o} { foreach p [array names :ignorePattern] { if {[string match $p $o]} {return 1} } return 0 } :method collect-var-traces {o s} { set traces {} foreach v [$o info vars] { # Use directdispatch to query existing traces without the need # of an extra method. set t [::nsf::directdispatch $o -frame object ::trace info variable $v] if {$t ne ""} { foreach ops $t { lassign $ops op cmd # save traces in post_cmds set traceCmd [list ::nsf::directdispatch $o -frame object ::trace add variable $v $op $cmd] $s addPostCmd $traceCmd append traces $traceCmd \n # remove trace from object ::nsf::directdispatch $o -frame object ::trace remove variable $v $op $cmd } } } return $traces } ############################### # general dependency handling ############################### :public method needsNothing {x s} { return [:[:classify $x]-needsNothing $x $s] } :method alias-dependency {x where} { set handle :alias_dependency($x,$where) if {[info exists $handle]} { return [set $handle] } set needed [list] foreach alias [$x ::nsf::methods::${where}::info::methods -type alias -callprotection all -path] { set definition [$x ::nsf::methods::${where}::info::method definition $alias] set aliasedCmd [lindex $definition end] # # The aliasedCmd is fully qualified and could be a method # handle or a primitive cmd. For a primitive cmd, we have no # alias dependency. If the cmd is registered on an object, we # report the dependency. # set regObj [::nsf::method::registered $aliasedCmd] if {$regObj ne ""} { if {$regObj eq $x} { :warn "Dependency for alias $alias from $x to $x not handled (no guarantee on method order)" } else { lappend needed $regObj } } else { puts stderr "=== aliasedCmd $aliasedCmd has regObj <$regObj> x '$x' where '$where'" #lappend needed $x } } if {[llength $needed]>0} { puts stderr "aliases: $x needs $needed" puts stderr "set alias-deps for $x - $handle - $needed" } set $handle $needed return $needed } :method Class-needsNothing {x s} { if {![:Object-needsNothing $x $s]} {return 0} set scs [$x ::nsf::methods::class::info::superclass] if {[$s needsOneOf $scs]} {return 0} if {[$s needsOneOf [::nsf::relation::get $x class-mixin]]} {return 0} foreach sc $scs {if {[$s needsOneOf [$sc ::nsf::methods::class::info::slotobjects]]} {return 0}} if {[$s needsOneOf [:alias-dependency $x class]]} {return 0} return 1 } :method Object-needsNothing {x s} { set p [::nsf::directdispatch $x ::nsf::methods::object::info::parent] set cl [::nsf::directdispatch $x ::nsf::methods::object::info::class] if {$p ne "::" && [$s needsOneOf $p]} {return 0} if {[$s needsOneOf $cl]} {return 0} if {[$s needsOneOf [$cl ::nsf::methods::class::info::slotobjects -closure -source application]]} {return 0} if {[$s needsOneOf [:alias-dependency $x object]]} {return 0} return 1 } :method forward-serialize {o m s perObject} { if {$perObject ne ""} { set scope "object" } else { set scope "class" } set def [$o ::nsf::methods::${scope}::info::method definition $m] if {${:targetName} ne $o} { # # Handle targets of forwarders: when target object mapping # is activated, we might have to adapt the forwarding target # as well. This is in particular important for per-object # forwarders, which are used frequently in the slot objects # (but not necessarily only there). # set forwardTarget [nsf::method::forward::property $o {*}$perObject $m target] set mappedForwardTarget [$s getTargetName $forwardTarget] if {$forwardTarget ne $mappedForwardTarget} { nsf::method::forward::property $o {*}$perObject $m target $mappedForwardTarget set def [$o ::nsf::methods::${scope}::info::method definition $m] nsf::method::forward::property $o {*}$perObject $m target $forwardTarget } } return $def } } ########################################################################### # nx specific serializer ########################################################################### ObjectSystemSerializer create nx { set :rootClass ::nx::Object set :rootMetaClass ::nx::Class array set :ignorePattern [list "::nsf::*" 1 "::nx::*" 1 "::xotcl::*" 1] :public object method serialize-all-start {s} { # # Code to be executed at the begin of the serialization of nx. # # # The blueprint in OpenACS might be evaluated against either a # virgin interpreter (e.g. thread startup) or an existing # interpreter when the blueprint script was changed. In the # latter case, we have already in the current interpreter # predefined objects and classes. When objects are created at # run time and staying the connection threads, these object will # be turned into base class objects, when the classes are # deleted and newly defined. Therefore, we cleanup the interp in # a first step. Alternate approaches could be to handle these # cases before classes/metaclasses are define (per class), or to # define a callback via (ns_ictl update). # # Since this might be an issue happening in all kind of # interpreters, and this is mostly serializer specific, we # handle this here via "finalize_application_classes". # set intro [subst { if {\[info commands ::xotcl::Object\] ne "" && \[info command ::nx::serializer::Serializer\] ne "" } { ::nx::serializer::Serializer finalize_application_classes [self] } else { package require nx } }] append intro [subst { ::nx::configure defaultMethodCallProtection [::nx::configure defaultMethodCallProtection] ::nx::configure defaultAccessor [::nx::configure defaultAccessor] }] foreach pkg {nx::mongo} { if {![catch {package present $pkg}]} { append intro "package require $pkg\n" } } if {[info command ::Object] ne "" && [namespace origin ::Object] eq "::nx::Object"} { append intro "\n" "namespace import -force ::nx::*" } return "$intro\n[next]" } ############################### # nx method serialization ############################### :object method methodExists {object kind name} { expr {[$object info method type $name] ne ""} } :public object method serializeExportedMethod {object kind name s} { set :targetName $object switch $kind { "inst" - "method" { set modifier "" } "nsfproc" { return [::nsf::cmd::info definition $name] } default { set modifier "object" } } return [:method-serialize $object $name $modifier $s] } :object method method-serialize {o m modifier s} { if {![::nsf::is class $o]} {set modifier "object"} if {$modifier eq "object"} { set perObject "-per-object" set scope object } else { set perObject "" set scope class } set perObject [expr {$modifier eq "object" ? "-per-object" : ""}] set methodType [$o ::nsf::methods::${scope}::info::method type $m] set def [$o ::nsf::methods::${scope}::info::method definition $m] switch -exact -- $methodType { "object" { # object serialization is fully handled by the serializer return "# $def" } "setter" { return "" } "forward" { set def [:forward-serialize $o $m $s $perObject] } } if {${:targetName} ne $o} { set def [lreplace $def 0 0 ${:targetName}] } return $def[:extraMethodProperties $o $perObject $m] } ############################### # nx object serialization ############################### :object method Object-serialize {o s} { if {[$o ::nsf::methods::object::info::hastype ::nx::EnsembleObject]} { return "" } set traces [:collect-var-traces $o $s] set serializeSlot [$o info has type ::nx::Slot] set evalList [:collectVars -serializeSlot $serializeSlot $o $s] if {$serializeSlot} { # Slots need to be explicitly initialized to ensure # __invalidateobjectparameter to be called lappend evalList ": init" } set objectName [::nsf::directdispatch $o -frame method ::nsf::current object] set isSlotContainer [::nx::isSlotContainer $objectName] if {$isSlotContainer} { append cmd [list ::nx::slotObj -container [namespace tail $objectName] \ [$s getTargetName [$objectName ::nsf::methods::object::info::parent]]]\n if {[llength $evalList] > 0} { append cmd [list ${:targetName} eval [join $evalList "\n "]]\n } } else { #puts stderr "CREATE targetName '${:targetName}'" append cmd [list ::nsf::object::alloc [$o info class] ${:targetName} [join $evalList "\n "]]\n foreach i [lsort [$o ::nsf::methods::object::info::methods -callprotection all -path]] { append cmd [:method-serialize $o $i "object" $s] "\n" } } append cmd \ [:frameWorkCmd ::nsf::relation::get $o object-mixin] \ [:frameWorkCmd ::nsf::method::assertion $o object-invar] \ [:frameWorkCmd ::nsf::object::property $o keepcallerself -unless 0] \ [:frameWorkCmd ::nsf::object::property $o perobjectdispatch -unless 0] eval $traces $s addPostCmd [:frameWorkCmd ::nsf::relation::get $o object-filter] return $cmd } ############################### # nx class serialization ############################### :object method Class-serialize {o s} { set cmd [:Object-serialize $o $s] foreach i [lsort [$o ::nsf::methods::class::info::methods -callprotection all -path]] { append cmd [:method-serialize $o $i "" $s] "\n" } append cmd \ [:frameWorkCmd ::nsf::relation::get $o superclass -unless ${:rootClass}] \ [:frameWorkCmd ::nsf::relation::get $o class-mixin] \ [:frameWorkCmd ::nsf::method::assertion $o class-invar] $s addPostCmd [:frameWorkCmd ::nsf::relation::get $o class-filter] return $cmd\n } # register serialize a global method ::nx::Object public method serialize {-target} { set objmap [expr {[info exists target] ? [list [::nsf::current object] $target] : ""}] ::Serializer deepSerialize -objmap $objmap [::nsf::current object] } } ########################################################################### # XOTcl specific serializer ########################################################################### ObjectSystemSerializer create xotcl { set :rootClass ::xotcl::Object set :rootMetaClass ::xotcl::Class array set :ignorePattern [list "::nsf::*" 1 "::nx::*" 1 "::xotcl::*" 1] :public object method serialize-all-start {s} { set intro [subst { if {\[info commands ::xotcl::Object\] ne "" && \[info command ::nx::serializer::Serializer\] ne "" } { ::nx::serializer::Serializer finalize_application_classes [self] } else { package require XOTcl 2.0 } }] if {[info command ::Object] ne "" && [namespace origin ::Object] eq "::xotcl::Object"} { append intro "\nnamespace import -force ::xotcl::*" } return "$intro\n::xotcl::Object instproc trace args {}\n[next]" } :public object method serialize-all-end {s} { return "[next]\n::nsf::method::alias ::xotcl::Object trace -frame object ::trace\n" } ############################### # XOTcl method serialization ############################### :object method methodExists {object kind name} { switch $kind { proc - instproc { return [expr {[$object info ${kind}s $name] ne ""}] } forward - instforward { return [expr {[$object info ${kind} $name] ne ""}] } } } :public object method serializeExportedMethod {object kind name s} { set :targetName $object set code "" switch $kind { "" - inst { # legacy; kind is prefix set code [:method-serialize $object $name $kind $s]\n } proc - instproc { if {[$object info ${kind}s $name] ne ""} { set prefix [expr {$kind eq "proc" ? "" : "inst"}] set code [:method-serialize $object $name $prefix $s]\n } } forward - instforward { if {[$object info $kind $name] ne ""} { set code [concat [list $object] $kind $name [$object info $kind -definition $name]]\n } } } return $code } :object method method-serialize {o m prefix s} { if {![nsf::is class $o] || $prefix eq ""} { set scope object set perObject "-per-object" } else { set scope class set perObject "" } set methodType [$o ::nsf::methods::${scope}::info::method type $m] if {$methodType eq "forward"} { set def [:forward-serialize $o $m $s $perObject] if {$perObject eq ""} { regsub "(public|protected|private) forward" $def "instforward" def } else { regsub "(public|protected|private) object forward" $def "forward" def } } elseif {$methodType eq "alias"} { set def [$o ::nsf::methods::${scope}::info::method definition $m] if {$perObject eq ""} { regsub "^(.*) (public|protected|private) alias" $def {::nsf::method::alias \1} def } else { regsub "^(.*) (public|protected|private) object alias" $def {::nsf::method::alias \1 -per-object} def } } else { if {$perObject eq ""} { set returns [::nsf::method::property $o $m returns] } else { set returns [::nsf::method::property $o -per-object $m returns] } set arglist [$o ::nsf::methods::${scope}::info::method parameter $m] lappend def ${:targetName} ${prefix}proc $m \ $arglist \ {*}[expr {$returns ne "" ? [list -returns $returns] : {}}] \ [$o ::nsf::methods::${scope}::info::method body $m] foreach p {pre post} { set cond [$o ::nsf::methods::${scope}::info::method ${p}condition $m] if {$cond ne ""} { lappend def $cond } } } return $def[:extraMethodProperties $o $perObject $m] } ############################### # XOTcl object serialization ############################### :object method Object-serialize {o s} { set traces [:collect-var-traces $o $s] append cmd [list ::nsf::object::alloc [$o info class] ${:targetName} [join [:collectVars $o $s] "\n "]]\n foreach i [$o ::nsf::methods::object::info::methods -type scripted -callprotection all] { append cmd [:method-serialize $o $i "" $s] "\n" } foreach i [$o ::nsf::methods::object::info::methods -type forward -callprotection all] { append cmd [concat [list ${:targetName}] forward $i [$o info forward -definition $i]] "\n" } foreach i [$o ::nsf::methods::object::info::methods -type setter -callprotection all] { append cmd [list ${:targetName} parametercmd $i] "\n" } append cmd \ [:frameWorkCmd ::nsf::relation::get $o object-mixin] \ [:frameWorkCmd ::nsf::method::assertion $o object-invar] $s addPostCmd [:frameWorkCmd ::nsf::relation::get $o object-filter] eval $traces return $cmd } ############################### # XOTcl class serialization ############################### :object method Class-serialize {o s} { set cmd [:Object-serialize $o $s] foreach i [$o info instprocs] { append cmd [:method-serialize $o $i inst $s] "\n" } foreach i [$o info instforward] { append cmd [concat [list ${:targetName}] instforward $i [$o info instforward -definition $i]] "\n" } foreach i [$o info instparametercmd] { append cmd [list ${:targetName} instparametercmd $i] "\n" } # provide limited support for exporting aliases for XOTcl objects foreach i [$o ::nsf::methods::class::info::methods -type alias -callprotection all] { set nxDef [$o ::nsf::methods::class::info::method definition $i] append cmd [list ::nsf::method::alias ${:targetName} {*}[lrange $nxDef 3 end]]\n } append cmd \ [:frameWorkCmd ::nsf::relation::get $o superclass -unless ${:rootClass}] \ [:frameWorkCmd ::nsf::relation::get $o class-mixin] \ [:frameWorkCmd ::nsf::method::assertion $o class-invar] # # Check for overloaded accessors generated by the slots and make sure, these are # available in the serialized code. # set slotObjects [nsf::directdispatch $o ::nsf::methods::class::info::slotobjects -type ::nx::Slot] foreach so $slotObjects { set methodName [namespace tail $so] if {[$o info instprocs $methodName] ne ""} { # # The method was overloaded. # $s addPostCmd [:method-serialize $o $methodName inst $s] } } $s addPostCmd [:frameWorkCmd ::nsf::relation::get $o class-filter] return $cmd } # register serialize a global method for XOTcl ::xotcl::Object instproc serialize {-target} { set objmap [expr {[info exists target] ? [list [::nsf::current object] $target] : ""}] ::Serializer deepSerialize -objmap $objmap [::nsf::current object] } # include this method in the serialized code #Serializer exportMethods { # ::xotcl::Object instproc contains #} } namespace export Serializer namespace eval :: "::namespace import -force [namespace current]::*" } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/mongodb/nsfmongo.c.ast.sh000644 000766 000024 00000001004 13543460721 021452 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.a67844.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/library/mongodb/nsfmongo.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/library/mongodb/nsfmongo.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/library/mongodb/nsfmongo.c.ast.bdump./nsf2.4.0/library/mongodb/configure.ac000644 000766 000024 00000025753 13466507354 020600 0ustar00neumannstaff000000 000000 #!/bin/bash -norc dnl This file is an input file used by the GNU "autoconf" program to dnl generate the file "configure", which is run during Tcl installation dnl to configure the system for the local environment. # #----------------------------------------------------------------------- # Sample configure.in for Tcl Extensions. The only places you should # need to modify this file are marked by the string __CHANGE__ #----------------------------------------------------------------------- configdir=$(srcdir)/../../tclconfig #----------------------------------------------------------------------- # __CHANGE__ # Set your package name and version numbers here. # # This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION # set as provided. These will also be added as -D defs in your Makefile # so you can encode the package version directly into the source files. #----------------------------------------------------------------------- AC_INIT([nsfmongo], [2.4.0]) AC_CONFIG_MACRO_DIR([m4]) #-------------------------------------------------------------------- # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable = "unix" or "windows" # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. #-------------------------------------------------------------------- TEA_INIT([3.10]) AC_CONFIG_AUX_DIR([../../tclconfig]) #-------------------------------------------------------------------- # specify some extra flags #-------------------------------------------------------------------- AC_ARG_WITH([mongoc], [ --with-mongoc=MONGOC_INCLUDE_DIR[,MONGOC_LIB_DIR] absolute path to mongo.h and optionally the path to the library, --without-mongoc disables build of the mongo interface], [with_mongoc=$withval], [with_mongoc=no]) AC_ARG_WITH([bson], [ --with-bson=BSON_INCLUDE_DIR[,BSON_LIB_DIR] absolute path to bson.h and optionally the path to the library, --without-bson disables build of the mongo interface], [with_bson=$withval], [with_bson=no]) AC_ARG_WITH([nsf], [ --with-nsf=DIR_CONTAINING_NSFCONFIG_SH absolute path to nsfConfig.sh, --without-nsf disables, but this is pointless], [with_nsf=$withval], [AC_MSG_ERROR([--with-nsf is required])]) AC_ARG_ENABLE([development], AS_HELP_STRING([--enable-development], [build nsf with development support (intensive runtime checking, etc.; default: disabled)]), [enable_development=$enableval], [enable_development=no]) AC_ARG_ENABLE([profile], AS_HELP_STRING([--enable-profile], [build nsf with profile support (default: disabled)]), [enable_profile=$enableval], [enable_profile=no]) AC_ARG_ENABLE([assertions], AS_HELP_STRING([--enable-assertions],[build nsf with assertion support (default: enabled)]), [enable_assertions=$enableval], [enable_assertions=yes]) #-------------------------------------------------------------------- # Load the tclConfig.sh file #-------------------------------------------------------------------- TEA_PATH_TCLCONFIG TEA_LOAD_TCLCONFIG #-------------------------------------------------------------------- # Load the tkConfig.sh file if necessary (Tk extension) #-------------------------------------------------------------------- #TEA_PATH_TKCONFIG #TEA_LOAD_TKCONFIG #----------------------------------------------------------------------- # Handle the --prefix=... option by defaulting to what Tcl gave. # Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. #----------------------------------------------------------------------- TEA_PREFIX #----------------------------------------------------------------------- # Standard compiler checks. # This sets up CC by using the CC env var, or looks for gcc otherwise. # This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create # the basic setup necessary to compile executables. #----------------------------------------------------------------------- TEA_SETUP_COMPILER #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, # public headers that need to be installed in TEA_ADD_HEADERS, # stub library C source files to compile in TEA_ADD_STUB_SOURCES, # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- if test ! "${with_mongoc}" = no; then MONGOC_INC_DIR="`echo $with_mongoc |cut -f1 -d,`" MONGOC_LIB_DIR="`echo $with_mongoc |cut -f2 -d, -s`" fi if test ! "${with_bson}" = no; then BSON_INC_DIR="`echo $with_bson |cut -f1 -d,`" BSON_LIB_DIR="`echo $with_bson |cut -f2 -d, -s`" fi mongo_h_ok=1 if test -z "$MONGOC_INC_DIR" ; then mongo_h_ok=0 MONGO_INC_SPEC="" fi if test -z "$BSON_INC_DIR" ; then mongo_h_ok=0 MONGO_INC_SPEC="" fi if test "${mongo_h_ok}" = "1" ; then MONGO_INC_SPEC="-I${MONGOC_INC_DIR} -I${BSON_INC_DIR}" echo "Checking ${MONGOC_INC_DIR}/mongoc.h" if test ! -f "${MONGOC_INC_DIR}/mongoc.h" ; then mongo_h_ok=0 fi echo "Checking ${BSON_INC_DIR}/bson.h" if test ! -f "${BSON_INC_DIR}/bson.h" ; then mongo_h_ok=0 fi fi if test "${mongo_h_ok}" = "0" ; then AC_MSG_ERROR([ Could not locate bson.h and mongoc.h on your machine to build the nsf mongo interface. ]) fi if test -z "${MONGOC_LIB_DIR}" ; then MONGO_LIB_SPEC="" else MONGO_LIB_SPEC="-L${MONGOC_LIB_DIR}" fi if test ! -z "${BSON_LIB_DIR}" ; then MONGO_LIB_SPEC="${MONGO_LIB_SPEC} -L${BSON_LIB_DIR}" fi #echo "MONGO include spec = '${MONGO_INC_SPEC}'" #echo "MONGO lib spec = '${MONGO_LIB_SPEC}'" #-------------------------------------------------------------------- # Load the nsfConfig.sh file #-------------------------------------------------------------------- AC_MSG_NOTICE([Reading file ${with_nsf}/nsfConfig.sh]) source ${with_nsf}/nsfConfig.sh TEA_ADD_SOURCES([nsfmongo.c]) TEA_ADD_HEADERS([]) TEA_ADD_INCLUDES([-I${with_nsf}/generic ${NSF_BUILD_INCLUDE_SPEC} ${MONGO_INC_SPEC}]) #TEA_ADD_LIBS([$NSF_BUILD_STUB_LIB_SPEC $MONGO_LIB_SPEC -Wl,-rpath,${MONGO_LIB_DIR} -L${MONGO_LIB_DIR} -lmongoc -lbson]) #TEA_ADD_LIBS([$NSF_BUILD_STUB_LIB_SPEC $MONGO_LIB_SPEC -L${MONGO_LIB_DIR} -lmongoc -lbson]) TEA_ADD_LIBS([$NSF_BUILD_STUB_LIB_SPEC $MONGO_LIB_SPEC -lmongoc-1.0 -lbson-1.0]) TEA_ADD_CFLAGS([]) TEA_ADD_STUB_SOURCES([]) TEA_ADD_TCL_SOURCES([]) #-------------------------------------------------------------------- # __CHANGE__ # A few miscellaneous platform-specific items: # # Define a special symbol for Windows (BUILD_sample in this case) so # that we create the export library with the dll. # # Windows creates a few extra files that need to be cleaned up. # You can add more files to clean if your extension creates any extra # files. # # TEA_ADD_* any platform specific compiler/build info here. #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then CLEANFILES="pkgIndex.tcl *.lib *.dll *.exp *.ilk *.pdb vc*.pch" #TEA_ADD_SOURCES([win/winFile.c]) #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"]) else CLEANFILES="pkgIndex.tcl" #TEA_ADD_SOURCES([unix/unixFile.c]) #TEA_ADD_LIBS([-lsuperfly]) fi AC_SUBST([CLEANFILES]) #-------------------------------------------------------------------- # __CHANGE__ # Choose which headers you need. Extension authors should try very # hard to only rely on the Tcl public header files. Internal headers # contain private data structures and are subject to change without # notice. # This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG #-------------------------------------------------------------------- TEA_PUBLIC_TCL_HEADERS #TEA_PRIVATE_TCL_HEADERS #TEA_PUBLIC_TK_HEADERS #TEA_PRIVATE_TK_HEADERS #TEA_PATH_X #-------------------------------------------------------------------- # Check whether --enable-threads or --disable-threads was given. #-------------------------------------------------------------------- TEA_ENABLE_THREADS #-------------------------------------------------------------------- # The statement below defines a collection of symbols related to # building as a shared library instead of a static library. #-------------------------------------------------------------------- TEA_ENABLE_SHARED #-------------------------------------------------------------------- # This macro figures out what flags to use with the compiler/linker # when building shared/static debug/optimized objects. This information # can be taken from the tclConfig.sh file, but this figures it all out. #-------------------------------------------------------------------- TEA_CONFIG_CFLAGS #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols option. #-------------------------------------------------------------------- TEA_ENABLE_SYMBOLS #-------------------------------------------------------------------- # Everyone should be linking against the Tcl stub library. If you # can't for some reason, remove this definition. If you aren't using # stubs, you also need to modify the SHLIB_LD_LIBS setting below to # link against the non-stubbed Tcl library. Add Tk too if necessary. #-------------------------------------------------------------------- AC_DEFINE([USE_TCL_STUBS]) #AC_DEFINE([USE_TK_STUBS]) if test "$enable_development" = yes; then AC_DEFINE([NSF_DEVELOPMENT], [1], [Are we building with development support?]) fi #-------------------------------------------------------------------- # This macro generates a line to use when building a library. It # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, # and TEA_LOAD_TCLCONFIG macros above. #-------------------------------------------------------------------- TEA_MAKE_LIB #-------------------------------------------------------------------- # Find tclsh so that we can run pkg_mkIndex to generate the pkgIndex.tcl # file during the install process. Don't run the TCLSH_PROG through # ${CYGPATH} because it's being used directly by make. # Require that we use a tclsh shell version 8.2 or later since earlier # versions have bugs in the pkg_mkIndex routine. # Add WISH as well if this is a Tk extension. #-------------------------------------------------------------------- TEA_PROG_TCLSH #TEA_PROG_WISH #-------------------------------------------------------------------- # Finally, substitute all of the various values into the Makefile. # You may alternatively have a special pkgIndex.tcl.in or other files # which require substituting th AC variables in. Include these here. #-------------------------------------------------------------------- AC_CONFIG_FILES([Makefile pkgIndex.add]) AC_OUTPUT ./nsf2.4.0/library/mongodb/mongoAPI.decls000644 000766 000024 00000012635 13030507001 020742 0ustar00neumannstaff000000 000000 # -*- Tcl -*- # # API declarations for the nsf mongo interface # # namespaces for types of methods array set ns { cmd "::mongo" } array set ptrConverter { mongoc_client_t 1 mongoc_collection_t 1 mongoc_cursor_t 1 mongoc_gridfs_file_t 1 mongoc_gridfs_t 1 } # produce json string from triples cmd json::generate NsfMongoJsonGenerate { {-argName "list" -required 1 -type tclobj} } # parse json string into triples cmd json::parse NsfMongoJsonParse { {-argName "json" -required 1 -type tclobj} } cmd close NsfMongoClose { {-argName "conn" -required 1 -type mongoc_client_t -withObj 1} } cmd connect NsfMongoConnect { {-argName "-uri" -required 0 -nrargs 1} } cmd run NsfMongoRunCmd { {-argName "-nocomplain" -required 0 -nrargs 0} {-argName "conn" -required 1 -type mongoc_client_t} {-argName "db" -required 1} {-argName "cmd" -required 1 -type tclobj} } cmd status NsfMongoStatus { {-argName "conn" -required 1 -type mongoc_client_t -withObj 1} } # # collection # cmd "collection::close" NsfCollectionClose { {-argName "collection" -required 1 -type mongoc_collection_t -withObj 1} } cmd "collection::count" NsfMongoCollectionCount { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "query" -required 1 -type tclobj} } cmd "collection::delete" NsfMongoCollectionDelete { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "condition" -required 1 -type tclobj} } cmd "collection::index" NsfMongoCollectionIndex { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "attributes" -required 1 -type tclobj} {-argName "-name" -required 0 -nrargs 1} {-argName "-background" -required 0 -nrargs 0} {-argName "-dropdups" -required 0 -nrargs 0} {-argName "-sparse" -required 0 -nrargs 0} {-argName "-ttl" -required 0 -nrargs 1 -type int32} {-argName "-unique" -required 0 -nrargs 0} } cmd "collection::insert" NsfMongoCollectionInsert { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "values" -required 1 -type tclobj} } cmd collection::open NsfCollectionOpen { {-argName "conn" -required 1 -type mongoc_client_t} {-argName "dbname" -required 1} {-argName "collectionname" -required 1} } cmd "collection::query" NsfMongoCollectionQuery { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "filter" -required 1 -type tclobj} {-argName "-opts" -required 0 -nrargs 1 -type tclobj} } cmd "collection::stats" NsfMongoCollectionStats { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "-options" -required 0 -type tclobj} } cmd "collection::update" NsfMongoCollectionUpdate { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "cond" -required 1 -type tclobj} {-argName "values" -required 1 -type tclobj} {-argName "-upsert" -required 0 -nrargs 0} {-argName "-all" -required 0 -nrargs 0} } # # Cursor # cmd cursor::aggregate NsfMongoCursorAggregate { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "pipeline" -required 1 -type tclobj} {-argName "options" -required 1 -type tclobj} {-argName "-tailable" -required 0 -nrargs 0} {-argName "-awaitdata" -required 0 -nrargs 0} } cmd cursor::find NsfMongoCursorFind { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "filter" -required 1 -type tclobj} {-argName "-opts" -required 0 -nrargs 1 -type tclobj} } cmd cursor::next NsfMongoCursorNext { {-argName "cursor" -required 1 -type mongoc_cursor_t} } cmd cursor::close NsfMongoCursorClose { {-argName "cursor" -required 1 -type mongoc_cursor_t -withObj 1} } # # GridFS # cmd gridfs::close NsfMongoGridFSClose { {-argName "gfs" -required 1 -type mongoc_gridfs_t -withObj 1} } cmd gridfs::open NsfMongoGridFSOpen { {-argName "conn" -required 1 -type mongoc_client_t} {-argName "dbname" -required 1} {-argName "prefix" -required 1} } # # GridFile commands operating on GridFS # cmd gridfile::create NsfMongoGridFileCreate { {-argName "-source" -required 1 -typeName "gridfilesource" -type "file|string"} {-argName "gfs" -required 1 -type mongoc_gridfs_t} {-argName "value" -required 1} {-argName "name" -required 1} {-argName "contenttype" -required 1} {-argName "-metadata" -type tclobj} } cmd "gridfile::delete" NsfMongoGridFileDelete { {-argName "gfs" -required 1 -type mongoc_gridfs_t} {-argName "query" -required 1 -type tclobj} } cmd "gridfile::open" NsfMongoGridFileOpen { {-argName "gfs" -required 1 -type mongoc_gridfs_t} {-argName "query" -required 1 -type tclobj} } # # GridFile # cmd "gridfile::close" NsfMongoGridFileClose { {-argName "gridfile" -required 1 -type mongoc_gridfs_file_t -withObj 1} } cmd "gridfile::get_contentlength" NsfMongoGridFileGetContentlength { {-argName "gridfile" -required 1 -type mongoc_gridfs_file_t} } cmd "gridfile::get_contenttype" NsfMongoGridFileGetContentType { {-argName "gridfile" -required 1 -type mongoc_gridfs_file_t} } cmd "gridfile::get_metadata" NsfMongoGridFileGetMetaData { {-argName "gridfile" -required 1 -type mongoc_gridfs_file_t} } cmd "gridfile::read" NsfMongoGridFileRead { {-argName "gridfile" -required 1 -type mongoc_gridfs_file_t} {-argName "size" -required 1 -type int32} } cmd "gridfile::seek" NsfMongoGridFileSeek { {-argName "gridfile" -required 1 -type mongoc_gridfs_file_t} {-argName "offset" -required 1 -type int32} } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/mongodb/tclconfig/install-sh000755 000766 000024 00000033054 12501766547 022257 0ustar00neumannstaff000000 000000 #!/bin/sh # install - install a program, script, or datafile scriptversion=2011-04-20.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -S $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -S) stripcmd="$stripprog $2" shift;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ./nsf2.4.0/library/mongodb/configure000755 000766 000024 00001114627 14270756071 020215 0ustar00neumannstaff000000 000000 #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for nsfmongo 2.4.0. # # # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="as_nop=: if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else $as_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='nsfmongo' PACKAGE_TARNAME='nsfmongo' PACKAGE_VERSION='2.4.0' PACKAGE_STRING='nsfmongo 2.4.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS TCLSH_PROG PRACTCL_NAME_LIBRARY PRACTCL_VC_MANIFEST_EMBED_EXE PRACTCL_VC_MANIFEST_EMBED_DLL PRACTCL_STUB_LIB PRACTCL_STATIC_LIB PRACTCL_SHARED_LIB PRACTCL_TOOLSET PRACTCL_CFLAGS VC_MANIFEST_EMBED_EXE VC_MANIFEST_EMBED_DLL RANLIB_STUB MAKE_STUB_LIB MAKE_STATIC_LIB MAKE_SHARED_LIB MAKE_LIB TCL_DBGX LDFLAGS_DEFAULT CFLAGS_DEFAULT LD_LIBRARY_PATH_VAR SHLIB_CFLAGS SHLIB_LD_LIBS SHLIB_SUFFIX SHLIB_LD STLIB_LD CFLAGS_WARNING CFLAGS_OPTIMIZE CFLAGS_DEBUG RC CELIB_DIR AR STUBS_BUILD SHARED_BUILD TCL_THREADS TCL_INCLUDES PKG_OBJECTS PKG_SOURCES EGREP GREP MATH_LIBS RANLIB SET_MAKE INSTALL_LIBRARY INSTALL_SCRIPT INSTALL_PROGRAM INSTALL_DATA INSTALL_DATA_DIR INSTALL CPP TCL_SHLIB_LD_LIBS TCL_LD_FLAGS TCL_EXTRA_CFLAGS TCL_DEFS TCL_LIBS CLEANFILES OBJEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC TCL_STUB_LIB_SPEC TCL_STUB_LIB_FLAG TCL_STUB_LIB_FILE TCL_LIB_SPEC TCL_LIB_FLAG TCL_LIB_FILE TCL_SRC_DIR TCL_BIN_DIR TCL_PATCH_LEVEL TCL_VERSION PKG_CFLAGS PKG_LIBS PKG_INCLUDES PKG_HEADERS PKG_TCL_SOURCES PKG_STUB_OBJECTS PKG_STUB_SOURCES PKG_STUB_LIB_FILE PKG_LIB_FILE9 PKG_LIB_FILE8 PKG_LIB_FILE EXEEXT CYGPATH TEA_TK_EXTENSION target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_mongoc with_bson with_nsf enable_development enable_profile enable_assertions with_tcl with_tclinclude enable_threads enable_shared enable_stubs enable_64bit enable_64bit_vis enable_rpath enable_wince with_celib enable_symbols with_tclsh ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures nsfmongo 2.4.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/nsfmongo] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of nsfmongo 2.4.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-development build nsf with development support (intensive runtime checking, etc.; default: disabled) --enable-profile build nsf with profile support (default: disabled) --enable-assertions build nsf with assertion support (default: enabled) --enable-threads build with threads --enable-shared build and link with shared libraries (default: on) --enable-stubs build and link with stub libraries. Always true for shared builds (default: on) --enable-64bit enable 64bit support (default: off) --enable-64bit-vis enable 64bit Sparc VIS support (default: off) --disable-rpath disable rpath support (default: on) --enable-wince enable Win/CE support (where applicable) --enable-symbols build with debugging symbols (default: off) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-mongoc=MONGOC_INCLUDE_DIR,MONGOC_LIB_DIR absolute path to mongo.h and optionally the path to the library, --without-mongoc disables build of the mongo interface --with-bson=BSON_INCLUDE_DIR,BSON_LIB_DIR absolute path to bson.h and optionally the path to the library, --without-bson disables build of the mongo interface --with-nsf=DIR_CONTAINING_NSFCONFIG_SH absolute path to nsfConfig.sh, --without-nsf disables, but this is pointless --with-tcl directory containing tcl configuration (tclConfig.sh) --with-tclinclude directory containing the public Tcl header files --with-celib=DIR use Windows/CE support library from DIR --with-tclsh Specify a local tcl shell to use for dynamic code Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF nsfmongo configure 2.4.0 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that # executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: program exited with status $ac_status" >&5 printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. */ #include #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func ac_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by nsfmongo $as_me 2.4.0, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu #-------------------------------------------------------------------- # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable = "unix" or "windows" # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. #-------------------------------------------------------------------- # TEA extensions pass this us the version of TEA they think they # are compatible with. TEA_VERSION="3.10" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for correct TEA configuration" >&5 printf %s "checking for correct TEA configuration... " >&6; } if test x"${PACKAGE_NAME}" = x ; then as_fn_error $? " The PACKAGE_NAME variable must be defined by your TEA configure.ac" "$LINENO" 5 fi if test x"3.10" = x ; then as_fn_error $? " TEA version not specified." "$LINENO" 5 elif test "3.10" != "${TEA_VERSION}" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: warning: requested TEA version \"3.10\", have \"${TEA_VERSION}\"" >&5 printf "%s\n" "warning: requested TEA version \"3.10\", have \"${TEA_VERSION}\"" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok (TEA ${TEA_VERSION})" >&5 printf "%s\n" "ok (TEA ${TEA_VERSION})" >&6; } fi # If the user did not set CFLAGS, set it now to keep macros # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi TEA_TK_EXTENSION=0 case "`uname -s`" in *win32*|*WIN32*|*MINGW32_*) # Extract the first word of "cygpath", so it can be a program name with args. set dummy cygpath; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CYGPATH+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CYGPATH"; then ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CYGPATH="cygpath -m" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo" fi fi CYGPATH=$ac_cv_prog_CYGPATH if test -n "$CYGPATH"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CYGPATH" >&5 printf "%s\n" "$CYGPATH" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi EXEEXT=".exe" TEA_PLATFORM="windows" ;; *CYGWIN_*) EXEEXT=".exe" # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG ;; *) CYGPATH=echo # Maybe we are cross-compiling.... case ${host_alias} in *mingw32*) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *) EXEEXT="" TEA_PLATFORM="unix" ;; esac ;; esac # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}" >&5 printf "%s\n" "$as_me: configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}" >&6;} # This package name must be replaced statically for AC_SUBST to work # Substitute STUB_LIB_FILE in case package creates a stub library too. # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... #-------------------------------------------------------------------- # specify some extra flags #-------------------------------------------------------------------- # Check whether --with-mongoc was given. if test ${with_mongoc+y} then : withval=$with_mongoc; with_mongoc=$withval else $as_nop with_mongoc=no fi # Check whether --with-bson was given. if test ${with_bson+y} then : withval=$with_bson; with_bson=$withval else $as_nop with_bson=no fi # Check whether --with-nsf was given. if test ${with_nsf+y} then : withval=$with_nsf; with_nsf=$withval else $as_nop as_fn_error $? "--with-nsf is required" "$LINENO" 5 fi # Check whether --enable-development was given. if test ${enable_development+y} then : enableval=$enable_development; enable_development=$enableval else $as_nop enable_development=no fi # Check whether --enable-profile was given. if test ${enable_profile+y} then : enableval=$enable_profile; enable_profile=$enableval else $as_nop enable_profile=no fi # Check whether --enable-assertions was given. if test ${enable_assertions+y} then : enableval=$enable_assertions; enable_assertions=$enableval else $as_nop enable_assertions=yes fi #-------------------------------------------------------------------- # Load the tclConfig.sh file #-------------------------------------------------------------------- # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true # Check whether --with-tcl was given. if test ${with_tcl+y} then : withval=$with_tcl; with_tclconfig="${withval}" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Tcl configuration" >&5 printf %s "checking for Tcl configuration... " >&6; } if test ${ac_cv_c_tclconfig+y} then : printf %s "(cached) " >&6 else $as_nop # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case "${with_tclconfig}" in */tclConfig.sh ) if test -f "${with_tclconfig}"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&5 printf "%s\n" "$as_me: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&2;} with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" else as_fn_error $? "${with_tclconfig} directory doesn't contain tclConfig.sh" "$LINENO" 5 fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../tcl[8-9].[0-9]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../tcl[8-9].[0-9]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../../tcl[8-9].[0-9]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/pkg/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ `ls -d /usr/lib/tcl8.6 2>/dev/null` \ `ls -d /usr/lib/tcl8.5 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi fi if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" as_fn_error $? "Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh" "$LINENO" 5 else no_tcl= TCL_BIN_DIR="${ac_cv_c_tclconfig}" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found ${TCL_BIN_DIR}/tclConfig.sh" >&5 printf "%s\n" "found ${TCL_BIN_DIR}/tclConfig.sh" >&6; } fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for existence of ${TCL_BIN_DIR}/tclConfig.sh" >&5 printf %s "checking for existence of ${TCL_BIN_DIR}/tclConfig.sh... " >&6; } if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: loading" >&5 printf "%s\n" "loading" >&6; } . "${TCL_BIN_DIR}/tclConfig.sh" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: could not find ${TCL_BIN_DIR}/tclConfig.sh" >&5 printf "%s\n" "could not find ${TCL_BIN_DIR}/tclConfig.sh" >&6; } fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitrary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" break fi done fi if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking platform" >&5 printf %s "checking platform... " >&6; } hold_cc=$CC; CC="$TCL_CC" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifdef _WIN32 #error win32 #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : TEA_PLATFORM="unix" CYGPATH=echo else $as_nop TEA_PLATFORM="windows" # Extract the first word of "cygpath", so it can be a program name with args. set dummy cygpath; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CYGPATH+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CYGPATH"; then ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CYGPATH="cygpath -m" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo" fi fi CYGPATH=$ac_cv_prog_CYGPATH if test -n "$CYGPATH"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CYGPATH" >&5 printf "%s\n" "$CYGPATH" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CC=$hold_cc { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TEA_PLATFORM" >&5 printf "%s\n" "$TEA_PLATFORM" >&6; } # The BUILD_$pkg is to define the correct extern storage class # handling when making this package printf "%s\n" "#define BUILD_${PACKAGE_NAME} /**/" >>confdefs.h # Do this here as we have fully defined TEA_PLATFORM now if test "${TEA_PLATFORM}" = "windows" ; then EXEEXT=".exe" CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp" fi # TEA specific: #-------------------------------------------------------------------- # Load the tkConfig.sh file if necessary (Tk extension) #-------------------------------------------------------------------- #TEA_PATH_TKCONFIG #TEA_LOAD_TKCONFIG #----------------------------------------------------------------------- # Handle the --prefix=... option by defaulting to what Tcl gave. # Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. #----------------------------------------------------------------------- if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&5 printf "%s\n" "$as_me: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&6;} prefix=${TCL_PREFIX} else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: --prefix defaulting to /usr/local" >&5 printf "%s\n" "$as_me: --prefix defaulting to /usr/local" >&6;} prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&5 printf "%s\n" "$as_me: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&6;} exec_prefix=${TCL_EXEC_PREFIX} else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: --exec-prefix defaulting to ${prefix}" >&5 printf "%s\n" "$as_me: --exec-prefix defaulting to ${prefix}" >&6;} exec_prefix=$prefix fi fi #----------------------------------------------------------------------- # Standard compiler checks. # This sets up CC by using the CC env var, or looks for gcc otherwise. # This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create # the basic setup necessary to compile executables. #----------------------------------------------------------------------- # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 printf %s "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test ${ac_cv_prog_CPP+y} then : printf %s "(cached) " >&6 else $as_nop # Double quotes because $CC needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 printf "%s\n" "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c' INSTALL_DATA_DIR='${INSTALL} -d -m 755' INSTALL_DATA='${INSTALL} -m 644' INSTALL_PROGRAM='${INSTALL}' INSTALL_SCRIPT='${INSTALL}' INSTALL_LIBRARY='${INSTALL_DATA}' #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 else $as_nop cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SET_MAKE= else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 printf "%s\n" "$RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 printf "%s\n" "$ac_ct_RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 printf %s "checking for grep that handles long lines and -e... " >&6; } if test ${ac_cv_path_GREP+y} then : printf %s "(cached) " >&6 else $as_nop if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in grep ggrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 printf "%s\n" "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 printf %s "checking for egrep... " >&6; } if test ${ac_cv_path_EGREP+y} then : printf %s "(cached) " >&6 else $as_nop if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in egrep do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 printf %s 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" printf "%s\n" 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 printf "%s\n" "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the compiler understands -pipe" >&5 printf %s "checking if the compiler understands -pipe... " >&6; } if test ${tcl_cv_cc_pipe+y} then : printf %s "(cached) " >&6 else $as_nop hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_cc_pipe=yes else $as_nop tcl_cv_cc_pipe=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS=$hold_cflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_pipe" >&5 printf "%s\n" "$tcl_cv_cc_pipe" >&6; } if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 printf %s "checking whether byte ordering is bigendian... " >&6; } if test ${ac_cv_c_bigendian+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO" then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_bigendian=yes else $as_nop ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_bigendian=yes else $as_nop ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ unsigned short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; unsigned short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } unsigned short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; unsigned short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main (void) { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_c_bigendian=no else $as_nop ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 printf "%s\n" "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) printf "%s\n" "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac if test "${TEA_PLATFORM}" = "unix" ; then #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- ac_fn_c_check_func "$LINENO" "sin" "ac_cv_func_sin" if test "x$ac_cv_func_sin" = xyes then : MATH_LIBS="" else $as_nop MATH_LIBS="-lm" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -lieee" >&5 printf %s "checking for main in -lieee... " >&6; } if test ${ac_cv_lib_ieee_main+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lieee $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_ieee_main=yes else $as_nop ac_cv_lib_ieee_main=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee_main" >&5 printf "%s\n" "$ac_cv_lib_ieee_main" >&6; } if test "x$ac_cv_lib_ieee_main" = xyes then : MATH_LIBS="-lieee $MATH_LIBS" fi #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -linet" >&5 printf %s "checking for main in -linet... " >&6; } if test ${ac_cv_lib_inet_main+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-linet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_inet_main=yes else $as_nop ac_cv_lib_inet_main=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_main" >&5 printf "%s\n" "$ac_cv_lib_inet_main" >&6; } if test "x$ac_cv_lib_inet_main" = xyes then : LIBS="$LIBS -linet" fi ac_fn_c_check_header_compile "$LINENO" "net/errno.h" "ac_cv_header_net_errno_h" "$ac_includes_default" if test "x$ac_cv_header_net_errno_h" = xyes then : printf "%s\n" "#define HAVE_NET_ERRNO_H 1" >>confdefs.h fi #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = xyes then : tcl_checkSocket=0 else $as_nop tcl_checkSocket=1 fi if test "$tcl_checkSocket" = 1; then ac_fn_c_check_func "$LINENO" "setsockopt" "ac_cv_func_setsockopt" if test "x$ac_cv_func_setsockopt" = xyes then : else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for setsockopt in -lsocket" >&5 printf %s "checking for setsockopt in -lsocket... " >&6; } if test ${ac_cv_lib_socket_setsockopt+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char setsockopt (); int main (void) { return setsockopt (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_socket_setsockopt=yes else $as_nop ac_cv_lib_socket_setsockopt=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_setsockopt" >&5 printf "%s\n" "$ac_cv_lib_socket_setsockopt" >&6; } if test "x$ac_cv_lib_socket_setsockopt" = xyes then : LIBS="$LIBS -lsocket" else $as_nop tcl_checkBoth=1 fi fi fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" ac_fn_c_check_func "$LINENO" "accept" "ac_cv_func_accept" if test "x$ac_cv_func_accept" = xyes then : tcl_checkNsl=0 else $as_nop LIBS=$tk_oldLibs fi fi ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" if test "x$ac_cv_func_gethostbyname" = xyes then : else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 printf %s "checking for gethostbyname in -lnsl... " >&6; } if test ${ac_cv_lib_nsl_gethostbyname+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char gethostbyname (); int main (void) { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_nsl_gethostbyname=yes else $as_nop ac_cv_lib_nsl_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 printf "%s\n" "$ac_cv_lib_nsl_gethostbyname" >&6; } if test "x$ac_cv_lib_nsl_gethostbyname" = xyes then : LIBS="$LIBS -lnsl" fi fi # TEA specific: Don't perform the eval of the libraries here because # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dirent.h" >&5 printf %s "checking dirent.h... " >&6; } if test ${tcl_cv_dirent_h+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_dirent_h=yes else $as_nop tcl_cv_dirent_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_dirent_h" >&5 printf "%s\n" "$tcl_cv_dirent_h" >&6; } if test $tcl_cv_dirent_h = no; then printf "%s\n" "#define NO_DIRENT_H 1" >>confdefs.h fi # TEA specific: ac_fn_c_check_header_compile "$LINENO" "errno.h" "ac_cv_header_errno_h" "$ac_includes_default" if test "x$ac_cv_header_errno_h" = xyes then : else $as_nop printf "%s\n" "#define NO_ERRNO_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "float.h" "ac_cv_header_float_h" "$ac_includes_default" if test "x$ac_cv_header_float_h" = xyes then : else $as_nop printf "%s\n" "#define NO_FLOAT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "values.h" "ac_cv_header_values_h" "$ac_includes_default" if test "x$ac_cv_header_values_h" = xyes then : else $as_nop printf "%s\n" "#define NO_VALUES_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default" if test "x$ac_cv_header_limits_h" = xyes then : printf "%s\n" "#define HAVE_LIMITS_H 1" >>confdefs.h else $as_nop printf "%s\n" "#define NO_LIMITS_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes then : tcl_ok=1 else $as_nop tcl_ok=0 fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtol" >/dev/null 2>&1 then : else $as_nop tcl_ok=0 fi rm -rf conftest* cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtoul" >/dev/null 2>&1 then : else $as_nop tcl_ok=0 fi rm -rf conftest* cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtod" >/dev/null 2>&1 then : else $as_nop tcl_ok=0 fi rm -rf conftest* if test $tcl_ok = 0; then printf "%s\n" "#define NO_STDLIB_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default" if test "x$ac_cv_header_string_h" = xyes then : tcl_ok=1 else $as_nop tcl_ok=0 fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strstr" >/dev/null 2>&1 then : else $as_nop tcl_ok=0 fi rm -rf conftest* cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strerror" >/dev/null 2>&1 then : else $as_nop tcl_ok=0 fi rm -rf conftest* # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then printf "%s\n" "#define NO_STRING_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/wait.h" "ac_cv_header_sys_wait_h" "$ac_includes_default" if test "x$ac_cv_header_sys_wait_h" = xyes then : else $as_nop printf "%s\n" "#define NO_SYS_WAIT_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" if test "x$ac_cv_header_dlfcn_h" = xyes then : else $as_nop printf "%s\n" "#define NO_DLFCN_H 1" >>confdefs.h fi # OS/390 lacks sys/param.h (and doesn't need it, by chance). ac_fn_c_check_header_compile "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" if test "x$ac_cv_header_sys_param_h" = xyes then : printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h fi # Let the user call this, because if it triggers, they will # need a compat/strtod.c that is correct. Users can also # use Tcl_GetDouble(FromObj) instead. #TEA_BUGGY_STRTOD fi #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, # public headers that need to be installed in TEA_ADD_HEADERS, # stub library C source files to compile in TEA_ADD_STUB_SOURCES, # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- if test ! "${with_mongoc}" = no; then MONGOC_INC_DIR="`echo $with_mongoc |cut -f1 -d,`" MONGOC_LIB_DIR="`echo $with_mongoc |cut -f2 -d, -s`" fi if test ! "${with_bson}" = no; then BSON_INC_DIR="`echo $with_bson |cut -f1 -d,`" BSON_LIB_DIR="`echo $with_bson |cut -f2 -d, -s`" fi mongo_h_ok=1 if test -z "$MONGOC_INC_DIR" ; then mongo_h_ok=0 MONGO_INC_SPEC="" fi if test -z "$BSON_INC_DIR" ; then mongo_h_ok=0 MONGO_INC_SPEC="" fi if test "${mongo_h_ok}" = "1" ; then MONGO_INC_SPEC="-I${MONGOC_INC_DIR} -I${BSON_INC_DIR}" echo "Checking ${MONGOC_INC_DIR}/mongoc.h" if test ! -f "${MONGOC_INC_DIR}/mongoc.h" ; then mongo_h_ok=0 fi echo "Checking ${BSON_INC_DIR}/bson.h" if test ! -f "${BSON_INC_DIR}/bson.h" ; then mongo_h_ok=0 fi fi if test "${mongo_h_ok}" = "0" ; then as_fn_error $? " Could not locate bson.h and mongoc.h on your machine to build the nsf mongo interface. " "$LINENO" 5 fi if test -z "${MONGOC_LIB_DIR}" ; then MONGO_LIB_SPEC="" else MONGO_LIB_SPEC="-L${MONGOC_LIB_DIR}" fi if test ! -z "${BSON_LIB_DIR}" ; then MONGO_LIB_SPEC="${MONGO_LIB_SPEC} -L${BSON_LIB_DIR}" fi #echo "MONGO include spec = '${MONGO_INC_SPEC}'" #echo "MONGO lib spec = '${MONGO_LIB_SPEC}'" #-------------------------------------------------------------------- # Load the nsfConfig.sh file #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Reading file ${with_nsf}/nsfConfig.sh" >&5 printf "%s\n" "$as_me: Reading file ${with_nsf}/nsfConfig.sh" >&6;} source ${with_nsf}/nsfConfig.sh vars="nsfmongo.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then as_fn_error $? "could not find source file '$i'" "$LINENO" 5 fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then as_fn_error $? "could not find header file '${srcdir}/$i'" "$LINENO" 5 fi PKG_HEADERS="$PKG_HEADERS $i" done vars="-I${with_nsf}/generic ${NSF_BUILD_INCLUDE_SPEC} ${MONGO_INC_SPEC}" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done #TEA_ADD_LIBS([$NSF_BUILD_STUB_LIB_SPEC $MONGO_LIB_SPEC -Wl,-rpath,${MONGO_LIB_DIR} -L${MONGO_LIB_DIR} -lmongoc -lbson]) #TEA_ADD_LIBS([$NSF_BUILD_STUB_LIB_SPEC $MONGO_LIB_SPEC -L${MONGO_LIB_DIR} -lmongoc -lbson]) vars="$NSF_BUILD_STUB_LIB_SPEC $MONGO_LIB_SPEC -lmongoc-1.0 -lbson-1.0" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done PKG_CFLAGS="$PKG_CFLAGS " vars="" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then as_fn_error $? "could not find stub source file '$i'" "$LINENO" 5 fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done vars="" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then as_fn_error $? "could not find tcl source file '${srcdir}/$i'" "$LINENO" 5 fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done #-------------------------------------------------------------------- # __CHANGE__ # A few miscellaneous platform-specific items: # # Define a special symbol for Windows (BUILD_sample in this case) so # that we create the export library with the dll. # # Windows creates a few extra files that need to be cleaned up. # You can add more files to clean if your extension creates any extra # files. # # TEA_ADD_* any platform specific compiler/build info here. #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then CLEANFILES="pkgIndex.tcl *.lib *.dll *.exp *.ilk *.pdb vc*.pch" #TEA_ADD_SOURCES([win/winFile.c]) #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"]) else CLEANFILES="pkgIndex.tcl" #TEA_ADD_SOURCES([unix/unixFile.c]) #TEA_ADD_LIBS([-lsuperfly]) fi #-------------------------------------------------------------------- # __CHANGE__ # Choose which headers you need. Extension authors should try very # hard to only rely on the Tcl public header files. Internal headers # contain private data structures and are subject to change without # notice. # This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Tcl public headers" >&5 printf %s "checking for Tcl public headers... " >&6; } # Check whether --with-tclinclude was given. if test ${with_tclinclude+y} then : withval=$with_tclinclude; with_tclinclude=${withval} fi if test ${ac_cv_c_tclh+y} then : printf %s "(cached) " >&6 else $as_nop # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else as_fn_error $? "${with_tclinclude} directory does not contain tcl.h" "$LINENO" 5 fi else list="" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi fi # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then as_fn_error $? "tcl.h not found. Please specify its location with --with-tclinclude" "$LINENO" 5 else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${ac_cv_c_tclh}" >&5 printf "%s\n" "${ac_cv_c_tclh}" >&6; } fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" #TEA_PRIVATE_TCL_HEADERS #TEA_PUBLIC_TK_HEADERS #TEA_PRIVATE_TK_HEADERS #TEA_PATH_X #-------------------------------------------------------------------- # Check whether --enable-threads or --disable-threads was given. #-------------------------------------------------------------------- # Check whether --enable-threads was given. if test ${enable_threads+y} then : enableval=$enable_threads; tcl_ok=$enableval else $as_nop tcl_ok=yes fi if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention printf "%s\n" "#define USE_THREAD_ALLOC 1" >>confdefs.h printf "%s\n" "#define _REENTRANT 1" >>confdefs.h if test "`uname -s`" = "SunOS" ; then printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h fi printf "%s\n" "#define _THREAD_SAFE 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthread" >&5 printf %s "checking for pthread_mutex_init in -lpthread... " >&6; } if test ${ac_cv_lib_pthread_pthread_mutex_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char pthread_mutex_init (); int main (void) { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_pthread_pthread_mutex_init=yes else $as_nop ac_cv_lib_pthread_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_init" >&5 printf "%s\n" "$ac_cv_lib_pthread_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthread_pthread_mutex_init" = xyes then : tcl_ok=yes else $as_nop tcl_ok=no fi if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __pthread_mutex_init in -lpthread" >&5 printf %s "checking for __pthread_mutex_init in -lpthread... " >&6; } if test ${ac_cv_lib_pthread___pthread_mutex_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char __pthread_mutex_init (); int main (void) { return __pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_pthread___pthread_mutex_init=yes else $as_nop ac_cv_lib_pthread___pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_mutex_init" >&5 printf "%s\n" "$ac_cv_lib_pthread___pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthread___pthread_mutex_init" = xyes then : tcl_ok=yes else $as_nop tcl_ok=no fi fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthreads" >&5 printf %s "checking for pthread_mutex_init in -lpthreads... " >&6; } if test ${ac_cv_lib_pthreads_pthread_mutex_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpthreads $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char pthread_mutex_init (); int main (void) { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_pthreads_pthread_mutex_init=yes else $as_nop ac_cv_lib_pthreads_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_mutex_init" >&5 printf "%s\n" "$ac_cv_lib_pthreads_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthreads_pthread_mutex_init" = xyes then : tcl_ok=yes else $as_nop tcl_ok=no fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc" >&5 printf %s "checking for pthread_mutex_init in -lc... " >&6; } if test ${ac_cv_lib_c_pthread_mutex_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char pthread_mutex_init (); int main (void) { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_c_pthread_mutex_init=yes else $as_nop ac_cv_lib_c_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_pthread_mutex_init" >&5 printf "%s\n" "$ac_cv_lib_c_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_c_pthread_mutex_init" = xyes then : tcl_ok=yes else $as_nop tcl_ok=no fi if test "$tcl_ok" = "no"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc_r" >&5 printf %s "checking for pthread_mutex_init in -lc_r... " >&6; } if test ${ac_cv_lib_c_r_pthread_mutex_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char pthread_mutex_init (); int main (void) { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_c_r_pthread_mutex_init=yes else $as_nop ac_cv_lib_c_r_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_mutex_init" >&5 printf "%s\n" "$ac_cv_lib_c_r_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_c_r_pthread_mutex_init" = xyes then : tcl_ok=yes else $as_nop tcl_ok=no fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&5 printf "%s\n" "$as_me: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&2;} fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for building with threads" >&5 printf %s "checking for building with threads... " >&6; } if test "${TCL_THREADS}" = 1; then printf "%s\n" "#define TCL_THREADS 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (default)" >&5 printf "%s\n" "yes (default)" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads." >&5 printf "%s\n" "$as_me: WARNING: Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads." >&2;} fi ;; *) if test "${TCL_THREADS}" = "1"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core." >&5 printf "%s\n" "$as_me: WARNING: --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core." >&2;} fi ;; esac #-------------------------------------------------------------------- # The statement below defines a collection of symbols related to # building as a shared library instead of a static library. #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to build libraries" >&5 printf %s "checking how to build libraries... " >&6; } # Check whether --enable-shared was given. if test ${enable_shared+y} then : enableval=$enable_shared; shared_ok=$enableval else $as_nop shared_ok=yes fi if test "${enable_shared+set}" = set; then enableval="$enable_shared" shared_ok=$enableval else shared_ok=yes fi # Check whether --enable-stubs was given. if test ${enable_stubs+y} then : enableval=$enable_stubs; stubs_ok=$enableval else $as_nop stubs_ok=yes fi if test "${enable_stubs+set}" = set; then enableval="$enable_stubs" stubs_ok=$enableval else stubs_ok=yes fi # Stubs are always enabled for shared builds if test "$shared_ok" = "yes" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: shared" >&5 printf "%s\n" "shared" >&6; } SHARED_BUILD=1 STUBS_BUILD=1 else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: static" >&5 printf "%s\n" "static" >&6; } SHARED_BUILD=0 printf "%s\n" "#define STATIC_BUILD 1" >>confdefs.h if test "$stubs_ok" = "yes" ; then STUBS_BUILD=1 else STUBS_BUILD=0 fi fi if test "${STUBS_BUILD}" = "1" ; then printf "%s\n" "#define USE_TCL_STUBS 1" >>confdefs.h printf "%s\n" "#define USE_TCLOO_STUBS 1" >>confdefs.h if test "${TEA_WINDOWINGSYSTEM}" != ""; then printf "%s\n" "#define USE_TK_STUBS 1" >>confdefs.h fi fi #-------------------------------------------------------------------- # This macro figures out what flags to use with the compiler/linker # when building shared/static debug/optimized objects. This information # can be taken from the tclConfig.sh file, but this figures it all out. #-------------------------------------------------------------------- if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 printf "%s\n" "$RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 printf "%s\n" "$ac_ct_RANLIB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi # Step 0.a: Enable 64 bit support? { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if 64bit support is requested" >&5 printf %s "checking if 64bit support is requested... " >&6; } # Check whether --enable-64bit was given. if test ${enable_64bit+y} then : enableval=$enable_64bit; do64bit=$enableval else $as_nop do64bit=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $do64bit" >&5 printf "%s\n" "$do64bit" >&6; } # Step 0.b: Enable Solaris 64 bit VIS support? { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if 64bit Sparc VIS support is requested" >&5 printf %s "checking if 64bit Sparc VIS support is requested... " >&6; } # Check whether --enable-64bit-vis was given. if test ${enable_64bit_vis+y} then : enableval=$enable_64bit_vis; do64bitVIS=$enableval else $as_nop do64bitVIS=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $do64bitVIS" >&5 printf "%s\n" "$do64bitVIS" >&6; } # Force 64bit on with VIS if test "$do64bitVIS" = "yes" then : do64bit=yes fi # Step 0.c: Check if visibility support is available. Do this here so # that platform specific alternatives can be used below if this fails. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler supports visibility \"hidden\"" >&5 printf %s "checking if compiler supports visibility \"hidden\"... " >&6; } if test ${tcl_cv_cc_visibility_hidden+y} then : printf %s "(cached) " >&6 else $as_nop hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ extern __attribute__((__visibility__("hidden"))) void f(void); void f(void) {} int main (void) { f(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_cc_visibility_hidden=yes else $as_nop tcl_cv_cc_visibility_hidden=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_visibility_hidden" >&5 printf "%s\n" "$tcl_cv_cc_visibility_hidden" >&6; } if test $tcl_cv_cc_visibility_hidden = yes then : printf "%s\n" "#define MODULE_SCOPE extern __attribute__((__visibility__(\"hidden\")))" >>confdefs.h printf "%s\n" "#define HAVE_HIDDEN 1" >>confdefs.h fi # Step 0.d: Disable -rpath support? { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if rpath support is requested" >&5 printf %s "checking if rpath support is requested... " >&6; } # Check whether --enable-rpath was given. if test ${enable_rpath+y} then : enableval=$enable_rpath; doRpath=$enableval else $as_nop doRpath=yes fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $doRpath" >&5 printf "%s\n" "$doRpath" >&6; } # TEA specific: Cross-compiling options for Windows/CE builds? if test "${TEA_PLATFORM}" = windows then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if Windows/CE build is requested" >&5 printf %s "checking if Windows/CE build is requested... " >&6; } # Check whether --enable-wince was given. if test ${enable_wince+y} then : enableval=$enable_wince; doWince=$enableval else $as_nop doWince=no fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $doWince" >&5 printf "%s\n" "$doWince" >&6; } fi # Set the variable "system" to hold the name and version number # for the system. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking system version" >&5 printf %s "checking system version... " >&6; } if test ${tcl_cv_sys_version+y} then : printf %s "(cached) " >&6 else $as_nop # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: can't find uname command" >&5 printf "%s\n" "$as_me: WARNING: can't find uname command" >&2;} tcl_cv_sys_version=unknown else if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_sys_version" >&5 printf "%s\n" "$tcl_cv_sys_version" >&6; } system=$tcl_cv_sys_version # Require ranlib early so we can override it in special cases below. # Set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case and removed some core-only vars. do64bit_ok=no # default to '{$LIBS}' and set to "" on per-platform necessary basis SHLIB_LD_LIBS='${LIBS}' # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" UNSHARED_LIB_SUFFIX="" # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g if test "$GCC" = yes then : CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall" else $as_nop CFLAGS_OPTIMIZE=-O CFLAGS_WARNING="" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 printf "%s\n" "$AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 printf "%s\n" "$ac_ct_AR" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" if test "x$SHLIB_VERSION" = x then : SHLIB_VERSION="" else $as_nop SHLIB_VERSION=".$SHLIB_VERSION" fi case $system in # TEA specific: windows) # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test "$GCC" != "yes" -a ! -d "${PATH64}" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&5 printf "%s\n" "$as_me: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Ensure latest Platform SDK is installed" >&5 printf "%s\n" "$as_me: WARNING: Ensure latest Platform SDK is installed" >&2;} do64bit="no" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using 64-bit $MACHINE mode" >&5 printf "%s\n" " Using 64-bit $MACHINE mode" >&6; } do64bit_ok="yes" fi fi if test "$doWince" != "no" ; then if test "$do64bit" != "no" ; then as_fn_error $? "Windows/CE and 64-bit builds incompatible" "$LINENO" 5 fi if test "$GCC" = "yes" ; then as_fn_error $? "Windows/CE and GCC builds incompatible" "$LINENO" 5 fi # First, look for one uninstalled. # the alternative search directory is invoked by --with-celib if test x"${no_celib}" = x ; then # we reset no_celib in case something fails here no_celib=true # Check whether --with-celib was given. if test ${with_celib+y} then : withval=$with_celib; with_celibconfig=${withval} fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Windows/CE celib directory" >&5 printf %s "checking for Windows/CE celib directory... " >&6; } if test ${ac_cv_c_celibconfig+y} then : printf %s "(cached) " >&6 else $as_nop # First check to see if --with-celibconfig was specified. if test x"${with_celibconfig}" != x ; then if test -d "${with_celibconfig}/inc" ; then ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` else as_fn_error $? "${with_celibconfig} directory doesn't contain inc directory" "$LINENO" 5 fi fi # then check for a celib library if test x"${ac_cv_c_celibconfig}" = x ; then for i in \ ../celib-palm-3.0 \ ../celib \ ../../celib-palm-3.0 \ ../../celib \ `ls -dr ../celib-*3.[0-9]* 2>/dev/null` \ ${srcdir}/../celib-palm-3.0 \ ${srcdir}/../celib \ `ls -dr ${srcdir}/../celib-*3.[0-9]* 2>/dev/null` \ ; do if test -d "$i/inc" ; then ac_cv_c_celibconfig=`(cd $i; pwd)` break fi done fi fi if test x"${ac_cv_c_celibconfig}" = x ; then as_fn_error $? "Cannot find celib support library directory" "$LINENO" 5 else no_celib= CELIB_DIR=${ac_cv_c_celibconfig} CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found $CELIB_DIR" >&5 printf "%s\n" "found $CELIB_DIR" >&6; } fi fi # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F, '{ \ if (length($1)) { printf "CEVERSION=\"%s\"\n", $1; \ if ($1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length($2)) { printf "TARGETCPU=\"%s\"\n", toupper($2) }; \ if (length($3)) { printf "ARCH=\"%s\"\n", toupper($3) }; \ if (length($4)) { printf "PLATFORM=\"%s\"\n", $4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then as_fn_error $? "could not find PocketPC SDK or target compiler to enable WinCE mode $CEVERSION,$TARGETCPU,$ARCH,$PLATFORM" "$LINENO" 5 doWince="no" else # We could PATH_NOSPACE these, but that's not important, # as long as we quote them when used. CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi case "x`echo \${VisualStudioVersion}`" in x1[4-9]*) lflags="${lflags} -nodefaultlib:libucrt.lib" vars="ucrt.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done ;; *) ;; esac if test "$do64bit" != "no" ; then # All this magic is necessary for the Win64 SDK RC1 - hobbs CC="\"${PATH64}/cl.exe\"" CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" lflags="${lflags} -nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 vars="bufferoverflowU.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done elif test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="\"${CEBINROOT}/cl.exe\"" else CC="\"${CEBINROOT}/cl${ARCH}.exe\"" fi CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower($0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" if test "${SHARED_BUILD}" = "1" ; then # Static CE builds require static celib as well defs="${defs} _DLL" fi for i in $defs ; do printf "%s\n" "#define $i 1" >>confdefs.h done printf "%s\n" "#define _WIN32_WCE $CEVERSION" >>confdefs.h printf "%s\n" "#define UNDER_CE $CEVERSION" >>confdefs.h CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -Ox" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="${lflags} -MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" else RC="rc" lflags="${lflags} -nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args. set dummy ${ac_tool_prefix}windres; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$RC"; then ac_cv_prog_RC="$RC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_RC="${ac_tool_prefix}windres" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RC=$ac_cv_prog_RC if test -n "$RC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RC" >&5 printf "%s\n" "$RC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_RC"; then ac_ct_RC=$RC # Extract the first word of "windres", so it can be a program name with args. set dummy windres; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_RC"; then ac_cv_prog_ac_ct_RC="$ac_ct_RC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RC="windres" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RC=$ac_cv_prog_ac_ct_RC if test -n "$ac_ct_RC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RC" >&5 printf "%s\n" "$ac_ct_RC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_RC" = x; then RC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RC=$ac_ct_RC fi else RC="$ac_cv_prog_RC" fi CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD='${CC} -shared' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' PRACTCL_UNSHARED_LIB_SUFFIX='.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cross-compile version of gcc" >&5 printf %s "checking for cross-compile version of gcc... " >&6; } if test ${ac_cv_cross+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef _WIN32 #error cross-compiler #endif int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_cross=yes else $as_nop ac_cv_cross=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cross" >&5 printf "%s\n" "$ac_cv_cross" >&6; } if test "$ac_cv_cross" = "yes"; then case "$do64bit" in amd64|x64|yes) CC="x86_64-w64-mingw32-gcc" LD="x86_64-w64-mingw32-ld" AR="x86_64-w64-mingw32-ar" RANLIB="x86_64-w64-mingw32-ranlib" RC="x86_64-w64-mingw32-windres" ;; *) CC="i686-w64-mingw32-gcc" LD="i686-w64-mingw32-ld" AR="i686-w64-mingw32-ar" RANLIB="i686-w64-mingw32-ranlib" RC="i686-w64-mingw32-windres" ;; esac fi else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" if test "$doWince" != "no" ; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots ;; AIX-*) if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes" then : # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r|*_r\ *) # ok ... ;; *) # Make sure only first arg gets _r CC=`echo "$CC" | sed -e 's/^\([^ ]*\)/\1_r/'` ;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using $CC for compiling with threads" >&5 printf "%s\n" "Using $CC for compiling with threads" >&6; } fi LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_SUFFIX=".so" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = yes then : if test "$GCC" = yes then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 printf "%s\n" "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;} else $as_nop do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" fi fi if test "`uname -m`" = ia64 then : # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" if test "$GCC" = yes then : CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' else $as_nop CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' else $as_nop if test "$GCC" = yes then : SHLIB_LD='${CC} -shared -Wl,-bexpall' else $as_nop SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" LDFLAGS="$LDFLAGS -brtl" fi SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_SUFFIX=".so" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lbind" >&5 printf %s "checking for inet_ntoa in -lbind... " >&6; } if test ${ac_cv_lib_bind_inet_ntoa+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lbind $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char inet_ntoa (); int main (void) { return inet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_bind_inet_ntoa=yes else $as_nop ac_cv_lib_bind_inet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bind_inet_ntoa" >&5 printf "%s\n" "$ac_cv_lib_bind_inet_ntoa" >&6; } if test "x$ac_cv_lib_bind_inet_ntoa" = xyes then : LIBS="$LIBS -lbind -lsocket" fi ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; CYGWIN_*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$@.a" SHLIB_SUFFIX=".dll" EXEEXT=".exe" do64bit_ok=yes CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lnetwork" >&5 printf %s "checking for inet_ntoa in -lnetwork... " >&6; } if test ${ac_cv_lib_network_inet_ntoa+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnetwork $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char inet_ntoa (); int main (void) { return inet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_network_inet_ntoa=yes else $as_nop ac_cv_lib_network_inet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_inet_ntoa" >&5 printf "%s\n" "$ac_cv_lib_network_inet_ntoa" >&6; } if test "x$ac_cv_lib_network_inet_ntoa" = xyes then : LIBS="$LIBS -lnetwork" fi ;; HP-UX-*.11.*) # Use updated header definitions where possible printf "%s\n" "#define _XOPEN_SOURCE_EXTENDED 1" >>confdefs.h # TEA specific: Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library if test "`uname -m`" = ia64 then : SHLIB_SUFFIX=".so" # Use newer C++ library for C++ extensions #if test "$GCC" != "yes" ; then # CPPFLAGS="-AA" #fi else $as_nop SHLIB_SUFFIX=".sl" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 printf %s "checking for shl_load in -ldld... " >&6; } if test ${ac_cv_lib_dld_shl_load+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char shl_load (); int main (void) { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dld_shl_load=yes else $as_nop ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 printf "%s\n" "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes then : tcl_ok=yes else $as_nop tcl_ok=no fi if test "$tcl_ok" = yes then : LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" fi if test "$GCC" = yes then : SHLIB_LD='${CC} -shared' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} else $as_nop CFLAGS="$CFLAGS -z" # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" fi # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes" then : if test "$GCC" = yes then : case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 printf "%s\n" "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;} ;; esac else $as_nop do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" fi fi ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "$GCC" = yes then : CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" else $as_nop case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" fi ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = yes then : if test "$GCC" = yes then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported by gcc" >&5 printf "%s\n" "$as_me: WARNING: 64bit mode not supported by gcc" >&2;} else $as_nop do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" fi fi ;; Linux*|GNU*|NetBSD-Debian) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "`uname -m`" = "alpha" then : CFLAGS="$CFLAGS -mieee" fi if test $do64bit = yes then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -m64 flag" >&5 printf %s "checking if compiler accepts -m64 flag... " >&6; } if test ${tcl_cv_cc_m64+y} then : printf %s "(cached) " >&6 else $as_nop hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_cc_m64=yes else $as_nop tcl_cv_cc_m64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_m64" >&5 printf "%s\n" "$tcl_cv_cc_m64" >&6; } if test $tcl_cv_cc_m64 = yes then : CFLAGS="$CFLAGS -m64" do64bit_ok=yes fi fi # The combo of gcc + glibc has a bug related to inlining of # functions like strtod(). The -fno-builtin flag should address # this problem but it does not work. The -fno-inline flag is kind # of overkill but it works. Disable inlining only when one of the # files in compat/*.c is being linked in. if test x"${USE_COMPAT}" != x then : CFLAGS="$CFLAGS -fno-inline" fi ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' LD_FLAGS="-Wl,--export-dynamic" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi ;; OpenBSD-*) arch=`arch -s` case "$arch" in vax) SHLIB_SUFFIX="" SHARED_LIB_SUFFIX="" LDFLAGS="" ;; *) case "$arch" in alpha|sparc64) SHLIB_CFLAGS="-fPIC" ;; *) SHLIB_CFLAGS="-fpic" ;; esac SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}' LDFLAGS="-Wl,-export-dynamic" ;; esac case "$arch" in vax) CFLAGS_OPTIMIZE="-O1" ;; *) CFLAGS_OPTIMIZE="-O2" ;; esac if test "${TCL_THREADS}" = "1" then : # On OpenBSD: Compile with -pthread # Don't link with -lpthread LIBS=`echo $LIBS | sed s/-lpthread//` CFLAGS="$CFLAGS -pthread" fi # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*) # NetBSD has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "${TCL_THREADS}" = "1" then : # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi ;; FreeBSD-*) # This configuration from FreeBSD Ports. SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,-soname,\$@" SHLIB_SUFFIX=".so" LDFLAGS="" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi if test "${TCL_THREADS}" = "1" then : # The -pthread needs to go in the LDFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LDFLAGS="$LDFLAGS $PTHREAD_LIBS" fi case $system in FreeBSD-3.*) # Version numbers are dot-stripped by system policy. TCL_TRIM_DOTS=`echo ${PACKAGE_VERSION} | tr -d .` UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ($i~/^(isysroot|mmacosx-version-min)/) print "-"$i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!($i~/^(isysroot|mmacosx-version-min)/)) print "-"$i}'`" if test $do64bit = yes then : case `arch` in ppc) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch ppc64 flag" >&5 printf %s "checking if compiler accepts -arch ppc64 flag... " >&6; } if test ${tcl_cv_cc_arch_ppc64+y} then : printf %s "(cached) " >&6 else $as_nop hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_cc_arch_ppc64=yes else $as_nop tcl_cv_cc_arch_ppc64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_arch_ppc64" >&5 printf "%s\n" "$tcl_cv_cc_arch_ppc64" >&6; } if test $tcl_cv_cc_arch_ppc64 = yes then : CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes fi;; i386) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch x86_64 flag" >&5 printf %s "checking if compiler accepts -arch x86_64 flag... " >&6; } if test ${tcl_cv_cc_arch_x86_64+y} then : printf %s "(cached) " >&6 else $as_nop hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_cc_arch_x86_64=yes else $as_nop tcl_cv_cc_arch_x86_64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_arch_x86_64" >&5 printf "%s\n" "$tcl_cv_cc_arch_x86_64" >&6; } if test $tcl_cv_cc_arch_x86_64 = yes then : CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes fi;; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Don't know how enable 64-bit on architecture \`arch\`" >&5 printf "%s\n" "$as_me: WARNING: Don't know how enable 64-bit on architecture \`arch\`" >&2;};; esac else $as_nop # Check for combined 32-bit and 64-bit fat build if echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) ' then : fat_32_64=yes fi fi # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ld accepts -single_module flag" >&5 printf %s "checking if ld accepts -single_module flag... " >&6; } if test ${tcl_cv_ld_single_module+y} then : printf %s "(cached) " >&6 else $as_nop hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { int i; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_ld_single_module=yes else $as_nop tcl_cv_ld_single_module=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_single_module" >&5 printf "%s\n" "$tcl_cv_ld_single_module" >&6; } if test $tcl_cv_ld_single_module = yes then : SHLIB_LD="${SHLIB_LD} -Wl,-single_module" fi # TEA specific: link shlib with current and compatibility version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([0-9]\{1,5\}\)\(\(\.[0-9]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" SHLIB_SUFFIX=".dylib" # Don't use -prebind when building for Mac OS X 10.4 or later only: if test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int($2)}'`" -lt 4 -a \ "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int($2)}'`" -lt 4 then : LDFLAGS="$LDFLAGS -prebind" fi LDFLAGS="$LDFLAGS -headerpad_max_install_names" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if ld accepts -search_paths_first flag" >&5 printf %s "checking if ld accepts -search_paths_first flag... " >&6; } if test ${tcl_cv_ld_search_paths_first+y} then : printf %s "(cached) " >&6 else $as_nop hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { int i; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_ld_search_paths_first=yes else $as_nop tcl_cv_ld_search_paths_first=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_search_paths_first" >&5 printf "%s\n" "$tcl_cv_ld_search_paths_first" >&6; } if test $tcl_cv_ld_search_paths_first = yes then : LDFLAGS="$LDFLAGS -Wl,-search_paths_first" fi if test "$tcl_cv_cc_visibility_hidden" != yes then : printf "%s\n" "#define MODULE_SCOPE __private_extern__" >>confdefs.h tcl_cv_cc_visibility_hidden=yes fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for combined 32 & 64 bit fat builds of Tk # extensions, verify that 64-bit build is possible. if test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}" then : if test "${TEA_WINDOWINGSYSTEM}" = x11 then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit X11" >&5 printf %s "checking for 64-bit X11... " >&6; } if test ${tcl_cv_lib_x11_64+y} then : printf %s "(cached) " >&6 else $as_nop for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { XrmInitialize(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_lib_x11_64=yes else $as_nop tcl_cv_lib_x11_64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_lib_x11_64" >&5 printf "%s\n" "$tcl_cv_lib_x11_64" >&6; } fi if test "${TEA_WINDOWINGSYSTEM}" = aqua then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit Tk" >&5 printf %s "checking for 64-bit Tk... " >&6; } if test ${tcl_cv_lib_tk_64+y} then : printf %s "(cached) " >&6 else $as_nop for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { Tk_InitStubs(NULL, "", 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_lib_tk_64=yes else $as_nop tcl_cv_lib_tk_64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_lib_tk_64" >&5 printf "%s\n" "$tcl_cv_lib_tk_64" >&6; } fi # remove 64-bit arch flags from CFLAGS et al. if configuration # does not support 64-bit. if test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Removing 64-bit architectures from compiler & linker flags" >&5 printf "%s\n" "$as_me: Removing 64-bit architectures from compiler & linker flags" >&6;} for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done fi fi ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy printf "%s\n" "#define _OE_SOCKETS 1" >>confdefs.h ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" if test "$SHARED_BUILD" = 1 then : SHLIB_LD='ld -shared -expect_unresolved "*"' else $as_nop SHLIB_LD='ld -non_shared -expect_unresolved "*"' fi SHLIB_SUFFIX=".so" if test $doRpath = yes then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "$GCC" = yes then : CFLAGS="$CFLAGS -mieee" else $as_nop CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee" fi # see pthread_intro(3) for pthread support on osf1, k.furukawa if test "${TCL_THREADS}" = 1 then : CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` if test "$GCC" = yes then : LIBS="$LIBS -lpthread -lmach -lexc" else $as_nop CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi fi ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) if test "$GCC" = yes then : SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" else $as_nop SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" fi SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-5.[0-6]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. printf "%s\n" "#define _REENTRANT 1" >>confdefs.h printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h SHLIB_CFLAGS="-KPIC" SHLIB_SUFFIX=".so" if test "$GCC" = yes then : SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} else $as_nop SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. printf "%s\n" "#define _REENTRANT 1" >>confdefs.h printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = yes then : arch=`isainfo` if test "$arch" = "sparcv9 sparc" then : if test "$GCC" = yes then : if test "`${CC} -dumpversion | awk -F. '{print $1}'`" -lt 3 then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&5 printf "%s\n" "$as_me: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&2;} else $as_nop do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" fi else $as_nop do64bit_ok=yes if test "$do64bitVIS" = yes then : CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" else $as_nop CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" fi # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" fi else $as_nop if test "$arch" = "amd64 i386" then : if test "$GCC" = yes then : case $system in SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 printf "%s\n" "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;};; esac else $as_nop do64bit_ok=yes case $system in SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac fi else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported for $arch" >&5 printf "%s\n" "$as_me: WARNING: 64bit mode not supported for $arch" >&2;} fi fi fi SHLIB_SUFFIX=".so" if test "$GCC" = yes then : SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "$do64bit_ok" = yes then : if test "$arch" = "sparcv9 sparc" then : # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" else $as_nop if test "$arch" = "amd64 i386" then : # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" fi fi fi else $as_nop case $system in SunOS-5.[1-9][0-9]*) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' fi ;; UNIX_SV* | UnixWare-5*) SHLIB_CFLAGS="-KPIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers # that don't grok the -Bexport option. Test that it does. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld accepts -Bexport flag" >&5 printf %s "checking for ld accepts -Bexport flag... " >&6; } if test ${tcl_cv_ld_Bexport+y} then : printf %s "(cached) " >&6 else $as_nop hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-Bexport" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { int i; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : tcl_cv_ld_Bexport=yes else $as_nop tcl_cv_ld_Bexport=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_Bexport" >&5 printf "%s\n" "$tcl_cv_ld_Bexport" >&6; } if test $tcl_cv_ld_Bexport = yes then : LDFLAGS="$LDFLAGS -Wl,-Bexport" fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; esac if test "$do64bit" = yes -a "$do64bit_ok" = no then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 64bit support being disabled -- don't know magic for this platform" >&5 printf "%s\n" "$as_me: WARNING: 64bit support being disabled -- don't know magic for this platform" >&2;} fi # Add in the arch flags late to ensure it wasn't removed. # Not necessary in TEA, but this is aligned with core LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. if test "$GCC" = yes then : case $system in AIX-*) ;; BSD/OS*) ;; CYGWIN_*|MINGW32_*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*|OpenBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; windows) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac fi if test "$tcl_cv_cc_visibility_hidden" != yes then : printf "%s\n" "#define MODULE_SCOPE extern" >>confdefs.h fi if test "$SHARED_LIB_SUFFIX" = "" then : # TEA specific: use PACKAGE_VERSION instead of VERSION SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}' fi if test "$UNSHARED_LIB_SUFFIX" = "" then : # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a' fi if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SEH support in compiler" >&5 printf %s "checking for SEH support in compiler... " >&6; } if test ${tcl_cv_seh+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : tcl_cv_seh=no else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN int main(int argc, char** argv) { int a, b = 0; __try { a = 666 / b; } __except (EXCEPTION_EXECUTE_HANDLER) { return 0; } return 1; } _ACEOF if ac_fn_c_try_run "$LINENO" then : tcl_cv_seh=yes else $as_nop tcl_cv_seh=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_seh" >&5 printf "%s\n" "$tcl_cv_seh" >&6; } if test "$tcl_cv_seh" = "no" ; then printf "%s\n" "#define HAVE_NO_SEH 1" >>confdefs.h fi # # Check to see if the excpt.h include file provided contains the # definition for EXCEPTION_DISPOSITION; if not, which is the case # with Cygwin's version as of 2002-04-10, define it to be int, # sufficient for getting the current code to work. # { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for EXCEPTION_DISPOSITION support in include files" >&5 printf %s "checking for EXCEPTION_DISPOSITION support in include files... " >&6; } if test ${tcl_cv_eh_disposition+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # define WIN32_LEAN_AND_MEAN # include # undef WIN32_LEAN_AND_MEAN int main (void) { EXCEPTION_DISPOSITION x; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_eh_disposition=yes else $as_nop tcl_cv_eh_disposition=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_eh_disposition" >&5 printf "%s\n" "$tcl_cv_eh_disposition" >&6; } if test "$tcl_cv_eh_disposition" = "no" ; then printf "%s\n" "#define EXCEPTION_DISPOSITION int" >>confdefs.h fi # Check to see if winnt.h defines CHAR, SHORT, and LONG # even if VOID has already been #defined. The win32api # used by mingw and cygwin is known to do this. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for winnt.h that ignores VOID define" >&5 printf %s "checking for winnt.h that ignores VOID define... " >&6; } if test ${tcl_cv_winnt_ignore_void+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define VOID void #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN int main (void) { CHAR c; SHORT s; LONG l; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_winnt_ignore_void=yes else $as_nop tcl_cv_winnt_ignore_void=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_winnt_ignore_void" >&5 printf "%s\n" "$tcl_cv_winnt_ignore_void" >&6; } if test "$tcl_cv_winnt_ignore_void" = "yes" ; then printf "%s\n" "#define HAVE_WINNT_IGNORE_VOID 1" >>confdefs.h fi fi # See if the compiler supports casting to a union type. # This is used to stop gcc from printing a compiler # warning when initializing a union member. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cast to union support" >&5 printf %s "checking for cast to union support... " >&6; } if test ${tcl_cv_cast_to_union+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { union foo { int i; double d; }; union foo f = (union foo) (int) 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_cast_to_union=yes else $as_nop tcl_cv_cast_to_union=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cast_to_union" >&5 printf "%s\n" "$tcl_cv_cast_to_union" >&6; } if test "$tcl_cv_cast_to_union" = "yes"; then printf "%s\n" "#define HAVE_CAST_TO_UNION 1" >>confdefs.h fi # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for required early compiler flags" >&5 printf %s "checking for required early compiler flags... " >&6; } tcl_flags="" if test ${tcl_cv_flag__isoc99_source+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { char *p = (char *)strtoll; char *q = (char *)strtoull; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_flag__isoc99_source=no else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _ISOC99_SOURCE 1 #include int main (void) { char *p = (char *)strtoll; char *q = (char *)strtoull; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_flag__isoc99_source=yes else $as_nop tcl_cv_flag__isoc99_source=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "x${tcl_cv_flag__isoc99_source}" = "xyes" ; then printf "%s\n" "#define _ISOC99_SOURCE 1" >>confdefs.h tcl_flags="$tcl_flags _ISOC99_SOURCE" fi if test ${tcl_cv_flag__largefile64_source+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { struct stat64 buf; int i = stat64("/", &buf); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_flag__largefile64_source=no else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE64_SOURCE 1 #include int main (void) { struct stat64 buf; int i = stat64("/", &buf); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_flag__largefile64_source=yes else $as_nop tcl_cv_flag__largefile64_source=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "x${tcl_cv_flag__largefile64_source}" = "xyes" ; then printf "%s\n" "#define _LARGEFILE64_SOURCE 1" >>confdefs.h tcl_flags="$tcl_flags _LARGEFILE64_SOURCE" fi if test ${tcl_cv_flag__largefile_source64+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { char *p = (char *)open64; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_flag__largefile_source64=no else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE_SOURCE64 1 #include int main (void) { char *p = (char *)open64; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_flag__largefile_source64=yes else $as_nop tcl_cv_flag__largefile_source64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "x${tcl_cv_flag__largefile_source64}" = "xyes" ; then printf "%s\n" "#define _LARGEFILE_SOURCE64 1" >>confdefs.h tcl_flags="$tcl_flags _LARGEFILE_SOURCE64" fi if test "x${tcl_flags}" = "x" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5 printf "%s\n" "none" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${tcl_flags}" >&5 printf "%s\n" "${tcl_flags}" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit integer type" >&5 printf %s "checking for 64-bit integer type... " >&6; } if test ${tcl_cv_type_64bit+y} then : printf %s "(cached) " >&6 else $as_nop tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { __int64 value = (__int64) 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_type_64bit=__int64 else $as_nop tcl_type_64bit="long long" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { switch (0) { case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ; } ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_type_64bit=${tcl_type_64bit} fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "${tcl_cv_type_64bit}" = none ; then printf "%s\n" "#define TCL_WIDE_INT_IS_LONG 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: using long" >&5 printf "%s\n" "using long" >&6; } elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # TEA specific: We actually want to use the default tcl.h checks in # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: using Tcl header defaults" >&5 printf "%s\n" "using Tcl header defaults" >&6; } else printf "%s\n" "#define TCL_WIDE_INT_TYPE ${tcl_cv_type_64bit}" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${tcl_cv_type_64bit}" >&5 printf "%s\n" "${tcl_cv_type_64bit}" >&6; } # Now check for auxiliary declarations { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct dirent64" >&5 printf %s "checking for struct dirent64... " >&6; } if test ${tcl_cv_struct_dirent64+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main (void) { struct dirent64 p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_struct_dirent64=yes else $as_nop tcl_cv_struct_dirent64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_struct_dirent64" >&5 printf "%s\n" "$tcl_cv_struct_dirent64" >&6; } if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then printf "%s\n" "#define HAVE_STRUCT_DIRENT64 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct stat64" >&5 printf %s "checking for struct stat64... " >&6; } if test ${tcl_cv_struct_stat64+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { struct stat64 p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_struct_stat64=yes else $as_nop tcl_cv_struct_stat64=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_struct_stat64" >&5 printf "%s\n" "$tcl_cv_struct_stat64" >&6; } if test "x${tcl_cv_struct_stat64}" = "xyes" ; then printf "%s\n" "#define HAVE_STRUCT_STAT64 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "open64" "ac_cv_func_open64" if test "x$ac_cv_func_open64" = xyes then : printf "%s\n" "#define HAVE_OPEN64 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "lseek64" "ac_cv_func_lseek64" if test "x$ac_cv_func_lseek64" = xyes then : printf "%s\n" "#define HAVE_LSEEK64 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for off64_t" >&5 printf %s "checking for off64_t... " >&6; } if test ${tcl_cv_type_off64_t+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { off64_t offset; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : tcl_cv_type_off64_t=yes else $as_nop tcl_cv_type_off64_t=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then printf "%s\n" "#define HAVE_TYPE_OFF64_T 1" >>confdefs.h { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols option. #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build with symbols" >&5 printf %s "checking for build with symbols... " >&6; } # Check whether --enable-symbols was given. if test ${enable_symbols+y} then : enableval=$enable_symbols; tcl_ok=$enableval else $as_nop tcl_ok=no fi DBGX="" if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (standard debugging)" >&5 printf "%s\n" "yes (standard debugging)" >&6; } fi fi # TEA specific: if test "${TEA_PLATFORM}" != "windows" ; then LDFLAGS_DEFAULT="${LDFLAGS}" fi if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then printf "%s\n" "#define TCL_MEM_DEBUG 1" >>confdefs.h fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: enabled symbols mem debugging" >&5 printf "%s\n" "enabled symbols mem debugging" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: enabled $tcl_ok debugging" >&5 printf "%s\n" "enabled $tcl_ok debugging" >&6; } fi fi #-------------------------------------------------------------------- # Everyone should be linking against the Tcl stub library. If you # can't for some reason, remove this definition. If you aren't using # stubs, you also need to modify the SHLIB_LD_LIBS setting below to # link against the non-stubbed Tcl library. Add Tk too if necessary. #-------------------------------------------------------------------- printf "%s\n" "#define USE_TCL_STUBS 1" >>confdefs.h #AC_DEFINE([USE_TK_STUBS]) if test "$enable_development" = yes; then printf "%s\n" "#define NSF_DEVELOPMENT 1" >>confdefs.h fi #-------------------------------------------------------------------- # This macro generates a line to use when building a library. It # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, # and TEA_LOAD_TCLCONFIG macros above. #-------------------------------------------------------------------- PRACTCL_TOOLSET="gcc" PRACTCL_VC_MANIFEST_EMBED_DLL=: PRACTCL_VC_MANIFEST_EMBED_EXE=: if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then PRACTCL_TOOLSET="msvc" PRACTCL_STATIC_LIB="%STLIB_LD% -out:%OUTFILE% %LIBRARY_OBJECTS%" PRACTCL_SHARED_LIB="%SHLIB_LD% %SHLIB_LD_LIBS% %LDFLAGS_DEFAULT% -out:%OUTFILE% %LIBRARY_OBJECTS%" MAKE_STATIC_LIB="\${STLIB_LD} -out:\$@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\$@ \$(PKG_OBJECTS)" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined(_MSC_VER) && _MSC_VER >= 1400 print("manifest needed") #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "manifest needed" >/dev/null 2>&1 then : # Could do a CHECK_PROG for mt, but should always be with MSVC8+ PRACTCL_VC_MANIFEST_EMBED_DLL="mt.exe -nologo -manifest %OUTFILE%.manifest -outputresource:%OUTFILE%\;2" PRACTCL_VC_MANIFEST_EMBED_EXE="mt.exe -nologo -manifest %OUTFILE%.manifest -outputresource:%OUTFILE%\;1" VC_MANIFEST_EMBED_DLL="if test -f \$@.manifest ; then mt.exe -nologo -manifest \$@.manifest -outputresource:\$@\;2 ; fi" VC_MANIFEST_EMBED_EXE="if test -f \$@.manifest ; then mt.exe -nologo -manifest \$@.manifest -outputresource:\$@\;1 ; fi" MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" CLEANFILES="$CLEANFILES *.manifest" fi rm -rf conftest* PRACTCL_STUB_LIB="%STLIB_LD% -nodefaultlib -out:%OUTFILE% %LIBRARY_OBJECTS%" MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\$@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \$@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} -o \$@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \$@ \$(PKG_STUB_OBJECTS)" PRACTCL_STATIC_LIB="%STLIB_LD% %OUTFILE% %LIBRARY_OBJECTS%" PRACTCL_SHARED_LIB="%SHLIB_LD% -o %OUTFILE% %LIBRARY_OBJECTS% %SHLIB_LD_LIBS%" PRACTCL_STUB_LIB="%STLIB_LD% %OUTFILE% %LIBRARY_OBJECTS%" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}" PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9" if test "${TCL_MAJOR_VERSION}" -gt 8 ; then PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}" else PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}" fi if test "${TEA_PLATFORM}" = "windows" ; then PRACTCL_NAME_LIBRARY="%LIBRARY_PREFIX%%LIBRARY_NAME%%LIBRARY_VERSION_NODOTS%" if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test "$GCC" = "yes"; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc" fi eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_LIB_FILE=lib${PKG_LIB_FILE} fi fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else PRACTCL_NAME_LIBRARY="lib%LIBRARY_PREFIX%%LIBRARY_NAME%%LIBRARY_VERSION%" RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # Store the raw CFLAGS before we add the trimmings PRACTCL_CFLAGS=${CFLAGS} # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi #-------------------------------------------------------------------- # Find tclsh so that we can run pkg_mkIndex to generate the pkgIndex.tcl # file during the install process. Don't run the TCLSH_PROG through # ${CYGPATH} because it's being used directly by make. # Require that we use a tclsh shell version 8.2 or later since earlier # versions have bugs in the pkg_mkIndex routine. # Add WISH as well if this is a Tk extension. #-------------------------------------------------------------------- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for tclsh" >&5 printf %s "checking for tclsh... " >&6; } # Check whether --with-tclsh was given. if test ${with_tclsh+y} then : withval=$with_tclsh; with_tclsh=${withval} fi # Use the value from --with-tclsh, if it was given TCLSH_PROG=0 if test x"${with_tclsh}" != x ; then if test -f "${with_tclsh}" ; then TCLSH_PROG=${with_tclsh} else if test -f "${with_tclsh}/tcl8.6" ; then TCLSH_PROG="${with_tclsh}/tcl8.6" else if test -f "${with_tclsh}/tclsh86.exe" ; then TCLSH_PROG="${with_tclsh}/tclsh86.exe" else as_fn_error $? "${with_tclsh} does not point to a valid Tcl executable" "$LINENO" 5 fi fi fi else if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" fi else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${TCLSH_PROG}" >&5 printf "%s\n" "${TCLSH_PROG}" >&6; } #TEA_PROG_WISH #-------------------------------------------------------------------- # Finally, substitute all of the various values into the Makefile. # You may alternatively have a special pkgIndex.tcl.in or other files # which require substituting th AC variables in. Include these here. #-------------------------------------------------------------------- ac_config_files="$ac_config_files Makefile pkgIndex.add" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS="" : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by nsfmongo $as_me 2.4.0, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ nsfmongo config.status 2.4.0 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "pkgIndex.add") CONFIG_FILES="$CONFIG_FILES pkgIndex.add" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi ./nsf2.4.0/library/mongodb/example-nx-wiki0.tcl000644 000766 000024 00000002312 12440120610 022050 0ustar00neumannstaff000000 000000 package require nx::mongo package require nx::serializer package require nx::test # Establish connection to the database ::nx::mongo::db connect -db "tutorial" # Make sure, we start always from scratch, so remove everything from # the collection. nx::mongo::db remove tutorial.pages {} nx::mongo::Class create nx::mongo::Content { :property text:optional :property mime_type:optional } # item_id, (revision_id != 0) ? nx::mongo::Class create nx::mongo::Page { :index tags :property name:required :property title:optional :property creator:optional :property page_order:optional :property description:optional :property nls_language:optional ;# en, es, de, ... | locale: en_US, ... :property creation_user:integer,required ;# openacs-id? openacs-fk? user_id? :property publish_date:required :property publish_status:required :property content:embedded,type=::nx::mongo::Content :property page_template:optional ;# openacs-id? :property instance_attributes:optional ;# attributes? :property assignee ;# openacs-id? openacs-fk? user_id? :property state :property form :property form_constraints :property tags:incremental,0..n } ./nsf2.4.0/library/mongodb/nsfmongo.c000644 000766 000024 00000164615 14260773731 020302 0ustar00neumannstaff000000 000000 /* * Interface between MongoDB based on NSF (Next Scripting * Framework) * * This implementation provides a low-level interface based on tagged elements * to force / preserve the datatypes of MongoDB when converting into Tcl. * * This code serves as well as an example how to use the source code generator * of NSF. The example shows how to use the source code generator from NSF to * generate a C interface. * * -gustaf neumann March 27, 2011 * * Copyright (C) 2011-2021 Gustaf Neumann */ #include #include #include #include "bson.h" #include "mongoc.h" #include #include #include #define USE_CLIENT_POOL 1 /* * Size of handle as used by Nsf_PointerAdd() */ #define POINTER_HANDLE_SIZE 80u /* * Define the counters to generate nice symbols for pointer converter */ static int gridfileCount = 0; static int gridfsCount = 0; static int mongoClientCount = 0; static int mongoCollectionCount = 0; static int mongoCursorCount = 0; #if defined(USE_CLIENT_POOL) static NsfMutex poolMutex = 0; static mongoc_client_pool_t *mongoClientPool = NULL; static int mongoClientPoolRefCount = 0; static mongoc_uri_t *mongoUri = NULL; #endif typedef enum { NSF_BSON_ARRAY, NSF_BSON_BINARY, NSF_BSON_BOOL, NSF_BSON_INT32, NSF_BSON_INT64, NSF_BSON_DATE_TIME, NSF_BSON_DECIMAL128, NSF_BSON_DOCUMENT, NSF_BSON_DOUBLE, NSF_BSON_MINKEY, NSF_BSON_MAXKEY, NSF_BSON_NULL, NSF_BSON_OID, NSF_BSON_REGEX, NSF_BSON_STRING, NSF_BSON_TIMESTAMP, NSF_BSON_UNKNOWN } nsfMongoTypes; static const char * NsfMongoGlobalStrings[] = { "array", "binary", "boolean", "int32", "int64", "datetime", "decimal128", "document", "double", "minkey", "maxkey", "null", "oid", "regex", "string", "timestamp", "unknown", NULL }; static Tcl_Obj **NsfMongoGlobalObjs = NULL; static Tcl_Obj *BsonToList(Tcl_Interp *interp, const bson_t *data , int depth); static bson_type_t BsonTagToType(Tcl_Interp *interp, Tcl_Obj *tagObj); extern Tcl_PackageInitProc Nsfmongo_SafeInit; extern Tcl_PackageInitProc Nsfmongo_Init; static Tcl_ExitProc Nsfmongo_Exit; static Tcl_ExitProc Nsfmongo_ThreadExit; Nsf_TypeConverter Nsf_ConvertTo_Boolean; Nsf_TypeConverter Nsf_ConvertTo_Class; Nsf_TypeConverter Nsf_ConvertTo_Int32; Nsf_TypeConverter Nsf_ConvertTo_Integer; Nsf_TypeConverter Nsf_ConvertTo_Object; Nsf_TypeConverter Nsf_ConvertTo_Pointer; Nsf_TypeConverter Nsf_ConvertTo_String; Nsf_TypeConverter Nsf_ConvertTo_Tclobj; /*********************************************************************** * The following definitions should not be here, but they are included * to get compilation going for the time being. ***********************************************************************/ typedef void *NsfObject; #define PARSE_CONTEXT_PREALLOC 20 typedef struct { ClientData *clientData; /* 4 members pointer to the actual parse context data */ Tcl_Obj **objv; Tcl_Obj **full_objv; /* contains method as well */ unsigned int *flags; ClientData clientData_static[PARSE_CONTEXT_PREALLOC]; /* 3 members preallocated parse context data */ Tcl_Obj *objv_static[PARSE_CONTEXT_PREALLOC+1]; unsigned int flags_static[PARSE_CONTEXT_PREALLOC+1]; unsigned int status; int lastObjc; /* points to the first "unprocessed" argument */ int objc; NsfObject *object; int varArgs; /* does the parameter end with some kind of "args" */ } ParseContext; #define nr_elements(arr) ((int) (sizeof(arr) / sizeof(arr[0]))) #define ObjStr(obj) (obj)->bytes ? (obj)->bytes : Tcl_GetString(obj) #ifdef UNUSED #elif defined(__GNUC__) # define UNUSED(x) UNUSED_ ## x __attribute__((unused)) #elif defined(__LCLINT__) # define UNUSED(x) /*@unused@*/ x #else # define UNUSED(x) x #endif #if defined(HAVE_STDINT_H) # define HAVE_INTPTR_T # define HAVE_UINTPTR_T #endif #if !defined(INT2PTR) && !defined(PTR2INT) # if defined(HAVE_INTPTR_T) || defined(intptr_t) # define INT2PTR(p) ((void *)(intptr_t)(p)) # define PTR2INT(p) ((int)(intptr_t)(p)) # else # define INT2PTR(p) ((void *)(p)) # define PTR2INT(p) ((int)(p)) # endif #endif #if !defined(UINT2PTR) && !defined(PTR2UINT) # if defined(HAVE_UINTPTR_T) || defined(uintptr_t) # define UINT2PTR(p) ((void *)(uintptr_t)(p)) # define PTR2UINT(p) ((unsigned int)(uintptr_t)(p)) # else # define UINT2PTR(p) ((void *)(p)) # define PTR2UINT(p) ((unsigned int)(p)) # endif #endif static int ArgumentParse(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], NsfObject *obj, Tcl_Obj *procName, Nsf_Param const *paramPtr, int nrParameters, int serial, unsigned int processFlags, ParseContext *pc) { return Nsf_ArgumentParse(interp, objc, objv, (Nsf_Object *)obj, procName, paramPtr, nrParameters, serial, processFlags, (Nsf_ParseContext *)pc); } /*********************************************************************** * Include the generated mongo db API. ***********************************************************************/ #include "mongoAPI.h" /*********************************************************************** * Helper functions ***********************************************************************/ /* *---------------------------------------------------------------------- * * BsonToList -- * * Convert a bson_t structure to a tagged list. Each value field is * preceded by a tag denoting its bson type. * * Results: * Tagged list. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Obj * BsonToList(Tcl_Interp *interp, const bson_t *data , int depth) { bson_iter_t i; char oidhex[25]; Tcl_Obj *resultObj, *elemObj; bson_iter_init( &i , data ); resultObj = Tcl_NewListObj(0, NULL); while ( bson_iter_next( &i ) ){ bson_type_t t = bson_iter_type( &i ); nsfMongoTypes tag; const char *key; if ( t == 0 ) break; key = bson_iter_key( &i ); /*fprintf(stderr, "BsonToList: key %s t %d string %d\n", key, t, bson_string);*/ switch ( t ){ case BSON_TYPE_INT32: tag = NSF_BSON_INT32; elemObj = Tcl_NewIntObj(bson_iter_int32( &i )); break; case BSON_TYPE_INT64: tag = NSF_BSON_INT64; elemObj = Tcl_NewLongObj(bson_iter_int64( &i )); break; case BSON_TYPE_DATE_TIME: tag = NSF_BSON_DATE_TIME; elemObj = Tcl_NewLongObj(bson_iter_date_time( &i )); break; case BSON_TYPE_DOUBLE: tag = NSF_BSON_DOUBLE; elemObj = Tcl_NewDoubleObj(bson_iter_double( &i )); break; case BSON_TYPE_BOOL: tag = NSF_BSON_BOOL; elemObj = Tcl_NewBooleanObj(bson_iter_bool( &i )); break; case BSON_TYPE_REGEX: { const char *options = NULL, *regex; tag = NSF_BSON_REGEX; regex = bson_iter_regex( &i, &options ); elemObj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, elemObj, Tcl_NewStringObj(regex, TCL_INDEX_NONE)); Tcl_ListObjAppendElement(interp, elemObj, Tcl_NewStringObj(options, TCL_INDEX_NONE)); break; } case BSON_TYPE_UTF8: { uint32_t utf8_len; const char *string = bson_iter_utf8( &i, &utf8_len); /*fprintf(stderr, "append UTF8: <%s> %d\n", string, utf8_len);*/ tag = NSF_BSON_STRING; elemObj = Tcl_NewStringObj(string, (int)utf8_len); break; } case BSON_TYPE_MINKEY: tag = NSF_BSON_MINKEY; elemObj = Tcl_NewStringObj("null", 4); break; case BSON_TYPE_MAXKEY: tag = NSF_BSON_MAXKEY; elemObj = Tcl_NewStringObj("null", 4); break; case BSON_TYPE_NULL: tag = NSF_BSON_NULL; elemObj = Tcl_NewStringObj("null", 4); break; case BSON_TYPE_OID: { tag = NSF_BSON_OID; bson_oid_to_string(bson_iter_oid(&i), oidhex); elemObj = Tcl_NewStringObj(oidhex, TCL_INDEX_NONE); break; } case BSON_TYPE_TIMESTAMP: { uint32_t timestamp, increment; tag = NSF_BSON_TIMESTAMP; bson_iter_timestamp( &i, ×tamp, &increment ); elemObj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, elemObj, Tcl_NewLongObj((long)timestamp)); Tcl_ListObjAppendElement(interp, elemObj, Tcl_NewLongObj((long)increment)); break; } case BSON_TYPE_DOCUMENT: { const uint8_t *docbuf = NULL; uint32_t doclen = 0; bson_t b; tag = NSF_BSON_DOCUMENT; bson_iter_document(&i, &doclen, &docbuf); bson_init_static(&b, docbuf, doclen); elemObj = BsonToList(interp, &b , depth + 1 ); break; } case BSON_TYPE_ARRAY: { const uint8_t *docbuf = NULL; uint32_t doclen = 0; bson_t b; tag = NSF_BSON_ARRAY; bson_iter_array(&i, &doclen, &docbuf); bson_init_static(&b, docbuf, doclen); elemObj = BsonToList(interp, &b , depth + 1 ); break; } case BSON_TYPE_DECIMAL128: { bson_decimal128_t decimal128; char string[BSON_DECIMAL128_STRING]; tag = NSF_BSON_DECIMAL128; bson_iter_decimal128( &i, &decimal128); bson_decimal128_to_string(&decimal128, string); elemObj = Tcl_NewStringObj(string, TCL_INDEX_NONE); break; } case BSON_TYPE_BINARY: { uint32_t length; const uint8_t *bytes; tag = NSF_BSON_BINARY; bson_iter_binary( &i, NULL /* subtype_t */, &length, &bytes); elemObj = Tcl_NewByteArrayObj(bytes, (int)length); break; } case BSON_TYPE_CODE: NSF_FALL_THROUGH; /* fall through */ case BSON_TYPE_CODEWSCOPE: NSF_FALL_THROUGH; /* fall through */ case BSON_TYPE_DBPOINTER: NSF_FALL_THROUGH; /* fall through */ case BSON_TYPE_EOD: NSF_FALL_THROUGH; /* fall through */ case BSON_TYPE_SYMBOL: NSF_FALL_THROUGH; /* fall through */ case BSON_TYPE_UNDEFINED: NSF_FALL_THROUGH; /* fall through */ default: tag = NSF_BSON_UNKNOWN; elemObj = Tcl_NewStringObj("", 0); NsfLog(interp, NSF_LOG_WARN, "BsonToList: unknown type %d", t); } Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(key, TCL_INDEX_NONE)); Tcl_ListObjAppendElement(interp, resultObj, NsfMongoGlobalObjs[tag]); Tcl_ListObjAppendElement(interp, resultObj, elemObj); } return resultObj; } /* *---------------------------------------------------------------------- * * BsonTagToType -- * * Convert a bson tag string to a bson_type. For the time being * we compare as little as possible characters. In the future we * might want to cache the bson tag in the Tcl_obj, maybe we can * use Tcl_GetIndexFromObj(); * * Results: * bson_type. * * Side effects: * None. * *---------------------------------------------------------------------- */ bson_type_t BsonTagToType(Tcl_Interp *interp, Tcl_Obj *tagObj) { const char *tag = ObjStr(tagObj); char firstChar = *tag; switch (firstChar) { case 'a': /* array */ return BSON_TYPE_ARRAY; case 'b': /* bool */ return BSON_TYPE_BOOL; case 'd': if (*(tag + 1) == 'a') /* date */ return BSON_TYPE_DATE_TIME; if (*(tag + 1) == 'o' && *(tag + 2) == 'c') /* document */ return BSON_TYPE_DOCUMENT; if (*(tag + 1) == 'o' && *(tag + 2) == 'u') /* double */ return BSON_TYPE_DOUBLE; break; case 'i': /* int32|64 */ if (*(tag + 1) == 'n' && *(tag + 2) == 't' && *(tag + 3) == '3') return BSON_TYPE_INT32; if (*(tag + 1) == 'n' && *(tag + 2) == 't' && *(tag + 3) == '6') return BSON_TYPE_INT64; if (*(tag + 1) == 'n' && *(tag + 2) == 't') return BSON_TYPE_INT32; break; case 'm': if (*(tag + 1) == 'i') /* minkey */ return BSON_TYPE_MINKEY; if (*(tag + 1) == 'a') /* maxkey */ return BSON_TYPE_MAXKEY; break; case 'n': /* null */ return BSON_TYPE_NULL; case 'o': if (*(tag + 1) == 'i') /* oid */ return BSON_TYPE_OID; break; case 'r': /* regex */ return BSON_TYPE_REGEX; case 's': /* string */ return BSON_TYPE_UTF8; case 't': /* timestamp */ return BSON_TYPE_TIMESTAMP; } NsfLog(interp, NSF_LOG_WARN, "BsonTagToType: Treat unknown tag '%s' as string", tag); return BSON_TYPE_UTF8; } /* *---------------------------------------------------------------------- * * BsonAppend -- * * append a tagged element to a bson buffer. * * Results: * A standard Tcl result. * * Side effects: * Value appended to bson buffer. * *---------------------------------------------------------------------- */ static int BsonAppend(Tcl_Interp *interp, bson_t *bbPtr, Tcl_Obj *nameObj, Tcl_Obj *tagObj, Tcl_Obj *value) { int result = TCL_OK; bson_type_t t = BsonTagToType(interp, tagObj); int keyLength; const char *name = Tcl_GetStringFromObj(nameObj, &keyLength); /*fprintf(stderr, "BsonAppend: add name %s tag %s value '%s'\n", name, tag, ObjStr(value));*/ switch ( t ){ case BSON_TYPE_UTF8: { int stringLength; const char* string = Tcl_GetStringFromObj(value, &stringLength); bson_append_utf8(bbPtr, name, keyLength, string, stringLength); break; } case BSON_TYPE_INT32: { int32_t v; result = Tcl_GetIntFromObj(interp, value, &v); if (result != TCL_OK) break; bson_append_int32(bbPtr, name, keyLength, v); break; } case BSON_TYPE_DOUBLE: { double v; result = Tcl_GetDoubleFromObj(interp, value, &v); if (result != TCL_OK) break; bson_append_double(bbPtr, name, keyLength, v); break; } case BSON_TYPE_BOOL: { int v; result = Tcl_GetBooleanFromObj(interp, value, &v); if (result != TCL_OK) break; bson_append_bool(bbPtr, name, keyLength, v); break; } case BSON_TYPE_INT64: { long v; result = Tcl_GetLongFromObj(interp, value, &v); if (result != TCL_OK) break; bson_append_int64(bbPtr, name, keyLength, v); break; } case BSON_TYPE_MAXKEY: bson_append_maxkey(bbPtr, name, keyLength); break; case BSON_TYPE_MINKEY: bson_append_minkey(bbPtr, name, keyLength); break; case BSON_TYPE_NULL: { bson_append_null(bbPtr, name, keyLength); break; } case BSON_TYPE_OID: { bson_oid_t v; bson_oid_init_from_string(&v, ObjStr(value)); bson_append_oid(bbPtr, name, keyLength, &v); break; } case BSON_TYPE_REGEX: { int objc = 0; Tcl_Obj **objv; result = Tcl_ListObjGetElements(interp, value, &objc, &objv); if (result != TCL_OK || objc != 2) { return NsfPrintError(interp, "invalid regexp representation: %s", ObjStr(value)); } bson_append_regex(bbPtr, name, keyLength, ObjStr(objv[0]), ObjStr(objv[1])); break; } case BSON_TYPE_DATE_TIME: { long v; result = Tcl_GetLongFromObj(interp, value, &v); if (result != TCL_OK) break; bson_append_date_time(bbPtr, name, keyLength, v); break; } case BSON_TYPE_TIMESTAMP: { int timestamp = 0, increment = 0, objc = 0; Tcl_Obj **objv; result = Tcl_ListObjGetElements(interp, value, &objc, &objv); if (result != TCL_OK || objc != 2) { return NsfPrintError(interp, "invalid timestamp: %s", ObjStr(value)); } else { result = Tcl_GetIntFromObj(interp, objv[0], ×tamp); if (result == TCL_OK) { result = Tcl_GetIntFromObj(interp, objv[1], &increment); } if (result == TCL_OK) { bson_append_timestamp(bbPtr, name, keyLength, (uint32_t)timestamp, (uint32_t)increment); } } break; } case BSON_TYPE_DOCUMENT: case BSON_TYPE_ARRAY: { int i, objc; Tcl_Obj **objv; bson_t child, *childPtr = &child; result = Tcl_ListObjGetElements(interp, value, &objc, &objv); if (result != TCL_OK || ((objc % 3) != 0)) { return NsfPrintError(interp, "invalid %s value contain multiple of 3 elements %s", ObjStr(tagObj), ObjStr(value)); } if (t == BSON_TYPE_DOCUMENT) { bson_append_document_begin(bbPtr, name, keyLength, childPtr); } else { bson_append_array_begin(bbPtr, name, keyLength, childPtr); } for (i = 0; i< objc; i += 3) { /*fprintf(stderr, "value %s, i %d, [0]: %s, [1]: %s, [2]: %s\n", ObjStr(value), i, ObjStr(objv[i]), ObjStr(objv[i+1]), ObjStr(objv[i+2]));*/ result = BsonAppend(interp, childPtr, objv[i], objv[i+1], objv[i+2]); if (result != TCL_OK) break; } if (t == BSON_TYPE_DOCUMENT) { bson_append_document_end(bbPtr, childPtr); } else { bson_append_array_end(bbPtr, childPtr); } break; } case BSON_TYPE_DECIMAL128: { bson_decimal128_t decimal128; bson_decimal128_from_string(ObjStr(value), &decimal128); bson_append_decimal128(bbPtr, name, keyLength, &decimal128); break; } case BSON_TYPE_BINARY: { int length; const uint8_t *data = Tcl_GetByteArrayFromObj(value, &length); bson_append_binary(bbPtr, name, keyLength, 0x00 /*bson_subtype_t*/, data, (uint32_t)length); break; } case BSON_TYPE_DBPOINTER: case BSON_TYPE_CODE: case BSON_TYPE_SYMBOL: case BSON_TYPE_CODEWSCOPE: return NsfPrintError(interp, "tag %s not handled yet", ObjStr(tagObj)); break; case BSON_TYPE_UNDEFINED: case BSON_TYPE_EOD: break; /* no default here, to get the warning to the compilation log for the time being */ } return result; } /* *---------------------------------------------------------------------- * * BsonAppendObjv -- * * Append all elements of objv to an uninitialized bson buffer. * * Results: * A standard Tcl result. * * Side effects: * Value appended to bson buffer. * *---------------------------------------------------------------------- */ static int BsonAppendObjv(Tcl_Interp *interp, bson_t *bPtr, int objc, Tcl_Obj **objv) { int i, result = TCL_OK; bson_init(bPtr); for (i = 0; i < objc; i += 3) { /*fprintf(stderr, "adding pair '%s' (%s) '%s'\n", ObjStr(objv[i]), ObjStr(objv[i+1]), ObjStr(objv[i+2]));*/ result = BsonAppend(interp, bPtr, objv[i], objv[i+1], objv[i+2]); if (result != TCL_OK) { break; } } return result; } /*********************************************************************** * Define the API functions ***********************************************************************/ /* cmd json::generate NsfMongoJsonGenerate { {-argName "list" -required 1 -type tclobj} } */ static int NsfMongoJsonGenerate(Tcl_Interp *interp, Tcl_Obj *listObj) { bson_t list, *listPtr = &list; size_t length; int result, objc; Tcl_Obj **objv; result = Tcl_ListObjGetElements(interp, listObj, &objc, &objv); if (result != TCL_OK || ((objc % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(listObj)); } result = BsonAppendObjv(interp, listPtr, objc, objv); if (result == TCL_OK) { char *jsonString; jsonString = bson_as_json(listPtr, &length); if (jsonString != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj(jsonString, (int)length)); bson_free(jsonString); } else { result = NsfPrintError(interp, "invalid bson string: %s", ObjStr(listObj)); } bson_destroy( listPtr ); } return result; } /* cmd json::parse NsfMongoJsonParse { {-argName "json" -required 1 -type tclobj} } */ static int NsfMongoJsonParse(Tcl_Interp *interp, Tcl_Obj *jsonObj) { bson_t bson, *bsonPtr = &bson; const char *jsonString; int result, jsonLength; bson_error_t bsonError; jsonString = Tcl_GetStringFromObj(jsonObj, &jsonLength); if (bson_init_from_json (bsonPtr, jsonString,jsonLength, &bsonError) == true) { Tcl_SetObjResult(interp, BsonToList(interp, bsonPtr, 0)); bson_destroy( bsonPtr ); result = TCL_OK; } else { result = NsfPrintError(interp, "mongo::json::parse: error: %s", bsonError.message); } return result; } /* cmd close NsfMongoClose { {-argName "conn" -required 1 -type mongoc_client_t -withObj 1} } */ static int NsfMongoClose(Tcl_Interp *UNUSED(interp), mongoc_client_t *connPtr, Tcl_Obj *connObj) { #if defined(USE_CLIENT_POOL) mongoc_client_pool_push(mongoClientPool, connPtr); #else mongoc_client_destroy(connPtr); #endif Nsf_PointerDelete(ObjStr(connObj), connPtr, 0); return TCL_OK; } /* cmd connect NsfMongoConnect { {-argName "-uri" -required 0 -nrargs 1} } */ static int NsfMongoConnect(Tcl_Interp *interp, const char *uri) { char channelName[POINTER_HANDLE_SIZE]; mongoc_client_t *clientPtr; if (uri == NULL) { uri = "mongodb://127.0.0.1:27017/"; } #if defined(USE_CLIENT_POOL) NsfMutexLock(&poolMutex); if (mongoClientPool == NULL) { mongoUri = mongoc_uri_new(uri); NsfLog(interp, NSF_LOG_NOTICE, "nsf::mongo::connect: creating pool with uri %s", uri); mongoClientPool = mongoc_client_pool_new(mongoUri); } NsfMutexUnlock(&poolMutex); clientPtr = mongoc_client_pool_pop(mongoClientPool); #else clientPtr = mongoc_client_new(uri); #endif if (clientPtr == NULL) { return NsfPrintError(interp, "failed to parse Mongo URI"); } /* * Make an entry in the symbol table and return entry name it as * result. */ if (Nsf_PointerAdd(interp, channelName, sizeof(channelName), "mongoc_client_t", clientPtr) != TCL_OK) { mongoc_client_destroy(clientPtr); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewStringObj(channelName, TCL_INDEX_NONE)); return TCL_OK; } /* cmd run NsfMongoRunCmd { {-argName "-nocomplain" -required 0 -nrargs 0} {-argName "conn" -required 1 -type mongoc_client_t} {-argName "db" -required 1} {-argName "cmd" -required 1 -type tclobj} } */ static int NsfMongoRunCmd(Tcl_Interp *interp, int withNocomplain, mongoc_client_t *clientPtr, const char *db, Tcl_Obj *cmdObj) { bson_t cmd, *cmdPtr = &cmd, reply, *replyPtr = &reply; mongoc_read_prefs_t *readPrefsPtr = NULL; /* TODO: not used */ bson_error_t bsonError; int result, objc; Tcl_Obj **objv; result = Tcl_ListObjGetElements(interp, cmdObj, &objc, &objv); if (result != TCL_OK || ((objc % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(cmdObj)); } BsonAppendObjv(interp, cmdPtr, objc, objv); /*mongo_clear_errors( connPtr );*/ result = mongoc_client_command_simple( clientPtr, db, cmdPtr, readPrefsPtr, replyPtr, &bsonError); bson_destroy( cmdPtr ); if (withNocomplain == 0 && result == 0) { return NsfPrintError(interp, "mongo::run: command '%s' returned error: %s", ObjStr(cmdObj), bsonError.message); } Tcl_SetObjResult(interp, BsonToList(interp, replyPtr, 0)); bson_destroy(replyPtr); return TCL_OK; } /* cmd status NsfMongoStatus { {-argName "conn" -required 1 -type mongoc_client_t -withObj 1} } */ static int NsfMongoStatus(Tcl_Interp *interp, mongoc_client_t *clientPtr, Tcl_Obj *UNUSED(clientObj)) { mongoc_read_prefs_t *readPrefs = NULL; /* TODO: not handled */ bson_t reply, *replyPtr = &reply; bson_error_t bsonError; int result = TCL_OK; bson_t cmd = BSON_INITIALIZER; bool ret; BSON_APPEND_INT32(&cmd, "serverStatus", 1); ret = mongoc_client_command_simple(clientPtr, "admin", &cmd, readPrefs, replyPtr, &bsonError); bson_destroy(&cmd); if (likely(ret != 0)) { Tcl_SetObjResult(interp, BsonToList(interp, replyPtr, 0)); } else { result = NsfPrintError(interp, "mongo::status: error: %s", bsonError.message); } bson_destroy(replyPtr); return result; } /* cmd collection::open NsfCollectionOpen { {-argName "conn" -required 1 -type mongoc_client_t} {-argName "dbname" -required 1} {-argName "collectionname" -required 1} } */ int NsfCollectionOpen(Tcl_Interp *interp, mongoc_client_t *clientPtr, const char *dbName, const char *collectionName) { int result = TCL_ERROR; mongoc_collection_t *collectionPtr; collectionPtr = mongoc_client_get_collection(clientPtr, dbName, collectionName); if (collectionPtr != NULL) { char buffer[POINTER_HANDLE_SIZE]; if (Nsf_PointerAdd(interp, buffer, sizeof(buffer), "mongoc_collection_t", collectionPtr) == TCL_OK) { Tcl_SetObjResult(interp, Tcl_NewStringObj(buffer, TCL_INDEX_NONE)); result = TCL_OK; } else { mongoc_collection_destroy(collectionPtr); result = TCL_ERROR; } } if (collectionPtr == NULL) { result = NsfPrintError(interp, "collection::open: could not open collection: %s.%s", dbName, collectionName); } return result; } /* cmd collection::close NsfCollectionClose { {-argName "collection" -required 1 -type mongoc_collection_t -withObj 1} } */ static int NsfCollectionClose(Tcl_Interp *UNUSED(interp), mongoc_collection_t *collectionPtr, Tcl_Obj *clientObj) { mongoc_collection_destroy(collectionPtr); Nsf_PointerDelete(ObjStr(clientObj), collectionPtr, 0); return TCL_OK; } /* cmd collection::count NsfMongoCollectionCount { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "query" -required 1 -type tclobj} } */ static int NsfMongoCollectionCount(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *queryObj) { int objc, result; int64_t count; Tcl_Obj **objv; bson_t query, *queryPtr = &query; bson_error_t bsonError; /*bson_t* opts = BCON_NEW("skip", BCON_INT64(5));*/ result = Tcl_ListObjGetElements(interp, queryObj, &objc, &objv); if (result != TCL_OK || ((objc % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(queryObj)); } BsonAppendObjv(interp, queryPtr, objc, objv); count = mongoc_collection_count_documents(collectionPtr, queryPtr, NULL /* opts */, NULL /* read preferences */, NULL /* replyPtr */, &bsonError); if (count == -1) { bson_destroy( queryPtr ); return NsfPrintError(interp, "mongo::collection::count: error: %s", bsonError.message); } bson_destroy( queryPtr ); Tcl_SetObjResult(interp, Tcl_NewWideIntObj((Tcl_WideInt)count)); return TCL_OK; } /* cmd "collection::delete" NsfMongoCollectionDelete { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "condition" -required 1 -type tclobj} } */ static int NsfMongoCollectionDelete(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *conditionObj) { int objc, result, success; Tcl_Obj **objv; bson_t query, *queryPtr = &query; bson_error_t bsonError; mongoc_remove_flags_t removeFlags = 0; /* TODO: not handled */ /* MONGOC_DELETE_SINGLE_REMOVE = 1 << 0,**/ const mongoc_write_concern_t *writeConcern = NULL; /* TODO: not handled yet */ result = Tcl_ListObjGetElements(interp, conditionObj, &objc, &objv); if (result != TCL_OK || ((objc % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(conditionObj)); } BsonAppendObjv(interp, queryPtr, objc, objv); success = mongoc_collection_remove(collectionPtr, removeFlags, queryPtr, writeConcern, &bsonError); if (success == 0) { result = NsfPrintError(interp, "mongo::collection::delete: error: %s", bsonError.message); } bson_destroy(queryPtr); return result; } /* cmd "collection::index" NsfMongoCollectionIndex { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "attributes" -required 1 -type tclobj} {-argName "-name" -required 0 -nrargs 1} {-argName "-background" -required 0 -nrargs 0} {-argName "-dropdups" -required 0 -nrargs 0} {-argName "-sparse" -required 0 -nrargs 0} {-argName "-ttl" -required 0 -nrargs 1 -type int32} {-argName "-unique" -required 0 -nrargs 0} } */ static int NsfMongoCollectionIndex(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *attributesObj, const char *withName, int withBackground, int withDropdups, int withSparse, int withTtl, int withUnique) { int objc, result, success = 0; Tcl_Obj **objv; bson_t keys, *keysPtr = &keys; bson_error_t bsonError; mongoc_index_opt_t options; bson_t *create_indexes; char *index_name; const char *collection_name; result = Tcl_ListObjGetElements(interp, attributesObj, &objc, &objv); if (result != TCL_OK || ((objc % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(attributesObj)); } BsonAppendObjv(interp, keysPtr, objc, objv); index_name = mongoc_collection_keys_to_index_string(keysPtr); collection_name = mongoc_collection_get_name(collectionPtr); create_indexes = BCON_NEW("createIndexes", BCON_UTF8(collection_name), "indexes", "[", "{", "key", BCON_DOCUMENT(keysPtr), "name", BCON_UTF8(index_name), "}", "]"); mongoc_index_opt_init(&options); if (withBackground != 0) {options.background = 1;} if (withDropdups != 0) {options.drop_dups = 1;} if (withSparse != 0) {options.sparse = 1;} if (withUnique != 0) {options.unique = 1;} if (withTtl != 0) {options.expire_after_seconds = withTtl;} if (withName != 0) {options.name = withName;} /* TODO: not handled: is_initialized, v, weights, default_language, language_override, padding */ success = mongoc_collection_write_command_with_opts( collectionPtr, create_indexes, NULL /* opts */, NULL /*&reply*/, &bsonError); bson_destroy(keysPtr); bson_free(index_name); bson_destroy(create_indexes); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(success)); return TCL_OK; } /* cmd "collection::insert" NsfMongoCollectionInsert { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "values" -required 1 -type tclobj} } */ static int NsfMongoCollectionInsert(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *valuesObj) { int i, objc, result, success; Tcl_Obj **objv; bson_t bson, *bsonPtr = &bson; bson_oid_t oid; bson_error_t bsonError; mongoc_insert_flags_t insertFlags = MONGOC_INSERT_NO_VALIDATE; /* otherwise, we can't insert a DBRef */ /* TODO: insertFlags not handled: MONGOC_INSERT_NONE = 0, MONGOC_INSERT_CONTINUE_ON_ERROR = 1 << 0, MONGOC_INSERT_NO_VALIDATE = 1 << 31, */ const mongoc_write_concern_t *writeConcern = NULL; /* TODO: not handled yet */ result = Tcl_ListObjGetElements(interp, valuesObj, &objc, &objv); if (result != TCL_OK || ((objc % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(valuesObj)); } bson_init(bsonPtr); bson_oid_init(&oid, NULL); bson_append_oid(bsonPtr, "_id", 3, &oid); for (i = 0; i < objc; i += 3) { /*fprintf(stderr, "adding pair '%s' (%s) '%s'\n", ObjStr(name), ObjStr(tag), ObjStr(value));*/ BsonAppend(interp, bsonPtr, objv[i], objv[i+1], objv[i+2]); } success = mongoc_collection_insert(collectionPtr, insertFlags, bsonPtr, writeConcern, &bsonError); if (success == 0) { result = NsfPrintError(interp, "mongo::collection::insert: error: %s", bsonError.message); } else { Tcl_SetObjResult(interp, BsonToList(interp, bsonPtr, 0)); } bson_destroy(bsonPtr); return result; } /* cmd collection::query NsfMongoCollectionQuery { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "filter" -required 1 -type tclobj} {-argName "-opts" -required 0 -nrargs 1 -type tclobj} } */ static int NsfMongoCollectionQuery(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *filterObj, Tcl_Obj *withOptsObj) { int objc1, objc2 = 0, result; Tcl_Obj **objv1, **objv2 = NULL, *resultObj; mongoc_cursor_t *cursor; bson_t filter, *const filterPtr = &filter; bson_t opts, *const optsPtr = &opts; const bson_t *nextPtr; mongoc_read_prefs_t *readPrefsPtr = NULL; /* TODO: not handled */ /*fprintf(stderr, "NsfMongoQuery: namespace %s withLimit %d withSkip %d\n", namespace, withLimit, withSkip);*/ result = Tcl_ListObjGetElements(interp, filterObj, &objc1, &objv1); if (result != TCL_OK || ((objc1 % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(filterObj)); } if (withOptsObj != NULL) { result = Tcl_ListObjGetElements(interp, withOptsObj, &objc2, &objv2); if (result != TCL_OK || ((objc2 % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(withOptsObj)); } } else { objc2 = 0; } BsonAppendObjv(interp, filterPtr, objc1, objv1); BsonAppendObjv(interp, optsPtr, objc2, objv2); resultObj = Tcl_NewListObj(0, NULL); cursor = mongoc_collection_find_with_opts( collectionPtr, filterPtr, optsPtr, readPrefsPtr); while( mongoc_cursor_next( cursor, &nextPtr ) == 1 ) { Tcl_ListObjAppendElement(interp, resultObj, BsonToList(interp, nextPtr, 0)); } mongoc_cursor_destroy( cursor ); bson_destroy( filterPtr ); bson_destroy( optsPtr ); Tcl_SetObjResult(interp, resultObj); return TCL_OK; } /* cmd "collection::stats" NsfMongoCollectionStats { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "-options" -required 0 -type tclobj} } */ static int NsfMongoCollectionStats(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *optionsObj) { int objc = 0, success, result; Tcl_Obj **objv = NULL; bson_t options, *optionsPtr = NULL; bson_t stats, *statsPtr = &stats; bson_t cmd = BSON_INITIALIZER; bson_iter_t iter; bson_error_t bsonError; if (optionsObj != NULL) { result = Tcl_ListObjGetElements(interp, optionsObj, &objc, &objv); if (result != TCL_OK || ((objc % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(optionsObj)); } optionsPtr = &options; BsonAppendObjv(interp, optionsPtr, objc, objv); } if (optionsPtr != NULL && bson_iter_init_find(&iter, optionsPtr, "scale") && !BSON_ITER_HOLDS_INT32 (&iter)) { bson_set_error(&bsonError, MONGOC_ERROR_BSON, MONGOC_ERROR_BSON_INVALID, "'scale' must be an int32 value."); success = 0; } else { BSON_APPEND_UTF8(&cmd, "collStats", mongoc_collection_get_name(collectionPtr)); if (optionsPtr != NULL) { bson_concat(&cmd, optionsPtr); } success = mongoc_collection_command_simple(collectionPtr, &cmd, mongoc_collection_get_read_prefs(collectionPtr), statsPtr, &bsonError); bson_destroy(&cmd); } if (optionsPtr != NULL) { bson_destroy(optionsPtr); } if (success != 0) { Tcl_SetObjResult(interp, BsonToList(interp, statsPtr, 0)); bson_destroy(statsPtr); result = TCL_OK; } else { result = NsfPrintError(interp, "mongo::collection::stats: error: %s", bsonError.message); } return result; } /* cmd "collection::update" NsfMongoCollectionUpdate { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "cond" -required 1 -type tclobj} {-argName "values" -required 1 -type tclobj} {-argName "-upsert" -required 0 -nrargs 0} {-argName "-all" -required 0 -nrargs 0} } */ static int NsfMongoCollectionUpdate(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *conditionObj, Tcl_Obj *valuesObj, int withUpsert, int withAll) { const mongoc_write_concern_t *writeConcern = NULL; /* TODO: not handled yet */ mongoc_update_flags_t updateFlags = MONGOC_UPDATE_NO_VALIDATE; /* for dbrefs */ bson_error_t bsonError; bson_t cond, *condPtr = &cond, values, *valuesPtr = &values; int objc, result, success; Tcl_Obj **objv; result = Tcl_ListObjGetElements(interp, conditionObj, &objc, &objv); if (result != TCL_OK || ((objc % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(conditionObj)); } BsonAppendObjv(interp, condPtr, objc, objv); result = Tcl_ListObjGetElements(interp, valuesObj, &objc, &objv); if (result != TCL_OK || ((objc % 3) != 0)) { bson_destroy(condPtr); return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(valuesObj)); } BsonAppendObjv(interp, valuesPtr, objc, objv); if (withUpsert != 0) {updateFlags |= MONGOC_UPDATE_UPSERT;} if (withAll != 0) {updateFlags |= MONGOC_UPDATE_MULTI_UPDATE;} success = mongoc_collection_update(collectionPtr, updateFlags, condPtr, valuesPtr, writeConcern, &bsonError); if (success == 0) { result = NsfPrintError(interp, "mongo::collection::delete: error: %s", bsonError.message); } return result; } /*********************************************************************** * Cursor interface ***********************************************************************/ /* cmd cursor::aggregate NsfMongoCursorAggregate { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "pipeline" -required 1 -type tclobj} {-argName "options" -required 1 -type tclobj} {-argName "-tailable" -required 0 -nrargs 0} {-argName "-awaitdata" -required 0 -nrargs 0} } */ static int NsfMongoCursorAggregate(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *pipelineObj, Tcl_Obj *optionsObj, int withTailable, int withAwaitdata) { int objc1, objc2, result; mongoc_query_flags_t queryFlags = 0; Tcl_Obj **objv1, **objv2 = NULL; mongoc_cursor_t *cursor; bson_t pipeline, *pipelinePtr = &pipeline; bson_t options, *optionsPtr = &options; mongoc_read_prefs_t *readPrefsPtr = NULL; /* TODO: not used */ result = Tcl_ListObjGetElements(interp, pipelineObj, &objc1, &objv1); if (result != TCL_OK || ((objc1 % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(pipelineObj)); } result = Tcl_ListObjGetElements(interp, optionsObj, &objc2, &objv2); if (result != TCL_OK || ((objc2 % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(optionsObj)); } BsonAppendObjv(interp, pipelinePtr, objc1, objv1); BsonAppendObjv(interp, optionsPtr, objc2, objv2); /* * The last field of mongo_find is options, semantics are described here * https://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-OPQUERY */ if (withTailable != 0) { queryFlags |= MONGOC_QUERY_TAILABLE_CURSOR; } if (withAwaitdata != 0) { queryFlags |= MONGOC_QUERY_AWAIT_DATA; } /* TODO: query flags: MONGOC_QUERY_SLAVE_OK = 1 << 2, MONGOC_QUERY_OPLOG_REPLAY = 1 << 3, MONGOC_QUERY_NO_CURSOR_TIMEOUT = 1 << 4, MONGOC_QUERY_EXHAUST = 1 << 6, MONGOC_QUERY_PARTIAL = 1 << 7, */ cursor = mongoc_collection_aggregate(collectionPtr, queryFlags, pipelinePtr, optionsPtr, readPrefsPtr); if (cursor != NULL) { char buffer[POINTER_HANDLE_SIZE]; if (Nsf_PointerAdd(interp, buffer, sizeof(buffer), "mongoc_cursor_t", cursor) == TCL_OK) { Tcl_SetObjResult(interp, Tcl_NewStringObj(buffer, TCL_INDEX_NONE)); } else { mongoc_cursor_destroy( cursor ); result = TCL_ERROR; } } else { Tcl_ResetResult(interp); } bson_destroy( pipelinePtr ); bson_destroy( optionsPtr ); return result; } /* cmd cursor::find NsfMongoCursorFind { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "filter" -required 1 -type tclobj} {-argName "-opts" -required 0 -nrargs 1 -type tclobj} } */ static int NsfMongoCursorFind(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *filterObj, Tcl_Obj *withOptsObj) { int objc1, objc2 = 0, result; Tcl_Obj **objv1, **objv2 = NULL; mongoc_cursor_t *cursor; bson_t filter, *filterPtr = &filter; bson_t opts, *optsPtr = &opts; mongoc_read_prefs_t *readPrefsPtr = NULL; /* TODO: not used */ /*fprintf(stderr, "NsfMongoQuery: namespace %s withLimit %d withSkip %d\n", namespace, withLimit, withSkip);*/ result = Tcl_ListObjGetElements(interp, filterObj, &objc1, &objv1); if (result != TCL_OK || ((objc1 % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(filterObj)); } if (withOptsObj != NULL) { result = Tcl_ListObjGetElements(interp, withOptsObj, &objc2, &objv2); if (result != TCL_OK || ((objc2 % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(withOptsObj)); } } BsonAppendObjv(interp, filterPtr, objc1, objv1); BsonAppendObjv(interp, optsPtr, objc2, objv2); cursor = mongoc_collection_find_with_opts( collectionPtr, filterPtr, optsPtr, readPrefsPtr); if (cursor != NULL) { char buffer[POINTER_HANDLE_SIZE]; if (Nsf_PointerAdd(interp, buffer, sizeof(buffer), "mongoc_cursor_t", cursor) == TCL_OK) { Tcl_SetObjResult(interp, Tcl_NewStringObj(buffer, TCL_INDEX_NONE)); } else { mongoc_cursor_destroy( cursor ); result = TCL_ERROR; } } else { Tcl_ResetResult(interp); } bson_destroy( filterPtr ); bson_destroy( optsPtr ); return result; } /* cmd cursor::next NsfMongoCursorNext { {-argName "cursor" -required 1 -type mongoc_cursor_t} } */ static int NsfMongoCursorNext(Tcl_Interp *interp, mongoc_cursor_t *cursor) { int result; const bson_t *nextPtr; result = mongoc_cursor_next( cursor, &nextPtr ); if (result == 1) { Tcl_SetObjResult(interp, BsonToList(interp, nextPtr, 0)); } return TCL_OK; } /* cmd cursor::close NsfMongoCursorClose { {-argName "cursor" -required 1 -type mongoc_cursor_t -withObj 1} } */ static int NsfMongoCursorClose(Tcl_Interp *UNUSED(interp), mongoc_cursor_t *cursor, Tcl_Obj *cursorObj) { mongoc_cursor_destroy( cursor ); Nsf_PointerDelete(ObjStr(cursorObj), cursor, 0); return TCL_OK; } /*********************************************************************** * GridFS interface ***********************************************************************/ /* cmd gridfs::close NsfMongoGridFSClose { {-argName "gfs" -required 1 -type mongoc_gridfs_t -withObj 1} } */ static int NsfMongoGridFSClose(Tcl_Interp *UNUSED(interp), mongoc_gridfs_t *gridfsPtr, Tcl_Obj *gridfsObj) { mongoc_gridfs_destroy(gridfsPtr); Nsf_PointerDelete(ObjStr(gridfsObj), gridfsPtr, 0); return TCL_OK; } /* cmd gridfs::open NsfMongoGridFSOpen { {-argName "conn" -required 1 -type mongoc_client_t} {-argName "dbname" -required 1} {-argName "prefix" -required 1} } */ static int NsfMongoGridFSOpen(Tcl_Interp *interp, mongoc_client_t *clientPtr, const char *dbname, const char *prefix) { char buffer[POINTER_HANDLE_SIZE]; int result = TCL_OK; bson_error_t bsonError; mongoc_gridfs_t *gfsPtr; gfsPtr = mongoc_client_get_gridfs(clientPtr, dbname, prefix, &bsonError); if (gfsPtr == NULL) { result = NsfPrintError(interp, "mongo::gridfs::open: error: %s", bsonError.message); } if (Nsf_PointerAdd(interp, buffer, sizeof(buffer), "mongoc_gridfs_t", gfsPtr) == TCL_OK) { Tcl_SetObjResult(interp, Tcl_NewStringObj(buffer, TCL_INDEX_NONE)); } else { mongoc_gridfs_destroy(gfsPtr); result = TCL_ERROR; } return result; } /*********************************************************************** * GridFile interface operating on GridFS ***********************************************************************/ #define MONGOC_GRIDFS_READ_CHUNK 4096*4 /* cmd gridfile::create NsfMongoGridFileCreate { {-argName "-source" -required 1 -typeName "gridfilesource" -type "file|string"} {-argName "gfs" -required 1 -type mongoc_gridfs_t} {-argName "value" -required 1} {-argName "name" -required 1} {-argName "contenttype" -required 1} {-argName "-metadata" -required 0 -nrags 1 -type tclobj} } */ static int NsfMongoGridFileCreate(Tcl_Interp *interp, GridfilesourceIdx_t withSource, mongoc_gridfs_t *gridfsPtr, const char *value, const char *name, const char *contenttype, Tcl_Obj *withMetadata ) { int result = TCL_OK; mongoc_gridfs_file_opt_t fileOpts ; mongoc_gridfs_file_t *gridFile; bson_t bsonMetaData, *bsonMetaDataPtr = &bsonMetaData; memset(&fileOpts, 0, sizeof(fileOpts)); if (withSource == GridfilesourceNULL) { withSource = GridfilesourceFileIdx; } if (withMetadata != NULL) { Tcl_Obj **objv; int objc; result = Tcl_ListObjGetElements(interp, withMetadata, &objc, &objv); if (result != TCL_OK || ((objc % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(withMetadata)); } BsonAppendObjv(interp, bsonMetaDataPtr, objc, objv); fileOpts.metadata = bsonMetaDataPtr; } fileOpts.filename = name; fileOpts.content_type = contenttype; /* const char *md5; const bson_t *aliases; uint32_t chunk_size; */ gridFile = mongoc_gridfs_create_file(gridfsPtr, &fileOpts); if (withSource == GridfilesourceFileIdx) { uint8_t buf[MONGOC_GRIDFS_READ_CHUNK]; mongoc_iovec_t iov = { buf, 0 }; int fd = open(value, O_RDONLY); if (fd < 1) { mongoc_gridfs_file_destroy(gridFile); return NsfPrintError(interp, "nsf::gridfile::create: cannot open file '%s' for reading", value); } for (;;) { ssize_t n = read(fd, iov.iov_base, MONGOC_GRIDFS_READ_CHUNK); if (n > 0) { iov.iov_len = (size_t)n; n = mongoc_gridfs_file_writev(gridFile, &iov, 1, 0); if ((size_t)n != iov.iov_len) { NsfLog(interp, NSF_LOG_WARN, "mongodb: write of %d bytes returned %d", iov.iov_len, n); } } else if (n == 0) { break; } else { result = TCL_ERROR; break; } } close(fd); } else { mongoc_iovec_t iov = { (char *)value, strlen(value) }; mongoc_gridfs_file_writev(gridFile, &iov, 1, 0); } if (result == TCL_OK) { mongoc_gridfs_file_save(gridFile); } mongoc_gridfs_file_destroy(gridFile); Tcl_SetObjResult(interp, Tcl_NewIntObj(result == TCL_OK)); return result; } /* cmd "gridfile::delete" NsfMongoGridFileDelete { {-argName "gfs" -required 1 -type mongoc_gridfs_t} {-argName "query" -required 1 -type tclobj} } */ static int NsfMongoGridFileDelete(Tcl_Interp *interp, mongoc_gridfs_t *gridfsPtr, Tcl_Obj *queryObj) { bson_t query, *queryPtr = &query; mongoc_cursor_t *files; const bson_t *nextPtr; bson_iter_t it; Tcl_Obj **objv; int objc, result; mongoc_read_prefs_t *readPrefsPtr = NULL; /* TODO: not handled */ result = Tcl_ListObjGetElements(interp, queryObj, &objc, &objv); if (result != TCL_OK || ((objc % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(queryObj)); } BsonAppendObjv(interp, queryPtr, objc, objv); files = mongoc_collection_find_with_opts( mongoc_gridfs_get_files(gridfsPtr), queryPtr, NULL, readPrefsPtr); bson_destroy(queryPtr); /* * Files should be a valid cursor even if the file doesn't exist. */ if ( files == NULL ) { return NsfPrintError(interp, "gridfs::remove_file: invalid cursor for files"); } /* * Remove each file and it's chunks from files named filename. */ while (mongoc_cursor_next(files, &nextPtr)) { bson_t bson, *bsonPtr = &bson; bson_error_t bsonError; bson_oid_t id; bson_iter_init_find(&it, nextPtr, "_id"); id = *bson_iter_oid(&it); /* * Remove the file with the specified id. */ bson_init(bsonPtr); bson_append_oid(bsonPtr, "_id", 3, &id); mongoc_collection_remove(mongoc_gridfs_get_files(gridfsPtr), 0, bsonPtr, NULL, &bsonError); bson_destroy(bsonPtr); /* * Remove all chunks from the file with the specified id. */ bson_init(bsonPtr); bson_append_oid(bsonPtr, "files_id", 8, &id); mongoc_collection_remove(mongoc_gridfs_get_chunks(gridfsPtr), 0, bsonPtr, NULL, &bsonError); bson_destroy(bsonPtr); } mongoc_cursor_destroy(files); return TCL_OK; } /* cmd gridfile::open NsfMongoGridFileOpen { {-argName "gfs" -required 1 -type mongoc_gridfs_t} {-argName "filter" -required 1 -type tclobj} } */ static int NsfMongoGridFileOpen(Tcl_Interp *interp, mongoc_gridfs_t *gridfsPtr, Tcl_Obj *filterObj) { mongoc_gridfs_file_t* gridFilePtr; bson_error_t bsonError; bson_t filter, *filterPtr = &filter; int result, objc; Tcl_Obj **objv; /*fprintf(stderr, "NsfMongoFilter: namespace %s withLimit %d withSkip %d\n", namespace, withLimit, withSkip);*/ result = Tcl_ListObjGetElements(interp, filterObj, &objc, &objv); if (result != TCL_OK || ((objc % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(filterObj)); } BsonAppendObjv(interp, filterPtr, objc, objv); gridFilePtr = mongoc_gridfs_find_one_with_opts(gridfsPtr, filterPtr, NULL, &bsonError); if (gridFilePtr != NULL) { char buffer[POINTER_HANDLE_SIZE]; if (Nsf_PointerAdd(interp, buffer, sizeof(buffer), "mongoc_gridfs_file_t", gridFilePtr) == TCL_OK) { Tcl_SetObjResult(interp, Tcl_NewStringObj(buffer, TCL_INDEX_NONE)); } else { mongoc_gridfs_file_destroy(gridFilePtr); result = TCL_ERROR; } } else { Tcl_ResetResult(interp); } bson_destroy(filterPtr); return result; } /*********************************************************************** * GridFile interface * * Currently offsets and sizes are limited to 32-bit integers, we should * relax this later. ***********************************************************************/ /* cmd gridfile::close NsfMongoGridFileClose { {-argName "gridfile" -required 1 -type mongoc_gridfs_file_t -withObj 1} } */ static int NsfMongoGridFileClose(Tcl_Interp *UNUSED(interp), mongoc_gridfs_file_t* gridFilePtr, Tcl_Obj *gridFileObj) { mongoc_gridfs_file_destroy(gridFilePtr); Nsf_PointerDelete(ObjStr(gridFileObj), gridFilePtr, 0); return TCL_OK; } /* cmd gridfile::get_contentlength NsfMongoGridFileGetContentlength { {-argName "gridfile" -required 1 -type mongoc_gridfs_file_t} } */ static int NsfMongoGridFileGetContentlength(Tcl_Interp *interp, mongoc_gridfs_file_t* gridFilePtr) { int64_t len; len = mongoc_gridfs_file_get_length(gridFilePtr); Tcl_SetObjResult(interp, Tcl_NewLongObj(len)); return TCL_OK; } /* cmd gridfile::get_contenttype NsfMongoGridFileGetContentType { {-argName "gridfile" -required 1 -type mongoc_gridfs_file_t} } */ static int NsfMongoGridFileGetContentType(Tcl_Interp *interp, mongoc_gridfs_file_t* gridFilePtr) { Tcl_SetObjResult(interp, Tcl_NewStringObj(mongoc_gridfs_file_get_content_type(gridFilePtr), TCL_INDEX_NONE)); return TCL_OK; } /* cmd gridfile::get_metadata NsfMongoGridFileGetMetaData { {-argName "gridfile" -required 1 -type mongoc_gridfs_file_t} } */ static int NsfMongoGridFileGetMetaData(Tcl_Interp *interp, mongoc_gridfs_file_t* gridFilePtr) { const bson_t *metaDataPtr = mongoc_gridfs_file_get_metadata(gridFilePtr); if (metaDataPtr != NULL) { Tcl_SetObjResult(interp, BsonToList(interp, metaDataPtr, 0)); } return TCL_OK; } /* cmd gridfile::read NsfMongoGridFileRead { {-argName "gridfile" -required 1 -type mongoc_gridfs_file_t} {-argName "size" -required 1 -type int} } */ static int NsfMongoGridFileRead(Tcl_Interp *interp, mongoc_gridfs_file_t *gridFilePtr, int size) { ssize_t readSize; Tcl_Obj *resultObj = Tcl_NewByteArrayObj(NULL, size); mongoc_iovec_t iov = { NULL, (size_t)size }; assert(size > 0); iov.iov_base = Tcl_SetByteArrayLength(resultObj, size); readSize = mongoc_gridfs_file_readv(gridFilePtr, &iov, 1, 0 /* min_bytes */, 0 /* timeout_msec */); /*fprintf(stderr, "NsfMongoGridFileRead want %d got %d\n", size, readSize);*/ Tcl_SetByteArrayLength(resultObj, (int)readSize); Tcl_SetObjResult(interp, resultObj); return TCL_OK; } /* cmd "gridfile::seek" NsfMongoGridFileSeek { {-argName "gridfile" -required 1 -type mongoc_gridfs_file_t} {-argName "offset" -required 1 -type int32} } */ static int NsfMongoGridFileSeek(Tcl_Interp *UNUSED(interp), mongoc_gridfs_file_t *gridFilePtr, int offset) { int result; /* * TODO: whence SEEK_SET, SEEK_CUR or SEEK_END; implementation of SEEK_END looks incorrect */ result = mongoc_gridfs_file_seek(gridFilePtr, offset, SEEK_SET); return result < 0 ? TCL_ERROR : TCL_OK; } /*********************************************************************** * Finally, provide the necessary Tcl package interface. ***********************************************************************/ static void Nsfmongo_ThreadExit(ClientData UNUSED(clientData)) { /* * The exit might happen at a time, when Tcl is already shut down. * We can't reliably call NsfLog. */ fprintf(stderr, "+++ Nsfmongo_ThreadExit\n"); #if defined(USE_CLIENT_POOL) NsfMutexLock(&poolMutex); mongoClientPoolRefCount --; if (mongoClientPool != NULL) { /*fprintf(stderr, "========= Nsfmongo_ThreadExit mongoClientPoolRefCount %d\n", mongoClientPoolRefCount);*/ if (mongoClientPoolRefCount < 1) { mongoc_client_pool_destroy(mongoClientPool); mongoClientPool = NULL; mongoc_uri_destroy(mongoUri); mongoUri = NULL; } } NsfMutexUnlock(&poolMutex); #endif } static void Nsfmongo_Exit(ClientData clientData) { /* * The exit might happen at a time, when Tcl is already shut down. * We can't reliably call NsfLog. * * Tcl_Interp *interp = (Tcl_Interp *)clientData; * NsfLog(interp,NSF_LOG_NOTICE, "Nsfmongo Exit"); */ fprintf(stderr, "+++ Nsfmongo_Exit\n"); #if defined(TCL_THREADS) Tcl_DeleteThreadExitHandler(Nsfmongo_ThreadExit, clientData); #endif Tcl_Release(clientData); /* * Release the state of mongo-c-driver explicitly. */ mongoc_cleanup(); } extern int Nsfmongo_Init(Tcl_Interp * interp) { int i; static NsfMutex initMutex = 0; #ifdef USE_TCL_STUBS if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) { return TCL_ERROR; } # ifdef USE_NSF_STUBS if (Nsf_InitStubs(interp, "2.0", 0) == NULL) { return TCL_ERROR; } # endif #else if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL) { return TCL_ERROR; } #endif Tcl_PkgProvide(interp, "nsf::mongo", PACKAGE_VERSION); #ifdef PACKAGE_REQUIRE_FROM_SLAVE_INTERP_WORKS_NOW if (Tcl_PkgRequire(interp, "nsf", PACKAGE_VERSION, 0) == NULL) { return TCL_ERROR; } #endif Tcl_Preserve(interp); #if defined(TCL_THREADS) Tcl_CreateThreadExitHandler(Nsfmongo_ThreadExit, interp); #endif Tcl_CreateExitHandler(Nsfmongo_Exit, interp); #if defined(USE_CLIENT_POOL) NsfMutexLock(&poolMutex); mongoClientPoolRefCount ++; NsfMutexUnlock(&poolMutex); #endif /* * Register global mongo Tcl_Objs once. */ NsfMutexLock(&initMutex); if (NsfMongoGlobalObjs == NULL) { NsfMongoGlobalObjs = (Tcl_Obj **)ckalloc(sizeof(Tcl_Obj*)*nr_elements(NsfMongoGlobalStrings)); for (i = 0; i < nr_elements(NsfMongoGlobalStrings); i++) { NsfMongoGlobalObjs[i] = Tcl_NewStringObj(NsfMongoGlobalStrings[i], TCL_INDEX_NONE); Tcl_IncrRefCount(NsfMongoGlobalObjs[i]); } /* * Initializing state of mongo-c-driver explicitly. */ mongoc_init(); } NsfMutexUnlock(&initMutex); Nsf_EnumerationTypeRegister(interp, enumeratorConverterEntries); Nsf_CmdDefinitionRegister(interp, method_definitions); /* * Register the pointer converter. */ Nsf_PointerTypeRegister(interp, "mongoc_client_t", &mongoClientCount); Nsf_PointerTypeRegister(interp, "mongoc_collection_t", &mongoCollectionCount); Nsf_PointerTypeRegister(interp, "mongoc_cursor_t", &mongoCursorCount); Nsf_PointerTypeRegister(interp, "mongoc_gridfs_file_t", &gridfileCount); Nsf_PointerTypeRegister(interp, "mongoc_gridfs_t", &gridfsCount); for (i=0; i < nr_elements(method_command_namespace_names); i++) { Tcl_CreateNamespace(interp, method_command_namespace_names[i], 0, (Tcl_NamespaceDeleteProc *)NULL); } /* * Create all method commands (will use the namespaces above) */ for (i = 0; i < nr_elements(method_definitions)-1; i++) { Tcl_CreateObjCommand(interp, method_definitions[i].methodName, method_definitions[i].proc, 0, 0); } Tcl_SetIntObj(Tcl_GetObjResult(interp), 1); return TCL_OK; } extern int Nsfmongo_SafeInit( Tcl_Interp *interp) { return Nsfmongo_Init(interp); } /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * End: */ ./nsf2.4.0/library/mongodb/tests/nx-mongo.test000644 000766 000024 00000011605 13560225751 022077 0ustar00neumannstaff000000 000000 # -*- tcl -*- # # This is an example how to use the nx mongo mapping. We show here # single class mapped to the mongo db with sing and multivalued # scalars together with some querying options. # # Gustaf Neumann fecit, April 2011 # package require nx::mongo package require nx::test #nsf::configure debug 2 # Establish connection to the database ? {::nx::mongo::db connect -db "tutorial"} mongoc_client_t:0 # # Create or lookup collection handle; the first operation is a create, # the second a lookup. # ? {::nx::mongo::db collection tutorial.persons} "mongoc_collection_t:0" ? {::nx::mongo::db collection tutorial.persons} "mongoc_collection_t:0" # # When we create a capped collection, we cannot use # # nx::mongo::db delete tutorial.persons {} # # but have to use "drop collection" to get rid of it (this is enforced # by MongoDB 2.6.3 or newer). nx::mongo::db drop collection persons # # Create the application class "Person" # ? { nx::mongo::Class create Person { :index name :property name:required :property projects:0..n {set :incremental 1} :property age:integer } } ::Person # # Insert a tuple to the database via creating an object, saving and # destroying it: # ? { nsf::is object [set p [Person new -name Gustaf -projects {nsf nx nxmongo} -age 53]]} 1 ? { nx::mongo::db is_oid [$p save]} 1 ? { $p destroy; nsf::is object $p} 0 # # The insert operation of above can be achieved with less typing via # the convenience method "insert": # ? { nx::mongo::db is_oid [Person insert -name Stefan -projects {nsf nx}]} 1 ? { nx::mongo::db is_oid [Person insert -name Joe -projects abc -age 23]} 1 ? { nx::mongo::db is_oid [Person insert -name Franz -projects {gtat annobackend abc} -age 29]} 1 # # Quick check of the results: count all persons and count the persons # named Gustaf # ? {Person count} 4 ? {Person count -cond {name = Gustaf}} 1 set n "Gustaf" ? {Person count -cond [list name = $n]} 1 # # Lookup a single Person, create an instance of the object ... # ? {nsf::is object [set p [Person find first -cond {name = Gustaf}]]} 1 ? {Person find first -cond {name = unknown-name}} "" #puts [$p serialize] # # ... change the age, add an project, and save it. # ? {$p configure -age 55} "" ? {$p projects add xowiki} "xowiki nsf nx nxmongo" ? {nx::mongo::db is_oid [$p save]} 1 ? {$p destroy; nsf::is object $p} 0 # # Lookup a single Person and create a named object # ? {Person find first -instance p2 -cond {name = Gustaf}} ::p2 ? {lsort [p2 info vars]} "_id age name projects" ? {p2 destroy; nsf::is object p2} 0 # # Test a few queries based on the user-friendly query language defined # for the class objects. # puts "\nProject members of nsf:" ? {llength [set persons [Person find all -cond {projects = nsf}]]} 2 ? {lsort [lmap p $persons {$p cget -name}]} "Gustaf Stefan" puts "\nProject members of nsf or gtat:" ? {llength [set persons [Person find all -cond {projects in {nsf gtat}} -orderby name]]} 3 ? {lsort [lmap p $persons {$p cget -name}]} "Franz Gustaf Stefan" puts "\nProject members working on both nsf and nxmongo:" ? {llength [set persons [Person find all -cond {projects all {nsf nxmongo}}]]} 1 ? {lsort [lmap p $persons {$p cget -name}]} "Gustaf" puts "\nAll Persons sorted by name (ascending):" ? {llength [set persons [Person find all -orderby name]]} 4 ? {lmap p $persons {$p cget -name}} "Franz Gustaf Joe Stefan" puts "\nMembers of Projects != 'abc' nsf sorted by name desc and age:" ? {llength [set persons [Person find all -cond {projects != "abc"} -orderby {{name desc} age}]]} 2 ? {lmap p $persons {$p cget -name}} "Stefan Gustaf" puts "\nFind persons age > 30:" ? {llength [set persons [Person find all -cond {age > 30}]]} 1 ? {lsort [lmap p $persons {$p cget -name}]} "Gustaf" puts "\nFind persons with names matching regular expression /an/i (containing 'an', ignore case):" ? {llength [set persons [Person find all -cond {name ~ {an i}}]]} 2 ? {lsort [lmap p $persons {$p cget -name}]} "Franz Stefan" # # Define a special find method for "Person" named "oldies" by # extending the query interface (add sub-method to ensemble). # Person public object method "find oldies" {} { return [:find all -cond {age > 30}] } # # Use the special find method # puts "\nFind oldies:" ? {llength [set persons [Person find oldies]]} 1 ? {lsort [lmap p $persons {$p cget -name}]} "Gustaf" puts "\nCreate user with default for password:" ? { #nsf::__profile_trace -enable true -dontsave true -verbose 1 nx::mongo::Class create User { :index name :property name:required :property -incremental {groups:0..n ""} :property {password ""} } } ::User #nsf::__profile_trace -enable false ::User create u1 -name GN -groups {admin teacher} ? {u1 bson asJSON} {{ "__class" : "::User", "groups" : [ "admin", "teacher" ], "name" : "GN", "password" : "" }} # check autoclosing nx::mongo::db close # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/mongodb/tests/nx-bi.test000644 000766 000024 00000013406 13546145706 021360 0ustar00neumannstaff000000 000000 # -*- tcl -*- # # An example for the usage of the nx mongo object mapping based on the # the real world # # "Business Insider" Data Model # # (see e.g. # https://www.slideshare.net/mongodb/nosql-the-shift-to-a-nonrelational-world). # # { title: 'Too Big to Fail', # author: 'John S.', # ts: Date('05-Nov-09 10:33'), # [ comments: [ {author: 'Ian White', # comment: 'Great Article!' }, # {author: 'Joe Smith', # comment: 'But how fast is it?', # replies: [ {author: Jane Smith', # comment: 'scalable?' }] # } # ], # tags: ['finance', 'economy'] # } # # # # Gustaf Neumann fecit, May 2011 # package require nx::mongo package require nx::serializer package require nx::test #nsf::configure debug 2 # Establish connection to the database ::nx::mongo::db connect -db "tutorial" # Make sure, we start always from scratch, so remove everything from # the collection. nx::mongo::db drop collection postings ###################################################################### # Create the application classes based on the "Business Insider" data # model. Note that instances of the class "Comment" can be embedded in # a posting (property "comments") as well as in an comment itself # (property "replies"). All comments are in this example multivalued # and incremental (i.e. one can use slot methods "... add ..." and # "... delete ..." to add values to the attributes). # nx::mongo::Class create Comment { :property author:required :property comment:required :property -incremental replies:embedded,type=::Comment,0..n } nx::mongo::Class create Posting { :index tags :property title:required :property author:required :property ts:required :property -incremental comments:embedded,type=::Comment,0..n :property -incremental tags:0..n } #puts stderr "OP [join [Posting info configure parameters] \n\t]" ###################################################################### # Build a composite Posting instance based on the example above. # set p [Posting new -title "Too Big to Fail" -author "John S." \ -ts "05-Nov-09 10:33" -tags {finance economy} \ -comments [list \ [Comment new -author "Ian White" -comment "Great Article!"] \ [Comment new -author "Joe Smith" -comment "But how fast is it?" \ -replies [list [Comment new -author "Jane Smith" -comment "scalable?"]]] \ ]] # # When we save the item, the embedded objects (the comments and # replies) are saved together with the posting in a compound document. # $p save # After saving the item, the main object contains an _id, such that a # subsequent save operations do not create an additional entries in # the database. For our little experiment here, we like to save # multiple copies to see the results of our changes. Therefore, we # remove the _id manually: $p eval {unset :_id} # We have two comments for the posting $p ? [list llength [$p cget -comments]] 2 # Now we want to remove e.g. the second comment (with the embedded # replies). First get this comment object $c ... set c [lindex [$p cget -comments] 1] # ... and delete it $c delete # The delete operation destroy the embedded object and removes the # reference to it in the comments property. ? [list llength [$p cget -comments]] 1 # The delete operation does not automatically persist the change, # since there might be multiple changes in a complex # document. Therefore, we have to perform an save operation of the # containing document. $p save # Now, we have two postings in the database, the first with the two # comments, the second one with just a single comment. ? {Posting count} 2 # Again, we want to continue with our test and remove the fresh _id as # well. $p eval {unset :_id} # We add an additional comment at the end of the list of the comments # with the incremental operations (the slot is incremental) ... $p comments add [Comment new -author "Gustaf N" -comment "This sounds pretty cool"] end # ... and we add another tag ... $p tags add nx # ... and save everything $p save # We have now three entries in the database collection. ? {Posting count} 3 # Now fetch the first entry with the tag "nx" set q [Posting find first -cond {tags = nx}] # The fetched entry should have the two comments: ? [list llength [$q cget -comments]] 2 # We add jet another tag and save it $q tags add nsf $q save # We still have three entries in the database ? {Posting count} 3 Posting show nx::mongo::db close ###################################################################### # Output ###################################################################### # { # _id: 4daaeb04727b2b1000000000, # title: {Too Big to Fail}, # comments: [ { # author: {Ian White}, # comment: {Great Article!} }, { # replies: [ { # author: {Jane Smith}, # comment: scalable? } ], # author: {Joe Smith}, # comment: {But how fast is it?} } ], # author: {John S.}, # ts: {05-Nov-09 10:33}, # tags: [ finance, economy ] # }, { # _id: 4daaeb04727b2b1000000001, # title: {Too Big to Fail}, # comments: [ { # author: {Ian White}, # comment: {Great Article!} } ], # author: {John S.}, # ts: {05-Nov-09 10:33}, # tags: [ finance, economy ] # }, { # _id: 4daaeb04727b2b1000000002, # title: {Too Big to Fail}, # comments: [ { # author: {Ian White}, # comment: {Great Article!} }, { # author: {Gustaf N}, # comment: {This sounds pretty cool} } ], # author: {John S.}, # ts: {05-Nov-09 10:33}, # tags: [ nsf, nx, finance, economy ] # } ###################################################################### # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/mongodb/tests/nx-reference-one.test000644 000766 000024 00000011501 13441310616 023461 0ustar00neumannstaff000000 000000 # -*- tcl -*- # # This is an introductory example how to use the nx mongo mapping for # referencing some object. We use here an example of an Posting having # a single (possible compound) user as originator. All example work # the same way as well with with multivalued attributes. # # Gustaf Neumann fecit, May 2011 # package require nx::mongo package require nx::test # Establish connection to the database ? {::nx::mongo::db connect -db "tutorial"} mongoc_client_t:0 # Make sure, we start always from scratch nx::mongo::db drop collection users nx::mongo::db drop collection posts ###################################################################### # The first approach to implement references simply as a property. # This is just feasible in cases, where the user has just a name and # not more attributes. # ? {nx::mongo::Class create Post { :property title :property user }} ::Post # Insert entry with the schema of ::Post into the database: ? {nx::mongo::db is_oid [Post insert -title "Hello trivial World" -user smith] } 1 # Retrieve the entry from the database: ? {nsf::is object [set p [Post find first -cond {title = "Hello trivial World"}]]} 1 ? {$p cget -user} smith ? {$p destroy; nsf::is object $p} 0 ###################################################################### # The second approach to implement references to other objects via an # property pointing to the object id of another object. This is the # classical database approach. When the object is fetched, the # application developer has to care about fetching/dereferencing the # referenced object. # ? {nx::mongo::Class create User { :property name }} ::User ? {nx::mongo::Class create Post { :property title :property user_id }} ::Post # The method "insert" returns the object id of the newly created # object. We can use this value as a reference in the Post. ? {nx::mongo::db is_oid [set oid [User insert -name Smith]]} 1 ? {nx::mongo::db is_oid [Post insert -title "Hello simple World" -user_id $oid]} 1 # Retrieve the entry from the database: ? {nsf::is object [set p [Post find first -cond {title = "Hello simple World"}]]} 1 ? {nsf::is object [set u [User find first -cond [list _id = [$p cget -user_id]]]]} 1 ? {$u cget -name} "Smith" ###################################################################### # The third approach is to embed the object in the referencing # document. This might be feasible when the values of the embedded # objects seldom change, When the containing object (the Post # instance) is loaded, the appropriate object structure is created # automatically. # ? {nx::mongo::Class create User { :property name }} ::User ? {nx::mongo::Class create Post { :property title :property user:embedded,type=::User }} ::Post ? {nx::mongo::db is_oid [Post insert -title "Hello embedded World" -user [User new -name Smith]]} 1 # Retrieve the entry from the database: ? {nsf::is object [set p [Post find first -cond {title = "Hello embedded World"}]]} 1 ? {[$p cget -user] cget -name} "Smith" ###################################################################### # The fourth approach is to use mongo db-refs for referencing. This # is similar to approach two, but provides support for dereferencing # and maintaining the reference lists. # ? {nx::mongo::Class create User { :property name }} ::User ? {nx::mongo::Class create Post { :property title :property user:reference,type=::User }} ::Post ? {nx::mongo::db is_oid [Post insert -title "Hello referenced World" -user [User new -name SmithR]]} 1 # Retrieve the entry from the database: ? {nsf::is object [set p [Post find first -cond {title = "Hello referenced World"}]]} 1 ? {[$p cget -user] cget -name} SmithR puts stderr "\nContent of the collection posts:" Post show puts stderr "\nContent of the collection users:" User show ###################################################################### # Output ###################################################################### # Content of the collection posts: # Content of the collection posts: # { # _id: 51fa2f29cb562e0000000000, # title: {Hello trivial World}, # user: smith # }, { # _id: 51fa2f29cb562e0000000002, # title: {Hello simple World}, # user_id: 51fa2f29cb562e0000000001 # }, { # _id: 51fa2f29cb562e0000000003, # title: {Hello embedded World}, # user: { # name: Smith } # }, { # _id: 51fa2f29cb562e0000000005, # title: {Hello referenced World}, # user: { # $ref: users, # $id: 51fa2f29cb562e0000000004, # $db: tutorial } # } # # Content of the collection users: # { # _id: 51fa2f29cb562e0000000001, # name: Smith # }, { # _id: 51fa2f29cb562e0000000004, # name: SmithR # } # ###################################################################### # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/mongodb/tests/t.test000644 000766 000024 00000006131 12303063421 020562 0ustar00neumannstaff000000 000000 # -*- tcl -*- # # This is a sample test set using the low-level (pure tcl) interface # for inserting and querying tuples into MongoDB. # rename load tcl_load proc load {args} {puts stderr "load $args";::tcl_load {*}$args} # package require nsf load /usr/local/ns/lib/nsf2.0b6/libnsf2.0b6.dylib nsf #load /Users/neumann/src/nsf2.0b4/./libnsf2.0b6.dylib nsf puts stderr 3 #package require nsf::mongo load /usr/local/ns/lib/nsfmongo0.2/libnsfmongo0.2.dylib #load /Users/neumann/src/nsf2.0b4/library/mongodb/libnsfmongo0.2.dylib puts stderr 4 exit ======== crash 45-170:~/src/nsf2.0b4% /usr/local/ns/bin/tclsh8.5 library/mongodb/tests/t.test load /usr/local/ns/lib/nsf2.0b6/libnsf2.0b6.dylib nsf Nsf_Init InitHashTable 0x104f71640 InitHashTable 0x104f71640 findProc 0x103a59631 3 load /usr/local/ns/lib/nsfmongo0.2/libnsfmongo0.2.dylib call mutex create hash entry 0x104ff3640 gridfs findProc 0x0 Segmentation fault: 11 ======== no crash 45-170:~/src/nsf2.0b4% export TCLLIBPATH=`pwd` 45-170:~/src/nsf2.0b4% /usr/local/ns/bin/tclsh8.5 library/mongodb/tests/t.test load /Users/neumann/src/nsf2.0b4/./libnsf2.0b6.dylib nsf Nsf_Init InitHashTable 0x110b71640 InitHashTable 0x110b71640 findProc 0x10f677631 3 load /Users/neumann/src/nsf2.0b4/library/mongodb/libnsfmongo0.2.dylib call mutex create hash entry 0x110b71640 gridfs findProc 0x10f677631 mutex unlock call mutex create hash entry 0x110b71640 gridfile findProc 0x10f677631 mutex unlock call mutex create hash entry 0x110b71640 mongo findProc 0x10f677631 mutex unlock call mutex create hash entry 0x110b71640 mongo_cursor findProc 0x10f677631 mutex unlock 4 PointerExit 0x110b71640 =============================== 45-170:~/src/nsf2.0b4% ls -l /usr/local/ns/lib/nsf2.0b6/libnsf2.0b6.dylib /Users/neumann/src/nsf2.0b4/./libnsf2.0b6.dylib -rwxr-xr-x 1 neumann staff 528772 15 Dez 16:00 /Users/neumann/src/nsf2.0b4/./libnsf2.0b6.dylib -rwxr-xr-x 1 root staff 528772 15 Dez 16:00 /usr/local/ns/lib/nsf2.0b6/libnsf2.0b6.dylib 45-170:~/src/nsf2.0b4% md5 /usr/local/ns/lib/nsf2.0b6/libnsf2.0b6.dylib /Users/neumann/src/nsf2.0b4/./libnsf2.0b6.dylib MD5 (/usr/local/ns/lib/nsf2.0b6/libnsf2.0b6.dylib) = 29935b359b7753f52cf5974ea09a8c44 MD5 (/Users/neumann/src/nsf2.0b4/./libnsf2.0b6.dylib) = 29935b359b7753f52cf5974ea09a8c44 45-170:~/src/nsf2.0b4% ls -l /usr/local/ns/lib/nsfmongo0.2/libnsfmongo0.2.dylib /Users/neumann/src/nsf2.0b4/library/mongodb/libnsfmongo0.2.dylib -rwxr-xr-x 1 neumann staff 80640 14 Dez 21:13 /Users/neumann/src/nsf2.0b4/library/mongodb/libnsfmongo0.2.dylib -rwxr-xr-x 1 root staff 80640 15 Dez 16:00 /usr/local/ns/lib/nsfmongo0.2/libnsfmongo0.2.dylib 45-170:~/src/nsf2.0b4% md5 /usr/local/ns/lib/nsfmongo0.2/libnsfmongo0.2.dylib /Users/neumann/src/nsf2.0b4/library/mongodb/libnsfmongo0.2.dylib MD5 (/usr/local/ns/lib/nsfmongo0.2/libnsfmongo0.2.dylib) = d8215601eb16ce19b5669f2b40a1f7ff MD5 (/Users/neumann/src/nsf2.0b4/library/mongodb/libnsfmongo0.2.dylib) = d8215601eb16ce19b5669f2b40a1f7ff ###################################################################### # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/mongodb/tests/nsf-mongo.test000644 000766 000024 00000021560 13560527022 022235 0ustar00neumannstaff000000 000000 # -*- tcl -*- # # This is a sample test set using the low-level (pure tcl) interface # for inserting and querying tuples into MongoDB. # # No interface changes so far between mongodb interface between 2.1 and 2.2. # # Main differences in the query interface due to changes in the # upstream c-driver interface between the interface in nsf 2.0.0 (old) # and 2.1.0 (new): # # Simple Query: # old [::mongo::collection::query $mongoColl [list \$query document {projects string nsf}]] # new [::mongo::collection::query $mongoColl {projects string nsf}] # # old [::mongo::collection::query $mongoColl [list \$query document {age document {$gt int 30}}]] # new [::mongo::collection::query $mongoColl {age document {$gt int 30}}] # # Sort: # old [::mongo::collection::query $mongoColl \ # [list \$query document {projects string nsf} \$orderby document {name int -1}]] # new [::mongo::collection::query $mongoColl \ # {projects string nsf} \ # -opts {sort document {name int -1}}] # Projection: # old [::mongo::collection::query $mongoColl \ # {$query document {age document {$gt int 30}}} \ # -atts {name int 1 age int 1}] # new [::mongo::collection::query $mongoColl \ # {age document {$gt int 30}} \ # -opts {projection document {name int 1 age int 1}}] # # Skip: # old [::mongo::collection::query $mongoColl \ # [list \$query document {projects string nsf} \$orderby document {name int -1}] \ # -skip 1 ] # new [::mongo::collection::query $mongoColl \ # {projects string nsf} \ # -opts { # sort document {name int 1} # skip int64 1 # }] # Limit: # old [::mongo::collection::query $mongoColl \ # [list \$query document {projects string nsf} \$orderby document {name int -1}] \ # -limit 1 ] # new [::mongo::collection::query $mongoColl \ # {projects string nsf} \ # -opts { # sort document {name int 1} # limit int64 1 # }] package require nsf puts stderr "PWD [pwd]" puts stderr "auto_path $auto_path" foreach p [lsort [package names]] { if {![catch {package present $p}]} { set l [format %-15s $p] puts stderr "loaded $l [package ifneeded $p [package require $p]]" } } package require nx::test package require nsf::mongo #nsf::configure debug 2 # # One might query the resulting tuples from the mongo shell via: # # mongo # > use tutorial # > db.persons.find(); # #set mongoConn [::mongo::connect -uri mongodb://127.0.0.1:27017/] ? {set mongoConn [::mongo::connect]} "mongoc_client_t:0" puts "Connection: $mongoConn" if {1} { #::mongo::collection::delete $mongoConn tutorial.persons {} # Drop old potentially old collection and # recreate it as a capped collection ::mongo::run -nocomplain $mongoConn tutorial {drop string persons} puts "\nCreate a capped collection:" ? {::mongo::run $mongoConn tutorial { create string persons capped bool 1 size int32 100000 }} "ok double 1.0" ? {set mongoColl [::mongo::collection::open $mongoConn tutorial persons]} "mongoc_collection_t:0" puts "Collection: $mongoColl" ? {mongo::collection::count $mongoColl {}} 0 puts "\nInserting a few tuples" ? {llength [::mongo::collection::insert $mongoColl \ [list name string Gustaf projects string nsf age int32 53]]} "12" ? {mongo::collection::count $mongoColl {}} 1 ::mongo::collection::insert $mongoColl \ [list name string Stefan projects string nsf] ::mongo::collection::insert $mongoColl \ [list name string Victor a array {0 string "x" 1 string "y"} age int 31] ? { set r [::mongo::collection::insert $mongoColl \ [list name string Joe \ projects string abc \ age int32 23 \ classes array {0 document {$ref string courses $id oid 1}}]] string match "_id oid *" $r } 1 ::mongo::collection::insert $mongoColl \ [list name string Franz info document {x int 203 y int 102} age int 29 projects string gtat] ::mongo::collection::insert $mongoColl \ [list name string Selim ts timestamp {1302945037 1} d date 1302947619279] ? {mongo::collection::count $mongoColl {}} 6 puts stderr "\nCreate an index on name (ascending)" ? {::mongo::collection::index $mongoColl [list name int 1]} 1 } puts stderr "\nFull content" ? {llength [::mongo::collection::query $mongoColl {}]} 6 puts stderr RESULT=[::mongo::collection::query $mongoColl {}] puts stderr "\nProject members" ? { llength [::mongo::collection::query $mongoColl \ {projects string nsf} \ -opts {sort document {name int -1}}] } 2 set all [::mongo::collection::query $mongoColl \ {projects string nsf} \ -opts { sort document {name int 1} }] set first [::mongo::collection::query $mongoColl \ {projects string nsf} \ -opts { sort document {name int 1} limit int64 1 }] set second [::mongo::collection::query $mongoColl \ {projects string nsf} \ -opts { sort document {name int 1} skip int64 1 }] ? {llength $all} 2 ? {list [lindex $all 0]} $first ? {list [lindex $all 1]} $second package req nx::mongo nx::mongo::Class create C set result [::mongo::run $mongoConn tutorial {distinct string persons key string name}] puts stderr "\nDistinct Persons: [C bson pp $result]" puts stderr "\nProject members of nsf sorted by name" ? { set r [lindex [::mongo::collection::query $mongoColl {projects string nsf} \ -opts {sort document {name int 1}}] 0] string match *Gustaf* $r } 1 puts stderr "\nAge > 30 (all atts)" ? { set r [::mongo::collection::query $mongoColl {age document {$gt int 30}}] set _ [llength $r]-[llength [lindex $r 0]] } 2-12 puts stderr "\nAge > 30 (projection on name and age, aside of _id)" ? { set r [::mongo::collection::query $mongoColl \ {age document {$gt int 30}} \ -opts {projection document {name int 1 age int 1}}] set _ [llength $r]-[llength [lindex $r 0]] } 2-9 puts stderr "\nCount Age > 30" ? {::mongo::collection::count $mongoColl {age document {$gt int 30}}} 2 puts stderr "\nAge > 30 (all atts, via cursor interface)" ? { set cursor [::mongo::cursor::find $mongoColl \ {age document {$gt int 30}}] puts "Cursor: $cursor" set r0 [::mongo::cursor::next $cursor] set r1 [::mongo::cursor::next $cursor] set r2 [::mongo::cursor::next $cursor] ::mongo::cursor::close $cursor set _ [llength $r0]-[llength $r1]-[llength $r2] } 12-12-0 puts stderr "\nAge > 30 (all atts, via cursor interface, tailable)" ? { set cursor [::mongo::cursor::find $mongoColl \ {age document {$gt int 30}} \ -opts {tailable boolean true}] if {$cursor ne ""} { set r "" while {1} { lappend r [::mongo::cursor::next $cursor] if {[lindex $r end] eq ""} break } ::mongo::cursor::close $cursor join [lmap x $r {llength $x}] - } } 12-12-0 puts stderr "\nEmpty result (via cursor interface)" ? { set cursor [::mongo::cursor::find $mongoColl \ [list \$query document {age document {$gt int 300}}]] if {$cursor ne ""} { set r {} while {1} { lappend r [::mongo::cursor::next $cursor] if {[lindex $r end] eq ""} break } ::mongo::cursor::close $cursor join [lmap x $r {llength $x}] - } } 0 puts stderr "\nArray 'a' contains 'x'" ? {llength [::mongo::collection::query $mongoColl \ {a string "x"}]} 1 puts stderr "\nEmbedded document has some value (info.y > 100)" ? {llength [::mongo::collection::query $mongoColl \ {info.y document {$gt int 100}}]} 1 puts stderr "\nProjects in {nsf gtat}" ? { llength [::mongo::collection::query $mongoColl \ {projects document {$in array {0 string nsf 1 string gtat}}}]} 3 puts stderr "\nName ~ /an/i" ? { set r [::mongo::collection::query $mongoColl \ {name document {$regex regex {an i}}} \ -opts {projection document {name int 1}}] set _ [llength $r]-[lindex [lindex $r 0] end]-[lindex [lindex $r 1] end] } 2-Franz-Stefan puts stderr "\nStatistics of $mongoColl" set stats [::mongo::collection::stats $mongoColl] ? {expr [llength $stats] % 3 == 0} 1 ? {expr [llength $stats] > 0} 1 if {[llength $stats] % 3 == 0} { puts [C bson pp $stats] } puts stderr "\nStatus" set status [::mongo::status $mongoConn] puts [C bson pp $status] ? {expr [llength $status] % 3 == 0} 1 ? {expr [llength $status] > 0} 1 puts stderr "\nClose connection $mongoConn" ::mongo::close $mongoConn # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/mongodb/tests/nx-serialize.test000644 000766 000024 00000010311 12501766547 022747 0ustar00neumannstaff000000 000000 # -*- tcl -*- # # An example for using MongoDB as a persistence store. # # Gustaf Neumann fecit, Feb 2014 # package require nx::mongo package require nx::serializer package require nx::test #nsf::configure debug 2 ###################################################################### # Define sample methods to use MongoDB as a simple persistence store # for nx. The provided methods are # # nx::Class "mongo persist" ?-db db? ?-collection name? ?-closure? # nx::Class "mongo fetch" ?-db db? ?-collection name? # # where "mongo persist" stores/updates the direct or indirect # instances in the specified collection and "mongo fetch" loads # all instances from this collection # nx::Class public method "mongo persist" { {-db "tutorial"} {-collection "nx"} {-closure:switch} } { set mongo_ns $db.$collection set count(update) 0 set count(insert) 0 foreach i [:info instances -closure=$closure] { set isNew [string match "::nsf::__#*" $i] set bson [list name string $i class string [$i info class] isNew string $isNew] lappend bson definition string [$i serialize] if {[::nx::var exists $i _id]} { #puts "we have to update " ::nx::mongo::db update $mongo_ns [list _id oid [::nx::var set $i _id]] $bson incr count(update) } else { #puts "we have to insert to $mongo_ns" set r [::nx::mongo::db insert $mongo_ns $bson] ::nx::var set $i _id [lindex $r 2] incr count(insert) } } puts "$count(insert) instances inserted, $count(update) instances updated in $mongo_ns" } nx::Class public method "mongo fetch" { {-db "tutorial"} {-collection "nx"} } { set mongo_ns $db.$collection set result {} set bson [::nx::mongo::db query $mongo_ns {}] foreach obj $bson { foreach {att type value} $obj { switch $att { _id {set _id $value} class {set class $value} definition {set definition $value} name {set name $value} } } eval $definition $name eval [list set _id $_id] ::nx::var set $name _id $_id lappend result $name } return $result } # ###################################################################### # # Sample usage of the two methods # # Establish connection to the database ::nx::mongo::db connect -db "tutorial" # Make sure, we start always from scratch, so remove everything from # the collection. nx::mongo::db drop collection nx ###################################################################### # # Define an arbitrary class # nx::Class create Foo { :property title :property {count 1} :public method ++ {} {incr :count} :public method hasArray {} {array exists :a} :public object method counts {} { foreach i [:info instances] {incr c [$i cget -count]} return $c } :public object method countArrays {} { foreach i [:info instances] {incr c [$i hasArray]} return $c } } ###################################################################### # # Create an instance of Foo containing e.g. arrays or dicts as # instance variables # Foo new -title t1 { set :a(1) a set :a(2) b set :d [dict create x 100 y 101] set :count 100 } Foo new -title t2 ? {llength [Foo info instances]} 2 "Foo instances before persist" ? {Foo counts} 101 ? {Foo countArrays} 1 foreach i [Foo info instances] {$i ++} ? {Foo counts} 103 # # Save all instances of Foo (inserts) # Foo mongo persist # # Destroy all instances of Foo in memory # foreach i [Foo info instances] {$i destroy} ? {llength [Foo info instances]} 0 "Foo instances after destroy" # # Load instances from MongoDB # ::nx::Class mongo fetch ? {llength [Foo info instances]} 2 "Foo instances after fetch" ? {Foo counts} 103 ? {Foo countArrays} 1 foreach i [Foo info instances] {$i ++} ? {Foo counts} 105 # # create one more instance, also with an array # Foo new {set :a(x) foo} ? {Foo counts} 106 ? {Foo countArrays} 2 # # Save all instances of Foo (updates) # Foo mongo persist foreach i [Foo info instances] {$i destroy} ? {llength [Foo info instances]} 0 "Foo instances after destroy" ::nx::Class mongo fetch ? {Foo counts} 106 ? {Foo countArrays} 2 ###################################################################### # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/mongodb/tests/nx-reference-many.test000644 000766 000024 00000012425 13331302520 023643 0ustar00neumannstaff000000 000000 # -*- tcl -*- # # This is an introductory example how to use the nx mongo mapping for # referencing some objects. We use here an example of a Group having # a (possible compound) users as members. # # Gustaf Neumann fecit, May 2011 # package require nx::mongo package require nx::test # Establish connection to the database ? {::nx::mongo::db connect -db "tutorial"} mongoc_client_t:0 # Make sure, we start always from scratch nx::mongo::db drop collection groups nx::mongo::db drop collection members ###################################################################### # The first approach to implement references simply as multivalued # attributes. This is just feasible in cases, where the user has just # a name and not more attributes. # ? {nx::mongo::Class create Group { :property name :property members:0..n }} ::Group # Insert entry with the schema of ::Group into the database: ? { nx::mongo::db is_oid [Group insert -name "grp1" -members {gustaf stefan}]} 1 # Retrieve the entry from the database: ? {nsf::is object [set g [Group find first -cond {name = "grp1"}]]} 1 ? {$g cget -members} "gustaf stefan" ###################################################################### # The second approach to implement references to other objects via an # property pointing to the object ids of other objects. This is # similar to the classical database approach. When the object is # fetched, the application developer has to care about # fetching/dereferencing the referenced objects. # ? {nx::mongo::Class create Member { :property name }} ::Member ? {nx::mongo::Class create Group { :property name :property members:0..n }} ::Group ? {nx::mongo::db is_oid [set id1 [Member insert -name gustaf]]} 1 ? {nx::mongo::db is_oid [set id2 [Member insert -name stefan]]} 1 ? {nx::mongo::db is_oid [Group insert -name "grp2" -members [list $id1 $id2]]} 1 # Retrieve the entry from the database: ? {nsf::is object [set g [Group find first -cond {name = "grp2"}]]} 1 # Obtain the objects with the oids contained in the group ? {llength [set members [Member find all -cond [list _id in [$g cget -members]]]]} 2 ? {lsort [lmap m $members {$m cget -name}]} "gustaf stefan" ###################################################################### # The third approach is to embed the objects in the referencing # document. This might be feasible when the values of the embedded # objects seldom change, When the containing object (the posting) is # loaded, the appropriate object structure is created automatically. # ? {nx::mongo::Class create Member { :property name }} ::Member ? {nx::mongo::Class create Group { :property name :property members:embedded,type=::Member,0..n }} ::Group ? {nx::mongo::db is_oid [Group insert -name "grp3" \ -members [list \ [Member new -name gustaf] \ [Member new -name stefan]]]} 1 # Retrieve the entry from the database: ? {nsf::is object [set g [Group find first -cond {name = "grp3"}]]} 1 ? {lsort [lmap m [$g cget -members] {$m cget -name}]} "gustaf stefan" ###################################################################### # The fourth approach is to use mongo db-refs for referencing. This # is similar to approach two, but provides support for dereferencing # and maintaining the reference lists. # ? {nx::mongo::Class create Member { :property name }} ::Member ? {nx::mongo::Class create Group { :property name :property members:reference,type=::Member,0..n }} ::Group # # Currently, the mongo c-driver does not allow one to add DBRefs, since # it refuses to accept field names with leading '$'. So we skip this # version for the time being. # ? {nx::mongo::db is_oid [Group insert -name "grp4" \ -members [list \ [Member new -name gustaf1] \ [Member new -name stefan2]]]} 1 # Retrieve the entry from the database: ? {nsf::is object [set g [Group find first -cond {name = "grp4"}]]} 1 ? {lsort [lmap m [$g cget -members] {$m cget -name}]} "gustaf1 stefan2" puts stderr "\nContent of collection groups:" Group show puts stderr "\nContent of collection members:" Member show ###################################################################### # Output ###################################################################### # Content of collection groups: # { # _id: 51fa2ea113760b0000000000, # name: grp1, # members: [ gustaf, stefan ] # }, { # _id: 51fa2ea113760b0000000003, # name: grp2, # members: [ 51fa2ea113760b0000000001, 51fa2ea113760b0000000002 ] # }, { # _id: 51fa2ea113760b0000000004, # name: grp3, # members: [ { # name: gustaf }, { # name: stefan } ] # }, { # _id: 51fa2ea113760b0000000007, # name: grp4, # members: [ { # $ref: members, # $id: 51fa2ea113760b0000000005, # $db: tutorial }, { # $ref: members, # $id: 51fa2ea113760b0000000006, # $db: tutorial } ] # } # # Content of collection members: # { # _id: 51fa2ea113760b0000000001, # name: gustaf # }, { # _id: 51fa2ea113760b0000000002, # name: stefan # }, { # _id: 51fa2ea113760b0000000005, # name: gustaf1 # }, { # _id: 51fa2ea113760b0000000006, # name: stefan2 # } ###################################################################### # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/mongodb/tests/nsf-gridfs.test000644 000766 000024 00000010006 14275673066 022403 0ustar00neumannstaff000000 000000 # -*- tcl -*- # # This test suite tests some basic interactions from the nsf mongo # interface with gridFS. It connects to mongoDB, opens a GridFS named # "myfs" and inserts a file into the filesystems. Run the script # with the current directory of nsfmongo, such it can find the README # file. # # After running the script, one can use the following command to # inspect the content in the GridFS via the mongo shell # # $ mongo # > use myfs # > show collections # > db.fs.files.find() # # or via the mongofiles interface: # # $ mongofiles -d myfs list # package require nx::test package require nsf::mongo # # First, as usual, open the connection to the mongo db # ? {set mongoConn [::mongo::connect]} mongoc_client_t:0 # # Open a GridFS in the mongo database "myfs" and use the usual prefix # "fs", such GridFS names the collections "fs.chunks" and "fs.files". # ? {set gridFS [::mongo::gridfs::open $mongoConn myfs fs]} mongoc_gridfs_t:0 set dir [file dirname [file dirname [info script]]] set fn [glob -tails -directory $dir -- README.md] ? {llength $fn} 1 ? {file readable [file join $dir $fn]} 1 set fileSize [file size $fn] # gridfs::remove_file removes all files with the specified name # multiple store operations create "revisions" with different uploadDates ::mongo::gridfile::delete $gridFS [list filename string $fn] # get the fs.files collection set mongoColl [mongo::collection::open $mongoConn myfs fs.files] # # The current version of gridfs_store_file() is quite unfriendly, # since it assumes that the file exists, and aborts otherwise. So, we # perform the existence test here. # # Store a known file: # ? {::mongo::gridfile::create -source file $gridFS [file join $dir $fn] $fn text/plain} 1 # # Open grid file, get some of its properties, and read it in chunks # of 1000 bytes, and close it finally. ? {set f [mongo::gridfile::open $gridFS [list filename string $fn]]} mongoc_gridfs_file_t:0 ? {mongo::gridfile::get_metadata $f} "" ? {mongo::gridfile::get_contentlength $f} [file size [file join $dir $fn]] ? {mongo::gridfile::get_contenttype $f} text/plain ? { set chunks 0 while {1} { set chunk [mongo::gridfile::read $f 1000] puts "... read chunk length [string length $chunk]" if {[string length $chunk] > 0} { incr chunks } if {[string length $chunk] < 1000} { break } } set chunks } [expr {$fileSize/1000 + 1}] ? {mongo::gridfile::close $f} "" # # Access the files stored in the gridfs via plain query interface. # (should be just one) puts "\nAll Files:" #puts [join [::mongo::collection::query $mongoColl {}] \n] set nr1 [llength [::mongo::collection::query $mongoColl {}]] ? {expr {$nr1 > 0}} 1 # store one more copy ? {::mongo::gridfile::create -source file $gridFS [file join $dir $fn] $fn text/plain} 1 # we should have now one more entry: set nr2 [llength [::mongo::collection::query $mongoColl {}]] ? {expr {$nr2 == $nr1 + 1}} 1 puts [join [::mongo::collection::query $mongoColl {}] \n] # # Get the file named README from the gridfs via plain query interface # ? {set files [::mongo::collection::query $mongoColl \ [list filename string $fn] \ -opts { limit int64 1 }] llength [lindex $files 0] } 18 # # Extract the oid from the bson attributes # ? { foreach {name type value} [lindex $files 0] { if {$name eq "_id"} {set oid $value; break} } expr {$oid ne ""} } 1 # # Add a dc:creator to the bson attributes # and update the entry in the gridfs # ? {::mongo::collection::update $mongoColl [list _id oid $oid] \ [concat [lindex $files 0] [list metadata document {dc:creator string "Gustaf Neumann"}]] } "" # # Now we can use the gridfs interface to obtain the additional # metadata as well # set f [mongo::gridfile::open $gridFS [list _id oid $oid]] ? {mongo::gridfile::get_metadata $f} "dc:creator string {Gustaf Neumann}" mongo::gridfile::close $f # # close everything # ::mongo::gridfs::close $gridFS ::mongo::collection::close $mongoColl ::mongo::close $mongoConn # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/mongodb/tests/korecky.tcl000644 000766 000024 00000002246 13443655612 021613 0ustar00neumannstaff000000 000000 package require nx::mongo ::nx::mongo::db connect -db "testing" # # Simplified example # nx::mongo::db drop collection posts nx::mongo::Class create Post { :index id :index replyToId :property -accessor public id:required :property -accessor public replyToId:required :property -accessor public subject :property -accessor public body :property -accessor public author:required :property -accessor public {rating 0} } # # Create a few posting objects in memory and save these # Post new -id 1 -replyToId 0 -rating 1 -subject "p1" -author rl Post new -id 2 -replyToId 1 -rating 2 -subject "re: p1" -author gn Post new -id 3 -replyToId 1 -rating 0 -subject "re: p1" -author aa Post new -id 4 -replyToId 1 -rating 1 -subject "re: p1 (in Österreich)" -author bb foreach p [Post info instances] {$p save} # # Query replies to "1" and try different sortings # set id 1 set orderby rating Post show -cond "replyToId = $id" -orderby "{$orderby desc}" set orderby id Post show -cond "replyToId = $id" -orderby "{$orderby desc}" # # Print posting objects in memory as JSON # foreach p [Post info instances] { puts [mongo::json::generate [$p bson encode]] } ./nsf2.4.0/library/mongodb/tests/nx-rep.test000644 000766 000024 00000010461 13331302520 021527 0ustar00neumannstaff000000 000000 # -*- tcl -*- # # An example for the usage of the nx mongo object mapping with # input/export functions for variables not following the standard # nx-mapping of properties. # # The MongoDB nx package supports special codec (encoding/decoding) # functions which perform the mapping from instance variables to bson # and vice versa. These special mappings can be defined via the # attribute "rep" for :variable and :property. The predefined # representations for "array" and "dict" are included here. The rep # mechanism is extensible, users can define on the application layer # their own representations. # package require nx::mongo package require nx::serializer package require nx::test #nsf::configure debug 2 # Establish connection to the database ::nx::mongo::db connect -db "tutorial" # Make sure, we start always from scratch, so remove everything from # the collection. nx::mongo::db drop collection foos ###################################################################### # nx-mongo has a built-in special representation for Tcl arrays which # can be used via e.g. # # :variable -rep array a # # The "array" representation differs from a string representation by # requiring a different method in tcl to read its values, and by # saving the tcl array in mongoDB in a different notation. The chosen # representation of the array in mongoDB is an array of key/value # pairs. # # Similarly we provide here a "dict" mapping, which transforms a dict # to a form similar to a nested object. Just the first level of the # dict is transformed. ###################################################################### # # Extend ::nx::mongo::Class to handle rep codecs "array" and "dict" # ::nx::mongo::Class eval { # # rep codec "array" # :public method "bson rep encode array" {slot obj name} { set body {} set c 0 foreach {k v} [$obj eval [list array get :$name]] { lappend body [incr c] document [list k string $k v string $v] } return [list array $body] } :public method "bson rep decode array" {slot name bsontype value} { set av "" foreach {pos type entry} $value { lappend av [lindex $entry 2] [lindex $entry 5] } return "array set :$name [list $av]" } # # rep codec "dict" # :public method "bson rep encode dict" {slot obj name} { set body {} dict for {k v} [$obj eval [list set :$name]] { lappend body $k string $v } return [list document $body] } :public method "bson rep decode dict" {slot name bsontype value} { set result "" foreach {k type v} $value { lappend result $k $v } return "set :$name \[dict create $result\]" } } ###################################################################### # # Define an application class Foo, using the rep type "array" for # instance variable "a" and the rep type "dict" for instance variable # "d". # nx::mongo::Class create Foo { :index tags :property title :property -incremental tags:0..n :variable -rep array a :variable -rep dict d :public method bar {} {return [lsort [array names :a]]} :public method baz {key} {dict get ${:d} $key} } ###################################################################### # Build a composite Posting instance based on the example above. # set p [Foo new -title "Hello World" { :tags add a set :a(1) a set :a(2) b set :d [dict create first_name Walter second_name White] }] ? {$p bar} "1 2" ? {$p baz first_name} "Walter" # # When we save the item, the instances variables are transformed into # a mongoDB representation, using the rep types defined above. # ? {nx::mongo::db is_oid [$p save]} 1 $p destroy ? {nsf::is object $p} 0 # Now fetch the first entry set q [Foo find first] ? {$q bar} "1 2" ? {$q baz first_name} "Walter" Foo show puts stderr "====EXIT [info script]" ###################################################################### # Output ###################################################################### # # { # _id: 5301d307249bc51c00000000, # d: { # first_name: Walter, # second_name: White }, # a: [ { # k: 1, # v: a }, { # k: 2, # v: b } ], # title: {Hello World}, # tags: [ a ] # } ###################################################################### # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/mongodb/tests/array.test000644 000766 000024 00000001452 13464235045 021452 0ustar00neumannstaff000000 000000 # -*- tcl -*- # # This is a sample test set using the low-level (pure tcl) interface # for inserting and querying tuples into MongoDB. # package require nsf package require nx::test package require nsf::mongo #nsf::configure debug 2 # # One might query the resulting tuples from the mongo shell via: # # mongo # > use tutorial # > db.persons.find(); # ? {set mongoConn [::mongo::connect]} "mongoc_client_t:0" puts "Connection: $mongoConn" ? {set mongoColl [::mongo::collection::open $mongoConn tutorial persons]} "mongoc_collection_t:0" puts "Collection: $mongoColl" puts PERSONS=[::mongo::collection::query $mongoColl {}] ? {set mongoColl [::mongo::collection::open $mongoConn tutorial z]} "mongoc_collection_t:1" puts "Collection: $mongoColl" puts Z=[::mongo::collection::query $mongoColl {}] ./nsf2.4.0/library/mongodb/README.md000644 000766 000024 00000011607 14274724145 017557 0ustar00neumannstaff000000 000000 # Interface between MongoDB and the Next Scripting Framework # This is an interface between MongoDB based on NSF (Next Scripting Framework) This implementation provides a low-level interface based on tagged elements to force / preserve the datatypes of MongoDB when converting into Tcl. This code serves as well as an example how to use the source code generator of NSF. The example shows how to use the source code generator from NSF to generate a C interface. -gustaf neumann March 27, 2011 -stefan sobernig May 6, 2019 ## Ingredients: ## https://github.com/mongodb/mongo https://github.com/mongodb/mongo-c-driver The current version of the NSF mongo binding is 2.2 and was tested with - Tcl 8.5, 8.6 and 8.7 - MongoDB 5.0.9 (released May 31, 2022) - mongodb-c-driver 1.22.1 (released August 2, 2022) - libbson 1.22.1 (released August 2, 2022) Follow the following steps to get MongoDB up and running and to compile the MongoDB driver for NX. ## Obtain MongoDB and Mongo-C-Driver: ## - Compile or obtain MongoDB (the database). - Compile or obtain the mongo-c-driver (client interface) ```` cd /usr/local/src wget https://github.com/mongodb/mongo-c-driver/releases/download/1.22.0/mongo-c-driver-1.22.0.tar.gz tar zxvf mongo-c-driver-1.22.0.tar.gz rm -rf mongo-c-driver ln -sf mongo-c-driver-1.22.0 mongo-c-driver cd mongo-c-driver cmake . make sudo make install ```` Alternatively, one can get the newest version from git ```` cd /usr/local/src git clone https://github.com/mongodb/mongo-c-driver cd mongo-c-driver cmake . make sudo make install ```` If you experience errors during autogen on Debian, you might have to apt-get install libtool If configure complains about not finding bson, you might have to do export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig Note: Version 1.5.1 of the c-driver leads on macOS to a crash on exit, when configured SASL support (from mac ports) and the flag "--disable-automatic-init-and-cleanup" is missing. ## Compiling the MongoDB NSF Binding: ## Assume the following installation directories - Tcl: /usr/local/ns/lib/ - mongo-c-driver: /usr/local/src/mongo-c-driver/ Configure the MongoDB NSF interface via the following command in the directory nsf*/library/mongodb/ You will probably have to adjust the paths. ```` ./configure --with-tcl=/usr/local/ns/lib/ --prefix=/usr/local/ns --with-nsf=../../ \ --with-mongoc=/usr/local/include/libmongoc-1.0/,/usr/local/lib/ \ --with-bson=/usr/local/include/libbson-1.0/,/usr/local/lib/ \ --enable-threads --enable-symbols ```` In order to run the NSF sample script, perform the following steps * first start the mongodb (e.g. mongod) * go to your NSF source directory * make sure, the c-driver libraries are on the library path (assuming the c-driver was installed in /usr/local/lib) Linux: ```` export LD_LIBRARY_PATH=/usr/local/lib:`pwd` ```` macOS: ```` export DYLD_LIBRARY_PATH=/usr/local/lib:`pwd` ```` * run ```` ./nxsh library/mongodb/tests/nsf-mongo.test ```` The script tests the low-level interface (nsf::mongo) and the high-level one (nx::mongo), with each exercising a few insert, query and delete statements. After running this script, you should check the content using the MongoDB shell: ```` % mongo MongoDB shell version: v4.0.9 connecting to: test > use tutorial switched to db tutorial > db.persons.find(); { "_id" : ObjectId("530c6e4649686ad16e261f81"), "name" : "Gustaf", "projects" : "nsf", "age" : 53 } { "_id" : ObjectId("530c6e4649686ad16e261f82"), "name" : "Stefan", "projects" : "nsf" } { "_id" : ObjectId("530c6e4649686ad16e261f83"), "name" : "Victor", "a" : [ "x", "y" ], "age" : 31 } { "_id" : ObjectId("530c6e4649686ad16e261f84"), "name" : "Joe", "projects" : "abc", "age" : 23, "classes" : [ DBRef("courses", ObjectId("100000000000000000000000")) ] } { "_id" : ObjectId("530c6e4649686ad16e261f85"), "name" : "Franz", "info" : { "x" : 203, "y" : 102 }, "age" : 29, "projects" : "gtat" } { "_id" : ObjectId("530c6e4649686ad16e261f86"), "name" : "Selim", "ts" : Timestamp(1302945037, 1), "d" : ISODate("2011-04-16T09:53:39.279Z") } > quit() ```` ## Testing the object oriented mapping between NX and MongoDB: ## Test the basic mapping and the OO query methods: ```` ./nxsh library/mongodb/tests/nx-mongo.test ```` Show the classical Business Informer example in NX: ```` ./nxsh library/mongodb/tests/nx-bi.test ```` Further test scripts for reference handling, serialization and MongoDB GridFS. ```` ./nxsh library/mongodb/tests/nx-reference-one.test ./nxsh library/mongodb/tests/nx-reference-many.test ./nxsh library/mongodb/tests/nx-rep.test ./nxsh library/mongodb/tests/nx-serialize.test ./nxsh library/mongodb/tests/nsf-gridfs.test ```` ./nsf2.4.0/library/mongodb/example-nx-wiki.tcl000644 000766 000024 00000002312 12440120610 021770 0ustar00neumannstaff000000 000000 package require nx::mongo package require nx::serializer package require nx::test # Establish connection to the database ::nx::mongo::db connect -db "tutorial" # Make sure, we start always from scratch, so remove everything from # the collection. nx::mongo::db remove tutorial.pages {} nx::mongo::Class create nx::mongo::Content { :property text:optional :property mime_type:optional } # item_id, (revision_id != 0) ? nx::mongo::Class create nx::mongo::Page { :index tags :property name:required :property title:optional :property creator:optional :property page_order:optional :property description:optional :property nls_language:optional ;# en, es, de, ... | locale: en_US, ... :property creation_user:integer,required ;# openacs-id? openacs-fk? user_id? :property publish_date:required :property publish_status:required :property content:embedded,type=::nx::mongo::Content :property page_template:optional ;# openacs-id? :property instance_attributes:optional ;# attributes? :property assignee ;# openacs-id? openacs-fk? user_id? :property state :property form :property form_constraints :property tags:incremental,0..n } ./nsf2.4.0/library/mongodb/pkgIndex.add000644 000766 000024 00000000126 14276141432 020507 0ustar00neumannstaff000000 000000 package ifneeded nsf::mongo 2.4.0 [list load [file join $dir libnsfmongo2.4.0.dylib]] ./nsf2.4.0/library/mongodb/pkgIndex.add.in000644 000766 000024 00000000132 12501766547 021122 0ustar00neumannstaff000000 000000 package ifneeded nsf::mongo @PACKAGE_VERSION@ [list load [file join $dir @PKG_LIB_FILE@]] ./nsf2.4.0/library/mongodb/m4/PaxHeader/tcl.m4000644 000766 000024 00000000036 14270756061 021605 xustar00neumannstaff000000 000000 30 mtime=1659100209.805200373 ./nsf2.4.0/library/mongodb/m4/tcl.m4000644 000766 000024 00000427317 14270756061 017653 0ustar00neumannstaff000000 000000 # tcl.m4 -- # # This file provides a set of autoconf macros to help TEA-enable # a Tcl extension. # # Copyright (c) 1999-2000 Ajuba Solutions. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. AC_PREREQ(2.57) dnl TEA extensions pass us the version of TEA they think they dnl are compatible with (must be set in TEA_INIT below) dnl TEA_VERSION="3.10" # Possible values for key variables defined: # # TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') # TEA_PLATFORM - windows unix # TEA_TK_EXTENSION - True if this is a Tk extension # TEACUP_OS - windows macosx linux generic # TEACUP_TOOLSET - Toolset in use (gcc,mingw,msvc,llvm) # TEACUP_PROFILE - win32 # #------------------------------------------------------------------------ # TEA_PATH_TCLCONFIG -- # # Locate the tclConfig.sh file and perform a sanity check on # the Tcl compile flags # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tcl=... # # Defines the following vars: # TCL_BIN_DIR Full path to the directory containing # the tclConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TCLCONFIG], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true AC_ARG_WITH(tcl, AC_HELP_STRING([--with-tcl], [directory containing tcl configuration (tclConfig.sh)]), with_tclconfig="${withval}") AC_MSG_CHECKING([for Tcl configuration]) AC_CACHE_VAL(ac_cv_c_tclconfig,[ # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case "${with_tclconfig}" in */tclConfig.sh ) if test -f "${with_tclconfig}"; then AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" else AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/pkg/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ `ls -d /usr/lib/tcl8.6 2>/dev/null` \ `ls -d /usr/lib/tcl8.5 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" AC_MSG_ERROR([Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh]) else no_tcl= TCL_BIN_DIR="${ac_cv_c_tclconfig}" AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_PATH_TKCONFIG -- # # Locate the tkConfig.sh file # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tk=... # # Defines the following vars: # TK_BIN_DIR Full path to the directory containing # the tkConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TKCONFIG], [ # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true TEA_TK_EXTENSION=0 AC_ARG_WITH(tk, AC_HELP_STRING([--with-tk], [directory containing tk configuration (tkConfig.sh)]), with_tkconfig="${withval}") AC_MSG_CHECKING([for Tk configuration]) AC_CACHE_VAL(ac_cv_c_tkconfig,[ # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case "${with_tkconfig}" in */tkConfig.sh ) if test -f "${with_tkconfig}"; then AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" else AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" AC_MSG_ERROR([Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh]) else no_tk= TEA_TK_EXTENSION=1 TK_BIN_DIR="${ac_cv_c_tkconfig}" AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_TCLCONFIG -- # # Load the tclConfig.sh file # # Arguments: # # Requires the following vars to be set: # TCL_BIN_DIR # # Results: # # Substitutes the following vars: # TCL_BIN_DIR # TCL_SRC_DIR # TCL_LIB_FILE #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TCLCONFIG], [ AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TCL_BIN_DIR}/tclConfig.sh" else AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitrary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" break fi done fi if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" AC_SUBST(TCL_VERSION) AC_SUBST(TCL_PATCH_LEVEL) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) AC_MSG_CHECKING([platform]) hold_cc=$CC; CC="$TCL_CC" AC_TRY_COMPILE(,[ #ifdef _WIN32 #error win32 #endif ], [ TEA_PLATFORM="unix" CYGPATH=echo ], [ TEA_PLATFORM="windows" AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) ] ) CC=$hold_cc AC_MSG_RESULT($TEA_PLATFORM) # The BUILD_$pkg is to define the correct extern storage class # handling when making this package AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME}, [], [Building extension source?]) # Do this here as we have fully defined TEA_PLATFORM now if test "${TEA_PLATFORM}" = "windows" ; then EXEEXT=".exe" CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp" fi # TEA specific: AC_SUBST(CLEANFILES) AC_SUBST(TCL_LIBS) AC_SUBST(TCL_DEFS) AC_SUBST(TCL_EXTRA_CFLAGS) AC_SUBST(TCL_LD_FLAGS) AC_SUBST(TCL_SHLIB_LD_LIBS) ]) #------------------------------------------------------------------------ # TEA_LOAD_TKCONFIG -- # # Load the tkConfig.sh file # # Arguments: # # Requires the following vars to be set: # TK_BIN_DIR # # Results: # # Sets the following vars that should be in tkConfig.sh: # TK_BIN_DIR #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TKCONFIG], [ AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TK_BIN_DIR}/tkConfig.sh" else AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TK_BIN_DIR}/Makefile" ; then TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tk.framework installed in an arbitrary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then for i in "`cd "${TK_BIN_DIR}"; pwd`" \ "`cd "${TK_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" break fi done fi if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" # TEA specific: Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) TEA_WINDOWINGSYSTEM="aqua" ;; *) TEA_WINDOWINGSYSTEM="x11" ;; esac elif test "${TEA_PLATFORM}" = "windows" ; then TEA_WINDOWINGSYSTEM="win32" fi AC_SUBST(TK_VERSION) AC_SUBST(TK_BIN_DIR) AC_SUBST(TK_SRC_DIR) AC_SUBST(TK_LIB_FILE) AC_SUBST(TK_LIB_FLAG) AC_SUBST(TK_LIB_SPEC) AC_SUBST(TK_STUB_LIB_FILE) AC_SUBST(TK_STUB_LIB_FLAG) AC_SUBST(TK_STUB_LIB_SPEC) # TEA specific: AC_SUBST(TK_LIBS) AC_SUBST(TK_XINCLUDES) ]) #------------------------------------------------------------------------ # TEA_PROG_TCLSH # Determine the fully qualified path name of the tclsh executable # in the Tcl build directory or the tclsh installed in a bin # directory. This macro will correctly determine the name # of the tclsh executable even if tclsh has not yet been # built in the build directory. The tclsh found is always # associated with a tclConfig.sh file. This tclsh should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments: # none # # Results: # Substitutes the following vars: # TCLSH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_TCLSH], [ AC_MSG_CHECKING([for tclsh]) AC_ARG_WITH(tclsh, [ --with-tclsh Specify a local tcl shell to use for dynamic code], with_tclsh=${withval}) # Use the value from --with-tclsh, if it was given TCLSH_PROG=0 if test x"${with_tclsh}" != x ; then if test -f "${with_tclsh}" ; then TCLSH_PROG=${with_tclsh} else if test -f "${with_tclsh}/tcl8.6" ; then TCLSH_PROG="${with_tclsh}/tcl8.6" else if test -f "${with_tclsh}/tclsh86.exe" ; then TCLSH_PROG="${with_tclsh}/tclsh86.exe" else AC_MSG_ERROR([${with_tclsh} does not point to a valid Tcl executable]) fi fi fi else if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" fi else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" fi fi AC_MSG_RESULT([${TCLSH_PROG}]) AC_SUBST(TCLSH_PROG) ]) #------------------------------------------------------------------------ # TEA_PROG_WISH # Determine the fully qualified path name of the wish executable # in the Tk build directory or the wish installed in a bin # directory. This macro will correctly determine the name # of the wish executable even if wish has not yet been # built in the build directory. The wish found is always # associated with a tkConfig.sh file. This wish should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments: # none # # Results: # Substitutes the following vars: # WISH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_WISH], [ AC_MSG_CHECKING([for wish]) if test -f "${TK_BIN_DIR}/Makefile" ; then # tkConfig.sh is in Tk build directory if test "${TEA_PLATFORM}" = "windows"; then if test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}s${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}$s{EXEEXT}" elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}t${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}t${EXEEXT}" elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}st${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}st${EXEEXT}" fi else WISH_PROG="${TK_BIN_DIR}/wish" fi else # tkConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" fi list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TK_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${WISH_PROG}" ; then REAL_TK_BIN_DIR="`cd "$i"; pwd`/" break fi done WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" fi AC_MSG_RESULT([${WISH_PROG}]) AC_SUBST(WISH_PROG) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SHARED -- # # Allows the building of shared libraries # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-shared=yes|no # --enable-stubs=yes|no # # Defines the following vars: # STATIC_BUILD Used for building import/export libraries # on Windows. # # Sets the following vars: # SHARED_BUILD Value of 1 or 0 # STUBS_BUILD Value if 1 or 0 # USE_TCL_STUBS Value true: if SHARED_BUILD or --enable-stubs # USE_TCLOO_STUBS Value true: if SHARED_BUILD or --enable-stubs # USE_TK_STUBS Value true: if SHARED_BUILD or --enable-stubs # AND TEA_WINDOWING_SYSTEM != "" #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SHARED], [ AC_MSG_CHECKING([how to build libraries]) AC_ARG_ENABLE(shared, AC_HELP_STRING([--enable-shared], [build and link with shared libraries (default: on)]), [shared_ok=$enableval], [shared_ok=yes]) if test "${enable_shared+set}" = set; then enableval="$enable_shared" shared_ok=$enableval else shared_ok=yes fi AC_ARG_ENABLE(stubs, AC_HELP_STRING([--enable-stubs], [build and link with stub libraries. Always true for shared builds (default: on)]), [stubs_ok=$enableval], [stubs_ok=yes]) if test "${enable_stubs+set}" = set; then enableval="$enable_stubs" stubs_ok=$enableval else stubs_ok=yes fi # Stubs are always enabled for shared builds if test "$shared_ok" = "yes" ; then AC_MSG_RESULT([shared]) SHARED_BUILD=1 STUBS_BUILD=1 else AC_MSG_RESULT([static]) SHARED_BUILD=0 AC_DEFINE(STATIC_BUILD, 1, [This a static build]) if test "$stubs_ok" = "yes" ; then STUBS_BUILD=1 else STUBS_BUILD=0 fi fi if test "${STUBS_BUILD}" = "1" ; then AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) AC_DEFINE(USE_TCLOO_STUBS, 1, [Use TclOO stubs]) if test "${TEA_WINDOWINGSYSTEM}" != ""; then AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) fi fi AC_SUBST(SHARED_BUILD) AC_SUBST(STUBS_BUILD) ]) #------------------------------------------------------------------------ # TEA_ENABLE_THREADS -- # # Specify if thread support should be enabled. If "yes" is specified # as an arg (optional), threads are enabled by default, "no" means # threads are disabled. "yes" is the default. # # TCL_THREADS is checked so that if you are compiling an extension # against a threaded core, your extension must be compiled threaded # as well. # # Note that it is legal to have a thread enabled extension run in a # threaded or non-threaded Tcl core, but a non-threaded extension may # only run in a non-threaded Tcl core. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-threads # # Sets the following vars: # THREADS_LIBS Thread library(s) # # Defines the following vars: # TCL_THREADS # _REENTRANT # _THREAD_SAFE #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_THREADS], [ AC_ARG_ENABLE(threads, AC_HELP_STRING([--enable-threads], [build with threads]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention AC_DEFINE(USE_THREAD_ALLOC, 1, [Do we want to use the threaded memory allocator?]) AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) if test "`uname -s`" = "SunOS" ; then AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) fi AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] AC_CHECK_LIB(pthread, __pthread_mutex_init, tcl_ok=yes, tcl_ok=no) fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else AC_CHECK_LIB(pthreads, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else AC_CHECK_LIB(c, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "no"; then AC_CHECK_LIB(c_r, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 AC_MSG_WARN([Do not know how to find pthread lib on your system - thread support disabled]) fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output AC_MSG_CHECKING([for building with threads]) if test "${TCL_THREADS}" = 1; then AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) AC_MSG_RESULT([yes (default)]) else AC_MSG_RESULT([no]) fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then AC_MSG_WARN([ Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads.]) fi ;; *) if test "${TCL_THREADS}" = "1"; then AC_MSG_WARN([ --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core.]) fi ;; esac AC_SUBST(TCL_THREADS) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SYMBOLS -- # # Specify if debugging symbols should be used. # Memory (TCL_MEM_DEBUG) debugging can also be enabled. # # Arguments: # none # # TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives # the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted. # Requires the following vars to be set in the Makefile: # CFLAGS_DEFAULT # LDFLAGS_DEFAULT # # Results: # # Adds the following arguments to configure: # --enable-symbols # # Defines the following vars: # CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true # Sets to "$(CFLAGS_OPTIMIZE) -DNDEBUG" if false # LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true # Sets to $(LDFLAGS_OPTIMIZE) if false # DBGX Formerly used as debug library extension; # always blank now. #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SYMBOLS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_CONFIG_CFLAGS]) AC_MSG_CHECKING([for build with symbols]) AC_ARG_ENABLE(symbols, AC_HELP_STRING([--enable-symbols], [build with debugging symbols (default: off)]), [tcl_ok=$enableval], [tcl_ok=no]) DBGX="" if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" AC_MSG_RESULT([no]) else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then AC_MSG_RESULT([yes (standard debugging)]) fi fi # TEA specific: if test "${TEA_PLATFORM}" != "windows" ; then LDFLAGS_DEFAULT="${LDFLAGS}" fi AC_SUBST(CFLAGS_DEFAULT) AC_SUBST(LDFLAGS_DEFAULT) AC_SUBST(TCL_DBGX) if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then AC_MSG_RESULT([enabled symbols mem debugging]) else AC_MSG_RESULT([enabled $tcl_ok debugging]) fi fi ]) #------------------------------------------------------------------------ # TEA_ENABLE_LANGINFO -- # # Allows use of modern nl_langinfo check for better l10n. # This is only relevant for Unix. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-langinfo=yes|no (default is yes) # # Defines the following vars: # HAVE_LANGINFO Triggers use of nl_langinfo if defined. #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_LANGINFO], [ AC_ARG_ENABLE(langinfo, AC_HELP_STRING([--enable-langinfo], [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), [langinfo_ok=$enableval], [langinfo_ok=yes]) HAVE_LANGINFO=0 if test "$langinfo_ok" = "yes"; then AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) fi AC_MSG_CHECKING([whether to use nl_langinfo]) if test "$langinfo_ok" = "yes"; then AC_CACHE_VAL(tcl_cv_langinfo_h, [ AC_TRY_COMPILE([#include ], [nl_langinfo(CODESET);], [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) AC_MSG_RESULT([$tcl_cv_langinfo_h]) if test $tcl_cv_langinfo_h = yes; then AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) fi else AC_MSG_RESULT([$langinfo_ok]) fi ]) #-------------------------------------------------------------------- # TEA_CONFIG_SYSTEM # # Determine what the system is (some things cannot be easily checked # on a feature-driven basis, alas). This can usually be done via the # "uname" command. # # Arguments: # none # # Results: # Defines the following var: # # system - System/platform/version identification code. #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_SYSTEM], [ AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then AC_MSG_WARN([can't find uname command]) tcl_cv_sys_version=unknown else if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi ]) system=$tcl_cv_sys_version ]) #-------------------------------------------------------------------- # TEA_CONFIG_CFLAGS # # Try to determine the proper flags to pass to the compiler # for building shared libraries and other such nonsense. # # Arguments: # none # # Results: # # Defines and substitutes the following vars: # # DL_OBJS, DL_LIBS - removed for TEA, only needed by core. # LDFLAGS - Flags to pass to the compiler when linking object # files into an executable application binary such # as tclsh. # LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. Could # be the same as CC_SEARCH_FLAGS if ${CC} is used to link. # CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. # SHLIB_CFLAGS - Flags to pass to cc when compiling the components # of a shared library (may request position-independent # code, among other things). # SHLIB_LD - Base command to use for combining object files # into a shared library. # SHLIB_LD_LIBS - Dependent libraries for the linker to scan when # creating shared libraries. This symbol typically # goes at the end of the "ld" commands that build # shared libraries. The value of the symbol defaults to # "${LIBS}" if all of the dependent libraries should # be specified when creating a shared library. If # dependent libraries should not be specified (as on # SunOS 4.x, where they cause the link to fail, or in # general if Tcl and Tk aren't themselves shared # libraries), then this symbol has an empty string # as its value. # SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable # extensions. An empty string means we don't know how # to use shared libraries on this platform. # LIB_SUFFIX - Specifies everything that comes after the "libfoo" # in a static or shared library name, using the $PACKAGE_VERSION variable # to put the version in the right place. This is used # by platforms that need non-standard library names. # Examples: ${PACKAGE_VERSION}.so.1.1 on NetBSD, since it needs # to have a version after the .so, and ${PACKAGE_VERSION}.a # on AIX, since a shared library needs to have # a .a extension whereas shared objects for loadable # extensions have a .so extension. Defaults to # ${PACKAGE_VERSION}${SHLIB_SUFFIX}. # CFLAGS_DEBUG - # Flags used when running the compiler in debug mode # CFLAGS_OPTIMIZE - # Flags used when running the compiler in optimize mode # CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_CFLAGS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # Step 0.a: Enable 64 bit support? AC_MSG_CHECKING([if 64bit support is requested]) AC_ARG_ENABLE(64bit, AC_HELP_STRING([--enable-64bit], [enable 64bit support (default: off)]), [do64bit=$enableval], [do64bit=no]) AC_MSG_RESULT([$do64bit]) # Step 0.b: Enable Solaris 64 bit VIS support? AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) AC_ARG_ENABLE(64bit-vis, AC_HELP_STRING([--enable-64bit-vis], [enable 64bit Sparc VIS support (default: off)]), [do64bitVIS=$enableval], [do64bitVIS=no]) AC_MSG_RESULT([$do64bitVIS]) # Force 64bit on with VIS AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) # Step 0.c: Check if visibility support is available. Do this here so # that platform specific alternatives can be used below if this fails. AC_CACHE_CHECK([if compiler supports visibility "hidden"], tcl_cv_cc_visibility_hidden, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" AC_TRY_LINK([ extern __attribute__((__visibility__("hidden"))) void f(void); void f(void) {}], [f();], tcl_cv_cc_visibility_hidden=yes, tcl_cv_cc_visibility_hidden=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ AC_DEFINE(MODULE_SCOPE, [extern __attribute__((__visibility__("hidden")))], [Compiler support for module scope symbols]) AC_DEFINE(HAVE_HIDDEN, [1], [Compiler support for module scope symbols]) ]) # Step 0.d: Disable -rpath support? AC_MSG_CHECKING([if rpath support is requested]) AC_ARG_ENABLE(rpath, AC_HELP_STRING([--disable-rpath], [disable rpath support (default: on)]), [doRpath=$enableval], [doRpath=yes]) AC_MSG_RESULT([$doRpath]) # TEA specific: Cross-compiling options for Windows/CE builds? AS_IF([test "${TEA_PLATFORM}" = windows], [ AC_MSG_CHECKING([if Windows/CE build is requested]) AC_ARG_ENABLE(wince, AC_HELP_STRING([--enable-wince], [enable Win/CE support (where applicable)]), [doWince=$enableval], [doWince=no]) AC_MSG_RESULT([$doWince]) ]) # Set the variable "system" to hold the name and version number # for the system. TEA_CONFIG_SYSTEM # Require ranlib early so we can override it in special cases below. AC_REQUIRE([AC_PROG_RANLIB]) # Set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case and removed some core-only vars. do64bit_ok=no # default to '{$LIBS}' and set to "" on per-platform necessary basis SHLIB_LD_LIBS='${LIBS}' # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" UNSHARED_LIB_SUFFIX="" # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g AS_IF([test "$GCC" = yes], [ CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall" ], [ CFLAGS_OPTIMIZE=-O CFLAGS_WARNING="" ]) AC_CHECK_TOOL(AR, ar) STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION=""],[SHLIB_VERSION=".$SHLIB_VERSION"]) case $system in # TEA specific: windows) # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test "$GCC" != "yes" -a ! -d "${PATH64}" ; then AC_MSG_WARN([Could not find 64-bit $MACHINE SDK to enable 64bit mode]) AC_MSG_WARN([Ensure latest Platform SDK is installed]) do64bit="no" else AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) do64bit_ok="yes" fi fi if test "$doWince" != "no" ; then if test "$do64bit" != "no" ; then AC_MSG_ERROR([Windows/CE and 64-bit builds incompatible]) fi if test "$GCC" = "yes" ; then AC_MSG_ERROR([Windows/CE and GCC builds incompatible]) fi TEA_PATH_CELIB # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F, '{ \ if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \ if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \ if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \ if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]]) doWince="no" else # We could PATH_NOSPACE these, but that's not important, # as long as we quote them when used. CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi case "x`echo \${VisualStudioVersion}`" in x1[[4-9]]*) lflags="${lflags} -nodefaultlib:libucrt.lib" TEA_ADD_LIBS([ucrt.lib]) ;; *) ;; esac if test "$do64bit" != "no" ; then # All this magic is necessary for the Win64 SDK RC1 - hobbs CC="\"${PATH64}/cl.exe\"" CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" lflags="${lflags} -nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 TEA_ADD_LIBS([bufferoverflowU.lib]) elif test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="\"${CEBINROOT}/cl.exe\"" else CC="\"${CEBINROOT}/cl${ARCH}.exe\"" fi CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower([$]0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" if test "${SHARED_BUILD}" = "1" ; then # Static CE builds require static celib as well defs="${defs} _DLL" fi for i in $defs ; do AC_DEFINE_UNQUOTED($i, 1, [WinCE def ]$i) done AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION, [_WIN32_WCE version]) AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION, [UNDER_CE version]) CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -Ox" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="${lflags} -MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" AC_SUBST(CELIB_DIR) else RC="rc" lflags="${lflags} -nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode AC_CHECK_TOOL(RC, windres) CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD='${CC} -shared' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' PRACTCL_UNSHARED_LIB_SUFFIX='.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" AC_CACHE_CHECK(for cross-compile version of gcc, ac_cv_cross, AC_TRY_COMPILE([ #ifdef _WIN32 #error cross-compiler #endif ], [], ac_cv_cross=yes, ac_cv_cross=no) ) if test "$ac_cv_cross" = "yes"; then case "$do64bit" in amd64|x64|yes) CC="x86_64-w64-mingw32-gcc" LD="x86_64-w64-mingw32-ld" AR="x86_64-w64-mingw32-ar" RANLIB="x86_64-w64-mingw32-ranlib" RC="x86_64-w64-mingw32-windres" ;; *) CC="i686-w64-mingw32-gcc" LD="i686-w64-mingw32-ld" AR="i686-w64-mingw32-ar" RANLIB="i686-w64-mingw32-ranlib" RC="i686-w64-mingw32-windres" ;; esac fi else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" if test "$doWince" != "no" ; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots ;; AIX-*) AS_IF([test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"], [ # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r|*_r\ *) # ok ... ;; *) # Make sure only first arg gets _r CC=`echo "$CC" | sed -e 's/^\([[^ ]]*\)/\1_r/'` ;; esac AC_MSG_RESULT([Using $CC for compiling with threads]) ]) LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_SUFFIX=".so" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported with GCC on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" ]) ]) AS_IF([test "`uname -m`" = ia64], [ # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" AS_IF([test "$GCC" = yes], [ CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' ], [ CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' ]) LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ], [ AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared -Wl,-bexpall' ], [ SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" LDFLAGS="$LDFLAGS -brtl" ]) SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_SUFFIX=".so" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; CYGWIN_*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$[@].a" SHLIB_SUFFIX=".dll" EXEEXT=".exe" do64bit_ok=yes CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"]) ;; HP-UX-*.11.*) # Use updated header definitions where possible AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) # TEA specific: Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library AS_IF([test "`uname -m`" = ia64], [ SHLIB_SUFFIX=".so" # Use newer C++ library for C++ extensions #if test "$GCC" != "yes" ; then # CPPFLAGS="-AA" #fi ], [ SHLIB_SUFFIX=".sl" ]) AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) AS_IF([test "$tcl_ok" = yes], [ LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" ]) AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ CFLAGS="$CFLAGS -z" # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" ]) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = "yes"], [ AS_IF([test "$GCC" = yes], [ case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]) ;; esac ], [ do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" ]) ]) ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [ CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" ], [ case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" ]) ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported by gcc]) ], [ do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" ]) ]) ;; Linux*|GNU*|NetBSD-Debian) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) AS_IF([test $do64bit = yes], [ AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_m64 = yes], [ CFLAGS="$CFLAGS -m64" do64bit_ok=yes ]) ]) # The combo of gcc + glibc has a bug related to inlining of # functions like strtod(). The -fno-builtin flag should address # this problem but it does not work. The -fno-inline flag is kind # of overkill but it works. Disable inlining only when one of the # files in compat/*.c is being linked in. AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"]) ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' LD_FLAGS="-Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) ;; OpenBSD-*) arch=`arch -s` case "$arch" in vax) SHLIB_SUFFIX="" SHARED_LIB_SUFFIX="" LDFLAGS="" ;; *) case "$arch" in alpha|sparc64) SHLIB_CFLAGS="-fPIC" ;; *) SHLIB_CFLAGS="-fpic" ;; esac SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}' LDFLAGS="-Wl,-export-dynamic" ;; esac case "$arch" in vax) CFLAGS_OPTIMIZE="-O1" ;; *) CFLAGS_OPTIMIZE="-O2" ;; esac AS_IF([test "${TCL_THREADS}" = "1"], [ # On OpenBSD: Compile with -pthread # Don't link with -lpthread LIBS=`echo $LIBS | sed s/-lpthread//` CFLAGS="$CFLAGS -pthread" ]) # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*) # NetBSD has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) ;; FreeBSD-*) # This configuration from FreeBSD Ports. SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,-soname,\$[@]" SHLIB_SUFFIX=".so" LDFLAGS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the LDFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LDFLAGS="$LDFLAGS $PTHREAD_LIBS"]) case $system in FreeBSD-3.*) # Version numbers are dot-stripped by system policy. TCL_TRIM_DOTS=`echo ${PACKAGE_VERSION} | tr -d .` UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" AS_IF([test $do64bit = yes], [ case `arch` in ppc) AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], tcl_cv_cc_arch_ppc64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" AC_TRY_LINK(,, tcl_cv_cc_arch_ppc64=yes, tcl_cv_cc_arch_ppc64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes ]);; i386) AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], tcl_cv_cc_arch_x86_64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" AC_TRY_LINK(,, tcl_cv_cc_arch_x86_64=yes, tcl_cv_cc_arch_x86_64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes ]);; *) AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; esac ], [ # Check for combined 32-bit and 64-bit fat build AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ fat_32_64=yes]) ]) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_single_module = yes], [ SHLIB_LD="${SHLIB_LD} -Wl,-single_module" ]) # TEA specific: link shlib with current and compatibility version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" SHLIB_SUFFIX=".dylib" # Don't use -prebind when building for Mac OS X 10.4 or later only: AS_IF([test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \ "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4], [ LDFLAGS="$LDFLAGS -prebind"]) LDFLAGS="$LDFLAGS -headerpad_max_install_names" AC_CACHE_CHECK([if ld accepts -search_paths_first flag], tcl_cv_ld_search_paths_first, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, tcl_cv_ld_search_paths_first=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ LDFLAGS="$LDFLAGS -Wl,-search_paths_first" ]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [__private_extern__], [Compiler support for module scope symbols]) tcl_cv_cc_visibility_hidden=yes ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for combined 32 & 64 bit fat builds of Tk # extensions, verify that 64-bit build is possible. AS_IF([test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"], [ AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" AC_TRY_LINK([#include ], [XrmInitialize();], tcl_cv_lib_x11_64=yes, tcl_cv_lib_x11_64=no) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua], [ AC_CACHE_CHECK([for 64-bit Tk], tcl_cv_lib_tk_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" AC_TRY_LINK([#include ], [Tk_InitStubs(NULL, "", 0);], tcl_cv_lib_tk_64=yes, tcl_cv_lib_tk_64=no) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) # remove 64-bit arch flags from CFLAGS et al. if configuration # does not support 64-bit. AS_IF([test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no], [ AC_MSG_NOTICE([Removing 64-bit architectures from compiler & linker flags]) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done]) ]) ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h [Should OS/390 do the right thing with sockets?]) ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" AS_IF([test "$SHARED_BUILD" = 1], [ SHLIB_LD='ld -shared -expect_unresolved "*"' ], [ SHLIB_LD='ld -non_shared -expect_unresolved "*"' ]) SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) # see pthread_intro(3) for pthread support on osf1, k.furukawa AS_IF([test "${TCL_THREADS}" = 1], [ CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` AS_IF([test "$GCC" = yes], [ LIBS="$LIBS -lpthread -lmach -lexc" ], [ CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) ]) ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) AS_IF([test "$GCC" = yes], [ SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" ], [ SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" ]) SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-5.[[0-6]]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ arch=`isainfo` AS_IF([test "$arch" = "sparcv9 sparc"], [ AS_IF([test "$GCC" = yes], [ AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [ AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" ]) ], [ do64bit_ok=yes AS_IF([test "$do64bitVIS" = yes], [ CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" ], [ CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" ]) # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" ]) ], [AS_IF([test "$arch" = "amd64 i386"], [ AS_IF([test "$GCC" = yes], [ case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]);; esac ], [ do64bit_ok=yes case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac ]) ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) ]) SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "$do64bit_ok" = yes], [ AS_IF([test "$arch" = "sparcv9 sparc"], [ # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" ], [AS_IF([test "$arch" = "amd64 i386"], [ # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" ])]) ]) ], [ case $system in SunOS-5.[[1-9]][[0-9]]*) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ]) ;; UNIX_SV* | UnixWare-5*) SHLIB_CFLAGS="-KPIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers # that don't grok the -Bexport option. Test that it does. AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-Bexport" AC_TRY_LINK(, [int i;], tcl_cv_ld_Bexport=yes, tcl_cv_ld_Bexport=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_Bexport = yes], [ LDFLAGS="$LDFLAGS -Wl,-Bexport" ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; esac AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [ AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) ]) dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so dnl # until the end of configure, as configure's compile and link tests use dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's dnl # preprocessing tests use only CPPFLAGS. AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) # Add in the arch flags late to ensure it wasn't removed. # Not necessary in TEA, but this is aligned with core LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. AS_IF([test "$GCC" = yes], [ case $system in AIX-*) ;; BSD/OS*) ;; CYGWIN_*|MINGW32_*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*|OpenBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; windows) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [extern], [No Compiler support for module scope symbols]) ]) AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}' ]) AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a' ]) if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then AC_CACHE_CHECK(for SEH support in compiler, tcl_cv_seh, AC_TRY_RUN([ #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN int main(int argc, char** argv) { int a, b = 0; __try { a = 666 / b; } __except (EXCEPTION_EXECUTE_HANDLER) { return 0; } return 1; } ], tcl_cv_seh=yes, tcl_cv_seh=no, tcl_cv_seh=no) ) if test "$tcl_cv_seh" = "no" ; then AC_DEFINE(HAVE_NO_SEH, 1, [Defined when mingw does not support SEH]) fi # # Check to see if the excpt.h include file provided contains the # definition for EXCEPTION_DISPOSITION; if not, which is the case # with Cygwin's version as of 2002-04-10, define it to be int, # sufficient for getting the current code to work. # AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files, tcl_cv_eh_disposition, AC_TRY_COMPILE([ # define WIN32_LEAN_AND_MEAN # include # undef WIN32_LEAN_AND_MEAN ],[ EXCEPTION_DISPOSITION x; ], tcl_cv_eh_disposition=yes, tcl_cv_eh_disposition=no) ) if test "$tcl_cv_eh_disposition" = "no" ; then AC_DEFINE(EXCEPTION_DISPOSITION, int, [Defined when cygwin/mingw does not support EXCEPTION DISPOSITION]) fi # Check to see if winnt.h defines CHAR, SHORT, and LONG # even if VOID has already been #defined. The win32api # used by mingw and cygwin is known to do this. AC_CACHE_CHECK(for winnt.h that ignores VOID define, tcl_cv_winnt_ignore_void, AC_TRY_COMPILE([ #define VOID void #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN ], [ CHAR c; SHORT s; LONG l; ], tcl_cv_winnt_ignore_void=yes, tcl_cv_winnt_ignore_void=no) ) if test "$tcl_cv_winnt_ignore_void" = "yes" ; then AC_DEFINE(HAVE_WINNT_IGNORE_VOID, 1, [Defined when cygwin/mingw ignores VOID define in winnt.h]) fi fi # See if the compiler supports casting to a union type. # This is used to stop gcc from printing a compiler # warning when initializing a union member. AC_CACHE_CHECK(for cast to union support, tcl_cv_cast_to_union, AC_TRY_COMPILE([], [ union foo { int i; double d; }; union foo f = (union foo) (int) 0; ], tcl_cv_cast_to_union=yes, tcl_cv_cast_to_union=no) ) if test "$tcl_cv_cast_to_union" = "yes"; then AC_DEFINE(HAVE_CAST_TO_UNION, 1, [Defined when compiler supports casting to union type.]) fi AC_SUBST(CFLAGS_DEBUG) AC_SUBST(CFLAGS_OPTIMIZE) AC_SUBST(CFLAGS_WARNING) AC_SUBST(STLIB_LD) AC_SUBST(SHLIB_LD) AC_SUBST(SHLIB_SUFFIX) AC_SUBST(SHLIB_LD_LIBS) AC_SUBST(SHLIB_CFLAGS) AC_SUBST(LD_LIBRARY_PATH_VAR) # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary TEA_TCL_EARLY_FLAGS TEA_TCL_64BIT_FLAGS ]) #-------------------------------------------------------------------- # TEA_SERIAL_PORT # # Determine which interface to use to talk to the serial port. # Note that #include lines must begin in leftmost column for # some compilers to recognize them as preprocessor directives, # and some build environments have stdin not pointing at a # pseudo-terminal (usually /dev/null instead.) # # Arguments: # none # # Results: # # Defines only one of the following vars: # HAVE_SYS_MODEM_H # USE_TERMIOS # USE_TERMIO # USE_SGTTY #-------------------------------------------------------------------- AC_DEFUN([TEA_SERIAL_PORT], [ AC_CHECK_HEADERS(sys/modem.h) AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ AC_TRY_RUN([ #include int main() { struct termios t; if (tcgetattr(0, &t) == 0) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include #include int main() { struct termios t; if (tcgetattr(0, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) fi]) case $tcl_cv_api_serial in termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; esac ]) #-------------------------------------------------------------------- # TEA_MISSING_POSIX_HEADERS # # Supply substitutes for missing POSIX header files. Special # notes: # - stdlib.h doesn't define strtol, strtoul, or # strtod in some versions of SunOS # - some versions of string.h don't declare procedures such # as strstr # # Arguments: # none # # Results: # # Defines some of the following vars: # NO_DIRENT_H # NO_ERRNO_H # NO_VALUES_H # HAVE_LIMITS_H or NO_LIMITS_H # NO_STDLIB_H # NO_STRING_H # NO_SYS_WAIT_H # NO_DLFCN_H # HAVE_SYS_PARAM_H # # HAVE_STRING_H ? # # tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and # CHECK on limits.h #-------------------------------------------------------------------- AC_DEFUN([TEA_MISSING_POSIX_HEADERS], [ AC_CACHE_CHECK([dirent.h], tcl_cv_dirent_h, [ AC_TRY_LINK([#include #include ], [ #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)]) if test $tcl_cv_dirent_h = no; then AC_DEFINE(NO_DIRENT_H, 1, [Do we have ?]) fi # TEA specific: AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H, 1, [Do we have ?])]) AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have ?])]) AC_CHECK_HEADER(limits.h, [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have ?])], [AC_DEFINE(NO_LIMITS_H, 1, [Do we have ?])]) AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0) if test $tcl_ok = 0; then AC_DEFINE(NO_STDLIB_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0) AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0) # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then AC_DEFINE(NO_STRING_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have ?])]) # OS/390 lacks sys/param.h (and doesn't need it, by chance). AC_HAVE_HEADERS(sys/param.h) ]) #-------------------------------------------------------------------- # TEA_PATH_X # # Locate the X11 header files and the X11 library archive. Try # the ac_path_x macro first, but if it doesn't find the X stuff # (e.g. because there's no xmkmf program) then check through # a list of possible directories. Under some conditions the # autoconf macro will return an include directory that contains # no include files, so double-check its result just to be safe. # # This should be called after TEA_CONFIG_CFLAGS as setting the # LIBS line can confuse some configure macro magic. # # Arguments: # none # # Results: # # Sets the following vars: # XINCLUDES # XLIBSW # PKG_LIBS (appends to) #-------------------------------------------------------------------- AC_DEFUN([TEA_PATH_X], [ if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then TEA_PATH_UNIX_X fi ]) AC_DEFUN([TEA_PATH_UNIX_X], [ AC_PATH_X not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then AC_TRY_CPP([#include ], , not_really_there="yes") else if test ! -r $x_includes/X11/Xlib.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then AC_MSG_CHECKING([for X11 header files]) found_xincludes="no" AC_TRY_CPP([#include ], found_xincludes="yes", found_xincludes="no") if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Xlib.h; then AC_MSG_RESULT([$i]) XINCLUDES=" -I$i" found_xincludes="yes" break fi done fi else if test "$x_includes" != ""; then XINCLUDES="-I$x_includes" found_xincludes="yes" fi fi if test "$found_xincludes" = "no"; then AC_MSG_RESULT([couldn't find any!]) fi if test "$no_x" = yes; then AC_MSG_CHECKING([for X11 libraries]) XLIBSW=nope dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" for i in $dirs ; do if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then AC_MSG_RESULT([$i]) XLIBSW="-L$i -lX11" x_libraries="$i" break fi done else if test "$x_libraries" = ""; then XLIBSW=-lX11 else XLIBSW="-L$x_libraries -lX11" fi fi if test "$XLIBSW" = nope ; then AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) fi if test "$XLIBSW" = nope ; then AC_MSG_RESULT([could not find any! Using -lX11.]) XLIBSW=-lX11 fi # TEA specific: if test x"${XLIBSW}" != x ; then PKG_LIBS="${PKG_LIBS} ${XLIBSW}" fi ]) #-------------------------------------------------------------------- # TEA_BLOCKING_STYLE # # The statements below check for systems where POSIX-style # non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. # On these systems (mostly older ones), use the old BSD-style # FIONBIO approach instead. # # Arguments: # none # # Results: # # Defines some of the following vars: # HAVE_SYS_IOCTL_H # HAVE_SYS_FILIO_H # USE_FIONBIO # O_NONBLOCK #-------------------------------------------------------------------- AC_DEFUN([TEA_BLOCKING_STYLE], [ AC_CHECK_HEADERS(sys/ioctl.h) AC_CHECK_HEADERS(sys/filio.h) TEA_CONFIG_SYSTEM AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) case $system in OSF*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; *) AC_MSG_RESULT([O_NONBLOCK]) ;; esac ]) #-------------------------------------------------------------------- # TEA_TIME_HANDLER # # Checks how the system deals with time.h, what time structures # are used on the system, and what fields the structures have. # # Arguments: # none # # Results: # # Defines some of the following vars: # USE_DELTA_FOR_TZ # HAVE_TM_GMTOFF # HAVE_TM_TZADJ # HAVE_TIMEZONE_VAR #-------------------------------------------------------------------- AC_DEFUN([TEA_TIME_HANDLER], [ AC_CHECK_HEADERS(sys/time.h) AC_HEADER_TIME AC_STRUCT_TIMEZONE AC_CHECK_FUNCS(gmtime_r localtime_r) AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_tzadj;], tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)]) if test $tcl_cv_member_tm_tzadj = yes ; then AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) fi AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_gmtoff;], tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)]) if test $tcl_cv_member_tm_gmtoff = yes ; then AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) fi # # Its important to include time.h in this check, as some systems # (like convex) have timezone functions, etc. # AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ AC_TRY_COMPILE([#include ], [extern long timezone; timezone += 1; exit (0);], tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)]) if test $tcl_cv_timezone_long = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) else # # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. # AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ AC_TRY_COMPILE([#include ], [extern time_t timezone; timezone += 1; exit (0);], tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)]) if test $tcl_cv_timezone_time = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) fi fi ]) #-------------------------------------------------------------------- # TEA_BUGGY_STRTOD # # Under Solaris 2.4, strtod returns the wrong value for the # terminating character under some conditions. Check for this # and if the problem exists use a substitute procedure # "fixstrtod" (provided by Tcl) that corrects the error. # Also, on Compaq's Tru64 Unix 5.0, # strtod(" ") returns 0.0 instead of a failure to convert. # # Arguments: # none # # Results: # # Might defines some of the following vars: # strtod (=fixstrtod) #-------------------------------------------------------------------- AC_DEFUN([TEA_BUGGY_STRTOD], [ AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) if test "$tcl_strtod" = 1; then AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ AC_TRY_RUN([ extern double strtod(); int main() { char *infString="Inf", *nanString="NaN", *spaceString=" "; char *term; double value; value = strtod(infString, &term); if ((term != infString) && (term[-1] == 0)) { exit(1); } value = strtod(nanString, &term); if ((term != nanString) && (term[-1] == 0)) { exit(1); } value = strtod(spaceString, &term); if (term == (spaceString+1)) { exit(1); } exit(0); }], tcl_cv_strtod_buggy=ok, tcl_cv_strtod_buggy=buggy, tcl_cv_strtod_buggy=buggy)]) if test "$tcl_cv_strtod_buggy" = buggy; then AC_LIBOBJ([fixstrtod]) USE_COMPAT=1 AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) fi fi ]) #-------------------------------------------------------------------- # TEA_TCL_LINK_LIBS # # Search for the libraries needed to link the Tcl shell. # Things like the math library (-lm) and socket stuff (-lsocket vs. # -lnsl) are dealt with here. # # Arguments: # Requires the following vars to be set in the Makefile: # DL_LIBS (not in TEA, only needed in core) # LIBS # MATH_LIBS # # Results: # # Substitutes the following vars: # TCL_LIBS # MATH_LIBS # # Might append to the following vars: # LIBS # # Might define the following vars: # HAVE_NET_ERRNO_H #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_LINK_LIBS], [ #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) AC_CHECK_HEADER(net/errno.h, [ AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have ?])]) #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) if test "$tcl_checkSocket" = 1; then AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) fi AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, [LIBS="$LIBS -lnsl"])]) # TEA specific: Don't perform the eval of the libraries here because # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' AC_SUBST(TCL_LIBS) AC_SUBST(MATH_LIBS) ]) #-------------------------------------------------------------------- # TEA_TCL_EARLY_FLAGS # # Check for what flags are needed to be passed so the correct OS # features are available. # # Arguments: # None # # Results: # # Might define the following vars: # _ISOC99_SOURCE # _LARGEFILE64_SOURCE # _LARGEFILE_SOURCE64 #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_EARLY_FLAG],[ AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, AC_TRY_COMPILE([[#define ]$1[ 1 ]$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) tcl_flags="$tcl_flags $1" fi ]) AC_DEFUN([TEA_TCL_EARLY_FLAGS],[ AC_MSG_CHECKING([for required early compiler flags]) tcl_flags="" TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], [char *p = (char *)strtoll; char *q = (char *)strtoull;]) TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include ], [struct stat64 buf; int i = stat64("/", &buf);]) TEA_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include ], [char *p = (char *)open64;]) if test "x${tcl_flags}" = "x" ; then AC_MSG_RESULT([none]) else AC_MSG_RESULT([${tcl_flags}]) fi ]) #-------------------------------------------------------------------- # TEA_TCL_64BIT_FLAGS # # Check for what is defined in the way of 64-bit features. # # Arguments: # None # # Results: # # Might define the following vars: # TCL_WIDE_INT_IS_LONG # TCL_WIDE_INT_TYPE # HAVE_STRUCT_DIRENT64 # HAVE_STRUCT_STAT64 # HAVE_TYPE_OFF64_T #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_64BIT_FLAGS], [ AC_MSG_CHECKING([for 64-bit integer type]) AC_CACHE_VAL(tcl_cv_type_64bit,[ tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], tcl_type_64bit=__int64, tcl_type_64bit="long long") # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... AC_TRY_COMPILE(,[switch (0) { case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ; }],tcl_cv_type_64bit=${tcl_type_64bit})]) if test "${tcl_cv_type_64bit}" = none ; then AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?]) AC_MSG_RESULT([using long]) elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # TEA specific: We actually want to use the default tcl.h checks in # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* AC_MSG_RESULT([using Tcl header defaults]) else AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, [What type should be used to define wide integers?]) AC_MSG_RESULT([${tcl_cv_type_64bit}]) # Now check for auxiliary declarations AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ AC_TRY_COMPILE([#include #include ],[struct dirent64 p;], tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in ?]) fi AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ AC_TRY_COMPILE([#include ],[struct stat64 p; ], tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) if test "x${tcl_cv_struct_stat64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in ?]) fi AC_CHECK_FUNCS(open64 lseek64) AC_MSG_CHECKING([for off64_t]) AC_CACHE_VAL(tcl_cv_type_off64_t,[ AC_TRY_COMPILE([#include ],[off64_t offset; ], tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the dnl functions lseek64 and open64 are defined. if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi ]) ## ## Here ends the standard Tcl configuration bits and starts the ## TEA specific functions ## #------------------------------------------------------------------------ # TEA_INIT -- # # Init various Tcl Extension Architecture (TEA) variables. # This should be the first called TEA_* macro. # # Arguments: # none # # Results: # # Defines and substs the following vars: # CYGPATH # EXEEXT # Defines only: # TEA_VERSION # TEA_INITED # TEA_PLATFORM (windows or unix) # # "cygpath" is used on windows to generate native path names for include # files. These variables should only be used with the compiler and linker # since they generate native path names. # # EXEEXT # Select the executable extension based on the host type. This # is a lightweight replacement for AC_EXEEXT that doesn't require # a compiler. #------------------------------------------------------------------------ AC_DEFUN([TEA_INIT], [ # TEA extensions pass this us the version of TEA they think they # are compatible with. TEA_VERSION="3.10" AC_MSG_CHECKING([for correct TEA configuration]) if test x"${PACKAGE_NAME}" = x ; then AC_MSG_ERROR([ The PACKAGE_NAME variable must be defined by your TEA configure.ac]) fi if test x"$1" = x ; then AC_MSG_ERROR([ TEA version not specified.]) elif test "$1" != "${TEA_VERSION}" ; then AC_MSG_RESULT([warning: requested TEA version "$1", have "${TEA_VERSION}"]) else AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) fi # If the user did not set CFLAGS, set it now to keep macros # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi TEA_TK_EXTENSION=0 AC_SUBST(TEA_TK_EXTENSION) case "`uname -s`" in *win32*|*WIN32*|*MINGW32_*) AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *CYGWIN_*) EXEEXT=".exe" # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG ;; *) CYGPATH=echo # Maybe we are cross-compiling.... case ${host_alias} in *mingw32*) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *) EXEEXT="" TEA_PLATFORM="unix" ;; esac ;; esac # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi AC_MSG_NOTICE([configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}]) AC_SUBST(EXEEXT) AC_SUBST(CYGPATH) # This package name must be replaced statically for AC_SUBST to work AC_SUBST(PKG_LIB_FILE) AC_SUBST(PKG_LIB_FILE8) AC_SUBST(PKG_LIB_FILE9) # Substitute STUB_LIB_FILE in case package creates a stub library too. AC_SUBST(PKG_STUB_LIB_FILE) # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) AC_SUBST(PKG_TCL_SOURCES) AC_SUBST(PKG_HEADERS) AC_SUBST(PKG_INCLUDES) AC_SUBST(PKG_LIBS) AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_SOURCES # PKG_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_SOURCES], [ vars="$@" for i in $vars; do case $i in [\$]*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then AC_MSG_ERROR([could not find source file '$i']) fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done AC_SUBST(PKG_SOURCES) AC_SUBST(PKG_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_STUB_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_STUB_SOURCES # PKG_STUB_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_STUB_SOURCES], [ vars="$@" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then AC_MSG_ERROR([could not find stub source file '$i']) fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_TCL_SOURCES -- # # Specify one or more Tcl source files. These should be platform # independent runtime files. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_TCL_SOURCES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_TCL_SOURCES], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done AC_SUBST(PKG_TCL_SOURCES) ]) #------------------------------------------------------------------------ # TEA_ADD_HEADERS -- # # Specify one or more source headers. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_HEADERS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_HEADERS], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find header file '${srcdir}/$i']) fi PKG_HEADERS="$PKG_HEADERS $i" done AC_SUBST(PKG_HEADERS) ]) #------------------------------------------------------------------------ # TEA_ADD_INCLUDES -- # # Specify one or more include dirs. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_INCLUDES], [ vars="$@" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done AC_SUBST(PKG_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_ADD_LIBS -- # # Specify one or more libraries. Users should check for # the right platform before adding to their list. For Windows, # libraries provided in "foo.lib" format will be converted to # "-lfoo" when using GCC (mingw). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_LIBS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_LIBS], [ vars="$@" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.lib[$]/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done AC_SUBST(PKG_LIBS) ]) #------------------------------------------------------------------------ # TEA_ADD_CFLAGS -- # # Specify one or more CFLAGS. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_CFLAGS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CFLAGS], [ PKG_CFLAGS="$PKG_CFLAGS $@" AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_CLEANFILES -- # # Specify one or more CLEANFILES. # # Arguments: # one or more file names to clean target # # Results: # # Appends to CLEANFILES, already defined for subst in LOAD_TCLCONFIG #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CLEANFILES], [ CLEANFILES="$CLEANFILES $@" ]) #------------------------------------------------------------------------ # TEA_PREFIX -- # # Handle the --prefix=... option by defaulting to what Tcl gave # # Arguments: # none # # Results: # # If --prefix or --exec-prefix was not specified, $prefix and # $exec_prefix will be set to the values given to Tcl when it was # configured. #------------------------------------------------------------------------ AC_DEFUN([TEA_PREFIX], [ if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) prefix=${TCL_PREFIX} else AC_MSG_NOTICE([--prefix defaulting to /usr/local]) prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) exec_prefix=${TCL_EXEC_PREFIX} else AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) exec_prefix=$prefix fi fi ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER_CC -- # # Do compiler checks the way we want. This is just a replacement # for AC_PROG_CC in TEA configure.ac files to make them cleaner. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER_CC], [ # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. AC_PROG_CC AC_PROG_CPP INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c' INSTALL_DATA_DIR='${INSTALL} -d -m 755' INSTALL_DATA='${INSTALL} -m 644' INSTALL_PROGRAM='${INSTALL}' INSTALL_SCRIPT='${INSTALL}' INSTALL_LIBRARY='${INSTALL_DATA}' AC_SUBST(INSTALL) AC_SUBST(INSTALL_DATA_DIR) AC_SUBST(INSTALL_DATA) AC_SUBST(INSTALL_PROGRAM) AC_SUBST(INSTALL_SCRIPT) AC_SUBST(INSTALL_LIBRARY) #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- AC_PROG_MAKE_SET #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- AC_CHECK_TOOL(RANLIB, ranlib) #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- AC_OBJEXT AC_EXEEXT ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER -- # # Do compiler checks that use the compiler. This must go after # TEA_SETUP_COMPILER_CC, which does the actual compiler check. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER], [ # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. AC_REQUIRE([TEA_SETUP_COMPILER_CC]) #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then AC_CACHE_CHECK([if the compiler understands -pipe], tcl_cv_cc_pipe, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" AC_TRY_COMPILE(,, tcl_cv_cc_pipe=yes, tcl_cv_cc_pipe=no) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- AC_C_BIGENDIAN if test "${TEA_PLATFORM}" = "unix" ; then TEA_TCL_LINK_LIBS TEA_MISSING_POSIX_HEADERS # Let the user call this, because if it triggers, they will # need a compat/strtod.c that is correct. Users can also # use Tcl_GetDouble(FromObj) instead. #TEA_BUGGY_STRTOD fi ]) #------------------------------------------------------------------------ # TEA_MAKE_LIB -- # # Generate a line that can be used to build a shared/unshared library # in a platform independent manner. # # Arguments: # none # # Requires: # # Results: # # Defines the following vars: # CFLAGS - Done late here to note disturb other AC macros # MAKE_LIB - Command to execute to build the Tcl library; # differs depending on whether or not Tcl is being # compiled as a shared library. # MAKE_SHARED_LIB Makefile rule for building a shared library # MAKE_STATIC_LIB Makefile rule for building a static library # MAKE_STUB_LIB Makefile rule for building a stub library # VC_MANIFEST_EMBED_DLL Makefile rule for embedded VC manifest in DLL # VC_MANIFEST_EMBED_EXE Makefile rule for embedded VC manifest in EXE # # PRACTCL_TOOLSET What toolset is in use (gcc or msvc) # PRACTCL_SHARED_LIB Template rule for building a shared library # PRACTCL_STATIC_LIB Template rule for building a static library # PRACTCL_STUB_LIB Template rule for building a stub library # PRACTCL_VC_MANIFEST_EMBED_DLL Template rule for embedded VC manifest in DLL # PRACTCL_VC_MANIFEST_EMBED_EXE Template rule for embedded VC manifest in EXE # PRACTCL_NAME_LIBRARY Template rule for naming libraries # #------------------------------------------------------------------------ AC_DEFUN([TEA_MAKE_LIB], [ PRACTCL_TOOLSET="gcc" PRACTCL_VC_MANIFEST_EMBED_DLL=: PRACTCL_VC_MANIFEST_EMBED_EXE=: if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then PRACTCL_TOOLSET="msvc" PRACTCL_STATIC_LIB="%STLIB_LD% -out:%OUTFILE% %LIBRARY_OBJECTS%" PRACTCL_SHARED_LIB="%SHLIB_LD% %SHLIB_LD_LIBS% %LDFLAGS_DEFAULT% -out:%OUTFILE% %LIBRARY_OBJECTS%" MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS)" AC_EGREP_CPP([manifest needed], [ #if defined(_MSC_VER) && _MSC_VER >= 1400 print("manifest needed") #endif ], [ # Could do a CHECK_PROG for mt, but should always be with MSVC8+ PRACTCL_VC_MANIFEST_EMBED_DLL="mt.exe -nologo -manifest %OUTFILE%.manifest -outputresource:%OUTFILE%\;2" PRACTCL_VC_MANIFEST_EMBED_EXE="mt.exe -nologo -manifest %OUTFILE%.manifest -outputresource:%OUTFILE%\;1" VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;2 ; fi" VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;1 ; fi" MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" TEA_ADD_CLEANFILES([*.manifest]) ]) PRACTCL_STUB_LIB="%STLIB_LD% -nodefaultlib -out:%OUTFILE% %LIBRARY_OBJECTS%" MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\[$]@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" PRACTCL_STATIC_LIB="%STLIB_LD% %OUTFILE% %LIBRARY_OBJECTS%" PRACTCL_SHARED_LIB="%SHLIB_LD% -o %OUTFILE% %LIBRARY_OBJECTS% %SHLIB_LD_LIBS%" PRACTCL_STUB_LIB="%STLIB_LD% %OUTFILE% %LIBRARY_OBJECTS%" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}" PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9" if test "${TCL_MAJOR_VERSION}" -gt 8 ; then PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}" else PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}" fi if test "${TEA_PLATFORM}" = "windows" ; then PRACTCL_NAME_LIBRARY="%LIBRARY_PREFIX%%LIBRARY_NAME%%LIBRARY_VERSION_NODOTS%" if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test "$GCC" = "yes"; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc" fi eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_LIB_FILE=lib${PKG_LIB_FILE} fi fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else PRACTCL_NAME_LIBRARY="lib%LIBRARY_PREFIX%%LIBRARY_NAME%%LIBRARY_VERSION%" RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # Store the raw CFLAGS before we add the trimmings PRACTCL_CFLAGS=${CFLAGS} # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi AC_SUBST(MAKE_LIB) AC_SUBST(MAKE_SHARED_LIB) AC_SUBST(MAKE_STATIC_LIB) AC_SUBST(MAKE_STUB_LIB) AC_SUBST(RANLIB_STUB) AC_SUBST(VC_MANIFEST_EMBED_DLL) AC_SUBST(VC_MANIFEST_EMBED_EXE) AC_SUBST(PRACTCL_CFLAGS) AC_SUBST(PRACTCL_TOOLSET) AC_SUBST(PRACTCL_SHARED_LIB) AC_SUBST(PRACTCL_STATIC_LIB) AC_SUBST(PRACTCL_STUB_LIB) AC_SUBST(PRACTCL_VC_MANIFEST_EMBED_DLL) AC_SUBST(PRACTCL_VC_MANIFEST_EMBED_EXE) AC_SUBST(PRACTCL_NAME_LIBRARY) ]) #------------------------------------------------------------------------ # TEA_LIB_SPEC -- # # Compute the name of an existing object library located in libdir # from the given base name and produce the appropriate linker flags. # # Arguments: # basename The base name of the library without version # numbers, extensions, or "lib" prefixes. # extra_dir Extra directory in which to search for the # library. This location is used first, then # $prefix/$exec-prefix, then some defaults. # # Requires: # TEA_INIT and TEA_PREFIX must be called first. # # Results: # # Defines the following vars: # ${basename}_LIB_NAME The computed library name. # ${basename}_LIB_SPEC The computed linker flags. #------------------------------------------------------------------------ AC_DEFUN([TEA_LIB_SPEC], [ AC_MSG_CHECKING([for $1 library]) # Look in exec-prefix for the library (defined by TEA_PREFIX). tea_lib_name_dir="${exec_prefix}/lib" # Or in a user-specified location. if test x"$2" != x ; then tea_extra_lib_dir=$2 else tea_extra_lib_dir=NONE fi for i in \ `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib64/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib64/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do if test -f "$i" ; then tea_lib_name_dir=`dirname $i` $1_LIB_NAME=`basename $i` $1_LIB_PATH_NAME=$i break fi done if test "${TEA_PLATFORM}" = "windows"; then $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" else # Strip off the leading "lib" and trailing ".a" or ".so" tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" fi if test "x${$1_LIB_NAME}" = x ; then AC_MSG_ERROR([not found]) else AC_MSG_RESULT([${$1_LIB_SPEC}]) fi ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TCL_HEADERS -- # # Locate the private Tcl include files # # Arguments: # # Requires: # TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has # already been called. # # Results: # # Substitutes the following vars: # TCL_TOP_DIR_NATIVE # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [ # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} AC_REQUIRE([TEA_PUBLIC_TCL_HEADERS]) AC_MSG_CHECKING([for Tcl private include files]) TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" # Check to see if tclPort.h isn't already with the public headers # Don't look for tclInt.h because that resides with tcl.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tclh}/tclWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tclh}/tclUnixPort.h"; then result="private headers found with public headers" else TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" if test "${TEA_PLATFORM}" = "windows"; then TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" else TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TCL_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -d "${TCL_BIN_DIR}/Headers" -a \ -d "${TCL_BIN_DIR}/PrivateHeaders"; then TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" else TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TCL_INCLUDES}" else if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then AC_MSG_ERROR([Cannot find private header tclInt.h in ${TCL_SRC_DIR}]) fi result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" fi fi AC_SUBST(TCL_TOP_DIR_NATIVE) AC_SUBST(TCL_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TCL_HEADERS -- # # Locate the installed public Tcl header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tclinclude switch to configure. # Result is cached. # # Substitutes the following vars: # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [ AC_MSG_CHECKING([for Tcl public headers]) AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tclh, [ # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) fi else list="" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) else AC_MSG_RESULT([${ac_cv_c_tclh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TCL_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TK_HEADERS -- # # Locate the private Tk include files # # Arguments: # # Requires: # TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has # already been called. # # Results: # # Substitutes the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [ # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} AC_REQUIRE([TEA_PUBLIC_TK_HEADERS]) AC_MSG_CHECKING([for Tk private include files]) TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" # Check to see if tkPort.h isn't already with the public headers # Don't look for tkInt.h because that resides with tk.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tkh}/tkWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tkh}/tkUnixPort.h"; then result="private headers found with public headers" else TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" if test "${TEA_PLATFORM}" = "windows"; then TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" else TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TK_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" # Detect and add ttk subdir if test -d "${TK_SRC_DIR}/generic/ttk"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" fi if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_XLIB_DIR_NATIVE}\"" fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" fi if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TK_DEFS} in *TK_FRAMEWORK*) if test -d "${TK_BIN_DIR}/Headers" -a \ -d "${TK_BIN_DIR}/PrivateHeaders"; then TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" else TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TK_INCLUDES}" else if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then AC_MSG_ERROR([Cannot find private header tkInt.h in ${TK_SRC_DIR}]) fi result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" fi fi AC_SUBST(TK_TOP_DIR_NATIVE) AC_SUBST(TK_XLIB_DIR_NATIVE) AC_SUBST(TK_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TK_HEADERS -- # # Locate the installed public Tk header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tkinclude switch to configure. # Result is cached. # # Substitutes the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TK_HEADERS], [ AC_MSG_CHECKING([for Tk public headers]) AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files], with_tkinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tkh, [ # Use the value from --with-tkinclude, if it was given if test x"${with_tkinclude}" != x ; then if test -f "${with_tkinclude}/tk.h" ; then ac_cv_c_tkh=${with_tkinclude} else AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) fi else list="" if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers directory. case ${TK_DEFS} in *TK_FRAMEWORK*) list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tk is not installed, # and in that situation, look there before installed locations. if test -f "${TK_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tk's --prefix location, # relative to directory of tkConfig.sh, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TK_PREFIX}/include 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TK_INCLUDE_SPEC}" != x ; then d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tk.h" ; then ac_cv_c_tkh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tkh}" = x ; then AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) else AC_MSG_RESULT([${ac_cv_c_tkh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_INCLUDES) if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then # On Windows and Aqua, we need the X compat headers AC_MSG_CHECKING([for X11 header files]) if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_XINCLUDES) fi AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) fi ]) #------------------------------------------------------------------------ # TEA_PATH_CONFIG -- # # Locate the ${1}Config.sh file and perform a sanity check on # the ${1} compile flags. These are used by packages like # [incr Tk] that load *Config.sh files from more than Tcl and Tk. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-$1=... # # Defines the following vars: # $1_BIN_DIR Full path to the directory containing # the $1Config.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CONFIG], [ # # Ok, lets find the $1 configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-$1 # if test x"${no_$1}" = x ; then # we reset no_$1 in case something fails here no_$1=true AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) AC_MSG_CHECKING([for $1 configuration]) AC_CACHE_VAL(ac_cv_c_$1config,[ # First check to see if --with-$1 was specified. if test x"${with_$1config}" != x ; then case ${with_$1config} in */$1Config.sh ) if test -f ${with_$1config}; then AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` fi;; esac if test -f "${with_$1config}/$1Config.sh" ; then ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` else AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) fi fi # then check for a private $1 installation if test x"${ac_cv_c_$1config}" = x ; then for i in \ ../$1 \ `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../$1 \ `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../../$1 \ `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ${srcdir}/../$1 \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi if test -f "$i/unix/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i/unix; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_$1config}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_$1config}" = x ; then $1_BIN_DIR="# no $1 configs found" AC_MSG_WARN([Cannot find $1 configuration definitions]) exit 0 else no_$1= $1_BIN_DIR=${ac_cv_c_$1config} AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG -- # # Load the $1Config.sh file # # Arguments: # # Requires the following vars to be set: # $1_BIN_DIR # # Results: # # Substitutes the following vars: # $1_SRC_DIR # $1_LIB_FILE # $1_LIB_SPEC #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG], [ AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) if test -f "${$1_BIN_DIR}/$1Config.sh" ; then AC_MSG_RESULT([loading]) . "${$1_BIN_DIR}/$1Config.sh" else AC_MSG_RESULT([file not found]) fi # # If the $1_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable $1_LIB_SPEC will be set to the value # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC # instead of $1_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. # if test -f "${$1_BIN_DIR}/Makefile" ; then AC_MSG_WARN([Found Makefile - using build library specs for $1]) $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} $1_INCLUDE_SPEC=${$1_BUILD_INCLUDE_SPEC} $1_LIBRARY_PATH=${$1_LIBRARY_PATH} fi AC_SUBST($1_VERSION) AC_SUBST($1_BIN_DIR) AC_SUBST($1_SRC_DIR) AC_SUBST($1_LIB_FILE) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_STUB_LIB_FILE) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_PATH) # Allow the caller to prevent this auto-check by specifying any 2nd arg AS_IF([test "x$2" = x], [ # Check both upper and lower-case variants # If a dev wanted non-stubs libs, this function could take an option # to not use _STUB in the paths below AS_IF([test "x${$1_STUB_LIB_SPEC}" = x], [TEA_LOAD_CONFIG_LIB(translit($1,[a-z],[A-Z])_STUB)], [TEA_LOAD_CONFIG_LIB($1_STUB)]) ]) ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG_LIB -- # # Helper function to load correct library from another extension's # ${PACKAGE}Config.sh. # # Results: # Adds to LIBS the appropriate extension library #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG_LIB], [ AC_MSG_CHECKING([For $1 library for LIBS]) # This simplifies the use of stub libraries by automatically adding # the stub lib to your path. Normally this would add to SHLIB_LD_LIBS, # but this is called before CONFIG_CFLAGS. More importantly, this adds # to PKG_LIBS, which becomes LIBS, and that is only used by SHLIB_LD. if test "x${$1_LIB_SPEC}" != "x" ; then if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes" ; then TEA_ADD_LIBS([\"`${CYGPATH} ${$1_LIB_PATH}`\"]) AC_MSG_RESULT([using $1_LIB_PATH ${$1_LIB_PATH}]) else TEA_ADD_LIBS([${$1_LIB_SPEC}]) AC_MSG_RESULT([using $1_LIB_SPEC ${$1_LIB_SPEC}]) fi else AC_MSG_RESULT([file not found]) fi ]) #------------------------------------------------------------------------ # TEA_EXPORT_CONFIG -- # # Define the data to insert into the ${PACKAGE}Config.sh file # # Arguments: # # Requires the following vars to be set: # $1 # # Results: # Substitutes the following vars: #------------------------------------------------------------------------ AC_DEFUN([TEA_EXPORT_CONFIG], [ #-------------------------------------------------------------------- # These are for $1Config.sh #-------------------------------------------------------------------- # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib) eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}" if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}${DBGX}" eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}${DBGX}" else eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" fi $1_BUILD_LIB_SPEC="-L`$CYGPATH $(pwd)` ${$1_LIB_FLAG}" $1_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` ${$1_LIB_FLAG}" $1_BUILD_STUB_LIB_SPEC="-L`$CYGPATH $(pwd)` [$]{$1_STUB_LIB_FLAG}" $1_STUB_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` [$]{$1_STUB_LIB_FLAG}" $1_BUILD_STUB_LIB_PATH="`$CYGPATH $(pwd)`/[$]{PKG_STUB_LIB_FILE}" $1_STUB_LIB_PATH="`$CYGPATH ${pkglibdir}`/[$]{PKG_STUB_LIB_FILE}" AC_SUBST($1_BUILD_LIB_SPEC) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_PATH) AC_SUBST($1_STUB_LIB_PATH) AC_SUBST(MAJOR_VERSION) AC_SUBST(MINOR_VERSION) AC_SUBST(PATCHLEVEL) ]) #------------------------------------------------------------------------ # TEA_PATH_CELIB -- # # Locate Keuchel's celib emulation layer for targeting Win/CE # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-celib=... # # Defines the following vars: # CELIB_DIR Full path to the directory containing # the include and platform lib files #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CELIB], [ # First, look for one uninstalled. # the alternative search directory is invoked by --with-celib if test x"${no_celib}" = x ; then # we reset no_celib in case something fails here no_celib=true AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], with_celibconfig=${withval}) AC_MSG_CHECKING([for Windows/CE celib directory]) AC_CACHE_VAL(ac_cv_c_celibconfig,[ # First check to see if --with-celibconfig was specified. if test x"${with_celibconfig}" != x ; then if test -d "${with_celibconfig}/inc" ; then ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` else AC_MSG_ERROR([${with_celibconfig} directory doesn't contain inc directory]) fi fi # then check for a celib library if test x"${ac_cv_c_celibconfig}" = x ; then for i in \ ../celib-palm-3.0 \ ../celib \ ../../celib-palm-3.0 \ ../../celib \ `ls -dr ../celib-*3.[[0-9]]* 2>/dev/null` \ ${srcdir}/../celib-palm-3.0 \ ${srcdir}/../celib \ `ls -dr ${srcdir}/../celib-*3.[[0-9]]* 2>/dev/null` \ ; do if test -d "$i/inc" ; then ac_cv_c_celibconfig=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_celibconfig}" = x ; then AC_MSG_ERROR([Cannot find celib support library directory]) else no_celib= CELIB_DIR=${ac_cv_c_celibconfig} CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` AC_MSG_RESULT([found $CELIB_DIR]) fi fi ]) #-------------------------------------------------------------------- # TEA_CONFIG_TEAPOT # # Try to determine the canonical name for this package's binary # target # # Arguments: # none AC_DEFUN([TEA_CONFIG_TEAPOT], [ TEACUP_OS=$system TEACUP_ARCH="unknown" TEACUP_TOOLSET="gcc" TEACUP_PROFILE="unknown" arch="unknown" if test "${TEA_PLATFORM}" = "windows" ; then if test "$GCC" = "yes" ; then TEACUP_TOOLSET="gcc" else TEACUP_TOOLSET="msvc" fi if test "$do64bit" != "no" ; then case "$do64bit" in amd64|x64|yes) arch="x86_64" TEACUP_PROFILE="win32-x86_64" ;; ia64) arch="ia64" TEACUP_PROFILE="win32-ia64" ;; esac else arch="ix86" TEACUP_PROFILE="win32-ix86" fi else case $system in Linux*) TEACUP_OS="linux" arch=`uname -m` TEACUP_PROFILE="linux-glibc2.3-$arch" ;; GNU*) TEACUP_OS="gnu" arch=`uname -m` ;; NetBSD-Debian) TEACUP_OS="netbsd-debian" arch=`uname -m` ;; OpenBSD-*) TEACUP_OS="openbsd" arch=`arch -s` ;; Darwin*) TEACUP_OS="macosx" TEACUP_PROFILE="macosx-universal" arch=`uname -m` if test $arch = "x86_64"; then TEACUP_PROFILE="macosx10.5-i386-x86_84" fi ;; OpenBSD*) TEACUP_OS="openbsd" arch=`arch -s` ;; esac fi TEACUP_ARCH=$arch if test "$TEACUP_PROFILE" = "unknown"; then if test $arch = "unknown"; then arch=`uname -m` fi case $arch in i*86) arch="ix86" ;; amd64) arch="x86_64" ;; esac TEACUP_PROFILE="$TEACUP_OS-$arch" fi TEA_SYSTEM=$system AC_SUBST(TEA_SYSTEM) AC_SUBST(TEA_PLATFORM) AC_SUBST(TEA_WINDOWINGSYSTEM) AC_SUBST(TEACUP_OS) AC_SUBST(TEACUP_ARCH) AC_SUBST(TEACUP_TOOLSET) AC_SUBST(TEACUP_PROFILE) ]) # Local Variables: # mode: autoconf # End: ./nsf2.4.0/library/mongodb/m4/nsf.m4000644 000766 000024 00000007373 12501766547 017660 0ustar00neumannstaff000000 000000 # nsf.m4 -- # # This file provides a set of autoconf macros to help TEA-enable # a Tcl extension. # # Copyright (c) 1999 Scriptics Corporation. # Copyright (c) 1999-2008 Uwe Zdun # Copyright (c) 1999-2014 Gustaf Neumann # # See the file "tcl-license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. #------------------------------------------------------------------------ # SC_PATH_NSFCONFIG -- # # Locate the nsfConfig.sh file and perform a sanity check on # the Tcl compile flags # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-nsf=... # # Defines the following vars: # NX_BIN_DIR Full path to the directory containing # the nsfConfig.sh file #------------------------------------------------------------------------ AC_DEFUN(SC_PATH_NSFCONFIG, [ # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_nsf}" = x ; then # we reset no_nsf in case something fails here no_nsf=true AC_ARG_WITH(nsf, [ --with-nsf directory containing nsf configuration (nsfConfig.sh)], with_nsfconfig=${withval}) AC_MSG_CHECKING([for nsf configuration]) AC_CACHE_VAL(ac_cv_c_nsfconfig,[ # First check to see if --with-nsf was specified. if test x"${with_nsfconfig}" != x ; then if test -f "${with_nsfconfig}/nsfConfig.sh" ; then ac_cv_c_nsfconfig=`(cd ${with_nsfconfig}; pwd)` else AC_MSG_ERROR([${with_nsfconfig} directory doesn't contain nsfConfig.sh]) fi fi # then check for a private Tcl installation if test x"${ac_cv_c_nsfconfig}" = x ; then for i in \ ${srcdir}/../nsf \ `ls -dr ${srcdir}/../nsf-* 2>/dev/null` \ ${srcdir}/../../nsf \ `ls -dr ${srcdir}/../../nsf-* 2>/dev/null` \ ${srcdir}/../../../nsf \ `ls -dr ${srcdir}/../../../nsf-* 2>/dev/null` \ ${srcdir}/../../../../nsf \ `ls -dr ${srcdir}/../../../../nsf-* 2>/dev/null` \ ${srcdir}/../../../../../nsf \ `ls -dr ${srcdir}/../../../../../nsf-* 2>/dev/null` ; do if test -f "$i/nsfConfig.sh" ; then ac_cv_c_nsfconfig=`(cd $i; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_nsfconfig}" = x ; then for i in `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` ; do if test -f "$i/nsfConfig.sh" ; then ac_cv_c_nsfconfig=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_nsfconfig}" = x ; then NX_BIN_DIR="# no nsf configs found" AC_MSG_WARN(Can't find nsf configuration definitions) exit 0 else no_nsf= NX_BIN_DIR=${ac_cv_c_nsfconfig} AC_MSG_RESULT(found $NX_BIN_DIR/nsfConfig.sh) fi fi ]) #------------------------------------------------------------------------ # SC_LOAD_NSFCONFIG -- # # Load the tclConfig.sh file # # Arguments: # # Requires the following vars to be set: # NX_BIN_DIR # # Results: # # Subst the vars: # #------------------------------------------------------------------------ AC_DEFUN(SC_LOAD_NSFCONFIG, [ AC_MSG_CHECKING([for existence of $NX_BIN_DIR/nsfConfig.sh]) if test -f "$NX_BIN_DIR/nsfConfig.sh" ; then AC_MSG_RESULT([loading]) . $NX_BIN_DIR/nsfConfig.sh else AC_MSG_RESULT([file not found]) fi # # The eval is required to do the TCL_DBGX substitution in the # TCL_LIB_FILE variable # AC_SUBST(NX_VERSION) AC_SUBST(NX_MAJOR_VERSION) AC_SUBST(NX_MINOR_VERSION) AC_SUBST(NX_RELEASE_LEVEL) AC_SUBST(NX_LIB_FILE) AC_SUBST(NX_BUILD_LIB_SPEC) AC_SUBST(NX_LIB_SPEC) AC_SUBST(NX_STUB_LIB_FILE) AC_SUBST(NX_BUILD_STUB_LIB_SPEC) AC_SUBST(NX_STUB_LIB_SPEC) AC_SUBST(NX_SRC_DIR) ]) ./nsf2.4.0/library/mongodb/COPYRIGHT000644 000766 000024 00000004453 13322636554 017573 0ustar00neumannstaff000000 000000 /* * MongoDB driver for the Next Scripting Framework * * Copyright (C) 2011-2018 Gustaf Neumann (a) (b) * * Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License * http://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * * This software is based upon MIT Object Tcl by David Wetherall and * Christopher J. Lindblad, that contains the following copyright * message: * * "Copyright 1993 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this * software and its documentation for any purpose is hereby granted * without fee, provided that the above copyright notice appear in * all copies and that both that copyright notice and this * permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity * pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about * the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty." */ ./nsf2.4.0/library/mongodb/example-nx-gridfs.tcl000644 000766 000024 00000006632 13677316536 022347 0ustar00neumannstaff000000 000000 #package require nx package require nx::mongo package require nx::serializer package require nx::test # # This sample script shows some basic interactions from the nsf mongo # interface with gridFS. It connects to mongo, opens a GridFS named # "myfs" and inserts a file into the filesystems. Run the script # with the current directory of nsfmongo, such it can find the README # file. # # After running the script, one can use the following command to # inspect the content in the GridFS via the mongo shell # # $ mongo # > use myfs # > show collections # > db.fs.files.find() # # or via the mongofiles interface: # # $ mongofiles -d myfs list # # # First, as usual, open the connection to the mongo db # set mongoConn [::mongo::connect] #nsf::configure debug 2 # Establish connection to the database ::nx::mongo::db connect -db "tutorial" # # Open a GridFS in the mongo database "myfs" and use the usual prefix # "fs", such GridFS names the collections "fs.chunks" and "fs.files". # set gridFS [::mongo::gridfs::open $mongoConn myfs fs] # # gridfs::remove_file removes all files with the specified name # multiple store operations create "revisions" with different uploadDates ::mongo::gridfs::remove_file $gridFS README # # ::mongo::gridfs::store_file $gridFS $inputFileName $storeFileName text/plain # Note that the input filename can be "-" for reading from stdin. # # The current version of gridfs_store_file() is quite unfriendly, # since it assumes that the file exists, and aborts otherwise. So, we # perform the existence test here. # # Store a known file: # set fn README if {[file readable $fn]} { set r [::mongo::gridfs::store_file $gridFS $fn $fn text/plain] puts stderr "::mongo::gridfs::store_file returned $r" } else { puts stderr "no such file: $fn" } # # Open a grid file, get some of its properties, and read it in chunks # of 500 bytes, and close it finally. # set f [mongo::gridfile::open $gridFS README] puts stderr "\nOpened grid file '$f'" puts stderr "Metadata: [mongo::gridfile::get_metadata $f]" puts stderr "ContentLength: [mongo::gridfile::get_contentlength $f]" puts stderr "ContentType: [mongo::gridfile::get_contenttype $f]" while {1} { set chunk [mongo::gridfile::read $f 500] puts stderr "read chunk-len [string length $chunk] content [string range $chunk 0 10]..." if {[string length $chunk] < 500} { break } } mongo::gridfile::close $f # # Access the files stored in the gridfs via plain query interface # puts "\nAll Files:\n[join [::mongo::query $mongoConn myfs.fs.files {}] \n]\n" # # Get the filenamed README from the gridfs via plain query interface # set atts [lindex [::mongo::query $mongoConn myfs.fs.files \ [list \$query object {filename string README}] \ -limit 1] 0] puts "Attributes of file README:\n$atts\n" # # Extract the oid from the bson attributes # foreach {name type value} $atts { if {$name eq "_id"} { set oid $value break } } # # Add a dc:creator to the bson attributes ... # lappend atts metadata object {dc:creator string "Gustaf Neumann"} # .. and update the entry in the gridfs ::mongo::update $mongoConn myfs.fs.files [list _id oid $oid] $atts # # Now we can use the gridfs interface to obtain the additional # metadata as well # set f [mongo::gridfile::open $gridFS README] puts stderr "Metadata: [mongo::gridfile::get_metadata $f]" mongo::gridfile::close $f # # close everything # ::mongo::gridfs::close $gridFS ::mongo::close $mongoConn ./nsf2.4.0/library/mongodb/mongoAPI.h000644 000766 000024 00000126120 14270262575 020117 0ustar00neumannstaff000000 000000 /* * This source code file was generated by the C-code generator gentclAPI.tcl, * part of the Next Scripting Framework. */ #if defined(USE_NSF_STUBS) int Nsf_ConvertTo_Boolean(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToBoolean(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Class(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToClass(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Int32(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToInt32(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Integer(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToInteger(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Object(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToObject(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Pointer(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToPointer(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_String(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToString(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Tclobj(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToTclobj(interp, objPtr, pPtr, clientData, outObjPtr); } #else # define Nsf_ConvertTo_Boolean Nsf_ConvertToBoolean # define Nsf_ConvertTo_Class Nsf_ConvertToClass # define Nsf_ConvertTo_Int32 Nsf_ConvertToInt32 # define Nsf_ConvertTo_Integer Nsf_ConvertToInteger # define Nsf_ConvertTo_Object Nsf_ConvertToObject # define Nsf_ConvertTo_Pointer Nsf_ConvertToPointer # define Nsf_ConvertTo_String Nsf_ConvertToString # define Nsf_ConvertTo_Tclobj Nsf_ConvertToTclobj #endif #if !defined(likely) # if defined(__GNUC__) && __GNUC__ > 2 /* Use gcc branch prediction hint to minimize cost of e.g. DTrace * ENABLED checks. */ # define unlikely(x) (__builtin_expect((x), 0)) # define likely(x) (__builtin_expect((x), 1)) # else # define unlikely(x) (x) # define likely(x) (x) # endif #endif typedef enum {GridfilesourceNULL=0x0u, GridfilesourceFileIdx=1, GridfilesourceStringIdx=2} GridfilesourceIdx_t; static int ConvertToGridfilesource(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; static const Nsf_ObjvTable opts[] = { {"file", 1}, {"string", 2}, {NULL, 0u} }; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, opts, sizeof(Nsf_ObjvTable), "gridfilesource", 0, &pos); *clientData = (ClientData) INT2PTR(opts[pos].value); *outObjPtr = objPtr; return result; } static Nsf_EnumeratorConverterEntry enumeratorConverterEntries[] = { {ConvertToGridfilesource, "file|string"}, {NULL, NULL} }; /* just to define the symbol */ static Nsf_methodDefinition method_definitions[31]; static const char *method_command_namespace_names[] = { "::mongo" }; static int NsfCollectionCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfCollectionOpenStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoCollectionCountStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoCollectionDeleteStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoCollectionIndexStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoCollectionInsertStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoCollectionQueryStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoCollectionStatsStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoCollectionUpdateStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoConnectStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoCursorAggregateStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoCursorCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoCursorFindStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoCursorNextStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoGridFSCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoGridFSOpenStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoGridFileCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoGridFileCreateStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoGridFileDeleteStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoGridFileGetContentTypeStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoGridFileGetContentlengthStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoGridFileGetMetaDataStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoGridFileOpenStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoGridFileReadStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoGridFileSeekStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoJsonGenerateStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoJsonParseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoRunCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMongoStatusStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfCollectionClose(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *collectionObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfCollectionOpen(Tcl_Interp *interp, mongoc_client_t *connPtr, const char *dbname, const char *collectionname) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3) NSF_nonnull(4); static int NsfMongoClose(Tcl_Interp *interp, mongoc_client_t *connPtr, Tcl_Obj *connObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfMongoCollectionCount(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *queryObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfMongoCollectionDelete(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *conditionObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfMongoCollectionIndex(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *attributesObj, const char *withName, int withBackground, int withDropdups, int withSparse, int withTtl, int withUnique) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfMongoCollectionInsert(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *valuesObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfMongoCollectionQuery(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *filterObj, Tcl_Obj *optsObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfMongoCollectionStats(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *optionsObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfMongoCollectionUpdate(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *condObj, Tcl_Obj *valuesObj, int withUpsert, int withAll) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3) NSF_nonnull(4); static int NsfMongoConnect(Tcl_Interp *interp, const char *withUri) NSF_nonnull(1); static int NsfMongoCursorAggregate(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *pipelineObj, Tcl_Obj *optionsObj, int withTailable, int withAwaitdata) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3) NSF_nonnull(4); static int NsfMongoCursorClose(Tcl_Interp *interp, mongoc_cursor_t *cursorPtr, Tcl_Obj *cursorObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfMongoCursorFind(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *filterObj, Tcl_Obj *optsObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfMongoCursorNext(Tcl_Interp *interp, mongoc_cursor_t *cursorPtr) NSF_nonnull(1) NSF_nonnull(2); static int NsfMongoGridFSClose(Tcl_Interp *interp, mongoc_gridfs_t *gfsPtr, Tcl_Obj *gfsObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfMongoGridFSOpen(Tcl_Interp *interp, mongoc_client_t *connPtr, const char *dbname, const char *prefix) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3) NSF_nonnull(4); static int NsfMongoGridFileClose(Tcl_Interp *interp, mongoc_gridfs_file_t *gridfilePtr, Tcl_Obj *gridfileObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfMongoGridFileCreate(Tcl_Interp *interp, GridfilesourceIdx_t withSource, mongoc_gridfs_t *gfsPtr, const char *value, const char *name, const char *contenttype, Tcl_Obj *metadataObj) NSF_nonnull(1) NSF_nonnull(3) NSF_nonnull(4) NSF_nonnull(5) NSF_nonnull(6); static int NsfMongoGridFileDelete(Tcl_Interp *interp, mongoc_gridfs_t *gfsPtr, Tcl_Obj *queryObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfMongoGridFileGetContentType(Tcl_Interp *interp, mongoc_gridfs_file_t *gridfilePtr) NSF_nonnull(1) NSF_nonnull(2); static int NsfMongoGridFileGetContentlength(Tcl_Interp *interp, mongoc_gridfs_file_t *gridfilePtr) NSF_nonnull(1) NSF_nonnull(2); static int NsfMongoGridFileGetMetaData(Tcl_Interp *interp, mongoc_gridfs_file_t *gridfilePtr) NSF_nonnull(1) NSF_nonnull(2); static int NsfMongoGridFileOpen(Tcl_Interp *interp, mongoc_gridfs_t *gfsPtr, Tcl_Obj *queryObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfMongoGridFileRead(Tcl_Interp *interp, mongoc_gridfs_file_t *gridfilePtr, int size) NSF_nonnull(1) NSF_nonnull(2); static int NsfMongoGridFileSeek(Tcl_Interp *interp, mongoc_gridfs_file_t *gridfilePtr, int offset) NSF_nonnull(1) NSF_nonnull(2); static int NsfMongoJsonGenerate(Tcl_Interp *interp, Tcl_Obj *listObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfMongoJsonParse(Tcl_Interp *interp, Tcl_Obj *jsonObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfMongoRunCmd(Tcl_Interp *interp, int withNocomplain, mongoc_client_t *connPtr, const char *db, Tcl_Obj *cmdObj) NSF_nonnull(1) NSF_nonnull(3) NSF_nonnull(4) NSF_nonnull(5); static int NsfMongoStatus(Tcl_Interp *interp, mongoc_client_t *connPtr, Tcl_Obj *connObj) NSF_nonnull(1) NSF_nonnull(2); EXTERN enum { NsfCollectionCloseIdx, NsfCollectionOpenIdx, NsfMongoCloseIdx, NsfMongoCollectionCountIdx, NsfMongoCollectionDeleteIdx, NsfMongoCollectionIndexIdx, NsfMongoCollectionInsertIdx, NsfMongoCollectionQueryIdx, NsfMongoCollectionStatsIdx, NsfMongoCollectionUpdateIdx, NsfMongoConnectIdx, NsfMongoCursorAggregateIdx, NsfMongoCursorCloseIdx, NsfMongoCursorFindIdx, NsfMongoCursorNextIdx, NsfMongoGridFSCloseIdx, NsfMongoGridFSOpenIdx, NsfMongoGridFileCloseIdx, NsfMongoGridFileCreateIdx, NsfMongoGridFileDeleteIdx, NsfMongoGridFileGetContentTypeIdx, NsfMongoGridFileGetContentlengthIdx, NsfMongoGridFileGetMetaDataIdx, NsfMongoGridFileOpenIdx, NsfMongoGridFileReadIdx, NsfMongoGridFileSeekIdx, NsfMongoJsonGenerateIdx, NsfMongoJsonParseIdx, NsfMongoRunCmdIdx, NsfMongoStatusIdx } NsfMethods; static int NsfCollectionCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfCollectionCloseIdx].paramDefs, method_definitions[NsfCollectionCloseIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_collection_t *collectionPtr = (mongoc_collection_t *)pc.clientData[0]; assert(pc.status == 0); return NsfCollectionClose(interp, collectionPtr,pc.objv[0]); } else { return TCL_ERROR; } } static int NsfCollectionOpenStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfCollectionOpenIdx].paramDefs, method_definitions[NsfCollectionOpenIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_client_t *connPtr = (mongoc_client_t *)pc.clientData[0]; const char *dbname = (const char *)pc.clientData[1]; const char *collectionname = (const char *)pc.clientData[2]; assert(pc.status == 0); return NsfCollectionOpen(interp, connPtr, dbname, collectionname); } else { return TCL_ERROR; } } static int NsfMongoCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoCloseIdx].paramDefs, method_definitions[NsfMongoCloseIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_client_t *connPtr = (mongoc_client_t *)pc.clientData[0]; assert(pc.status == 0); return NsfMongoClose(interp, connPtr,pc.objv[0]); } else { return TCL_ERROR; } } static int NsfMongoCollectionCountStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoCollectionCountIdx].paramDefs, method_definitions[NsfMongoCollectionCountIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_collection_t *collectionPtr = (mongoc_collection_t *)pc.clientData[0]; Tcl_Obj *queryObj = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); return NsfMongoCollectionCount(interp, collectionPtr, queryObj); } else { return TCL_ERROR; } } static int NsfMongoCollectionDeleteStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoCollectionDeleteIdx].paramDefs, method_definitions[NsfMongoCollectionDeleteIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_collection_t *collectionPtr = (mongoc_collection_t *)pc.clientData[0]; Tcl_Obj *conditionObj = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); return NsfMongoCollectionDelete(interp, collectionPtr, conditionObj); } else { return TCL_ERROR; } } static int NsfMongoCollectionIndexStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoCollectionIndexIdx].paramDefs, method_definitions[NsfMongoCollectionIndexIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_collection_t *collectionPtr = (mongoc_collection_t *)pc.clientData[0]; Tcl_Obj *attributesObj = (Tcl_Obj *)pc.clientData[1]; const char *withName = (const char *)pc.clientData[2]; int withBackground = (int )PTR2INT(pc.clientData[3]); int withDropdups = (int )PTR2INT(pc.clientData[4]); int withSparse = (int )PTR2INT(pc.clientData[5]); int withTtl = (int )PTR2INT(pc.clientData[6]); int withUnique = (int )PTR2INT(pc.clientData[7]); assert(pc.status == 0); return NsfMongoCollectionIndex(interp, collectionPtr, attributesObj, withName, withBackground, withDropdups, withSparse, withTtl, withUnique); } else { return TCL_ERROR; } } static int NsfMongoCollectionInsertStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoCollectionInsertIdx].paramDefs, method_definitions[NsfMongoCollectionInsertIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_collection_t *collectionPtr = (mongoc_collection_t *)pc.clientData[0]; Tcl_Obj *valuesObj = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); return NsfMongoCollectionInsert(interp, collectionPtr, valuesObj); } else { return TCL_ERROR; } } static int NsfMongoCollectionQueryStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoCollectionQueryIdx].paramDefs, method_definitions[NsfMongoCollectionQueryIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_collection_t *collectionPtr = (mongoc_collection_t *)pc.clientData[0]; Tcl_Obj *filterObj = (Tcl_Obj *)pc.clientData[1]; Tcl_Obj *optsObj = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); return NsfMongoCollectionQuery(interp, collectionPtr, filterObj, optsObj); } else { return TCL_ERROR; } } static int NsfMongoCollectionStatsStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoCollectionStatsIdx].paramDefs, method_definitions[NsfMongoCollectionStatsIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_collection_t *collectionPtr = (mongoc_collection_t *)pc.clientData[0]; Tcl_Obj *optionsObj = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); return NsfMongoCollectionStats(interp, collectionPtr, optionsObj); } else { return TCL_ERROR; } } static int NsfMongoCollectionUpdateStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoCollectionUpdateIdx].paramDefs, method_definitions[NsfMongoCollectionUpdateIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_collection_t *collectionPtr = (mongoc_collection_t *)pc.clientData[0]; Tcl_Obj *condObj = (Tcl_Obj *)pc.clientData[1]; Tcl_Obj *valuesObj = (Tcl_Obj *)pc.clientData[2]; int withUpsert = (int )PTR2INT(pc.clientData[3]); int withAll = (int )PTR2INT(pc.clientData[4]); assert(pc.status == 0); return NsfMongoCollectionUpdate(interp, collectionPtr, condObj, valuesObj, withUpsert, withAll); } else { return TCL_ERROR; } } static int NsfMongoConnectStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoConnectIdx].paramDefs, method_definitions[NsfMongoConnectIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { const char *withUri = (const char *)pc.clientData[0]; assert(pc.status == 0); return NsfMongoConnect(interp, withUri); } else { return TCL_ERROR; } } static int NsfMongoCursorAggregateStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoCursorAggregateIdx].paramDefs, method_definitions[NsfMongoCursorAggregateIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_collection_t *collectionPtr = (mongoc_collection_t *)pc.clientData[0]; Tcl_Obj *pipelineObj = (Tcl_Obj *)pc.clientData[1]; Tcl_Obj *optionsObj = (Tcl_Obj *)pc.clientData[2]; int withTailable = (int )PTR2INT(pc.clientData[3]); int withAwaitdata = (int )PTR2INT(pc.clientData[4]); assert(pc.status == 0); return NsfMongoCursorAggregate(interp, collectionPtr, pipelineObj, optionsObj, withTailable, withAwaitdata); } else { return TCL_ERROR; } } static int NsfMongoCursorCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoCursorCloseIdx].paramDefs, method_definitions[NsfMongoCursorCloseIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_cursor_t *cursorPtr = (mongoc_cursor_t *)pc.clientData[0]; assert(pc.status == 0); return NsfMongoCursorClose(interp, cursorPtr,pc.objv[0]); } else { return TCL_ERROR; } } static int NsfMongoCursorFindStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoCursorFindIdx].paramDefs, method_definitions[NsfMongoCursorFindIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_collection_t *collectionPtr = (mongoc_collection_t *)pc.clientData[0]; Tcl_Obj *filterObj = (Tcl_Obj *)pc.clientData[1]; Tcl_Obj *optsObj = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); return NsfMongoCursorFind(interp, collectionPtr, filterObj, optsObj); } else { return TCL_ERROR; } } static int NsfMongoCursorNextStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoCursorNextIdx].paramDefs, method_definitions[NsfMongoCursorNextIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_cursor_t *cursorPtr = (mongoc_cursor_t *)pc.clientData[0]; assert(pc.status == 0); return NsfMongoCursorNext(interp, cursorPtr); } else { return TCL_ERROR; } } static int NsfMongoGridFSCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoGridFSCloseIdx].paramDefs, method_definitions[NsfMongoGridFSCloseIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_gridfs_t *gfsPtr = (mongoc_gridfs_t *)pc.clientData[0]; assert(pc.status == 0); return NsfMongoGridFSClose(interp, gfsPtr,pc.objv[0]); } else { return TCL_ERROR; } } static int NsfMongoGridFSOpenStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoGridFSOpenIdx].paramDefs, method_definitions[NsfMongoGridFSOpenIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_client_t *connPtr = (mongoc_client_t *)pc.clientData[0]; const char *dbname = (const char *)pc.clientData[1]; const char *prefix = (const char *)pc.clientData[2]; assert(pc.status == 0); return NsfMongoGridFSOpen(interp, connPtr, dbname, prefix); } else { return TCL_ERROR; } } static int NsfMongoGridFileCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoGridFileCloseIdx].paramDefs, method_definitions[NsfMongoGridFileCloseIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_gridfs_file_t *gridfilePtr = (mongoc_gridfs_file_t *)pc.clientData[0]; assert(pc.status == 0); return NsfMongoGridFileClose(interp, gridfilePtr,pc.objv[0]); } else { return TCL_ERROR; } } static int NsfMongoGridFileCreateStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoGridFileCreateIdx].paramDefs, method_definitions[NsfMongoGridFileCreateIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { GridfilesourceIdx_t withSource = (GridfilesourceIdx_t )PTR2INT(pc.clientData[0]); mongoc_gridfs_t *gfsPtr = (mongoc_gridfs_t *)pc.clientData[1]; const char *value = (const char *)pc.clientData[2]; const char *name = (const char *)pc.clientData[3]; const char *contenttype = (const char *)pc.clientData[4]; Tcl_Obj *metadataObj = (Tcl_Obj *)pc.clientData[5]; assert(pc.status == 0); return NsfMongoGridFileCreate(interp, withSource, gfsPtr, value, name, contenttype, metadataObj); } else { return TCL_ERROR; } } static int NsfMongoGridFileDeleteStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoGridFileDeleteIdx].paramDefs, method_definitions[NsfMongoGridFileDeleteIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_gridfs_t *gfsPtr = (mongoc_gridfs_t *)pc.clientData[0]; Tcl_Obj *queryObj = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); return NsfMongoGridFileDelete(interp, gfsPtr, queryObj); } else { return TCL_ERROR; } } static int NsfMongoGridFileGetContentTypeStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoGridFileGetContentTypeIdx].paramDefs, method_definitions[NsfMongoGridFileGetContentTypeIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_gridfs_file_t *gridfilePtr = (mongoc_gridfs_file_t *)pc.clientData[0]; assert(pc.status == 0); return NsfMongoGridFileGetContentType(interp, gridfilePtr); } else { return TCL_ERROR; } } static int NsfMongoGridFileGetContentlengthStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoGridFileGetContentlengthIdx].paramDefs, method_definitions[NsfMongoGridFileGetContentlengthIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_gridfs_file_t *gridfilePtr = (mongoc_gridfs_file_t *)pc.clientData[0]; assert(pc.status == 0); return NsfMongoGridFileGetContentlength(interp, gridfilePtr); } else { return TCL_ERROR; } } static int NsfMongoGridFileGetMetaDataStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoGridFileGetMetaDataIdx].paramDefs, method_definitions[NsfMongoGridFileGetMetaDataIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_gridfs_file_t *gridfilePtr = (mongoc_gridfs_file_t *)pc.clientData[0]; assert(pc.status == 0); return NsfMongoGridFileGetMetaData(interp, gridfilePtr); } else { return TCL_ERROR; } } static int NsfMongoGridFileOpenStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoGridFileOpenIdx].paramDefs, method_definitions[NsfMongoGridFileOpenIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_gridfs_t *gfsPtr = (mongoc_gridfs_t *)pc.clientData[0]; Tcl_Obj *queryObj = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); return NsfMongoGridFileOpen(interp, gfsPtr, queryObj); } else { return TCL_ERROR; } } static int NsfMongoGridFileReadStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoGridFileReadIdx].paramDefs, method_definitions[NsfMongoGridFileReadIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_gridfs_file_t *gridfilePtr = (mongoc_gridfs_file_t *)pc.clientData[0]; int size = (int )PTR2INT(pc.clientData[1]); assert(pc.status == 0); return NsfMongoGridFileRead(interp, gridfilePtr, size); } else { return TCL_ERROR; } } static int NsfMongoGridFileSeekStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoGridFileSeekIdx].paramDefs, method_definitions[NsfMongoGridFileSeekIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_gridfs_file_t *gridfilePtr = (mongoc_gridfs_file_t *)pc.clientData[0]; int offset = (int )PTR2INT(pc.clientData[1]); assert(pc.status == 0); return NsfMongoGridFileSeek(interp, gridfilePtr, offset); } else { return TCL_ERROR; } } static int NsfMongoJsonGenerateStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (objc != 2) { return NsfArgumentError(interp, "wrong # of arguments:", method_definitions[NsfMongoJsonGenerateIdx].paramDefs, NULL, objv[0]); } return NsfMongoJsonGenerate(interp, objv[1]); } static int NsfMongoJsonParseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (objc != 2) { return NsfArgumentError(interp, "wrong # of arguments:", method_definitions[NsfMongoJsonParseIdx].paramDefs, NULL, objv[0]); } return NsfMongoJsonParse(interp, objv[1]); } static int NsfMongoRunCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoRunCmdIdx].paramDefs, method_definitions[NsfMongoRunCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withNocomplain = (int )PTR2INT(pc.clientData[0]); mongoc_client_t *connPtr = (mongoc_client_t *)pc.clientData[1]; const char *db = (const char *)pc.clientData[2]; Tcl_Obj *cmdObj = (Tcl_Obj *)pc.clientData[3]; assert(pc.status == 0); return NsfMongoRunCmd(interp, withNocomplain, connPtr, db, cmdObj); } else { return TCL_ERROR; } } static int NsfMongoStatusStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMongoStatusIdx].paramDefs, method_definitions[NsfMongoStatusIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_client_t *connPtr = (mongoc_client_t *)pc.clientData[0]; assert(pc.status == 0); return NsfMongoStatus(interp, connPtr,pc.objv[0]); } else { return TCL_ERROR; } } static Nsf_methodDefinition method_definitions[31] = { {"::mongo::collection::close", NsfCollectionCloseStub, 1, { {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::collection::open", NsfCollectionOpenStub, 3, { {"conn", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_client_t",NULL,NULL,NULL,NULL,NULL}, {"dbname", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"collectionname", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::close", NsfMongoCloseStub, 1, { {"conn", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_client_t",NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::collection::count", NsfMongoCollectionCountStub, 2, { {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}, {"query", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::collection::delete", NsfMongoCollectionDeleteStub, 2, { {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}, {"condition", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::collection::index", NsfMongoCollectionIndexStub, 8, { {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}, {"attributes", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-name", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-background", 0, 0, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-dropdups", 0, 0, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-sparse", 0, 0, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-ttl", 0, 1, Nsf_ConvertTo_Int32, NULL,NULL,"int32",NULL,NULL,NULL,NULL,NULL}, {"-unique", 0, 0, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::collection::insert", NsfMongoCollectionInsertStub, 2, { {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}, {"values", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::collection::query", NsfMongoCollectionQueryStub, 3, { {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}, {"filter", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-opts", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::collection::stats", NsfMongoCollectionStatsStub, 2, { {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}, {"-options", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::collection::update", NsfMongoCollectionUpdateStub, 5, { {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}, {"cond", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"values", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-upsert", 0, 0, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-all", 0, 0, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::connect", NsfMongoConnectStub, 1, { {"-uri", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::cursor::aggregate", NsfMongoCursorAggregateStub, 5, { {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}, {"pipeline", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"options", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-tailable", 0, 0, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-awaitdata", 0, 0, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::cursor::close", NsfMongoCursorCloseStub, 1, { {"cursor", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_cursor_t",NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::cursor::find", NsfMongoCursorFindStub, 3, { {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}, {"filter", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-opts", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::cursor::next", NsfMongoCursorNextStub, 1, { {"cursor", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_cursor_t",NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::gridfs::close", NsfMongoGridFSCloseStub, 1, { {"gfs", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_gridfs_t",NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::gridfs::open", NsfMongoGridFSOpenStub, 3, { {"conn", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_client_t",NULL,NULL,NULL,NULL,NULL}, {"dbname", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"prefix", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::gridfile::close", NsfMongoGridFileCloseStub, 1, { {"gridfile", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_gridfs_file_t",NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::gridfile::create", NsfMongoGridFileCreateStub, 6, { {"-source", NSF_ARG_REQUIRED|NSF_ARG_IS_ENUMERATION, 1, ConvertToGridfilesource, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"gfs", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_gridfs_t",NULL,NULL,NULL,NULL,NULL}, {"value", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"name", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"contenttype", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-metadata", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::gridfile::delete", NsfMongoGridFileDeleteStub, 2, { {"gfs", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_gridfs_t",NULL,NULL,NULL,NULL,NULL}, {"query", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::gridfile::get_contenttype", NsfMongoGridFileGetContentTypeStub, 1, { {"gridfile", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_gridfs_file_t",NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::gridfile::get_contentlength", NsfMongoGridFileGetContentlengthStub, 1, { {"gridfile", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_gridfs_file_t",NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::gridfile::get_metadata", NsfMongoGridFileGetMetaDataStub, 1, { {"gridfile", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_gridfs_file_t",NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::gridfile::open", NsfMongoGridFileOpenStub, 2, { {"gfs", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_gridfs_t",NULL,NULL,NULL,NULL,NULL}, {"query", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::gridfile::read", NsfMongoGridFileReadStub, 2, { {"gridfile", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_gridfs_file_t",NULL,NULL,NULL,NULL,NULL}, {"size", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Int32, NULL,NULL,"int32",NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::gridfile::seek", NsfMongoGridFileSeekStub, 2, { {"gridfile", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_gridfs_file_t",NULL,NULL,NULL,NULL,NULL}, {"offset", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Int32, NULL,NULL,"int32",NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::json::generate", NsfMongoJsonGenerateStub, 1, { {"list", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::json::parse", NsfMongoJsonParseStub, 1, { {"json", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::run", NsfMongoRunCmdStub, 4, { {"-nocomplain", 0, 0, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"conn", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_client_t",NULL,NULL,NULL,NULL,NULL}, {"db", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"cmd", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::status", NsfMongoStatusStub, 1, { {"conn", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_client_t",NULL,NULL,NULL,NULL,NULL}} }, {NULL, NULL, 0, {{NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}}} }; ./nsf2.4.0/library/mongodb/nx-mongo.tcl000644 000766 000024 00000104201 13713317040 020524 0ustar00neumannstaff000000 000000 # # Object orientend mapping between MongoDB and NX. # # Gustaf Neumann fecit, April 2011 # package require nx package require nsf::mongo package provide nx::mongo 2.4.0 # todo: How to handle multiple connections; currently we have a single, global connection, # todo: All references are currently auto-fetched. Make this optional. # todo: Extend the query language syntax, e.g. regexp, ... (handled at least partly via "~" operator) # todo: Handle remove for non-multivalued embedded objects # idea: Handle names of nx objects (e.g. property like __name) # idea: Combine incremental slot operations with e.g. add -> $push, remove -> $pull # todo: Make "embedded", "reference" spec even nicer? namespace eval ::nx::mongo { set ::nx::mongo::log 0 ::nx::Object create ::nx::mongo::db { :object property db :object property mongoConn :object property gridFsName :public object method connect {{-db test} args} { if {[info exists :db]} { if {${:db} eq $db} { # reuse existing connection return ${:mongoConn} } ::mongo::close ${:mongoConn} } set :db $db set :mongoConn [::mongo::connect {*}$args] } :public object method close {} { if {[info exists :gridFs]} { ::nsf::log notice "nx::mongo: auto close gridfs" :gridfs close } foreach {ns coll} [array get :collection] { ::nsf::log notice "nx::mongo: auto close collection $ns $coll" ::mongo::collection::close $coll } ::mongo::close ${:mongoConn} unset :db :mongoConn } :public object method destroy {} { if {[info exists :db]} { ::nsf::log notice "nx::mongo: auto close connection to database '${:db}'" ::mongo::close ${:mongoConn} } } :public object method collection {ns} { set key :collection($ns) if {[info exists $key]} {return [set $key]} if {[regexp {^([^.]+)[.](.+)$} $ns _ db coll]} { return [set $key [mongo::collection::open ${:mongoConn} $db $coll]] } return -code error "invalid mongo namespace '$ns'" } :public object method count {ns args} {::mongo::collection::count [:collection $ns] {*}$args} :public object method index {ns args} {::mongo::collection::index [:collection $ns] {*}$args} :public object method insert {ns args} {::mongo::collection::insert [:collection $ns] {*}$args} :public object method delete {ns args} {::mongo::collection::delete [:collection $ns] {*}$args} :public object method query {ns args} {::mongo::collection::query [:collection $ns] {*}$args} :public object method update {ns args} {::mongo::collection::update [:collection $ns] {*}$args} :public object method "drop collection" {name} { ::mongo::run -nocomplain ${:mongoConn} ${:db} [list drop string $name] } :public object method "drop database" {} { ::mongo::run -nocomplain ${:mongoConn} ${:db} [list dropDatabase integer 1] } :public object method "reset error" {} { ::mongo::run -nocomplain ${:mongoConn} ${:db} [list reseterror integer 1] } :public object method is_oid {string} {expr {[string length $string] == 24}} # # GridFS # :object property gridFs :public object method "gridfs open" {{name fs}} { if {[info exists :gridFsName]} { if {${:gridFsName} eq $name} {return ${:gridFs}} :gridfs close } set :gridFsName $name set :gridFs [::mongo::gridfs::open ${:mongoConn} ${:db} $name] } :public object method "gridfs close" {} { ::mongo::gridfs::close ${:gridFs} unset :gridFs :gridFsName } :public object method "gridfs create" {{-source file} value name {mime text/plain} {-metadata}} { ::mongo::gridfile::create -source $source ${:gridFs} $value $name $mime \ {*}[expr {[info exists metadata] ? [list -metadata $metadata] : {}}] } :public object method "gridfs list" {{-all:switch false} query} { set coll [:collection ${:db}.${:gridFsName}.files] if {!$all} { set info [::mongo::collection::query $coll $query -limit 1] return [lindex $info 0] } else { set info [::mongo::collection::query $coll {}] return $info } } :public object method "gridfs update" {id bson} { ::mongo::collection::update [:collection ${:db}.${:gridFsName}.files] \ [list _id oid $id] $bson } :public object method "file content" {query} { set f [mongo::gridfile::open ${:gridFs} $query] set content "" while {1} { append content [set chunk [mongo::gridfile::read $f 4096]] if {[string length $chunk] < 4096} { break } } mongo::gridfile::close $f return $content } :public object method "gridfs set attribute" {query attribute value} { set info [::nx::mongo::db gridfs list $query] if {$info eq ""} {return -code error "no such file <$query> stored in gridfs"} foreach {att type v} $info { dict set d $att $v } if {[dict exists $d $attribute] && [dict get $d $attribute] eq $value} { # right value, nothing to do return } elseif {[dict exists $d $attribute]} { # wrong value replace it set bson {} foreach {att type v} $info { if {$att eq $attribute} { lappend bson $att $type $value } else { lappend bson $att $type $v } } } else { #no such value, add it lappend bson {*}$info $attribute string $value } nx::mongo::db gridfs update [dict get $d _id] $bson } :public object method "gridfs unset attribute" {query attribute} { set info [::nx::mongo::db gridfs list $query] if {$info eq ""} {return -code error "no such file <$query> stored in gridfs"} foreach {att type v} $info { dict set d $att $v } if {[dict exists $d $attribute]} { # delete the attribute nx::mongo::db gridfs update [dict get $d _id] [list \$unset document [list $attribute string ""]] } else { # does not exist, nothing to do } } :public object method "gridfs map" {query url} { # map always the newest entry set fullQuery [list \$query document $query \$orderby document {uploadDate integer -1}] ::nx::mongo::db gridfs set attribute $fullQuery url $url } :public object method "gridfs mapped" {url} { set info [::mongo::collection::query [:collection ${:db}.${:gridFsName}.files] \ [list \$query document [list url string $url]] \ -limit 1] return [lindex $info 0] } } ####################################################################### # nx::mongo::Attribute is a specialized property slot # ::nx::MetaSlot create ::nx::mongo::Attribute -superclass ::nx::VariableSlot { :property mongotype :property rep # # manage logging of mongo concerns # :public method log {msg} { if {$::nx::mongo::log} { nsf::log notice "mongo-attribute: $msg" } } :protected method init {} { # # If the mongotype was not provided, set it to a value derived # from "type". Not all types are mappable easily to mongo types. # if {![info exists :mongotype]} { set :mongotype string if {[info exists :type]} { switch -glob ${:type} { "boolean" - "integer" {set :mongotype ${:type}} "embedded" {set :mongotype embedded_object} "reference" {set :mongotype referenced_object} } #"::*" {set :mongotype object} } } #puts stderr "mongo type of ${:name} is ${:mongotype} [info exists :type]" next } # # The methods "bson encode|decode" perform the low-level type # mapping between NX objects and the bson serialization. For now, # this handles just the array notation. # :public method "bson decode" {bsontype value} { #puts stderr "bson decode of ${:name} /$bsontype/ '$value'" if {$bsontype eq "array"} { if {![:isMultivalued]} { # We got an array, but the slot is not multivalued. Maybe # generating an error is too harsh, but for the mapping back, # we check for multivalued as well. return -code error "Attribute ${:name} should be multivalued, but it is not" } set result [list] foreach {pos type v} $value {lappend result [:bson decode $type $v]} return $result } elseif {$bsontype eq "document"} { #puts stderr "*** we have a document '$value', [:serialize]" if {${:type} eq "embedded" && [info exists :arg]} { #puts stderr "*** we have an embedded class = ${:arg}" set value [${:arg} bson create $value] #puts stderr "*** ${:arg} bson create ==> $value" } elseif {${:type} eq "reference" && [info exists :arg]} { #puts stderr "*** we have a reference, class = ${:arg}" # TODO we assume auto_deref set value [:bson deref ${:arg} $value] #puts stderr "*** bson deref ${:arg} ==> $value" } else { return -code error "don't know how to decode document with value '$value'; [:serialize]" } } return $value } :method "bson deref" {class value} { #puts stderr "*** bson deref $class '$value'" foreach {name type v} $value { if {[string match {$*} $name]} {set ([string range $name 1 end]) $v} } if {![info exists (id)]} { return -code error "value to be dereferenced does not contain dbref id: $value" } if {[info exists (db)]} { if {$(db) ne [$class cget -mongo_db]} { return -code error "$(db) is different to [$class cget -mongo_db]" } } if {[info exists (ref)]} { if {$(ref) ne [$class cget -mongo_collection]} { return -code error "$(ref) is different to [$class cget -mongo_collection]" } } return [$class find first -cond [list _id = $(id)]] } :method "bson encodeValue" {value} { if {${:mongotype} eq "embedded_object"} { #puts "embedded_object <$value>" return [list document [$value bson encode]] } elseif {${:mongotype} eq "referenced_object"} { if {![::nsf::var::exists $value _id]} { :log "autosave $value to obtain an object_id" $value save } set _id [$value cget -_id] set cls [$value info class] return [list document [list \ {$ref} string [$cls cget -mongo_collection] \ {$id} oid $_id \ {$db} string [$cls cget -mongo_db]]] } else { return [list ${:mongotype} $value] } } :method "bson encodeArray" {value} { set c -1 set array [list] foreach v $value {lappend array [incr c] {*}[:bson encodeValue $v]} return [list array $array] } :public method "bson encode" {-array:switch value} { if {[:isMultivalued] || $array} { return [:bson encodeArray $value] } else { return [:bson encodeValue $value] } } :public method remove {object value} { if {[:isMultivalued]} { set values [::nsf::var::set $object ${:name}] set p [lsearch $values $value] if {$p < 0} { return -code error "$value not included in $object.$value ($values)" } set newValues [lreplace $values $p $p] ::nsf::var::set $object ${:name} $newValues } else { return -code error "remove just implemented for multivalued slots" } } # # Type converter for handling embedded objects. Makes sure to # track "embedded in" relationship # :public method type=embedded {name value arg} { # Determine the calling object of the type converter, which # might be object itself or a variable slot managing the object. set s [:uplevel self] #puts stderr "XXXX check $name '$value' arg='$arg' s=$s // [:uplevel 1 self]" # The calling objects have the mongo::Object mixed in. if {![$s info has mixin ::nx::mongo::Object]} { # If this is not the case, we might be in a variable slot, # where we cannot trust the incoming name and we have to # obtain the object from one level higher. if {[$s info has type ::nx::VariableSlot]} { set name [$s cget -name] set s [:uplevel 2 self] if {![$s info has mixin ::nx::mongo::Object]} {set s ""} } else { # no slot object, some strange constellation set s "" } if {$s eq ""} { return -code error "$name '$value' is not embedded in object of type ::nx::mongo::Object" } } if {[::nsf::object::exists $value] && [::nsf::is class $arg] && [$value info has type $arg]} { ::nsf::var::set $value __embedded_in [list $s $name] ::nsf::var::set $s __contains($value) 1 } else { return -code error "value '$value' for property $name is not of type $arg" } } # # Type converter for handling embedded objects. Makes sure to # track "embedded in" relationship # :public method type=reference {name value arg} { set s [:uplevel self] #puts stderr "check $name '$value' arg='$arg' s=$s" if {[::nsf::object::exists $value] && [::nsf::is class $arg] && [$value info has type $arg]} { set ref [list $s $name] if {[::nsf::var::exists $value __referenced_in]} { set refs [::nsf::var::set $value __referenced_in] if {[lsearch $refs $ref] == -1} {lappend refs $ref} } else { set refs [list $ref] } ::nsf::var::set $value __referenced_in $refs } else { return -code error "value '$value' for property $name is not of type $arg" } } # # Type converter for datetime handling (scan date strings into # input values into integers in the form mongo expects it) # :public method type=datetime {name value} { # puts stderr "... [clock format [clock scan $value -format {%B %d, %Y}] -format {%B %d, %Y}]" # MongoDB stores time in ms if {[info exists :scanformat]} {return [expr {[clock scan $value -format ${:scanformat}] * 1000}]} return [expr {[clock scan $value] * 1000}] } } ####################################################################### # The class mongo::Class provides methods for mongo classes (such as # "find", "insert", ...) # ::nx::Class create ::nx::mongo::Class -superclass nx::Class { # # Every mongo class can be configured with a mongo_ns, from which # its instance data is queried. # :property mongo_ns :property mongo_db :property mongo_collection # # Provide helper methods to access from an external specifier # (property name or operator name) internal representations # (e.g. mongo type, or mongo operator). # :public method "get slot" {att} { set classes [list [self] {*}[:info mixins] {*}[:info heritage]] #puts stderr "searching for <$att> along <$classes>" foreach cls $classes { set slot [$cls info slots $att] if {$slot ne ""} { return $slot } } } :public method "get relop" {op} { array set "" {< $lt > $gt <= $lte >= $gte != $ne in $in all $all} return $($op) } # # For interaction with bson structures, we provide on the class # level "bson cond" (a small dsl for a more convenient syntax in # bson queries), "bson opts" (options like e.g. ordering), "bson # atts (a simplifed property selection) and "bson parameter" which # translates from a bson structure (tuple) into a dashed parameter # list used in object creation. # :method "bson cond" {cond} { #puts "bson cond $cond" set bson [list] foreach {att op value} $cond { set slot [:get slot $att] if {$slot eq ""} {return -code error "could not obtain slot for <$att $op $value>"} switch $op { "=" {lappend bson $att [$slot cget -mongotype] $value} ">" - "<" - "<=" - ">=" - "!=" { lappend bson $att document [list [:get relop $op] [$slot cget -mongotype] $value] } "in" - "all" { lappend bson $att document [list [:get relop $op] {*}[$slot bson encode -array $value]] } "~" { # value should be a two-element list contain pattern and options lappend bson $att document [list {$regex} regex $value] } default {return -code error "unknown operator $op"} } } #puts "bson cond <$cond> => $bson" return $bson } :method "bson opts" {{-orderby ""} {-atts ""} -limit:integer -skip:integer} { set result "" if {$atts ne ""} { lappend result projection document [:bson atts $atts] } if {[info exists limit]} { lappend result limit int64 $limit } if {[info exists skip]} { lappend result skip int64 $skip } if {$orderby ne ""} { lappend result sort document [:bson orderby $orderby] } return $result } :method "bson orderby" {orderby} { set bson [list] foreach attspec $orderby { lassign $attspec att direction lappend bson $att int [expr {$direction eq "desc" ? -1 : 1}] } return $bson } :method "bson atts" {atts} { set result {} foreach {att value} $atts { if {![string is integer -strict $value]} { return -code error "$atts: $value should be integer" } lappend result $att int $value } return $result } :method "bson parameter" {tuple} { # # Translate bson tuple into a parameter values pairs suited as # configure parameters # #puts "bson parameter: <$tuple>" set objParams [list] foreach {att type value} $tuple { set slot [:get slot $att] if {$slot eq ""} {return -code error "could not obtain slot for <$att $type $value>"} lappend objParams -$att [$slot bson decode $type $value] } #puts "bson parameter <$tuple> => $objParams" return $objParams } :public method "bson setvalues" {tuple} { # # Translate bson tuple into a cmd to set instance values, which # can be evaluated in the context of an object. # #puts "bson setvalues: <$tuple>" set cmd "" foreach {att type value} $tuple { set slot [:get slot $att] if {$slot eq ""} {return -code error "could not obtain slot for <$att $type $value>"} if {[nx::var exists $slot rep] && [nx::var set $slot rep] ne ""} { set script [:bson rep decode [nx::var set $slot rep] $slot $att $type $value] append cmd $script\n } else { append cmd "set [list :$att] [list [$slot bson decode $type $value]]\n" } } #puts "bson parameter <$tuple> => $objParams" return $cmd } :public method "bson create" {{-name ""} tuple} { #puts stderr "=== [self] bson create name <$name> tuple <$tuple>" set class [self] set filtered_tuple {} foreach {att_name att_type att_value} $tuple { if {$att_name eq "__class"} { # # Special handlnig of "__class" attribute # if {[nsf::is class $att_value]} { set class $att_value } continue } lappend filtered_tuple $att_name $att_type $att_value } #puts "FINAL class $class, values\n[$class bson setvalues $filtered_tuple]" set o [::nsf::object::alloc $class $name [$class bson setvalues $filtered_tuple]] $o eval :init return $o } :method "bson pp_array" {{-indent 0} list} { set result [list] foreach {name type value} $list { switch $type { document { lappend result "\{ [:bson pp -indent $indent $value] \}" } array { lappend result "\[ [:bson pp_array -indent $indent $value] \]" } default { lappend result [list $value]} } } return [join $result ", "] } :public method "bson pp" {{-indent 0} list} { set result [list] set nextIndent [expr {$indent + 2}] foreach {name type value} $list { set prefix "\n[string repeat { } $indent]$name: " switch $type { document { lappend result "$prefix\{ [:bson pp -indent $nextIndent $value] \}" } array { lappend result "$prefix\[ [:bson pp_array -indent $nextIndent $value] \]" } default { lappend result $prefix[list $value]} } } return [join $result ", "] } # # Overload method property to provide "::nx::mongo::Attribute" as a # default slot class # :public method property { {-accessor ""} {-class ::nx::mongo::Attribute} {-configurable:boolean true} {-incremental:switch} {-rep ""} spec:parameter {initblock ""} } { regsub -all {,type=::} $spec {,arg=::} spec set result [next [list -accessor $accessor -class $class \ -configurable $configurable -incremental=$incremental \ $spec $initblock]] lassign [::nx::MetaSlot parseParameterSpec -target [self] {*}$spec] name parameterOptions class options #puts stderr "==== spec <$spec> => name <$name> parameterOptions <$parameterOptions> class <$class> options <$options>" #puts stderr "==== [list [self] property [:info slots $name] configure -rep $rep]" [:info slots $name] configure -rep $rep return $result } :public method variable { {-accessor "none"} {-class ::nx::mongo::Attribute} {-configurable:boolean false} {-incremental:switch} {-initblock ""} {-rep ""} spec:parameter defaultValue:optional } { regsub -all {,type=::} $spec {,arg=::} spec set result [next [list -accessor $accessor -class $class \ -configurable $configurable -incremental=$incremental \ -initblock $initblock $spec \ {*}[expr {[info exists defaultValue] ? [list $defaultValue] : ""}]]] lassign [::nx::MetaSlot parseParameterSpec -target [self] $spec] name [:info slots $name] configure -rep $rep return $result } :public method pretty_variables {} { set vars {} foreach p [lmap handle [lsort [:info variables]] {::nx::Object info variable parameter $handle}] { if {[regexp {^([^:]+):(.*)$} $p _ name options]} { set resultOptions {} set opts [split $options ,] if {[lindex $opts 0] eq "embedded"} { set resultOpts {} foreach opt $opts { switch -glob $opt { slot=* {continue} arg=* {lappend resultOpts type=[string range $opt 4 end]} default {lappend resultOpts $opt} } } lappend vars $name:[join $resultOpts ,] continue } } lappend vars $p } return $vars } # # index method # :public method index {att {-type 1} args} { if {![info exists :mongo_ns]} {:mongo_setup} # todo: 2nd index will need a different type # todo: multi-property indices db index ${:mongo_ns} [list $att int $type] {*}$args } # # A convenience method for inserting a fresh tuple # :public method insert {args} { set p [:new {*}$args] $p save set _id [$p cget -_id] $p destroy return $_id } # # The method "count" is similar to find, but returns just the # number of tuples for the query. # :public method count {{-cond ""}} { return [::nx::mongo::db count ${:mongo_ns} [:bson cond $cond]] } # # The query interface consists currently of "find first" (returning # a single instance) and "find all" (returning a list of instances). # :public method "find first" { {-instance ""} {-atts ""} {-cond ""} {-orderby ""} } { set tuple [lindex [::nx::mongo::db query ${:mongo_ns} \ [:bson cond $cond] \ -opts [:bson opts -atts $atts -limit 1 -orderby $orderby] \ ] 0] if {$tuple eq ""} { return "" } if {$instance ne ""} {set instance [:uplevel [list ::nsf::object::qualify $instance]]} return [:bson create -name $instance $tuple] } :public method "find all" { {-atts ""} {-cond ""} {-orderby ""} {-limit:integer} {-skip:integer} {-asJSON:boolean 0} } { set result [list] set opts [list] if {[info exists limit]} {lappend opts -limit $limit} if {[info exists skip]} {lappend opts -skip $skip} set fetched [::nx::mongo::db query ${:mongo_ns} \ [:bson cond $cond] \ -opts [:bson opts -orderby $orderby -atts $atts {*}$opts] ] if {$asJSON} { # # Return fetched tuples form mongoDB in form of a JSON array # (between square brackets). # # The last 5 lines of this proc could be written as the following line, # but we keep it traditional... # # return [subst { \[ [join [lmap tuple $fetched {mongo::json::generate $tuple}] ,\n] \] }] # set tuples [list] foreach tuple $fetched { lappend tuples [mongo::json::generate $tuple] } return [subst { \[ [join $tuples ",\n"] \] }] } else { # # Create from the fetched tuples form mongoDB objects. # foreach tuple $fetched { lappend result [:bson create $tuple] } return $result } } :public method show { {-atts ""} {-cond ""} {-orderby ""} {-limit} {-skip} {-puts:boolean 1} } { set opts [list] if {[info exists limit]} {lappend opts -limit $limit} if {[info exists skip]} {lappend opts -skip $skip} set fetched [::nx::mongo::db query ${:mongo_ns} \ [:bson cond $cond] \ -opts [:bson opts -orderby $orderby -atts $atts {*}$opts] ] set tuples [list] foreach tuple $fetched { lappend tuples "\{[:bson pp -indent 4 $tuple]\n\}" } if {$puts} {puts [join $tuples ", "]} return $tuples } :method mongo_setup {} { # # setup mongo_collection, mongo_db and mongo_ns # if {[info exists :mongo_ns]} { #puts stderr "given mongo_ns ${:mongo_ns}" if {![regexp {^([^.]+)[.](.*)$} ${:mongo_ns} :mongo_db :mongo_collection]} { return -code error "${:mongo_ns} does not contain a dot." } } else { if {![info exists :mongo_collection]} { set :mongo_collection [string tolower [namespace tail [self]]]s } if {![info exists :mongo_db]} { set :mongo_db [::nx::mongo::db cget -db] } set :mongo_ns ${:mongo_db}.${:mongo_collection} #puts stderr "mongo_ns is set to ${:mongo_ns}" } } # # When a mongo::Class is created, mixin the mongo::Object to make # "save" etc. available # :method init {} { :mixins add ::nx::mongo::Object :mongo_setup } # :public method "bson rep encode array" {slot obj name} { return [$slot bson encode -array [$obj eval [list array get :$name]]] } :public method "bson rep decode array" {slot name bsontype value} { set result [list] foreach {pos type v} $value {lappend result [$slot bson decode $type $v]} return [list array set :$name $result] } } # # Provide special representations in MongoDB for instance variables. # The methods # # bson rep encode .... # bson rep decode .... # # can be used for creating tailored methods to obtain and encode # instance variables and for decoding and setting these. The codecs # (coder/decoder) are extensible on the application level by # defining ensemble methods with the name of the codec as last part. ::nx::mongo::Class eval { # # rep codec "array" # :public method "bson rep encode array" {slot obj name} { set body {} set c 0 foreach {k v} [$obj eval [list array get :$name]] { lappend body [incr c] document [list k string $k v string $v] } return [list array $body] } :public method "bson rep decode array" {slot name bsontype value} { set av "" foreach {pos type entry} $value { lappend av [lindex $entry 2] [lindex $entry 5] } return "array set :$name [list $av]" } # # rep codec "dict" # :public method "bson rep encode dict" {slot obj name} { set body {} dict for {k v} [$obj eval [list set :$name]] { lappend body $k string $v } return [list document $body] } :public method "bson rep decode dict" {slot name bsontype value} { set result "" foreach {k type v} $value { lappend result $k $v } return "set :$name \[dict create $result\]" } } ####################################################################### # The class mongo::Object provides methods for mongo objects (such as # "save") # ::nx::Class create ::nx::mongo::Object { # # manage logging of mongo concerns # :public method log {msg} { if {$::nx::mongo::log} { nsf::log notice "mongo: $msg" } } # # Manage lifecycle concerns for NaviServer/AOLserver: at the end # of every request, all global variables are deleted. We can use # this to destroy as well volatile mongoDB objects via Tcl # variable traces. # :public method destroy_on_cleanup {} { set name ::__volatile_mongo_objects([self]) set $name 1 trace add variable $name unset [list [self] __cleanup] } :public method __cleanup {args} { :destroy } # # _id is the special property maintained by mongoDB # :property -accessor public -class ::nx::mongo::Attribute _id { set :mongotype oid } # # Encode all object data in bson notation # :public method "bson encode" {{-ignore ""}} { set bson [list] set cls [:info class] lappend bson "__class" string $cls foreach var [:info vars] { if {$var in $ignore} continue set slot [$cls get slot $var] if {$slot ne ""} { if {[nx::var exists $slot rep] && [nx::var set $slot rep] ne ""} { lappend bson $var {*}[$cls bson rep encode [nx::var set $slot rep] $slot [self] $var] } else { lappend bson $var {*}[$slot bson encode [set :$var]] } } } return $bson } :public method "bson asJSON" {} { # # Return the current object in JSON syntax. # return [mongo::json::generate [:bson encode]] } # # destroy a mapped object from memory # :public method destroy {} { if {[array exists :__contains]} { # destroy embedded object foreach o [array names :__contains] { :log "[self] contains $o -> destroy" $o destroy } } if {[info exists :__embedded_in]} { lassign ${:__embedded_in} parent att ::nsf::var::unset $parent __contains([self]) } next } # # delete the current object from the db # :public method delete {} { if {[info exists :__embedded_in]} { # # When an embedded object is deleted, it is removed for the # reference list. The containing object is not automatically # saved for the time being. We could consider an automatic # save or mongo-$pull update operation. # #puts "[self] is embedded in ${:__embedded_in}" lassign ${:__embedded_in} parent att set slot [[$parent info class] get slot $att] if {$slot eq ""} {return -code error "could not obtain slot for <[$parent info class] $att>"} $slot remove $parent [self] #puts stderr [:serialize] :log "[self] must save parent $parent in db" :destroy } elseif {[info exists :__referenced_in]} { # # When a referenced is deleted, we do for now essentially the # same as for embedded objects. However, the same object might # be referenced by several objects. # #puts "[self] is referenced in ${:__referenced_in}" foreach reference ${:__referenced_in} { lassign $reference parent att set slot [[$parent info class] get slot $att] if {$slot eq ""} {return -code error "could not obtain slot for <[$parent info class] $att>"} $slot remove $parent [self] :log "[self] must save parent $parent in db" } :destroy } else { #puts "delete a non-embedded entry" if {[info exists :_id]} { set mongo_ns [[:info class] cget -mongo_ns] ::nx::mongo::db delete $mongo_ns [list _id oid ${:_id}] } else { return -code error "[self]: object does not contain an _id; it can't be delete from the mongo db." } } } # # Save the current object. When we have an _id, perform an update, # otherwise perform an insert # :public method save {} { set mongo_ns [[:info class] cget -mongo_ns] if {$mongo_ns eq ""} { # We could perform the delegation probably automatically, but # for now we provide an error return -code error "No mongo_ns specified for [:info class]. In case this is an embedded object, save the embedding one." } else { set bson [:bson encode] if {[info exists :_id]} { :log "we have to update [[:info class] bson pp -indent 4 $bson]" ::nx::mongo::db update $mongo_ns [list _id oid ${:_id}] $bson set :_id } else { :log "we have to insert [[:info class] bson pp -indent 4 $bson]" set r [::nx::mongo::db insert $mongo_ns $bson] set :_id [lindex $r 2] } } } } } #puts stderr "NX MONGO LOADED" # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/mongodb/__test.log000644 000766 000024 00000000677 14275673120 020262 0ustar00neumannstaff000000 000000 Test-set nsf-mongo tests 29 success 29 failure 0 ms 271 Test-set nsf-gridfs tests 18 success 18 failure 0 ms 9 Test-set nx-bi tests 6 success 6 failure 0 ms 3 Test-set nx-mongo tests 40 success 40 failure 0 ms 420 Test-set nx-reference-one tests 23 success 23 failure 0 ms 209 Test-set nx-reference-many tests 23 success 23 failure 0 ms 192 Test-set nx-serialize tests 14 success 14 failure 0 ms 1 Test-set nx-rep tests 6 success 6 failure 0 ms 1 ./nsf2.4.0/library/mongodb/Makefile.in000644 000766 000024 00000040603 13677321015 020336 0ustar00neumannstaff000000 000000 # Makefile.in -- # # This file is a Makefile for Sample TEA Extension. If it has the name # "Makefile.in" then it is a template for a Makefile; to generate the # actual Makefile, run "./configure", which is a configuration script # generated by the "autoconf" program (constructs like "@foo@" will get # replaced in the actual Makefile. # # Copyright (c) 1999 Scriptics Corporation. # Copyright (c) 2002-2003 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # #======================================================================== # Add additional lines to handle any additional AC_SUBST cases that # have been added in a customized configure script. #======================================================================== #SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@ #======================================================================== # Nothing of the variables below this line should need to be changed. # Please check the TARGETS section below to make sure the make targets # are correct. #======================================================================== #======================================================================== # The names of the source files is defined in the configure script. # The object files are used for linking into the final library. # This will be used when a dist target is added to the Makefile. # It is not important to specify the directory, as long as it is the # $(srcdir) or in the generic, win or unix subdirectory. #======================================================================== PKG_SOURCES = @PKG_SOURCES@ PKG_OBJECTS = @PKG_OBJECTS@ PKG_STUB_SOURCES = @PKG_STUB_SOURCES@ PKG_STUB_OBJECTS = @PKG_STUB_OBJECTS@ #======================================================================== # PKG_TCL_SOURCES identifies Tcl runtime files that are associated with # this package that need to be installed, if any. #======================================================================== PKG_TCL_SOURCES = @PKG_TCL_SOURCES@ #======================================================================== # This is a list of public header files to be installed, if any. #======================================================================== PKG_HEADERS = @PKG_HEADERS@ #======================================================================== # "PKG_LIB_FILE" refers to the library (dynamic or static as per # configuration options) composed of the named objects. #======================================================================== PKG_LIB_FILE = @PKG_LIB_FILE@ PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@ lib_BINARIES = $(PKG_LIB_FILE) BINARIES = $(lib_BINARIES) SHELL = @SHELL@ srcdir = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ datarootdir = @datarootdir@ datadir = @datadir@ mandir = @mandir@ includedir = @includedir@ DESTDIR = PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_VERSION) pkgdatadir = $(datadir)/$(PKG_DIR) pkglibdir = $(libdir)/$(PKG_DIR) pkgincludedir = $(includedir)/$(PKG_DIR) top_builddir = . INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ CC = @CC@ CFLAGS_DEFAULT = @CFLAGS_DEFAULT@ CFLAGS_WARNING = @CFLAGS_WARNING@ CLEANFILES = @CLEANFILES@ EXEEXT = @EXEEXT@ LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@ MAKE_LIB = @MAKE_LIB@ MAKE_SHARED_LIB = @MAKE_SHARED_LIB@ MAKE_STATIC_LIB = @MAKE_STATIC_LIB@ MAKE_STUB_LIB = @MAKE_STUB_LIB@ OBJEXT = @OBJEXT@ RANLIB = @RANLIB@ RANLIB_STUB = @RANLIB_STUB@ SHLIB_CFLAGS = @SHLIB_CFLAGS@ SHLIB_LD = @SHLIB_LD@ SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ STLIB_LD = @STLIB_LD@ TCL_DEFS = @TCL_DEFS@ TCL_BIN_DIR = @TCL_BIN_DIR@ TCL_SRC_DIR = @TCL_SRC_DIR@ # Not used, but retained for reference of what libs Tcl required TCL_LIBS = @TCL_LIBS@ #======================================================================== # TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our # package without installing. The other environment variables allow us # to test against an uninstalled Tcl. Add special env vars that you # require for testing here (like TCLX_LIBRARY). #======================================================================== EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR) TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` \ @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \ PATH="$(EXTRA_PATH):$(PATH)" \ TCLLIBPATH="../../ $(top_builddir)" TCLSH_PROG = @TCLSH_PROG@ TCLSH = $(TCLSH_ENV) $(TCLSH_PROG) SHARED_BUILD = @SHARED_BUILD@ INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ EXTRA_CFLAGS = @PKG_CFLAGS@ EXTRA_CFLAGS = @PKG_CFLAGS@ -DMONGO_HAVE_STDINT -DUSE_NSF_STUBS=1 # TCL_DEFS is not strictly need here, but if you remove it, then you # must make sure that configure.in checks for the necessary components # that your library may use. TCL_DEFS can actually be a problem if # you do not compile with a similar machine setup as the Tcl core was # compiled with. #DEFS = $(TCL_DEFS) @DEFS@ $(EXTRA_CFLAGS) DEFS = @DEFS@ $(EXTRA_CFLAGS) CONFIG_CLEAN_FILES = Makefile CPPFLAGS = @CPPFLAGS@ LIBS = @PKG_LIBS@ @LIBS@ AR = ar CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) #======================================================================== # Start of user-definable TARGETS section #======================================================================== CPPCHECK = cppcheck #======================================================================== # TEA TARGETS. Please note that the "libraries:" target refers to platform # independent files, and the "binaries:" target includes executable programs and # platform-dependent libraries. Modify these targets so that they install # the various pieces of your package. The make and install rules # for the BINARIES that you specified above have already been done. #======================================================================== all: binaries libraries doc #======================================================================== # The binaries target builds executable programs, Windows .dll's, unix # shared/static libraries, and any other platform-dependent files. # The list of targets to build for "binaries:" is specified at the top # of the Makefile, in the "BINARIES" variable. #======================================================================== binaries: $(BINARIES) pkgIndex.tcl libraries: cppcheck: $(CPPCHECK) --enable=all *.c $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) \ -DNDEBUG=1 -I/usr/include -D__x86_64__ doc: @echo "If you have documentation to create, place the commands to" @echo "build the docs in the 'doc:' target. For example:" @echo " xml2nroff sample.xml > sample.n" @echo " xml2html sample.xml > sample.html" install: all install-binaries install-libraries install-doc install-binaries: binaries install-lib-binaries install-bin-binaries if test "x$(SHARED_BUILD)" = "x1"; then \ $(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir); \ fi #======================================================================== # This rule installs platform-independent files, such as header files. #======================================================================== install-libraries: libraries @mkdir -p $(DESTDIR)$(includedir) @echo "Installing header files in $(DESTDIR)$(includedir)" @if test -n "$(PKG_HEADERS)" ; then \ for i in "$(PKG_HEADERS)" ; do \ echo "Installing $(srcdir)/$$i" ; \ $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir) ; \ done; \ fi $(INSTALL_DATA) $(srcdir)/nx-mongo.tcl $(DESTDIR)$(pkglibdir) #======================================================================== # Install documentation. Unix manpages should go in the $(mandir) # directory. #======================================================================== install-doc: doc #install-doc: doc # @mkdir -p $(DESTDIR)$(mandir)/mann # @echo "Installing documentation in $(DESTDIR)$(mandir)" # @for i in $(srcdir)/doc/*.n; do \ # echo "Installing $$i"; \ # rm -f $(DESTDIR)$(mandir)/mann/`basename $$i`; \ # $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \ # done TESTLOG = ./__test.log TESTFLAGS = -testlog $(TESTLOG) test: binaries libraries rm -f $(TESTLOG) $(TCLSH) $(srcdir)/tests/nsf-mongo.test -libdir . $(TESTFLAGS) $(TCLSH) $(srcdir)/tests/nsf-gridfs.test -libdir . $(TESTFLAGS) $(TCLSH) $(srcdir)/tests/nx-bi.test -libdir . $(TESTFLAGS) $(TCLSH) $(srcdir)/tests/nx-mongo.test -libdir . $(TESTFLAGS) $(TCLSH) $(srcdir)/tests/nx-reference-one.test -libdir . $(TESTFLAGS) $(TCLSH) $(srcdir)/tests/nx-reference-many.test -libdir . $(TESTFLAGS) $(TCLSH) $(srcdir)/tests/nx-serialize.test -libdir . $(TESTFLAGS) $(TCLSH) $(srcdir)/tests/nx-rep.test -libdir . $(TESTFLAGS) @$(TCLSH) $(srcdir)/../../tests/summary.tcl -title MongoDB -libdir . $(TESTFLAGS) shell: binaries libraries @$(TCLSH) $(SCRIPT) gdb: $(TCLSH_ENV) gdb $(TCLSH_PROG) $(SCRIPT) depend: #======================================================================== # $(PKG_LIB_FILE) should be listed as part of the BINARIES variable # mentioned above. That will ensure that this target is built when you # run "make binaries". # # The $(PKG_OBJECTS) objects are created and linked into the final # library. In most cases these object files will correspond to the # source files above. #======================================================================== $(PKG_LIB_FILE): $(PKG_OBJECTS) -rm -f $(PKG_LIB_FILE) ${MAKE_LIB} $(RANLIB) $(PKG_LIB_FILE) $(PKG_STUB_LIB_FILE): $(PKG_STUB_OBJECTS) -rm -f $(PKG_STUB_LIB_FILE) ${MAKE_STUB_LIB} $(RANLIB_STUB) $(PKG_STUB_LIB_FILE) #======================================================================== # We need to enumerate the list of .c to .o lines here. # # In the following lines, $(srcdir) refers to the toplevel directory # containing your extension. If your sources are in a subdirectory, # you will have to modify the paths to reflect this: # # sample.$(OBJEXT): $(srcdir)/generic/sample.c # $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@ # # Setting the VPATH variable to a list of paths will cause the makefile # to look into these paths when resolving .c to .obj dependencies. # As necessary, add $(srcdir):$(srcdir)/compat:.... #======================================================================== VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win .c.@OBJEXT@: $(COMPILE) -c `@CYGPATH@ $<` -o $@ nsfmongo.@OBJEXT@: nsfmongo.c mongoAPI.h mongoAPI.h: ../../generic/gentclAPI.tcl mongoAPI.decls $(TCLSH) ../../generic/gentclAPI.tcl mongoAPI.decls > mongoAPI.h #======================================================================== # Create the pkgIndex.tcl file. # It is usually easiest to let Tcl do this for you with pkg_mkIndex, but # you may find that you need to customize the package. If so, either # modify the -hand version, or create a pkgIndex.tcl.in file and have # the configure script output the pkgIndex.tcl by editing configure.in. #======================================================================== #pkgIndex.tcl: # ( echo pkg_mkIndex . $(PKG_LIB_FILE) \; exit; ) | $(TCLSH) pkgIndex.tcl: (echo 'package ifneeded nsf::mongo $(PACKAGE_VERSION) \ [list load [file join $$dir $(PKG_LIB_FILE)]]'\ ) > pkgIndex.tcl (echo 'package ifneeded nx::mongo $(PACKAGE_VERSION) \ [list source [file join $$dir nx-mongo.tcl]]'\ ) >> pkgIndex.tcl #======================================================================== # Distribution creation # You may need to tweak this target to make it work correctly. #======================================================================== #COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar COMPRESS = gtar zcvf $(PKG_DIR).tar.gz $(PKG_DIR) DIST_ROOT = /tmp/dist DIST_DIR = $(DIST_ROOT)/$(PKG_DIR) dist-clean: rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.* dist: dist-clean mkdir -p $(DIST_DIR) cp -p $(srcdir)/ChangeLog $(srcdir)/README* $(srcdir)/license* \ $(srcdir)/aclocal.m4 $(srcdir)/configure $(srcdir)/*.in \ $(DIST_DIR)/ chmod 664 $(DIST_DIR)/Makefile.in $(DIST_DIR)/aclocal.m4 chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.in cp -p $(srcdir)/*.[ch] $(DIST_DIR)/ mkdir $(DIST_DIR)/tclconfig cp $(srcdir)/tclconfig/install-sh $(srcdir)/tclconfig/tcl.m4 \ $(DIST_DIR)/tclconfig/ chmod 664 $(DIST_DIR)/tclconfig/tcl.m4 chmod +x $(DIST_DIR)/tclconfig/install-sh list='demos doc generic library mac tests unix win'; \ for p in $$list; do \ if test -d $(srcdir)/$$p ; then \ mkdir $(DIST_DIR)/$$p; \ cp -p $(srcdir)/$$p/*.* $(DIST_DIR)/$$p/; \ fi; \ done (cd $(DIST_ROOT); $(COMPRESS);) #======================================================================== # End of user-definable section #======================================================================== #======================================================================== # Don't modify the file to clean here. Instead, set the "CLEANFILES" # variable in configure.in #======================================================================== clean: -test -z "$(BINARIES)" || rm -f $(BINARIES) -rm -f *.$(OBJEXT) core *.core -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean: clean -rm -f *.tab.c -rm -f $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log config.status #======================================================================== # Install binary object libraries. On Windows this includes both .dll and # .lib files. Because the .lib files are not explicitly listed anywhere, # we need to deduce their existence from the .dll file of the same name. # Library files go into the lib directory. # In addition, this will generate the pkgIndex.tcl # file in the install location (assuming it can find a usable tclsh shell) # # You should not have to modify this target. #======================================================================== install-lib-binaries: @mkdir -p $(DESTDIR)$(pkglibdir) @list='$(lib_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p; \ stub=`echo $$p|sed -e "s/.*\(stub\).*/\1/"`; \ if test "x$$stub" = "xstub"; then \ echo " $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p"; \ $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p; \ else \ echo " $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p"; \ $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p; \ fi; \ ext=`echo $$p|sed -e "s/.*\.//"`; \ if test "x$$ext" = "xdll"; then \ lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \ if test -f $$lib; then \ echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \ $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib; \ fi; \ fi; \ fi; \ done @list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ if test -f $(srcdir)/$$p; then \ destp=`basename $$p`; \ echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \ fi; \ done #======================================================================== # Install binary executables (e.g. .exe files and dependent .dll files) # This is for files that must go in the bin directory (located next to # wish and tclsh), like dependent .dll files on Windows. # # You should not have to modify this target, except to define bin_BINARIES # above if necessary. #======================================================================== install-bin-binaries: @mkdir -p $(DESTDIR)$(bindir) @list='$(bin_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \ fi; \ done .SUFFIXES: .c .$(OBJEXT) Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status uninstall-binaries: list='$(lib_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ p=`basename $$p`; \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(bin_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(bindir)/$$p; \ done .PHONY: all binaries clean depend distclean doc install libraries test # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ./nsf2.4.0/library/mongodb/aclocal.m4000644 000766 000024 00000001262 13464223572 020132 0ustar00neumannstaff000000 000000 # generated automatically by aclocal 1.16.1 -*- Autoconf -*- # Copyright (C) 1996-2018 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_include([m4/tcl.m4]) ./nsf2.4.0/library/mongodb/mongoAPI.nxdocindex000644 000766 000024 00000002667 12750610465 022040 0ustar00neumannstaff000000 000000 set ::nxdoc::include(::mongo::json::generate) 0 set ::nxdoc::include(::mongo::json::parse) 0 set ::nxdoc::include(::mongo::close) 0 set ::nxdoc::include(::mongo::connect) 0 set ::nxdoc::include(::mongo::run) 0 set ::nxdoc::include(::mongo::status) 0 set ::nxdoc::include(::mongo::collection::close) 0 set ::nxdoc::include(::mongo::collection::count) 0 set ::nxdoc::include(::mongo::collection::delete) 0 set ::nxdoc::include(::mongo::collection::index) 0 set ::nxdoc::include(::mongo::collection::insert) 0 set ::nxdoc::include(::mongo::collection::open) 0 set ::nxdoc::include(::mongo::collection::query) 0 set ::nxdoc::include(::mongo::collection::stats) 0 set ::nxdoc::include(::mongo::collection::update) 0 set ::nxdoc::include(::mongo::cursor::aggregate) 0 set ::nxdoc::include(::mongo::cursor::find) 0 set ::nxdoc::include(::mongo::cursor::next) 0 set ::nxdoc::include(::mongo::cursor::close) 0 set ::nxdoc::include(::mongo::gridfs::close) 0 set ::nxdoc::include(::mongo::gridfs::open) 0 set ::nxdoc::include(::mongo::gridfile::create) 0 set ::nxdoc::include(::mongo::gridfile::delete) 0 set ::nxdoc::include(::mongo::gridfile::open) 0 set ::nxdoc::include(::mongo::gridfile::close) 0 set ::nxdoc::include(::mongo::gridfile::get_contentlength) 0 set ::nxdoc::include(::mongo::gridfile::get_contenttype) 0 set ::nxdoc::include(::mongo::gridfile::get_metadata) 0 set ::nxdoc::include(::mongo::gridfile::read) 0 set ::nxdoc::include(::mongo::gridfile::seek) 0 ./nsf2.4.0/library/xml/TclExpat-1.1/Makefile000644 000766 000024 00000045304 12161565453 021133 0ustar00neumannstaff000000 000000 # Makefile.in -- # # This file is a Makefile for Sample TEA Extension. If it has the name # "Makefile.in" then it is a template for a Makefile; to generate the # actual Makefile, run "./configure", which is a configuration script # generated by the "autoconf" program (constructs like "@foo@" will get # replaced in the actual Makefile. # # Copyright (c) 1999 Scriptics Corporation. # Copyright (c) 2002-2003 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: Makefile.in,v 1.5 2007/08/14 16:38:27 neumann Exp $ #======================================================================== # Add additional lines to handle any additional AC_SUBST cases that # have been added in a customized configure script. #======================================================================== #SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@ #======================================================================== # Nothing of the variables below this line should need to be changed. # Please check the TARGETS section below to make sure the make targets # are correct. #======================================================================== #======================================================================== # The names of the source files is defined in the configure script. # The object files are used for linking into the final library. # This will be used when a dist target is added to the Makefile. # It is not important to specify the directory, as long as it is the # $(srcdir) or in the generic, win or unix subdirectory. #======================================================================== PKG_SOURCES = xmltok.c unixfilemap.c xmlrole.c xmlwf.c codepage.c xmlparse.c hashtable.c tclexpat.c PKG_OBJECTS = xmltok.o unixfilemap.o xmlrole.o xmlwf.o codepage.o xmlparse.o hashtable.o tclexpat.o PKG_STUB_SOURCES = PKG_STUB_OBJECTS = #======================================================================== # PKG_TCL_SOURCES identifies Tcl runtime files that are associated with # this package that need to be installed, if any. #======================================================================== PKG_TCL_SOURCES = #======================================================================== # This is a list of public header files to be installed, if any. #======================================================================== PKG_HEADERS = #======================================================================== # "PKG_LIB_FILE" refers to the library (dynamic or static as per # configuration options) composed of the named objects. #======================================================================== PKG_LIB_FILE = libxotclexpat0.9.dylib PKG_STUB_LIB_FILE = libxotclexpatstub0.9.a lib_BINARIES = $(PKG_LIB_FILE) BINARIES = $(lib_BINARIES) SHELL = /bin/sh srcdir = . prefix = /usr/local exec_prefix = /usr/local/ bindir = ${exec_prefix}/bin libdir = ${exec_prefix}/lib datadir = ${prefix}/share mandir = ${prefix}/share/man includedir = ${prefix}/include DESTDIR = PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_VERSION) pkgdatadir = $(datadir)/$(PKG_DIR) pkglibdir = $(libdir)/$(PKG_DIR) pkgincludedir = $(includedir)/$(PKG_DIR) top_builddir = . INSTALL = /usr/bin/install -c INSTALL_PROGRAM = ${INSTALL} INSTALL_DATA = ${INSTALL} -m 644 INSTALL_SCRIPT = ${INSTALL} PACKAGE_NAME = xotclexpat PACKAGE_VERSION = 0.9 CC = gcc CFLAGS_DEFAULT = -g CFLAGS_WARNING = -Wall CLEANFILES = pkgIndex.tcl EXEEXT = LDFLAGS_DEFAULT = -prebind -headerpad_max_install_names -Wl,-search_paths_first MAKE_LIB = ${SHLIB_LD} -o $@ $(PKG_OBJECTS) ${SHLIB_LD_LIBS} MAKE_SHARED_LIB = ${SHLIB_LD} -o $@ $(PKG_OBJECTS) ${SHLIB_LD_LIBS} MAKE_STATIC_LIB = ${STLIB_LD} $@ $(PKG_OBJECTS) MAKE_STUB_LIB = ${STLIB_LD} $@ $(PKG_STUB_OBJECTS) OBJEXT = o RANLIB = : RANLIB_STUB = ranlib SHLIB_CFLAGS = -fno-common SHLIB_LD = ${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT} -Wl,-single_module -current_version 0.9 -compatibility_version 0.9 SHLIB_LD_FLAGS = @SHLIB_LD_FLAGS@ SHLIB_LD_LIBS = ${LIBS} -L/usr/local/src/tcl8.5.13/unix -ltclstub8.5 STLIB_LD = ${AR} cr TCL_DEFS = -DPACKAGE_NAME=\"tcl\" -DPACKAGE_TARNAME=\"tcl\" -DPACKAGE_VERSION=\"8.5\" -DPACKAGE_STRING=\"tcl\ 8.5\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DNO_VALUES_H=1 -DHAVE_LIMITS_H=1 -DHAVE_SYS_PARAM_H=1 -DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 -D_THREAD_SAFE=1 -DHAVE_PTHREAD_ATTR_SETSTACKSIZE=1 -DHAVE_PTHREAD_GET_STACKSIZE_NP=1 -DTCL_THREADS=1 -DTCL_CFGVAL_ENCODING=\"iso8859-1\" -DMODULE_SCOPE=extern\ __attribute__\(\(__visibility__\(\"hidden\"\)\)\) -DMAC_OSX_TCL=1 -DHAVE_COREFOUNDATION=1 -DHAVE_CAST_TO_UNION=1 -DTCL_SHLIB_EXT=\".dylib\" -DTCL_TOMMATH=1 -DMP_PREC=4 -DTCL_WIDE_INT_IS_LONG=1 -DHAVE_GETCWD=1 -DHAVE_OPENDIR=1 -DHAVE_STRTOL=1 -DHAVE_WAITPID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETPWUID_R_5=1 -DHAVE_GETPWUID_R=1 -DHAVE_GETPWNAM_R_5=1 -DHAVE_GETPWNAM_R=1 -DHAVE_GETGRGID_R_5=1 -DHAVE_GETGRGID_R=1 -DHAVE_GETGRNAM_R_5=1 -DHAVE_GETGRNAM_R=1 -DHAVE_MTSAFE_GETHOSTBYNAME=1 -DHAVE_MTSAFE_GETHOSTBYADDR=1 -DUSE_TERMIOS=1 -DHAVE_SYS_TIME_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_GMTIME_R=1 -DHAVE_LOCALTIME_R=1 -DHAVE_MKTIME=1 -DHAVE_TM_GMTOFF=1 -DHAVE_TIMEZONE_VAR=1 -DHAVE_STRUCT_STAT_ST_BLOCKS=1 -DHAVE_STRUCT_STAT_ST_BLKSIZE=1 -DHAVE_BLKCNT_T=1 -DHAVE_INTPTR_T=1 -DHAVE_UINTPTR_T=1 -DHAVE_SIGNED_CHAR=1 -DHAVE_LANGINFO=1 -DHAVE_CHFLAGS=1 -DHAVE_GETATTRLIST=1 -DHAVE_COPYFILE_H=1 -DHAVE_COPYFILE=1 -DHAVE_LIBKERN_OSATOMIC_H=1 -DHAVE_OSSPINLOCKLOCK=1 -DHAVE_PTHREAD_ATFORK=1 -DUSE_VFORK=1 -DTCL_DEFAULT_ENCODING=\"utf-8\" -DTCL_LOAD_FROM_MEMORY=1 -DTCL_WIDE_CLICKS=1 -DHAVE_AVAILABILITYMACROS_H=1 -DHAVE_WEAK_IMPORT=1 -D_DARWIN_C_SOURCE=1 -DHAVE_FTS=1 -DHAVE_SYS_IOCTL_H=1 -DHAVE_SYS_FILIO_H=1 -DTCL_UNLOAD_DLLS=1 -DHAVE_CPUID=1 TCL_BIN_DIR = /usr/local/src/tcl8.5.13/unix TCL_SRC_DIR = /usr/local/src/tcl8.5.13 # This is necessary for packages that use private Tcl headers #TCL_TOP_DIR_NATIVE = @TCL_TOP_DIR_NATIVE@ # Not used, but retained for reference of what libs Tcl required TCL_LIBS = ${DL_LIBS} ${LIBS} ${MATH_LIBS} #======================================================================== # TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our # package without installing. The other environment variables allow us # to test against an uninstalled Tcl. Add special env vars that you # require for testing here (like TCLX_LIBRARY). #======================================================================== EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR) TCLSH_ENV = TCL_LIBRARY=`echo $(TCL_SRC_DIR)/library` \ DYLD_LIBRARY_PATH="$(EXTRA_PATH):$(DYLD_LIBRARY_PATH)" \ PATH="$(EXTRA_PATH):$(PATH)" \ TCLLIBPATH="$(top_builddir)" TCLSH_PROG = /usr/local/src/tcl8.5.13/unix/tclsh TCLSH = $(TCLSH_ENV) $(TCLSH_PROG) SHARED_BUILD = 1 INCLUDES = -I/Users/neumann/src/nsf2.0b4/generic -I./generic -I"/usr/local/src/tcl8.5.13/generic" EXTRA_CFLAGS = # TCL_DEFS is not strictly need here, but if you remove it, then you # must make sure that configure.in checks for the necessary components # that your library may use. TCL_DEFS can actually be a problem if # you do not compile with a similar machine setup as the Tcl core was # compiled with. #DEFS = $(TCL_DEFS) -DPACKAGE_NAME=\"xotclexpat\" -DPACKAGE_TARNAME=\"xotclexpat\" -DPACKAGE_VERSION=\"0.9\" -DPACKAGE_STRING=\"xotclexpat\ 0.9\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DNO_VALUES_H=1 -DHAVE_LIMITS_H=1 -DHAVE_SYS_PARAM_H=1 -DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 -D_THREAD_SAFE=1 -DTCL_THREADS=1 -DMODULE_SCOPE=extern\ __attribute__\(\(__visibility__\(\"hidden\"\)\)\) -DTCL_WIDE_INT_IS_LONG=1 -DUSE_TCL_STUBS=1 $(EXTRA_CFLAGS) DEFS = -DPACKAGE_NAME=\"xotclexpat\" -DPACKAGE_TARNAME=\"xotclexpat\" -DPACKAGE_VERSION=\"0.9\" -DPACKAGE_STRING=\"xotclexpat\ 0.9\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DNO_VALUES_H=1 -DHAVE_LIMITS_H=1 -DHAVE_SYS_PARAM_H=1 -DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 -D_THREAD_SAFE=1 -DTCL_THREADS=1 -DMODULE_SCOPE=extern\ __attribute__\(\(__visibility__\(\"hidden\"\)\)\) -DTCL_WIDE_INT_IS_LONG=1 -DUSE_TCL_STUBS=1 $(EXTRA_CFLAGS) CONFIG_CLEAN_FILES = Makefile CPPFLAGS = LIBS = -L/Users/neumann/src/nsf2.0b4 -lxotclstub1.6.8 AR = ar CFLAGS = -pipe ${CFLAGS_DEFAULT} ${CFLAGS_WARNING} ${SHLIB_CFLAGS} COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) #======================================================================== # Start of user-definable TARGETS section #======================================================================== #======================================================================== # TEA TARGETS. Please note that the "libraries:" target refers to platform # independent files, and the "binaries:" target inclues executable programs and # platform-dependent libraries. Modify these targets so that they install # the various pieces of your package. The make and install rules # for the BINARIES that you specified above have already been done. #======================================================================== all: binaries libraries doc #======================================================================== # The binaries target builds executable programs, Windows .dll's, unix # shared/static libraries, and any other platform-dependent files. # The list of targets to build for "binaries:" is specified at the top # of the Makefile, in the "BINARIES" variable. #======================================================================== binaries: $(BINARIES) pkgIndex.tcl libraries: doc: @echo "If you have documentation to create, place the commands to" @echo "build the docs in the 'doc:' target. For example:" @echo " xml2nroff sample.xml > sample.n" @echo " xml2html sample.xml > sample.html" install: all install-binaries install-libraries install-doc install-binaries: binaries install-lib-binaries install-bin-binaries if test "x$(SHARED_BUILD)" = "x1"; then \ $(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir); \ fi #======================================================================== # This rule installs platform-independent files, such as header files. #======================================================================== install-libraries: libraries @mkdir -p $(DESTDIR)$(includedir) @echo "Installing header files in $(DESTDIR)$(includedir)" @if test -n "$(PKG_HEADERS)" ; then \ for i in "$(PKG_HEADERS)" ; do \ echo "Installing $(srcdir)/$$i" ; \ $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir) ; \ done; \ fi #======================================================================== # Install documentation. Unix manpages should go in the $(mandir) # directory. #======================================================================== install-doc: doc #install-doc: doc # @mkdir -p $(DESTDIR)$(mandir)/mann # @echo "Installing documentation in $(DESTDIR)$(mandir)" # @for i in $(srcdir)/doc/*.n; do \ # echo "Installing $$i"; \ # rm -f $(DESTDIR)$(mandir)/mann/`basename $$i`; \ # $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \ # done test: binaries libraries $(TCLSH) `echo $(srcdir)/tests/all.tcl` $(TESTFLAGS) shell: binaries libraries @$(TCLSH) $(SCRIPT) gdb: $(TCLSH_ENV) gdb $(TCLSH_PROG) $(SCRIPT) depend: #======================================================================== # $(PKG_LIB_FILE) should be listed as part of the BINARIES variable # mentioned above. That will ensure that this target is built when you # run "make binaries". # # The $(PKG_OBJECTS) objects are created and linked into the final # library. In most cases these object files will correspond to the # source files above. #======================================================================== $(PKG_LIB_FILE): $(PKG_OBJECTS) -rm -f $(PKG_LIB_FILE) ${MAKE_LIB} $(RANLIB) $(PKG_LIB_FILE) $(PKG_STUB_LIB_FILE): $(PKG_STUB_OBJECTS) -rm -f $(PKG_STUB_LIB_FILE) ${MAKE_STUB_LIB} $(RANLIB_STUB) $(PKG_STUB_LIB_FILE) #======================================================================== # We need to enumerate the list of .c to .o lines here. # # In the following lines, $(srcdir) refers to the toplevel directory # containing your extension. If your sources are in a subdirectory, # you will have to modify the paths to reflect this: # # sample.$(OBJEXT): $(srcdir)/generic/sample.c # $(COMPILE) -c `echo $(srcdir)/generic/sample.c` -o $@ # # Setting the VPATH variable to a list of paths will cause the makefile # to look into these paths when resolving .c to .obj dependencies. # As necessary, add $(srcdir):$(srcdir)/compat:.... #======================================================================== VPATH = $(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win .c.o: $(COMPILE) -c `echo $<` -o $@ #======================================================================== # Create the pkgIndex.tcl file. # It is usually easiest to let Tcl do this for you with pkg_mkIndex, but # you may find that you need to customize the package. If so, either # modify the -hand version, or create a pkgIndex.tcl.in file and have # the configure script output the pkgIndex.tcl by editing configure.in. #======================================================================== pkgIndex.tcl: ( echo pkg_mkIndex . $(PKG_LIB_FILE) \; exit; ) | $(TCLSH) pkgIndex.tcl-hand: (echo 'package ifneeded xotcl::xml::expat $(PACKAGE_VERSION) \ [list load [file join $$dir $(PKG_LIB_FILE)]]'\ ) > pkgIndex.tcl #======================================================================== # Distribution creation # You may need to tweak this target to make it work correctly. #======================================================================== #COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar COMPRESS = gtar zcvf $(PKG_DIR).tar.gz $(PKG_DIR) DIST_ROOT = /tmp/dist DIST_DIR = $(DIST_ROOT)/$(PKG_DIR) dist-clean: rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.* dist: dist-clean mkdir -p $(DIST_DIR) cp -p $(srcdir)/ChangeLog $(srcdir)/README* $(srcdir)/license* \ $(srcdir)/aclocal.m4 $(srcdir)/configure $(srcdir)/*.in \ $(DIST_DIR)/ chmod 664 $(DIST_DIR)/Makefile.in $(DIST_DIR)/aclocal.m4 chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.in cp -p $(srcdir)/*.[ch] $(DIST_DIR)/ mkdir $(DIST_DIR)/tclconfig cp $(srcdir)/tclconfig/install-sh $(srcdir)/tclconfig/tcl.m4 \ $(DIST_DIR)/tclconfig/ chmod 664 $(DIST_DIR)/tclconfig/tcl.m4 chmod +x $(DIST_DIR)/tclconfig/install-sh list='demos doc generic library mac tests unix win'; \ for p in $$list; do \ if test -d $(srcdir)/$$p ; then \ mkdir $(DIST_DIR)/$$p; \ cp -p $(srcdir)/$$p/*.* $(DIST_DIR)/$$p/; \ fi; \ done (cd $(DIST_ROOT); $(COMPRESS);) #======================================================================== # End of user-definable section #======================================================================== #======================================================================== # Don't modify the file to clean here. Instead, set the "CLEANFILES" # variable in configure.in #======================================================================== clean: -test -z "$(BINARIES)" || rm -f $(BINARIES) -rm -f *.$(OBJEXT) core *.core -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean: clean -rm -f *.tab.c -rm -f $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log config.status #======================================================================== # Install binary object libraries. On Windows this includes both .dll and # .lib files. Because the .lib files are not explicitly listed anywhere, # we need to deduce their existence from the .dll file of the same name. # Library files go into the lib directory. # In addition, this will generate the pkgIndex.tcl # file in the install location (assuming it can find a usable tclsh shell) # # You should not have to modify this target. #======================================================================== install-lib-binaries: @mkdir -p $(DESTDIR)$(pkglibdir) @list='$(lib_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p; \ stub=`echo $$p|sed -e "s/.*\(stub\).*/\1/"`; \ if test "x$$stub" = "xstub"; then \ echo " $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p"; \ $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p; \ else \ echo " $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p"; \ $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p; \ fi; \ ext=`echo $$p|sed -e "s/.*\.//"`; \ if test "x$$ext" = "xdll"; then \ lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \ if test -f $$lib; then \ echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \ $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib; \ fi; \ fi; \ fi; \ done @list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ if test -f $(srcdir)/$$p; then \ destp=`basename $$p`; \ echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \ fi; \ done #======================================================================== # Install binary executables (e.g. .exe files and dependent .dll files) # This is for files that must go in the bin directory (located next to # wish and tclsh), like dependent .dll files on Windows. # # You should not have to modify this target, except to define bin_BINARIES # above if necessary. #======================================================================== install-bin-binaries: @mkdir -p $(DESTDIR)$(bindir) @list='$(bin_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \ fi; \ done .SUFFIXES: .c .$(OBJEXT) Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status uninstall-binaries: list='$(lib_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ p=`basename $$p`; \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(bin_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(bindir)/$$p; \ done .PHONY: all binaries clean depend distclean doc install libraries test # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ./nsf2.4.0/library/xotcl/tests/slottest.xotcl000644 000766 000024 00000050767 13717246170 022112 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require XOTcl 2.0; namespace import -force ::xotcl::* package require nx::test nx::test configure -count 1000 # what's new: # - slots instances are manager objects for slot values # - generalization of slots to have different kind of domains and managers # - slots for objects and classes (slot parameter 'per-object' true|false, # when to used on a class object) # - works for mixins/filters/class/superclass (e.g. ... superclass add ::M) # - defaultcmd and valuecmd # defaultcmd: is executed when the instance variable is read the first time # valuecmd: is executed whenever the instance variable is read # (implemented via trace; alternate approach for similar behavior # is to define per-object procs for get/assign, see e.g. slots for # class and superclass; slots require methods to be invoked, # not var references; # otoh, trace are somewhat more fragile and harder to debug) # default, defaultcmd and valuecmd are to be used mutually exclusively # - valuechangedcmd: executed after the change of an instance variable, # can be used e.g. for validation # # -gustaf neumann 21.Jan. 2006 package require nx::serializer ####################################################### set ::hu 0 proc T1 {var sub op} {c1 set $var t1} proc T2 {var sub op} {c1 set $var t2} Class C -slots { #Attribute create x -defaultcmd {set x 1} #Attribute create y -defaultcmd {incr ::hu} #Attribute create z -defaultcmd {my trace add variable z read T1} Attribute create x -trace default x object method value=default {obj property} { return 1 } Attribute create y -trace default y object method value=default {obj property} { incr ::hu } Attribute create z -trace default z object method value=default {obj property} { $obj trace add variable z read T1 } } C create c1 ? {c1 info vars x} "" ? {c1 x} "1" ? {c1 info vars x} "x" ? {c1 info vars y} "" ? {c1 y} 1 ? {c1 set x} 1 ? {set ::hu} 1 proc ?? {cmd expected {msg ""}} { #puts "??? $cmd" set r [uplevel $cmd] if {$msg eq ""} {set msg $cmd} if {$r ne $expected} { puts stderr "ERROR $msg returned '$r' ne '$expected'" error "FAILED $msg returned '$r' ne '$expected'" } else { puts stderr "OK $msg" } } Class D -slots { # Attribute create x -defaultcmd {set x 2} # Attribute create z -defaultcmd {my trace add variable z read T2} Attribute create x -trace default x object method value=default {obj property} { return 2 } Attribute create z -trace default z object method value=default {obj property} { $obj trace add variable z read T2 } ?? self ::D ?? {namespace current} ::D::slot } -superclass C D create c1 ? {c1 set x} 2 ? {c1 z} "" ? {c1 z} t2 ? {c1 y} 2 ? {set ::hu} 2 ####################################################### # # a small helper Object instproc slots cmds { if {![my isobject [self]::slot]} {Object create [self]::slot} namespace eval [self]::slot $cmds } ###################### # system slots ###################### Class M Class O -mixin M ? {O mixin} ::M ? {catch {Object o -mixin check1 M}} 1 ? {O mixin} ::M Class M2 O mixin add M2 ? {O mixin} {::M2 ::M} O mixin M2 ? {O mixin} ::M2 O mixin "" ? {O mixin} "" #O mixin set M ;# not sure, whether we should keep set here, or use assign or some better term O mixin assign M ;# new name ? {O mixin} ::M ? {O mixin ""} "" # with slots like class etc. we have to option to # a) rename the original command like in the following # b) provide a no-op value, such that we define only meta-data in the slot # c) define a low-level tcl command like setrelation (or extend it) to handle the setter # "class" is not multivalued, therefore, we should not add (or remove) add/delete # from the set of subcommands... ? {::nx::RelationSlot info class} "::nx::MetaSlot" O o1 ? {o1 class} "::O" o1 class Object ? {o1 class} "::xotcl::Object" ? {o1 __object_configureparameter} "-mixin:mixinreg,alias,0..n -filter:filterreg,alias,0..n -class:class,alias args:alias,method=residualargs,args" ? {Object __object_configureparameter} "-instfilter:filterreg,alias,0..n -superclass:alias,0..n -instmixin:mixinreg,alias,0..n {-__default_metaclass ::xotcl::Class} {-__default_superclass ::xotcl::Object} -mixin:mixinreg,alias,0..n -filter:filterreg,alias,0..n -class:class,alias args:alias,method=residualargs,args" ? {o1 class add M} {class: expected a class but got "M ::xotcl::Object"} ? {O superclass} "::xotcl::Object" Class O2 -superclass O #? {O2 superclass O} "superclass 1" ? {O superclass} "::xotcl::Object" ::nx::ObjectParameterSlot public method slot {object name property} { switch $property { self {return [self]} domain {return [my domain]} } } #? {O superclass slot self} "::xotcl::Class::slot::superclass" ? {O ::nsf::methods::object::info::lookupslots superclass} "::xotcl::Class::slot::superclass" ? {::xotcl::Class::slot::superclass cget -domain} "::xotcl::Class" ? {O2 superclass} "::O" O2 superclass add M ? {O2 superclass} "::M ::O" O2 superclass delete ::O ? {O2 superclass} "::M" # # test "... info default ..." and "... info instdefault ..." # ::nx::test case info-default { ::xotcl::Class create ::Test ::Test proc m0 {-id:required {-flag:boolean true} -switch:switch x {y 1}} {return 0} ::Test instproc m1 {-id:required {-flag:boolean true} -switch:switch x {y 1}} {return 0} ? {::Test info default m0 y default0} 1 ? {info exists default0} 1 ? {::Test info default m0 x default1} 0 unset -nocomplain default0 default1 ? {::Test info instdefault m1 y default0} 1 ? {info exists default0} 1 ? {::Test info instdefault m1 x default1} 0 } # # The main difference between an Attribute and a Role is that it # references some other objects # ::xotcl::MetaSlot create Role -superclass Attribute -parameter {references} ::nx::test case info-slots-heritage { ::xotcl::Class create C -parameter {c1 c2} ::xotcl::Class create D -superclass C -parameter {c2 c3} ? {C info heritage} "::xotcl::Object" ? {D info heritage} "::C ::xotcl::Object" # xotcl info heritage should not see the mixins C instmixin [::xotcl::Class create M] ? {C info superclass -closure} "::xotcl::Object" ? {D info superclass -closure} "::C ::xotcl::Object" ? {D info heritage} "::C ::xotcl::Object" ? {C info slots} "::C::slot::c1 ::C::slot::c2" ? {D info slots} "::D::slot::c2 ::D::slot::c3" ? {D info slots -closure -source application} "::D::slot::c2 ::D::slot::c3 ::C::slot::c1" } ###################### # application classes ###################### Class Person -slots { Attribute create name Attribute create age -default 0 } Class Article -slots { Attribute create title Attribute create date } Class publishes -slots { Role create written_by -references Person -multiplicity 0..n Role create has_published -references Paper -multiplicity 0..n } Class Project -slots { Attribute create name Role create manager -references Person Role create member -references Person -multiplicity 0..n } puts [Person serialize] Person::slot::name configure -default "gustaf" ? {Person::slot::name cget -default} gustaf Person p1 -name neophytos ? {p1 name} neophytos ? {p1 age} 0 p1 age 123 ? {p1 age} 123 Object o1 o1 set i 0 ::nsf::method::alias o1 Incr -frame object ::incr ? {o1 incr i} 1 "method incr" ? {o1 Incr i} 1002 "aliased tcl incr" ? {o1 incr i} 2003 "method incr" ? {o1 Incr i} 3004 "aliased tcl incr" ::nsf::method::alias ::xotcl::Object Set -frame object ::set ? {o1 set i 1} 1 "method set" ? {o1 set i} 1 "method set" ? {o1 Set i 1} 1 "aliased tcl set" ? {o1 Set i} 1 "aliased tcl set" ::nsf::method::alias o1 Set -frame object ::set ? {o1 Set i 1} 1 "aliased object tcl set" ? {o1 Set i} 1 "aliased object tcl set" ::xotcl::Object instforward SSet -earlybinding -objscope ::set ? {o1 SSet i 1} 1 "forward earlybinding tcl set" ? {o1 SSet i} 1 "forward earlybinding tcl set" ? {::xotcl::Object info instforward -definition SSet} "-earlybinding -objscope ::set" o1 set z 100 #o1 forward z o1 [list %argclindex [list set set]] %proc #o1 proc get name {my set $name} o1 forward get -earlybinding ::nsf::var::set %self %1 ? {o1 info forward} get ? {o1 get z 101} 101 ? {o1 get z} "101" ? {o1 get z} 101 "get value via new parametercmd get" ? {o1 get z 124} 124 "set value via new parametercmd get" o1 forward zz -earlybinding ::nsf::var::set %self %proc ? {o1 zz 123} 123 ? {o1 zz} 123 ? {o1 zz} 123 "parametercmd forward earlybinding setinstvar" ? {o1 zz 124} 124 "parametercmd forward earlybinding setinstvar" o1 forward z2 -earlybinding -objscope ::set %proc ? {o1 z2 111} 111 "parametercmd forward earlybinding tcl set" ? {o1 z2} 111 "parametercmd forward earlybinding tcl set" o1 forward z3 -objscope ::set %proc ? {o1 z3 111} 111 "parametercmd forward tcl set" ? {o1 z3} 111 "parametercmd forward tcl set" o1 set y 11 o1 parametercmd y ? {o1 y} 11 "parametercmd" ? {o1 y 1} 1 "parametercmd" #Class C -parameter {a {b 10} {c "Hello World"}} #C copy V #puts [C serialize] #puts [V serialize] #C destroy #V v1 #puts [v1 b] # ::xotcl::Object instproc param arglist { # foreach arg $arglist { # puts "arg=$arg" # set l [llength $arg] # set name [lindex $arg 0] # if {![my isobject [self]::slot]} {::xotcl::Object create [self]::slot} # if {$l == 1} { # Attribute create [self]::slot::$name # } elseif {$l == 2} { # Attribute create [self]::slot::$name -default [lindex $arg 1] # } else { # set paramstring [string range $arg [expr {[string length $name]+1}] end] # #puts stderr "remaining arg = '$paramstring'" # if {[string match {[$\[]*} $paramstring]} { # #puts stderr "match, $cl set __defaults($name) $paramstring" # Attribute create [self]::slot::$name -default $paramstring # continue # } # } # } # } # maybe work directly on ::xotcl::Attribute would be nicer, when # ::xotcl::Attribute would be true alias for ::nx::VariableSlot ... #::nx::VariableSlot mixin delete ::nx::VariableSlot::Optimizer Class C1 -parameter {a {b 10} {c "Hello World"}} C1 c1 -a 1 ? {c1 a} 1 ? {c1 b} 10 ? {c1 c} "Hello World" ##### is short form of Class C2 -slots { Attribute create a Attribute create b -default 10 Attribute create c -default "Hello World" } C2 c2 -a 1 ? {c2 procsearch a} "::C2 instparametercmd a" ? {c2 a} 1 ? {c2 b} 10 ? {c2 c} "Hello World" ? {c2 a} 1 "new indirect parametercmd" ? {c2 a 1} 1 "new indirect parametercmd" #::nx::VariableSlot mixin add ::nx::VariableSlot::Optimizer Class C3 -slots { Attribute create a Attribute create b -default 10 Attribute create c -default "Hello World" } C3 c3 -a 1 ? {c3 procsearch a} "::C3 instparametercmd a" ? {c3 a} 1 ? {c3 b} 10 ? {c3 c} "Hello World" ? {c3 a} 1 "new indirect parametercmd optimized" ? {c3 a 1} 1 "new indirect parametercmd optimized" ####### nasty names Class create D -slots { Attribute create create -default 1 } D d1 ####### gargash 2 Class create A -parameter {{foo 1}} # or Class create A -slots { Attribute create foo -default 1 } A create a1 -foo 234 ;# calls default foo setter A instproc f1 {} {puts hu} A instforward f2 puts hu A create a0 #a0 f1 a0 proc f3 {} {puts hu} a0 forward f4 puts hu ? {a0 procsearch f1} "::A instproc f1" ? {a0 procsearch f2} "::A instforward f2" ? {a0 procsearch f3} "::a0 proc f3" ? {a0 procsearch f4} "::a0 forward f4" ? {a0 procsearch set} "::xotcl::Object instcmd set" ? {A::slot::foo info lookup method value=set} "::nsf::classes::xotcl::Attribute::value=set" # redefine setter for foo of class A #A slot foo method assign {domain var val} ... A::slot::foo public object method assign {domain var val} { # Do something with [self] that isn't valid before init #puts setter-[self proc] $domain set $var $val } a1 foo ;# calls default foo getter a1 foo 123 ;# calls overridden foosetter ? {a1 foo} 123 #puts [A serialize] ################### nx::test case req-param { ::xotcl::Class create C -parameter {y:required x:required} C instproc init args {set ::_ $args} set ::_ "" ? {C create c2 -y 1 -x} {value for parameter '-x' expected} ? {set ::_} "" ? {::nsf::is object c2} 0 ? {C create c3 -y 1 -x 0} "::c3" ? {set ::_} "" ? {c3 x} "0" } ################### # Application Slots # nx::test case app-slots Class Person -slots { Attribute create name Attribute create age -default 0 Attribute create projects -default {} -multiplicity 0..n -incremental true } Person p1 -name "Gustaf" ? {p1 name} Gustaf ? {p1 age} 0 ? {p1 projects} {} Class Project -slots { Attribute create name Attribute create description } Project project1 -name XOTcl -description "A highly flexible OO scripting language" p1 projects add ::project1 ? {p1 projects} ::project1 #p1 projects add some-other-value #? {p1 projects} "some-other-value ::project1" ::nx::ObjectParameterSlot method check { {-keep_old_value:boolean true} value predicate type obj var } { puts "+++ checking $value with $predicate ==> [expr $predicate]" if {![expr $predicate]} { if {[$obj exists __oldvalue($var)]} { $obj set $var [$obj set __oldvalue($var)] } else { $obj unset $var } error "$value is not of type $type" } if {$keep_old_value} {$obj set __oldvalue($var) $value} } ::nx::ObjectParameterSlot method checkall {values predicate type obj var} { foreach value $values { my check -keep_old_value false $value $predicate $type $obj $var } $obj set __oldvalue($var) $value } Person slots { Attribute create projects -default "" -multiplicity 0..n -incremental true -type ::Project Attribute create salary -type integer } Person p2 -name "Gustaf" p2 projects add ::project1 ? {p2 projects add ::o1} {expected object of type ::Project but got "::o1" for parameter "value"} p2 salary 100 ? {catch {p2 salary 100.9}} 1 ? {p2 salary} 100 p2 append salary 9 ? {p2 salary} 1009 # todo currently not checked #? {catch {p2 append salary b}} 1 ? {p2 salary} 1009 Person slots { Attribute create sex -type "sex" -convert true -proc type=sex {name value} { #puts stderr "[self] slot specific converter" switch -glob $value { m* {return m} f* {return f} default {error "expected sex but got $value"} } } } Person p3 -sex male ? {p3 sex} m Person method foo {s:sex,slot=::Person::slot::sex,convert} {return $s} ? {p3 foo male} "m" ? {p3 sex male} m ####################################################### # defaultcmd via slots ####################################################### nx::test case defaultcmd set ::hu 0 Class C -slots { # Attribute create x -defaultcmd {incr ::hu; set x 101} Attribute create x -trace default x object method value=default {obj property} { incr ::hu; return 101 } } C c1 ? {c1 info vars} "__initcmd" ? {c1 set x} 101 ? {c1 info vars} "x __initcmd" ? {set ::hu 1} 1 ####################################################### # nested contains ####################################################### nx::test case nested-contains Class Point -parameter {{x 100} {y 300}} Class Rectangle -parameter {color} Rectangle r0 -color pink -contains { Rectangle r1 -color red -contains { Point x1 -x 1 -y 2 Point x2 -x 1 -y 2 } Rectangle r2 -color green -contains { Point x1 Point x2 } } #? {r0 color} pink #? {r0 r1 color} red #? {r0 r1 x1 x} 1 #? {r0 r1 x2 y} 2 #? {r0 r2 color} green ? {r0 color} pink ? {r0::r1 color} red ? {r0::r1::x1 x} 1 ? {r0::r1::x2 y} 2 ? {r0::r2 color} green #puts [r0 serialize] ####################################################### # assign via slots ####################################################### nx::test case assign-via-slots Class create A -slots { Attribute create foo -default 1 -proc value=set {domain var value} { if {$value < 0 || $value > 99} { error "$value is not in the range of 0 .. 99" } $domain set $var $value } } A create a1 ? {a1 foo 10} 10 ? {a1 foo 20} 20 ? {a1 foo} 20 ? {a1 foo -1} "-1 is not in the range of 0 .. 99" ? {catch {a1 foo -1}} 1 ? {a1 foo 100} "100 is not in the range of 0 .. 99" ? {a1 foo 99} 99 set x [Object new -set x 1 -contains { Object new -set x 1.1 Object new -set x 1.2 -contains { Object new -set x 1.2.1 Object new -set x 1.2.2 -contains { Object new -set x 1.2.2.1 } Object new -set x 1.2.3 } Object new -set x 1.3 }] ? {llength [$x info children]} 3 ? {llength [[lindex [lsort [$x info children]] 0] info children]} 0 ? {llength [[lindex [lsort [$x info children]] 1] info children]} 3 ? {llength [[lindex [lsort [$x info children]] 2] info children]} 0 # # test case (bug) posted by Neil Hampton # Class Fred -slots { #Attribute create attr1 -defaultcmd { set _ 4 } Attribute create attr1 -trace default attr1 object method value=default {obj property} { return 4 } } ? {Fred create x} ::x ? {x attr1 4} 4 x move y ? {y attr1} 4 ::nx::test case slots-compat # # Some tests covering the backward compatibility of NX/XOTcl2 hybrid # slots to the XOTcl1 slot API (as extracted from the XOTcl language # reference) # # # 1) old-style Attribute creation # Class Window -slots { Attribute scrollbar; # old style Attribute create title; # new style } ? {lsort [Window info slots]} "::Window::slot::scrollbar ::Window::slot::title" # # 2) Dropped/missing slot attributes: multivalued # Class Person -slots { Attribute name Attribute salary -default 0 Attribute projects -default {} -multivalued true } ? {lsort [Person info slots]} "::Person::slot::name ::Person::slot::projects ::Person::slot::salary" ? {Person::slot::name multivalued get} 0 ? {Person::slot::salary multivalued get} 0 ? {Person::slot::projects multivalued get} 1 Person p2 -name "John Doe" ? {p2 name} "John Doe" ? {p2 salary} "0" ? {p2 projects} [list] Project compatPrj -name XOTclCompat p2 projects add ::compatPrj p2 projects add some-other-value ? {lsort [p2 projects]} "::compatPrj some-other-value" p2 projects delete some-other-value ? {lsort [p2 projects]} "::compatPrj" ? {catch {p2 name add BOOM!}} 1 ? {p2 name} "John Doe" # # 3) -proc inline statements upon Attribute creation # (as found in the tutorial) # Class create AA -slots { Attribute foo -default 1 -proc value=set {domain var value} { if {$value < 0 || $value > 99} { error "$value is not in the range of 0 .. 99" } $domain set $var $value } } AA create aa1 ? {aa1 foo 10} 10 ? {aa1 foo} 10 ? {catch {aa1 foo -1}} 1 nx::test case nx-serialize-debug-deprecated { ::xotcl::Object create o o proc ofoo {} {return 1} o proc obar {} {return 1} ? {::nsf::method::property o ofoo deprecated} 0 ? {::nsf::method::property o ofoo debug} 0 ? {::nsf::method::property o obar deprecated} 0 ? {::nsf::method::property o obar debug} 0 ::nsf::method::property o ofoo deprecated 1 ::nsf::method::property o obar debug 1 ? {::nsf::method::property o ofoo deprecated} 1 ? {::nsf::method::property o ofoo debug} 0 ? {::nsf::method::property o obar deprecated} 0 ? {::nsf::method::property o obar debug} 1 set script [o serialize] o destroy ? {::nsf::object::exists ::o} 0 eval $script ? {::nsf::method::property o ofoo deprecated} 1 ? {::nsf::method::property o ofoo debug} 0 ? {::nsf::method::property o obar deprecated} 0 ? {::nsf::method::property o obar debug} 1 } nx::test case nx-returns+serialize { ::xotcl::Class create Context ? {Context instproc default_form_loader {arg} -returns integer { return $arg }} "::nsf::classes::Context::default_form_loader" Context create c ? {c default_form_loader 0} 0 ? {c default_form_loader ""} {expected integer but got "" as return value} set ::string [Context serialize] c destroy Context destroy ? {eval $::string} "::nsf::classes::Context::default_form_loader" Context create c ? {c default_form_loader 0} 0 ? {c default_form_loader ""} {expected integer but got "" as return value} } nx::test case nx-serialize-param-overload { # # Create slot via "parameter" # ::xotcl::Class create C -parameter p # # Create a method overloading slot accessor for "p". # C instproc p args {return 1} C create c1 ? {c1 p} 1 set ::stringC [C serialize] ? {expr {[string length $::stringC] > 100}} 1 c1 destroy C destroy ? {catch {eval $::stringC}} 0 C create c1 ? {c1 p} 1 # # Create slot directly via ::xotcl::Attribute and not via # "parameter" and overload its accessor with an instproc. # ::xotcl::Class create Person -slots { ::xotcl::Attribute salary -default 0 } Person instproc salary args {return 100} Person create p1 ? {p1 salary} 100 set ::stringP [Person serialize] p1 destroy Person destroy ? {catch {eval $::stringP}} 0 Person create p1 ? {p1 salary} 100 } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/xotcl/tests/speedtest.xotcl000644 000766 000024 00000047661 13617007060 022220 0ustar00neumannstaff000000 000000 # -*- Tcl -*- #memory trace on package prefer latest package require XOTcl 2.0; namespace import ::xotcl::* package require nx::test nx::test new -msg {test multiple dashed args o0} \ -cmd {Object create o0 [list -set a -a1] [list -set b "-b 1 -y 2"]} \ -expected ::o0 \ -post {o0 destroy} nx::test new -msg {test multiple dashed args o1} \ -cmd {Object create o1 -proc foo args {return 1} [list -set a -a1] [list -set b "-b 1 -y 2"]} \ -expected ::o1 \ -post {o1} nx::test new -msg {test multiple dashed args o2} \ -cmd {Object create o2 {-proc foo args {return 1}} {-set -a -t1} {-set b "-b 1 -y 2"}} \ -expected ::o2 \ -post {o2 destroy} nx::test new -msg {test multiple dashed args o3} \ -cmd {Object create o3 -proc foo args {return 1} {-set -a -t1} {-set b "-b 1 -y 2"}} \ -expected ::o3 \ -post {o3 destroy} nx::test configure -count 1000 @ @File {description { Regression and speed test for various ways to achieve a similar behavior. } } set ccount 20 #set ocount 1014 #set ocount [expr {$ccount + 206}] #set ocount [expr {$ccount + 15}] set ocount [expr {$ccount + 6}] Class M1; Class M2 Class C -parameter {{p 99} {q 98} r} C instproc f args {next} C instproc init args { my instvar n v #for {set i 1} {$i<1000} {incr i} {set n($i) 1} #for {set i 1} {$i<1000} {incr i} {Object [self]::$i} for {set i 0} {$i<$::ccount} {incr i} {set n($i) 1} for {set i 0} {$i<$::ccount} {incr i} {Object [self]::$i} set v 1 } C instproc mixinappend m { my mixin [concat [my info mixin] $m] my info mixin } C instproc ma m { set mix [my info mixin] my mixin [lappend mix $m] my info mixin } C instproc existsViaInstvar {} { my instvar v info exists v } C instproc existsViaMyInstvar {} { my instvar v info exists v } C instproc existsViaExistsMethod {} { [self] exists v } C instproc existsViaMyExistsMethod {} { my exists v } C instproc existsViaDotExistsMethod {} { :exists v } C instproc existsViaResolver {} { info exists :v } C instproc notExistsViaInstvar {} { my instvar xxx info exists xxx } C instproc notExistsViaExistsMethod {} { my exists xxx } C instproc existsAndReturnValue1 {} { if {[my exists v]} { my set v } } C instproc existsAndReturnValue3 {} { if {[my exists v]} { set x [my set v] } } C instproc setViaInstvar x { my instvar v set v $x } C instproc setViaSetMethod x { my set v $x } C instproc setViaParameter x { my r $x } C instproc testAndSetViaInstvar x { my instvar v if {[info exists v]} {set v $x} } C instproc testAndSetViaSetMethod x { if {[my info vars v] ne ""} {my set v $x} } C instproc readViaInstvar {} { my instvar p set p } C instproc readViaSetMethod {} { my set p } C instproc readViaSetMethodNoSelf {} { ::c set p } C instproc readViaParameter {} { my p } C instproc readTwiceViaInstvar {} { my instvar p set p set p } C instproc readTwiceViaSetMethod {} { my set p my set p } C instproc readTwiceViaSetMethodNoSelf {} { ::c set p ::c set p } C instproc readTwiceViaParameter {} { my p my p } C instproc readTwovarsViaInstvar {} { my instvar p q set p set q } C instproc readTwovarsViaSetMethod {} { my set p my set q } C instproc readTwovarsViaSetMethodNoSelf {} { ::c set p ::c set q } C instproc readTwovarsViaParameter {} { my p my q } C instproc instvarAlias {} { my instvar {a b} set b 1 my exists a } C instproc explicitReturn {} { return [set i 1] } C instproc implicitReturn {} { set i 1 } C instproc explicitReturnFromVar {} { set i 1 return $i } C instproc implicitReturnFromVar {} { set i 1 set i } C instproc childNodeNamespace {} { Object [self]::13 } C instproc childNodeNamespaceCreate {} { Object create [self]::13 } C instproc createVolatileRc {} { Object new -volatile return 2 } C c Class D -superclass C D instproc init args {} D d #nx::test new -cmd {llength [c info children]} -count 1 -expected 999 #nx::test new -cmd {set x [llength [c info children]]} -count 1 -expected 999 nx::test new -cmd {llength [c info children]} -count 1 -expected $ccount nx::test new -cmd {set x [llength [c info children]]} -count 1 -expected $ccount nx::test new -cmd {set x [llength [Object info instances]]} -count 1 -expected $ocount nx::test new -cmd {llength [Object info instances]} -count 1 -expected $ocount nx::test new -cmd {d istype D} -expected 1 nx::test new -cmd {c setViaInstvar 100} -expected 100 nx::test new -cmd {c setViaSetMethod 100} -expected 100 nx::test new -cmd {c setViaParameter 100} -expected 100 nx::test new -cmd {c existsViaInstvar} nx::test new -cmd {c existsViaMyInstvar} nx::test new -cmd {c existsViaExistsMethod} nx::test new -cmd {c existsViaMyExistsMethod} nx::test new -cmd {c existsViaDotExistsMethod} nx::test new -cmd {c existsViaResolver} nx::test new -cmd {c exists v} nx::test new -cmd {c notExistsViaInstvar} -expected 0 nx::test new -cmd {c notExistsViaExistsMethod} -expected 0 nx::test new -cmd {c exists xxx} -expected 0 nx::test new -cmd {c existsAndReturnValue1} -expected 100 nx::test new -cmd {c existsAndReturnValue3} -expected 100 nx::test new -cmd {c testAndSetViaInstvar 100} -expected 100 nx::test new -cmd {c testAndSetViaSetMethod 100} -expected 100 nx::test new -cmd {c readViaInstvar} -expected 99 nx::test new -cmd {c readViaSetMethod} -expected 99 nx::test new -cmd {c readViaParameter} -expected 99 nx::test new -cmd {c readViaSetMethodNoSelf} -expected 99 nx::test new -cmd {c readTwiceViaInstvar} -expected 99 nx::test new -cmd {c readTwiceViaSetMethod} -expected 99 nx::test new -cmd {c readTwiceViaParameter} -expected 99 nx::test new -cmd {c readTwiceViaSetMethodNoSelf} -expected 99 nx::test new -cmd {c readTwovarsViaInstvar} -expected 98 nx::test new -cmd {c readTwovarsViaSetMethod} -expected 98 nx::test new -cmd {c readTwovarsViaParameter} -expected 98 nx::test new -cmd {c readTwovarsViaSetMethodNoSelf} -expected 98 nx::test new -cmd {c instvarAlias} nx::test new -cmd {c incr v} -post {c set v 1} -expected 101 nx::test new -cmd {c unset v; set r [c exists v]; c set v 1; set r} -expected 0 nx::test new -cmd {llength [Object info instances]} -count 1 -expected $ocount nx::test new -cmd {set x [llength [Object info instances]]} -count 1 -expected $ocount nx::test new -cmd {c explicitReturn} nx::test new -cmd {c implicitReturn} nx::test new -cmd {c explicitReturnFromVar} nx::test new -cmd {c implicitReturnFromVar} nx::test new -cmd {llength [Object info instances]} -count 1 -expected $ocount nx::test new -cmd {set x [llength [Object info instances]]} -count 1 -expected $ocount nx::test new -cmd {c childNodeNamespace} -expected ::c::13 nx::test new -cmd {llength [Object info instances]} -count 1 -expected $ocount nx::test new -cmd {c childNodeNamespaceCreate} -expected ::c::13 nx::test new -cmd {llength [Object info instances]} -expected $ocount nx::test new -cmd {c createVolatileRc} -expected 2 # should be still the same number as above nx::test new -count 1 -cmd {llength [Object info instances]} -expected $ocount nx::test new -cmd {Object new -volatile} -expected ::nsf::__\#F9 -count 2000 \ -post {foreach o [Object info instances ::nsf::__*] {$o destroy}} # should be still the same number as above nx::test new -count 1 -cmd {llength [Object info instances]} -expected $ocount nx::test new -cmd {Object new} -expected ::nsf::__\#lQ -count 2000 \ -post {foreach o [Object info instances ::nsf::__*] {$o destroy}} # should be still the same number as above nx::test new -count 1 -cmd {llength [Object info instances]} -expected $ocount nx::test new -cmd {Object new -childof o} -expected ::o::__\#0Hh \ -pre {Object o} -post {o destroy} # should be still the same number as above nx::test new -count 1 -cmd {llength [Object info instances]} -expected $ocount nx::test new -count 1000 -pre {::set ::count 0} \ -cmd {Object create [incr ::count]} \ -expected ::1 \ -post {::unset ::count} nx::test new -count 1000 -pre {::set ::count 0} \ -cmd {[incr ::count] destroy} \ -post {::unset ::count} \ -expected "" # nx::test new -count 1 -cmd {llength [Object info instances]} -expected $ocount # we create another object set ocount [expr {$ocount + 1}] nx::test new -cmd {Object create x} -expected ::x nx::test new -count 1 -cmd {llength [Object info instances]} -expected $ocount nx::test new -cmd {Object create x -set a -1 -set b ,, -set c a--} \ -expected ::x nx::test new -count 1 -cmd {llength [Object info instances]} -expected $ocount nx::test new -cmd {expr {[c array names n 5] ne ""}} nx::test new -count 1 -cmd {llength [Object info instances]} -expected $ocount nx::test new -cmd {info exists c::n(5)} nx::test new -count 1 -cmd {llength [Object info instances]} -expected $ocount nx::test new -cmd {c exists n(5)} nx::test new -cmd {llength [c info children]} -expected $ccount nx::test new -cmd {c info children ::c::5} -expected ::c::5 nx::test new -cmd {c info children 5} -expected ::c::5 nx::test new -cmd {c info children 5*} -expected ::c::5 nx::test new -count 1 -cmd {llength [Object info instances]} -expected $ocount nx::test new -cmd {Object info instances ::c::5*} -expected ::c::5 nx::test new -cmd {Object info instances ::c::5} -expected ::c::5 nx::test new -cmd {Object info instances ::c::5000} -expected "" nx::test new -count 100 -pre {set ::c::l ""} \ -cmd {lappend ::c::l 1} \ -post {c unset l} nx::test new \ -count 100 \ -cmd {c mixinappend M1} \ -expected ::M1 \ -post {c mixin ""} nx::test new \ -count 100 \ -cmd {c ma M1} \ -expected ::M1 \ -post {c mixin ""} nx::test new \ -count 100 \ -cmd {c mixin add M1} \ -expected "::M1" \ -post {c mixin ""} nx::test new \ -count 100 \ -cmd {c mixinappend M1; c mixinappend M2} \ -expected {::M1 ::M2} \ -post {c mixin ""} nx::test new \ -count 100 \ -cmd {c ma M1; c ma M2} \ -expected {::M1 ::M2} \ -post {c mixin ""} nx::test new \ -count 100 \ -pre {Class D; Class E; Object o -mixin {D E}} \ -cmd {o info mixin D} \ -expected {::D} \ -post {foreach o {D E o} {$o destroy}} nx::test new \ -count 100 \ -pre {Class D; Class E; Object o -mixin {D E}} \ -cmd {o info mixin E} \ -expected {::E} \ -post {foreach o {D E o} {$o destroy}} nx::test new \ -count 100 \ -pre {Class D; Class E; Object o -mixin {D E}} \ -cmd {o info mixin ::E*} \ -expected {::E} \ -post {foreach o {D E o} {$o destroy}} nx::test new \ -count 100 \ -pre {Class D; Class E; Class E1; Object o -mixin {D E E1}} \ -cmd {o info mixin ::E*} \ -expected {::E ::E1} \ -post {foreach o {D E E1 o} {$o destroy}} nx::test new \ -count 100 \ -pre {Class D; Class E; Class X1 -instmixin {D E}} \ -cmd {X1 info instmixin D} \ -expected {::D} \ -post {foreach o {D E X1} {$o destroy}} nx::test new \ -count 100 \ -pre {Class D; Class E; Class X2 -instmixin {D E}} \ -cmd {X2 info instmixin E} \ -expected {::E} \ -post {foreach o {D E X2} {$o destroy}} nx::test new \ -count 100 \ -pre {Class D; Class E; Class E1; Class X -instmixin {D E E1}} \ -cmd {X info instmixin ::E*} \ -expected {::E ::E1} \ -post {foreach o {D E E1 X} {$o destroy}} nx::test new \ -count 100 \ -pre {Class D; Class E; Class X3 -instmixin {D E}} \ -cmd {X3 info instmixin ::E*} \ -expected {::E} \ -post {foreach o {D E X3} {$o destroy}} nx::test new \ -count 100 \ -pre {Class D; Class E; Class X} \ -cmd {X instmixin {D E}; X instmixin delete ::E; X info instmixin} \ -expected {::D} \ -post {foreach o {D E X} {$o destroy}} nx::test new \ -count 100 \ -pre {Class D; Class E; Class X} \ -cmd {X instmixin {D E}; X instmixin delete E; X info instmixin} \ -expected {::D} \ -post {foreach o {D E X} {$o destroy}} nx::test new \ -count 100 \ -pre {Class D; Class E; Class E1; Class X} \ -cmd {X instmixin {D E E1}; catch {X instmixin delete ::E*}; X info instmixin} \ -expected {::D} \ -post {foreach o {D E E1 X} {$o destroy}} nx::test new \ -count 100 \ -pre {Class D; Class E; Class E1; Class X} \ -cmd {X instmixin {D E E1}; catch {X instmixin delete E*}; X info instmixin} \ -expected {::D} \ -post {foreach o {D E E1 X} {$o destroy}} nx::test new \ -cmd {C instfilter f; C info instfilter} \ -expected f \ -post {C instfilter ""} nx::test new -pre {set s \#hallo} -cmd {string match "\#*" $s} nx::test new -pre {set s \#hallo} -cmd {regexp {^\#} $s} nx::test new -pre {set s \#hallo} -cmd {expr {[string first "\#" $s] == 0}} nx::test new -pre {set s \#hallo} -cmd {expr {[string range $s 0 0] == "\#"}} nx::test new -pre {set s \#hallo} -cmd {regexp {^\#.*a} $s} nx::test new -pre {set s \#hallo} -cmd {regexp {^\#.*a.*o} $s} nx::test new -pre {set s \#hallo} -cmd {regexp {^\#.*a(.*)o} $s} nx::test new -pre {set s \#hallo} -cmd {regexp {^\#.*a(.*)o} $s _} nx::test new -pre {set s \#hallo} -cmd {regexp {^\#.*a(.*)o} $s _ out} nx::test new -msg {call proc of subobject directly} \ -pre {C c2; C c2::o; c2::o proc f a {incr a}} \ -cmd {c2::o::f 10} -expected 11 -count 5000 \ -post {c2 destroy} nx::test new -msg {call proc of subobject via dispatch} \ -pre {C c2; C c2::o; c2::o proc f a {incr a}} \ -cmd {c2::o f 10} -expected 11 -count 5000 \ -post {c2 destroy} #nx::test new -msg {call proc of object and subobject via dispatch} \ # -pre {C c2; C c2::o; c2::o proc f a {incr a}} \ # -cmd {c2 o f 10} -expected 11 -count 5000 \ # -post {c2 destroy} nx::test new -msg {dispatch subobject directly via [self]} \ -pre {C c2; C c2::o; c2::o proc f a {incr a}; c2 proc t a {[self]::o f $a}} \ -cmd {c2 t 12} -expected 13 -count 5000 \ -post {c2 destroy} #nx::test new -msg {dispatch subobject via my} \ # -pre {C c2; C c2::o; c2::o proc f a {incr a}; c2 proc t a {my o f $a}} \ # -cmd {c2 t 12} -expected 13 -count 5000 \ # -post {c2 destroy} ###### insttclcmd tests set cnt 10000 #nx::test new -msg {call insttclcmd (append) and check created variable} \ -pre {Object o} \ -cmd {o append X 1; o exists X} -expected 1 \ -post {o destroy} #nx::test new -msg {call tclcmd (regexep) and check created variable} \ -pre {Object o; o tclcmd regexp} \ -cmd {o regexp (a) a _ x; o exists x} -expected 1 -count $cnt \ -post {o destroy} nx::test new -msg {call forwarder for (append) and check created variable} \ -pre {Object o; o forward append -objscope} \ -cmd {o append X 1; o exists X} -expected 1 \ -post {o destroy} nx::test new -msg {call forwarder (regexep) and check created variable} \ -pre {Object o; o forward regexp -objscope} \ -cmd {o regexp (a) a _ x; o exists x} -expected 1 -count $cnt \ -post {o destroy} nx::test new -msg {call forwarder to another obj} \ -pre {Object o; Object t; o forward set t set; t set x 100} \ -cmd {o set x} -expected 100 -count $cnt \ -post {o destroy} set cnt 100000 nx::test new -msg {call handcoded incr} \ -pre {Class C; C create o; o set x 1} \ -cmd {o incr x 77} -expected 78 -count $cnt \ -post {o destroy} nx::test new -msg {call incr via instforward} \ -pre {Class C; C instforward ::incr -objscope; C create o; o set x 1} \ -cmd {o incr x 77} -expected 78 -count $cnt \ -post {o destroy} nx::test new -msg {call incr via forward} \ -pre {Class C; C create o; o forward ::incr -objscope; o set x 1} \ -cmd {o incr x 77} -expected 78 -count $cnt \ -post {o destroy} set cnt 10000 nx::test new -msg {call obj with namespace via forward} \ -pre {Object n; Object n::x; Object o -forward ::n::x} \ -cmd {o x self} -expected ::n::x -count $cnt \ -post {o destroy} nx::test new -msg {call obj with namespace via instforward} \ -pre {Object n; Object n::x; Class C; C create o; C instforward ::n::x} \ -cmd {o x self} -expected ::n::x -count $cnt \ -post {o destroy} nx::test new -msg {call obj with namespace via instforward and mixinclass} \ -pre {Object n; Object n::x; Class M -instforward ::n::x; Class C -instmixin M; C create o } \ -cmd {o x self} -expected ::n::x -count $cnt \ -post {o destroy} nx::test new -msg {call obj with namespace via instforward and next from proc} \ -pre { Object n; Object n::x; Class C -instforward ::n::x; C create o -proc x args {next} } \ -cmd {o x self} -expected ::n::x -count $cnt \ -post {o destroy} nx::test new -msg {call obj with namespace via instforward and next from instproc} \ -pre { Object n; Object n::x; Class C -instforward ::n::x; Class D -superclass C -instproc x args {next}; D create o } \ -cmd {o x self} -expected ::n::x -count $cnt \ -post {o destroy} nx::test new -msg {call obj with namespace via mixin and instforward and next} \ -pre {Object n; Object n::x; Class M -instforward ::n::x; Class N -superclass M -instproc x args {next}; Class C -instmixin N; C create o} \ -cmd {o x self} -expected ::n::x -count $cnt \ -post {o destroy} nx::test new -msg {return -code break} \ -pre {Class A -instproc br {} {return -code break}; A create a1} \ -cmd {catch {a1 br}} -expected 3 -count 2 \ -post {A destroy; a1 destroy} # # volatile tests # nx::test new -msg {volatile + new overloaded } \ -pre {Class A; A proc new args {next}} \ -cmd {set a [A new -volatile]; $a info class} -expected ::A -count 2 \ -post {A destroy} nx::test new -msg {volatile + next overloaded + proc } \ -pre {Class A; A proc new args {next}; proc foo {} {set a [A new -volatile]; $a info class}} \ -cmd {foo; ::A info instances} -expected {} -count 2 \ -post {A destroy; rename foo ""} nx::test new -msg {volatile + configure overloaded} \ -pre {Class A; A instproc configure args {next}} \ -cmd {A create a1 -volatile; A a2 -volatile; lsort [A info instances]} -expected "::a1 ::a2" -count 2 \ -post {A destroy} nx::test new -msg {volatile + configure overloaded + proc} \ -pre {Class A; A instproc configure args {next}; proc foo {} {A create a1 -volatile; A a2 -volatile}} \ -cmd {foo; ::A info instances} -expected {} -count 2 \ -post {A destroy; rename foo ""} nx::test new -msg {volatile + new overloaded + mixin + proc} \ -pre { Class MC -superclass Class;MC instproc new args {next} Class M; M instproc new args {puts M; next} MC A; A instmixin M MC B -superclass A; B proc new args {next} proc foo {} {B create b1 -volatile; b1 info class} } \ -cmd {foo; ::B info instances} -expected {} -count 2 \ -post {B destroy; A destroy; M destroy; MC destroy; rename foo ""} nx::test new -msg {dict external} \ -pre { unset ::_ Object create o } \ -cmd { lappend ::_ [o dict set d a first] lappend ::_ [o dict set d b second] lappend ::_ [o dict get [o set d] b] set ::_ } -expected {{a first} {a first b second} second} -count 2 \ -post {o destroy; unset ::_} nx::test new -msg {dict resolver} \ -pre { Object create o o proc foo {} { dict set :mydict 1 one dict set :mydict 2 two dict keys ${:mydict} } } \ -cmd { o foo } -expected {1 2} -count 2 \ -post {o destroy} # # Check whether the setting of the autoname object property is already # visible immediately after the object creation (e.g. in an overloaded # "create" method. This is e.g. important for ttrace, catching object # creates via instmixin. # nx::test new -msg {autonamed property + overloaded create} \ -pre { set ::_ {} ::xotcl::Class create ::xotcl::_creator -instproc create {args} { set r [next] lappend ::_ [nsf::object::property $r autonamed] return $r } ::xotcl::Class instmixin ::xotcl::_creator } \ -cmd {::xotcl::Object new; ::xotcl::Object a; ::xotcl::Object create a; ::xotcl::Object new; set ::_} \ -expected {1 0 0 1} -count 1 \ -post {::xotcl::Class instmixin ""; ::xotcl::_creator destroy; a destroy} nx::test run # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/xotcl/tests/testx.xotcl000644 000766 000024 00000430653 13717245175 021400 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require XOTcl 2.0; namespace import -force ::xotcl::* proc ::errorCheck {got expected msg} { nsf::__db_run_assertions if {$got != $expected} { if {[catch {uplevel self} self]} { set self "NO CURRENT OBJECT" } puts stderr "$self FAILED: $msg\nGot: $got\nExpected: $expected" foreach g $got e $expected { set result [expr {$g == $e}] if {[string length $g]>60} { puts "$result g='$g'\n e='$e'" } else { puts "$result g='$g' e='$e'" } } exit -1 } } proc ::cutSpaces {string} { regsub -all " " $string "" result regsub -all "\n" $result " " result return $result } Class TestX \ -instmixin [Class TestXM -instproc run args {next; puts "[self] PASSED"}] @ @File {description { This is a file which provides a regression test for the features of the XOTcl - Language. } } @ Class TestX @ TestX nestingClasses { description {Regression test object testing the class nesting feature.} } TestX nestingClasses -proc run {{n 20}} { for {set i 0} {$i < $n} {incr i} { Class x($i) Class x($i)::y ::errorCheck [x($i) info commands y] "y" " -- creating Nested Class " Class x($i)::z Class x($i)::z::t Class x($i)::t ::errorCheck [x($i) info classchildren] "::x($i)::t ::x($i)::y ::x($i)::z" \ "info classchildren" ::errorCheck [x($i) info children] "::x($i)::t ::x($i)::y ::x($i)::z" \ "info children" ::errorCheck [x($i)::z info classparent] "::x($i)" \ "info classparent" ::errorCheck [x($i)::z info parent] "::x($i)" \ "info parent" ::errorCheck [x($i) info commands t] "t" "-- MakeClass " x($i) a x($i)::z a x($i)::z::t a x($i)::z::t move x($i)::z::rt x($i)::z::rt a ::errorCheck [x($i)::z info commands rt] "rt" \ "renaming leaf " x($i)::z move x($i)::rz ::errorCheck [x($i) info commands rz] "rz" \ "renaming node (node itself)" ::errorCheck [x($i)::rz info commands rt] "rt" \ "renaming node (leaf in node)" ::errorCheck [x($i)::rz info classchildren] "::x($i)::rz::rt" \ "info classchildren (2)" ::errorCheck [x($i)::rz info children] "::x($i)::rz::rt" \ "info children (2)" ::errorCheck [x($i)::rz::rt info classparent] "::x($i)::rz" \ "info classparent (2)" ::errorCheck [x($i)::rz::rt info parent] "::x($i)::rz" \ "info parent (2)" x($i) move rx ::errorCheck [rx info commands rz] "rz" \ "renaming root " ::errorCheck [info commands rx] "rx" \ "renaming root " rx destroy } } @ TestX nestingObjects { description {Regression test object testing the object nesting feature.} } TestX nestingObjects -proc run {{n 20}} { for {set i 0} {$i < $n} {incr i} { Class C($i) C($i) instproc testinstproc {} { return } C($i) o o proc testproc {} { return } o testproc; o testinstproc C($i) o::y ::errorCheck [o info commands y] y "creating Nested Object " C($i) o::z C($i) o::z::t C($i) o::t ::errorCheck [o info children] "::o::t ::o::y ::o::z" "info children" ::errorCheck [o::t info parent] "::o" "info parent" ::errorCheck [o info commands t] t "MakeObject" o::z::t move o::z::rt ::errorCheck [o::z info commands rt] rt "renaming leaf" o::z move o::rz ::errorCheck [o::rz info commands rt] rt "renaming node" ::errorCheck [o info commands rz] rz "renaming node" o move rx ::errorCheck [rx info commands rz] rz "renaming root " ::errorCheck [info commands rx] rx "renaming root" rx destroy C($i) destroy Class A A instproc x {a1 args} { my set var $a1 } A a A a::n -x "1 2 3" ::errorCheck [::a::n set var] "1 2 3" "arg passing - init dash" } } @ TestX assertions { description {Regression test object testing the assertions.} } TestX assertions -proc run {{n 20}} { if {!$::nsf::config(assertions)} { return } for {set i 0} {$i < $n} {incr i} { Class C($i) set r [C($i) invar { {$a > 2} {$c < 3} {$d > 5} {#a } {#b } }] C($i) instinvar { {$a > 2} {$c < 3} {$d > 5} {#a } {#b } } ::errorCheck [C($i) info invar] {{$a > 2} {$c < 3} {$d > 5} {#a } {#b }} \ "Class invar " ::errorCheck [C($i) info invar] {{$a > 2} {$c < 3} {$d > 5} {#a } {#b }} \ "Class instinvar " Object b($i) b($i) invar { {$a > 2} {$c < 3} {$d > 5} {#a} {#b} } ::errorCheck [C($i) info invar] {{$a > 2} {$c < 3} {$d > 5} {#a } {#b }} \ "Object invar " b($i) proc p {a b c} { return p } {pre1 pre2 pre3} {post1 post2 post3} ::errorCheck [b($i) info pre p] {pre1 pre2 pre3} \ "Obj proc pre assertion " ::errorCheck [b($i) info post p] {post1 post2 post3} \ "Obj proc post assertion " C($i) instproc p {a b c} { return p } {} {post1 post2 post3} ::errorCheck [C($i) info instpre p] "" \ "CL proc pre assertion " ::errorCheck [C($i) info instpost p] {post1 post2 post3} \ "CL proc post assertion " C(0) set a 3; C(0) set c 2; C(0) set d 7; C(0) set f 50; C(0) check all C(0) proc checkit {} { C(0) instvar a c d f ::errorCheck [my info check] {invar instinvar pre post} \ "check options != all" # turn obj-invar off C(0) check {pre post instinvar} C(0) set c 10 ::errorCheck [my info check] {instinvar pre post} \ "check options != instinvar pre post" } {{$f > 10}} {{$f < 100}} C(0) checkit } for {set i 0} {$i < $n} {incr i} { b($i) destroy C($i) destroy } Object b b proc p {a b c} { return p } {pre1 pre2 pre3} {post1 post2 post3} ::rename b a ::errorCheck [a info pre p] {pre1 pre2 pre3} \ "renamed Obj proc pre assertion " ::errorCheck [a info post p] {post1 post2 post3} \ "renamed Obj proc post assertion " Class Sensor -parameter {{value 1}} Sensor instinvar { {[regexp {^[0-9]$} [my value]] == 1} } Sensor s s check all Sensor instproc x {} { s value } { {[regexp {^[0-9]$} [my value]] == 1} } {} s x s value # inheritance Class A -parameter {{x 1} {y 1}} A instinvar {{$x == 1}} A instproc xTo2 args { my set x 2 } A instproc yTo2 args { my set y 2 } {} {{$y == 1}} A a -check all if {![catch {a xTo2} err]} { set err "ok" } else { a check {} a set x 1 a check all } ::errorCheck $err {assertion failed check: {$x == 1} in proc 'set'} \ "inheritance a xTo2" if {![catch {a yTo2} err]} { set err "ok" } ::errorCheck $err {assertion failed check: {$y == 1} in proc 'yTo2'} \ "inheritance a yTo2" Class B -superclass A B b -check all if {![catch {b xTo2} err]} { set err "ok" } else { b check {} b set x 1 b check all } ::errorCheck $err {assertion failed check: {$x == 1} in proc 'set'} \ "inheritance b xTo2" if {![catch {b yTo2} err]} { set err "ok" } ::errorCheck $err {assertion failed check: {$y == 1} in proc 'yTo2'} \ "inheritance b yTo2" a destroy b destroy } @ TestX filterAddRemove { description {Regression test object testing adding/removing of filters.} } TestX filterAddRemove -proc run {{n 20}} { set ::filterCount 0 for {set i 0} {$i < $n} {incr i} { Class SA($i) Class SB($i) Class SC($i) -superclass [list SB($i) SA($i)] SA($i) instproc fa args { incr ::filterCount my set x 150 set r [next] lappend ::result "$r-[self class]::[self proc]" return $r } SA($i) instproc f2 args { incr ::filterCount my set x 150 set r [next] lappend ::result "$r-[self class]::[self proc]" return $r } SB($i) instproc f2 args { incr ::filterCount my set x 150 set r [next] lappend ::result "$r-[self class]::[self proc]" return $r } SB($i) instproc fb args { incr ::filterCount my set x 150 set r [next] lappend ::result "$r-[self class]::[self proc]" return $r } SC($i) instproc fc args { incr ::filterCount my set x 150 set r [next] lappend ::result "$r-[self class]::[self proc]" return $r } SC($i) instfilter fc SB($i) instfilter {fb f2} SA($i) instfilter {fa f2} Class T T proc s {} { return } Class Filtered${i} -superclass SC($i) Filtered${i} instproc testfilter args { incr ::filterCount T s set r [next] lappend ::result "$r-[self class]::[self proc]" return $r } Filtered${i} instfilter testfilter Filtered${i} instproc a1 args { return "in a1" } Filtered${i} f${i} set ::result "" set erg [f${i} a1] ::errorCheck $::result \ "{in a1-::SA($i)::f2} {in a1-::SA($i)::fa} {in a1-::SB($i)::f2} {in a1-::SB($i)::fb} {in a1-::SC($i)::fc} {in a1-::Filtered${i}::testfilter}" \ "Filter Test - add" SC($i) instfilter {} SB($i) instfilter fb SA($i) instfilter {} set ::result "" set erg [f${i} a1] ::errorCheck $::result "{in a1-::SB($i)::fb} {in a1-::Filtered${i}::testfilter}" \ "Filter Test - remove" f${i} proc procFilter args { return "[next]-[self class]::[self proc]" } f${i} filter {fa f2 procFilter} set ::result "" set erg [f${i} a1] ::errorCheck $::result "{in a1-::SB($i)::fb} {in a1-::Filtered${i}::testfilter} {in a1-::procFilter-::SB($i)::f2} {in a1-::procFilter-::SA($i)::fa}" \ "Obj Filter Test call three filter + instfilter" ::errorCheck [f${i} info filter]-[SB($i) info instfilter]-[SC($i) info instfilter] \ "fa f2 procFilter-::procFilter-fb-" \ "filter infos" ::errorCheck [f${i} filtersearch fa]-[f${i} filtersearch fb]-[f${i} filtersearch procFilter] \ "::SA($i) instproc fa-::procFilter-::SB($i) instproc fb-::procFilter-::f${i} proc procFilter-::procFilter" \ "filtersearch" Filtered${i} instfilter {} SB($i) instfilter {} set ::result "" set erg [f${i} a1] ::errorCheck $::result \ "{in a1-::procFilter-::SB($i)::f2} {in a1-::procFilter-::SA($i)::fa}" \ "only obj filter" f${i} filter {} set ::result "" set erg [f${i} a1] ::errorCheck $erg "in a1" \ "obj filter remove" } for {set i 0} {$i < $n} {incr i} { SA($i) destroy SB($i) destroy SC($i) destroy } ::errorCheck $::filterCount 1080 \ "Filter Test - Filter Count -- Got: $::filterCount" # # instvar test # Object o o set x 1 Object o1 o1 set x 11 Object o2 o2 proc t {} { # multiple imports for existing (x) and not existing vars (y) o instvar x y append result "x: $x " append result "y: info-exists [info exists y] me [my exists y] " \ "iv '[info vars y]' oe [o exists y] oiv '[o info vars y]' // " set y 100 append result "y: info-exists [info exists y] me [my exists y] " \ "iv '[info vars y]' oe [o exists y] oiv '[o info vars y]'" ::errorCheck $result \ "x: 1 y: info-exists 0 me 0 iv 'y' oe 0 oiv '' // y: info-exists 1 me 0 iv 'y' oe 1 oiv 'y'" \ "instvar test 1 failed" set result "" o1 instvar x y append result "x: $x " append result "y: info-exists [info exists y] me [my exists y] " \ "iv '[info vars y]' oe [o1 exists y] oiv '[o1 info vars y]' // " set y 101 append result "y: info-exists [info exists y] me [my exists y] " \ "iv '[info vars y]' oe [o1 exists y] oiv '[o1 info vars y]'" ::errorCheck $result \ "x: 11 y: info-exists 0 me 0 iv 'y' oe 0 oiv '' // y: info-exists 1 me 0 iv 'y' oe 1 oiv 'y'" \ "instvar test 2 failed" } o2 t o destroy o1 destroy o2 destroy global filterResult set filterResult "" Object a1 -requireNamespace a1 set o 12 a1 set p 13 Class A A set m 14 Object instproc f args { global filterResult a1 instvar o p A instvar m ::append filterResult " [self] [self calledproc] [self callingproc]" ::append filterResult " $o $p $m" next } proc x {} { set ::a1::e xxx } Object instfilter f x rename x "" ::errorCheck $::a1::e xxx \ "filterAddRemove: instvar test -- proc set failed" a1 set e yyy ::errorCheck $::a1::e yyy \ "filterAddRemove: instvar test -- obj set failed" ::errorCheck $filterResult " ::A instvar f 12 13 14 ::a1 set run 12 13 14" \ "filterAddRemove: instvar test -- instvar filter failed" Object instfilter "" Object instproc f args { next } Object instfilter f ::errorCheck [Object o] "::o" \ "filterAddRemove: Object creation with filter" # This produces a bug, if not # RUNTIME_STATE(in)->returnCode = TCL_OK; # in ObjDispatch -> UNKNOWN handling */ # abrupt stop of program because result is set to XOTCL_UNKNOWN # instead of TCL_ERROR, as it should be catch {puts ${ZZZZZZZZZZZZZZZ::ZZZZZ}} o set r 43 ::errorCheck [o set r] "43" \ "filterAddRemove: Object creation with filter: setting var" Object instfilter "" # test for CmdListReplaceCmd set ::r "" Class A A instproc f2 args {lappend ::r [self class]-[self proc]; next} Class C -superclass A Class D -superclass C D instfilter {f2} D d d filter {f2} C instproc f2 args {lappend ::r [self class]-[self proc]; next} set ::r "" d set r 1 ::errorCheck $::r "::C-f2 ::A-f2" \ "filter method addition" o proc m {} { } o proc f args { my incr count next } o set count 0 o filter f o m ::errorCheck [o set count] 2 "filter count" o filter "" set filterstate [::nsf::configure filter off] o set count 0 o m ::errorCheck [o set count]-$filterstate 0-1 "filter off + old state" o filter "" ::nsf::configure filter on set ::r "" Object instproc f args { set r [next] lappend ::r [self]-[self calledproc] return $r } Class D D filter f D d1 ::errorCheck $::r "::D-d1 ::D-alloc ::D-create ::D-unknown" \ "filter state after next" Object instproc f {} {} D destroy } @ TestX filterClassChange { description {Regression test object testing class changes of filters.} } TestX filterClassChange -proc run {{n 20}} { for {set i 0} {$i < $n} {incr i} { Class A($i) Class B A($i) instproc f args { set result pre*[self]*[self proc]*$args lappend result [next] post*[self]*[self proc] return $result } A($i) o($i) o($i) proc change {} { my class B } o($i) proc call {} { return in-call } A($i) instfilter f set erg [o($i) call] ::errorCheck $erg "pre*::o($i)*f* in-call post*::o($i)*f" \ "Filter Class Change -- Call before change" o($i) change set erg [o($i) call] ::errorCheck $erg "in-call" \ "Filter Class Change -- Call after change" # testing deleting a filter proc Class F F instproc testf args {return filtered} F instfilter testf F f1 ::errorCheck [f1 set r 45] "filtered" "Deleting a filter proc ... before" F instproc testf {} {} ::errorCheck [f1 set r 45] "45" "Deleting a filter proc ... after" # testing remove a superclass Class F1 Class F2 -superclass F1 Class F3 -superclass F2 F1 instproc testf args { set r [next] lappend ::result $r-filtered return $r } F2 instproc testf2 args { set r [next] lappend ::result $r-filtered return $r } F3 instfilter {testf testf2} F3 f2 set ::result "" ::errorCheck [f2 filtersearch testf2] "::F2 instproc testf2" "filtersearch 2" set ::result "" f2 set r 45 ::errorCheck $::result "45-filtered 45-filtered" \ "Removing a superclass ... before" F3 superclass [F1 info superclass] set ::result "" ::errorCheck [f2 filtersearch testf2] "" "filtersearch 2 after" set ::result "" ::errorCheck [f2 set r 45] "45" "Class F2 removed from classtree ... after" } B destroy for {set i 0} {$i < $n} {incr i} {A($i) destroy} } @ TestX filterGuards { description {Regression test object testing filter guards.} } TestX filterGuards -proc run {{n 20}} { global filterResult for {set i 0} {$i < $n} {incr i} { set ::filterResult "" Class A A instproc f2 args { append ::filterResult "-[self]-[self proc]-[self class]-[self calledproc]" next } Class B -superclass A B instproc f1 args { append ::filterResult "-[self]-[self proc]-[self class]-[self calledproc]" next } B instproc f3 args { append ::filterResult "-[self]-[self proc]-[self class]-[self calledproc]" next } B instproc f01 args { append ::filterResult 1; next } B instproc f02 args { append ::filterResult 2; next } B instfilter {{f1 -guard "1 2 3"}} ;# guard with error set r [catch {B b} errorMsg] ::errorCheck $r-$::filterResult "1-" "Filter guard: Filter guard with error" ::errorCheck [lrange $errorMsg 0 4] "Guard error: '1 2 3'" errormsg set ::filterResult "" B instfilter {f01 {f02 -guard "a b"}} ;# guard with error if {[info commands ::b] ne ""} { catch {::b destroy} } set r [catch {B b}] ::errorCheck $r-$::filterResult "1-11" "Filter guard: Filter guard with error via next" set ::filterResult "" B instfilter {{f1 -guard "1<0"}} ;# failing guard B b ::errorCheck $::filterResult "" "Filter guard: Filter never to be applied" b destroy A instproc f1 args { append ::filterResult "-[self]-[self proc]-[self class]-[self calledproc]" next } set ::filterResult "" B b ::errorCheck $::filterResult "" \ "Filter guard: Filter never to be applied + filter inheritance on this filter" # filter w/o guard -> has to be applied A instfilter f1 b destroy set ::filterResult "" B b set r1 "-::b-f1-::A-configure-::b-f1-::A-residualargs-::b-f1-::A-init" set r2 "-::b-f1-::A-configure-::b-f1-::A-init" ::errorCheck $::filterResult $r2 \ "Filter guard: two different filters, same name + different class, one guarded, one not" # two filter w/o guard -> both have to be applied B instfilter f1 b destroy set ::filterResult "" B b set r1 "-::b-f1-::B-configure-::b-f1-::A-configure-::b-f1-::B-residualargs-::b-f1-::A-residualargs-::b-f1-::B-init-::b-f1-::A-init" set r2 "-::b-f1-::B-configure-::b-f1-::A-configure-::b-f1-::B-init-::b-f1-::A-init" ::errorCheck $::filterResult $r2 \ "Filter guard: two different filters, both not guarded anymore" # three filters with guards, not to be applied, in one chain b destroy A instfilter {} B instfilter {{f1 -guard {0}} {f3 -guard {0}} {f2 -guard {0}}} set ::filterResult "" B b ::errorCheck $::filterResult "" "Filter guard: three filters in one chain" # three times the same filter --> guards are and-combined set ::filterResult "" B instfilter {{f2 -guard {[self calledproc] eq "set" || [self] == "::b2"}}} A instfilter {{f2 -guard {[self] == "::b2"}}} B b1 B b2 if {$i == 0} { set r1 "-::b2-f2-::A-configure-::b2-f2-::A-residualargs-::b2-f2-::A-init" set r2 "-::b2-f2-::A-configure-::b2-f2-::A-init" ::errorCheck $::filterResult $r2 \ "Filter guard: creation with less restrictive guards" } else { set r1 "-::b2-f2-::A-cleanup-::b2-f2-::A-configure-::b2-f2-::A-residualargs-::b2-f2-::A-init" set r2 "-::b2-f2-::A-cleanup-::b2-f2-::A-configure-::b2-f2-::A-init" ::errorCheck $::filterResult $r2 \ "Filter guard: creation with less restrictive guards (b)" } set ::filterResult "" b1 set x 45 ::errorCheck $::filterResult "-::b1-f2-::A-set" \ "Filter guard: setting restricted object" set ::filterResult "" b1 info class ::errorCheck $::filterResult "" \ "Filter guard: info restricted object (no guard applies)" set ::filterResult "" b2 info class ::errorCheck $::filterResult "-::b2-f2-::A-info" \ "Filter guard: setting restricted object (2nd guard applies)" b1 filter {{f2 -guard {[self calledproc] eq "info"}}} set ::filterResult "" b1 proc a1 {} { # } ::errorCheck $::filterResult "" \ "Filter guard: proc on restricted object (no guard applies)" set ::filterResult "" b1 info class ::errorCheck $::filterResult "-::b1-f2-::A-info" \ "Filter guard: info filtered by object filter guard" # checking infos ::errorCheck [b1 info filterguard f2]-[B info instfilterguard f2]-[A info instfilterguard f2] \ {[self calledproc] eq "info"-[self calledproc] eq "set" || [self] == "::b2"-[self] == "::b2"} \ "Filter guard: info filtered by object filter guard" # checking info -guards option Class A A instproc f1 args {next} A instproc fx args {next} Class B -superclass A B instproc f1 args {next} B instproc f2 args {next} B b B instfilter {{f1 -guard {[self] eq "::b"}} {f2 -guard 0} f1} b filter {{f1 -guard {[self] eq "::b"}} {f2 -guard 0}} ::errorCheck [B info instfilter] {f1 f2} "info filter order a" ::errorCheck [B info instfilter -guards] {f1 {f2 -guard 0}} "info filter order b" ::errorCheck [b info filter] {f1 f2} "info filter order c" ::errorCheck [b info filter -guards] {{f1 -guard {[self] eq "::b"}} {f2 -guard 0}} "info filter order d" A instfilter {f1 fx} A a a proc x args {next} a filter x ::errorCheck [b info filter -order] \ "{::B instproc f1} {::B instproc f2} {::A instproc f1} {::A instproc fx}" "info filter-order- 2a" ::errorCheck [a info filter -order] \ "{::a proc x} {::A instproc f1} {::A instproc fx}" "info filter-order- 2b" ::errorCheck [b info filter -order]-[a info filter -order] "{::B instproc f1} {::B instproc f2} {::A instproc f1} {::A instproc fx}-{::a proc x} {::A instproc f1} {::A instproc fx}" \ {[self] -- Filter guard: -order option} ::errorCheck [b info filter -order -guards] {{f1 -guard {[self] eq "::b"}} {f2 -guard 0}} \ "filter order guards 1" ::errorCheck [a info filter -order -guards] {x} \ "filter order guards 2" Class Foo Foo instproc init {args} {my set bar hello} Foo instproc baz {args} { my instvar bar return $bar } Foo instproc myFilter {args} { lappend ::r myFilter->[self calledproc] my set r 4 next } Foo instfilter myFilter Foo instfilterguard myFilter { ([self calledproc] eq "baz") } Foo instfilterguard myFilter { ([self calledproc] eq "baz") } set f [Foo new] $f baz ::errorCheck [$f baz] "hello" {Filter guard from method call} Foo instfilterguard myFilter {} set ::r "" Foo create f f filter myFilter f filterguard myFilter { ([self calledproc] eq "baz") } lappend ::r [f baz] [f set r 1] f filterguard myFilter {} lappend ::r [f baz] [f set r 1] set r1 [list myFilter->configure myFilter->residualargs myFilter->init myFilter->set myFilter->filter myFilter->filterguard myFilter->baz hello 1 myFilter->baz myFilter->instvar myFilter->set hello 1] set r2 [list myFilter->configure myFilter->init myFilter->set myFilter->filter myFilter->filterguard myFilter->baz hello 1 myFilter->baz myFilter->instvar myFilter->set hello 1] ::errorCheck $::r $r2 "Filter guard from method call" f destroy Class Room Room instproc open {} {lappend ::r [self proc]} Room instproc x {} {lappend ::r [self proc]} Room instproc loggingFilter args { lappend ::r [self proc]-[self calledproc] next } Room instproc callsMethod {method calledproc} { return [string match $calledproc $method] } Room instproc callsLevel2 {} { set level [self guardedlevel] lappend ::r $level set calledproc [uplevel $level self calledproc] lappend ::r $calledproc } Room instfilter loggingFilter Room instfilterguard loggingFilter {[my callsMethod open [self calledproc]]} Room r set ::r "" r open r x ::errorCheck $::r "loggingFilter-open open x" {info guarded scope} } } @ TestX mixinGuards { description {Regression test object testing mixin guards.} } TestX mixinGuards -proc run {{n 20}} { set ::r "" Class Fly Fly instproc fly {} {lappend ::r "[my signature]: yippee, fly like an eagle!"} Class Sing Sing instproc sing {} {lappend ::r "[my signature]: what a difference a day make"} Class Animal -parameter age Animal instproc unknown args { lappend ::r "[my signature]: how should i $args?"} Animal instproc signature {} { return "[self] [my info class] ([my age] years)" } Class Bird -superclass Animal Class Penguine -superclass Bird Class Parrot -superclass Bird Class Duck -superclass Bird Parrot tweedy -age 1 Penguine pingo -age 5 Duck donald -age 4 Parrot lora -age 6 Bird instmixin {{Fly -guard {[my age]>2 && ![my istype Penguine]}} Sing} foreach bird {tweedy pingo donald lora} { $bird fly } ::errorCheck [set ::r] [list \ {::tweedy ::Parrot (1 years): how should i fly?} \ {::pingo ::Penguine (5 years): how should i fly?} \ {::donald ::Duck (4 years): yippee, fly like an eagle!} \ {::lora ::Parrot (6 years): yippee, fly like an eagle!}] \ {Simple Instmixin Guard} set ::r "" tweedy age 3 pingo class Duck lora class Penguine foreach bird {tweedy pingo donald lora} { $bird fly } ::errorCheck [set ::r] [list \ {::tweedy ::Parrot (3 years): yippee, fly like an eagle!} \ {::pingo ::Duck (5 years): yippee, fly like an eagle!} \ {::donald ::Duck (4 years): yippee, fly like an eagle!} \ {::lora ::Penguine (6 years): how should i fly?}] \ {Simple Instmixin Guard ... Class Change} set ::r "" pingo mixin {{Fly -guard {[my age]>2}} Sing} foreach i { {Bird info instmixin -guards} {pingo info mixin -guards} {pingo info mixin -order -guards}} { lappend ::r "$i [eval $i]" } ::errorCheck [set ::r] [list \ {Bird info instmixin -guards {::Fly -guard {[my age]>2 && ![my istype Penguine]}} ::Sing} \ {pingo info mixin -guards {::Fly -guard {[my age]>2}} ::Sing} \ {pingo info mixin -order -guards {::Fly -guard {[my age]>2}} ::Sing}] \ {Simple Instmixin Guard ... Info} set ::r "" Class POM-start Class POM-end Class PCM-start Class PCM-end pingo mixin {POM-start {Fly -guard {[my age]>2}} Sing POM-end} Bird instmixin {PCM-start {Fly -guard {[my age]>2 && ![my istype Penguine]}} Sing PCM-end} pingo class Penguine foreach i { {Bird info instmixin -guards} {pingo info mixin -guards} {pingo info mixin -order -guards}} { lappend ::r "$i [eval $i]" } ::errorCheck [Bird info instmixin -guards] \ {::PCM-start {::Fly -guard {[my age]>2 && ![my istype Penguine]}} ::Sing ::PCM-end} pingo1 ::errorCheck [pingo info mixin -guards] \ {::POM-start {::Fly -guard {[my age]>2}} ::Sing ::POM-end} pingo2 ::errorCheck [pingo info mixin -order -guards] \ {::POM-start {::Fly -guard {[my age]>2}} ::Sing ::POM-end ::PCM-start ::PCM-end} pingo3 set ::r "" pingo fly ::errorCheck [set ::r] [list \ {::pingo ::Penguine (5 years): yippee, fly like an eagle!}] \ {Same Mixin Guard ... most specific counts} set ::r "" Animal a -set age 20 a mixin Fly a mixinguard ::Fly {[my age] > 3} a fly lappend ::r [a info mixin -guards] lappend ::r [a info mixin -order -guards] a set age 2 a fly a mixinguard ::Fly {[my age] > 4} a fly set info "" lappend info [a info mixinguard Fly] lappend ::r [a info mixin -guards] lappend ::r [a info mixin -order -guards] a mixinguard ::Fly {} a fly lappend ::r [a info mixin -guards] lappend info [a info mixinguard Fly] lappend ::r [a info mixin -order -guards] ::errorCheck [set ::r] [list \ {::a ::Animal (20 years): yippee, fly like an eagle!} \ {{::Fly -guard {[my age] > 3}}} {{::Fly -guard {[my age] > 3}}} \ {::a ::Animal (2 years): how should i fly?} \ {::a ::Animal (2 years): how should i fly?} \ {{::Fly -guard {[my age] > 4}}} {{::Fly -guard {[my age] > 4}}} \ {::a ::Animal (2 years): yippee, fly like an eagle!} \ ::Fly ::Fly] \ {mixinguard method} set ::r "" Class A -superclass Animal A a -set age 20 A instmixin Fly A instmixinguard ::Fly {[my age] > 3} lappend info [A info instmixinguard ::Fly] a fly lappend ::r [A info instmixin -guards] lappend ::r [a info mixin -order -guards] a set age 2 a fly A instmixinguard ::Fly {[my age] > 4} lappend info [A info instmixinguard ::Fly] a fly lappend ::r [A info instmixin -guards] lappend ::r [a info mixin -order -guards] A instmixinguard ::Fly {} lappend info [A info instmixinguard ::Fly] a fly lappend ::r [A info instmixin -guards] lappend ::r [a info mixin -order -guards] ::errorCheck [set ::r] [list \ {::a ::A (20 years): yippee, fly like an eagle!} \ {{::Fly -guard {[my age] > 3}}} {{::Fly -guard {[my age] > 3}}} \ {::a ::A (2 years): how should i fly?} \ {::a ::A (2 years): how should i fly?} \ {{::Fly -guard {[my age] > 4}}} {{::Fly -guard {[my age] > 4}}} \ {::a ::A (2 years): yippee, fly like an eagle!} \ ::Fly ::Fly] \ {instmixinguard method} ::errorCheck [set info] [list {[my age] > 4} {} {[my age] > 3} \ {[my age] > 4} {} ] {info (inst)mixinguard} Class create C C method foo {} {return 0} Class create M M method foo {} {return 1} Class create M1 M1 method foo {} {return 2} C c1 -mixin {M} ::errorCheck [c1 foo] 1 "no mixin guard" C c1 -mixin {{M -guard {0>1}}} ::errorCheck [c1 foo] 0 "mixin guard prevents call" C c1 -mixin {{M -guard {0 1 2}}} ::errorCheck [catch {c1 foo}] 1 "mixin guard with error" M method foo {} {next} C c1 -mixin {M {M1 -guard {a b c}}} ::errorCheck [catch {c1 foo}] 1 "mixin guard with error in next" c1 destroy C destroy M destroy M1 destroy } @ TestX filterSimpleObserver { description {Regression test object testing a simple observer using filters. } } TestX filterSimpleObserver -proc run {{n 20}} { set ::filterCount 0 for {set i 0} {$i < $n} {incr i} { set ::filterResult [list] Class NetAccess$i Class Http$i -superclass NetAccess$i Class TransferDialog$i TransferDialog$i proc addObserver cl { $cl instproc observerFilter args { set calledMethod [self calledproc] set callingClass [my info class] incr ::filterCount set result [next] my set r 34 foreach var {args calledMethod callingClass result} { if {[info vars $var] != $var} { puts stderr "[self] -- Simple Observer - info vars in filter" exit } } lappend ::filterResult [self]-[self class]-[my info class]-$args-[self calledproc]-[self callingproc]-$result return $result } $cl instfilter observerFilter } TransferDialog$i instproc show {i} { next TransferDialog${i} addObserver NetAccess$i [self class] instvar observingObjects lappend observingObjects(::NetAccess$i) [self] } Http$i parameter {a be bu} Http$i instproc path x { my set path $x } Http$i instproc query x { my set [self proc] $x } Http$i instproc init {args} { my set url abc next my instvar query path bu if {![info exists query] || ![info exists path] || ![info exists bu] || $query ne "q"} { puts stderr "FAILED - [self] -- Simple Observer - Variable Init"; exit } } Http$i instproc GET {x} { my instvar query url path if {[info exists query]} { append url ?$query append path ?$query } set ::baseLevel [info level] if {0 != [info level] - $::baseLevel} { puts stderr "FAILED - [self] -- Simple Observer - info level in filtered proc\n\ expected 0, got [expr {[info level] - $::baseLevel}]" exit } foreach var {x path query url} { if {[info vars $var] != $var} { puts stderr "FAILED - [self] -- Simple Observer - info vars in filtered proc"; exit } } return $url } TransferDialog$i t($i) t($i) show $i Http$i h($i) -query q -path p -bu b set ::filterResult [list] set erg [h($i) GET 1] ::errorCheck $erg "abc?q" \ "Simple Observer - Filter Return" ::errorCheck $::filterResult "{::h($i)-::NetAccess$i-::Http$i-query url path-instvar-GET-} ::h($i)-::NetAccess$i-::Http$i-1-GET-run-abc?q" \ "Simple Observer - Filter Return" } for {set i 0} {$i < $n} {incr i} { NetAccess$i instfilter {} h($i) destroy t($i) destroy Http$i destroy NetAccess$i destroy TransferDialog$i destroy } ::errorCheck $::filterCount 260 \ "Simple Observer - Filter Count" } @ TestX stdargs { description { Regression test object testing the ability of the next primitive to pass arguments without naming them. } } TestX stdargs -proc run {{n 20}} { for {set i 0} {$i < $n} {incr i} { Class C Class D Class A -superclass {C D} Class B -superclass A C instproc t {} { next return } D instproc t args { ::errorCheck $args "" --noArgs next return } A instproc t {a b args} { if {$a != 1 || $b != 2 || $args != {3 4 5 6 7 8 9}} { puts stderr "FAILED - [self] -- StdArgs not computed"; exit } next --noArgs return } B instproc t {a b args} { if {$a != 1 || $b != 2 || $args != {3 4 5 6 7 8 9}} { puts stderr "FAILED -[self] -- StdArgs not computed"; exit } next return } B x x t 1 2 3 4 5 6 7 8 9 } foreach o {x A B C D} {$o destroy} } @ TestX filterInfo { description{ Regression test object testing introspection of filters. } } TestX filterInfo # Helper Procs proc ::showStack {{m 100}} { set r "" set max [info level] if {$m<$max} {set max $m} for {set i 0} {$i < $max} {incr i} { set r ${r}-$i=[info level [expr -$i]] } return $r } proc ::showCall {} { set n "" for {set level -1} {1} {incr level -1} { set p [info level $level] if {[lindex $p 0] eq "next"} {set n "next:"} break } return [showStack] } filterInfo proc run {{n 20}} { # TODO for now, deactivated, since different configure-semantics leads to very different traces" return for {set i 0} {$i < $n} {incr i} { global FInfo set FInfo "" Class FI FI proc addFilter {classname} { $classname instproc infoFilter args { global FInfo lappend FInfo \ [list callingclass [self callingclass] \ filterreg [self filterreg] \ callingobject [self callingobject] \ callingproc [self callingproc] \ calledproc [self calledproc]] set r [next] lappend FInfo \ [list self [self] proc [self proc] class [self class] \ infoclass [my info class] r $r] return $r } $classname instfilter infoFilter } Class C0 FI addFilter C0 C0 instproc m1 {} { my instvar aa bb cc set cc 1 } Class C1 -superclass C0 C1 instproc init args { my set a 1 my set c 22 next } C1 instproc m1 args { set r [next] my instvar a b cc return $r--${a}--[set cc] } set safedObjFilters [Object info filter] Object instfilter "" C1 c1 Object instfilter $safedObjFilters if {$i == 0} { ::errorCheck "$FInfo" \ "{callingclass {} filterreg {::C0 instfilter infoFilter} callingobject ::filterInfo callingproc run calledproc configure} {callingclass {} filterreg {::C0 instfilter infoFilter} callingobject ::filterInfo callingproc run calledproc residualargs} {self ::c1 proc infoFilter class ::C0 infoclass ::C1 r {}} {self ::c1 proc infoFilter class ::C0 infoclass ::C1 r {}} {callingclass {} filterreg {::C0 instfilter infoFilter} callingobject ::filterInfo callingproc run calledproc init} {callingclass ::C1 filterreg {::C0 instfilter infoFilter} callingobject ::c1 callingproc init calledproc set} {self ::c1 proc infoFilter class ::C0 infoclass ::C1 r 1} {callingclass ::C1 filterreg {::C0 instfilter infoFilter} callingobject ::c1 callingproc init calledproc set} {self ::c1 proc infoFilter class ::C0 infoclass ::C1 r 22} {self ::c1 proc infoFilter class ::C0 infoclass ::C1 r {}}" \ "Wrong filtering of instproc creation C/C1" } else { ::errorCheck "$FInfo" \ "{callingclass {} filterreg {::C0 instfilter infoFilter} callingobject ::filterInfo callingproc run calledproc cleanup} {self ::c1 proc infoFilter class ::C0 infoclass ::C1 r {}} {callingclass {} filterreg {::C0 instfilter infoFilter} callingobject ::filterInfo callingproc run calledproc configure} {callingclass {} filterreg {::C0 instfilter infoFilter} callingobject ::filterInfo callingproc run calledproc residualargs} {self ::c1 proc infoFilter class ::C0 infoclass ::C1 r {}} {self ::c1 proc infoFilter class ::C0 infoclass ::C1 r {}} {callingclass {} filterreg {::C0 instfilter infoFilter} callingobject ::filterInfo callingproc run calledproc init} {callingclass ::C1 filterreg {::C0 instfilter infoFilter} callingobject ::c1 callingproc init calledproc set} {self ::c1 proc infoFilter class ::C0 infoclass ::C1 r 1} {callingclass ::C1 filterreg {::C0 instfilter infoFilter} callingobject ::c1 callingproc init calledproc set} {self ::c1 proc infoFilter class ::C0 infoclass ::C1 r 22} {self ::c1 proc infoFilter class ::C0 infoclass ::C1 r {}}" \ "Wrong filtering of instproc creation C/C1 (b)" } set FInfo "" set result [c1 m1] ::errorCheck $FInfo \ "{callingclass {} filterreg {::C0 instfilter infoFilter} callingobject ::filterInfo callingproc run calledproc m1} {callingclass ::C0 filterreg {::C0 instfilter infoFilter} callingobject ::c1 callingproc m1 calledproc instvar} {self ::c1 proc infoFilter class ::C0 infoclass ::C1 r {}} {callingclass ::C1 filterreg {::C0 instfilter infoFilter} callingobject ::c1 callingproc m1 calledproc instvar} {self ::c1 proc infoFilter class ::C0 infoclass ::C1 r {}} {self ::c1 proc infoFilter class ::C0 infoclass ::C1 r 1--1--1}" \ "Wrong filtering of c1 m1" set FInfo "" ::errorCheck $result \ "1--1--1" "Wrong return result of Filter Example 2 'c1 m1' " Class T0 FI addFilter T0 T0 instproc m {} { set e -0=showStack-1=showCall-2=m-3=m-4=m-5=run-6=run if {[string first $e [showCall]] == -1} { puts stderr "FAILED - Wrong calling stack in T0 m: [showCall]" puts stderr "expected = '$e'" puts stderr "got = '[showCall]'" exit } return [self]-[self proc]-[self class]-[my info class] } Class T1 -superclass T0 T1 instproc m {} { set e 0=showStack-1=showCall-2=m-3=m-4=run-5=run if {[string first $e [showCall]] == -1} { puts stderr "FAILED - Wrong calling stack in T1 m: [showCall]" puts stderr "expected = '$e'" puts stderr "got = '[showCall]'" exit } set r1 before-[self]-[self proc]-[self class]-[my info class] set r2 [next] set r after-[self]-[self proc]-[self class]-[my info class]-${r1}-$r2 } T1 t set FInfo "" set result [t m] ::errorCheck $FInfo \ "{callingclass {} filterreg {::T0 instfilter infoFilter} callingobject ::filterInfo callingproc run calledproc m} {callingclass ::T1 filterreg {::T0 instfilter infoFilter} callingobject ::t callingproc m calledproc info} {self ::t proc infoFilter class ::T0 infoclass ::T1 r ::T1} {callingclass ::T0 filterreg {::T0 instfilter infoFilter} callingobject ::t callingproc m calledproc info} {self ::t proc infoFilter class ::T0 infoclass ::T1 r ::T1} {callingclass ::T1 filterreg {::T0 instfilter infoFilter} callingobject ::t callingproc m calledproc info} {self ::t proc infoFilter class ::T0 infoclass ::T1 r ::T1} {self ::t proc infoFilter class ::T0 infoclass ::T1 r after-::t-m-::T1-::T1-before-::t-m-::T1-::T1-::t-m-::T0-::T1}" \ "Wrong filtering of t m" set FInfo "" ::errorCheck $result \ "after-::t-m-::T1-::T1-before-::t-m-::T1-::T1-::t-m-::T0-::T1" \ "Wrong return result of Filter Example 2 \"t m\" " } c1 destroy for {set i 0} {$i < $n} {incr i} { global InfoTraceResult Object instfilter "" Object InfoTrace InfoTrace proc createInfoTrace cl { $cl instproc infoTraceFilter args { global InfoTraceResult ::set r [next] ::lappend InfoTraceResult [list \ $r-[self]-[self proc]-[self class] \ [my info class]-[self calledproc] \ [self callingproc]-[self callingobject] \ [self callingclass]-[self filterreg]] return $r } $cl instfilter infoTraceFilter } Class ObjectsClass ObjectsClass anObject Class aClass ObjectsClass instproc aProc {} {aClass create anotherObject} InfoTrace createInfoTrace Object set InfoTraceResult "" set r [anObject aProc] if {$i > 0} { ::errorCheck $InfoTraceResult \ "{::aClass-::xotcl::objectInfo-infoTraceFilter-::xotcl::Object {valid options are: args, body, callable, check, children, class, commands, default, filter, filterguard, forward, hasnamespace, info, invar, is, method, methods, mixin, mixinguard, nonposargs, parametercmd, parent, post, pre, precedence, procs, slotobjects, vars-class} info-::anotherObject {::xotcl::Object-::xotcl::Object instfilter infoTraceFilter}} {-::anotherObject-infoTraceFilter-::xotcl::Object ::aClass-cleanup aProc-::anObject {::ObjectsClass-::xotcl::Object instfilter infoTraceFilter}} {::aClass-::xotcl::objectInfo-infoTraceFilter-::xotcl::Object {valid options are: args, body, callable, check, children, class, commands, default, filter, filterguard, forward, hasnamespace, info, invar, is, method, methods, mixin, mixinguard, nonposargs, parametercmd, parent, post, pre, precedence, procs, slotobjects, vars-class} info-::anotherObject {::xotcl::Object-::xotcl::Object instfilter infoTraceFilter}} {-::anotherObject-infoTraceFilter-::xotcl::Object ::aClass-residualargs aProc-::anObject {::ObjectsClass-::xotcl::Object instfilter infoTraceFilter}} {::aClass-::xotcl::objectInfo-infoTraceFilter-::xotcl::Object {valid options are: args, body, callable, check, children, class, commands, default, filter, filterguard, forward, hasnamespace, info, invar, is, method, methods, mixin, mixinguard, nonposargs, parametercmd, parent, post, pre, precedence, procs, slotobjects, vars-class} info-::anotherObject {::xotcl::Object-::xotcl::Object instfilter infoTraceFilter}} {-::anotherObject-infoTraceFilter-::xotcl::Object ::aClass-configure aProc-::anObject {::ObjectsClass-::xotcl::Object instfilter infoTraceFilter}} {::aClass-::xotcl::objectInfo-infoTraceFilter-::xotcl::Object {valid options are: args, body, callable, check, children, class, commands, default, filter, filterguard, forward, hasnamespace, info, invar, is, method, methods, mixin, mixinguard, nonposargs, parametercmd, parent, post, pre, precedence, procs, slotobjects, vars-class} info-::anotherObject {::xotcl::Object-::xotcl::Object instfilter infoTraceFilter}} {-::anotherObject-infoTraceFilter-::xotcl::Object ::aClass-init aProc-::anObject {::ObjectsClass-::xotcl::Object instfilter infoTraceFilter}} {::xotcl::Class-::xotcl::classInfo-infoTraceFilter-::xotcl::Object {valid options are: args, body, callable, check, children, class, classchildren, classparent, commands, default, filter, filterguard, forward, hasnamespace, heritage, info, instances, instargs, instbody, instcommands, instdefault, instfilter, instfilterguard, instforward, instinvar, instmixin, instmixinguard, instmixinof, instnonposargs, instparametercmd, instpost, instpre, instprocs, invar, is, method, methods, mixin, mixinguard, mixinof, nonposargs, parameter, parametercmd, parent, post, pre, precedence, procs, slotobjects, slots, subclass, superclass, vars-class} info-::aClass {::xotcl::Class-::xotcl::Object instfilter infoTraceFilter}} {::anotherObject-::aClass-infoTraceFilter-::xotcl::Object ::xotcl::Class-recreate aProc-::anObject {::ObjectsClass-::xotcl::Object instfilter infoTraceFilter}} {::xotcl::Class-::xotcl::classInfo-infoTraceFilter-::xotcl::Object {valid options are: args, body, callable, check, children, class, classchildren, classparent, commands, default, filter, filterguard, forward, hasnamespace, heritage, info, instances, instargs, instbody, instcommands, instdefault, instfilter, instfilterguard, instforward, instinvar, instmixin, instmixinguard, instmixinof, instnonposargs, instparametercmd, instpost, instpre, instprocs, invar, is, method, methods, mixin, mixinguard, mixinof, nonposargs, parameter, parametercmd, parent, post, pre, precedence, procs, slotobjects, slots, subclass, superclass, vars-class} info-::aClass {::xotcl::Class-::xotcl::Object instfilter infoTraceFilter}} {::anotherObject-::aClass-infoTraceFilter-::xotcl::Object ::xotcl::Class-create aProc-::anObject {::ObjectsClass-::xotcl::Object instfilter infoTraceFilter}} {::ObjectsClass-::xotcl::objectInfo-infoTraceFilter-::xotcl::Object {valid options are: args, body, callable, check, children, class, commands, default, filter, filterguard, forward, hasnamespace, info, invar, is, method, methods, mixin, mixinguard, nonposargs, parametercmd, parent, post, pre, precedence, procs, slotobjects, vars-class} info-::anObject {::xotcl::Object-::xotcl::Object instfilter infoTraceFilter}} {::anotherObject-::anObject-infoTraceFilter-::xotcl::Object ::ObjectsClass-aProc run-::filterInfo {-::xotcl::Object instfilter infoTraceFilter}}" \ "FilterInfo InfoTrace: Filter information wrong (b)" } else { ::errorCheck $InfoTraceResult \ "{::xotcl::Class-::xotcl::classInfo-infoTraceFilter-::xotcl::Object {valid options are: args, body, callable, check, children, class, classchildren, classparent, commands, default, filter, filterguard, forward, hasnamespace, heritage, info, instances, instargs, instbody, instcommands, instdefault, instfilter, instfilterguard, instforward, instinvar, instmixin, instmixinguard, instmixinof, instnonposargs, instparametercmd, instpost, instpre, instprocs, invar, is, method, methods, mixin, mixinguard, mixinof, nonposargs, parameter, parametercmd, parent, post, pre, precedence, procs, slotobjects, slots, subclass, superclass, vars-class} info-::aClass {::xotcl::Class-::xotcl::Object instfilter infoTraceFilter}} {::anotherObject-::aClass-infoTraceFilter-::xotcl::Object ::xotcl::Class-alloc aProc-::anObject {::ObjectsClass-::xotcl::Object instfilter infoTraceFilter}} {::aClass-::xotcl::objectInfo-infoTraceFilter-::xotcl::Object {valid options are: args, body, callable, check, children, class, commands, default, filter, filterguard, forward, hasnamespace, info, invar, is, method, methods, mixin, mixinguard, nonposargs, parametercmd, parent, post, pre, precedence, procs, slotobjects, vars-class} info-::anotherObject {::xotcl::Object-::xotcl::Object instfilter infoTraceFilter}} {-::anotherObject-infoTraceFilter-::xotcl::Object ::aClass-residualargs aProc-::anObject {::ObjectsClass-::xotcl::Object instfilter infoTraceFilter}} {::aClass-::xotcl::objectInfo-infoTraceFilter-::xotcl::Object {valid options are: args, body, callable, check, children, class, commands, default, filter, filterguard, forward, hasnamespace, info, invar, is, method, methods, mixin, mixinguard, nonposargs, parametercmd, parent, post, pre, precedence, procs, slotobjects, vars-class} info-::anotherObject {::xotcl::Object-::xotcl::Object instfilter infoTraceFilter}} {-::anotherObject-infoTraceFilter-::xotcl::Object ::aClass-configure aProc-::anObject {::ObjectsClass-::xotcl::Object instfilter infoTraceFilter}} {::aClass-::xotcl::objectInfo-infoTraceFilter-::xotcl::Object {valid options are: args, body, callable, check, children, class, commands, default, filter, filterguard, forward, hasnamespace, info, invar, is, method, methods, mixin, mixinguard, nonposargs, parametercmd, parent, post, pre, precedence, procs, slotobjects, vars-class} info-::anotherObject {::xotcl::Object-::xotcl::Object instfilter infoTraceFilter}} {-::anotherObject-infoTraceFilter-::xotcl::Object ::aClass-init aProc-::anObject {::ObjectsClass-::xotcl::Object instfilter infoTraceFilter}} {::xotcl::Class-::xotcl::classInfo-infoTraceFilter-::xotcl::Object {valid options are: args, body, callable, check, children, class, classchildren, classparent, commands, default, filter, filterguard, forward, hasnamespace, heritage, info, instances, instargs, instbody, instcommands, instdefault, instfilter, instfilterguard, instforward, instinvar, instmixin, instmixinguard, instmixinof, instnonposargs, instparametercmd, instpost, instpre, instprocs, invar, is, method, methods, mixin, mixinguard, mixinof, nonposargs, parameter, parametercmd, parent, post, pre, precedence, procs, slotobjects, slots, subclass, superclass, vars-class} info-::aClass {::xotcl::Class-::xotcl::Object instfilter infoTraceFilter}} {::anotherObject-::aClass-infoTraceFilter-::xotcl::Object ::xotcl::Class-create aProc-::anObject {::ObjectsClass-::xotcl::Object instfilter infoTraceFilter}} {::ObjectsClass-::xotcl::objectInfo-infoTraceFilter-::xotcl::Object {valid options are: args, body, callable, check, children, class, commands, default, filter, filterguard, forward, hasnamespace, info, invar, is, method, methods, mixin, mixinguard, nonposargs, parametercmd, parent, post, pre, precedence, procs, slotobjects, vars-class} info-::anObject {::xotcl::Object-::xotcl::Object instfilter infoTraceFilter}} {::anotherObject-::anObject-infoTraceFilter-::xotcl::Object ::ObjectsClass-aProc run-::filterInfo {-::xotcl::Object instfilter infoTraceFilter}}" \ "FilterInfo InfoTrace: Filter information wrong" } } Object instfilter {} global fUplevelResult set fUplevelResult "" Class FilterMix FilterMix instproc calls args { global fUplevelResult set calledproc [uplevel 1 {self calledproc}] set calledclass [uplevel 1 {self calledclass}] append fUplevelResult "-[self class]-[self proc]-$calledproc-$calledclass" } Class FilterCL -instmixin FilterMix FilterCL instproc filterA args { global fUplevelResult append fUplevelResult -[self class]-[self proc]-[self calledproc]-[self calledclass] my calls next } FilterCL instproc fclproc args {} FilterCL instfilter filterA FilterCL fcl fcl fclproc # ::errorCheck $fUplevelResult "-::FilterCL-filterA-configure-::xotcl::Object-::FilterMix-calls-configure-::xotcl::Object-::FilterCL-filterA-init-::xotcl::Object-::FilterMix-calls-init-::xotcl::Object-::FilterCL-filterA-fclproc-::FilterCL-::FilterMix-calls-fclproc-::FilterCL" "Filter/Mixin Info Uplevel Test" } @ TestX nextTest { description {Regression test object testing the next primitive.} } TestX nextTest -proc run {{n 20}} { for {set i 0} {$i < $n} {incr i} { global result infoNext set result "" set infoNext "" Class X X instproc n {} { append ::infoNext " [self]+[self class]->[self proc]*<[self next]>" next } Class Y -superclass X Y instproc m {} { append ::infoNext " [self]+[self class]->[self proc]*<[self next]>" next } Y instproc n {} { append ::infoNext " [self]+[self class]->[self proc]*<[self next]>" next } Y y y m y n y proc n {} { append ::infoNext " [self]+[self class]->[self proc]*<[self next]>" next } y n ::errorCheck $infoNext " ::y+::Y->m*<> ::y+::Y->n*<::X instproc n> ::y+::X->n*<> ::y+->n*<::Y instproc n> ::y+::Y->n*<::X instproc n> ::y+::X->n*<>" \ "simple self next test" set infoNext "" set result "" Class A A instproc m arg { global result infoNext set result ${result}-[self]-$arg } Class B -superclass A B instproc m arg { global result infoNext set result ${result}-[self]-$arg append infoNext " 2[self]+[self class]->[self proc]*<[self next]>" next } B b0 -m 1 B b -m "" ::errorCheck $result "-::b0-1-::b0-1-::b--::b-" \ "Next Test A/B -- Wrong result" set result "" Class X X instproc init args { global result infoNext set result ${result}-[self]-$args append infoNext " 1[self]+[self class]->[self proc]*<[self next]>" next } X instproc test {} { global result set result ${result}-[self] } X x -test ::errorCheck $result "-::x-::x-" \ "Next Test X -- Wrong result" ::errorCheck $infoNext " 2::b0+::B->m*<::A instproc m> 2::b+::B->m*<::A instproc m> 1::x+::X->init*<::xotcl::Object instproc init>" \ "self next test 2" X destroy x destroy A destroy B destroy b0 destroy b destroy Class MIX MIX instproc mProc args { global result append result "[self]-[self class]-[self next]" next } Object o -mixin MIX o proc mProc args { global result append result "[self]-[self class]-[self next]" } set result "" o mProc ::errorCheck $result "::o-::MIX-::o proc mProc::o--" \ "Next Test Proc & Mixin" o destroy; MIX destroy } } @ TestX init_params { description { Regression test object testing the parameter instance method, the init dash '-' and constructor calling. } } TestX init_params -proc run {{n 20}} { for {set i 0} {$i < $n} {incr i} { global dashResult set dashResult "" set dashResultEnd "" Class A A instproc t0 {} { global dashResult set dashResult ${dashResult}*[self proc] } A instproc t1 {a} { global dashResult set dashResult ${dashResult}*[self proc]-$a } A instproc t2 {a b} { global dashResult set dashResult ${dashResult}*[self proc]-${a}-$b } A instproc t3 {a b c} { global dashResult set dashResult ${dashResult}*[self proc]-${a}-${b}-$c } A a set dashResultEnd "[A a -t0] $dashResultEnd" A a set dashResultEnd "[A a -t1 1] $dashResultEnd" A a set dashResultEnd "[A a -t2 1 2] $dashResultEnd" A a set dashResultEnd "[A a -t3 1 2 3] $dashResultEnd" A a set dashResultEnd "[A a -t0 -t0 -t3 1 2 3 -t0 -t1 1 -t1 1 -t0] $dashResultEnd" catch {A a t} ::errorCheck $dashResult \ "*t0*t1-1*t2-1-2*t3-1-2-3*t0*t0*t3-1-2-3*t0*t1-1*t1-1*t0" \ "Init Dash Test fails" ::errorCheck $dashResultEnd \ "::a ::a ::a ::a ::a " \ "Init Dash Test fails -- result" Class Foo -parameter {{match -exact}} Foo ff ::errorCheck [ff match] "-exact" "default with dash" } # parameter/defaults test proc ::cmd {a b} { return in-cmd-${a}-${b} } global parameterResult global initResult for {set i 0} {$i < $n} {incr i} { Class O -parameter { {a 0} {b {[cmd 3 4]}} c d {e 3} {Self [self]} } O instproc init args { global initResult set initResult ${initResult}-[self]-[self class]-[self proc]--$args next } O instproc show {} { global parameterResult set parameterResult [self] foreach v [lsort [my info vars]] { set parameterResult ${parameterResult}-${v}=<[my set ${v}]> } } Class Meta -superclass Class Meta instproc create args {next; return Meta-create} Meta C -superclass O -parameter {a {b ""} {c 1}} Class D -parameter {a {c 1}} -superclass O # create on class should not be called D instproc create args {next; return D-create} D instproc init args { global initResult append initResult -[self]-[self class]-[self proc]--$args next } D instproc test i { ::errorCheck [my set c]-[my set a] "2-0" "Wrong order of init call" } set parameterResult "" set initResult "" C c0 -show ::errorCheck $parameterResult "::c0-Self=<::c0>-b=<>-c=<1>-e=<3>" \ "C c0 parameter Test failed" if {$i == 0} { ::errorCheck $initResult "-::c0-::O-init--" \ "C c0 parameter init Test failed" } else { ::errorCheck $initResult "-::c0-::O-init--" \ "C c0 parameter init Test failed (b)" } set parameterResult "" set initResult "" set r [C c1 -c 2 -init a b c -a 1 -show] ::errorCheck $parameterResult "::c1-Self=<::c1>-a=<1>-b=<>-c=<2>-e=<3>" \ "C c1 parameter Test failed (b)" ::errorCheck $initResult "-::c1-::O-init--a b c" \ "C c1 parameter init Test failed" set parameterResult "" set initResult "" set r $r-[D d1 -c 2 -a 0 -init a b c -test $i -a 1 -show] ::errorCheck $parameterResult "::d1-Self=<::d1>-a=<1>-b=-c=<2>-e=<3>" \ "D d1 parameter Test failed" if {$i == 0} { ::errorCheck $initResult "-::d1-::D-init--a b c-::d1-::O-init--a b c" \ "D d1 parameter init Test failed" } else { ::errorCheck $initResult "-::d1-::D-init--a b c-::d1-::O-init--a b c" \ "D d1 parameter init Test failed (b)" } ::errorCheck $r "Meta-create-::d1" "User defined object creation failed" } } @ TestX mixinTest { description { Regression test object testing per-object mixins. } } TestX mixinTest -proc run {{n 10}} { global mixinResult set mixinResult "" Class Agent Agent instproc moveAgent {x y} { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] next } Agent instproc otherProc {} { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] next } Class InteractiveAgent -superclass Agent InteractiveAgent instproc moveAgent {x y} { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] next } Class InteractiveAgent2 -superclass Agent InteractiveAgent2 instproc moveAgent {x y} { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] next } Class InteractiveAgent3 -superclass Agent InteractiveAgent3 instproc moveAgent {x y} { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] next } # Addition-Classes Class MovementLog MovementLog instproc moveAgent {x y} { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] my otherProc next } MovementLog instproc otherProc {} { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] next } Class MovementTest MovementTest instproc moveAgent {x y} { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] next } InteractiveAgent i1; InteractiveAgent i2 i1 mixin MovementLog i2 mixin MovementTest InteractiveAgent2 instmixin {MovementLog MovementTest} InteractiveAgent3 instmixin MovementTest InteractiveAgent2 i3; InteractiveAgent3 i4; ::errorCheck [InteractiveAgent2 info instmixin] "::MovementLog ::MovementTest" "Mixin: info instmixin" i2 moveAgent 1 2 ::errorCheck $mixinResult \ "-::i2-moveAgent-::MovementTest-::i2-moveAgent-::InteractiveAgent-::i2-moveAgent-::Agent" \ "Mixin: 'i2 moveAgent 1 2' failed" set mixinResult "" i1 moveAgent 3 4 ::errorCheck $mixinResult \ "-::i1-moveAgent-::MovementLog-::i1-otherProc-::MovementLog-::i1-otherProc-::Agent-::i1-moveAgent-::InteractiveAgent-::i1-moveAgent-::Agent" \ "Mixin: 'i1 moveAgent 3 4' failed" set mixinResult "" i3 moveAgent 3 4 ::errorCheck $mixinResult \ "-::i3-moveAgent-::MovementLog-::i3-otherProc-::MovementLog-::i3-otherProc-::Agent-::i3-moveAgent-::MovementTest-::i3-moveAgent-::InteractiveAgent2-::i3-moveAgent-::Agent" \ "Instmixin: 'i3 moveAgent 3 4' failed" set mixinResult "" i4 moveAgent 3 4 ::errorCheck $mixinResult \ "-::i4-moveAgent-::MovementTest-::i4-moveAgent-::InteractiveAgent3-::i4-moveAgent-::Agent" \ "Instmixin: 'i4 moveAgent 3 4' failed" i4 mixin {MovementTest MovementLog} i4 proc aaa args {puts TEST} ::errorCheck [i4 info precedence] "::MovementTest ::MovementLog ::InteractiveAgent3 ::Agent ::xotcl::Object" "precedence i4" ::errorCheck [i4 procsearch moveAgent] "::MovementTest instproc moveAgent" "procsearch1" ::errorCheck [i4 procsearch aaa] "::i4 proc aaa" "procsearch2" ::errorCheck [i4 procsearch set] "::xotcl::Object instcmd set" "procsearch3" Class create A A instproc f1 {} {puts hu} A instforward f2 puts hu A instparametercmd f5 A create a0 a0 proc f3 {} {puts hu} a0 forward f4 puts hu a0 parametercmd f6 ::errorCheck [a0 procsearch f1] "::A instproc f1" procsearch-1 ::errorCheck [a0 procsearch f2] "::A instforward f2" procsearch-2 ::errorCheck [a0 procsearch f3] "::a0 proc f3" procsearch-3 ::errorCheck [a0 procsearch f4] "::a0 forward f4" procsearch-4 ::errorCheck [a0 procsearch f5] "::A instparametercmd f5" procsearch-4 ::errorCheck [a0 procsearch f6] "::a0 parametercmd f6" procsearch-6 ::errorCheck [a0 procsearch set] "::xotcl::Object instcmd set" procsearch-6 ::errorCheck [catch {a0 parametercmd f6 puts}] 1 "parametercmd with wrong args returns error" set mixinResult "" i4 moveAgent 5 6 ::errorCheck $mixinResult \ -::i4-moveAgent-::MovementTest-::i4-moveAgent-::MovementLog-::i4-otherProc-::MovementLog-::i4-otherProc-::Agent-::i4-moveAgent-::InteractiveAgent3-::i4-moveAgent-::Agent \ "Instmixin: 'i4 moveAgent 5 6' failed" Class A A instproc test {} { global mixinResult set mixinResult "test" i1 moveAgent 3 4 } A a a test ::errorCheck $mixinResult \ "test-::i1-moveAgent-::MovementLog-::i1-otherProc-::MovementLog-::i1-otherProc-::Agent-::i1-moveAgent-::InteractiveAgent-::i1-moveAgent-::Agent" \ "Mixin: 'a test' failed" i2 mixin {MovementLog MovementTest} set mixinResult "" i2 moveAgent a b ::errorCheck $mixinResult \ "-::i2-moveAgent-::MovementLog-::i2-otherProc-::MovementLog-::i2-otherProc-::Agent-::i2-moveAgent-::MovementTest-::i2-moveAgent-::InteractiveAgent-::i2-moveAgent-::Agent" \ "Mixin: 'i2 moveAgent a b' failed" ::errorCheck "[i2 info mixin]-[i1 info mixin]-[a info mixin]" \ "::MovementLog ::MovementTest-::MovementLog-" \ "Mixin: Info failed" ::errorCheck "[i2 ismixin MovementTest]-[i4 ismixin MovementTest]-[a ismixin MovementTest]-[i3 ismixin MovementTest]-[i4 ismixin MovementTest]-[i4 ismixin MovementLog]-[i3 ismixin YXZ]-[i3 ismixin InteractiveAgent]" \ "1-1-0-1-1-1-0-0" \ "'ismixin test' failed" ::errorCheck "[i2 hasclass MovementTest]-[i4 hasclass MovementTest]-[a hasclass MovementTest]-[i3 hasclass MovementTest]-[i4 hasclass MovementTest]-[i4 hasclass MovementLog]-[i3 hasclass YXZ]-[i3 hasclass InteractiveAgent]-[a hasclass A]-[i3 hasclass Agent]" \ "1-1-0-1-1-1-0-0-1-1" \ "'hasclass test' failed" set mixinResult "" i2 mixin "" i2 moveAgent a b ::errorCheck $mixinResult \ "-::i2-moveAgent-::InteractiveAgent-::i2-moveAgent-::Agent" \ "Mixin: remove failed" set mixinResult "" Class A A instproc destroy args { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] next } A instproc y args { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] next } Class B B instproc destroy args { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] next } B instproc y args { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] my mixin "" next } B instproc x args { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] my destroy } A a -mixin B a destroy A a -mixin B a x A a -mixin B a y ::errorCheck $mixinResult \ "-::a-destroy-::B-::a-destroy-::A-::a-x-::B-::a-destroy-::B-::a-destroy-::A-::a-y-::B-::a-y-::A" \ "Mixin: destroy failed" A instmixin B set mixinResult "" A a2 a2 destroy A a2 a2 x A a2 a2 y ::errorCheck $mixinResult \ "-::a2-destroy-::B-::a2-destroy-::A-::a2-x-::B-::a2-destroy-::B-::a2-destroy-::A-::a2-y-::B-::a2-y-::A" \ "Instmixin: destroy failed" # mixin Test: calls the mixins and a proc of the object set ::mixinResult "" Class A Class B A instproc a {} {set ::mixinResult ${::mixinResult}-[self]-[self class]-[self proc];next} B instproc a {} {set ::mixinResult ${::mixinResult}-[self]-[self class]-[self proc]; next} A d -mixin B d proc a {} {set ::mixinResult ${::mixinResult}-[self]-[self class]-[self proc]; next} d a ::errorCheck $::mixinResult \ "-::d-::B-a-::d--a-::d-::A-a" \ "Mixin: calling of object's proc" set mixinResult "" d mixin {} A instmixin B d a ::errorCheck $::mixinResult \ "-::d-::B-a-::d--a-::d-::A-a" \ "Instmixin: calling of object's proc" # # combining filters with mixins # set ::traceResults "" Class M1 M1 instproc test args { global traceResults lappend traceResults "[self] [self proc] [self class]" next } Class M2 M2 instproc test args { global traceResults lappend traceResults "[self] [self proc] [self class]" next } Class A A instproc test args { global traceResults lappend traceResults "[self] [self proc] [self class]" next } A instproc f1 args { global traceResults lappend traceResults "[self] [self proc] [self class]" next } A instproc f2 args { global traceResults lappend traceResults "[self] [self proc] [self class]" next } A a A instmixin {M1 M2} A instfilter {f1 f2} a test ::errorCheck $::traceResults \ "{::a f1 ::A} {::a f2 ::A} {::a test ::M1} {::a test ::M2} {::a test ::A}" \ "Combining mixins and filters" # mixin recursion test set mixinResult "" Class Computation Computation instproc compute args { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] # abstract interface for computations } Class ComputationOutput -superclass Computation Computation instproc compute args { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] return $args } Class RecFacultyMixin RecFacultyMixin instproc compute args { global mixinResult set mixinResult ${mixinResult}-[self]-[self proc]-[self class] set n [lindex $args 0] set callingClass - #puts stderr [self class]=[uplevel 1 self class]-[self callingclass] #catch {set callingClass [uplevel 1 self class]} set callingClass [self callingclass] if {$n == 0} { set result 1 } else { set f [my compute [expr {$n - 1}] x] set result [expr {$n * $f}] } if {$callingClass != [self class]} { next $result return $result } else { return $result } } ComputationOutput faculty faculty mixin RecFacultyMixin ::errorCheck [faculty compute 3] 6 \ "Mixin: faculty wrong result" ::errorCheck $mixinResult \ "-::faculty-compute-::RecFacultyMixin-::faculty-compute-::RecFacultyMixin-::faculty-compute-::RecFacultyMixin-::faculty-compute-::RecFacultyMixin-::faculty-compute-::Computation" \ "Mixin: faculty failed" set mixinResult "" ComputationOutput faculty ComputationOutput instmixin RecFacultyMixin ::errorCheck [faculty compute 3] 6 "Mixin: faculty wrong result" ::errorCheck $mixinResult \ "-::faculty-compute-::RecFacultyMixin-::faculty-compute-::RecFacultyMixin-::faculty-compute-::RecFacultyMixin-::faculty-compute-::RecFacultyMixin-::faculty-compute-::Computation" \ "Mixin: faculty failed" set ::mixinResult "" set ::calling "" Class GrObject GrObject instproc draw args { lappend ::mixinResult [list grObject [self] [self proc] [self class]] lappend ::calling [list grObject [self proc]: [self callingobject] [self callingclass] [self callingproc] [self next]] } Class Image -superclass GrObject Image instproc draw args { lappend ::mixinResult [list image [self] [self proc] [self class]] lappend ::calling [list image [self proc]: [self callingobject] [self callingclass] [self callingproc] [self next]] next } Class MenuDecorator MenuDecorator instproc draw args { lappend ::mixinResult [list m1 [self] [self proc] [self class]] lappend ::calling [list m1 [self proc]: [self callingobject] [self callingclass] [self callingproc] [self next]] next } Class ScrollBarDecorator ScrollBarDecorator instproc draw args { lappend ::mixinResult [list m2 [self] [self proc] [self class]] lappend ::calling [list m2 [self proc]: [self callingobject] [self callingclass] [self callingproc] [self next]] next } Image mainImage -mixin {MenuDecorator ScrollBarDecorator} Image zoom -mixin {ScrollBarDecorator} Object instproc f args { if {[self calledproc] ne "filter"} { lappend ::mixinResult [list filter [self] [self proc] [self class]] lappend ::calling [list filter [self proc]: [self callingobject] [self callingclass] [self callingproc] [self calledproc] [self next]] } return [next] } Object instfilter f mainImage draw zoom draw Object instfilter "" ::errorCheck $::calling \ "{filter f: ::mixinTest {} run draw {::MenuDecorator instproc draw}} {m1 draw: ::mixinTest {} run {::ScrollBarDecorator instproc draw}} {m2 draw: ::mixinTest {} run {::Image instproc draw}} {image draw: ::mixinTest {} run {::GrObject instproc draw}} {grObject draw: ::mixinTest {} run {}} {filter f: ::mixinTest {} run draw {::ScrollBarDecorator instproc draw}} {m2 draw: ::mixinTest {} run {::Image instproc draw}} {image draw: ::mixinTest {} run {::GrObject instproc draw}} {grObject draw: ::mixinTest {} run {}} {filter f: ::mixinTest {} run instfilter {::xotcl::Class instforward instfilter}}" \ "Mixin: Calling-Obj/Cl/Proc failed" # ::errorCheck $::calling \ # "{filter f: ::mixinTest {} run draw {::MenuDecorator method draw}} {m1 draw: ::mixinTest {} run {::ScrollBarDecorator method draw}} {m2 draw: ::mixinTest {} run {::Image method draw}} {image draw: ::mixinTest {} run {::GrObject method draw}} {grObject draw: ::mixinTest {} run {}} {filter f: ::mixinTest {} run draw {::ScrollBarDecorator method draw}} {m2 draw: ::mixinTest {} run {::Image method draw}} {image draw: ::mixinTest {} run {::GrObject method draw}} {grObject draw: ::mixinTest {} run {}} {filter f: ::mixinTest {} run instfilter {::xotcl::Class forward instfilter}}" \ # "Mixin: Calling-Obj/Cl/Proc failed" ::errorCheck $::mixinResult \ "{filter ::mainImage f ::xotcl::Object} {m1 ::mainImage draw ::MenuDecorator} {m2 ::mainImage draw ::ScrollBarDecorator} {image ::mainImage draw ::Image} {grObject ::mainImage draw ::GrObject} {filter ::zoom f ::xotcl::Object} {m2 ::zoom draw ::ScrollBarDecorator} {image ::zoom draw ::Image} {grObject ::zoom draw ::GrObject} {filter ::xotcl::Object f ::xotcl::Object}" \ "Mixin: Filter failed" set ::mixinResult "" set ::calling "" Class InfoTrace2 InfoTrace2 instproc infoTraceFilter2 args { lappend ::calling \ self [self] \ "self proc" [self proc] \ "self class" [self class] \ "self calledproc" [self calledproc] \ "self callingproc" [self callingproc] \ "self callingobject" [self callingobject] \ "self callingclass" [self callingclass] \ "self filterreg" [self filterreg] \ "self next" [self next] next } Class CallingObjectsClass CallingObjectsClass create callingObject Class FilterRegClass -superclass InfoTrace2 Class FilteredObjectsClass -superclass FilterRegClass FilteredObjectsClass filteredObject CallingObjectsClass instproc callingProc args { filteredObject set someVar 0 } FilterRegClass instfilter infoTraceFilter2 callingObject callingProc # ::errorCheck $::calling \ # {self ::filteredObject {self proc} infoTraceFilter2 {self class} ::InfoTrace2 {self calledproc} set {self callingproc} callingProc {self callingobject} ::callingObject {self callingclass} ::CallingObjectsClass {self filterreg} {::FilterRegClass instfilter infoTraceFilter2} {self next} {::xotcl::Object instcmd set}} \ # "call stack info" ::errorCheck $::calling \ {self ::filteredObject {self proc} infoTraceFilter2 {self class} ::InfoTrace2 {self calledproc} set {self callingproc} callingProc {self callingobject} ::callingObject {self callingclass} ::CallingObjectsClass {self filterreg} {::FilterRegClass filter infoTraceFilter2} {self next} {::xotcl::Object instcmd set}} \ "call stack info" Class M1; Class M2; Class M3; Class M4 Class A; Class B -superclass A; B b A instmixin {M1 M2} B instmixin {M3 M1 M1 M4} b mixin {M1 M1 M4} ::errorCheck [b info mixin] "::M1 ::M4" "Mixin Info: -no dups1" ::errorCheck [b info precedence] "::M1 ::M4 ::M3 ::M2 ::B ::A ::xotcl::Object" "Mixin Info: -no dups2" ::errorCheck [b info mixin -order] "::M1 ::M4 ::M3 ::M2" "Mixin Info: -order option1" ::errorCheck [B info instmixin]-[b info mixin] "::M3 ::M1 ::M4-::M1 ::M4" "Mixin Info: no duplicates" B instmixin {} ::errorCheck [b info mixin -order] "::M1 ::M4 ::M2" "Mixin Info: -order option2" set ::r "" Class X11 -instproc test {args} { lappend ::r [self class] next } Class X12 -instproc test {args} { lappend ::r [self class] next } Class X -instmixin {X11 X12} -instproc test {args} { lappend ::r [self class] next } Class Y -instmixin X Y create y -test X create x -test ::errorCheck $::r [list ::X11 ::X12 ::X ::X11 ::X12 ::X] \ {transitive mixin} unset ::r # test for MixinRemoveFromMixinStack, MixinRemoveFromCmdPtr, # MixinRemoveOnObjFromCmdPtr Class A A instproc x {} {B destroy; next} Class B B instproc x {} {next} Class C C instproc x {} {next} Object o -mixin {A B C} o proc x {} {return x} ::errorCheck [o x] {x} {mixin destroy on stack} o destroy # testing transitive mixins; should be in both cases the same Class IM Class M Object o -mixin M M instmixin IM ::errorCheck [o info precedence] {::IM ::M ::xotcl::Object} \ {trans. mixin precedence 1} Object o -mixin M ::errorCheck [o info precedence] {::IM ::M ::xotcl::Object} \ {trans. mixin precedence 2} o destroy } @ TestX procsearchTest { description { Regression test for procsearch } } TestX procsearchTest -proc run {{n 10}} { Class M -instproc foo args {puts m;next} Object o -mixin M -proc foo args {puts o;next} ::errorCheck [o procsearch foo] "::M instproc foo" "mixin before proc in procsearch" M destroy o destroy Class CC -instproc foo args {puts CC;next} CC create c -proc foo args {puts c;next} ::errorCheck [c procsearch foo] "::c proc foo" "proc before instproc in procsearch" CC destroy c destroy } @ TestX mixinInheritanceTest { description { Regression test object testing per-object mixin inheritance. } } TestX mixinInheritanceTest -proc run {{n 10}} { for {set i 0} {$i < $n} {incr i} { global mixinResult set mixinResult "" Class A Class B Class C -superclass {A B} Class GeneralMixin Class RefinedMixin1 -superclass GeneralMixin Class RefinedMixin2 -superclass GeneralMixin Class AppMixin1 -superclass {RefinedMixin1 RefinedMixin2} Class AppMixin2 -superclass {RefinedMixin2 RefinedMixin1} Class AppMixin3 -superclass {RefinedMixin1} A instproc aProc args { global mixinResult; ::set mixinResult "$mixinResult [self class]" return $args } B instproc aProc args { global mixinResult; ::set mixinResult "$mixinResult [self class]" return $args } C instproc aProc args { global mixinResult; ::set mixinResult "$mixinResult [self class]" return [next "$args [self class]"] } GeneralMixin instproc aProc args { global mixinResult; ::set mixinResult "$mixinResult [self class]" return [next "$args [self class]"] } RefinedMixin1 instproc aProc args { global mixinResult; ::set mixinResult "$mixinResult [self class]" return [next "$args [self class]"] } RefinedMixin2 instproc aProc args { global mixinResult; ::set mixinResult "$mixinResult [self class]" return [next "$args [self class]"] } AppMixin1 instproc aProc args { global mixinResult; ::set mixinResult "$mixinResult [self class]" return [next "$args [self class]"] } AppMixin1 mixinInstance set r [mixinInstance aProc ARGS1 ARGS2] ::errorCheck $mixinResult \ " ::AppMixin1 ::RefinedMixin1 ::RefinedMixin2 ::GeneralMixin" \ "Mixin inheritance: mixinInstance aProc" set mixinResult "" AppMixin3 mixinInstance2 set r [mixinInstance2 aProc ARGS1 ARGS2] ::errorCheck $mixinResult \ " ::RefinedMixin1 ::GeneralMixin" \ "Mixin inheritance: mixinInstance2 aProc" set mixinResult "" A a a mixin AppMixin1 set r [a aProc ARGS1 ARGS2] ::errorCheck $mixinResult \ " ::AppMixin1 ::RefinedMixin1 ::RefinedMixin2 ::GeneralMixin ::A" \ "Mixin inheritance: a aProc" ::errorCheck $r \ "{{{{ARGS1 ARGS2 ::AppMixin1} ::RefinedMixin1} ::RefinedMixin2} ::GeneralMixin}" \ "Mixin inheritance result: a aProc" A a A instmixin AppMixin1 set mixinResult "" set r [a aProc ARGS1 ARGS2] ::errorCheck $mixinResult \ " ::AppMixin1 ::RefinedMixin1 ::RefinedMixin2 ::GeneralMixin ::A" \ "Instmixin inheritance: a aProc" ::errorCheck $r \ "{{{{ARGS1 ARGS2 ::AppMixin1} ::RefinedMixin1} ::RefinedMixin2} ::GeneralMixin}" \ "Instmixin inheritance: a aProc" set mixinResult "" C c c mixin {AppMixin3 AppMixin2} ::errorCheck [c info precedence] \ "::AppMixin3 ::AppMixin2 ::AppMixin1 ::RefinedMixin1 ::RefinedMixin2 ::GeneralMixin ::C ::A ::B ::xotcl::Object" \ "mixin precedence" set r [c aProc ARGS1 ARGS2] ::errorCheck $mixinResult \ " ::AppMixin1 ::RefinedMixin1 ::RefinedMixin2 ::GeneralMixin ::C ::A" \ "Mixin/Instmixin inheritance: c aProc" set mixinResult "" A instmixin {} set r [c aProc ARGS1 ARGS2] ::errorCheck $mixinResult \ " ::RefinedMixin2 ::RefinedMixin1 ::GeneralMixin ::C ::A" \ "Mixin/Instmixin inheritance: c aProc" GeneralMixin instproc set args { global mixinResult; ::set mixinResult "$mixinResult [self class]" return [next] } RefinedMixin1 instproc set args { global mixinResult; ::set mixinResult "$mixinResult [self class]" return [next] } AppMixin1 instproc set args { global mixinResult; ::set mixinResult "$mixinResult [self class]" return [next] } global setFilterResult set setFilterResult "" Object instproc setFilter args { global setFilterResult ::append setFilterResult \ -[self]-[self calledproc]-[self calledclass] next } Object instfilter setFilter set mixinResult "" set r [c set setVar 111] ::errorCheck $mixinResult \ " ::RefinedMixin1 ::GeneralMixin" \ "Mixin inheritance: c set" # UNKNOWN PROBLEM 2 # ::errorCheck [c setsetVar] 111 "Mixin inheritance: c set - value" ::errorCheck [c set setVar] 111 "Mixin inheritance: c set - value" set mixinResult "" mixinInstance set setVar 222 ::errorCheck $mixinResult \ " ::AppMixin1 ::RefinedMixin1 ::GeneralMixin" \ "Mixin inheritance: mixinInstance set" ::errorCheck [mixinInstance set setVar] 222\ "Mixin inheritance: mixinInstance set - value" ::errorCheck $setFilterResult \ "-::c-set-::xotcl::Object-::c-set-::xotcl::Object-::mixinInstance-set-::AppMixin1-::mixinInstance-set-::AppMixin1" \ "Mixin inheritance: Wrong classes in mixin set test" Object instfilter "" } # Mixin init test global initResult set initResult "" Class A A instproc init args { my mixin B global initResult append initResult [self class]- next } Class C C instproc init args { global initResult append initResult [self class]- next } Class B -superclass C B instproc init args { global initResult append initResult [self class]- next } Class D D instproc init args { global initResult append initResult [self class]- next } A a ::errorCheck $initResult "::A-" "Mixin init 1 failed" set initResult "" # in A mixin changes to B - before D's constructor must # be called A b -mixin D ::errorCheck $initResult "::D-::A-" "Mixin init 2 failed" Class Mix Mix instproc init args { global initResult append initResult [self class]- next } Class Mix1 Mix1 instproc init args { global initResult append initResult [self class]- next } Class Mix2 Mix2 instproc init args { global initResult append initResult [self class]- next } Class A A instproc init args { global initResult append initResult [self class]- next } Class B B instproc init args { my mixin {Mix Mix1} global initResult append initResult [self class]- next } set initResult "" A a a mixin {Mix Mix1} ::errorCheck $initResult ::A- "Mixin init 3 failed" set initResult "" B b ::errorCheck $initResult ::B- "Mixin init 4 failed" set initResult "" B mixin add Mix2 ::errorCheck $initResult "" "Mixin init 5 failed" set initResult "" A mixin {}; A mixin {Mix Mix1} ::errorCheck $initResult "" "Mixin init 6 failed" set initResult "" A a -mixin {Mix} ::errorCheck $initResult "::Mix-::A-" "Mixin init 7 failed" Class Strategy Strategy instproc init args { global initResult append initResult [self class]- next } Class A A instproc strategy {n} { set a [my info mixin] my mixin [concat $n $a] } A instproc init args { global initResult append initResult [self class]- next } Class Mix1 Mix1 instproc init args { global initResult append initResult [self class]- my strategy Strategy next } set initResult "" A a -mixin Mix1 ::errorCheck $initResult ::Mix1-::A- "Mixin init 8 failed" set initResult "" Class X X instproc init args { append ::initResult " [self]: [self class]->[self proc]" next } Class Y -superclass X Y instproc init args { append ::initResult " [self]: [self class]->[self proc]" next } Class U -superclass X U instproc init args { append ::initResult " [self]: [self class]->[self proc]" next } Class V V instproc init args { append ::initResult " [self]: [self class]->[self proc]" next } Class A A instproc init args { append ::initResult " [self]: [self class]->[self proc]" next } Class B -superclass A B instproc init args { append ::initResult " [self]: [self class]->[self proc]" next } A a a mixin X B b b mixin Y A a2 -mixin Y B b2 -mixin X A a3 -mixin {U V} B b3 b3 mixin {U V} A a3 A instmixin X A instmixin {} B instmixin Y B b3 b3 mixin Y ::errorCheck $initResult \ " ::a: ::A->init ::b: ::B->init ::b: ::A->init ::a2: ::Y->init ::a2: ::X->init ::a2: ::A->init ::b2: ::X->init ::b2: ::B->init ::b2: ::A->init ::a3: ::U->init ::a3: ::X->init ::a3: ::V->init ::a3: ::A->init ::b3: ::B->init ::b3: ::A->init ::a3: ::A->init ::b3: ::Y->init ::b3: ::X->init ::b3: ::B->init ::b3: ::A->init" \ "Mixin init 9 failed" } @ TestX copymove { description {Regression test for copy/move methods} } TestX copymove -proc run {{n 10}} { # Composite Class Composite -superclass Class Composite instproc addop {op} { my instvar ops set ops($op) $op } Composite instproc compositeFilter args { set m [self calledproc] set c [lindex [self filterreg] 0] set r [next] if {[$c exists ops($m)]} { foreach child [my info children] { eval [self]::$child $m $args } } return $r } Composite AbstractNode AbstractNode abstract instproc iterate v AbstractNode addop iterate for {set i 0} {$i < $n} {incr i} { # # class copy # Class X Class X::Y Class X::Y::Z -parameter { {param1 1} {param2 2} } #X::Y::Z metadata add {Version Author Nothing} #X::Y::Z metadata Version {0.0.9} #X::Y::Z metadata Author {Uwe} X::Y::Z instproc defaultValueIP {{a defA} {b defB} v} { return } X::Y::Z proc defaultValueP {{c defC} {d defD} v} { return } X::Y::Z instinvar {{7 > 6} { #a comment } } X::Y::Z instproc assProc {} {puts x} {{5 > 4} { #pre }} {{5 > 4} { #post } } X::Y::Z check {pre post instinvar} foreach C {X X::Y X::Y::Z} { $C instproc q {a b c} { return [self]--[self class]--[self proc]--[next]-- } } X::Y::Z instforward a b X::Y::Z forward c d ::errorCheck [X::Y::Z info instforward -definition a] "b" "define instforward" ::errorCheck [X::Y::Z info forward -definition c] "d" "define forward" X::Y::Z z X::Y::Z copy V V v ::errorCheck "[z q 1 2 3]--[X::Y::Z info class]--[X::Y::Z info classparent]" \ "::z--::X::Y::Z--q------::xotcl::Class--::X::Y"\ "classparent class copy z" ::errorCheck "[z q 1 2 3]--[X::Y::Z info class]--[X::Y::Z info parent]" \ "::z--::X::Y::Z--q------::xotcl::Class--::X::Y"\ "parent class copy z" ::errorCheck "[v q 1 2 3]--[V info class]--[V info classparent]" "::v--::V--q------::xotcl::Class--::"\ "classparent class copy v" ::errorCheck "[v q 1 2 3]--[V info class]--[V info parent]" "::v--::V--q------::xotcl::Class--::"\ "parent class copy v" ::errorCheck "[::cutSpaces [V info parameter]--[v set param1]--[v set param2]]" \ " {param1 1} {param2 2} --1--2" \ "parameter test" if {$::nsf::config(assertions)} { ::errorCheck "[::cutSpaces [V info instinvar]--[V info instpre assProc]--[V info instpost assProc]]"\ "{7 > 6} { #a comment }--{5 > 4} { #pre }--{5 > 4} { #post }"\ "Copy Class Assertions" } ::errorCheck [V info instforward -definition a] "b" "copied instforward" ::errorCheck [V info forward -definition c] "d" "copied forward" #::errorCheck "[V info metadata]--[V metadata Author]--[V metadata Version]--[V metadata Nothing]"\ "Version Author Nothing--Uwe--0.0.9--"\ "Copy Metadata" set df1 [V info default defaultValueP v dfv1] set df2 [V info default defaultValueP c dfv2] set df3 [V info instdefault defaultValueIP v dfv3] set df4 [V info instdefault defaultValueIP a dfv4] ::errorCheck "$df1 $dfv1 $df2 $dfv2 $df3 $dfv3 $df4 $dfv4"\ "0 1 defC 0 1 defA"\ "Copy Default Values" # class hierarchy copy Class O X copy O::X ::errorCheck "[::xotcl::is object O::X]" 1 "O::X is an object" ::errorCheck "[::xotcl::is object O::X::Y]" 1 "O::X::Y is an object" ::errorCheck "[::xotcl::is object O::X::Y::Z]" 1 "O::X::Y::Z is an object" O::X x1; O::X::Y y1; O::X::Y::Z z1 ::errorCheck "[x1 q 1 2 3]--[y1 q 1 2 3]--[z1 q 1 2 3]" \ "::x1--::O::X--q------::y1--::O::X::Y--q------::z1--::O::X::Y::Z--q----"\ "class hierarchy copy" # # object copy # X x -set var1 12 -requireNamespace proc ::x::tclProc args {return tclProc} x proc q {a b c} {return [self]--[self class]--[self proc]--[next]--} x copy y ::errorCheck "[::y::tclProc]--[x q 1 2 3]--[y q 1 2 3]" \ "tclProc--::x----q--::x--::X--q--------::y----q--::y--::X--q------"\ "object copy" # object hierarchy copy x copy x::a x copy x::a::z ::errorCheck "[::x::a::tclProc]--[::x::a::z::a::tclProc]" \ "tclProc--tclProc"\ "object hierarchy copy" Class O O x x invar {{7 > 5} { #a comment }} x proc assProc {} {return} {{5 > 3} { #pre }} {{5 > 4} {#post }} x set var1 12 x proc p1 {} {return [self]-p1} x copy y ::errorCheck "[x p1]--[x set var1]--[::x info class]" "::x-p1--12--::O"\ "Simple Copy - Origin" ::errorCheck "[y p1]--[y set var1]--[::y info class]" "::y-p1--12--::O"\ "Simple Copy - Duplicate" if {$::nsf::config(assertions)} { ::errorCheck "[::cutSpaces [y info invar]--[y info pre assProc]--[y info post assProc]]"\ "{7 > 5} { #a comment }--{5 > 3} { #pre }--{5 > 4} {#post }"\ "Copy Obj Assertions" } # # move test # V destroy X::Y::Z move V V v ::errorCheck "[v q 1 2 3]--[V info class]--[V info classparent]" "::v--::V--q------::xotcl::Class--::"\ "classparent class move v" ::errorCheck "[v q 1 2 3]--[V info class]--[V info parent]" "::v--::V--q------::xotcl::Class--::"\ "parent class move v" ::errorCheck "[::cutSpaces [V info parameter]--[v set param1]--[v set param2]]" \ " {param1 1} {param2 2} --1--2" \ "parameter move test" if {$::nsf::config(assertions)} { ::errorCheck "[::cutSpaces [V info instinvar]--[V info instpre assProc]--[V info instpost assProc]]"\ "{7 > 6} { #a comment }--{5 > 4} { #pre }--{5 > 4} { #post }"\ "Move Class Assertions" } #::errorCheck "[V info metadata]--[V metadata Author]--[V metadata Version]--[V metadata Nothing]"\ "Version Author Nothing--Uwe--0.0.9--"\ "Move Metadata" set df1 [V info default defaultValueP v dfv1] set df2 [V info default defaultValueP c dfv2] set df3 [V info instdefault defaultValueIP v dfv3] set df4 [V info instdefault defaultValueIP a dfv4] ::errorCheck "$df1 $dfv1 $df2 $dfv2 $df3 $dfv3 $df4 $dfv4"\ "0 1 defC 0 1 defA"\ "Move Default Values" ::errorCheck [::info commands X::Y::Z] "" "Moved command still exists" # # copy with filters test # foreach filters {{} compositeFilter} { Composite instfilter $filters AbstractNode instfilter $filters Object commands Class Commands -superclass AbstractNode Class Command -superclass Commands Command instproc init args { my instvar label set label [self] next } Command instproc setlabel {{arg ""}} { my instvar label if {$arg eq ""} { set label } else { set label $arg } } Command instproc setproc {value} { my instvar src set src $value } # prototypes Command commands::cellcmd commands::cellcmd setlabel cell commands::cellcmd setproc {return "coucou" } commands::cellcmd proc x args {return xxx} commands::cellcmd copy toto ::errorCheck [::toto info class] ::Command "Copy with Filter: info class" ::errorCheck [toto set label] cell "Copy with Filter: set var" ::errorCheck [toto x] xxx "Copy with Filter: call proc" ::errorCheck [commands::cellcmd set label] cell \ "Copy with Filter: set var" } Class A Class V Class Z Class B -superclass A Class B1 -superclass {V A Z} A move X ::errorCheck [B info superclass]-[B1 info superclass]-[X info subclass] \ "::X-::V ::X ::Z-::B ::B1" \ "Move of subclass relationship" # # test nonpos args # Class X X proc do0 {arg1 arg2} {puts "$arg1 $arg2"} X proc do1 {-arg1 -arg2} {puts "$arg1 $arg2"} X proc do2 {-arg1 arg2} {puts "$arg1 $arg2"} X proc do3 {arg1 {arg2 d1}} {puts "$arg1 $arg2"} X proc do4 {-arg1 {-arg2 d2}} {puts "$arg1 $arg2"} X proc do5 {{-arg1 d3} {arg2 d4}} {puts "$arg1 $arg2"} X instproc do6 {{-arg1 d3} {arg2 d4}} {puts "$arg1 $arg2"} X copy Y ::errorCheck [lsort [X info procs]] "do0 do1 do2 do3 do4 do5" "check procs to be copied" ::errorCheck [lsort [Y info procs]] "do0 do1 do2 do3 do4 do5" "check copied procs" ::errorCheck [lsort [X info instprocs]] "do6" "check instprocs to be copied" ::errorCheck [lsort [Y info instprocs]] "do6" "check copied instprocs" foreach m [lsort [X info procs]] { foreach info {args nonposargs} { set x [X info $info $m] set y [Y info $info $m] ::errorCheck $x $y "copy nonposargs: $x ne $y" } foreach a [X info args $m] { set vx ""; set vy "" set dx [X info default $m $a vx] set dy [Y info default $m $a vy] ::errorCheck $dx $dy "copy nonposargs: hasdefault $m $a: (source) $dx ne (copy) $dy" if {[info exists dx] && [info exists dy]} { ::errorCheck $vx $vy "copy nonposargs: hasdefault value $vx ne $vy" } } } foreach m [lsort [X info instprocs]] { foreach info {instargs instnonposargs} { set x [X info $info $m] set y [Y info $info $m] ::errorCheck $x $y "copy inst nonposargs: $x ne $y" } foreach a [X info instargs $m] { set vx ""; set vy "" set dx [X info instdefault $m $a vx] set dy [Y info instdefault $m $a vy] ::errorCheck $dx $dy "copy inst nonposargs: hasdefault $dx ne $dy" if {[info exists dx] && [info exists dy]} { ::errorCheck $vx $vy "copy inst nonposargs: hasdefault value $vx ne $vy" } } } Object X X proc do0 {arg1 arg2} {puts "$arg1 $arg2"} X proc do1 {-arg1 -arg2} {puts "$arg1 $arg2"} X proc do2 {-arg1 arg2} {puts "$arg1 $arg2"} X proc do3 {arg1 {arg2 d1}} {puts "$arg1 $arg2"} X proc do4 {-arg1 {-arg2 d2}} {puts "$arg1 $arg2"} X proc do5 {{-arg1 d3} {arg2 d4}} {puts "$arg1 $arg2"} X copy Y foreach m [lsort [X info procs]] { foreach info {args nonposargs} { set x [X info $info $m] set y [Y info $info $m] ::errorCheck $x $y "copy nonposargs: $x ne $y" } foreach a [X info args $m] { set vx ""; set vy "" set dx [X info default $m $a vx] set dy [Y info default $m $a vy] ::errorCheck $dx $dy "copy nonposargs: hasdefault $dx ne $dy" if {[info exists dx] && [info exists dy]} { ::errorCheck $vx $vy "copy nonposargs: hasdefault value $vx ne $vy" } } } } } @ TestX recreation { description { Regression test for object recreation/cleanup. } } TestX recreation -proc run {{n 10}} { for {set i 0} {$i < $n} {incr i} { set ::recreateResult "" Class R R instproc recreate args { global recreateResult append recreateResult "*recreate [self] $args* " set r [next] append recreateResult "*recreate [self] <[lindex $args 0]> $r * " return $r } Object instmixin R catch { C destroy c1 destroy } Class C -parameter {a b} C instproc cProc {} {return cProc} C set r 4 C set v 5 C c1 -a 1 c1 proc x {} {return p} c1 set x 3 C c1 -b 2 append ::recreateResult "+[c1 info vars]," append ::recreateResult "[c1 info procs] +" Class C C set w 3 append ::recreateResult "+[C info vars]," append ::recreateResult "[C info instprocs] +" if {$i > 0} { errorCheck [set ::recreateResult] \ "*recreate ::xotcl::Class ::R* *recreate ::xotcl::Class <::R> ::R * *recreate ::C ::c1 -b 2* *recreate ::C <::c1> ::c1 * +b, +*recreate ::xotcl::Class ::C* *recreate ::xotcl::Class <::C> ::C * +w __default_superclass __default_metaclass, +" \ "Var/proc recreate delete failed (n)" } else { errorCheck [set ::recreateResult] \ "*recreate ::C ::c1 -b 2* *recreate ::C <::c1> ::c1 * +b, +*recreate ::xotcl::Class ::C* *recreate ::xotcl::Class <::C> ::C * +w __default_superclass __default_metaclass, +" \ "Var/proc recreate delete failed (0)" } global recreateMixinResult global recreateFilterResult set recreateMixinResult "" set recreateFilterResult "" Class RecreateObserve foreach ip {create destroy dealloc init configure recreate cleanup alloc class} { RecreateObserve instproc $ip args { append ::recreateMixinResult " [self]+[self class]->[self proc]" next } } Class Recreated Recreated instproc recreationFilter args { append ::recreateFilterResult " [self]+[self calledclass]->[self calledproc]" next } Recreated instfilter recreationFilter Recreated mixin RecreateObserve Recreated instmixin RecreateObserve Recreated recreateObj Recreated recreateObj recreateObj destroy errorCheck [set ::recreateFilterResult] \ " ::recreateObj+::xotcl::Object->configure ::recreateObj+::xotcl::Object->__object_configureparameter ::recreateObj+::xotcl::Object->init ::recreateObj+::xotcl::Object->cleanup ::recreateObj+::xotcl::Object->configure ::recreateObj+::xotcl::Object->init ::recreateObj+::xotcl::Object->destroy" \ "recreateObj - recreateFilterResult" if {$i == 0} { errorCheck [set ::recreateMixinResult] \ " ::Recreated+::RecreateObserve->create ::Recreated+::RecreateObserve->alloc ::recreateObj+::RecreateObserve->configure ::recreateObj+::RecreateObserve->init ::Recreated+::RecreateObserve->create ::Recreated+::RecreateObserve->recreate ::recreateObj+::RecreateObserve->cleanup ::recreateObj+::RecreateObserve->configure ::recreateObj+::RecreateObserve->init ::recreateObj+::RecreateObserve->destroy ::Recreated+::RecreateObserve->dealloc" \ "recreateObj - recreateMixinResult (0)" } else { errorCheck [set ::recreateMixinResult] \ " ::Recreated+::RecreateObserve->cleanup ::Recreated+::RecreateObserve->create ::Recreated+::RecreateObserve->alloc ::recreateObj+::RecreateObserve->configure ::recreateObj+::RecreateObserve->init ::Recreated+::RecreateObserve->create ::Recreated+::RecreateObserve->recreate ::recreateObj+::RecreateObserve->cleanup ::recreateObj+::RecreateObserve->configure ::recreateObj+::RecreateObserve->init ::recreateObj+::RecreateObserve->destroy ::Recreated+::RecreateObserve->dealloc" \ "recreateObj - recreateMixinResult (n)" } } set ::cleanupResult "" catch {a destroy} catch {A destroy} catch {X destroy} catch {META destroy} nsf::__db_run_assertions Class A A proc dealloc args {append ::cleanupResult " [self]+[self class]->[self proc]"; next} A proc recreate args {append ::cleanupResult " [self]+[self class]->[self proc]"; next} A instproc destroy args {append ::cleanupResult " [self]+[self class]->[self proc]"; next} A instproc cleanup args {append ::cleanupResult " [self]+[self class]->[self proc]"; next} A a A a::b errorCheck [set ::cleanupResult] "" "Cleanup Create Failed" A a errorCheck [a info children] "" "Cleanup Object Children Destroy Failed" A a::b errorCheck [set ::cleanupResult] \ " ::A+->recreate ::a+::A->cleanup ::a::b+::A->destroy ::A+->dealloc" \ "Cleanup a/a::b Failed (n)" a destroy set ::cleanupResult "" A instproc cleanup args {append ::cleanupResult " [self]+[self class]->[self proc]"} A a A a::b errorCheck [set ::cleanupResult] "" "Cleanup Redefine Create Failed" A a errorCheck [a info children] ::a::b \ "Cleanup Redefine Object Children Survive Failed" A a::b errorCheck [set ::cleanupResult] \ " ::A+->recreate ::a+::A->cleanup ::A+->recreate ::a::b+::A->cleanup" \ "Cleanup Redefine a/a::b Failed" a destroy set ::cleanupResult "" nsf::__db_run_assertions Class META -superclass Class META proc dealloc args {append ::cleanupResult " [self]+[self class]->[self proc]"; next} META proc recreate args {append ::cleanupResult " [self]+[self class]->[self proc]"; next} META instproc destroy args {append ::cleanupResult " [self]+[self class]->[self proc]"; next} META instproc cleanup args {append ::cleanupResult " [self]+[self class]->[self proc]"; next} META X META X::Y errorCheck [set ::cleanupResult] "" "Class Cleanup Create Failed" META X errorCheck [X info classchildren] "" "classchildren Class Cleanup Class Children Destroy Failed" errorCheck [X info children] "" "children Class Cleanup Class Children Destroy Failed" META X::Y errorCheck [set ::cleanupResult] \ " ::META+->recreate ::X+::META->cleanup ::X::Y+::META->destroy ::META+->dealloc" \ "Class Cleanup X/X::Y Failed" X destroy set ::cleanupResult "" META instproc cleanup args {append ::cleanupResult " [self]+[self class]->[self proc]"} META X META X::Y errorCheck [set ::cleanupResult] "" "Class Cleanup Redefine Create Failed" META X errorCheck [X info classchildren] ::X::Y \ "classchildren Class Cleanup Redefine Class Children Survive Failed" errorCheck [X info children] ::X::Y \ "children Class Cleanup Redefine Class Children Survive Failed" META X::Y errorCheck [set ::cleanupResult] \ " ::META+->recreate ::X+::META->cleanup ::META+->recreate ::X::Y+::META->cleanup" \ "Class Cleanup Redefine X/X::Y Failed" X destroy A destroy META destroy unset ::cleanupResult Object instmixin "" # upgrading/downgrading Class B Class C -superclass B C c1 Object o1 -mixin B Object o2 -mixin C ::errorCheck [B info class] "::xotcl::Class" "up/down before 0" ::errorCheck [c1 istype B] 1 "up/down before 1" ::errorCheck [C info superclass] ::B "up/down before 2" ::errorCheck [B info subclass] ::C "up/down before 3" ::errorCheck [o1 info mixin] ::B "up/down before 4" ::errorCheck [o2 info mixin] ::C "up/down before 5" ::errorCheck [B info mixinof] ::o1 "up/down before 6" ::errorCheck [C info mixinof] ::o2 "up/down before 7" ::errorCheck [c1 info precedence] "::C ::B ::xotcl::Object" "up/down before 8" ::errorCheck [o1 info precedence] "::B ::xotcl::Object" "up/down before 9" ::errorCheck [o2 info precedence] "::C ::B ::xotcl::Object" "up/down before 10" ::errorCheck [catch {B class Object}] 1 "don't allow downgrading" Object B ::errorCheck [B info class] "::xotcl::Object" "up/down after 0" ::errorCheck [c1 istype B] 0 "up/down after 1" ::errorCheck [C info superclass] ::xotcl::Object "up/down after 2" ::errorCheck [catch {B info subclass}] 1 "up/down after 3" ::errorCheck [o1 info mixin] "" "up/down after 4" ::errorCheck [o2 info mixin] ::C "up/down after 5" ::errorCheck [catch {B info mixinof}] 1 "up/down after 6" ::errorCheck [C info mixinof] ::o2 "up/down after 7" ::errorCheck [c1 info precedence] "::C ::xotcl::Object" "up/down after 8" ::errorCheck [o1 info precedence] "::xotcl::Object" "up/down after 9" ::errorCheck [o2 info precedence] "::C ::xotcl::Object" "up/down after 10" ::errorCheck [B info class] "::xotcl::Object" "up/down after 0x" B class Object ::errorCheck [catch {B class Object}] 0 "don't complain when same level" ::errorCheck [catch {B class Class}] 1 "don't allow upgrading" } @ TestX smallScripts { description { Regression test object testing arbitrary features. } } TestX smallScripts proc ::up1 {} { return [uplevel 1 self] } proc ::up3 {} { return [uplevel 3 self] } proc ::up2 {} { return [up3] } smallScripts proc run {{n 20}} { catch {Object o; o r} errMsg ::errorCheck $errMsg "::o: unable to dispatch method 'r'" "Unknown Test" # uplevel test for {set i 0} {$i < $n} {incr i} { Object o o proc u2 {} {return [::up2]} o proc u1 {} {return [::up1]} Class SM SM instproc init args { ::errorCheck [o u1] "::o" "FAILED - UpLevel Test 1" ::errorCheck [o u2] "::s" "FAILED - UpLevel Test 2" } SM s } for {set i 1} {$i < $n} {incr i} { Class A A a1 set oname1 [Object autoname ooo] set oname2 [Object autoname -instance OOO] A autoname -reset AAA set names [A autoname AAA] a1 autoname -reset aaa lappend names [a1 autoname aaa] lappend names [a1 autoname aaa] ::errorCheck $names "AAA1 aaa1 aaa2" "Autoname creation" ::errorCheck $oname1 "ooo$i" "Autoname Object 1" ::errorCheck $oname2 "oOO$i" "Autoname Object 2" ::errorCheck [xotcl::Object set __autonames(ooo)] $i \ "Autoname Object Count" } Class P; P p P instproc x {} { my instvar "x(1) t" return $t } p set x(1) rrr ::errorCheck [p x] rrr "Array member alias, no ns" Object o o proc x {} { my instvar "x(1) t" return $t } o set x(1) rrr ::errorCheck [o x] rrr "Array member alias, with ns" Object o o proc x args {puts r} ::errorCheck [o info body x] "puts r" "Info Body" #::errorCheck [info body o::x] "puts r" "Info Body"; #don't do this Object o o proc a {} { my lappend table(i) xxx } ::errorCheck [o a]-[o set table(i)] "xxx-xxx" "Array instvar create" Class A A instproc myProc args {} Class Mix1 Mix1 instproc myProcMix1 args {} Class Mix2 Mix2 instproc myProcMix2 args {} Class B -superclass A -instmixin Mix1 B instproc myProc2 args {} B b -mixin Mix2 b proc objproc args {} ::errorCheck [b info procs] objproc "info procs" ::errorCheck [B info instprocs] myProc2 "info instprocs" ::errorCheck [lsort [b info methods]] "__object_configureparameter abstract append array autoname check class cleanup configure contains copy defaultmethod destroy dict eval exists extractConfigureArg f filter filterguard filtersearch forward hasclass incr info init instvar invar isclass ismetaclass ismixin isobject istype lappend method mixin mixinguard move myProc myProc2 myProcMix1 myProcMix2 noinit objproc parametercmd proc procsearch requireNamespace residualargs self set setFilter signature subst trace unknown unset uplevel upvar volatile vwait" "b info methods" ::errorCheck [lsort [b info methods -nocmds]] "__object_configureparameter abstract check extractConfigureArg f filtersearch forward hasclass init isclass ismetaclass ismixin isobject istype method myProc myProc2 myProcMix1 myProcMix2 objproc proc procsearch self setFilter signature unknown vwait" "b info methods -nocmds" ::errorCheck [lsort [b info methods -noprocs]] "append array autoname class cleanup configure destroy dict eval exists filter filterguard incr info instvar invar lappend mixin mixinguard noinit parametercmd requireNamespace residualargs set subst trace unset uplevel upvar volatile" "b info methods -noprocs" ::errorCheck [lsort [b info methods -nocmds -nomixins]] "__object_configureparameter abstract check extractConfigureArg f filtersearch forward hasclass init isclass ismetaclass ismixin isobject istype method myProc myProc2 objproc proc procsearch self setFilter signature unknown vwait" "b info methods -nocmds -nomixins" ::errorCheck [b info methods -nocmds -noprocs] "" "b info methods -nocmds -noprocs" ::errorCheck [lsort [B info methods -nocmds]] "__class_configureparameter __object_configureparameter abstract allinstances check extractConfigureArg f filtersearch forward hasclass init instforward instproc isclass ismetaclass ismixin isobject istype method parameter proc procsearch self setFilter signature slots unknown uses vwait" "B info methods -nocmds" namespace eval a { proc o args {return o} } namespace eval a::b { proc b args {return b} } Object a a requireNamespace set r [a::b::b] Object a::b a::b proc x args { return x } set r "$r-[a::b x]-[a o]" ::errorCheck $r b-x-o "Tcl Namespace should survive requireNamespace" xotcl::interp create in set ::r [in eval { package prefer latest package req XOTcl 2.0; namespace import ::xotcl::* Object o }] xotcl::interp delete in ::errorCheck $::r ::o "XOTcl slave interpreter " Object o -requireNamespace o set r 1 after 100 {o set r 3} o vwait r ::errorCheck [o set r] 3 "Vwait test" Class NS Class NS::Main NS::Main proc m1 {} { my m2 } NS::Main proc m2 {} { namespace eval :: Object toplevelObj } NS::Main m1 ::errorCheck [::toplevelObj set a 1] 1 "toplevel object allocated in ns" namespace eval foo { Class Foo Foo instproc blah {} {puts jou} Foo proc bar {} {puts bar} } namespace delete foo ::errorCheck [Object isobject ::foo::Foo] 0 "Namespace delete under object" # destroy test set x [Object create x] x destroy ::errorCheck [catch {$x set a 1}] 1 "Reference to destroyed object still valid" Object create x -volatile unset x ::errorCheck [catch {x destroy}] 1 "Object should not exist anymore" Object create x -volatile x destroy ::errorCheck [catch {unset x}] 1 "Variable should not exist anymore" } @ TestX objectReferences { description { Regression test for object and class references in tcl_objs } } TestX objectReferences -proc run {{n 20}} { my proc ok01 {} { Class AAA AAA destroy Class AAA } my proc ok02 {} { Class ::AAA AAA destroy Class AAA } my proc ok03 {} { Class ::AAA ::AAA destroy Class AAA } my proc ok04 {} { Class ::AAA ::AAA destroy Class ::AAA } my proc ok05 {} { set c [Class AAA] $c destroy Class AAA } my proc ok06 {} { set c [Class ::AAA] $c destroy Class AAA } my proc ok07 {} { set c [Class ::AAA] $c destroy Class ::AAA } my proc ok08 {} { set c [Class ::AAA] $c destroy Class $c } my proc ok09 {} { [Class AAA] destroy Class AAA } my proc ok10 {} { [Class ::AAA] destroy Class AAA } my proc ok11 {} { [Class ::AAA] destroy Class ::AAA } for {set i 1} {$i < 20} {incr i} { # "reference to XOTcl object in instvar" Class LexxTreeMounter Class LexxTree LexxTreeMounter proc new {args} { if {[LexxTree exists LexxTreeMounter]} { set o [LexxTree set LexxTreeMounter] } else { set o [my create [my autoname [self]]] } $o incr C(refcnt) return $o } LexxTreeMounter instproc init {args} { my instvar C set C(refcnt) 0 if {[LexxTree exists LexxTreeMounter] == 0} { LexxTree set LexxTreeMounter [self] } next } set x [LexxTreeMounter new] set x [LexxTreeMounter new] ::errorCheck [llength [LexxTreeMounter info instances]] 1 singleton # "Global reference to XOTcl object" set ::v [Object ::a] set ::w [Object ::b] set ::z(1) [Object ::c] unset ::v # "Class creation and Class destroys, after 2nd round procs contain xotcl-object references" foreach m [lsort [my info procs ok*]] {my $m} ::errorCheck [my isobject AAA] 1 classdestroys } catch {UnknownClass destroy} set ::utest "" Class proc __unknown args { #puts stderr ===UNK-$args lappend ::utest $args set x [Class $args] set r [$x] #puts r=$r return $r } Class O -superclass UnknownClass ::errorCheck $::utest ::UnknownClass "__unknown 1" Object o ::errorCheck [o mixin XX1] ::XX1 "__unknown XX1" namespace eval "" { Object o ::errorCheck [o mixin XX2] ::XX2 "__unknown XX2" } namespace eval "::" { Object o ::errorCheck [o mixin XX3] ::XX3 "__unknown XX3" } # this version of unknown creates global objects Class proc __unknown {name} { #puts "unknown called with $name" set name ::[namespace tail $name] set x [Class $name] set r [$x] #puts "... created $r" return $r } Object o ::errorCheck [o mixin XY1] ::XY1 " __unknown XY1" namespace eval "" { Object o ::errorCheck [o mixin XY2] ::XY2 " __unknown XY2" } namespace eval :: { Object o ::errorCheck [o mixin XY3] ::XY3 " __unknown XY3" } Class C namespace eval ::tmp { Object o -mixin C ::errorCheck [o mixin XY4] ::XY4 " __unknown XY4" } ::errorCheck [UnknownClass info info] {valid options are: args, body, check, children, class, classchildren, classparent, commands, default, filter, filterguard, forward, hasnamespace, heritage, info, instances, instargs, instbody, instcommands, instdefault, instfilter, instfilterguard, instforward, instinvar, instmixin, instmixinguard, instmixinof, instnonposargs, instparametercmd, instpost, instpre, instprocs, invar, methods, mixin, mixinguard, mixinof, nonposargs, parameter, parametercmd, parent, post, pre, precedence, procs, slots, subclass, superclass, vars} "UnknownClass info info" # clear unknown handler to avoid strange results later Class proc __unknown "" "" ::errorCheck [Class info instances *Unk*] ::UnknownClass "match in info instances" ::errorCheck [Class info instances Unk*] "::UnknownClass" "no match in info instances" ::errorCheck [Class info instances Unk] "" "no match in info instances (no metachars)" ::errorCheck [Class info class] ::xotcl::Class "info class of Class" ::errorCheck [Class info precedence ::xotcl::Object] ::xotcl::Object "info class of Class Object" Class C Class D -superclass C Class E -superclass D -parameter {{x 1}} E instproc t {a b {c 1}} {return ok} E proc p {a b {c 1}} {return ok} E instproc q {} {return [self proc]} ::errorCheck [C info subclass D] ::D "transitive subclass 0" ::errorCheck [C info subclass E] "" "transitive subclass 0a" ::errorCheck [C info subclass -closure E] ::E "transitive subclass 1" ::errorCheck [Object info subclass -closure E] ::E "transitive subclass 2" ::errorCheck [D info subclass -closure C] "" "transitive subclass 3" ::errorCheck [E info heritage] "::D ::C ::xotcl::Object" "heritage" ::errorCheck [E info instargs t] "a b c" "instargs" ::errorCheck [E info instdefault t c x] 1 "instdefault" ::errorCheck [E info args p] "a b c" "args" ::errorCheck [E info default p c x] 1 "default" ::errorCheck [E configure [list -p -x -y]] {} "list params 1" #::errorCheck [E e1 [list -t -1 -e -3]] ::e1 "list params 2"; # TODO worked in 1.6 ::errorCheck [E create e1 [list -t -1 -e -3]] ::e1 "list params 2" ::errorCheck [e1 x] 1 "instparameter cmd 1" ::errorCheck [e1 x 2] 2 "instparameter cmd 2" ::errorCheck [e1 x] 2 "instparameter cmd 3" ::errorCheck [e1 parametercmd y] "::e1::y" "parametercmd 1" ::errorCheck [e1 y 3] 3 "parametercmd 2" ::errorCheck [e1 y] 3 "parametercmd 3" ::errorCheck [e1 forward regexp -objscope] "::e1::regexp" "forward 1" ::errorCheck [e1 regexp (y) xyz _ X] "1" "forward 2" ::errorCheck [e1 exists X] "1" "forward 3" ::errorCheck [e1 q] q "self proc" ::errorCheck [lsort [E info commands]] {p} "class commands" ::errorCheck [lsort [E info instcommands]] "q t x" "class instcommands" ::errorCheck [E info instbody t] "return ok" "class info instbody" Object o Object o::abc Object o::bcd Object o::cde namespace eval ns1 {Class C; namespace export C} o eval {namespace import ::ns1::*} ::errorCheck [lsort [o info children]] "::o::abc ::o::bcd ::o::cde" "info children 1" ::errorCheck [lsort [o info children *cd*]] "::o::bcd ::o::cde" "info children 2" ::errorCheck [o info children ::o::cde] ::o::cde "info children 3" ::errorCheck [o info children ::o::def] "" "info children 4" Object new -childof o ::errorCheck [llength [o info children]] 4 "info children 5" ::errorCheck [Object isobject o] 1 "is object 1" ::errorCheck [Object isobject ox] 0 "is object 2" Class M -superclass Class ::errorCheck [Object ismetaclass M] 1 "is metaclass 1" ::errorCheck [Object ismetaclass C] 0 "is metaclass 0" Class X ::errorCheck [Object ismetaclass X] 0 "is metaclass 0" ::errorCheck [X isclass] 1 "is isclass 1" ::errorCheck [Class info instances X] ::X "is an instance of Class" ::errorCheck [catch {X class Object}] 1 "turn class into an object (error)" Class Y -superclass X Object o1 -mixin Y ::errorCheck [o1 info precedence] "::Y ::X ::xotcl::Object" "normal mixin precedence" Object X ;# turn class X into Object X (via destroy/create) ::errorCheck [o1 info precedence] "::Y ::xotcl::Object" "reduced mixin precedence" X destroy Y destroy o1 destroy Class M -superclass Class M create m1 ::errorCheck [Object ismetaclass M] 1 "is metaclass 1" ::errorCheck [M isclass] 1 "is isclass 1" ::errorCheck [Class info instances M] ::M "is an instance of Class" ::errorCheck [m1 info class] ::M "m1 is an instance of the meta-class" ::errorCheck [m1 isclass] 1 "m1 is isclass 1" ::errorCheck [m1 info class] ::M "m1 is of class ::M" Object M ;# make object from metaclass ::errorCheck [Object ismetaclass M] 0 "is metaclass 0" ::errorCheck [M isclass] 0 "is isclass 0" ::errorCheck [Class info instances M] "" "is not an instance of Class" ::errorCheck [Object isclass m1] 1 "m1 is still a class" ::errorCheck [::xotcl::is object m1] 1 "m1 is still an object" ::errorCheck [::xotcl::is class m1] 1 "m1 is still a class" ::errorCheck [::xotcl::relation m1 class] ::xotcl::Class "m1 now a baseclass" ::errorCheck [m1 info class] ::xotcl::Class "m1 is now an instance of Class" ::errorCheck [m1 isclass] 1 "m1 is isclass 1" ::errorCheck [m1 info class] ::xotcl::Class "m1 is of class ::xotcl::Class" M destroy # to be completed XXX Class C -parameter {number name} C instproc test {} { my instvar {number x} name return [list $name $x] } C c -name koen -number 25 ::errorCheck [c test] "koen 25" "instvar with alias" # Class C Class D -superclass C Class D1 D instmixin D1 D d1 ::errorCheck [d1 info precedence] "::D1 ::D ::C ::xotcl::Object" "d1 info precedence" ::errorCheck [d1 info precedence *] "::D1 ::D ::C ::xotcl::Object" "d1 info precedence *" ::errorCheck [d1 info precedence ::D*] "::D1 ::D" "d1 info precedence pattern" ::errorCheck [d1 info precedence -intrinsic] "::D ::C ::xotcl::Object" "d1 info precedence -intrinsic" ::errorCheck [d1 info precedence -intrinsic *] "::D ::C ::xotcl::Object" "d1 info precedence -intrinsic *" ::errorCheck [d1 info precedence -intrinsic ::D*] "::D" "d1 info precedence -intrinsic pattern" d1 destroy D destroy D1 destroy } @ TestX condMixins { description { Regression test for conditional mixins } } TestX create condMixins -proc show {c obj} { set ::context $c set r [list] foreach x [list \ [list $obj info methods salary] \ [list $obj info methods -incontext salary] \ [list $obj info methods driv*] \ [list $obj info methods -incontext driv*] \ ] { lappend r "$::context: $x => [lsort [eval $x]]" } return $r } condMixins proc run {{n 20}} { Object instproc signature {} {return "[self] [my info class] ([my age] years)"} Class Person -parameter {id name age} Class Payroll-aspect -parameter salary Payroll-aspect instproc print {} {puts "[my signature]: [my salary]"} Class Driver-aspect -parameter driving-license Payroll-aspect instproc print {} {puts "[my signature]: [my driving-license]"} Person instmixin {{Payroll-aspect -guard {[string equal $::context "payrollApp"]}}} Person jim -mixin {{Driver-aspect -guard {[string equal $::context "shipmentApp"]}}} set ::context payrollApp ::errorCheck [lsort [jim info methods]] "__object_configureparameter abstract age append array autoname check class cleanup configure contains copy defaultmethod destroy dict driving-license eval exists extractConfigureArg filter filterguard filtersearch forward hasclass id incr info init instvar invar isclass ismetaclass ismixin isobject istype lappend method mixin mixinguard move name noinit parametercmd print proc procsearch requireNamespace residualargs salary self set signature subst trace unknown unset uplevel upvar volatile vwait" "condmixin all methods" ::errorCheck "[lsort [jim info methods -incontext]]" "__object_configureparameter abstract age append array autoname check class cleanup configure contains copy defaultmethod destroy dict eval exists extractConfigureArg filter filterguard filtersearch forward hasclass id incr info init instvar invar isclass ismetaclass ismixin isobject istype lappend method mixin mixinguard move name noinit parametercmd print proc procsearch requireNamespace residualargs salary self set signature subst trace unknown unset uplevel upvar volatile vwait" "all methods in context" ::errorCheck [my show payrollApp jim] "{payrollApp: jim info methods salary => salary} {payrollApp: jim info methods -incontext salary => salary} {payrollApp: jim info methods driv* => driving-license} {payrollApp: jim info methods -incontext driv* => }" "payrollApp jim" ::errorCheck [my show shipmentApp jim] "{shipmentApp: jim info methods salary => salary} {shipmentApp: jim info methods -incontext salary => } {shipmentApp: jim info methods driv* => driving-license} {shipmentApp: jim info methods -incontext driv* => driving-license}" "shipmentApp jim" } @ TestX volatileObjects { description { Regression test for volatile objects } } TestX create volatileObjects volatileObjects proc inscope {} { set r 0 set y 0 set z 0 set c [C new -volatile] catch {incr r [$c test]} catch {set y [$c y]} catch {set z [$c z]} if {[catch {set u [$c u]} err]} {puts stderr $err} return $r-[llength [C info instances]]-$y-$z-$u } volatileObjects proc run {{n 20}} { Class create ::xotcl::_creator -instproc create {args} { set result [next] return $result } Class instproc f args { #puts stderr "*****F [self calledproc]" return [next] } Class C -parameter {{x 0}} C instproc f args { #puts stderr "*****C [self calledproc]" return [next] } C instproc test {} { my incr x } C instproc y {} { my instvar x; incr x } C instproc z {} { my set x 10 } C instproc u {} { upvar [self callinglevel] z b; info exists b } Class create ::xotcl::I -instproc instvar args { #puts [self proc] next } -instproc set args { #puts [self proc] next } -instproc u args { #puts [self proc] next } ::errorCheck [llength [C info instances]] 0 "foreign instances" ::errorCheck [my inscope] 1-1-2-10-1 "volatile objects in scope" ::errorCheck [llength [C info instances]] 0 "instances survived scope" Class instmixin ::xotcl::_creator ::errorCheck [my inscope] 1-1-2-10-1 "volatile objects in scope through mixin" ::errorCheck [llength [C info instances]] 0 \ "instances survived scope through mixin" Class instfilter f ::errorCheck [my inscope] 1-1-2-10-1 \ "volatile objects in scope through mixin + filter" ::errorCheck [llength [C info instances]] 0 \ "instances survived scope through mixin + filter" Class instmixin {} Class instfilter f ::errorCheck [my inscope] 1-1-2-10-1 \ "volatile objects in scope through filter" ::errorCheck [llength [C info instances]] 0 \ "instances survived scope through filter" Class instfilter {} C instmixin ::xotcl::I ::errorCheck [my inscope] 1-1-2-10-1 \ "instvar overload in scope through mixin" C instfilter f ::errorCheck [my inscope] 1-1-2-10-1 \ "instvar overload in scope through mixin and filter" C instfilter {} Class instproc f {} {} } TestX create uplevelCmds uplevelCmds proc upproc {} { lappend ::result [list \ self=[self] \ up1=[uplevel 1 self] \ up2=[uplevel 2 self] \ up3=[uplevel 3 self] ] } uplevelCmds proc run {{n 20}} { Object o1 -proc m {} { set ::result [list] lappend ::result [list \ self=[self] \ up1=[uplevel 1 self] \ up2=[uplevel 2 self] \ up3=[uplevel 3 self] ] #uplevelCmds::upproc uplevelCmds upproc return $::result } Object o2 -proc m {} { o1 m } Object o3 -proc m {} { o2 m } Object o4 -proc m {} { o3 m } ::errorCheck [o4 m] \ "{self=::o1 up1=::o2 up2=::o3 up3=::o4} {self=::uplevelCmds up1=::o1 up2=::o2 up3=::o3}" \ "uplevel self" o4 m proc showstack {} { set l [info level] for {set i $l} {$i>0} {incr i -1} { set vars [uplevel \#$i info vars] upvar \#$i what w if {![info exists w]} {set w ""} puts "$i: $w[info level $i] vars=$vars" } } Class C C instproc u0 {} { upvar [self callinglevel] x y; incr y return [uplevel [self callinglevel] {incr x 1}] } C instproc u1 {} { upvar [self callinglevel] x y; incr y set r [uplevel [self callinglevel] {incr x 1}] set z [uplevel [self activelevel] incr z] return $z-$r } C instproc p0 {y} { set x $y set r [my u0] return $r-$x } C instproc p1 {y} { set z 0 set x $y set r [my u1] return $r-$x } Class D -superclass C D instproc u0 {} { upvar [self callinglevel] x y; incr y return [uplevel [self callinglevel] {incr x 1}] } D instproc u1 {} { set z [uplevel [self activelevel] incr z] set r [next] return $z-$r } Class M M instproc u1 {} { set z [uplevel [self activelevel] incr z] set r [next] return $z-$r } Object instproc f args { next } D create d1 errorCheck [d1 p0 1] 3-3 "simple uplevel" errorCheck [d1 p1 1] 2-2-3-3 "uplevel through next in class hierarchy + activelevel" D instmixin M errorCheck [d1 p1 1] 1-3-3-3-3 "uplevel through mixin and class hierarchy + activelevel" Object instfilter f errorCheck [d1 p1 1] 1-3-3-3-3 "uplevel through filter, mixin and class hierarchy + activelevel" Object instfilter "" D instmixin {} # now again the same tests with upvar and uplevel methods C instproc u0 {} { my upvar [self callinglevel] x y; incr y return [my uplevel {incr x 1}] } C instproc u1 {} { my upvar [self callinglevel] x y; incr y set r [my uplevel {incr x 1}] set z [my uplevel [self activelevel] incr z] return $z-$r } D instproc u0 {} { my upvar [self callinglevel] x y; incr y return [my uplevel {incr x 1}] } Class M M instproc u1 {} { set z [my uplevel [self activelevel] incr z] set r [next] return $z-$r } errorCheck [d1 p0 1] 3-3 "upvar method: simple uplevel" errorCheck [d1 p1 1] 2-2-3-3 \ "upvar method: uplevel through next in class hierarchy + activelevel" D instmixin M errorCheck [d1 p1 1] 1-3-3-3-3 \ "upvar method: uplevel through mixin and class hierarchy + activelevel" Object instfilter f errorCheck [d1 p1 1] 1-3-3-3-3 \ "upvar method: uplevel through filter, mixin and class hierarchy + activelevel" Object instfilter "" D instmixin {} # now again the same tests with upvar and uplevel methods with default levels C instproc u0 {} { my upvar x y; incr y return [my uplevel {incr x 1}] } C instproc u1 {} { my upvar x y; incr y set r [my uplevel {incr x 1}] set z [my uplevel [self activelevel] incr z] return $z-$r } D instproc u0 {} { my upvar x y; incr y return [my uplevel {incr x 1}] } Class M M instproc u1 {} { set z [my uplevel [self activelevel] incr z] set r [next] return $z-$r } errorCheck [d1 p0 1] 3-3 "upvar method: simple uplevel (dl)" errorCheck [d1 p1 1] 2-2-3-3 \ "upvar method: uplevel through next in class hierarchy + activelevel (dl)" D instmixin M errorCheck [d1 p1 1] 1-3-3-3-3 \ "upvar method: uplevel through mixin and class hierarchy + activelevel (dl)" Object instfilter f errorCheck [d1 p1 1] 1-3-3-3-3 \ "upvar method: uplevel through filter, mixin and class hierarchy + activelevel (dl)" Object instfilter "" D instmixin {} C instproc selftest args { return [self class]/[self isnextcall]-[next] } D instproc selftest args { return [self class]/[self isnextcall]-[next] } errorCheck [d1 selftest] "::D/0-::C/1-" \ "self isnextcall" Object instproc each {objName body} { #puts " *** level = [info level] self callinglevel = [self callinglevel]" uplevel [self callinglevel] [list foreach $objName [lsort [[self] info children]] $body] } Class TestB Class TestA TestA instproc init {args} { next TestB [self]::b1 TestB [self]::b2 TestB [self]::b3 } Class Test Test instproc init {args} { next TestA [self]::a1 TestA [self]::a2 TestA [self]::a3 } Test instproc loop1 {} { set i 0 [self] each a { incr i #puts "$a" } #puts "Total = $i" return $i } Test instproc loop2 {} { set i 0 [self] each a { incr i #puts "$a" $a each b { incr i #puts " $b" } } #puts "Total = $i" return $i } Object instproc f args {next} Test t errorCheck [t loop1] 3 "uplevel eval loop" errorCheck [t loop2] 12 "nested uplevel eval loop" t filter f errorCheck [t loop1] 3 "uplevel eval loop with filter" errorCheck [t loop2] 12 "nested uplevel eval loop with filter" t destroy } TestX create namespaceCommands -proc run {{n 20}} { errorCheck [catch { namespace eval foo { Class m Object o -mixin m } }] 0 "mixin resolved from namespace" Class create ::xotcl::_creator -instproc create {args} { set result [next] return $result } errorCheck [catch { namespace eval bar { Class A namespace export A } namespace eval foo { Class M -superclass Class namespace import ::bar::* Class B -superclass A -instmixin M Class instmixin ::xotcl::_creator Class C -superclass A -instmixin B Class instmixin "" } } error] 0 "mixin and Class resolve and import into namespace\n$error" } TestX create metaClassAsMixin -proc run {{n 20}} { Class create A -instmixin Class Class create B -superclass A B create b1 errorCheck [A ismetaclass]-[B ismetaclass]-[b1 ismetaclass]-[b1 isclass] \ "1-1-0-1" "metaclass through mixin" } TestX create nonposargs -proc run {{n 20}} { Object o o set result "" o proc test1 {-x:switch y} { my append result "x=$x y=$y, " } o test1 1 o test1 -x 1 o proc test2 {{-x:switch true} y} { my append result "x=$x y=$y, " } o test2 2 o test2 -x 2 o proc test3 {{-x:switch false} y} { my append result "x=$x y=$y, " } o test3 3 o test3 -x 3 errorCheck [o set result] \ "x=0 y=1, x=1 y=1, x=true y=2, x=0 y=2, x=false y=3, x=1 y=3, " \ "nonpos args switch" Object o o proc x {a b} { return "$a $b" } o proc y {-x {-a {1 2 3}} a b} { return "$args" } o proc z1 {-x:required {-a {1 2 3}} a1 args} { return "$x -- $args" } o proc z2 {-x:required {-a {1 }} {-b {1 2}} args} {return "$x -- $args -- $a -- $b"} o proc z3 {-b:boolean arg} { return "$b $arg" } Object colorchecker colorchecker proc color {var value} { lappend ::r "color <$var> <$value>" } colorchecker proc reddish {var value} { lappend ::r "reddish <$var> <$value>" } # o proc z4 { # {{-b: required, checkobj colorchecker,color, reddish, # checkobj xotcl::nonposArgs,required} red} # {{-c: required }} # arg # } { # lappend ::r "$b $arg" # return "$b $arg" # } o proc z5 {-pos args} { return [list $pos $args] } Class P P instproc x {a b} { return "$a $b" } P instproc z2 {-x:required {-a 1} {-b {1 2}} args} {return "$x -- $args -- $a -- $b"} P instproc z3 {-x:required {-a 1} {-b {1 2}} a b c} { return "$x -- $args -- $a -- $b" } P p errorCheck [o x 1 2] "1 2" "Ordinary Method" errorCheck [p x 3 4] "3 4" "Ordinary Method (2)" catch { o y 4 56 5 } m errorCheck $m \ {invalid argument '5', maybe too many arguments; should be "::o y ?-x /value/? ?-a /value/? /a/ /b/"} \ "wrong \# check 1" catch { o y } m errorCheck $m {required argument 'a' is missing, should be: ::o y ?-x /value/? ?-a /value/? /a/ /b/} "wrong \# check 2" catch { o y -x 1 } m errorCheck $m {required argument 'a' is missing, should be: ::o y ?-x /value/? ?-a /value/? /a/ /b/} "wrong \# check 3" catch { o z1 a 1 2 3 } m errorCheck $m {required argument 'x' is missing, should be: ::o z1 -x /value/ ?-a /value/? /a1/ ?/arg .../?} "required missing" errorCheck [o z1 -x 1 a 1 2 3] "1 -- 1 2 3" "invocation 1" errorCheck [o z2 -x 2 a 1 2 3] "2 -- a 1 2 3 -- 1 -- 1 2" "invocation 2" catch { o y -x 1 -a 2 2 3 } m errorCheck $m "can't read \"args\": no such variable" "args unset?" errorCheck [o z2 -a 2 -x 1 -b 3 a b c] \ "1 -- a b c -- 2 -- 3" "invocation 3" errorCheck [p z2 -x 1 -a 2 -b 3 a b c] \ "1 -- a b c -- 2 -- 3" "invocation 4" errorCheck [o z3 -b true -- -b] "true -b" "dash dash" errorCheck [o z5 -pos 1 a b] "1 {a b}" "nonpos with given args" errorCheck [o z5 -pos 1 a] "1 a" "nonpos with given args" errorCheck [o z5 -pos 1] "1 {}" "nonpos without given args" catch { o z3 -b abc -- -b } m errorCheck $m {expected boolean but got "abc" for parameter "-b"} "not boolean" set ::r "" #o z4 -c 1 1 #errorCheck $::r "{color } {reddish } {red 1}" \ "multiple check options + checkobject" errorCheck [o info body z2] {return "$x -- $args -- $a -- $b"} "info body 1" errorCheck [P info instbody z2] {return "$x -- $args -- $a -- $b"} "info instbody z2" # errorCheck [o info args z4] {arg} "info args" # errorCheck [o info nonposargs z4] "{{-b:required,checkobj colorchecker,color,reddish,checkobj xotcl::nonposArgs,required} red} -c:required" "info nonposargs 1" errorCheck [o info nonposargs x] {} "info nonposargs 2" errorCheck [P info instargs z3] {a b c} "info instargs" errorCheck [P info instnonposargs z3] {-x:required {-a 1} {-b {1 2}}} "info instnonposargs 1" errorCheck [P info instnonposargs x] {} "info instnonposargs 2" Object o o proc foo {{-a apple} {b banana}} { return [list [lsort [info locals]] a: $a b: $b] } o proc foo2 {{-a apple} {b banana} {c apple}} { return [list [lsort [info locals]] a: $a b: $b c: $c] } o proc foo3 {{-a apple} x y {b banana} {c apple}} { return [list [lsort [info locals]] x: $x y: $y a: $a b: $b c: $c] } errorCheck [o foo] [list {a b} a: apple b: banana] \ "non pos + default values 1" errorCheck [o foo -a ack] [list {a b} a: ack b: banana] \ "non pos + default values 2" errorCheck [o foo bar] [list {a b} a: apple b: bar] \ "non pos + default values 3" errorCheck [o foo -a ack bar] [list {a b} a: ack b: bar] \ "non pos + default values 4" errorCheck [o foo2 -a ack] [list {a b c} a: ack b: banana c: apple] \ "non pos + default values 5" errorCheck [ o foo3 -a ack 1 2] [list {a b c x y} x: 1 y: 2 \ a: ack b: banana c: apple] \ "non pos + default values 6" Object o o proc foo {{-foo 1}} { #puts "foo: $foo" } o foo o foo -foo 0 catch {o foo -foo} msg errorCheck $msg "value for parameter '-foo' expected" "Empty non-pos arg" Object oa oa proc foo {{-a A} b} { #puts "$a $b" } oa foo "B" oa foo "-" oa foo "---" catch {oa foo "--"} msg errorCheck $msg {required argument 'b' is missing, should be: ::oa foo ?-a /value/? /b/} "Non-pos arg: double dash alone" Class C C create c1 C instproc m2 { {-flag:boolean false} x y {z 15} } { return $flag-$z } c1 proc m14 { {-flag:boolean false} x y {z 15} } { return $flag-$z } errorCheck [list [c1 m14 1 2 3] [c1 info args m14] \ [c1 info default m14 z e] [set e]] \ "false-3 {x y z} 1 15" \ "Defaults proc" errorCheck [list [c1 m2 1 2 3] [C info instargs m2]] \ "false-3 {x y z}" \ "info instargs" errorCheck [list [C info instdefault m2 x d] [C info instdefault m2 z d] [set d]] \ "0 1 15" \ "Defaults for instproc" catch {C info instdefault m2 xxx e} msg errorCheck $msg {procedure "m2" doesn't have an argument "xxx"} \ "Defaults instproc error" C instproc m3 { {-flag:boolean} x y z } { return hu3 } errorCheck [c1 m3 1 2 3] "hu3" "Defaults instproc no flag" Object o o proc f1 {{-x:boolean true} a } { if {![info exists a]} {error "pos arg a does not exist"} if {$x ne "true"} {error "x $x ne true"} if {$a ne "x"} {error "a $a ne x"} if {[info exists args]} {error "args still exists"} } o proc f2 {{-x:boolean true} {a x}} { if {![info exists a]} {error "pos arg a does not exist"} if {$x ne "false"} {error "x $x ne false"} if {$a ne "x"} {error "a $a ne x"} if {[info exists args]} {error "args still exists"} } o proc f3 {{-x:boolean true} } { if {$x ne "true"} {error "x $x ne true"} if {[info exists args]} {error "args still exists"} } o proc p0 {{-x 1} a} { #puts "--- [self proc] x=$x [info exists a]" if {![info exists a]} {error "pos arg a does not exist"} if {$a != 1} {error "a $a != 1"} if {$x != 1} {error "x $x != 1"} if {[info exists args]} {error "args still exists"} } o proc p1 {{-x 1} a1 args} { #puts "--- [self proc] x=$x [info exists a1] args=$args" if {![info exists a1]} {error "pos arg a1 does not exist"} if {$a1 != 1} {error "a $a1 != 1"} if {$x != 1} {error "x $x != 1"} if {$args ne ""} {error "args $args ne {}"} } o proc p2 {{-x 1} args} { if {$x != 1} {error "x $x != 1"} if {$args ne ""} {error "args $args ne {}"} } o proc p3 {{-x 1} args} { if {$x != 1} {error "x $x != 1"} if {$args ne "a b c"} {error "args $args ne {}"} } o proc p4 {{-x 1} args} { if {$x != 2} {error "x $x != 2"} if {$args ne "a b c"} {error "args $args ne {a b c}"} } o proc p5 {{-x 1} a1 args} { #puts "--- [self proc] x=$x [info exists a1] args=$args" if {![info exists a1]} {error "pos arg a1 does not exist"} if {$a1 != 1} {error "a $a1 != 1"} if {$x != 1} {error "x $x != 1"} if {$args ne "a b c"} {error "args $args ne {a b c}"} } o proc p6 {{-x 1} a1 args} { #puts "--- [self proc] x=$x [info exists a1] args=$args" if {![info exists a1]} {error "pos arg a1 does not exist"} if {$a1 != 1} {error "a1 $a1 != 1"} if {$x != 2} {error "x $x != 2"} if {$args ne "a b c"} {error "args $args ne {a b c}"} } o proc p7 {{-x 1} a1 args} { #puts "--- [self proc] x=$x [info exists a1] args=$args" if {![info exists a1]} {error "pos arg a1 does not exist"} if {$a1 != 1} {error "a1 $a1 != 1"} if {$x != 2} {error "x $x != 2"} if {$args ne ""} {error "args $args ne {}"} } o proc p8 {{-x 1} {a1 1} args} { #puts "--- [self proc] x=$x [info exists a] args=$args" if {![info exists a1]} {error "pos arg a1 does not exist"} if {$a1 != 1} {error "a1 $a1 != 1"} if {$x != 2} {error "x $x != 2"} if {$args ne ""} {error "args $args ne {}"} } errorCheck [catch {o f1 x}] 0 nonpos-1 errorCheck [catch {o f1 -y 1}] 1 nonpos-2 errorCheck [catch {o f1 -x false}] 1 nonpos-3 errorCheck [catch {o f2 -x false}] 0 nonpos-4 errorCheck [catch {o f3}] 0 nonpos-5 errorCheck [catch {o f3 -x true -y 1}] 1 nonpos-6 errorCheck [catch {o f3-y 1}] 1 nonpos-7 errorCheck [catch {o p0 1}] 0 nonpos-8 errorCheck [catch {o p1 1}] 0 nonpos-9 errorCheck [catch {o p1 }] 1 nonpos-10 errorCheck [catch {o p2 }] 0 nonpos-11 errorCheck [catch {o p3 a b c}] 0 nonpos-12 errorCheck [catch {o p4 -x 2 a b c}] 0 nonpos-13 errorCheck [catch {o p5 1 a b c}] 0 nonpos-14 errorCheck [catch {o p7 -x 2 1}] 0 nonpos-15 errorCheck [catch {o p7 -x 2 }] 1 nonpos-16 errorCheck [catch {o p8 -x 2 }] 0 nonpos-17 o proc foo {-enable:switch i:integer} { return "enable=$enable, i=$i" } o proc bar {-enable:switch o:object c:class} { return "o=$o c=$c" } errorCheck [catch {o foo 123}] 0 check-pos-args-1 errorCheck [catch {o foo abc}] 1 check-pos-args-2 errorCheck [catch {o bar o Object}] 0 check-pos-args-3 errorCheck [catch {o bar ooo Object}] 1 check-pos-args-4 errorCheck [catch {o bar o Object1}] 1 check-pos-args-5 Class X X instproc ListOfStringsOption {{-default "murr6"} {-cb {}} name} { if {$cb eq {}} { set cb "::set ::$name " } ;# global variable eval $cb \$default } ::X create x1 ::x1 ListOfStringsOption uu errorCheck [set ::uu] murr6 murr6 ::x1 destroy X destroy } TestX copymove2 -proc run {{n 10}} { # Composite Class Composite -superclass Class Composite instproc addop {op} { my instvar ops set ops($op) $op } Composite instproc compositeFilter args { set m [self calledproc] set c [lindex [self filterreg] 0] set r [next] if {[$c exists ops($m)]} { foreach child [my info children] { eval [self]::$child $m $args } } return $r } Composite AbstractNode AbstractNode abstract instproc iterate v AbstractNode addop iterate for {set i 0} {$i < $n} {incr i} { # # class copy # foreach filters {{} compositeFilter} { Composite instfilter $filters AbstractNode instfilter $filters Object commands Class Commands -superclass AbstractNode Class Command -superclass Commands Command instproc init args { my instvar label set label [self] next } Command instproc setlabel {{arg ""}} { my instvar label if {$arg eq ""} { set label } else { set label $arg } } Command instproc setproc {value} { my instvar src set src $value } # prototypes Command commands::cellcmd commands::cellcmd copy toto } } } TestX proc run {} { foreach test [lsort [TestX info instances]] { puts stderr "$test: start" $test run } } puts "XOTcl - Test" puts "Time used: [time {TestX run} 1]" # toplevel tests ################################################# Class instmixin {} C instmixin {} set o [C new -volatile];errorCheck [Object isobject $o] 1 "topLevel, check object 1 - $o" Class instmixin ::xotcl::_creator set o [C new -volatile];errorCheck [Object isobject $o] 1 "topLevel, check object 2 - $o" C instmixin ::xotcl::I set o [C new -volatile];errorCheck [Object isobject $o] 1 "topLevel, check object 3 - $o" foreach i [C info instances] {$i destroy} proc x {} { Class instmixin {} C instmixin {} set c0 [llength [C info instances]] set o1 [C new -volatile]; errorCheck [Object isobject $o1] 1 "x, check object" Class instmixin ::xotcl::_creator set o2 [C new -volatile]; errorCheck [Object isobject $o2] 1 "x, check object" C instmixin ::xotcl::I set o3 [C new -volatile]; errorCheck [Object isobject $o3] 1 "x, check object" set c1 [llength [C info instances]] errorCheck [expr {$c1 - $c0 != 3}] 0 "exit x, three more objects" #puts stderr "WE HAVE $o1 $o2 $o3" } x errorCheck [expr {[llength [C info instances]] > 0}] 0 "top, all volatile object gone" proc x1 {} { set c0 [llength [C info instances]] set o1 [C new -volatile]; errorCheck [Object isobject $o1] 1 "x1, check object $o1" x set o2 [C new -volatile]; errorCheck [Object isobject $o2] 1 "x1, check object $o2" set c1 [llength [C info instances]] errorCheck [expr {$c1 - $c0 != 2}] 0 "exit x1, two more objects - $c1 ($o1,$o2), [C info instances]" } x1 errorCheck [expr {[llength [C info instances]] > 0}] 0 "top, volatile objects gone" Object o o proc test {} { x1; errorCheck [expr {[llength [C info instances]] > 0}] 0 "x1 from o" } o test puts "PASSED ::topLevelCommands" # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/xotcl/tests/xocomm.test000644 000766 000024 00000006703 12501766547 021355 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package prefer latest package require XOTcl 2.0; namespace import ::xotcl::* set auto_path [concat [file dirname [info script]]/../library $auto_path] package require nx::test @ @File { description { This is a webclient used as a regression test. When it is started it launches an xotcl-Web server as partner process. It tests currently the basic functionality of:

  • GET and PUT requests
  • Basic Access Control
} } array set opt {-startServer 1} array set opt $argv set xotclsh [info nameofexecutable] set dir [file dir [info script]] set serverScript $dir/../apps/comm/webserver.xotcl set startCmd "$xotclsh $serverScript -root $dir/../doc -pkgdir $dir/../library" puts $startCmd if {$opt(-startServer)} { set PIPE [open "| $startCmd"] } else { puts $startCmd } package require xotcl::comm::httpAccess package require xotcl::comm::ftp package require xotcl::trace #::xotcl::package verbose 1 #::xotcl::package require xotcl::comm::httpAccess #::xotcl::package require xotcl::comm::ftp #::xotcl::package require xotcl::trace set hostport localhost:8086 set protectedhostport localhost:9096 set slowURL "http://quote.yahoo.com/q?s=^DJI&d=1d" set ftpURL "ftp://mohegan.wi-inf.uni-essen.de/welcome.msg" proc printError msg {puts stderr !!!$msg!!!} Object userPwd userPwd proc user {u} { my set user $u if {[set ::tcl_platform(platform)] == "windows"} { my set user unknown } } userPwd proc show {realm userVar pwVar} { upvar $userVar u $pwVar pw set u [my set user] set pw test return 1 } #Test parameter {{errorReport { # puts "\tcontent-length: \[r0::sink set contentLength\]\n\ # \tstatus-code: \[\[r0 set token\] set responseCode\]" #}}} nx::test new -msg "Trying to load image logo-100.jpg ... " \ -verbose 1 \ -pre "puts starting..." \ -setResult {expr {[r0::sink set contentLength] == 1706}} \ -cmd [list SimpleRequest r0 -url http://$hostport/logo-100.jpg] \ nx::test new -msg "Trying to PUT a file on web-server ... " \ -setResult {expr [[r0 set token] set responseCode] == 201} \ -pre [list file delete -force $dir/../doc/junk.junk] \ -cmd [list SimpleRequest r0 \ -url http://$hostport/junk.junk \ -method PUT \ -data "this is a test\n" \ -contentType plain/text] nx::test new -msg "And download it again ... " \ -setResult {expr [r0 getContentLength] == 15} \ -post {file delete -force ../doc/junk.junk} \ -cmd [list SimpleRequest r0 -url http://$hostport/junk.junk] nx::test new -msg "Get protected resource ... " \ -setResult {expr [r0 getContentLength] > 500} \ -cmd [list SimpleRequest r0 -url http://$protectedhostport/ ] #nx::test new -msg "Try an FTP request $ftpURL ... " \ -setResult {expr [r0 getContentLength] > 100} \ -cmd [list SimpleRequest r0 -url $ftpURL] #nx::test new -msg "Try timeout with slow URL $slowURL ... " \ -setResult {expr {[[r0 set token] set errormsg] == {timeout exceeded}}} \ -cmd [list SimpleRequest r0 -url $slowURL -timeout 100] nx::test new -msg terminate \ -setResult {set x 1} \ -cmd [list SimpleRequest r0 -url http://$protectedhostport/exit] \ -post {set ::forever 1} #puts stderr "present [package present xotcl::comm::connection]" #puts stderr "versions [package versions xotcl::comm::connection]" after 1000 {nx::test run} catch {vwait forever} # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/xotcl/tests/testo.xotcl000644 000766 000024 00000027227 12501766547 021367 0ustar00neumannstaff000000 000000 # # Copyright 1993 Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # package prefer latest package require XOTcl 2.0; namespace import ::xotcl::* @ @File {description { This is a class which provides regression test objects for the OTcl derived features of the XOTcl - Language. This script is based upon the test.tcl script of the OTcl distribution and adopted for XOTcl. } } # # a meta-class for test objects, and a class for test suites # Class TestSuite @ Class TestSuite Class TestClass -superclass Class @ Class TestClass { description { A meta-class for test objects. } } # # check basic argument dispatch and unknown # TestSuite objectdispatch objectdispatch proc run {{n 50}} { Object adispatch adispatch proc unknown {m args} {eval list [list $m] $args} adispatch proc cycle {l n args} { if {$l>=$n} then {return ok} set i [llength $args] foreach a $args { if {$a != $i} then { error "wrong order in arguments: $l $n $args" } incr i -1 } incr l set ukn [eval [list [self]] $args] if {$ukn != $args} then { error "wrong order in unknown: $ukns" } eval [list [self]] [list [self proc]] [list $l] [list $n] [list $l] $args } if {[catch {adispatch cycle 1 $n 1} msg]} then { error "FAILED [self]: cycle: $msg" } return "PASSED [self]" } # # examples from the workshop paper # TestSuite paperexamples paperexamples proc example1 {} { Object astack astack set things {} astack proc put {thing} { my instvar things set things [concat [list $thing] $things] return $thing } astack proc get {} { my instvar things set top [lindex $things 0] set things [lrange $things 1 end] return $top } astack put bagel astack get astack destroy } paperexamples proc example2 {} { Class Safety Safety instproc init {} { next my set count 0 } Safety instproc put {thing} { my instvar count incr count next } Safety instproc get {} { my instvar count if {$count == 0} then { return {empty!} } incr count -1 next } Class Stack Stack instproc init {} { next my set things {} } Stack instproc put {thing} { my instvar things set things [concat [list $thing] $things] return $thing } Stack instproc get {} { my instvar things set top [lindex $things 0] set things [lrange $things 1 end] return $top } Class SafeStack -superclass {Safety Stack} SafeStack s s put bagel s get s get s destroy SafeStack destroy Stack destroy Safety destroy } paperexamples proc run {} { set msg {} if {[catch {my example1; my example2} msg] == "0"} then { return "PASSED [self]" } else { error "FAILED [self]: $msg" } } # # create a graph of classes # TestSuite classcreate classcreate proc factorgraph {{n 3600}} { TestClass $n for {set i [expr {$n/2}]} {$i>1} {incr i -1} { if {($n % $i) == 0} then { # # factors become subclasses, direct or indirect # if {[TestClass info instances $i] eq ""} then { my factorgraph $i $i superclass $n } elseif {[$i info superclass $n] == 0} then { $i superclass [concat [$i info superclass] $n] } } } } classcreate proc run {} { set msg {} if {[catch {my factorgraph} msg] == "0"} then { return "PASSED [self]" } else { error "FAILED [self]: $msg" } } # # lookup superclasses and combine inherited methods # TestSuite inheritance inheritance proc meshes {s l} { set p -1 foreach j $s { set n [lsearch -exact $l $j] if {$n == -1} then { error "FAILED [self] - missing superclass" } if {$n <= $p} then { error "FAILED [self] - misordered heritage: $s : $l" } set p $n } } inheritance proc superclass {} { foreach i [TestClass info instances] { set s [$i info superclass] set h [$i info heritage] # # superclasses should mesh with heritage # my meshes $s $h } } inheritance proc combination {} { foreach i [lsort [TestClass info instances]] { # # combination should mesh with heritage # $i anumber set obj [lrange [anumber combineforobj] 1 end] set h [$i info heritage] my meshes $obj $h anumber destroy if {[$i info procs combineforclass] ne ""} then { set cls [lrange [$i combineforclass] 1 end] my meshes $cls $h } } } inheritance proc run {} { # # add combine methods to "random" half of the graph # set t [TestClass info instances] for {set i 0} {$i < [llength $t]} {incr i 2} { set o [lindex $t $i] $o instproc combineforobj {} { return [concat [list [self class]] [next]] } $o proc combineforclass {} { return [concat [list [self class]] [next]] } } # # and to Object as a fallback # Object instproc combineforobj {} { return [concat [list [self class]] [next]] } Object proc combineforclass {} { return [concat [list [self class]] [next]] } my superclass my combination return "PASSED [self]" } # # destroy graph of classes # TestSuite classdestroy classdestroy proc run {} { # # remove half of the graph at a time # TestClass instproc destroy {} { global TCdestroy set TCdestroy [self] next } while {[TestClass info instances] ne ""} { set t [TestClass info instances] for {set i 0} {$i < [llength $t]} {incr i} { set o [lindex $t $i] # # quarter dies directly, quarter indirectly, quarter renamed # if {($i % 2) == 0} then { global TCdestroy set sb [$o info subclass] if {[info tclversion] >= 7.4 && ($i % 4) == 0} then { $o move "" } else { $o destroy } if {[catch {set TCdestroy}] || $TCdestroy != $o} then { error "FAILED [self] - destroy instproc not run for $o" } if {[info commands $o] ne ""} then { error "FAILED [self] - $o not removed from interpreter" } unset TCdestroy # # but everyone must still have a superclass # foreach j $sb { if {[$j info superclass] eq ""} then { $j superclass Object } } } elseif {[info tclversion] >= 7.4 && ($i % 3) == 0} then { $o move $o.$i } } inheritance superclass inheritance combination } return "PASSED [self]" } TestSuite objectinits objectinits proc prepare {n} { # # head of a chain of classes that do add inits # TestClass 0 0 instproc init {args} { next my set order {} } # # and the rest # for {set i 1} {$i < $n} {incr i} { TestClass $i -superclass [expr {$i-1}] # # record the reverse order of inits # $i instproc init {args} { eval next $args my instvar order lappend order [namespace tail [self class]] } # # add instproc for init options # $i instproc m$i.set {val} { my instvar [namespace tail [self class]] set [namespace tail [self class]] [self proc].$val } } } objectinits proc run {{n 15}} { my prepare $n set il {} for {set i 1} {$i < $n} {incr i} { lappend il $i set al {} set args {} for {set j $i} {$j > 0} {incr j -1} { lappend al $j lappend args -m$j.set $j # # create obj of increasing class with increasing options # if {[catch {eval $i m$i.$j $args} msg] != 0} then { error "FAILED [self] - $msg" } if {[m$i.$j set order] != $il} then { error "FAILED [self] - inited order was wrong" } set vl [lsort -decreasing -integer [m$i.$j info vars {[0-9]*}]] if {$vl != $al} then { error "FAILED [self] - wrong instvar names: $vl : $al" } foreach k $vl { if {[m$i.$j set $k] != "m$k.set.$k"} then { error "FAILED [self] - wrong instvar values" } } } } return "PASSED [self]" } TestSuite objectvariables objectvariables proc run {{n 100}} { TestClass Variables Variables avar foreach obj {avar Variables TestClass xotcl::Class xotcl::Object} { # # set up some variables # $obj set scalar 0 $obj set array() {} $obj unset array() $obj set unset.$n {} # # mess with them recursively # $obj proc recurse {n} { my instvar scalar array incr scalar set array($n) $n my instvar unset.$n unset unset.$n incr n -1 my instvar unset.$n set unset.$n [array names array] if {$n > 0} then { my recurse $n } } $obj recurse $n # # check the result and clean up # if {[$obj set scalar] != $n} then { error "FAILED [self] - scalar [$obj set scalar] != $n" } $obj unset scalar for {set i $n} {$i > 0} {incr i -1} { if {[$obj set array($i)] != $i} then { error "FAILED [self] - array" } } $obj unset array if {[$obj info vars "unset.0"] eq ""} then { error "FAILED [self] - unset: [$obj info vars]" } } # # trace variables # Variables avar2 proc ::traceproc {maj min op} { set majTmp [namespace tail "$maj"] #puts stderr ...TRACE global trail; lappend trail [list $majTmp $min $op] } avar2 proc trace {var ops} { my instvar $var ::trace variable $var $ops "avar2 traceproc" #puts stderr "::trace variable $var $ops avar2 traceproc" } avar2 proc traceproc {maj min op} { set majTmp [namespace tail $maj] #puts stderr ...TRACE global trail; lappend trail [list $majTmp $min $op] } avar2 proc killSelf {} { my destroy } global guide trail set trail {} set guide {} avar2 trace array wu for {set i 0} {$i < $n} {incr i} { avar2 trace scalar$i wu avar2 set scalar$i $i lappend guide [list scalar$i {} w] avar2 set array($i) [avar2 set scalar$i] lappend guide [list array $i w] } if {$guide != $trail} then { error "FAILED [self] - trace: expected $guide, got $trail" } # # destroy must trigger unset traces # set trail {} set guide {} lappend guide [list array {} u] for {set i 0} {$i < $n} {incr i} { lappend guide [list scalar$i {} u] } avar2 killSelf if {[lsort $guide] != [lsort $trail]} then { error "FAILED [self] - trace: expected $guide, got $trail" } Variables destroy return "PASSED [self]" } # # c api, if compiled with -DTESTCAPI # TestSuite capi capi proc run {{n 50}} { set start [dawnoftime read] for {set i 0} {$i < $n} {incr i} { Timer atime$i if {$i % 3} {atime$i stop} if {$i % 7} {atime$i read} if {$i % 2} {atime$i start} if {$i % 5} {atime$i stop} } set end [dawnoftime read] if {$end < $start} { error "FAILED [self]: timer doesn't work" } foreach i [Timer info instances] {$i destroy} Timer destroy return "PASSED [self]" } TestSuite proc run {} { # # run individual tests in needed order # puts [objectdispatch run] puts [paperexamples run] puts [classcreate run] puts [inheritance run] puts [classdestroy run] puts [objectinits run] puts [objectvariables run] if {[info commands Timer] ne ""} then { puts [capi run] } # puts [autoload run] } puts [time {TestSuite run} 1] # Local Variables: # mode: tcl # tcl-indent-level: 2 # End: ./nsf2.4.0/library/xotcl/library/comm/Ldap.xotcl000644 000766 000024 00000007757 12501766547 022354 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package provide xotcl::comm::ldap 2.0 package require xotcl::wafecompat ; # Get 'requireModules'. package require XOTcl 2.0 namespace eval ::xotcl::comm::ldap { namespace import ::xotcl::* requireModules { ldapOpen ldaplibGen.so } Class Ldap -superclass NetAccess -parameter {host port dn attributes scope filter} Ldap instproc initialize args { my instvar port mapToC useCache my set port 389 my set useCache 0 set mapToC(one) onelevel set mapToC(sub) subtree set mapToC(base) base next } Ldap proc urlDecode string { set toParse $string set parsed "" while {1} { if {[regexp {^([^%]*)%(..)(.*)$} $toParse _ front hex toParse]} { append parsed $front [binary format c 0x$hex] } else { append parsed $toParse break } } return $parsed } Ldap instproc getUrlcomponents {} { showCall my instvar path dn attributes scope filter url set path [Ldap urlDecode $path] puts stderr "___ path=<$path>" if {[regexp -nocase {^/([^?]*)(\?([^?]*)(\?([^?]*)(\?([^?]*))?)?)?$} \ $path _ dn a attributes s scope f filter]} { if {$scope eq ""} { set scope "base" } if {$filter eq ""} { set filter "(objectClass=*)" } } else { set errmsg "*** Ldap Url trail=<$path> does not match!\n" append errmsg "___ RFC 1959 says:\n" append errmsg " ldap://:/\[?\[??\]\]\n" append errmsg "___ Cineast and Netscape uses:\n" append errmsg " ldap://:/\[?\[?\[?\]\]\]" my abort "Unsupported URL: '$url' \n $errmsg" } } Ldap instproc GET {} { my instvar contentType totalsize state currentsize informObjects block showCall set contentType text/html my getUrlcomponents if {"start" ne $state } { puts stderr "... [self]:$proc ignoring request in state $state" return } my open my search my body-state set totalsize [string length $block] set currentsize $totalsize foreach obj $informObjects { $obj incCb [self] $totalsize $currentsize } my eof } Ldap instproc open {} { showCall my instvar port host ldapHandle set ldapHandle [ldapOpen $host $port] } Ldap instproc bind {} { my instvar ldapHandle showCall } Ldap instproc search {} { showVars my instvar url ldapHandle searchHandle dn attributes scope filter results mapToC path set searchHandle [ldapSearch $ldapHandle $dn \ $mapToC($scope) $filter [split $attributes ,] false results] set nentries [ldapCountEntries $ldapHandle $searchHandle] puts stderr "*** nentries = $nentries" if {!$nentries} {set results ""} my response } Ldap instproc getAttrs {dn} { } Ldap instproc makeUrl {dn} { showCall my instvar port host scope filter attributes set tmpUrl ldap://$host:$port/$dn?$attributes?$scope?$filter return "$dn" } Ldap instproc response {} { showCall my instvar block results attrsVals ldapHandle searchHandle set block " LDAP searching result!!

Result

\n
    \n" foreach {resDN} $results { append block "
  • [my makeUrl $resDN]

    \n

      \n" ldapAttributes $ldapHandle $searchHandle $resDN attrsVals foreach {a v} [array get attrsVals] { append block "
    • $a = $v

      \n" } append block "

    \n" } append block "
\n \n" } # destructor: Close Connection to LDAP-Server and unbind Ldap instproc destroy {} { showCall my instvar ldapHandle if {[catch {ldapUnbind $ldapHandle} error]} { return $error } my freeSearchHandle } Ldap instproc close {} { showCall my destroy next } Ldap instproc freeSearchHandle {} { showCall my instvar searchHandle if {[info exists searchHandle]} { ldapFreeSearch $searchHandle } } namespace export Ldap } namespace import ::xotcl::comm::ldap::* ./nsf2.4.0/library/xotcl/library/comm/Ftp.xotcl000644 000766 000024 00000011055 12501766547 022207 0ustar00neumannstaff000000 000000 # -*- Tcl -*- $ package provide xotcl::comm::ftp 2.0 package require xotcl::comm::httpAccess package require XOTcl 2.0 namespace eval ::xotcl::comm::ftp { namespace import ::xotcl::* Class Ftp -superclass NetAccess -parameter {user passwd} Ftp instproc initialize args { #my showCall my instvar port caching user passwd loginMsg resp blocksize set port 21 set blocksize 1024 set caching 0 set user ftp set passwd cineast@ set loginMsg {} set resp(connect) {220 provideUser} set resp(provideUser) {331 providePasswd} set resp(providePasswd) {230 loginFinished} set resp(loginFinished) {227 pasv} set resp(pasv) {200 type} set resp(type-list) {150 list} set resp(type-retr) {150 retr 550 retry-retrieve} set resp(transfer) {226 transferDone} next } Ftp instproc err {state reply} { my abort "Error in $state: $reply" } Ftp instproc queryServer {query state} { my instvar S puts $S $query flush $S fileevent $S readable [::list [self] response $state] } Ftp instproc response {state} { #my showCall my instvar S code msg set reply [gets $S] #my showVars reply if {[regexp {^([0-9]+)[-](.*)$} $reply _ code msg]} { fileevent $S readable [::list [self] responseMulti $state] } else { regexp {^([0-9]+) (.*)$} $reply _ code msg my responseEnd $state } } Ftp instproc responseMulti {state} { # multi line response my instvar S code msg set m [gets $S] if {[regexp "^$code " $m]} { my responseEnd $state } else { # try to strip code and dash regexp "^$code-(.*)\$" $m _ m append msg \n$m } } Ftp instproc responseEnd {state} { my instvar S code msg resp fileevent $S readable {} #puts stderr "code=$code, msg=<$msg>" foreach {c newState} $resp($state) { if {$c == $code} { return [my $newState] } } my err $state "expected=$resp($state), got $code $msg" } Ftp instproc GET {} { my instvar S host port url regexp {^(.*):([0-9]+)$} $host _ host port my running # rb running my $url ;# ??? # proxy ? set S [socket -async $host $port] fconfigure $S -blocking false -translation {auto crlf} fileevent $S readable [::list [self] response connect] } Ftp instproc provideUser {} { my instvar user msg loginMsg set loginMsg $msg my queryServer "USER $user" provideUser } Ftp instproc providePasswd {} { my instvar passwd # if {[pwdManager requirePasswd "Ftp $user\@$host" $user password]} { # my queryServer "PASS $password" providePasswd # } my queryServer "PASS $passwd" providePasswd } Ftp instproc loginFinished {} { my instvar msg loginMsg append loginMsg \n$msg my queryServer "PASV" loginFinished } Ftp instproc pasv {} { my instvar S D msg set d {([0-9]+)} if {[regexp "\[(]$d,$d,$d,$d,$d,$d" $msg _ 1 2 3 4 p1 p2]} { if {[catch {set D [socket -async $1.$2.$3.$4 [expr {$p1*256 + $p2}]]} err ]} { return [my err $proc $err] } fconfigure $D -blocking no -translation binary } else { return [my err $proc $msg] } my queryServer "TYPE I" pasv } Ftp instproc type {} { my instvar path if {$path=={}} { my queryServer "LIST" type-list } elseif {[regexp /$ $path]} { my queryServer "LIST $path" type-list } else { my queryServer "RETR $path" type-retr } } Ftp instproc retry-retrieve {} { my instvar path url append url / my queryServer "LIST $path/" type-list } Ftp instproc list {} { my instvar S D contentType set contentType text/dirlist my headerDone fileevent $S readable [::list [self] response transfer] fileevent $D readable [::list [self] readData] } Ftp instproc read {} { # the method read is called by the more general method readData my instvar D block blocksize if {[::eof $D]} { set block "" close $D unset D } else { #puts stderr blocksize=$blocksize set block [::read $D $blocksize] #puts stderr read:[string length $block]bytes } } Ftp instproc transferDone {} { my instvar D S if {[info exists D]} { fileevent $S readable {} set block "" close $D unset D } my finish } Ftp instproc retr {} { my instvar S D msg totalsize contentType path regexp {[(]([0-9]+)[ ]+[Bb]ytes} $msg _ totalsize set contentType [Mime guessContentType $path] my headerDone if {[info exists S]} { # file dialog was not canceled fileevent $S readable [::list [self] response transfer] fileevent $D readable [::list [self] readData] fconfigure $D -translation binary } } namespace export Ftp } namespace import ::xotcl::comm::ftp::* ./nsf2.4.0/library/xotcl/library/comm/Connection.xotcl000644 000766 000024 00000016657 13717240552 023563 0ustar00neumannstaff000000 000000 # -*- tcl -*- $ package provide xotcl::comm::connection 2.0 package require XOTcl 2.0 namespace eval ::xotcl::comm::connection { namespace import ::xotcl::* Class Connection -parameter {host port req socket handle} Connection proc make {r host port reuse reusedVar} { #my showCall my instvar openConnections upvar [self callinglevel] $reusedVar reused if {$reuse} { set handle $host:$port-[$r set blocking] #if {[array exists openConnections]} {parray openConnections} if {![info exists openConnections($handle)]} { # there is no persistent connection, we create a new one set reused 0 set openConnections($handle) \ [Connection new -host $host -port $port -req $r -handle $handle] #my showMsg "$openConnections($handle) CONNECTION add for $handle added" } else { # there is a persistent connection set reused 1 set c $openConnections($handle) $c instvar req #::puts stderr "$c CONNECTION reuse for $handle ($c) new req=$r" if {[info exists req]} { # the persistent connection is active with some request $req #::puts stderr "$c CONNECTION req $req already active" } else { # the persistent connection is currently not active $c set req $r } } return $openConnections($handle) } else { set reused 0 return [Connection new -host $host -port $port -req $r] } } Connection proc removeHandle handle { #my showVars #puts stderr "***************** unsetting $handle ***************" if {[my exists openConnections($handle)]} { my unset openConnections($handle) } } Connection instproc init args { ;# the constructor creates the socket my set blocked {} next if {[my exists socket]} { my set keepOpen 1 } else { my set keepOpen 0 if {[catch {my socket [socket -async [my host] [my port]]} msg]} { my set error $msg return } } ::fconfigure [my socket] -blocking false -buffersize 16384 } #Connection instproc STATUS {ctx} { # my instvar socket # ::puts stderr "*** $ctx: $socket blocking=[::fconfigure $socket -blocking]" #} Connection instproc destroy {} { ;# the destructor closes the socket #my showCall if {[my exists handle]} { #my showVars handle # the connection was created via make [self class] removeHandle [my set handle] #::puts stderr "my CONNECTION close and destroy [my set handle]" } else { #::puts stderr "my CONNECTION close and destroy" } # in cases of errors we might not have a socket yet if {[my exists socket]} { close [my set socket] } next } Connection instproc translation {translation} { #showCall ::fconfigure [my socket] -translation $translation } Connection instproc importSSL args { #my showCall package require tls eval tls::import [my socket] $args } Connection instproc fconfigure args { #my showCall eval ::fconfigure [my socket] $args } Connection instproc event {type r method} { #my showCall my instvar req blocked # is the request in the argument list the currently active request? if {[info exists req] && $r == $req} { # a request can overwrite its active request if {$method eq ""} { ::fileevent [my socket] $type "" #my showMsg "CONNECTION clear for [my socket]" } else { #my showMsg "CONNECTION register for [my socket]" ::fileevent [my socket] $type [list $r $method] } } else { #my showMsg "event BLOCKING current request=$req, new=$r $method" #my showMsg "event BLOCKING rd=[::fileevent [my socket] readable]" #my showMsg "event BLOCKING wr=[::fileevent [my socket] writable]" #my showMsg "event BLOCKING bl=$blocked" ::lappend blocked $r $type $method } } Connection instproc hold {} { my set continueCmd [list ::fileevent [my socket] readable \ [::fileevent [my socket] readable]] ::fileevent $socket readable {} #my showVars continueCmd } Connection instproc resume {} { #my showCall if {[my exists continueCmd]} { eval [my set continueCmd] my unset continueCmd } } Connection instproc puts {string} { #my showCall if {[catch {::puts [my socket] $string} msg]} { ::puts stderr message=$msg } } Connection instproc puts-nonewline {string} { #my showCall if {[catch {::puts -nonewline [my socket] $string} msg]} { ::puts stderr message=$msg } } Connection instproc gets {var} { #my showCall upvar [self callinglevel] $var result if {[catch {set n [::gets [my socket] result]} msg]} { my set error $msg #my showMsg "CONNECTION error: $msg" return 0 } #my showMsg "n=$n, result=<$result>" return $n } Connection instproc read {} { # my showCall my instvar socket # Prior to the fix for Tcl bug #3401422, there was a regression # in Tcl 8.6 beta versions, causing a previously nonblocking # socket created using [socket -async] to return to a blocking # state. This required a manual overwrite (see below). Starting # with the 8.6 release candidates, this is obsolete. # # ::fconfigure $socket -blocking 0 if {[catch {set result [::read $socket [::fconfigure $socket -buffersize]]} msg]} { my set error $msg return "" } return $result } Connection instproc readSize {length} { if {[catch {set result [::read [my socket] $length]} msg]} { my set error $msg return 0 } return $result } Connection instproc flush {} { #my showCall if {[catch {::flush [my socket]} msg]} { my set error $msg } } Connection instproc eof {} { #my showCall if {[my exists error]} { return 1 } else { return [::eof [my socket]] } } Connection instproc close {} { #my showCall my instvar req socket blocked if {![info exists socket]} return ;# error during connection open ::fileevent $socket readable "" ::fileevent $socket writable "" $req freeConnection if {[my exists persistent]} { my flush #::puts stderr "[self] PERSISTENT CONNECTION wants close" if {$blocked eq ""} { ::fileevent $socket readable [list [self] destroy] unset req } else { #my showVars blocked set req [lindex $blocked 0] set type [lindex $blocked 1] set method [lindex $blocked 2] set blocked [lrange $blocked 3 end] #my showMsg "in persistent connection unblock $type [list $req $method]" ::fileevent $socket $type [list $req $method] } } else { #my showMsg "in nonpersistent connection blocked=$blocked" if {$blocked ne ""} { set req [lindex $blocked 0] set type [lindex $blocked 1] set method [lindex $blocked 2] set nblocked [lrange $blocked 3 end] close $socket unset socket if {[my exists handle]} { [self class] removeHandle [my set handle] } if {[my exists error]} { #my showMsg "UNSETTING ERROR -----------" my unset error } my init set blocked $nblocked ::fileevent $socket $type [list $req $method] #my showMsg "REANIMATE $socket $type [list $req $method]" #my showVars } else { #my showMsg "Nothing blocked: readable=[::fileevent $socket readable]" my destroy } } } Connection instproc makePersistent {p} { if {$p} { my set persistent 1 } else { if {[my exists persistent]} { my unset persistent #my showMsg "no longer persistent" } } } namespace export Connection } namespace import ::xotcl::comm::connection::* if {[info command bgerror] eq ""} { proc bgerror {msg} { puts stderr "******* bgerror $msg $::errorInfo*****"} } ./nsf2.4.0/library/xotcl/library/comm/Mime.xotcl000644 000766 000024 00000016233 12501766547 022350 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package provide xotcl::comm::mime 2.0 package require XOTcl 2.0 namespace eval ::xotcl::comm::mime { namespace import ::xotcl::* ####################################################################### Class MimeTypeLoader MimeTypeLoader instproc loadMimeTypes {file} { if {![file exists $file]} return puts stderr "Loading Mime types from $file" set f [open $file r] set content [read $f] close $f regsub -all "\\\\ *\n" $content " " content foreach line [split $content \n] { set line [string trim $line] if {[regexp ^\# $line]} continue if {$line eq ""} continue regsub -all " +" $line " " line #puts stderr <$line> while {$line ne ""} { if {[regexp {^ *([^ ]+)=\"([^\"]+)\" *(.*)$} $line _ key value line]} { set v([string tolower $key]) $value } elseif {[regexp {^ *([^ ]+)=([^ ]+) *(.*)$} $line _ key value line]} { set v([string tolower $key]) $value } else { set tokens [split $line] if {![regexp / [lindex $line 0]]} { puts stderr "Mime: cannot parse line '$line' in $file" } else { set v(exts) [join [lrange $tokens 1 end] ,] set v(type) [lindex $tokens 0] } break } } if {[info exists v(exts)] && [info exists v(type)]} { set v(exts) [string tolower $v(exts)] set v(type) [string tolower $v(type)] foreach ext [split $v(exts) ,] { set ext [string trimleft $ext .] #puts stderr "ext '$ext', contentType = '$v(type)'" my set extTable($ext) $v(type) } unset v(exts) v(type) } else { puts stderr "invalid mime entry in $file" } } } MimeTypeLoader instproc guessContentType {name} { my loadMimeTypes ~/.mime.types my mixin {} return [next] } Class MIME MIME instproc guessContentType {name} { my instvar extTable nameTable if {[regexp {\.([a-zA-Z0-9]+)$} $name _ ext]} { catch {set contentType $extTable([string tolower $ext])} } if {![info exists contentType]} { foreach namePattern [array names nameTable] { if {[regexp $namePattern $name]} { set contentType text/plain break } } } if {![info exists contentType]} { set contentType unknown/unknown } return $contentType } MIME instproc multipart-decode-header {header obj} { $obj instvar name filename contentType foreach line [split $header \r] { set line [string trim $line \n] #puts stderr line=$line if {[regexp -nocase {^Content-Disposition: *([^;]+);(.*)$} $line _ \ dispo detail]} { if {$dispo ne "form-data"} { error "Unknown Content Disposition '$line'" } if {![regexp -nocase { name *= *"([^\"]+)"} $line _ name]} { error "can't parse form-data name '$line'" } regexp -nocase {filename *= *"([^\"]+)"} $line _ filename } elseif {[regexp -nocase {^Content-Type: *([^; ]+)} $line _ contentType]} { } else { my showMsg "ignoring '$line'" } } } MIME create Mime -mixin MimeTypeLoader Mime array set nameTable { README text/plain } Mime array set extTable { gif image/gif xpm image/x-xpixmap xbm image/x-xbitmap jpg image/jpeg png image/x-png html text/html htm text/html xml text/xml css text/css ps application/postscript pdf application/pdf doc application/msword xls application/msexel } ################################################################## Class FormData FormData instproc encode list {;#RFC 1867 my showCall } FormData formData ################################################################## Class Base64 Base64 instproc init args { my instvar base64 base64_en # Emit base64 encoding for a string set i 0 foreach char {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \ a b c d e f g h i j k l m n o p q r s t u v w x y z \ 0 1 2 3 4 5 6 7 8 9 + /} { set base64($char) $i set base64_en($i) $char incr i } next } Base64 instproc encode string { my instvar base64_en set result {} set length 0 foreach {a b c} [split $string {}] { scan $a %c x if {$c ne ""} { scan $b %c y scan $c %c z append result \ $base64_en([expr {($x>>2) & 0x3F}]) \ $base64_en([expr {(($x<<4) & 0x30) | (($y>>4) & 0xF)}]) \ $base64_en([expr {(($y<<2) & 0x3C) | (($z>>6) & 0x3)}]) \ $base64_en([expr {$z & 0x3F}]) } elseif {$b ne ""} { scan $b %c y append result \ $base64_en([expr {($x>>2) & 0x3F}]) \ $base64_en([expr {(($x<<4) & 0x30) | (($y>>4) & 0xF)}]) \ $base64_en([expr {($y<<2) & 0x3C}]) \ = } else { append result \ $base64_en([expr {($x>>2) & 0x3F}]) \ $base64_en([expr {($x<<4) & 0x30}]) \ == } if {[incr length 4] >= 72} { append result \n set length 0 } } return $result } Base64 instproc decode string { my instvar base64 set output {} set group 0 set j 18 foreach char [split $string {}] { if {$char != "="} { set group [expr {$group | ($base64($char) << $j)}] if {[incr j -6] < 0} { scan [format %06x $group] %2x%2x%2x a b c append output [format %c%c%c $a $b $c] set group 0 set j 18 } } else { scan [format %04x $group] %2x%2x a b if {$j==6} { append output [format %c $a] } else { append output [format %c%c $a $b] } break } } return $output } Base64 base64 ################################################################## Class Url Url instproc encode list { set result "" set sep "" foreach i $list { append result $sep [my encodeItem $i] if {$sep != "="} { set sep = } else { set sep & } } return $result } Url instproc encodeItem string { my instvar httpFormMap set alphanumeric a-zA-Z0-9. if {![info exists httpFormMap]} { for {set i 1} {$i <= 256} {incr i} { set c [format %c $i] if {![string match \[$alphanumeric\] $c]} { set httpFormMap($c) %[format %.2x $i] } } # these are handled specially array set httpFormMap { " " + \n %0d%0a } } regsub -all \[^$alphanumeric\] $string {$httpFormMap(&)} string regsub -all \n $string {\\n} string regsub -all \t $string {\\t} string regsub -all {[][{})\\]\)} $string {\\&} string return [subst $string] } Url instproc hexToChar hex { ::scan $hex %x h #my showMsg "::scan $hex %x h -> $h" format %c $h } Url instproc decodeItem string { #my showCall set result "" regsub -all {\+} $string " " string regsub -all {%0d%0a} $string "\n" string regsub -all {%([a-fA-F0-9][a-fA-F0-9])} $string {[my hexToChar \1]} string return [subst -novariables -nobackslashes $string] } Url instproc decodeName string { #my showCall set result "" regsub -all {%0d%0a} $string "\n" string regsub -all {%([a-fA-F0-9][a-fA-F0-9])} $string {[my hexToChar \1]} string return [subst -novariables -nobackslashes $string] } Url instproc decode string { #my showCall set result "" foreach i [split $string &=] { lappend result [decodeItem $i] } #my showVars result return $result } Url url namespace export Mime url base64 } namespace import ::xotcl::comm::mime::* #puts stderr "importing ::xotcl::comm::mime::* to [namespace current]" ./nsf2.4.0/library/xotcl/library/comm/pkgIndex.tcl000644 000766 000024 00000002254 14276141440 022647 0ustar00neumannstaff000000 000000 package ifneeded xotcl::comm::connection 2.0 "[list source [file join $dir Connection.xotcl]]; [list package provide xotcl::comm::connection 2.0]" package ifneeded xotcl::comm::dav 2.0 "[list source [file join $dir Dav.xotcl]]; [list package provide xotcl::comm::dav 2.0]" package ifneeded xotcl::comm::ftp 2.0 "[list source [file join $dir Ftp.xotcl]]; [list package provide xotcl::comm::ftp 2.0]" package ifneeded xotcl::comm::httpAccess 2.0 "[list source [file join $dir Access.xotcl]]; [list package provide xotcl::comm::httpAccess 2.0]" package ifneeded xotcl::comm::httpd 2.0 "[list source [file join $dir Httpd.xotcl]]; [list package provide xotcl::comm::httpd 2.0]" package ifneeded xotcl::comm::imap 2.0 "[list source [file join $dir Imap.xotcl]]; [list package provide xotcl::comm::imap 2.0]" package ifneeded xotcl::comm::ldap 2.0 "[list source [file join $dir Ldap.xotcl]]; [list package provide xotcl::comm::ldap 2.0]" package ifneeded xotcl::comm::mime 2.0 "[list source [file join $dir Mime.xotcl]]; [list package provide xotcl::comm::mime 2.0]" package ifneeded xotcl::comm::pcache 2.0 "[list source [file join $dir PCache.xotcl]]; [list package provide xotcl::comm::pcache 2.0]" ./nsf2.4.0/library/xotcl/library/comm/Httpd.xotcl000644 000766 000024 00000067740 13524464351 022547 0ustar00neumannstaff000000 000000 # -*- Tcl -*- $ # # The XOTcl class Httpd implements an HTTP/1.0 and HTTP/1.1 server with # basic functionality. # # Gustaf Neumann (neumann@wu-wien.ac.at) package provide xotcl::comm::httpd 2.0 set VERSION [package present xotcl::comm::httpd] package require XOTcl 2.0 #package require xotcl::comm::httpAccess package require xotcl::comm::connection package require xotcl::trace package require xotcl::comm::mime namespace eval ::xotcl::comm::httpd { namespace import -force ::xotcl::* Class Httpd -parameter { {port 80} ipaddr {root ./} {logdir "[set ::xotcl::logdir]"} {httpdWrk Httpd::Wrk} {redirects [list]} {workerTimeout 10000} } Httpd proc Date seconds {clock format $seconds -format {%a, %d %b %Y %T GMT} -gmt true} Httpd instproc checkRoot {} { my instvar root set root [string trimright $root /] if {![file isdir $root]} { puts stderr "Warning: create root directory '$root'" file mkdir $root } # make directory absolute set currentdir [pwd] cd $root set root [pwd] #puts stderr "[self] root=$root" cd $currentdir } proc ! string { set f [open [::xotcl::tmpdir]log w+]; puts $f "[clock format [clock seconds]] $string" close $f} Httpd instproc init args { my instvar port logdir logfile redirects if {![my exists workerMixins]} { my set workerMixins {} #puts stderr "resetting workermixins of [self]" } next set proto [string trim [namespace tail [my info class]] :d] puts stderr "Starting XOTcl [string toupper $proto] server $::VERSION\ [string tolower $proto]://[info hostname]:$port/" # Start a server by listening on the port if {[my exists ipaddr]} {set ip "-myaddr [my set ipaddr]"} {set ip ""} my set listen [eval [list socket -server [list [self] accept]] $ip $port] #my set listen [socket -server [list [self] accept] $port] my checkRoot if {![file isdir $logdir]} {file mkdir $logdir} set logfile [open $logdir/serverlog-$port a+] my array set requiresBody \ {GET 0 HEAD 0 POST 1 PUT 1 DELETE 0 OPTIONS 0 TRACE 0} } Httpd instproc destroy {} { # destructor catch {close [my set listen]} catch {close [my set logfile]} next } Httpd instproc accept {socket ipaddr port} { # Accept a new connection and set up a handler #puts stderr "using workermixins of [self] {[my set workerMixins]}" [my set httpdWrk] new -childof [self] -socket $socket -ipaddr $ipaddr \ -port $port -mixin [my set workerMixins] } Httpd instproc redirect list { foreach {pattern hostport} $list { my lappend redirects $pattern $hostport } } Class Httpd::Wrk -parameter {socket port ipaddr} Httpd::Wrk array set codes { 200 {Data follows} 201 {Created} 204 {No Content} 302 {Moved Temporarily} 304 {Not Modified} 400 {Bad Request} 401 {Unauthorized} 402 {Payment Required} 403 {Forbidden} 404 {Not Found} 405 {Method Not Allowed} 406 {Not Acceptable} 408 {Request Timeout} 411 {Length Required} 500 {Internal Server Error} 503 {Service Unavailable} 504 {Service Temporarily Unavailable} } Httpd::Wrk instproc formData {} {my set formData} Httpd::Wrk instproc init args { # Constructor my instvar socket port ipaddr my set formData [list] my set replyHeaderFields [list] next my makeConnection $socket my log Connect "$ipaddr $port" [self]::connection translation {auto crlf} [self]::connection event readable [self] firstLine } Httpd::Wrk instproc makeConnection {socket} { Connection create [self]::connection -socket $socket -req [self] } Httpd::Wrk instproc close {} { # logical close of a single request #my showCall my instvar version timeout meta set eof [[self]::connection eof] if {$version > 1.0 && !$eof} { #my showMsg "!EOF in http/$version" [self]::connection flush set timeout [after [[my info parent] workerTimeout] [self] destroy] ### reset parameters, worker will be potentially reused if {[array exists meta]} { unset meta array set meta {} } unset version if {[my exists user]} { my unset user my unset realm } foreach c [my set formData] { $c destroy } my set replyHeaderFields [list] my set formData {} #my showVars [self]::connection translation {auto crlf} [self]::connection event readable [self] firstLine } elseif {$eof} { #my showMsg "Destroy in http/$version" # the client side has closed the connection my destroy } else { #my showMsg "!EOF in http/$version ???" # we close the connection actively (e.g. forced by an error) [self]::connection flush #puts stderr "DESTROY----this line should never show up" my destroy } } Httpd::Wrk instproc destroy {} { #my showCall if {[my isobject [self]::connection]} { [self]::connection close } next } Httpd::Wrk instproc freeConnection {} { } Httpd::Wrk instproc firstLine {} { # Read the first line of the request #my showCall my instvar method resourceName hasFormData query fileName \ version timeout if {[info exists timeout]} { after cancel $timeout unset timeout } my lappend replyHeaderFields Date [Httpd Date [clock seconds]] set n [[self]::connection gets firstLine] if {$n > 0} { #::puts stderr "[self] firstline=<$firstLine>" # parse request line, ignore HTTP version for now if {[regexp {^(POST|GET|PUT|HEAD|OPTIONS) ([^?]+)(\??)([^ ]*) *HTTP/(.*)$} \ $firstLine _ method resourceName hasFormData query version]} { set resourceName [string trimright [string trimleft $resourceName ./] " "] # construct filename [my info parent] instvar root set fileName $root/[url decodeName $resourceName] #puts stderr ---[encoding convertfrom utf-8 $fileName]---- set fileName [encoding convertfrom utf-8 $fileName] # # Avoid directory traversal attacks # set fileName [file normalize $fileName] if {![string match $root/* $fileName]} { set fileName $root/ } # my decode-formData $query my log Query $firstLine if {[my exists forceVersion1.0]} { set version 1.0 } [self]::connection makePersistent [expr {$version > 1.0}] [self]::connection event readable [self] header } else { set version 1.0 set resourceName ??? set method ??? my log Error "bad first line:$firstLine" my replyCode 400 my replyErrorMsg } } elseif {![[self]::connection eof]} { #my showMsg "+++ not completed EOF=[[self]::connection eof]" } else { set version 1.0 #my showMsg "+++ n=negative ($n) EOF=[[self]::connection eof] version set to 1.0" my close } } Httpd::Wrk instproc header {} { # Read the header #my showCall my instvar method data if {[[self]::connection gets line] > 0} { #puts stderr line=$line if {[regexp -nocase {^([^:]+): *(.+)$} $line _ key value]} { my set meta([string tolower $key]) $value } } else { #puts stderr line-EMPTY if {[my exists meta(content-length)] && [my set meta(content-length)]>0} { #puts stderr "we have content-length [my set meta(content-length)]" set data "" [self]::connection translation binary [self]::connection event readable [self] receive-body } elseif {[my exists meta(content-type)] && [regexp -nocase {multipart/form-data; *boundary=} \ [my set meta(content-type)]]} { #puts stderr "formdata" set data "" [self]::connection event readable [self] receive-body } else { #puts stderr "no-content-length, triggering respond" [self]::connection event readable [self] "" [my info parent] instvar requiresBody if {$requiresBody($method)} { my replyCode 411 my replyErrorMsg } else { my check-redirect } } } } Httpd::Wrk instproc receive-body {} { ;# ... now we have to read the body #my showCall my instvar method data meta set d [[self]::connection read] if {$d ne ""} { append data $d #my showMsg "datal=[string length $data], cl=$meta(content-length)" if {[string length $data] >= $meta(content-length)} { [self]::connection event readable [self] "" if {$method eq "POST"} { my decode-POST-query } my check-redirect } } else { ;# 0 byte, must be eof... my showMsg "received 0 bytes" [self]::connection event readable [self] "" if {[string length $data] < $meta(content-length)} { my replyCode 404 my replyErrorMsg } else { my check-redirect } } } Httpd::Wrk instproc unmodified mtime { my instvar meta if {[info exists meta(if-modified-since)]} { set ms $meta(if-modified-since) regexp {^([^;]+);(.*)$} $ms _ ms options if {[catch {set mss [clock scan $ms]}]} { regsub -all -- {-} $ms " " ms if {[catch {set mss [clock scan $ms]}]} { set ms [lreplace $ms end end] set mss [clock scan $ms] } } return [expr {$mtime <= $mss}] } return 0 } Httpd::Wrk instproc check-redirect {} { [my info parent] instvar redirects my instvar resourceName hasFormData query set resource $resourceName$hasFormData$query foreach {pattern hostport} $redirects { #puts stderr "match <$pattern> <$resource> [regexp $pattern $resource]" if {[regexp $pattern $resource]} { #puts stderr "do redirect to $hostport/$resource" my replyCode 302 location $hostport/$resource my replyErrorMsg return } } my respond } Httpd::Wrk instproc respond {} { # Respond to the query # the request was read completely... This method is wellsuited for mixins! my respond-[my set method] } Httpd::Wrk instproc respond-GET {} { #my showCall my instvar fileName my sendFile $fileName } Httpd::Wrk instproc respond-HEAD {} { # Respond to the query my instvar fileName if {[file readable $fileName]} { my replyCode 200 \ Last-Modified [Httpd Date [file mtime $fileName]] \ Content-Type [Mime guessContentType $fileName] \ Content-Length [file size $fileName] [self]::connection puts "" #my log Done "$fileName [Mime guessContentType $fileName]" my close } else { my replyCode 404 my replyErrorMsg } } Httpd::Wrk instproc respond-OPTIONS {} { # Respond to the query my replyCode 200 \ Allow "OPTIONS, GET, HEAD, POST" \ Public "OPTIONS, GET, HEAD, POST" [self]::connection puts "" my close } Httpd::Wrk instproc respond-PUT {} { my instvar data method fileName my replyCode [expr {[file writable $fileName] ? 200 : 201}] [self]::connection puts "" set out [open $fileName w] fconfigure $out -translation binary puts -nonewline $out $data my log Done "$fileName [Mime guessContentType $fileName]" close $out my close } Httpd::Wrk instproc respond-CGI {} { my instvar fileName if {[file executable $fileName]} { my replyCode 200 [self]::connection puts [exec $fileName] ;# no parameter handling yet my close } else { my replyCode 403 my replyErrorMsg } } Httpd::Wrk instproc new-formData {} { set arg [Object create [self]::[my autoname formData]] my lappend formData $arg return $arg } Httpd::Wrk instproc decode-formData {query} { #my showCall foreach pair [split [string trimleft $query \n] &] { set arg [my new-formData] if {[regexp {^(.+)=(.*)$} $pair _ name content]} { $arg set name [url decodeItem $name] $arg set content [url decodeItem $content] } else { $arg set content [url decodeItem $pair] } } } Httpd::Wrk instproc decode-POST-query {} { if {[my exists meta(content-type)]} { set ct [my set meta(content-type)] if {[regexp -nocase {application/x-www-form-urlencoded} $ct]} { #my showMsg "ordinary FORM" my decode-formData [my set data] return } elseif {[regexp -nocase {multipart/form-data; *boundary=(.*)$} $ct \ _ boundary]} { #my showMsg "multipart FORM" set parts [my set data] set bl [expr {[string length $boundary]+2}] while {[set endIDX [string first --$boundary $parts]] > -1} { set part [string range $parts $bl [expr {$endIDX-1}]] if {[set endHD [string first \r\n\r\n $part]] > -1} { set arg [my new-formData] if {[catch {Mime multipart-decode-header \ [string range $part 0 [expr {$endHD-1}]] \ $arg} msg]} { my replyCode 406 my replyErrorMsg $msg return 0 } $arg set content [string range $part \ [expr {$endHD + 4}] \ [expr {[string length $part] -3}]] #$arg showVars } set parts [string range $parts [expr {$endIDX+2}] end] } } } } Httpd::Wrk instproc respond-POST {} { my replyCode 405 my replyErrorMsg #my respond-CGI } Httpd::Wrk instproc quotehtml {msg} { string map {< "<" > ">" & "&" "'" "'" "\"" """ } $msg } Httpd::Wrk instproc replyErrorMsg {{msg ""} args} { my instvar replyCode [self class] instvar codes foreach {tag value} $args {[self]::connection puts "$tag: $value"} my sendText "\nStatus Code: $replyCode\n\ [my quotehtml $msg]

\n\ Status Code $replyCode: $codes($replyCode)
\n\ Resource Name: [my quotehtml [my set resourceName]]\n" my close ;# close must be last call } Httpd::Wrk instproc replyCode {code args} { #my showCall my instvar version [self class] instvar codes my set replyCode $code [self]::connection puts "HTTP/$version $code $codes($code)" foreach {tag value} [my set replyHeaderFields] {[self]::connection puts "$tag: $value"} foreach {tag value} $args {[self]::connection puts "$tag: $value"} if {$code >= 400} { my log Error "$code $codes($code)\tmeta: [my array get meta]" } else { my log Done "$code $codes($code)" } } Httpd::Wrk instproc sendText {response {type text/html}} { #my showCall [self]::connection puts "Content-Type: $type" # bei einer leeren Responses blockieren Klienten und melden Fehler if {$response eq ""} { set response " " } [self]::connection puts "Content-Length: [string length $response]\n" if {[my set method] ne "HEAD"} { [self]::connection fconfigure -translation {auto binary} [self]::connection puts-nonewline $response } else { my showMsg HEAD! } } Httpd::Wrk instproc sendMsg {response {type text/html}} { # my showCall my replyCode 200 my sendText $response $type my close } Httpd::Wrk instproc sendDir {dirName} { [my info parent] instvar root set title "Directory listing" set reply "$title

$title

\n\n" set oldpwd [pwd] cd $root set dirs ""; set files "" foreach f [lsort -dictionary [glob -nocomplain ./$dirName/*]] { set full [file join $root $f] set pname [string trimleft $f ./] if {[file isdir $full]} { append pname / } if {![catch {set size [file size $full]}]} { # it is not a broken link set entry "" append entry \ \ " \ " \ \n if {[string match */ $pname]} {append dirs $entry} else {append files $entry} } } append reply $dirs $files "
"$pname" " $size " [clock format [file mtime $full]]
\n" cd $oldpwd my sendMsg $reply return } Httpd::Wrk instproc sendFile {fn {type ""}} { #my showCall if {[file isdirectory $fn]} { set full [file join $fn index.html] if {[file readable $full]} { set fn $full } else { my sendDir [my set resourceName] return } } #puts stderr "readable '$fn' [file readable $fn]" if {[file readable $fn]} { set mtime [file mtime $fn] if {[my unmodified $mtime]} { my replyCode 304 my replyErrorMsg return } if {$type eq ""} {set type [Mime guessContentType $fn]} my replyCode 200 \ Last-Modified [Httpd Date $mtime] \ Content-Type $type \ Content-Length [file size $fn] [self]::connection puts "" [self]::connection fconfigure -translation binary ;#-buffersize 65536 set localFile [open $fn] fconfigure $localFile -translation binary -buffersize 65536 fcopy $localFile [[self]::connection set socket] \ -command [list [self] fcopy-end $localFile] } else { my replyCode 404 my replyErrorMsg } } Httpd::Wrk instproc fcopy-end {localFile args} { # End of fcopy close $localFile [self]::connection fconfigure -blocking false ;# fconfigure changes blocking in 8.3.2! my close } Httpd::Wrk instproc log {reason arg} { # trivial logging my instvar port ipaddr if {[my exists user]} { set user [my set user]/[my set realm] } {set user -} [my info parent] instvar logfile puts $logfile "[clock format [clock seconds]] $user $ipaddr:$port\t$reason\t$arg" flush $logfile } ######################################################################### Class Httpsd -superclass Httpd -parameter { {port 443} {httpdWrk Httpsd::Wrk} {requestCert 0} {requireValidCert 0} {certfile filename.crt} {keyfile filename.key} {cafile cacert.pem} {infoCb {}} } Httpsd instproc init args { package require tls proc tls::password {} { puts stderr "getting passwd" return pemp } next } Class Httpsd::Wrk -superclass Httpd::Wrk Httpsd::Wrk instproc firstLine {} { my set forceVersion1.0 1 my lappend replyHeaderFields Connection close next } Httpsd::Wrk instproc makeConnection {socket} { Connection create [self]::connection -socket $socket -req [self] [my info parent] instvar \ keyfile certfile cafile infoCb requestCert requireValidCert # SSL-enable a regular Tcl channel - it need not be a socket, but # must provide bi-directional flow. Also setting session parameters # for SSL handshake. www.sensus.org/tcl/tls.htm # -request bool --> Request a certificate from peer during SSL # handshake. (default: true) # -require bool --> Require a valid certificate from peer during SSL # handshake. If this is set to true then -request must also be set # to true. (default: false) # -server bool --> Handshake as server if true, else handshake as # client.(default: false) [self]::connection importSSL -server 1 \ -certfile $certfile \ -keyfile $keyfile \ -cafile $cafile \ -request $requestCert \ -require $requireValidCert \ -command $infoCb } ######################################################################### ### ### Mixin-Classes for respond patterns ### mixes into Http and Httpd::Wrk ### Class Httpd::Responder Httpd::Responder instproc init args { next my lappend workerMixins Httpd::Responder::Wrk my set respondpatterns {} # Example how to register new methods: regexp is matched with the triple # (HTTP-METHOD URL HASFORMDATA) where HASFORMDATA is empty when no # parameters are given. The parsed components of the url etc. are # available as instvars my actions {^GET cgi[-]bin [?]} respond-CGI } Httpd::Responder instproc actions {regexp method} { my lappend respondpatterns $regexp $method } Class Httpd::Responder::Wrk Httpd::Responder::Wrk instproc respond {} { my instvar fileName method resourceName hasFormData [my info parent] instvar respondpatterns ### this is as well a candidate for a chain of responsibility foreach {pattern action} $respondpatterns { if {[regexp $pattern "$method $resourceName $hasFormData"]} { my $action return } } next } ### ### Mixin-Classes for Access Control ### mixes into Http and Httpd::Wrk ### Class Httpd::AccessControl Httpd::AccessControl abstract instproc protectedResource {fn method varAuthMethod varRealm} Httpd::AccessControl abstract instproc credentialsNotOk {wrk credentials authMethod realm} Httpd::AccessControl abstract instproc addRealmFile {realm authFile} Httpd::AccessControl abstract instproc addRealmEntry {realm passwds} Httpd::AccessControl abstract instproc protectDir {realm path methods} Class Httpd::AccessControl::Wrk Httpd::AccessControl::Wrk instproc respond {} { my instvar fileName method digestChallengeData set controller [my info parent] if {[$controller protectedResource $fileName $method authMethod realm]} { #my showMsg "*** Protected resource: $fileName $method" if {![my exists meta(authorization)] || [$controller credentialsNotOk [self] \ [my set meta(authorization)] $authMethod $realm]} { my unauthorizedAccess $realm return } } next } ########################################################################### ## Basic Access Control ########################################################################### Class Httpd::BasicAccessControl -superclass Httpd::AccessControl Httpd::BasicAccessControl instproc initWorkerMixins {} { my lappend workerMixins [self class]::Wrk } Httpd::BasicAccessControl instproc init args { next my initWorkerMixins } Httpd::BasicAccessControl instproc protectedResource {fn method varAuthMethod varRealm} { #my showCall # check whether access to $fn via $method is protected upvar [self callinglevel] $varAuthMethod authMethod $varRealm realm # we check only the current directory, not the parent directories if {[string match */ $fn]} { set path $fn } else { set path [file dirname $fn]/ } foreach i [list $path $path:$method] { if {[my exists protected($i)]} { set realm [my set protected($i)] set authMethod Basic return 1 } } return 0 } Httpd::BasicAccessControl instproc credentialsNotOk {wrk credentials authMethod realm} { # check whether $credentials are sufficient for $realm regexp {^(.*):(.*)$} [base64 decode [lindex $credentials 1]] _ user pwd #puts stderr "passwd($realm:$user)=[my exists passwd($realm:$user)]" $wrk set user $user $wrk set realm $realm if {[my exists passwd($realm:$user)]} { return [expr {[my set passwd($realm:$user)] != $pwd}] } return 1 } Httpd::BasicAccessControl instproc addRealmEntry {realm passwds} { if {[llength $passwds] == 1} { my addRealmFile [lindex $passwds 0] } else { foreach {name pwd} $passwds { #puts stderr "realm='$realm' adding user: $name pw: $pwd" my set passwd($realm:$name) $pwd } } } Httpd::BasicAccessControl instproc addRealmFile {realm authFile} { set FILE [open $authFile r] while {![eof $FILE]} { foreach {name pwd} [split [gets $FILE] :] { my addRealmEntry $realm [list $name $pwd] } } close $FILE } Httpd::BasicAccessControl instproc protectDir {realm path methods} { my instvar root my checkRoot set resource $root/$path ;# resources are currently directories if {$methods == {}} { my set protected($resource) $realm ;#for every method } else { foreach m $methods { my set protected($resource:$m) $realm ;#for selected methods } } } Class Httpd::BasicAccessControl::Wrk -superclass Httpd::AccessControl::Wrk Httpd::BasicAccessControl::Wrk instproc unauthorizedAccess {realm} { my set digestChallengeData(realm) $realm my replyCode 401 www-authenticate "Basic realm=\"$realm\"" my replyErrorMsg "Unauthorized request for realm '$realm'" } ########################################################################### ## Digest Access Control ########################################################################### Class Httpd::DigestAccessControl -superclass Httpd::BasicAccessControl Httpd::DigestAccessControl instproc init args { package require tcu next my lappend workerMixins [self class]::Wrk } Httpd::DigestAccessControl instproc credentialsNotOk {wrk credentials authMethod realm} { # check whether $credentials are sufficient for $realm my showMsg "Digest Authentication ..." # HELP FD: hier muss ich noch überprüfen, ob die digest-header # (credentials) ok sind. Hier habe ich probleme auf die sachen, # die der worker gesendet (bspw. nonce) hat zu kommen. Ich # weiß, man kann mit [my info children] daran kommen. Aber, # was is, wenn man mehrere Worker hat? ## Fredj, das sollte kein Problem sein: das credentialsNotOk wird ## vom aktuellen worker (respond) aufgerufen. man kann dem *NotOk ## den worker mitgeben, oder die beiden Methoden etwas umorganisieren. return } Class Httpd::DigestAccessControl::Wrk -superclass Httpd::BasicAccessControl::Wrk Httpd::DigestAccessControl::Wrk instproc unauthorizedAccess {realm} { my set digestChallengeData(realm) $realm my replyCode 401 www-authenticate "Digest [my digestChallenge]" my replyErrorMsg "Unauthorized request for realm '$realm'" } Httpd::DigestAccessControl::Wrk instproc digestChallenge {} { my showCall my instvar digestChallengeData my mkDigestChallengeData set digestResponse {} foreach {t v} [array get digestChallengeData] { append digestResponse "$t = \"$v\", " } regsub {, $} $digestResponse {} digestResponse return $digestResponse } Httpd::DigestAccessControl::Wrk instproc mkDigestChallengeData {} { my showCall my instvar digestChallengeData # RFC 2617 # challenge = "Digest" digest-challenge # digest-challenge = 1#( realm | [ domain ] | nonce | # [ opaque ] |[ stale ] | [ algorithm ] | # [ qop-options ] | [auth-param] ) # domain = "domain" "=" <"> URI ( 1*SP URI ) <"> # URI = absoluteURI | abs_path # nonce = "nonce" "=" nonce-value # nonce-value = quoted-string # opaque = "opaque" "=" quoted-string # stale = "stale" "=" ( "true" | "false" ) # algorithm = "algorithm" "=" ( "MD5" | "MD5-sess" | token ) # qop-options = "qop" "=" <"> 1#qop-value <"> # qop-value = "auth" | "auth-int" | token # FD: hier würde man die nötigen parametern (nonce,domain,opaque, # etc.) berechnen und in dem asso. Array speichern. # FD: minimale Anforderung set digestChallengeData(nonce) [my genNonce] set digestChallengeData(opaque) [base64 encode [self]:my-self-spcified-string] set digestChallengeData(algorithm) "MD5" ;#default set digestChallengeData(qop) "auth" set digestChallengeData(domain) [array names [my info parent]::protected] } Httpd::DigestAccessControl::Wrk instproc genNonce {} { my showCall my instvar digestChallengeData set timeStamp [clock seconds] set nonce [base64 encode [md5 $timeStamp:[self]]] return $nonce } # # example usage: #Httpd h1 -port 8081 -root [glob ~/wafe] #Httpd h2 -port 9086 -root $root \ -mixin {Httpd::Responder Httdp::BasicAccessControl} \ -addRealmEntry test {test test} -protectDir test "" {} \ -redirect {^(mailman|pipermail|cgi-bin) http://alice.wu-wien.ac.at:80} namespace export Httpd Httpsd namespace eval Httpd { namespace export Wrk \ AccessControl BasicAccessControl DigestAccessControl \ Responder } namespace eval Httpsd { namespace export Wrk } #namespace eval Responder {namespace export Wrk} #namespace eval AccessControl {namespace export Wrk} #namespace eval BasicAccessControl {namespace export Wrk} #namespace eval DigestAccessControl {namespace export Wrk} } namespace import ::xotcl::comm::httpd::* namespace eval Httpd {namespace import ::xotcl::comm::httpd::Httpd::*} namespace eval Httpsd {namespace import ::xotcl::comm::httpd::Httpsd::*} #namespace eval Responder {namespace import ::xotcl::comm::httpd::Responder::*} #namespace eval AccessControl {namespace import ::xotcl::comm::httpd::AccessControl::*} #namespace eval BasicAccessControl {namespace import ::xotcl::comm::httpd::BasicAccessControl::*} #namespace eval DigestAccessControl {namespace import ::xotcl::comm::httpd::DigestAccessControl::*} ./nsf2.4.0/library/xotcl/library/comm/PCache.xotcl000644 000766 000024 00000015656 13553530035 022601 0ustar00neumannstaff000000 000000 # -*- Tcl -*- $ # Persistent Cache object, using gdbm # Configuration: # The persistent cache is kept in a directory which is determined by # the following three rules. # # 1) the global variable "CACHE_DIR", which has to be set, # before this file is loaded # 2) If "CACHE_DIR" is not set, the global variable "homedir" # is checked, which is assumed to be the home directory # of the Cineast browser # 3) As a last resource the tmp directory is used as the cache directory # # Additionally, the cache directory can be specified after loading of this # file (before the first open) through the instance variable "dir" # in the object persistentCache. package provide xotcl::comm::pcache 2.0 #package require xotcl::package package require XOTcl 2.0 namespace eval ::xotcl::comm::pcache { namespace import ::xotcl::* variable CACHE_DIR variable homeDir if {![info exists CACHE_DIR]} { if {![info exists homeDir]} { set homeDir [::xotcl::tmpdir] } set CACHE_DIR $homeDir/cache2 } Object persistentCache persistentCache set dir $CACHE_DIR persistentCache proc flush { {cmd {}} } { my instvar DBID if {[info exists DBID]} { $DBID close } if {{} ne $cmd } { if {[catch {eval $cmd} err]} {puts stderr err=$err} } my open ;# UZ: wenn hier das self weggenommen wird, crashed das lintFilter #open ;# UZ: wenn hier das self weggenommen wird, crashed das lintFilter } # the open method for the first invocation persistentCache proc open {} { my instvar dir DBID package require xotcl::store set DBID [Storage someNewChildStore] if {![file isdirectory $dir]} { # if the cache directory does not exist, create it.. file mkdir $dir } # the open method for later invocations, doing the real work my proc open {} { my instvar dir DBID $DBID open $dir/index } # invoke the method open } persistentCache proc clear {} { my instvar cacheFileName contentType meta entry validated dir my flush [list eval file delete -force $dir/index \ [glob -nocomplain $dir/\[0-9\]*::*]] foreach var {cacheFileName contentType meta entry validated} { catch {unset $var} } } persistentCache proc clearEntry {url} { my instvar DBID cacheFileName contentType meta entry validated my inCache $url if {[info exists cacheFileName($url)]} { my flush [list eval file delete -force $cacheFileName($url)] foreach var {cacheFileName contentType meta entry validated} { my showMsg "unset ${var}($url)" catch {unset ${var}($url)} } catch {$DBID unset $url} } } persistentCache proc lazyFlush {} { my instvar flushPending if {[info exists flushPending]} { after cancel $flushPending } set flushPending [after 100 [self] flush] } persistentCache proc newEntry {url access doCache name} { my instvar cacheFileName contentType meta dir if {$name ne ""} { #$access set caching 0 return $name } elseif {$doCache} { set cacheFileName($url) $dir/[pid]-$access set contentType($url) [$access set contentType] set meta($url) [$access set meta] return $cacheFileName($url) } else { # we use the Memory cache only for non-persistent cache entries # which are deleted when the program terminates set fileName $dir/v[pid]-$access MemoryCache + $url $fileName return $fileName } } persistentCache proc entryDone {url} { my instvar entry cacheFileName contentType DBID meta if {![info exists DBID]} { open } $DBID set $url [list \ cacheFileName $cacheFileName($url) \ contentType $contentType($url) \ meta $meta($url) ] my lazyFlush #my showMsg "size=[file size $cacheFileName($url)]" set entry($url) 1 my set validated($url) 1 } persistentCache proc inCache {url} { my instvar entry if {[info exists entry($url)]} { set result 1 } else { my instvar cacheFileName contentType meta DBID if {![info exists DBID]} { open } set result [$DBID set $url] my lazyFlush if {$result ne ""} { set entry($url) 1 array set r $result set cacheFileName($url) $r(cacheFileName) set contentType($url) $r(contentType) set meta($url) $r(meta) set result 1 } else { set result 0 } } return $result } persistentCache proc validated {url} { my set validated($url) 1 } persistentCache proc invalidate {url} { if {[my exists validated($url)]} { my unset validated($url) } } persistentCache proc isValidated {url} { if {[my exists validated($url)]} { return 1 } return 0 } persistentCache proc ifModifiedHeader {url ifModVar} { set result 0 if {[my inCache $url]} { #puts stderr inCache:$url upvar [self callinglevel] $ifModVar ifModifiedHeader my instvar meta array set m $meta($url) if {[info exists m(last-modified)]} { set ifModifiedHeader [list If-Modified-Since $m(last-modified)] set result 1 } } else { #puts stderr "url=$url is not in cache" } return $result } persistentCache proc dump {} { my instvar DBID puts stderr DUMP: foreach k [$DBID names] { puts stderr $k puts stderr " [$DBID set $k]" } } persistentCache proc cacheFileName {url} { my instvar cacheFileName return $cacheFileName($url) } persistentCache proc contentType {url} { my instvar contentType return $contentType($url) } persistentCache proc meta {url} { my instvar meta return $meta($url) } persistentCache proc destroy {} { #my showCall next } #persistentCache flush ########################################################### Cache Object MemoryCache MemoryCache proc query {url entry} { my instvar cache if {[info exists cache($url)]} { upvar [self callinglevel] $entry e #puts stderr "-->[self] [self proc] finds: $url" set e $cache($url) return 1 } return 0 } MemoryCache proc + {url entry} { #puts stderr "-->[self class]:[self] [self proc] $url" my set cache($url) $entry } MemoryCache proc - {url} { #puts stderr "-->[self class]:[self] [self proc] $url" catch {my unset cache($url)} } MemoryCache proc destroy {} { my instvar cache foreach url [array names cache] { set f $cache($url) if {[regexp ^/ $f]} { #my showMsg "trying to remove $f [file exists $f]" file delete -force $f } } next } Object instproc allInstances {} { # Compute recursively all instances of a class. ::set inst [my info instances] foreach s [my info subclass] { foreach i [$s allInstances] { ::lappend inst $i } } return $inst } # onExit is automatically called when wafe terminates proc onExit {} { #puts stderr "allinstances of Access: [Access allInstances]" #foreach i [Access allInstances] { # if {[info command $i] eq ""} continue # $i destroy #} #MemoryCache clear persistentCache flush #Trace statReport } namespace export persistentCache MemoryCache } namespace import ::xotcl::comm::pcache::* ./nsf2.4.0/library/xotcl/library/comm/Imap.xotcl000644 000766 000024 00000012771 12501766547 022352 0ustar00neumannstaff000000 000000 # -*- Tcl -*- $ package provide xotcl::comm::imap 2.0 package require XOTcl 2.0 namespace eval ::xotcl::comm::imap { package require xotcl::comm::httpAccess namespace import ::xotcl::* Class Imap -superclass NetAccess -parameter {user} Imap instproc initialize args { my instvar port caching tokenCounter resp token set port 143 set caching 1 set resp(connect) {"[*] OK" login} set resp(login) {"A[0-9]+ OK" loginFinished "A[0-9]+ NO" login} set resp(loginFinished) {"[*] [0-9]+" inboxSize "[*] OK" inboxSelected} set resp(mailSelected) {"[*] [0-9]+ FETCH" fetchBody "A[0-9]+ OK " ignoreLine "[*] " ignoreLine} set resp(heads) {"[*] [0-9]+ FETCH" fetchHeaders "A[0-9]+ OK " ignoreLine "[*] " ignoreLine} set tokenCounter 0 next set token NONE } Imap instproc err {state reply} { my abort "Error in $state: $reply" } Imap instproc token {} { my instvar tokenCounter return [format {A%.4d} [incr tokenCounter]] } Imap instproc imapString {input} { regsub -all {(["\])} $input {\\\1} output ;#" return \"$output\" } Imap instproc queryServer {query state} { #my showCall my instvar S token set token [my token] puts $S "$token $query" #puts stderr "$token $query" flush $S fileevent $S readable [list [self] response $state] } Imap instproc response {state} { my instvar S resp msg token set msg [gets $S] #my showVars msg token foreach {c newState} $resp($state) { if {![regexp {^[*]} $msg] && ![regexp ^$token $msg]} { my showMsg "$state: token=$token IGNORING $msg" return } if {[regexp ^$c $msg]} { #my showMsg "$state NEWSTATE $newState" return [my $newState] } } my err $state "expected=$resp($state), got $msg" } Imap instproc GET {} { my instvar state S path host port user inbox mailNr # number at end of path is the message number in the mailbox if {[regexp {^([^/]+)/([^/]+)/([0-9]+)$} $path _ user inbox mailNr]} { } elseif {[regexp {^([^/]+)/([^/]+)/?$} $path _ user inbox]} { } else { my abort "invalid imap path $path" } regexp {^(.*):([0-9]+)$} $host _ host port # proxy ? if {[catch {set S [socket -async $host $port]} err]} { my abort "Could not open connection to host '$host:$port'\n $err" } else { fconfigure $S -blocking false fileevent $S readable [list [self] response connect] } } Imap instproc login {} { my instvar user host password if {[pwdManager requirePasswd "Imap $user\@$host" $user password]} { my queryServer "login $user [my imapString $password]" login } else { what now? } } Imap instproc loginFinished {} { my instvar user host password inbox pwdManager storePasswd "Imap $user\@$host" $user $password my queryServer "select $inbox" loginFinished } Imap instproc inboxSize {} { my instvar msg nrMails regexp {^[*] ([0-9]+) EXISTS} $msg _ nrMails } Imap instproc inboxSelected {} { my instvar msg contentType nrMails mailNr if {[info exists mailNr]} { set contentType text/plain my body-state my queryServer "fetch $mailNr rfc822" mailSelected } else { my instvar header inbox block host user block set contentType text/html my body-state set what "Mailbox $inbox of $user@$host" set block "$what\n" append block "

$what

\n" \ "The following $nrMails messages are in this mailbox:" \ "

\n

\n" my pushBlock my set state 4 my finish } } } namespace export Imap } namespace import ::xotcl::comm::imap::* ./nsf2.4.0/library/xotcl/library/comm/COPYRIGHT000644 000766 000024 00000005037 12501766547 021701 0ustar00neumannstaff000000 000000 /* * Next Scripting Framework * * Copyright (C) 1999-2014 Gustaf Neumann (a) (b) * Copyright (C) 1999-2007 Uwe Zdun (a) (b) * Copyright (C) 2007-2008 Martin Matuska (b) * Copyright (C) 2010-2014 Stefan Sobernig (b) * * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1090, Augasse 2-6 * Vienna, Austria * * This work is licensed under the MIT License * http://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * * This software is based upon MIT Object Tcl by David Wetherall and * Christopher J. Lindblad, that contains the following copyright * message: * * "Copyright 1993 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this * software and its documentation for any purpose is hereby granted * without fee, provided that the above copyright notice appear in * all copies and that both that copyright notice and this * permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity * pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about * the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty." */ ./nsf2.4.0/library/xotcl/library/comm/Dav.xotcl000644 000766 000024 00000010556 12501766547 022175 0ustar00neumannstaff000000 000000 # -*- Tcl -*- $ package provide xotcl::comm::dav 2.0 package require XOTcl 2.0 namespace eval ::xotcl::comm::dav { package require xotcl::comm::httpAccess namespace import ::xotcl::* Class Dav -superclass Http Dav instproc initialize args { my instvar contentType #showCall set contentType text/xml next } Dav instproc PROPFIND {} { #showCall # extra dav headers # Depth: ("0" | "1" | "infinity") [infinity is the default] # body is a propfind XML-Element # # # # # this should be set by the clients # # # # my open } Dav instproc PROPPATCH {} { #showCall # body is a propertyupdate XML-Element # # # # set xmlReqBody($method) " # # # # # # # " my open } Dav instproc MKCOL {} { #showCall # invoked without a request body (may contain a message body?) my open } Dav instproc GET {} { #showCall # invoked without a request body and without extra header # back to HTTP class next } Dav instproc HEAD {} { #showCall # invoked without a request bodyand without extra header # back to HTTP class next } Dav instproc POST {} { #showCall # the same as in RFC2068 # back to HTTP class next } Dav instproc DELETE {} { #showCall # extra dav headers # Depth: ("0" | "1" | "infinity") # invoked without a request body my open } Dav instproc PUT {} { #showCall # PUT for Non-Collection Resources --> RFC2068 # PUT for Collections --> MKCOL # next } Dav instproc COPY {} { #showCall # extra dav headers # If: [see 9.4 WebDAV] # Destination: [see RFC2396 for the definition of absolutURI] # Depth: ("0" | "1" | "infinity") # Overwrite: ("T" | "F") # body is a propertybehavior XML-Element # # # # my open } Dav instproc MOVE {} { #showCall # extra dav headers # If: [see 9.4 WebDAV] # Destination: [see RFC2396 for the definition of absolutURI] # Depth: "infinity" [see 8.9.2] # Overwrite: ("T" | "F") # body is a propertybehavior XML-Element # see COPY my open } Dav instproc LOCK {} { #showCall # extra dav headers # If: [see 9.4 WebDAV] # Destination: [see RFC2396 for the definition of absolutURI] # Depth: ("0" | "1" | "infinity") # Timeout: [see 9.8 WebDAV] # Authorization: (defined in HTTP1.1 in 14.8) # body is a lockinfo XML-Element # # # # # # # my open } # The Lock-Token request header is used with the UNLOCK method to # identify the lock to be removed. Dav instproc UNLOCK {} { my instvar headers #showCall # extra dav headers # Lock-Token: [see 8.11 in WebDAV] # invoked without a request body my open } #--------------------- # Utility # #--------------------- #? Object xmlReqBodyManager xmlReqBodyManager proc requireXmlReqBody {request} { } #? Object davHeaderManager davHeaderManager proc requireDavHeader {request} { } #LOCK /DAV/welcome.html HTTP/1.1 #Host: wawog #Connection: close namespace export Dav \ xmlReqBodyManager davHeaderManager } namespace import ::xotcl::comm::dav::* ./nsf2.4.0/library/xotcl/library/comm/Access.xotcl000644 000766 000024 00000133613 14261010240 022635 0ustar00neumannstaff000000 000000 # -*- tcl -*- $ package provide xotcl::comm::httpAccess 2.0 set ::httpAccessVersion [package present xotcl::comm::httpAccess] package require xotcl::comm::pcache package require xotcl::comm::mime package require xotcl::comm::connection package require xotcl::trace package require XOTcl 2.0 namespace eval ::xotcl::comm::httpAccess { namespace import ::xotcl::* variable os variable VERSION if {[catch {set os [exec uname -sr]}]} { if {[catch {set os [exec uname -a]}]} { set os unknownOS } } if {![info exists VERSION]} { set VERSION 1.0 } # assert is used only for invariants in the source proc assert {f r} { set got [eval $f] if {$got != $r} { puts stderr "assertion failed: \[$f\] == $r (got $got)" } } # resolve and checkUrl implement URL handling (primarily completion) proc checkUrl {url} { #puts stderr "checkUrl: <$url>" if {![regexp {^([^:]+:/)/([^/]+)(/.*)?$} $url _ scheme network path]} { regexp {^([^:]+:)(/.*)?$} $url _ scheme path } if {![info exists path]} { # no access scheme provided, try some heuristics... if {[regexp {^[./]} $url]} { # expand leading "." to pwd if {[regexp {^\.(.*)$} $url _ url]} { set url [pwd]$url } return file:$url } else { set url http://$url regsub {///$} $url // url return $url } } if {$path eq ""} {set path /} return [expr {[info exists network] ? "$scheme/$network$path" : "$scheme$path"}] } # resolving a relative url with respect to a base url (based on rfc 1808) proc resolve {rel base {childTagName ""}} { if {$base eq ""} { return [checkUrl $rel] } if {$rel eq ""} { return $base } if {[regexp {^[^:]+:/} $rel _]} { return [checkUrl $rel] } if {![regexp {^([^:]+:/)/([^/]+)(/.*)$} $base _ baseScheme baseNetwork basePath]} { regexp {^([^:]+:)(/.*)$} $base _ baseScheme basePath } elseif {[regexp {^[^:/]+:} $rel]} { return $rel } regexp {^(.*)\#.*$} $basePath _ basePath regexp {^(.*)[?].*$} $basePath _ basePath if {[regexp {^//([^/]+)/(.*)$} $rel _ relNetwork relPath]} { return $baseScheme/$relNetwork/$relPath } if {[info exists baseNetwork]} { append baseScheme /$baseNetwork } #puts stderr rel=<$rel> if {![string match "/*" $rel]} { #puts stderr rel<$rel>base<$basePath> if {[string match \#* $rel]} { set r $basePath$rel } elseif {![regsub {/([^/]*)$} $basePath /$rel r]} { set r /$rel } while {[regsub -all {/\./} $r / r]} {} regsub {/\.$} $r / r while {[regsub -all {/[^/.]+/\.\./} $r / r]} {} # remove leading /../ (netscapes navigator does this) while {[regsub {^/\.\./} $r / r]} {} set rel $r #puts stderr finalrel<$r> } #if {$childTagName ne ""} if {1} { upvar 1 $childTagName childTag catch {unset childTag} if {[regexp {^(.+)\#(.+)$} $rel _ rel childTag]} { #puts stderr childTag=$childTag,url=$baseScheme$rel. } } return $baseScheme$rel } assert {resolve "" http://mohegan/} http://mohegan/ assert {resolve http://mohegan/ ""} http://mohegan/ assert {resolve http://mohegan ""} http://mohegan/ assert {resolve http://mohegan/ http://nestroy} http://mohegan/ assert {resolve test.html http://127.0.0.1/} http://127.0.0.1/test.html assert {resolve test http://nestroy/} http://nestroy/test assert {resolve test file:/u/neumann/old} file:/u/neumann/test assert {resolve /test http://nestroy/} http://nestroy/test assert {resolve //mohegan/index.html http://nestroy/} http://mohegan/index.html assert {resolve //mohegan/index.html http://nestroy/} http://mohegan/index.html assert {resolve index.html http://nestroy/dir/} http://nestroy/dir/index.html assert {resolve ./index.html http://nestroy/dir/} http://nestroy/dir/index.html assert {resolve ././index.html http://nestroy/dir/} http://nestroy/dir/index.html assert {resolve ../index.html http://nestroy/dir/} http://nestroy/index.html assert {resolve ../../index.html http://nestroy/dir/} http://nestroy/index.html assert {resolve ../../../test file:/u/neumann/old} file:/test assert {resolve newdir/ http://nestroy/dir/} http://nestroy/dir/newdir/ assert {resolve /newdir/ http://nestroy/dir/} http://nestroy/newdir/ assert {resolve file:/u/neumann/ice.html ""} file:/u/neumann/ice.html assert {resolve \#label http://nestroy/h.html} http://nestroy/h.html assert {resolve mailto:user@host http://nestroy/h.html} mailto:user@host assert {resolve ../../../../mis2001/folien/081101.ppt http://wwwi.wu-wien.ac.at/Studium/Abschnitt_2/LVA_ws01/IT/index.html} http://wwwi.wu-wien.ac.at/mis2001/folien/081101.ppt ############################################################## # Every object of class Access informs the (possibly empty) list of # informObjects during its lifecycle with the following messages # # startCb: when the request for the object is created # and was classified and initialized # # notifyCb: when the type of the incming data is dertermined # (typically after parsing the http header) # # incCb: when new data is available # # endCb: when the request is finished successfully and the object # is going to be destroyed # # cancelCb: when the request is finished nonsuccessfully and the object # is going to be destroyed # # All these messages receive the name of the Access object # as first parameter, incCb has two more arguments (totalsize # and currentsize) # caching: # 0 no caching # 1 volatile cache (does not check cache, keeps spool file for back button) # 2 persistent cache Class Access -parameter { {method GET} {blocking 0} {httpVersion 1.1} {headers {}} url query data contentType path caching sinkClass parentUrl } Access instproc informObject x { foreach i $x { my lappend informObjects $i } } Access instproc method x { my set method [string toupper $x] } Access instproc unknown {m args} { error "Method '$m' with args '$args' is unknown for [self class]" } Access proc checkRunning {} { foreach u [my array names running] { puts stderr "... running: $u" } puts stderr "... -----------" } Access proc createRequest args { #my showCall set informobject {} set allowJoin 1 set nargs {} foreach {a v} $args { switch -exact -- $a { -url {set url $v; lappend nargs $a $v} -informObject {set informobject $v; lappend nargs $a $v} -parentRequest {set parentRequest $v} -allowJoin {set allowJoin $v} default {lappend nargs $a $v} } } #if {[my array exists running]} {parray [self]::running} if {[my exists running($url)] && $allowJoin} { my showMsg "we can join running($url)=[my set running($url)]" # we can join the request. # requests are joined by adding the informobjects to # the existing request set token [my set running($url)] # delegation to a different request works only so easy # when loading to a file... $token informObject $informobject return $token } else { set token [my autoname ::req] if {[info exists parentRequest]} { set token ${parentRequest}$token } #my showMsg "TOKEN = $token $url" return [eval my create $token $nargs] } } Access instproc running {} { #my showCall [self class] set running([my url]) [self] } Access instproc stop {} { #showCall my instvar url if {[[self class] exists running($url)]} { #puts stderr "my unset [[self class] set running($url)] [self class] unset running($url) #if {[my array exists running]} { parray [self class]::running } } else { #puts stderr "not running($url)" #if {[my array exists running]} { parray [self class]::running } } } #Access instproc destroy args { # my showCall # next #} Access instproc init args { #my showCall my instvar method url if {![my exists informObjects]} { my set informObjects {} } next if {![my exists caching]} { if {$method eq "GET"} { set defaultCaching 2 } else { set defaultCaching 1 } my caching $defaultCaching } #my showVars set url [string trim $url] my initialize if {[my classify $url]} { #my showVars # now inform all interested objects that we have the object my doCallbacks startCb #my showVars blocking # trigger the transfer... (might be blocking or not) my $method if {![my exists finished]} { # the request is not finished if {[my blocking]} { #my showMsg "waiting" my vwait finished #my showMsg "waiting DONE" } } } } Access instproc getContent {} { [my set sink] content } ######################################### Access instproc timeout t { my set timeout [::after $t [self] timeoutOccurred] } Access instproc timeoutOccurred {} { #my showCall my unset timeout my abort "timeout exceeded" } Access instproc timeoutFinish {} { if {[my exists timeout]} { after cancel [my set timeout] my unset timeout } } ######################################### Access instproc initialize {} { #my showCall my set state 0 my set meta {} my set currentsize 0 my set totalsize 0 } Access instproc classify {url} { my instvar host path port method #my showVars caching if {[my caching] > 1 && [persistentCache isValidated $url]} { #puts stderr "*** cacheable && validated" #showVars #persistentCache dump set access CacheAccess } elseif {[regexp -nocase {^http://([^/:]+)(:([0-9]+))?(/.*)?$} $url \ _ host y givenPort path]} { if {$givenPort ne ""} {set port $givenPort } {set port 80} switch -exact $method { PROPFIND - PROPPATCH - COPY - MKCOL - MOVE - LOCK - UNLOCK { package require xotcl::comm::dav set access Dav } default {set access Http} } } elseif {[regexp -nocase {^https://([^/:]+)(:([0-9]+))?(/.*)$} $url \ _ host y givenPort path]} { if {$givenPort ne ""} {set port $givenPort } {set port 443} set access Https } elseif {[regexp -nocase {^file:(.*)$} $url _ path]} { set access File } elseif {[regexp -nocase {^ftp://([^/]+)/(.*)$} $url _ host path]} { package require xotcl::comm::ftp set access Ftp } elseif {[regexp -nocase {^imap://([^/]+)/(.*)$} $url _ host path]} { package require xotcl::comm::imap set access Imap } elseif {[regexp -nocase {^cmd:/(.*)$} $url _ path]} { set access xotcl::Cmd } elseif {[regexp -nocase {^ldap://([^/:]+)?(:([0-9]+))?(/.*)$} \ $url _ host y givenPort path]} { if {$givenPort ne ""} { set port $givenPort } my showMsg "*** ldap://<$host>:<$port>/<$path>" package require xotcl::comm::ldap set access Ldap } else { #my set state 0 my abort "Unsupported URL: '$url'" return 0 } my class $access #my showMsg "class of request = $access" return 1 } Access instproc revisit {} { my class ReAccess my initialize my [my set method] } ### dummy stubs for 'close' and 'GET' for error cases Access instproc close {} { } Access instproc GET {} { if {[my exists errormsg]} { ;# the error was already reportet my finish } else { my abort "unknown error" } } Access instproc headerDone {} { my instvar caching sink if {[my exists ignoreBody]} return if {[my exists sinkClass] && $caching>0 } { error "can´t set both sinkclass and caching" } switch $caching { 2 { set sink [CacheFileSink create [self]::cfs] #my showMsg "[self class] result goes to cache" $sink notifyCb [self] } 1 { set sink [CacheFileSink create [self]::cfs -persistent 0] #my showMsg "result goes to volatile cache" $sink notifyCb [self] } 0 { if {[my exists sinkClass]} { set sink [[my sinkClass] create [self]::s] } } } my doCallbacks notifyCb } Access instproc mkSpoolFile {{name ""}} { if {![my exists fileName]} { my set fileName [persistentCache newEntry [my url] [self] [my caching] $name] } } Access instproc block {} { my set block } Access instproc kill {} { #my showCall my set state -1; #interrupted my finish } Access instproc abort {msg} { #my showCall #my showVars my instvar state errormsg if {[catch {::printError "[self] ($state): $msg"} err]} { puts stderr "\n$err\nERROR [self] ($state): $msg\n" } #my set error [list $msg $::errorInfo $::errorCode] my caching 0 if {[my exists ignoreBody]} { my unset ignoreBody } set state -2 ;# error set errormsg $msg my finish } Access instproc finish {} { #my showCall my timeoutFinish my close #my showVars state ignoreBody # state is "interrupted" or "error" if {[my set state] < 0} { set action cancelCb set success 0 } else { set action endCb #set state ok set success 1 } if {[my exists ignoreBody]} { my stop #my set finished $success set cmd [my set ignoreBody] my unset ignoreBody #my showMsg "executing... <$cmd>" eval my $cmd } else { if {[my exists sink]} { [my set sink] $action [self] } #catch {after cancel $after} ;# ???? my doCallbacks $action my stop my set finished $success } } Access instproc eof {} { #my showCall #my showMsg "c [my set currentsize]== t [[self set totalsize]]" #my set state eof my finish } Access instproc doCallbacks {cb} { #my showCall if {[my exists ignoreBody]} { my showMsg "ignoring callback" } else { foreach obj [my set informObjects] { #my showMsg "*** $obj $cb [self]" #puts stderr "------------ calling: $obj $cb [self]" if {[catch {$obj $cb [self]} errormsg]} { puts stderr "--------------$cb:errormsg=$errormsg, \ errorInfo=$::errorInfo, \ errorCode=$::errorCode." } #puts stderr "------------ calling DONE: $obj $cb [self]" } } } Access instproc shutdown {} { #my showMsg "state=[my set state] > 3" if {[my set state] > 3} { my set mustDestroy 1 } else { #my showVars #my showStack #my showMsg "DESTROY !!!" if {[my set state] > -2} { my destroy } } } Class FileAccess -superclass Access FileAccess instproc initialize args { my caching 0 next } FileAccess instproc close {} { } FileAccess instproc block {} { my showTimeStart set S [open [my set fileName] r] fconfigure $S -translation binary set block [::read $S] ::close $S my showTimeEnd return $block } FileAccess instproc GET {} { my instvar path response totalsize currentsize \ fileName informObjects set fileName $path set totalsize [file size $path] set response "file 200 OK" my headerDone my set state 4 set currentsize $totalsize #my showVars informObjects foreach obj $informObjects { $obj incCb [self] $totalsize $currentsize } my eof } Class File -superclass FileAccess File instproc GET {} { my instvar path #puts stderr path=$path,exists=[file exists $path] if {![file exists $path]} { my abort "No such file '$path'" return } if {![my exists contentType]} { my contentType [Mime guessContentType $path] } my set sink [FileSink create [self]::fas -fileName $path] #puts stderr ****sink=$sink,[$sink info class] #puts stderr "*** before next ([self class])" next #puts stderr "*** after next ([self class])" } Class CacheAccess -superclass File CacheAccess instproc GET {} { my instvar url my path [persistentCache cacheFileName $url] my contentType [persistentCache contentType $url] my set meta [persistentCache meta $url] next } Class ReAccess -superclass File ReAccess instproc GET {} { my instvar fileName sink my set block "" my set currentsize 0 my caching 0 if {![info exists fileName]} { set fileName [$sink set fileName] } my set path $fileName next } Class Cmd -superclass Access Cmd instproc init args { if {![my exists caching]} { my caching 0 } next } Cmd instproc GET {} { my instvar path block totalsize currentsize \ response informObjects state if {[catch {set block [eval $path]} error]} { my contentType text/plain set block $error } else { my contentType text/html } set totalsize [string length $block] set response "cmd 200 OK" my headerDone my set state 4 set currentsize $totalsize foreach obj $informObjects { $obj incCb [self] $totalsize $currentsize #$obj endCb [self] } #set state eof my finish } Cmd instproc block args { my instvar block return $block } #Class NetAccess -superclass Access -parameter {host port} Class NetAccess -superclass Access NetAccess instproc initialize args { if {![my exists blocksize]} {my set blocksize 512} my set readMethod read next } NetAccess instproc read {} { #my instvar S blocksize block #set block [::read $S $blocksize] my instvar S block blocksize set block [::read $S $blocksize] } NetAccess instproc gzread {} { my instvar S Z blocksize block puts -nonewline $Z [::read $S $blocksize] set block [::read $Z] #puts stderr len=[string length $block],block=<$block> } NetAccess instproc gzopen {} { my instvar Z S readMethod requireModules {zipchan libzipchan.so} fconfigure $S -translation binary set Z [zipchan] set readMethod gzread } NetAccess instproc close {} { #my showMsg "**** close persistent=[my exists persistent]" if {![my exists persistent]} { foreach stream {S Z} { if {[my exists $stream]} { ::close [my set $stream] my unset $stream } } } my stop } NetAccess instproc hold {} { my instvar S $S hold } NetAccess instproc resume {} { my instvar S $S resume } NetAccess instproc readData {} { #my showCall if {[catch { #puts stderr "??????????????readMethod=[my set readMethod]" my [my set readMethod] my pushBlock } err]} { puts stderr ERR=$err my set block "" my abort $err } } NetAccess instproc pushBlock {} { #my showCall my instvar block if {[set n [string length $block]]} { my instvar currentsize totalsize informObjects sink #my showVars n currentsize totalsize incr currentsize $n if {$currentsize > $totalsize} { set totalsize $currentsize } #my showMsg "total=$totalsize current=$currentsize" if {[my exists ignoreBody]} { #puts stderr "ignoring: <$block>" } else { if {[info exists sink]} { $sink incCb [self] $totalsize $currentsize } foreach obj $informObjects { #my showMsg "call incbCb $totalsize $currentsize $obj [$obj info class]" $obj incCb [self] $totalsize $currentsize #my showMsg "done incbCb $totalsize $currentsize" } } } else { #my showVars n return [my eof] } } Class Http -superclass NetAccess ;### -parameter {query {httpVersion 1.0}} Http set proxyfilter httpProxyRequired Http set proxyhost {} Http set proxyport {} Http set accept */* if {[info exists ::argv0]} { Http set useragent "[file tail $::argv0] httpAccess/$::httpAccessVersion xotcl/$::xotcl::version ($os)" } Http proc proxyfilter {host phostv pportv} { my instvar proxyfilter proxyhost proxyport upvar \#1 $phostv phost $pportv pport switch -- $proxyfilter { httpProxyRequired { if {[string length $proxyhost]} { if {![string length $proxyport]} { set proxyport 8080 } set phost $proxyhost set pport $proxyport } } } } Http instproc initialize args { if {![my exists port]} {my set port 80} if {![my exists httpVersion]} {my set httpVersion 1.1} next #my showMsg "result queried from net" } Http instproc GET {} { #my showCall if {[my exists query]} { my instvar query caching my append url ?$query my append path ?$query if {$caching == 2} {set caching 1} my showVars caching $query } my open } Http instproc HEAD {} { my open } Http instproc POST {} { # we have query and data only for a uniform interface for # forms that can pass the attribute value pairs always via # query. if {[my exists query]} { my data [my query] } my open } Http instproc PUT {} { my open } # Http1.1 Http instproc OPTIONS {} { my showCall my open } # Http1.1 Http instproc TRACE {} { my showCall } # Http1.1 Http instproc DELETE {} { #my showCall my open } Http instproc openConnection {host port reuse} { return [Connection make [self] $host $port $reuse _] } Http instproc open {} { #my showCall my instvar url S state host port path if {$state > 0} { puts stderr "... [self]:$proc ignoring request in state $state" return } Http proxyfilter $host phost pport if {[info exists phost] && [string length $phost]} { set usePort $pport set useHost $phost set path $url } else { set usePort $port set useHost $host } set S [my openConnection $useHost $usePort [expr {[my httpVersion]>1.0}]] if {[$S exists error]} { my abort [$S set error] return } set state 2 my running $S event writable [self] ask } Http instproc ask {} { my instvar url S state host port path \ method headers data caching $S event writable [self] {} if {[pwdManager checkAvailableCredentials $url credentials]} { eval lappend headers $credentials #my showMsg "*** new headers = <$headers>" } if {$caching==2 && [persistentCache ifModifiedHeader $url ifModified]} { eval lappend headers $ifModified #puts stderr "new headers = <$headers>" } # Send data in cr-lf format, but accept any line terminators $S translation {auto crlf} #my showMsg "'$method $path HTTP/[my httpVersion]' headers {$headers}" $S puts "$method $path HTTP/[my httpVersion]" if {[$S exists error]} { my abort "Connection refused by host '$host' port '$port'\n\ [$S set error]" return } $S puts "Accept: [Http set accept]" $S puts "Host: $host" $S puts "User-Agent: [Http set useragent]" foreach {tag value} $headers { regsub -all \[\n\r\] $value {} value set tag [string trim $tag] if {[string length $tag]} { #my showMsg "+++ <$tag: $value>" $S puts "$tag: $value" } } if {[my exists data]} { $S puts "Content-Length: [string length $data]" $S puts "Content-Type: [my contentType]" $S puts "" $S translation {auto binary} $S puts-nonewline $data } else { $S puts "" } $S flush if {[$S exists error]} { my instvar host port my abort "Connection refused by host '$host' port '$port'\n\ [$S set error]" } else { set state 3 $S event readable [self] headerStart } } Http instproc headerStart {} { #my showCall my instvar S response set n [$S gets response] #my showVars n response if {[$S exists error]} { my instvar host port my abort "Error on connection to host '$host' port '$port'\n\ [$S set error]" return } #my showMsg "n=$n, eof=[$S eof]" if {$n == -1 && ![$S eof]} { #my showMsg "******************************input pending, no full line" return } my instvar responseCode responseHttpVersion if {[regexp {^HTTP/([0-9.]+) +([0-9]+) *} $response _ \ responseHttpVersion responseCode]} { #my showMsg "response valid: '$response'" $S event readable [self] header } else { my instvar host port my abort "Unexpected response from $host:$port\n $n: '$response'" } } Http instproc header {} { my instvar S meta totalsize if {[$S gets line]} { #my showMsg "line=$line" if {[regexp -nocase {^content-type:(.+)$} $line _ type]} { my contentType [string trim $type] } elseif {[regexp -nocase {^content-length:(.+)$} $line _ length]} { set totalsize [string trim $length] } if {[regexp -nocase {^([^:]+): *(.+)$} $line _ key value]} { lappend meta [string tolower $key] $value } } else { my headerDone } } Http array set expectsBody \ {GET 1 HEAD 0 POST 1 PUT 0 DELETE 1 OPTIONS 0 TRACE 1} Http instproc headerDone {} { #my showVars meta my instvar S meta method responseCode responseHttpVersion [self class] instvar expectsBody set expectBody $expectsBody($method) array set v [my set meta] if {([info exists v(connection)] && $v(connection) eq "close") || \ $responseHttpVersion < 1.1} { $S makePersistent 0 } else { $S makePersistent 1 } switch $responseCode { 200 {} 204 { #set state empty my finish set block "" set expectBody 0 return } 301 - 302 { # the request is redirected to another server my set ignoreBody [list redirect $v(location)] # RFC2068 Note: When automatically redirecting a POST request after # receiving a 302 status code, some existing HTTP/1.0 user agents # will erroneously change it into a GET request. #my method GET my showMsg "redirect '[my url]' --> '$v(location)'" } 304 { ;# Not Modified, use cached version my set ignoreBody cacheAccess set expectBody 1 #my showMsg "result comes from cache" } 401 { my set ignoreBody \ [list resubmitAuthenticated $v(www-authenticate)] #my showMsg "resubmitAuthenticated $v(www-authenticate)" if {[my exists resubmitAuthenticated]} { if {[my set resubmitAuthenticated] > 5} { my abort "Too many wrong passwords given" } else { my incr resubmitAuthenticated } } else { my set resubmitAuthenticated 1 } set expectBody 1 } 404 { my instvar url #my showVars my set ignoreBody [list abort "File Not Found on Server '$url'"] set expectBody 1 } default { #my showVars responseCode } } next if {![my exists S]} {;# this request was already canceled return } if {[info exists v(transfer-encoding)]} { if {$v(transfer-encoding) == "chunked"} { $S translation {auto binary} my set state 4 $S event readable [self] readChunkedLength } else { my abort "Unexpected Transfer encoding '$v(transfer-encoding)'" } } else { # yahoo does not send a content length for a get request #if {$totalsize == 0 && ($responseCode > 300 || !$expectsBody($method) )} #my showVars method totalsize expectsBody($method) expectBody # the following is used currently for Actiweb-Agents: # the response of a PUTS contains a BODY! if {!$expectBody && [::info exists v(content-length)] && $v(content-length) > 0} { set expectBody 1 #my showMsg "setting expectBody 1" } if {!$expectBody} { #$S event readable [self] "" #set state eof my finish set block "" } else { ### To avoid CRLF problems we set the translation for ### the body entity to binary $S translation binary my set state 4 $S event readable [self] readData } } } Http instproc cacheAccess {} { # there is an actual version of the document in the cache #showCall persistentCache validated [my url] #my close my class CacheAccess #my showMsg "result comes from cache [persistentCache cacheFileName $url]" my caching 0 ;# should be really: toCache 0 my GET } Http instproc redirect location { # the request is redirected to another server if {$location ne [my url] } { #my showVars my url $location my initialize my classify $location my [my set method] } } Http instproc resubmitAuthenticated headerField { #my showCall # the server requires authentication my instvar path method if {[pwdManager checkRequestedAuthentification $method $path $headerField \ type realm]} { my instvar url caching method headers array set v $headers #my showVars catch {unset v(Authorization)} set headers [array get v] pwdManager removePasswd $realm my close if {[pwdManager requireCredentials $realm $url]} { my initialize if {$caching == 2} {set caching 1} my $method } } else { my abort "unknown authentication method '$headerField'" } } Http instproc readChunkedLength {} { #my showCall my instvar S chunkLength totalsize set length [$S gets lengthString] if {$length > 0} { set chunkLength [expr 0x$lengthString] #my showVars lengthString chunkLength if {$chunkLength == 0} { $S event readable [self] readChunkedTrailer } else { incr totalsize $chunkLength $S translation {binary} $S event readable [self] readChunkedData } } } Http instproc readChunkedTrailer {} { #my showCall my instvar S state block set size [$S gets line] if {$size != 0} { showObj [self] my abort "expected trailer size 0, got size $size" } else { #set state eof my finish set block "" #showObj [self] } } Http instproc readChunkedData {} { #my showCall my instvar S block totalsize currentsize chunkLength set block [$S readSize $chunkLength] set received [string length $block] #my showVars block #my showVars currentsize totalsize chunkLength received if {$chunkLength == $received} { $S translation {auto binary} $S event readable [self] readChunkedLength } else { incr chunkLength -$received } my pushBlock } Http instproc readData {} { #my showCall my instvar S block totalsize currentsize set block [$S read] #puts stderr "????? bl=[string length $block]" if {[$S exists error]} { set block "" my abort [$S set error] return } my pushBlock #my showMsg "c [my set currentsize]== t [[self set totalsize]]" if {$currentsize == $totalsize && [my exists S] && [$S exists persistent]} { #my showMsg "PERSITENT, end of entity reached" #my set state eof my finish set block "" #showObj [self] } if {[my exists mustDestroy]} { #my showMsg "mustDestroy was set" my destroy } } Http instproc close {} { #my showCall if {[my exists S]} { [my set S] close #unset S } #next } Http instproc freeConnection {} { #showCall my instvar S #::puts stderr "[self] freeing $S !!!!!!!!!!!!!!!!!!!!!!!" unset S } #Access instproc makeZombie {} { # my showMsg "procs= [my info procs], i [Object info instcommands]" # my class Zombie #} #Class Zombie #Zombie instproc unknown {m args} { # my showMsg "+++ zombie method '$m' called" #} Class Https -superclass Http Https instproc initialize args { #my showCall package require tls if {![my exists port]} { my set port 443} next ### temporary solution, FIXME: ### zur zeit muss man den secure-webserver.xotcl und ### secure-webclient.xotcl jedenfalls aus dem xotcl/apps/xocomm-apps ### verzeichnis starten, da haben wir mal die cfg files in unserem ### baum.... source .ssl/ssl-configuration.xotcl ### } Https instproc openConnection {host port reuse} { set S [Connection make [self] $host $port $reuse reused] if {$reused} { #my showMsg "reusing $S" } else { my showMsg "make the socket ([$S socket]) secure ..." set cmd [list $S importSSL] foreach attr {cafile cadir certfile cipher command keyfile \ model request require ssl2 ssl3 tls1} { if {[sslClientConfig exists $attr]} { lappend cmd -$attr [sslClientConfig set $attr] } } my showMsg "the assembled command is... ´$cmd´" eval $cmd puts stderr "CHANNELS= [file channels]" } return $S } ####################################################################### Object pwdManager pwdManager proc requirePasswd {realm username password} { # used by ftp and imap my instvar user area upvar [self callinglevel] $password passwd if {[my exists pwd($realm)]} { #my showMsg "*** reusing password for $realm" set passwd [my set pwd($realm)] return 1 } else { userPwd user $username if {[userPwd show $realm user($realm) passwd]} { set area($realm/$username) $realm return 1 } } return 0 } pwdManager proc storePasswd {realm username password} { # used by ftp and imap my instvar pwd user set pwd($realm) $password set user($realm) $username } pwdManager proc removePasswd {realm} { if {[my exists pwd($realm)]} { my unset pwd($realm) my unset user($realm) } } pwdManager proc requireCredentials {realm url} { regexp {^(.*/)[^/]*$} $url _ path if {[my exists pwd($realm)]} { #my showMsg "*** register url=$url for other realm=$realm" my set area($path) $realm return 1 } else { my instvar pwd user if {[info exists ::env(USER)]} { set USER $::env(USER) } elseif {[info exists ::env(USERNAME)]} { set USER $::env(USERNAME) } else { set USER unknown } userPwd user $USER if {[userPwd show $realm user($realm) pwd($realm)]} { #my showMsg "*** setting password for realm '$realm' url=$path" my set area($path) $realm return 1 } } return 0 } pwdManager proc encodeCredentials {authMethod realm} { #my showCall switch $authMethod { basic {set credential [my encodeCredentialsBasic $realm]} digest {set credential [my encodeCredentialsDigest $realm]} } return $credential } pwdManager proc encodeCredentialsBasic {realm} { my instvar pwd user return [list Authorization \ "Basic [base64 encode $user($realm):$pwd($realm)]"] } pwdManager proc encodeCredentialsDigest {realm} { #my showCall package require tcu; #FIXME: noch nicht in distribution my instvar digestResponseData my mkDigestResponseData $realm set digestResponse {} foreach {t v} [array get digestResponseData] { append digestResponse " $t = \"$v\"," } return [list Authorization "Digest [string trimright $digestResponse ,]"] } pwdManager proc mkDigestResponseData {realm} { #my showCall my instvar pwd user digestResponseData requestUri # RFC 2617 # credentials = "Digest" digest-response # digest-response = 1#( username | realm | nonce | digest-uri # | response | [ algorithm ] | [cnonce] | # [opaque] | [message-qop] | # [nonce-count] | [auth-param] ) # username = "username" "=" username-value # username-value = quoted-string # digest-uri = "uri" "=" digest-uri-value # digest-uri-value = request-uri ; As specified by HTTP/1.1 # message-qop = "qop" "=" qop-value # cnonce = "cnonce" "=" cnonce-value # cnonce-value = nonce-value # nonce-count = "nc" "=" nc-value # nc-value = 8LHEX # response = "response" "=" request-digest # request-digest = <"> 32LHEX <"> # LHEX = "0" | "1"| ...| "e" | "f" set digestResponseData(username) $user($realm) set digestResponseData(uri) $requestUri set digestResponseData(cnonce) "TEST" set digestResponseData(nc) 00000001 set digestResponseData(response) [my mkRequestDigest] #parray digestResponseData } pwdManager proc mkRequestDigest {} { # returns a string of 32 hex digits, which proves that the user # knows a password #A1 = unq(username-value) ":" unq(realm-value) ":" passwd my instvar digestResponseData pwd requestMethod requestUri append A1 $digestResponseData(username)\ : $digestResponseData(realm) : $pwd($digestResponseData(realm)) if {![my exists digestResponseData(qop)] || $digestResponseData(qop) eq "auth"} { append A2 $requestMethod : $requestUri } elseif {$digestResponseData(qop) eq "auth-int"} { #A2 = Method ":" digest-uri-value ":" H(entity-body) append A2 $requestMethod : $requestUri: "" } if {[my exists digestResponseData(qop)]} { append reqDigest $digestResponseData(nonce) : \ $digestResponseData(nc) : \ $digestResponseData(cnonce): \ $digestResponseData(qop) set reqDigest [md5 [md5 $A1]:$reqDigest:[md5 $A2]] } else { set reqDigest [md5 [md5 $A1]:$digestResponseData(nonce):[md5 $A2]] } return $reqDigest } pwdManager proc checkAvailableCredentials {url returnCredentials} { # we start a fresh request and check, whether we have sent for this url # (directory) already some credentials in an earlier reqhest. my instvar authMethod regexp {^(.*/)[^/]*$} $url _ path if {[my exists area($path)]} { set realm [my set area($path)] upvar [self callinglevel] $returnCredentials credentials #my showMsg "*** adding credentials for realm=$realm and $path" set credentials [my encodeCredentials $authMethod $realm] return 1 } return 0 } pwdManager proc checkRequestedAuthentification {reqMethod path headerField typeVar realmVar} { # check for which realm with which authentication method the # server wants an authentication #my showCall upvar [self callinglevel] $typeVar type $realmVar realm my instvar authMethod digestResponseData requestUri requestMethod set requestUri $path set requestMethod $reqMethod if {[regexp {^Basic realm="(.*)"$} $headerField _ realm]} { set type basic;# FD: musste da lassen wg. call by reference set authMethod $type return 1 } elseif {[regsub {^Digest } $headerField _ headerField]} { set type digest ;# FD: musste da lassen wg. call by reference set authMethod $type foreach pair [split $headerField ,] { if {[regexp {^(.*) *= *(".*")$} $pair _ n v]} { set digestResponseData([string trim $n]) [string trim [string trim $v] \"] } } set realm $digestResponseData(realm) return 1 } return 0 } ####################################################################### # test classes Class Sink Sink instproc startCb {r} { my set contentLength 0 next } Sink instproc notifyCb {r} { next } Sink instproc incCb {r t c} { my set contentLength $t next } Sink instproc endCb {r} { next #showCall } Sink instproc cancelCb {r} { next #showCall } Sink instproc content {} { next #showCall } Sink instproc contentLength {} { my set contentLength #showCall } Class TimeSink -superclass Sink TimeSink instproc startCb {r} { my set startTime [clock clicks] next } TimeSink instproc notifyCb {r} { my set notifyTime [clock clicks] next } TimeSink instproc endCb {r} { my set endTime [clock clicks] next my reportTimes } TimeSink instproc cancelCb {r} { my set endTime [clock clicks] next } TimeSink instproc reportTimes {} { my instvar startTime endTime notifyTime set bytes [my contentLength] set grossSecs [expr {($endTime-$startTime)/1000000.0}] set grossKbps [expr {($bytes/1000.0)/$grossSecs}] set netSecs [expr {($endTime-$notifyTime)/1000000.0}] set netKbps [expr {($bytes/1000.0)/$netSecs}] #if {[catch {set netKbps [expr {($bytes/1000.0)/$netSecs}]}]} { # set netKbps 0 #} set headSecs [expr {$grossSecs-$netSecs}] foreach v {grossSecs grossKbps netSecs netKbps headSecs} { set $v [format %.2f [set $v]] } my showMsg "got $bytes bytes in $grossSecs ($headSecs+$netSecs) seconds,\ $grossKbps ($netKbps) KB/S" } Class ParallelSink -superclass Sink -parameter { {httpVersion 1.1} {sinkClass TimeSink} {maxsimultaneous 20} } ParallelSink instproc init args { next my set running 1 my set numrequests 0 my set sumbytes 0 my set blocked {} } ParallelSink instproc startCb r { #my showCall my incr running my incr numrequests #puts stderr "... running++ [my set running]" } ParallelSink instproc endCb r { #my showCall my incr sumbytes [$r set currentsize] my done $r } ParallelSink instproc cancelCb r { #my showCall my done $r } ParallelSink instproc done r { #my showCall my instvar blocked $r shutdown my incr running -1 #puts stderr "... running-- [my set running] [llength [Http info instances]]" #puts stderr [Http info instances] #foreach i [Http info instances] {puts stderr "\t$i: [$i set method] [$i set url]"} #puts stderr RUNNING=[my set running] if {[llength $blocked] > 0} { set newreq [lindex $blocked 0] set blocked [lrange $blocked 1 end] my scheduleRequest [lindex $newreq 0] [lindex $newreq 1] [lindex $newreq 2] } elseif {[my set running] < 1} { my set done 1 } } ParallelSink instproc scheduleRequest {method url {parentUrl ""}} { my instvar requests blocked running maxsimultaneous if {$running > $maxsimultaneous} { lappend blocked [list $method $url $parentUrl] } else { set cmd [list Access createRequest -url $url \ -sinkClass [my sinkClass] \ -informObject [self] \ -method $method \ -timeout 25000 \ -caching 0 -allowJoin 0 -httpVersion [my httpVersion]] if {$parentUrl ne ""} { lappend cmd -parentUrl $parentUrl } set r [eval $cmd] } } ParallelSink instproc requests {URLs} { my showTimeStart foreach url $URLs { my scheduleRequest GET $url } my wait my showTimeEnd } ParallelSink instproc wait {} { my instvar running if {$running > 0} { set savedValue $running #my showMsg ".......... waiting for initially $running requests" if {[catch {my vwait done} err]} { my showMsg "vwait returned: $err " } #my showMsg "$savedValue requests FINISHED " } } Class MemorySink -superclass Sink MemorySink instproc incCb {r t c} { my append d [$r block] next } MemorySink instproc content {} { return [my set d] } MemorySink instproc contentLength {} { if {[my exists d]} { return [string length [my set d]] } else { return 0 } } Class FileSink -superclass Sink -parameter fileName ### write methods #FileSink instproc startCb {r} { # next #} FileSink instproc notifyCb {r} { #my showVars next my instvar file fileName if {[info exists fileName]} { set file [::open $fileName w] fconfigure $file -translation binary } else { # we have no filename; we assume the sink must be a dummy sink # that deletgates its work to some other FileSink my class ShadowFileSink my notifyCb $r } } FileSink instproc incCb {r t c} { next if {[my exists file]} { if {$r == "req0"} { puts stderr "*******************************************************" puts stderr [$r block] puts stderr "*******************************************************" } puts -nonewline [my set file] [$r block] } } FileSink instproc endCb {r} { #my showCall next my close } FileSink instproc cancelCb {r} { next my close } FileSink instproc close {} { if {[my exists file]} { ::close [my set file] my unset file } } ### read methods FileSink instproc content {} { next my instvar file fileName set file [::open $fileName r] fconfigure $file -translation binary set d [read [my set file]] my close return $d } FileSink instproc contentLength {} { next if {[my exists fileName]} { return [file size [my set fileName]] } else { return 0 } } Class ShadowFileSink -superclass Sink ShadowFileSink instproc notifyCb {r} { next my set token $r } ShadowFileSink instproc content {} { my instvar token next return [[$token set sink] content] } ShadowFileSink instproc contentLength {} { my instvar token next return [[$token set sink] contentLength] } Class CacheFileSink -superclass FileSink -parameter {{persistent 1}} CacheFileSink instproc notifyCb req { #my showCall if {![my exists fileName]} { my instvar persistent set url [$req set url] my set fileName [persistentCache newEntry $url $req $persistent ""] } # it is important to execute next after setting the fileName... next } CacheFileSink instproc endCb req { #my showCall my instvar persistent next if {$persistent} { persistentCache entryDone [$req set url] } } CacheFileSink instproc cancelCb req { next if {[my exists fileName]} { file delete [my set fileName] my unset fileName } } CacheFileSink instproc destroy {} { #my showCall if {[my exists fileName] && ![my set persistent]} { #my showMsg "file delete $fileName" file delete [my set fileName] my unset fileName } next } #=========================================================== Class SimpleRequest -parameter { {caching 0} {useFileSink 0} {blocking 1} {timing 0} url fileName timeout httpVersion method headers data query contentType informObject } SimpleRequest instproc fileName x { my set fileName $x my set useFileSink 1 } SimpleRequest instproc init args { my instvar useFileSink fileName sink caching token #my showMsg "Starting Request" next if {[info exists fileName]} { set sink [FileSink create [self]::sink -fileName $fileName] } elseif {$useFileSink || $caching > 0} { set sink [FileSink create [self]::sink] } else { set sink [MemorySink create [self]::sink] } #my showMsg "class of sink = [$sink info class]" if {[my set timing]} { $sink mixin TimeSink } set cmd [list Access createRequest \ -url [my url] \ -informObject $sink \ -blocking [my blocking] \ -caching $caching] foreach optionalParameter { timeout httpVersion method headers data query contentType informObject } { if {[my exists $optionalParameter]} { lappend cmd -$optionalParameter [my set $optionalParameter] } } #my showMsg "cmd=$cmd" set token [eval $cmd] #if {[my success]} { # $sink reportTimes # #puts stderr <[$sink content]> #} } SimpleRequest instproc success {} { if {[my exists token]} { return [expr {[[my set token] set finished] == 1}] } return 0 } SimpleRequest instproc destroy {} { if {[my exists token]} { [my set token] destroy } next } SimpleRequest instproc getContent {} { [my set sink] content } SimpleRequest instproc getContentLength {} { [my set sink] contentLength } #SimpleRequest instproc destroy args { next } ####################################################################### namespace export \ Access FileAccess File CacheAccess ReAccess \ Cmd NetAccess Http Https Sink TimeSink \ ParallelSink MemorySink FileSink \ ShadowFileSink CacheFileSink SimpleRequest } namespace import ::xotcl::comm::httpAccess::* ./nsf2.4.0/library/xotcl/library/serialize/pkgIndex.tcl000644 000766 000024 00000000747 14276141440 023710 0ustar00neumannstaff000000 000000 package ifneeded xotcl::scriptCreation::recoveryPoint 2.0 "[list source [file join $dir RecoveryPoint.xotcl]]; [list package provide xotcl::scriptCreation::recoveryPoint 2.0]" package ifneeded xotcl::scriptCreation::scriptCreator 2.0 "[list source [file join $dir ScriptCreator.xotcl]]; [list package provide xotcl::scriptCreation::scriptCreator 2.0]" package ifneeded xotcl::serializer 2.4 "[list source [file join $dir Serializer.xotcl]]; [list package provide xotcl::serializer 2.4]" ./nsf2.4.0/library/xotcl/library/serialize/Serializer.xotcl000644 000766 000024 00000000217 13521333630 024603 0ustar00neumannstaff000000 000000 # -*- Tcl -*- # offer old package name for backward minimal compatibility package provide xotcl::serializer 2.4 package require nx::serializer ./nsf2.4.0/library/xotcl/library/serialize/RecoveryPoint.xotcl000644 000766 000024 00000024161 13261441377 025317 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package provide xotcl::scriptCreation::recoveryPoint 2.0 package require XOTcl 2.0 namespace eval ::xotcl::scriptCreation::recoveryPoint { namespace import ::xotcl::* ## fehlt noch: filter, mixins, metadata, ass, assoption, etc ## beim recover Class's,Object's proc instproc vars nicht ueberschreiben ## filter dann anhaengen etc ... ## der Recovery Filter darf durch Object filter "" nicht gelöscht werden # # filter to ensure that recovering doesn't overwrite # existing objs/classes # Object instproc recoveryFilter args { ::set method [self calledproc] switch -- $method { create { # don't overwrite objects if {![::Object isobject [lindex $args 0]]} { next } else { # puts stderr "Recovery Filter: omitting [lindex $args 0]" } } proc { if {[lsearch [my info procs] [lindex $args 0]] == -1} { next } else { # puts stderr "Recovery Filter: omitting proc [self]::[lindex $args 0]" } } instproc { if {[lsearch [my info instprocs] [lindex $args 0]] == -1} { next } else { # puts stderr "Recovery Filter: omitting instproc [self]::[lindex $args 0]" } } set { if {[lsearch [my info vars] [lindex $args 0]] == -1} { next } else { # puts stderr "Recovery Filter: omitting var [self]::[lindex $args 0]" } } default {next} } } # # remove filter from object # Object instproc filterremove f { ::set fl [my info filter] puts stderr "filterremove on [self] with $f; fullName: [my filtersearch $f]" while {[::set index [lsearch $fl [my filtersearch $f]]] != -1} { ::set fl [lreplace $fl $index $index] } my filter $fl } # # remove mixin from object # Object instproc mixinremove m { puts stderr "mixinremove on [self] with $m" ::set ml [my info mixins] while {[::set index [lsearch $ml $m]] != -1} { ::set ml [lreplace $ml $index $index] } my mixin $ml } Class RecoveryPoint \ -parameter { {appendedObjs ""} {appendedCls ""} {appendedNamespaces ""} {withState 0} {appendToFile 0} {definedObjs [list Object \ Class \ Class::Parameter]} {excludeNames ""} } # # queries the definedObjs variable whether a given object # is already defined/predefined or not # -> a way to exclude classes/objs from saving # RecoveryPoint instproc isDefined {n} { my instvar definedObjs puts stderr "Checking Defined: $n in $definedObjs" if {[lsearch $definedObjs [string trimleft $n :]] == -1} { return 0 } else { return 1 } } RecoveryPoint instproc appendDefined {n} { my instvar definedObjs lappend definedObjs [string trimleft $n :] } # # check whether an obj/cls/namespace is appended already # append obj/cls/namespace # foreach method {Obj Cl Namespace} { set r { my instvar {appended${method}s name}} set r [subst -nocommands -nobackslash $r] set s $r append s { if {[lsearch $name [string trimleft $n :]] == -1} { return 0 } else { return 1 } } RecoveryPoint instproc isAppended$method {n} $s append r { lappend name [string trimleft $n :] } RecoveryPoint instproc append$method {n} $r } # # compare command for lsort # RecoveryPoint instproc namespaceDepth {a b} { set aCount 0 set bCount 0 for {set i 0} {$i < [string length $a]} {incr i} { if {[string index $a $i] eq ":"} { incr aCount } } for {set i 0} {$i < [string length $b]} {incr i} { if {[string index $b $i] eq ":"} { incr bCount } } if {$aCount == $bCount} { return 0 } elseif {$aCount > $bCount} { return 1 } return -1 } # # produces a script containing the current state of # the given obj # RecoveryPoint instproc stateScript {obj} { set script "" foreach v [$obj info vars] { if {[lsearch [my set excludeNames] $v] == -1} { $obj instvar $v if {[array exists $v]} { foreach name [array names $v] { set arr ${v}($name) set value [$obj set $arr] append script "$obj set $arr \"$value\"\n" } } else { set value [set $v] append script "$obj set $v \"$value\"\n" } } } return $script } # # produces a script containing the procs of the given obj # RecoveryPoint instproc procScript {obj} { set script "" foreach p [$obj info procs] { if {[lsearch [my set excludeNames] $v] == -1} { append script \ "$obj proc $p \{[$obj info args $p]\} \{[$obj info body $p]\}\n" } } return $script } # # produces a script containing the instprocs of the given class # RecoveryPoint instproc instprocScript {cl} { set script "" foreach p [$cl info instprocs] { if {[lsearch [my set excludeNames] $v] == -1} { append script \ "$cl instproc $p \{[$cl info instargs $p]\} \{[$cl info instbody $p]\}\n" } } return $script } # # append parent obj/classes/namespaces of an object completely # RecoveryPoint instproc appendParents {name} { # puts stderr "Recovery -- appendParents $name " set p "" set script "" set n $name while {[set np [namespace parent ::$n]] != "::"} { lappend p $np set n $np } set p [lsort -command {[self] namespaceDepth} $p] foreach n $p { if {[Object isobject $n]} { if {[$n isclass]} { append script [my classScript $n] } else { append script [my objectScript $n] } } else { if {![my isAppendedNamespace $n]} { append script "namespace eval $n \{\}\n" # puts stderr "Recovery -- Appending Namespace: $n" my appendedNamespace $n } } } return $script } # # produces a script recovering the given obj with all children # without state # RecoveryPoint instproc objectScript {obj} { # puts stderr "Recovery -- Object Script $obj" my instvar withState set script "" if {![my isDefined $obj] && ![my isAppendedObj $obj]} { # if the object's class is not yet appended => do it now set objClass [$obj info class] append script [my classScript $objClass] # append all parent namespaces append script [my appendParents $obj] # append the obj append script "$objClass $obj\n" append script [my procScript $obj] if {$withState == 1} { append script [my stateScript $obj] } # puts stderr "Recovery -- Appending Object: $obj" my appendObj $obj # append its children foreach o [$obj info children] { append script [my objectScript $o] } } return $script } # # produces a script recovering the given class with all children # without state # RecoveryPoint instproc classScript {cl} { # puts stderr "Recovery -- Class Script $cl" my instvar withState set script "" if {![my isDefined $cl] && ![my isAppendedCl $cl]} { # if the class's meta-class is not yet appended => do it now set metaClass [$cl info class] append script [my classScript $metaClass] # append all parent namespaces append script [my appendParents $cl] # append the class append script "$metaClass $cl" set sl [$cl info superclass] if {$sl ne ""} { append script " -superclass \{$sl\}\n" } else { append script "\n" } append script [my instprocScript $cl] append script [my procScript $cl] if {$withState == 1} { append script [my stateScript $cl] } # puts stderr "Recovery -- Appending Class: $cl \n $script" my appendCl $cl # append children set children [$cl info children] set classChildren [$cl info classchildren] foreach c $children { if {[lsearch $classChildren $c] != -1} { append script [my classScript $c] } else { append script [my objectScript $c] } } } return $script } # # produces a script recovering the given class and all subclasses # with all their children and all instances # # RecoveryPoint instproc hierarchyScript {cl} { set script [my classScript $cl] set sortedInstances \ [lsort -command {[self] namespaceDepth} [$cl info instances]] foreach o $sortedInstances { append script [my objectScript $o] } foreach c [$cl info subclass] { append script [my hierarchyScript $c] } return $script } # # saves a script to a file # RecoveryPoint instproc saveScript {filename script} { my instvar appendToFile if {$appendToFile} { set mode a } else { set mode w } set f [open $filename $mode] puts $f $script close $f } # # load a script from a file # RecoveryPoint instproc loadScript {filename} { set f [open $filename r] set r [read $f] close $f return $r } # # produce methods to save/recover an object script to/from a file # with/without state/only state # foreach method { Object ObjectState ObjectWithState Class ClassWithState \ Hierarchy HierarchyWithState } { set s { my set withState } if {[regexp {(.*)WithState} $method _ m]} { set call $m append s "1" } else { set call $method append s "0" } scan $call %c l set ::low "[format %c [expr {$l + 32}]][string range $call 1 end]" append s { my appendedObjs "" my appendedCls "" my appendedNamespaces "" } append s " foreach a \$args \{" set r { set script [my ${low}Script } set r [subst -nocommands -nobackslash $r] append s $r append s {$a] my saveScript $filename $script} append s " \} " RecoveryPoint instproc save$method {filename args} $s } RecoveryPoint instproc recover {filename} { set r [my loadScript $filename] Object filterappend recoveryFilter # puts stderr "RecoveryFilter appended for $filename" eval $r Object filterremove recoveryFilter # puts stderr "RecoveryFilter removed for $filename" return } namespace export RecoveryPoint } namespace import ::xotcl::scriptCreation::recoveryPoint::* ./nsf2.4.0/library/xotcl/library/serialize/ScriptCreator.xotcl000644 000766 000024 00000012074 13261441377 025273 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package provide xotcl::scriptCreation::scriptCreator 2.0 package require XOTcl 2.0 namespace eval ::xotcl::scriptCreation::scriptCreator { namespace import ::xotcl::* Class ScriptCreator \ -parameter { {excludedObjs {Object Class Class::Parameter}} {excludeNames ""} {dependencyChecking 1} } # # queries the excludedObjs variable whether a given object # is already defined/predefined or not # -> a way to exclude classes/objs from saving # ScriptCreator instproc isExcluded {n} { my instvar excludedObjs #puts stderr "Checking Excluded: $n in $excludedObjs" if {[lsearch $excludedObjs [string trimleft $n :]] == -1} { return 0 } else { return 1 } } ScriptCreator instproc appendExcluded {n} { my instvar excludedObjs lappend excludedObjs [string trimleft $n :] } # # compare command for lsort # ScriptCreator instproc namespaceDepth {a b} { set aCount 0 set bCount 0 for {set i 0} {$i < [string length $a]} {incr i} { if {[string index $a $i] eq ":"} { incr aCount } } for {set i 0} {$i < [string length $b]} {incr i} { if {[string index $b $i] eq ":"} { incr bCount } } if {$aCount == $bCount} { return 0 } elseif {$aCount > $bCount} { return 1 } return -1 } # # produces a script containing the current state of # the given obj # ScriptCreator instproc stateScript {obj} { set script "" foreach v [$obj info vars] { if {[lsearch [my set excludeNames] $v] == -1} { if {[$obj array exists $v]} { foreach name [$obj array names $v] { set arr ${v}($name) set value [$obj set $arr] append script "$obj set $arr \"$value\"\n" } } else { set value [$obj set $v] append script "$obj set $v \"$value\"\n" } } } return $script } # # produces a script containing the procs of the given obj # ScriptCreator instproc procScript {obj} { set script "" foreach p [$obj info procs] { if {[lsearch [my set excludeNames] $p] == -1} { append script \ "$obj proc $p \{[$obj info args $p]\} \{[$obj info body $p]\}\n" } } return $script } # # produces a script containing the instprocs of the given class # ScriptCreator instproc instprocScript {cl} { set script "" foreach p [$cl info instprocs] { if {[lsearch [my set excludeNames] $p] == -1} { append script \ "$cl instproc $p \{[$cl info instargs $p]\} \{[$cl info instbody $p]\}\n" } } return $script } # # saves a script to a file # ScriptCreator instproc saveScript {filename script} { set f [open $filename w] puts $f $script close $f } # # load a script from a file # ScriptCreator instproc loadScript {filename} { set f [open $filename r] set r [read $f] close $f return $r } # # check parent obj/classes/namespaces of an object completely # ScriptCreator instproc checkParents {name} { set p "" set n $name while {[set np [namespace parent ::$n]] != "::"} { lappend p $np set n $np } set p [lsort -command {my namespaceDepth} $p] foreach n $p { if {![my isExcluded $n] && ![my isAppended $n]} { error "ScriptCreator: $name needs parent $n, neither appended nor excluded yet." } } } ScriptCreator instproc checkClass {obj class} { if {![my isExcluded $class] && ![my isAppended $class]} { error "ScriptCreator: $obj depends on $class, neither appended nor excluded yet." } } ScriptCreator instproc isAppended name { set n [string trimleft $name :] if {[lsearch [my set appendedNames] $n]!=-1} { return 1 } else { return 0 } } ScriptCreator instproc appendName name { set n [string trimleft $name :] my lappend appendedNames $n } ScriptCreator instproc makeScript args { my instvar dependencyChecking my set appendedNames "" set script "" foreach name $args { #puts stderr "Script Creator -- $name" if {![my isExcluded $name] && ![my isAppended $name]} { if {$dependencyChecking} { my checkParents $name } if {[Object isobject $name]} { set class [$name info class] if {$dependencyChecking} { my checkClass $name $class } if {[Object isclass $name]} { # append the class #puts stderr "Appending Class: $name" append script "[$name info class] $name" set sl [$name info superclass] if {$dependencyChecking} { foreach c $sl { my checkClass $name $c } } if {$sl ne ""} { append script " -superclass \{$sl\}\n" } else { append script "\n" } append script [my instprocScript $name] } else { # append the obj #puts stderr "Appending Object: $name" append script "[$name info class] $name\n" } append script [my procScript $name] } else { append script "namespace eval $name \{\}\n" #puts stderr "Appending Namespace: $name" } my appendName $name } } return $script } namespace export ScriptCreator } namespace import ::xotcl::scriptCreation::scriptCreator::* ./nsf2.4.0/library/xotcl/library/pkgIndex.tcl000644 000766 000024 00000000155 14276141440 021712 0ustar00neumannstaff000000 000000 package ifneeded XOTcl 2.4.0 "[list source [file join $dir xotcl2.tcl]]; [list package provide XOTcl 2.4.0]" ./nsf2.4.0/library/xotcl/library/xotcl2.tcl000644 000766 000024 00000155617 13617007560 021374 0ustar00neumannstaff000000 000000 # -*- Tcl -*- ############################################################ # xotcl2.tcl -- # # Implementation of the XOTcl 2 object system, based # on the Next Scripting Framework (NSF). # # Copyright (C) 2010-2016 Gustaf Neumann # Copyright (C) 2010-2016,2019 Stefan Sobernig # # Vienna University of Economics and Business # Institute of Information Systems and New Media # A-1020, Welthandelsplatz 1 # Vienna, Austria # # This work is licensed under the MIT License https://www.opensource.org/licenses/MIT # # Copyright: # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # package require nx package provide XOTcl 2.4.0 ####################################################### # Classical ::xotcl* ####################################################### namespace eval ::xotcl { # # Set XOTcl version variables # set ::xotcl::version 2.3 set ::xotcl::patchlevel .0 namespace eval ::nsf {} ;# make pkg-indexer happy namespace eval ::nsf::parameter {} ;# make pkg-indexer happy set ::nsf::bootstrap ::xotcl # # Perform the basic setup of XOTcl. First, let us allocate the # basic classes of XOTcl. This call creates the classes # ::xotcl::Object and ::xotcl::Class and defines these as root class # of the object system and as root meta class. # ::nsf::objectsystem::create ::xotcl::Object ::xotcl::Class { -class.alloc alloc -class.create create -class.dealloc dealloc -class.configureparameter __class_configureparameter -class.recreate recreate -object.configure configure -object.configureparameter __object_configureparameter -object.cleanup cleanup -object.defaultmethod defaultmethod -object.destroy destroy -object.init init -object.move move -object.unknown unknown -slot.set value=set -slot.get value=get } # # create ::nx and ::nsf namespaces, otherwise mk_pkgindex will fail # namespace eval ::nx {} namespace eval ::nsf {} namespace eval ::nsf::method::create {} # # get frequently used primitiva into the ::xotcl namespace # namespace import ::nsf::configure ::nsf::my ::nsf::finalize ::nsf::interp namespace import ::nsf::method::alias ::nsf::is interp alias {} ::xotcl::next {} ::nsf::xotclnext interp alias {} ::xotcl::relation {} ::nsf::relation::set proc ::xotcl::self {{arg ""}} { switch $arg { "" {::uplevel ::nsf::self} next { set handle [::uplevel ::nsf::current nextmethod] method_handle_to_xotcl $handle } default {::uplevel ::nsf::current $arg} } } # @object ::xotcl::Object # # XOTcl programs are constructed out of objects. This class # describes common structural and behavioral features for all XOTcl # objects. It is the root object-class in the XOTcl 2 object system. # provide the standard command set for ::xotcl::Object ::nsf::method::alias Object autoname ::nsf::methods::object::autoname ::nsf::method::alias Object class ::nsf::methods::object::class ::nsf::method::alias Object cleanup ::nsf::methods::object::cleanup ::nsf::method::alias Object configure ::nsf::methods::object::configure ::nsf::method::alias Object defaultmethod ::nsf::methods::object::defaultmethod ::nsf::method::alias Object destroy ::nsf::methods::object::destroy ::nsf::method::alias Object exists ::nsf::methods::object::exists # ::nsf::method::alias Object init ::nsf::methods::object::init ::nsf::method::alias Object instvar ::nsf::methods::object::instvar ::nsf::method::alias Object noinit ::nsf::methods::object::noinit ::nsf::method::alias Object residualargs ::nsf::methods::object::residualargs # ::nsf::method::alias Object unknown ::nsf::methods::object::unknown ::nsf::method::alias Object uplevel ::nsf::methods::object::uplevel ::nsf::method::alias Object upvar ::nsf::methods::object::upvar ::nsf::method::alias Object volatile ::nsf::methods::object::volatile1 # # object methods # # @method ::xotcl::Object#autoname # # Provides a facility for auto-generating object identifiers. It is # constructed from a seeding string which is appended a numeric # index. This numeric index is incremented upon each call to # {{{autoname}}}. # {{{ # set obj [Object new] # $obj autoname a; # yields "a1" # $obj autoname -instance B; # yields "b1" # $obj autoname a; # yields "a2" # $obj autoname b; # yields "b1" # $obj autoname -reset a; # "" # $obj autoname -reset -instance B; # "" # $obj autoname -instance a; # yields "a1", and NOT "a3"! # $obj autoname -instance B; # yields "b1" # $obj autoname b; # yields "b2" # }}} # The seeding string may also contain {{{[format]}}} expressions (see ...): # {{{ # $obj autoname a%06d; # gives you "a000001", ... # }}} # # @param -instance Have the generated name start with a lower letter (though the seed string has a major first letter) # @param -reset Reset the object-internal counter for a given seed string # @param name The seeding string which is used as a base for name generation # @return The generated name string # @method ::xotcl::Object#cleanup # # TODO: this is a method not used in the Next Scripting Language. This # method is just called via recreate, so everything necessary can be # performed there as well. However, it is available for backward # compatibility available in XOTcl 2.0 # # Resets an object or class to its initial state, as after object # allocation (see {{@method ::xotcl::Class class alloc}}). This method # participates in recreating objects, i.e, it is called during the # recreation process by {{@method ::xotcl::Class class recreate}}. # Depending on the recreation scheme applied (see {{@command # ::nsf::configure}}, object variables are deleted, per-object # namespaces are cleared, and the object's relationships (e.g., mixin # relations) are reset. # # @properties internally-called # @method ::xotcl::Object#destroy # # @use ::xotcl::Object#destroy # @method ::xotcl::Object#exists # # A helper method for checking whether the variable {{{var}}} is # defined on the object and assigned a value. You may use a variable # name with or without prefix, both will resolve to the object scope: # {{{ # $obj eval { # set :foo 1 # set bar 2 # } # # $obj exists foo; # returns 1 # $obj exists :foo; # returns 1 # $obj exists bar; # returns 0 # $obj exists :bar; # returns 0 # }}} # # @param var The name of the variable to verify # @return :boolean 1 if the variable exists, 0 otherwise # @method ::xotcl::Object#instvar # # @param args # @method ::xotcl::Object#noinit # # Calling upon this method during object construction allows you to # bypass the constructor method: # {{{ # Class create C # C instproc init {} {puts stderr "A class-specific constructor shouts out ..."} # C c1 -noinit # }}} # This bypassing feature comes handy when streaming an object into a # scripted form (e.g., by using the bundled Serializer). Upon # deserializing the object, using the {{{noinit}}} flag helps you to # preserve the serialized object state (rather than having the # object re-initialized). # @method ::xotcl::Object#requireNamespace # # This method allows you to request the creation of a namespace for # the given object, a per-object namespace. The namespace is then used # to store instance variables, methods and nested objects. Per-object # namespaces are needed for using and binding object variables to # non-object scopes in Tcl and Tk. For instance, you may use an # per-object namespace to have object variables accessible Tk widgets # and Tk callbacks. To verify whether a per-object namespace is # available for an object, see ... # # Beware that there is a difference between per-object namespaces and # Tcl namespaces which shadow an existing object (i.e., carry the same # name): # {{{ # Object create Foo # Foo requireNamespace # namespace exists Foo; # returns 1 # Foo info hasnamespace; # returns 1 # # Object create Bar # namespace eval ::Bar {} # namespace exists Bar; # returns 1 # Bar info hasnamespace; # returns 0 # }}} # provide some Tcl-commands as methods for ::xotcl::Object ::nsf::method::alias Object append -frame object ::append ::nsf::method::alias Object array -frame object ::array ::nsf::method::alias Object dict -frame object ::dict ::nsf::method::alias Object eval -frame object ::eval ::nsf::method::alias Object incr -frame object ::incr ::nsf::method::alias Object lappend -frame object ::lappend ::nsf::method::alias Object set -frame object ::set ::nsf::method::alias Object subst -frame object ::subst ::nsf::method::alias Object trace -frame object ::trace ::nsf::method::alias Object unset -frame object ::unset # @method ::xotcl::Object#vwait # # A method variant of the Tcl {{{vwait}}} command. You can use it to # have the {{{interp}}} enter an event loop until the specified # variable {{{varname}}} is set on the object. # # @param varName The name of the signaling object variable. ::nsf::method::create Object vwait {varName} { if {[regexp {:[^:]*} $varName]} { error "invalid varName '$varName'; only plain or fully qualified variable names allowed" } if {[string match ::* $varName]} { ::vwait $varName } else { ::vwait :$varName } } # provide the standard command set for ::xotcl::Class ::nsf::method::alias Class alloc ::nsf::methods::class::alloc ::nsf::method::alias Class create ::nsf::methods::class::create ::nsf::method::alias Class dealloc ::nsf::methods::class::dealloc ::nsf::method::alias Class new ::nsf::methods::class::new ::nsf::method::alias Class recreate ::nsf::methods::class::recreate ::nsf::method::alias Class superclass ::nsf::methods::class::superclass # protect some methods against redefinition ::nsf::method::property Object destroy redefine-protected true ::nsf::method::property Class alloc redefine-protected true ::nsf::method::property Class dealloc redefine-protected true ::nsf::method::property Class create redefine-protected true # # define parametercmd and instparametercmd in terms of ::nsf::setter # define filterguard and instfilterguard in terms of filterguard # define mixinguard and instmixinguard in terms of mixinguard # ::nsf::method::forward Object parametercmd ::nsf::method::setter %self -per-object ::nsf::method::forward Class instparametercmd ::nsf::method::setter %self ::nsf::method::alias Object filterguard ::nsf::methods::object::filterguard ::nsf::method::alias Class instfilterguard ::nsf::methods::class::filterguard ::nsf::method::alias Object mixinguard ::nsf::methods::object::mixinguard ::nsf::method::alias Class instmixinguard ::nsf::methods::class::mixinguard ::nsf::method::alias Object requireNamespace ::nsf::methods::object::requirenamespace # define instproc and proc ::nsf::method::create Class instproc { -debug:switch -deprecated:switch name arguments:parameter,0..* -returns body precondition:optional postcondition:optional } { set conditions [list] if {[info exists precondition]} {lappend conditions -precondition $precondition} if {[info exists postcondition]} {lappend conditions -postcondition $postcondition} set r [::nsf::method::create [self] $name $arguments $body {*}$conditions] if {$debug} {::nsf::method::property [self] $r debug true} if {$deprecated} {::nsf::method::property [self] $r deprecated true} if {[info exists returns]} {::nsf::method::property [self] $r returns $returns} return $r } ::nsf::method::create Object proc { -debug:switch -deprecated:switch name arguments -returns body precondition:optional postcondition:optional } { set conditions [list] if {[info exists precondition]} {lappend conditions -precondition $precondition} if {[info exists postcondition]} {lappend conditions -postcondition $postcondition} set r [::nsf::method::create [self] -per-object $name $arguments $body {*}$conditions] if {$debug} {::nsf::method::property [self] $r debug true} if {$deprecated} {::nsf::method::property [self] $r deprecated true} if {[info exists returns]} {::nsf::method::property [self] $r returns $returns} return $r } # define a minimal implementation of "method" Object instproc method { -debug:switch -deprecated:switch name arguments:parameter,0..* -returns body } { set returns_flag [expr {[info exists returns] ? [list -returns $returns] : {}}] :proc -debug=$debug -deprecated=$deprecated $name $arguments {*}$returns_flag $body } Class instproc method { -debug:switch -deprecated:switch -per-object:switch name arguments:parameter,0..* body } { set returns_flag [expr {[info exists returns] ? [list -returns $returns] : {}}] if {${per-object}} { :proc -debug=$debug -deprecated=$deprecated $name $arguments {*}$returns_flag $body } else { :instproc -debug=$debug -deprecated=$deprecated $name $arguments {*}$returns_flag $body } } # define forward methods # # We could nearly define forward via forwarder # # ::nsf::method::forward Object forward ::nsf::method::forward %self -per-object # ::nsf::method::forward Class instforward ::nsf::method::forward %self # # but since we changed the name of -objscope in nsf to -objframe, we # have to provide the definition the hard way via methods. Object instproc forward { -debug:switch -deprecated:switch method -default -earlybinding:switch -methodprefix -objscope:switch -onerror -verbose:switch target:optional args } { set arglist [list] if {[info exists target] && [string index $target 0] eq "-"} { error "target '$target' must not start with a dash" } if {[info exists default]} {lappend arglist -default $default} if {$earlybinding} {lappend arglist -earlybinding} if {[info exists methodprefix]} {lappend arglist -prefix $methodprefix} if {$objscope} {lappend arglist -frame object} if {[info exists onerror]} {lappend arglist -onerror $onerror} if {$verbose} {lappend arglist -verbose} if {[info exists target]} {lappend arglist $target} if {[llength $args] > 0} {lappend arglist {*}$args} set r [::nsf::method::forward [self] -per-object $method {*}$arglist] if {$debug} {::nsf::method::property [self] $r debug true} if {$deprecated} {::nsf::method::property [self] $r deprecated true} return $r } Class instproc instforward { -debug:switch -deprecated:switch method -default -earlybinding:switch -methodprefix -objscope:switch -onerror -verbose:switch target:optional args } { set arglist [list] if {[info exists target] && [string index $target 0] eq "-"} { error "target '$target' must not start with a dash" } if {[info exists default]} {lappend arglist -default $default} if {$earlybinding} {lappend arglist -earlybinding} if {[info exists methodprefix]} {lappend arglist -prefix $methodprefix} if {$objscope} {lappend arglist -frame object} if {[info exists onerror]} {lappend arglist -onerror $onerror} if {$verbose} {lappend arglist -verbose} if {[info exists target]} {lappend arglist $target} if {[llength $args] > 0} {lappend arglist {*}$args} set r [::nsf::method::forward [self] $method {*}$arglist] if {$debug} {::nsf::method::property [self] $r debug true} if {$deprecated} {::nsf::method::property [self] $r deprecated true} return $r } Class instproc unknown {args} { # puts stderr "use '[self] create $args', not '[self] $args'" set lvl 1 if {[::nsf::current isnextcall]} { set lvl [::nsf::current callinglevel] } ::uplevel $lvl [list [self] create {*}$args] } Object instproc unknown {m args} { if {![self isnext]} { error "[self]: unable to dispatch method '$m'" } } # "init" must exist on Object. Per default it is empty. Object instproc init args { if {![::nsf::current isnextcall] && [llength $args] > 0 && [::nsf::configure debug] > 0} { ::nsf::log Warning "Arguments '$args' to constructor of object [self] are most likely not processed" } } Object instproc self {} {::xotcl::self} # # Method objectparameter, backwards upward compatible. We use # here the definition of parametersfromslots from nx.tcl # ::xotcl::Object instproc __object_configureparameter {} { set slotObjects [nsf::directdispatch [self] ::nsf::methods::object::info::lookupslots -type ::nx::Slot] set parameterDefinitions [::nsf::parameter::specs $slotObjects] lappend parameterDefinitions args:alias,method=residualargs,args } ::xotcl::Class instproc __class_configureparameter {} { set slotObjects [nsf::directdispatch [self] ::nsf::methods::class::info::slotobjects -closure -type ::nx::Slot] set parameterDefinitions [::nsf::parameter::specs $slotObjects] lappend parameterDefinitions args:alias,method=residualargs,args } ###################################################################### # Define default accessors for all parameters ###################################################################### ::nsf::method::create Object __default_accessor args {return public} ::nsf::method::property Object __default_accessor call-protected true # # Use parameter definition from nx # (same with classInfo parameter, see below) #::nsf::method::alias ::xotcl::Class parameter ::nsf::classes::nx::Class::attributes ::xotcl::Class instproc parameter {arglist} { set slotContainer [::nx::slotObj [::nsf::self]] foreach arg $arglist { #puts stderr "PARAMETER: [self] ::nsf::classes::nx::Class::property -accessor public $arg" [self] ::nsf::classes::nx::Class::property -class ::xotcl::Attribute -accessor public $arg ::nsf::method:::setter [self] [lindex $arg 0] } ::nsf::var::set $slotContainer __parameter $arglist } # We provide a default value for superclass (when no superclass is # specified explicitly) and metaclass, in case they should differ # from the root classes of the object system. proc createBootstrapVariableSlots {class definitions} { foreach att $definitions { if {[llength $att]>1} {lassign $att att default} set slotObj [::nx::slotObj $class $att] #puts stderr "::nx::BootStrapVariableSlot create $slotObj" ::nx::BootStrapVariableSlot create $slotObj if {[info exists default]} { #puts stderr "::nsf::var::set $slotObj default $default" ::nsf::var::set $slotObj default $default unset default } # # register the standard setter # ::nsf::method::setter $class $att # # make setter protected # #regexp {^([^:]+):} $att . att #::nsf::method::property $class $att call-protected true # # set for every bootstrap property slot the position 0 # ::nsf::var::set $slotObj position 0 ::nsf::var::set $slotObj configurable 1 } } createBootstrapVariableSlots ::xotcl::Class { {__default_superclass ::xotcl::Object} {__default_metaclass ::xotcl::Class} } ############################################ # Register system slots ############################################ # We need fully qualified "::xotcl" prefixes, since prefix # completion would skip the object system root namespace nx::MetaSlot create ::xotcl::RelationSlot -superclass ::nx::RelationSlot ::nsf::method::alias ::xotcl::RelationSlot value=assign ::nsf::relation::set set cSlotContainer [::nx::slotObj ::xotcl::Class] set oSlotContainer [::nx::slotObj ::xotcl::Object] ::xotcl::RelationSlot create ${cSlotContainer}::superclass \ -defaultmethods {get set} #::nsf::method::alias ${cSlotContainer}::superclass value=set ::nsf::relation::set ::xotcl::RelationSlot create ${oSlotContainer}::class -elementtype class -multiplicity 1..1 \ -defaultmethods {get set} #::nsf::method::alias ${oSlotContainer}::class value=set ::nsf::relation::set ::xotcl::RelationSlot create ${oSlotContainer}::mixin -forwardername object-mixin \ -defaultmethods {get set} \ -elementtype mixinreg -multiplicity 0..n ::xotcl::RelationSlot create ${oSlotContainer}::filter -forwardername object-filter \ -defaultmethods {get set} \ -elementtype filterreg -multiplicity 0..n ::xotcl::RelationSlot create ${cSlotContainer}::instmixin -forwardername class-mixin \ -defaultmethods {get set} \ -elementtype mixinreg -multiplicity 0..n ::xotcl::RelationSlot create ${cSlotContainer}::instfilter -forwardername class-filter \ -defaultmethods {get set} \ -elementtype filterreg -multiplicity 0..n ######################## # Info definition ######################## Object create ::xotcl::objectInfo Object create ::xotcl::classInfo ::nsf::object::property ::xotcl::objectInfo keepcallerself true ::nsf::object::property ::xotcl::classInfo keepcallerself true ::nsf::object::property ::xotcl::objectInfo perobjectdispatch true ::nsf::object::property ::xotcl::classInfo perobjectdispatch true # note, we are using ::xotcl::infoError, defined below #Object instforward info -onerror ::nsf::infoError ::xotcl::objectInfo %1 {%@2 %self} #Class instforward info -onerror ::nsf::infoError ::xotcl::classInfo %1 {%@2 %self} # # error handler for info # #proc ::nsf::infoerror msg { # #puts stderr "INFO ERROR: <$msg>\n$::errorInfo" # regsub -all " " $msg "" msg # regsub -all " " $msg "" msg # regsub {\"} $msg "\"info " msg # error $msg "" #} ::nsf::method::alias Object info ::xotcl::objectInfo ::nsf::method::alias Class info ::xotcl::classInfo # # Backward compatibility info subcommands; # # TODO: should go finally into a library. # # Obsolete methods # # already emulated: # # => info -per-object method parameter .... replaces # info instargs # info instnonposargs # info instdefault # # => info method .... replaces # info body # info instbody # # => info methods .... replaces # info commands # info instcommands # info procs # info instprocs # info parametercmd # info instparametercmd # # => info is (resp. ::xotcl::is) replaces # info isobject # info isclass # info ismetaclass # info ismixin # info istype # # => info method .... replaces # proc # instproc # info args # info nonposargs # info default # # TODO mark all obsolete calls at least as deprecated in library # proc ::xotcl::info_args {scope o method} { set result [list] foreach \ argName [$o ::nsf::methods::${scope}::info::method args $method] \ flag [$o ::nsf::methods::${scope}::info::method parameter $method] { if {[string match -* $flag]} continue lappend result $argName } #puts stderr "+++ get ${inst}args for $o $method => $result" return $result } proc ::xotcl::info_nonposargs {scope o method} { set result [list] foreach flag [$o ::nsf::methods::${scope}::info::method parameter $method] { if {![string match -* $flag]} continue lappend result $flag } #puts stderr "+++ get ${inst}nonposargs for $o $method => $result" return $result } proc ::xotcl::info_default {scope o method arg varName} { foreach \ argName [$o ::nsf::methods::${scope}::info::method args $method] \ flag [$o ::nsf::methods::${scope}::info::method parameter $method] { if {$argName eq $arg} { # we are in a proc, so using built-in "upvar" is safe ::upvar $varName default if {[llength $flag] == 2} { set default [lindex $flag 1] #puts "--- get $scope default for $o $method $arg => setting default to '$default'" return 1 } #puts "--- get $scope default for $o $method $arg fails" set default "" return 0 } } error "procedure \"$method\" doesn't have an argument \"$arg\"" } proc ::xotcl::info_forward_options {list} { set result [list] set i 0 for {set i 0} {$i < [llength $list]} {incr i} { switch -glob -- [lindex $list $i] { -frame { lappend result -objscope incr i } -prefix { lappend result -methodprefix incr i lappend result [lindex $list $i] } -* {lappend result [lindex $list $i]} default { lappend result {*}[lrange $list $i end] break } } } return $result } # define temporary method "alias" Object instproc alias {name cmd} {::nsf::method::alias [self] $name $cmd} objectInfo eval { :proc args {method} {::xotcl::info_args object [self] $method} :proc body {methodName} {my ::nsf::methods::object::info::method body $methodName} :proc check {} {::xotcl::checkoption_internal_to_xotcl1 [::nsf::method::assertion [self] check]} :alias class ::nsf::methods::object::info::class :alias children ::nsf::methods::object::info::children :proc commands {pattern:optional} { set cmd [list ::nsf::methods::object::info::methods -type all] if {[info exists pattern]} {lappend cmd $pattern} return [my {*}$cmd] } :proc default {method arg varName} { # # We are called from object "objectInfo". The true caller is 2 # levels up. # :upvar 2 $varName defaultVar # pass varName to be able produce the right error message set r [::xotcl::info_default object [self] $method $arg defaultVar] #if {$r == 1 && ![info exists defaultVar]} {error inconsistency} #puts "--- objectInfo default: var '$varName' level=[info level]" return $r } :proc filter {-order:switch -guards:switch pattern:optional} { set guardsFlag [expr {$guards ? "-guards" : ""}] set patternArg [expr {[info exists pattern] ? [list $pattern] : ""}] if {$order && !$guards} { set def [::nsf::directdispatch [::nsf::current object] \ ::nsf::methods::object::info::lookupfilters \ {*}$guardsFlag \ {*}$patternArg] set def [method_handles_to_xotcl $def] } else { set def [::nsf::directdispatch [::nsf::current object] \ ::nsf::methods::object::info::filters \ {*}$guardsFlag \ {*}$patternArg] } #puts stderr " => $def" return $def } :alias filterguard ::nsf::methods::object::info::filterguard :proc forward {-definition:switch name:optional} { if {$definition} { if {![info exists name]} {error "option -definition requires name of forwarding method to be specified" } set def [my ::nsf::methods::object::info::forward -definition $name] return [::xotcl::info_forward_options $def] } else { return [my ::nsf::methods::object::info::forward {*}[self args]] } } :alias hasnamespace ::nsf::methods::object::info::hasnamespace :proc invar {} {::nsf::method::assertion [self] object-invar} :proc methods { -nocmds:switch -noprocs:switch -nomixins:switch -incontext:switch pattern:optional } { set type all if {$nocmds} {set type scripted} if {$noprocs} {if {$nocmds} {return ""}; set type builtin} set cmd [list ::nsf::methods::object::info::lookupmethods -type $type] if {$nomixins} {lappend cmd -nomixins} if {$incontext} {lappend cmd -incontext} if {[info exists pattern]} {lappend cmd $pattern} my {*}$cmd } :proc mixin {-order:switch -guards:switch pattern:optional} { if {$order} { set cmd ::nsf::methods::object::info::lookupmixins } else { set cmd ::nsf::methods::object::info::mixins } if {$guards} {lappend cmd "-guards"} if {[info exists pattern]} {lappend cmd $pattern} my {*}$cmd } :alias mixinguard ::nsf::methods::object::info::mixinguard :proc nonposargs {method} {::xotcl::info_nonposargs object [self] $method} :proc parametercmd {name} {::nsf::classes::nx::Object::setter [self] $name} :alias parent ::nsf::methods::object::info::parent :proc post {methodName} {my ::nsf::methods::object::info::method post $methodName} :proc pre {methodName} {my ::nsf::methods::object::info::method pre $methodName} :proc procs {pattern:optional} { set cmd [list ::nsf::methods::object::info::methods -type scripted] if {[info exists pattern]} {lappend cmd $pattern} return [my {*}$cmd] } :alias slots ::nsf::methods::object::info::slotobjects :alias precedence ::nsf::methods::object::info::precedence :alias vars ::nsf::methods::object::info::vars } # # copy all methods from Object.info to Class.info # foreach m [objectInfo ::nsf::methods::object::info::methods] { ::nsf::method::alias classInfo $m [objectInfo ::nsf::methods::object::info::method registrationhandle $m] } classInfo eval { :alias classchildren ::nsf::methods::object::info::children :alias classparent ::nsf::methods::object::info::parent :proc default {method arg varName} { # # We are called from object "classInfo". The true caller is 2 # levels up. # :upvar 2 $varName defaultVar set r [::xotcl::info_default object [self] $method $arg defaultVar] #puts "--- classInfo default: var '$varName' level=[info level] result $r exists [info exists defaultVar]" #if {$r == 1 && ![info exists defaultVar]} {error inconsistency} return $r } :proc heritage {pattern:optional} { set cmd [list ::nsf::methods::class::info::superclass -closure] if {[info exists pattern]} {lappend cmd $pattern} return [my {*}$cmd] } :alias instances ::nsf::methods::class::info::instances :proc instargs {method} {::xotcl::info_args class [self] $method} :proc instbody {methodName} {my ::nsf::methods::class::info::method body $methodName} :proc instcommands {pattern:optional} { set cmd [list ::nsf::methods::class::info::methods] if {[info exists pattern]} {lappend cmd $pattern} return [my {*}$cmd] } :proc instdefault {method arg varName} { # # We are called from object "classInfo". The true caller is 2 # levels up. # :upvar 2 $varName defaultVar set r [::xotcl::info_default class [self] $method $arg defaultVar] #puts "--- classInfo instdefault: var '$varName' level=[info level]" #if {$r == 1 && ![info exists defaultVar]} {error inconsistency} return $r } :alias instfilter ::nsf::methods::class::info::filters :alias instfilterguard ::nsf::methods::class::info::filterguard #:alias instforward ::nsf::methods::class::info::forward :proc instforward {-definition:switch name:optional} { if {$definition} { if {![info exists name]} {error "option -definition requires name of forwarding method to be specified" } set def [my ::nsf::methods::class::info::forward -definition $name] return [::xotcl::info_forward_options $def] } else { return [my ::nsf::methods::class::info::forward {*}[self args]] } } :proc instinvar {} {::nsf::method::assertion [self] class-invar} :proc instmixin {-order:switch -guards:switch pattern:optional} { set cmd ::nsf::methods::class::info::mixins if {$order} {lappend cmd "-heritage"} if {$guards} {lappend cmd "-guards"} if {[info exists pattern]} {lappend cmd $pattern} my {*}$cmd } :alias instmixinguard ::nsf::methods::class::info::mixinguard :proc instmixinof {-closure:switch pattern:optional} { set cmd [list ::nsf::methods::class::info::mixinof -scope class] if {$closure} {lappend cmd -closure} if {[info exists pattern]} {lappend cmd $pattern} return [my {*}$cmd] } :proc instparametercmd {pattern:optional} { set cmd [list ::nsf::methods::class::info::methods -type setter] if {[info exists pattern]} {lappend cmd $pattern} return [my {*}$cmd] } :proc instnonposargs {method} {::xotcl::info_nonposargs class [self] $method} :proc instpost {methodName} {my ::nsf::methods::class::info::method postcondition $methodName} :proc instpre {methodName} {my ::nsf::methods::class::info::method precondition $methodName} :proc instprocs {pattern:optional} { set cmd [list ::nsf::methods::class::info::methods -type scripted] if {[info exists pattern]} {lappend cmd $pattern} return [my {*}$cmd] } :proc mixinof {-closure:switch pattern:optional} { set cmd [list ::nsf::methods::class::info::mixinof -scope object] if {$closure} {lappend cmd -closure} if {[info exists pattern]} {lappend cmd $pattern} return [my {*}$cmd] } #:alias parameter ::nx::Class::slot::__info::attributes :proc parameter {} { set slotContainer [::nx::slotObj [::nsf::self]] if {[::nsf::var::exists $slotContainer __parameter]} { return [::nsf::var::set $slotContainer __parameter] } return "" } :alias slots ::nsf::methods::class::info::slotobjects :alias subclass ::nsf::methods::class::info::subclass :alias superclass ::nsf::methods::class::info::superclass } # define "info info" objectInfo method info {} {::nx::internal::infoOptions ::xotcl::objectInfo} classInfo method info {} {::nx::internal::infoOptions ::xotcl::classInfo} # define "info unknown" objectInfo proc unknown {method args} { error "[::xotcl::self] unknown info option \"$method\"; [:info info]" } classInfo proc unknown {method args} { error "[::xotcl::self] unknown info option \"$method\"; [:info info]" } # # end if info # # remove temporary method "alias" Object instproc alias {} {} # emulation of object::exists, isclass ... Object instproc isobject {{object:substdefault "[self]"}} {::nsf::object::exists $object} Object instproc isclass {{class:substdefault "[self]"}} {::nsf::is class $class} Object instproc ismetaclass {{class:substdefault "[self]"}} {::nsf::is metaclass $class} Object instproc ismixin {class} { return [expr {[::nsf::is class $class] && [my ::nsf::methods::object::info::hasmixin $class]}] } Object instproc istype {class} { return [expr {[::nsf::is class $class] && [::nsf::directdispatch [self] ::nsf::methods::object::info::hastype $class]}] } # definition of "xotcl::Object contains", based on nx ::nsf::method::alias Object contains ::nsf::classes::nx::Object::contains # definition of "xotcl::Class slots", based on contains ::xotcl::Class instproc slots {cmd} { set slotContainer [::nx::slotObj [self]] ::uplevel [list [self] contains -object $slotContainer $cmd] } # # provide a stub function to allow reuse of copy of nx # ::nsf::method::create Object __resolve_method_path { -per-object:switch -verbose:switch path } { set object [::nsf::self] return [list object $object methodName $path regObject $object] } ::nsf::method::property Object __resolve_method_path call-protected true # assertion handling proc checkoption_xotcl1_to_internal checkoptions { set options [list] foreach option $checkoptions { if {$option eq "invar"} { lappend options "object-invar" } elseif {$option eq "instinvar"} { lappend options "class-invar" } else { lappend options $option } } return $options } proc checkoption_internal_to_xotcl1 checkoptions { set options [list] foreach option $checkoptions { if {$option eq "object-invar"} { lappend options "invar" } elseif {$option eq "class-invar"} { lappend options "instinvar" } else { lappend options $option } } return $options } proc method_handles_to_xotcl definitions { set defs [list] foreach def $definitions {lappend defs [method_handle_to_xotcl $def]} return $defs } proc method_handle_to_xotcl methodHandle { set definition [::nx::Object info method definition $methodHandle] #puts "method_handle_to_xotcl raw definition '$methodHandle' // $definition" if {$definition ne ""} { set obj [lindex $definition 0] set modifier [lindex $definition 2] if {$modifier eq "object"} { set prefix "" set kind [lindex $definition 3] set name [lindex $definition 4] } else { set prefix [expr {[::nsf::is class $obj] ? "inst" : ""}] set kind $modifier set name [lindex $definition 3] } if {$kind eq "method"} { set kind proc } elseif {$kind eq "setter"} { set kind parametercmd } elseif {$kind eq "alias"} { set kind "cmd" set name [lindex $definition 3] } set definition [list [lindex $definition 0] ${prefix}$kind $name] } #puts "method_handle_to_xotcl gets handle '$methodHandle' // $definition" return $definition } Object instproc check {checkoptions} { ::nsf::method::assertion [self] check [::xotcl::checkoption_xotcl1_to_internal $checkoptions] } Object instforward invar ::nsf::method::assertion %self object-invar Class instforward instinvar ::nsf::method::assertion %self class-invar Object instproc abstract {methtype methname arglist} { if {$methtype ne "proc" && $methtype ne "instproc" && $methtype ne "method"} { error "invalid method type '$methtype', \ must be either 'proc', 'instproc' or 'method'." } set arglist2 $arglist regsub -all {\"} $arglist {\\"} arglist2 :$methtype $methname $arglist " if {!\[::xotcl::self isnextcall\]} { error \"Abstract method $methname $arglist2 called\" } else {::xotcl::next} " # balance " for emacs syntax highlighter } # support for XOTcl specific convenience routines Object instproc hasclass cl { if {![::nsf::is class $cl]} {return 0} if {[::nsf::directdispatch [self] ::nsf::methods::object::info::hasmixin $cl]} {return 1} ::nsf::directdispatch [self] ::nsf::methods::object::info::hastype $cl } Object instproc filtersearch {filter} { set handle [::nsf::directdispatch [::nsf::current object] \ ::nsf::methods::object::info::lookupfilter $filter] return [method_handle_to_xotcl $handle] } Object instproc procsearch {name} { set handle [::nsf::directdispatch [::nsf::current object] \ ::nsf::methods::object::info::lookupmethod $name] return [method_handle_to_xotcl $handle] } Class instproc allinstances {} { # TODO: mark it deprecated return [:info instances -closure] } # keep old object interface for XOTcl Object proc unsetExitHandler {} {::nsf::exithandler unset} Object proc setExitHandler {newbody} {::nsf::exithandler set $newbody} Object proc getExitHandler {} {::nsf::exithandler get} # reuse some definitions from next scripting ::nsf::method::alias ::xotcl::Object copy ::nsf::classes::nx::Object::copy ::nsf::method::alias ::xotcl::Object move ::nsf::classes::nx::Object::move #::nsf::method::alias ::xotcl::Object defaultmethod ::nsf::classes::nx::Object::defaultmethod #::nsf::method::alias ::xotcl::Class -per-object __unknown ::nx::Class::__unknown ::nsf::method::create ::xotcl::Class -per-object __unknown {name} {} ::nsf::object::unknown::add xotcl {::xotcl::Class __unknown} proc myproc {args} {linsert $args 0 [::uplevel ::nsf::self]} proc myvar {var} {[::uplevel ::nsf::self] requireNamespace; return [::uplevel ::nsf::self]::$var} # # create ::xotcl::MetaSlot for better compatibility with XOTcl 1 # ::nx::Class create ::xotcl::MetaSlot -superclass ::nx::MetaSlot { :property parameter :method init {} { if {[info exists :parameter]} {my ::nsf::classes::xotcl::Class::parameter ${:parameter}} next } :public forward instproc %self public method :public forward proc %self public object method # # As NX/XOTcl hybrids, all slot kinds would not inherit the # unknown behavior of ::xotcl::Class. Therefore, we provide it # explicitly to slots for backward compatibility ... # :public alias unknown ::nsf::classes::xotcl::Class::unknown } # # Create ::xotcl::Attribute for compatibility # ::xotcl::MetaSlot create ::xotcl::Attribute -superclass ::nx::VariableSlot { :public alias value=set ::nsf::var::set #:property defaultmethods {get set} :property {substdefault} :property -accessor public multivalued { # # The slot object is an nx object, therefore, we need the nx # "set" variant no matter what xotcl2 uses. # :public object method value=set {object property value} { set mClass [expr {$value ? "0..n" : "1..1"}] $object configure -incremental $value -multiplicity $mClass } :public object method value=get {object property} { return [$object eval [list :isMultivalued]] } } :protected method setterRedefinedOptions {} { if {[:info lookup method value=set] ne "::nsf::classes::xotcl::Attribute::value=set"} { # In case the "set" method was provided on the slot, ask nsf to call it directly return [list slot=[::nsf::self] slotset] } if {[:info lookup method value=get] ne "::nsf::classes::nx::VariableSlot::value=get"} { # In case the "get" method was provided on the slot, ask nsf to call it directly return [list slot=[::nsf::self]] } } :protected method defineIncrementalOperations {options_single options} { # # Just define these setter methods, when these are not defined # jet. We need the methods as well for e.g. private properties, # where the setting of the property is handled via slot. # if {[:info lookup method value=set] eq "::nsf::classes::xotcl::Attribute::value=set"} { set args [list obj var [:namedParameterSpec {} value $options]] :public object method value=set $args {::nsf::var::set $obj $var $value} } if {[:isMultivalued] && [:info lookup method value=add] eq "::nsf::classes::nx::VariableSlot::value=add"} { lappend options_single slot=[::nsf::self] set args [list obj prop [:namedParameterSpec {} value $options_single] {pos 0}] :public object method value=add $args {::nsf::next} } else { # TODO should we deactivate add/delete? } } :protected method needsForwarder {} { # # We just forward, when # * "set", "get" and "add" are still untouched, or # * or incremental is specified # if {[:info lookup method value=set] ne "::nsf::classes::xotcl::Attribute::value=set"} {return 1} if {[:info lookup method value=add] ne "::nsf::classes::nx::VariableSlot::value=add"} {return 1} if {[:info lookup method value=get] ne "::nsf::classes::nx::VariableSlot::value=get"} {return 1} if {[info exists :settername]} {return 1} if {!${:incremental}} {return 0} #if {![:isMultivalued]} {return 0} #puts stderr "--------------- [self] ismultivalued" return 1 } :public method createForwarder {name domain} { ::nsf::method::forward $domain \ -per-object=${:per-object} \ $name \ -prefix value= \ ${:manager} \ "%1 {get set}" %self \ ${:forwardername} } :public method __object_configureparameter {} { set slotObjects [nsf::directdispatch [self] ::nsf::methods::object::info::lookupslots -type ::nx::Slot] set parameterDefinitions [::nsf::parameter::specs -nonposargs $slotObjects] lappend parameterDefinitions args:alias,method=residualargs,args return $parameterDefinitions } :method init args { # # Via XOTcl calling convention, init gets the residual arguments # passed. Since nx does not allow this, we simply ignore the passed # arguments $args. # if {[info exists :default] && ![info exists :substdefault]} { set :substdefault 0b111 } nsf::next "" } # provide minimal compatibility :public alias proc ::nsf::classes::xotcl::Object::proc :public method exists {var} {::nsf::var::exists [self] $var} :public method istype {class} [::nx::Object info method body ::nsf::classes::xotcl::Object::istype] :public alias set -frame object ::set :public alias residualargs ::nsf::methods::object::residualargs :public alias instvar ::nsf::methods::object::instvar ::nsf::method::setter [self] name ::nsf::method::setter [self] domain ::nsf::method::setter [self] default } # # Provide a backward compatible version of ::xotcl::alias # ::nsf::proc ::xotcl::alias { obj:object methodName -per-object:switch -objscope:switch target } { ::nsf::method::alias \ $obj \ {*}[expr {${per-object} ? "-per-object" : ""}] \ $methodName \ {*}[expr {${objscope} ? "-frame object" : ""}] \ $target } Object create ::xotcl::config config proc load {obj file} { source $file foreach i [array names ::auto_index [list $obj *proc *]] { set type [lindex $i 1] set meth [lindex $i 2] if {[$obj info ${type}s $meth] == {}} { $obj $type $meth auto $::auto_index($i) } } } config proc mkindex {meta dir args} { set sp {[ ]+} set st {^[ ]*} set wd {([^ ;]+)} foreach creator $meta { ::lappend cp $st$creator${sp}create$sp$wd ::lappend ap $st$creator$sp$wd } foreach methodkind {proc instproc} { ::lappend mp $st$wd${sp}($methodkind)$sp$wd } foreach cl [concat ::xotcl::Class [::xotcl::Class info heritage]] { ::lappend meths {*}[$cl info instcommands] } set old [pwd] cd $dir ::append idx "# Tcl autoload index file, version 2.0\n" ::append idx "# xotcl additions generated with " ::append idx "\"::xotcl::config::mkindex [list $meta] [list $dir] $args\"\n" set oc 0 set mc 0 foreach file [glob -nocomplain -- {*}$args] { if {[catch {set f [open $file]} msg]} { catch {close $f} cd $old error $msg } while {[gets $f line] >= 0} { foreach c $cp { if {[regexp $c $line x obj]==1 && [string index $obj 0]!={$}} then { ::incr oc ::append idx "set auto_index($obj) " ::append idx "\"::xotcl::config::load $obj \$dir/$file\"\n" } } foreach a $ap { if {[regexp $a $line x obj]==1 && [string index $obj 0]!={$} && [lsearch -exact $meths $obj]==-1} { ::incr oc ::append idx "set auto_index($obj) " ::append idx "\"::xotcl::config::load $obj \$dir/$file\"\n" } } foreach m $mp { if {[regexp $m $line x obj ty pr]==1 && [string index $obj 0]!={$} && [string index $pr 0]!={$}} then { ::incr mc ::append idx "set \{auto_index($obj " ::append idx "$ty $pr)\} \"source \$dir/$file\"\n" } } } close $f } set t [open tclIndex a+] puts $t $idx nonewline close $t cd $old return "$oc objects, $mc methods" } # # if cutTheArg not 0, it cut from upvar argsList # Object instproc extractConfigureArg {al name {cutTheArg 0}} { set value "" ::upvar $al argList set largs [llength $argList] for {set i 0} {$i < $largs} {incr i} { if {[lindex $argList $i] == $name && $i + 1 < $largs} { set startIndex $i set endIndex [expr {$i + 1}] while {$endIndex < $largs && [string first - [lindex $argList $endIndex]] != 0} { lappend value [lindex $argList $endIndex] incr endIndex } } } if {[info exists startIndex] && $cutTheArg != 0} { set argList [lreplace $argList $startIndex [expr {$endIndex - 1}]] } return $value } Object create ::xotcl::rcs rcs proc date string { lreplace [lreplace $string 0 0] end end } rcs proc version string { lindex $string 2 } # # package support # # puts this for the time being into XOTcl # ::xotcl::Class instproc uses list { foreach package $list { ::xotcl::package import -into [::xotcl::self] $package puts stderr "*** using ${package}::* in [::xotcl::self]" } } ::nx::Class create ::xotcl::package -superclass ::nx::Class { :property provide :property {version 1.0} :property {autoexport {}} :property {export {}} :public object method create {name args} { set nq [namespace qualifiers $name] if {$nq ne "" && ![namespace exists $nq]} {Object create $nq} next } :public object method extend {name args} { :require $name $name configure {*}$args } :public object method contains script { if {[info exists :provide]} { package provide [set :provide] [set :version] } else { package provide [::xotcl::self] [set :version] } namespace eval [::xotcl::self] {namespace import ::xotcl::*} #namespace eval [::xotcl::self] $script #::nsf::directdispatch [::xotcl::self] -frame method ::apply [list {} $script [::xotcl::self]] ::apply [list {} $script [::xotcl::self]] foreach e [set :export] { set nq [namespace qualifiers $e] if {$nq ne ""} { namespace eval [::xotcl::self]::$nq [list namespace export [namespace tail $e]] } else { namespace eval [::xotcl::self] [list namespace export $e] } } foreach e [set :autoexport] { namespace eval :: [list namespace import [::xotcl::self]::$e] } } :public object method unknown args { #puts stderr "unknown: package $args" [set :packagecmd] {*}$args } :public object method verbose value { set :verbose $value } :public object method present args { if {$::tcl_version<8.3} { switch -exact -- [lindex $args 0] { -exact {set pkg [lindex $args 1]} default {set pkg [lindex $args 0]} } if {[info exists :loaded($pkg)]} { return ${:loaded}($pkg) } else { error "not found" } } else { [set :packagecmd] present {*}$args } } :public object method import {{-into ::} pkg} { :require $pkg namespace eval $into [subst -nocommands { #puts stderr "*** package import ${pkg}::* into [namespace current]" namespace import ${pkg}::* }] # import subclasses if any foreach e [$pkg export] { set nq [namespace qualifiers $e] if {$nq ne ""} { namespace eval $into$nq [list namespace import ${pkg}::$e] } } } :public object method require args { #puts "XOTCL package require $args, current=[namespace current]" set prevComponent ${:component} if {[catch {set v [package present {*}$args]} msg]} { #puts stderr "we have to load $msg" switch -exact -- [lindex $args 0] { -exact {set pkg [lindex $args 1]} default {set pkg [lindex $args 0]} } set :component $pkg lappend :uses($prevComponent) ${:component} set v [::uplevel \#1 [set :packagecmd] require $args] if {$v ne "" && ${:verbose}} { set path [lindex [::package ifneeded $pkg $v] 1] puts "... $pkg $v loaded from '$path'" set :loaded($pkg) $v ;# loaded stuff needed for Tcl 8.0 } } set :component $prevComponent return $v } set :component . set :verbose 0 set :packagecmd ::package } unset -nocomplain cmd unset ::nsf::bootstrap # Documentation stub object -> just ignore per default. # if xoDoc is loaded, documentation will be activated ::xotcl::Object create ::xotcl::@ ::xotcl::@ proc unknown args {} set ::xotcl::confdir ~/.xotcl set ::xotcl::logdir $::xotcl::confdir/log namespace import ::nsf::tmpdir # finally, export contents defined for XOTcl namespace export Object Class Attribute myproc myvar my self next @ # # Provide parametersyntax for methods, which do not have a spec # # Tcl commands set ::nsf::parameter::syntax(::append) "/varName/ ?/value/ ...?" set ::nsf::parameter::syntax(::array) "/option/ /arrayName/ ?/arg/ ...?" set ::nsf::parameter::syntax(::dict) "/option/ /dictName|dictValue/ ?/arg/ ...?" set ::nsf::parameter::syntax(::eval) "/arg/ ?/arg/ ...?" set ::nsf::parameter::syntax(::incr) "/varName/ ?/increment/?" set ::nsf::parameter::syntax(::lappend) "/varName/ ?/value/ ...?" set ::nsf::parameter::syntax(::set) "/varName/ ?/value/?" set ::nsf::parameter::syntax(::set) "/varName/ ?/value/?" set ::nsf::parameter::syntax(::subst) "?-nobackslashes? ?-nocommands? ?-novariables? /string/" set ::nsf::parameter::syntax(::trace) "/option/ ?/arg/ ...?" set ::nsf::parameter::syntax(::unset) "?-nocomplain? ?--? ?/name/ ...?" set ::nsf::parameter::syntax(::nsf::classes::xotcl::Object::invar) "?/expr/?" set ::nsf::parameter::syntax(::nsf::classes::xotcl::Class::instinvar) "?/expr/?" set ::nsf::parameter::syntax(::nsf::classes::xotcl::Object::parametercmd) "/name/" set ::nsf::parameter::syntax(::nsf::classes::xotcl::Class::instparametercmd) "/name/" set ::nsf::parameter::syntax(::nsf::classes::xotcl::Class::slots) "/cmds/" # slots set ::nsf::parameter::syntax(::nsf::classes::xotcl::Object::class) "?/class/?" set value "?/class .../?|?add /class/?|?delete /class/?" set ::nsf::parameter::syntax(::nsf::classes::xotcl::Object::mixin) $value set ::nsf::parameter::syntax(::nsf::classes::xotcl::Class::instmixin) $value set ::nsf::parameter::syntax(::nsf::classes::xotcl::Class::superclass) $value set value "?/filters/?|?add /filter/?|?delete /filter/?" set ::nsf::parameter::syntax(::nsf::classes::xotcl::Object::filter) $value set ::nsf::parameter::syntax(::nsf::classes::xotcl::Class::instfilter) $value unset value } if {[::nsf::configure debug] > 1} { foreach ns {::xotcl} { puts "vars of $ns: [info vars ${ns}::*]" puts stderr "$ns exports: [namespace eval $ns {lsort [namespace export]}]" } puts stderr "======= XOTcl $::xotcl::version$::xotcl::patchlevel loaded" } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/xotcl/library/lib/metadataAnalyzer.xotcl000644 000766 000024 00000030515 13442270117 024545 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package provide xotcl::metadataAnalyzer 2.0 package require XOTcl 2.0 namespace eval ::xotcl::metadataAnalyzer { namespace import ::xotcl::* @ @File { description { XOTcl file analyzer for @ metadata. E.g.\ used for doumentation with xoDoc (but in the static variant StaticMetadataAnalyzer which uses the dynamic variant in this file). <@p> Sample sample usage: <@pre> package require xotcl::metadataAnalyzer # instantiate metadata analyzer object MetadataAnalyzer @::m # make this object be known to @ and turn @ metadata processing on @ analyzerObj @::m @ onOff 1 # read in some metadata tags (in sample file) & execute the file source lib/testx.xotcl # turn @ metadata processing off again @ onOff 0 # print out all collected metadata puts [@::m print] } } @ Class MetadataToken { description { Each collected metadata element is stored in a token object. MetadataToken is superclass of token object classes. Each metadata token has two interesting parameters: <@p> "properties" contains list of all described metadata properties. E.g. can be printed with <@pre> foreach p [my set properties] { if {[my exists $p]} { append c " $p=[my set $p]\n" } } "name" contains the method, object, ... name of the metadata element. <@p> All metadata token are aggregated by @. Therefore, <@pre> foreach mdt [@ info children] { if {[$mdt istype MetadataToken]} {$mdt print} } prints all token. } } Class create MetadataToken -parameter { {name ""} {properties ""} } @ MetadataToken proc sortTokenList {l "token list"} { description {Sort a token list with names. Since names are autonames, this means order of appearance in the program.} } MetadataToken proc sortTokenList l { foreach t $l { set names([$t set name]) $t } set sortedNames [lsort [array names names]] set sortedList "" foreach n $sortedNames { lappend sortedList $names($n) } return $sortedList } MetadataToken instproc evaluateMetadata md { my instvar properties foreach {p v} $md { # only append property, if its not already there # otherwise just overwrite the value if {[lsearch $properties $p] == -1} { my lappend properties $p } my set $p $v } } @ MetadataToken instproc printProperties {} { description {Print metadata properties to stdout.} } MetadataToken instproc printProperties {} { set c "" foreach p [my set properties] { if {[my exists $p]} { append c " [my capitalize $p]=[my set $p]\n" } } return $c } MetadataToken instproc capitalize string { if {$::tcl_version >= 8.3} { string toupper $string 0 0 } else { return "[string toupper [string range $string 0 0]][string range $string 1 end]" } } @ MetadataToken abstract instproc print {} { description { Abstract method for printing a token to stdout. } } MetadataToken abstract instproc print {} @ Class FileToken -superclass MetadataToken { description { Token for @File Metadata. } } Class create FileToken -superclass MetadataToken FileToken instproc print {} { set c "FILE=[my set name]\n" append c [my printProperties] return $c } @ Class ConstraintToken -superclass MetadataToken { description { Token for @Constraint Metadata. } } Class create ConstraintToken -superclass MetadataToken ConstraintToken instproc print {} { set c "CONSTRAINT=[my set name]\n" append c [my printProperties] return $c } @ Class PackageToken -superclass MetadataToken { description { Token for Package metadata. Contains additional parameters: "version" of the package and "type"= either "require" or "provide". } } Class create PackageToken -superclass MetadataToken -parameter { {version ""} {type ""} } @ Class ObjToken -superclass MetadataToken { description { Token for Object metadata. Contains additional parameters: "procList" = list of all proc token and "cl"= class name. } } Class create ObjToken -superclass MetadataToken -parameter { {procList ""} cl } ObjToken instproc printProcs {} { set c " PROCS:\n" set pl [MetadataToken sortTokenList [my procList]] if {[my istype ClassToken]} { set pl [concat [MetadataToken sortTokenList [my instprocList]] $pl] } foreach p $pl { append c " [$p set name]\n" } return $c } ObjToken instproc print {} { set c "OBJECT=[my set name]\n" if {[my exists cl]} {append c " CLASS=[my set cl]\n"} if {[my exists heritage]} {append c " HERITAGE=[my set heritage]\n"} append c [my printProperties] set pl [MetadataToken sortTokenList [my procList]] if {[my istype ClassToken]} { set pl [concat [MetadataToken sortTokenList [my instprocList]] $pl] } foreach p $pl { append c [$p print] } return $c } @ Class ClassToken -superclass ObjToken { description { Token for Class metadata. Contains additional parameters: "instprocList" = list of all instproc token. } } Class create ClassToken -superclass ObjToken -parameter { {instprocList ""} } ClassToken instproc print {} { regsub "^OBJECT=" [next] "CLASS=" r return $r } @ Class MetaClassToken -superclass ClassToken { description { Token for Meta-Class metadata. } } Class create MetaClassToken -superclass ClassToken MetaClassToken instproc print {} { regsub "^CLASS=" [next] "META-CLASS=" r return $r } @ Class MethodToken -superclass MetadataToken { description { Token for Method metadata. Contains additional parameters: "arguments" of the method, "returnValue" of the method, "obj" name, "abstract" = 0 or 1 (whether its an abstract method or not). } } Class create MethodToken -superclass MetadataToken -parameter { arguments returnValue obj {abstract 0} } # Prints out method information MethodToken instproc print {} { set c " METHOD=[my set name], ARGUMENTS= " if {[my exists arguments]} { foreach {arg argDescription} [my set arguments] { # ignore argDescription and default values if {[llength $arg] > 1} {set arg [lindex $arg 0]} append c $arg " " } } append c "\n [my printProperties]" return $c } @ Class ProcToken -superclass MethodToken { description { Token for Proc metadata } } Class create ProcToken -superclass MethodToken ProcToken instproc print {} { regsub "^ METHOD=" [next] " PROC=" r return $r } @ Class InstprocToken -superclass MethodToken { description { Token for Instproc metadata. } } Class create InstprocToken -superclass MethodToken InstprocToken instproc print {} { regsub "^ METHOD=" [next] " INSTPROC=" r return $r } @ Class MetadataAnalyzer { description "Handler class for building a metadata runtime structure" } Class create MetadataAnalyzer -parameter { {objList ""} {packageList ""} {knownMetaclasses "Class"} {ns ""} fileToken {constraintList ""} } MetadataAnalyzer instproc init args { next } MetadataAnalyzer instproc handleMethod {obj type name {argList ""} {doc ""}} { #puts stderr "+++Method $type $name $argList $doc" set procClass ProcToken set objCl ObjToken if {$type eq "instproc"} { set procCl InstprocToken set objCl ClassToken } set t [$procClass create [my autoname ::xotcl::@::t]] set n [$t set name [string trimleft $name :]] $t set obj $obj set objFound 0 foreach o [my set objList] { if {[$o set name] == $obj} { set objFound 1 if {$type eq "instproc" && ![$o istype ClassToken]} { $o class ClassToken } break } } if {$objFound == 0} { set o [$objCl create [my autoname ::xotcl::@::t]] $o set name $obj my lappend objList $o } $o lappend ${type}List $t $t set arguments $argList $t evaluateMetadata $doc return $t } MetadataAnalyzer instproc handleObj {class name args} { my instvar knownMetaclasses objList extensions set objCl ObjToken if {[lsearch $class $knownMetaclasses] != -1} { set objCl ClassToken } # if an instproc/proc has created an entry for this obj/class # -> use it and overwrite it with new info if {[set idx [lsearch $name $objList]] != -1} { set t [lindex $objList $idx] $t class $objCl } else { set t [$objCl create [my autoname ::xotcl::@::t]] my lappend objList $t } $t set name $name set la [llength $args] # evaluate -superclass argument if {($la == 3 || $la == 2) && [lindex $args 0] eq "-superclass"} { set heritage [$t set heritage [lindex $args 1]] foreach h $heritage { if {[lsearch $h $knownMetaclasses] != -1} { # A new metaclass was defined lappend knownMetaclasses $name $t class MetaClassToken } } } # evaluate documentation set doc "" if {$la == 1} { set doc [lindex $args 0] } elseif {$la == 3} { set doc [lindex $args 2] } $t evaluateMetadata $doc $t set cl $class #puts stderr "+++Obj $name $args" } MetadataAnalyzer instproc handleFile doc { if {[my exists fileToken]} { [my set fileToken] evaluateMetadata $doc } } MetadataAnalyzer instproc handleConstraint {constraint name args} { set t [ConstraintToken create [my autoname ::xotcl::@::t]] my lappend constraintList $t $t set name $name set doc [lindex $args 0] $t evaluateMetadata $doc } MetadataAnalyzer instproc handlePackage args { #puts "$args" if {[llength $args] > 2} { set type [lindex $args 1] if {$type eq "provide" || $type eq "require"} { set t [PackageToken create [my autoname ::xotcl::@::t]] my lappend packageList $t $t set name [lindex $args 2] $t set type $type if {[llength $args] > 3} { $t set version [lindex $args 3] } } } } @ MetadataAnalyzer instproc print {} { description "Print all collected token information to stdout. This method is also an example how the tokens can be used." } MetadataAnalyzer instproc print {} { my instvar extensions packageList set c "" if {[llength $packageList] > 0} { append c "PACKAGES:" foreach t $packageList { if {[$t type] eq "provide"} { append c " Package provided: [$t name] [$t version]\n" } elseif {[$t type] eq "require"} { append c " Package required: [$t name] [$t version]\n" } } } if {[my exists fileToken]} { append c [[my set fileToken] print] } if {[my exists constraintToken]} { append c [[my set constraintToken] print] } if {[info exists extensions]} { # Add list of extensions. foreach extension $extensions { append c "\nExtensions: [$extension name], " \ "Description: [$extension description]" } } set objList [MetadataToken sortTokenList [my objList]] if {[llength $objList]>0} { foreach obj $objList {append c [$obj print]} } return $c } @ Class AnalyzerCmd { description {Class that overload the unknown mechanism of @ to provide metadata analysis.} } Class create AnalyzerCmd -parameter { {analyzerObj ""} {onOff 0} } AnalyzerCmd instproc unknown args { my instvar analyzerObj onOff # puts stderr "AnalyzerCmd: [self args]" if {!$onOff} {return [next]} if {[llength $args] > 1} { set abstract 0 if {[lindex $args 1] eq "abstract"} { if {[llength $args] > 2} { set p [lindex $args 2] if {$p eq "proc" || $p eq "instproc"} { set args [lreplace $args 1 1] set abstract 1 } } } switch [lindex $args 1] { proc - instproc { set r [eval $analyzerObj handleMethod $args] if {$abstract} {$r abstract 1} return $r } default { switch [lindex $args 0] { @File { return [$analyzerObj handleFile [lindex $args 1]] } @Constraint { return [eval $analyzerObj handleConstraint $args] } default { return [eval $analyzerObj handleObj $args] } } } } } puts stderr "Unknown @ metadata: '$args'" } @ AnalyzerCmd @ { description {Recreate @ with metadata analysis functionality.} } AnalyzerCmd create ::xotcl::@ namespace export \ MetadataToken FileToken ConstraintToken PackageToken ObjToken \ ClassToken MetaClassToken MethodToken ProcToken InstprocToken \ MetadataAnalyzer AnalyzerCmd } namespace import ::xotcl::metadataAnalyzer::* ./nsf2.4.0/library/xotcl/library/lib/staticMetadata.xotcl000644 000766 000024 00000004705 12501766547 024225 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package require XOTcl 2.0 package require xotcl::metadataAnalyzer package provide xotcl::staticMetadataAnalyzer 2.0 namespace eval ::xotcl::staticMetadataAnalyzer { namespace import ::xotcl::* @ @File { description { XOTcl file static analyzer for @ metadata. E.g. used for doumentation with xoDoc. I.e. allows for reading in a file and evaluating the metadata-related info only. } } @ Class StaticMetadataAnalyzer -superclass MetadataAnalyzer { description { Metadata analyzer class that allows for reading in files and evaluation of the metadata content in the file. } } Class create StaticMetadataAnalyzer -superclass MetadataAnalyzer \ -parameter {{namespace ::}} StaticMetadataAnalyzer instproc cmdsplit {cmd} { # from Jeffrey's tkcon set inc {} set cmds {} foreach cmd [split [string trimleft $cmd] \n] { if {{} ne $inc } { append inc \n$cmd } else { append inc [string trimleft $cmd] } if {[info complete $inc] && ![regexp {[^\\]\\$} $inc]} { if {[regexp "^\[^#\]" $inc]} {lappend cmds $inc} set inc {} } } if {[regexp "^\[^#\]" $inc]} {lappend cmds $inc} return $cmds } StaticMetadataAnalyzer instproc evaluateCommands {c} { my instvar namespace foreach command [my cmdsplit $c] { #puts stderr "$command===========================" if {[regexp "^ *:*@ " $command]} { #puts stderr "$command===========================" namespace eval $namespace $command } elseif {[regexp "^ *package " $command]} { #puts stderr "$command===========================" namespace eval $namespace [list [self] handlePackage $command] } elseif {[regexp "^ *namespace *eval *(\[^\{\]*) *\{(.*)\}\[^\}\]*$" $command _ namespace nsc]} { #puts stderr "$command===========================" namespace eval $namespace [list [self] evaluateCommands $nsc] } } } @ StaticMetadataAnalyzer instproc analyzeFile {name "File name"} { description "Analyze a file and build up a token structure for each metadata token in the file." } StaticMetadataAnalyzer instproc analyzeFile name { my set cmd "" set t [FileToken create [my autoname t]] $t set name $name my set fileToken $t set f [open $name r] set c [read $f] close $f ::@ onOff 1 my evaluateCommands $c ::@ onOff 0 } namespace export StaticMetadataAnalyzer } namespace import ::xotcl::staticMetadataAnalyzer::* ./nsf2.4.0/library/xotcl/library/lib/wafecompat.tcl000644 000766 000024 00000002602 12501766547 023046 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package provide xotcl::wafecompat 2.0 set WAFELIB /usr/lib/X11/wafe/ set MODULE_PATH "$WAFELIB $auto_path" set COMPONENT_PATH $WAFELIB/otcl-classes proc MOTIFPREFIX {} {return {}} proc requireModules modules { global MODULE_PATH foreach {cmd module} $modules { if {{} ne [info command $cmd] } continue if {[regexp {([A-Za-z1-9]+)Gen} $module _ n] || [regexp {lib([a-z]+)} $module _ n] || [regexp {^(.+)[.]so} $module _ n] } { set name [string toupper $n] } foreach path $MODULE_PATH { set f $path/tcllib/bin/$module if {[set found [file exists $f]]} { puts stderr "Loading module $name from $f" load $f $name break } } if {!$found} { error "Could not find module $module in {$MODULE_PATH}"} }} proc requireTclComponents {files} { global COMPONENT_PATH _componentLoaded foreach component $files { if {[info exists _componentLoaded($component)]} continue foreach path $COMPONENT_PATH { set f $path/$component if {[file exists $f]} { puts stderr "Loading source file $f" uplevel \#0 source $f set _componentLoaded($component) $f break } } if {![info exists _componentLoaded($component)]} { error "Could not find component $component in {$COMPONENT_PATH}" } }} proc addTimeOut {n cmd} { after $n $cmd } proc removeTimeOut {n} { after cancel $n } proc quit {} { exit } ./nsf2.4.0/library/xotcl/library/lib/Script.xotcl000644 000766 000024 00000001546 12501766547 022541 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package provide xotcl::script 2.0 package require XOTcl 2.0 namespace eval ::xotcl::script { namespace import ::xotcl::* @ @File {description { A small package to instantiate an object, that represents a script. } } @ Class Script { description { An object of type Script becomes automatically the command line arguments evaluated as "-" method calls during creation, e.g. <@pre> Script s -set r 5 and a call with cmd-line "-set v 6" of the script, results in an object s with two vars set: r to 5, and v to 6. } } Class Script Script proc create args { eval lappend args $::argv eval next $args } Script instproc unknown args { puts stderr "$::argv0: Unknown option -$args provided" } namespace export Script } namespace import ::xotcl::script::* ./nsf2.4.0/library/xotcl/library/lib/htmllib.xotcl000644 000766 000024 00000043335 13527046227 022725 0ustar00neumannstaff000000 000000 ## -*- Tcl -*- $ # # htmllib.xotcl # # Author: Antti Salonen, as@fishpool.fi # # Copyright: # # This software is copyrighted by Fishpool Creations Oy Ltd. 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. # package provide xotcl::htmllib 2.0 package require XOTcl 2.0 namespace eval ::xotcl::htmllib { namespace import ::xotcl::* @ @File { description { This package provides the class HtmlBuilder, which can be used to generate HTML documents, or a part of a document. } authors { Antti Salonen, as@fishpool.fi } date { $Date: 2006/09/27 08:12:40 $ } } # # the compressed parameter means that minimal HTML page are created # i.e. that space indentation is turned off # Class create HtmlBuilder -parameter { {compressed 0} } ## The constructor. ## ## The HtmlBuilder object has two instance variables. The document Tcl list ## contains the document as a list of strings. The document is stored as a list ## rather than a single string to allow further indentation of the whole ## document when necessary. ## The indentLevel variable is the level of indentation, which is generally ## increased for the contents of any HTML element that may contain block-level ## elements. Typical examples would be
    ,
  • , and so forth. HtmlBuilder instproc init {} { my instvar document indentLevel set document [list] set indentLevel 0 return } HtmlBuilder instproc clear {} { my instvar document indentLevel set document [list] set indentLevel 0 return } HtmlBuilder instproc getDocument {} { my instvar document return $document } HtmlBuilder instproc toString {} { my instvar document compressed set rvalue "" foreach line $document { if {$compressed == "0"} { append rvalue "$line\n" } else { ## only new line for closing tags at the beginning ## of a document element if {[string equal -length 2 ", for ## example, is not required by the HTML specification, using the closing method ## is necessary to have the document properly indented. # Add a string to the document within ... HtmlBuilder instproc addStringStrong {str} { my addString "$str" return } # Add a string to the document within ... HtmlBuilder instproc addStringEmphasized {str} { my addString "$str" return } # Add a comment to the document HtmlBuilder instproc addComment {str} { my addString "" return } HtmlBuilder instproc addLineBreak {} { my addString "
    " return } ## startDocument - Start an HTML document. Currently all documents are HTML 4.0 ## Transitional. HTML, BODY, HEAD and TITLE elements are added/started here. ## Optional arguments: ## -title documentTitle (empty if not given) ## -stylesheet externalStyleSheet ## -bgcolor backgroundColour (deprecated in HTML 4.0) HtmlBuilder instproc startDocument {args} { set title "" foreach {name value} $args { switch -- $name { -title { set title $value } -stylesheet { set stylesheet $value } -bgcolor { set bgcolor $value } } } my addString {} my addWhiteSpace my addString {} my addStringIncr {} my addString "$title" if {[info exists stylesheet]} { my addString "" } my addStringDecr {} my addWhiteSpace if {[info exists bgcolor]} { my addStringIncr "" } else { my addStringIncr {} } return } ## endDocument - end an HTML document HtmlBuilder instproc endDocument {} { my addStringDecr {} my addString {} return } ## startParagraph - start a P element ## Optional arguments: ## Common HTML arguments HtmlBuilder instproc startParagraph {args} { set attributes [HtmlBuilder parseArguments $args [list] [list]] my addStringIncr "" return } ## endParagraph - end a P element HtmlBuilder instproc endParagraph {} { my addStringDecr {

    } return } ## startAnchor - start an A element ## Optional arguments: ## -href URI ## -name cdata ## -target frameTarget ## Common HTML arguments HtmlBuilder instproc startAnchor {args} { set attributes [HtmlBuilder parseArguments $args \ [list "HREF" "NAME" "TARGET"] [list]] my addStringIncr "" return } ## endAnchor - end an A element HtmlBuilder instproc endAnchor {args} { my addStringDecr {} return } ## addAnchor - add an A element, using content as the visible link. ## Optional arguments: ## -href URI ## -name cdata ## -target frameTarget ## Common HTML arguments HtmlBuilder instproc addAnchor {content args} { eval my startAnchor $args my addString $content my endAnchor return } ## startUnorderedList - start a UL element ## Optional arguments: ## Common HTML arguments HtmlBuilder instproc startUnorderedList {args} { set attributes [HtmlBuilder parseArguments $args [list] [list]] my addStringIncr "" return } ## endUnorderedList - end a UL element HtmlBuilder instproc endUnorderedList {} { my addStringDecr {
} return } ## startListItem - start an LI element ## Optional arguments: ## Common HTML arguments HtmlBuilder instproc startListItem {args} { set attributes [HtmlBuilder parseArguments $args [list] [list]] my addStringIncr "" return } ## endListItem - end an LI element HtmlBuilder instproc endListItem {} { my addStringDecr {} return } ## add a simple list item HtmlBuilder instproc addListItem {content} { my startListItem my addString $content my endListItem } ## startTable - start a TABLE element. Note that if the -border argument isn't ## used, by default the table are created with borders (). ## Optional arguments: ## -border pixels ## -cellpadding length ## -cellspacing length ## -summary text ## -width length ## -bgcolor color spec ## Common HTML arguments HtmlBuilder instproc startTable {args} { set attributes [HtmlBuilder parseArguments $args \ [list "BORDER" "CELLPADDING" "CELLSPACING" "SUMMARY" \ "WIDTH" "BGCOLOR"] [list]] if {[lsearch $args "-border"] == -1} { append attributes " BORDER" } my addStringIncr "" return } ## endTable - end a TABLE element HtmlBuilder instproc endTable {} { my addStringDecr {
} return } ## startTableRow - start a TR element ## Optional arguments: ## Common HTML arguments HtmlBuilder instproc startTableRow {args} { set attributes [HtmlBuilder parseArguments $args [list "VALIGN"] [list]] my addStringIncr "" return } ## endTableRow - end a TR element HtmlBuilder instproc endTableRow {} { my addStringDecr {} return } ## startTableCell - start a TD element ## Optional arguments: ## -colspan number ## -rowspan number ## -align left|center|right|justify|char ## -valign top|middle|bottom|baseline ## -bgcolor ## -width ## Common HTML arguments HtmlBuilder instproc startTableCell {args} { set attributes [HtmlBuilder parseArguments $args \ [list "COLSPAN" "ROWSPAN" "ALIGN" "VALIGN" \ "BGCOLOR" "WIDTH"] [list]] my addStringIncr "" return } ## endTableCell - end a TD element HtmlBuilder instproc endTableCell {} { my addStringDecr {} return } # # add a simple table cell which just contains a string # HtmlBuilder instproc addTableCell {{string ""} args} { eval my startTableCell $args my addString $string my endTableCell } ## startTableHeaderCell - start a TH element ## Optional arguments: ## -colspan number ## -rowspan number ## -align left|center|right|justify|char ## -valign top|middle|bottom|baseline ## Common HTML arguments HtmlBuilder instproc startTableHeaderCell {args} { set attributes [HtmlBuilder parseArguments $args \ [list "COLSPAN" "ROWSPAN" "ALIGN" "VALIGN"] [list]] my addStringIncr "" return } ## endTableHeaderCell - end a TH element HtmlBuilder instproc endTableHeaderCell {} { my addStringDecr {} return } ## startForm - start a FORM element ## Required arguments: ## -action URI ## Optional arguments: ## -method get|post ## Common HTML arguments HtmlBuilder instproc startForm {args} { set attributes [HtmlBuilder parseArguments $args \ [list "ACTION" "METHOD" "ENCTYPE"] [list]] my addStringIncr "" return } ## endForm - end a FORM element HtmlBuilder instproc endForm {} { my addStringDecr {} return } ## addInput - add in INPUT element ## Required arguments: ## -type ## -name ## Optional arguments: ## -value ## -size ## -maxlength ## -checked ## Common HTML arguments HtmlBuilder instproc addInput {args} { set attributes [HtmlBuilder parseArguments $args \ [list "TYPE" "NAME" "VALUE" "SIZE" "MAXLENGTH"] \ [list "CHECKED"]] my addString "" return } ## addTextArea - start a TEXTAREA element ## First parameter: value - Default value of the text area ## Required arguments: ## -rows ## -cols ## Optional arguments: ## -name ## Common HTML Arguments HtmlBuilder instproc addTextArea {value args} { set attributes [HtmlBuilder parseArguments $args \ [list "ROWS" "COLS" "NAME"] [list]] my addString "$value" return } ## startOptionSelector - start a SELECT element ## Optional arguments: ## -name ## -size ## -multiple ## Common HTML arguments HtmlBuilder instproc startOptionSelector {args} { set attributes [HtmlBuilder parseArguments $args \ [list "NAME" "SIZE"] [list "MULTIPLE"]] my addStringIncr "" return } ## endOptionSelector - end a SELECT element HtmlBuilder instproc endOptionSelector {} { my addStringDecr "" return } ## startOption - start an OPTION element ## Optional arguments: ## -value ## -selected ## Common HTML arguments HtmlBuilder instproc startOption {args} { set attributes [HtmlBuilder parseArguments $args \ [list "VALUE"] [list "SELECTED"]] my addStringIncr "" return } ## endOption - end an OPTION element HtmlBuilder instproc endOption {} { my addStringDecr "" return } ## addImage - add an IMG element ## Required arguments: ## -src ## -alt ## -align (deprecated in HTML 4.0) ## Optional arguments: ## Common HTML arguments HtmlBuilder instproc addImage {args} { set attributes [HtmlBuilder parseArguments $args \ [list "SRC" "ALT" "ALIGN"] [list]] my addString "" return } ## startBlock - start a DIV element (a generic block-level container) ## Optional arguments: ## Common HTML attributes HtmlBuilder instproc startBlock {args} { set attributes [HtmlBuilder parseArguments $args [list] [list]] my addStringIncr "" return } ## endBlock - end a DIV element HtmlBuilder instproc endBlock {} { my addStringDecr "" return } ## addHorizontalRule - add an HR element ## Optional arguments: ## Common HTML arguments HtmlBuilder instproc addHorizontalRule {args} { set attributes [HtmlBuilder parseArguments $args [list] [list]] my addString "" return } namespace export HtmlBuilder } namespace import ::xotcl::htmllib::* ./nsf2.4.0/library/xotcl/library/lib/pkgIndex-package.add000644 000766 000024 00000000121 12501766547 024022 0ustar00neumannstaff000000 000000 package ifneeded xotcl::package 2.0 [list source [file join $dir package.xotcl]] ./nsf2.4.0/library/xotcl/library/lib/package.xotcl000644 000766 000024 00000010037 12501766547 022663 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package provide xotcl::package 2.0 package require XOTcl 2.0 package require xotcl::mixinStrategy # if pgk_mkIndex is running, there is a conflict with the # new command package provided here. We can detect when # pkg_mkIndex is running by checking for the namespace variable # ::tcl::file. if {![info exists ::tcl::file]} { rename package tcl_package } namespace eval ::xotcl::package { namespace import ::xotcl::* @ @File {description { Represent Tcl package loading command by an XOTcl object. Enables tracking, tracing, and verbose output of package loading } } @ Object package { description { Supports all Tcl package options plus present and verbose. } } @ package proc present {args "packageName or -exact packageName"} { description { Check whether a package is present or not. Similar to Tcl's package present, but works with Tcl < 8.3 } } @ package proc verbose {v "1 or 0"} { description { Toggle verbose output on/off. If on, package prints the locations from where packages are loaded to the screen. Default is off. } } set package_obj [Object create package] $package_obj set component . $package_obj set verbose 0 $package_obj proc unknown args { #puts stderr "unknown: package $args" namespace eval :: tcl_package $args } $package_obj proc verbose value { my set verbose $value } $package_obj proc present args { namespace eval :: tcl_package present $args } $package_obj proc require args { my instvar component verbose uses loaded set prevComponent $component if {[catch {set v [eval package present $args]} msg]} { #puts stderr "we have to load $msg" switch -exact -- [lindex $args 0] { -exact {set pkg [lindex $args 1]} default {set pkg [lindex $args 0]} } set component $pkg lappend uses($prevComponent) $component set v [namespace eval :: tcl_package require $args] if {$v ne "" && $verbose} { set path [lindex [tcl_package ifneeded $pkg $v] 1] puts "... $pkg $v loaded from '$path'" set loaded($pkg) $v ;# loaded stuff needed for Tcl 8.0 } } set component $prevComponent return $v } Object create package::tracker package::tracker set verbose 0 package::tracker proc storeEntry {table index} { my instvar verbose $table set ${table}($index) "[package set component] [info script]" if {$verbose} { puts "... $table $index loaded from [info script]" } } package::tracker proc dump {} { my instvar class object instproc proc if {[info exist class]} { parray class } if {[info exist object]} { parray object } if {[info exist instproc]} { parray instproc } if {[info exist proc]} { parray proc } } package::tracker proc start {} { ::Class add mixin [self]::M ::Object add mixin [self]::M } Class create package::tracker::M package::tracker::M instproc create {cls args} { set table [string tolower [string trimleft [self] :]] package::tracker storeEntry $table [lindex $args 0] next $cls add mixin [self class] } package::tracker::M instproc instproc args { package::tracker storeEntry instproc [self]->[lindex $args 0] next } package::tracker::M instproc proc args { package::tracker storeEntry proc [self]->[lindex $args 0] next } #package::tracker set verbose 1 #package::tracker start # #Class A #A instproc p args { # puts A #} #A proc pp args { # a call #} #Object o #o proc ppp args { # another call #} #puts stderr ==================================================== #package::tracker dump #puts stderr AUTO_PATH=$auto_path. namespace export package namespace eval package { namespace export tracker namespace eval tracker { namespace export M } } } namespace import ::xotcl::package::* namespace eval package { namespace import ::xotcl::package::package::* namespace eval tracker { namespace import ::xotcl::package::package::tracker::* } } ./nsf2.4.0/library/xotcl/library/lib/pkgIndex.tcl000644 000766 000024 00000002626 14276141440 022465 0ustar00neumannstaff000000 000000 package ifneeded xotcl::htmllib 2.0 "[list source [file join $dir htmllib.xotcl]]; [list package provide xotcl::htmllib 2.0]" package ifneeded xotcl::metadataAnalyzer 2.0 "[list source [file join $dir metadataAnalyzer.xotcl]]; [list package provide xotcl::metadataAnalyzer 2.0]" package ifneeded xotcl::mixinStrategy 2.0 "[list source [file join $dir mixinStrategy.xotcl]]; [list package provide xotcl::mixinStrategy 2.0]" package ifneeded xotcl::package 2.0 "[list source [file join $dir package.xotcl]]; [list package provide xotcl::package 2.0]" package ifneeded xotcl::script 2.0 "[list source [file join $dir Script.xotcl]]; [list package provide xotcl::script 2.0]" package ifneeded xotcl::staticMetadataAnalyzer 2.0 "[list source [file join $dir staticMetadata.xotcl]]; [list package provide xotcl::staticMetadataAnalyzer 2.0]" package ifneeded xotcl::trace 2.0 "[list source [file join $dir trace.xotcl]]; [list package provide xotcl::trace 2.0]" package ifneeded xotcl::upvar-compat 2.0 "[list source [file join $dir upvarcompat.xotcl]]; [list package provide xotcl::upvar-compat 2.0]" package ifneeded xotcl::wafecompat 2.0 "[list source [file join $dir wafecompat.tcl]]; [list package provide xotcl::wafecompat 2.0]" package ifneeded xotcl::xodoc 2.0 "[list source [file join $dir xodoc.xotcl]]; [list package provide xotcl::xodoc 2.0]" package ifneeded xotcl::package 2.0 [list source [file join $dir package.xotcl]] ./nsf2.4.0/library/xotcl/library/lib/upvarcompat.xotcl000644 000766 000024 00000003104 12501766547 023626 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package provide xotcl::upvar-compat 2.0 package require XOTcl 2.0 namespace eval ::xotcl::upvar-compat { namespace import ::xotcl::* @ @File {description { Provide a version of upvar and uplevel that provide backward compatibility such that these commands ignore inactive filter and mixin frames (upvar behaves the same whether or not a filter is installed). Newer scripts should use <@TT>upvar/uplevel [self callinglevel] var/command instead. } } } # Define upvar and uplevel; use the level, if given explizitely: # otherwise point to the callinglevel from XOTcl rename ::uplevel ::xotcl::tcl_uplevel proc ::uplevel {lvl args} { set cl [::xotcl::tcl_uplevel 1 ::xotcl::self callinglevel] if {[string match #* $cl]} { # we were called from XOTcl, use the XOTcl method set cmd [concat [list my uplevel $lvl] $args] } else { # no XOTcl in sight, use tcl variant set cmd [concat [list ::xotcl::tcl_uplevel $lvl] $args] } #puts stderr cmd=$cmd set code [catch [list ::xotcl::tcl_uplevel 1 $cmd] msg] return -code $code $msg } rename ::upvar ::xotcl::tcl_upvar proc ::upvar {lvl args} { set cl [::xotcl::tcl_uplevel 1 ::xotcl::self callinglevel] if {[string match #* $cl]} { # we were called from XOTcl, use the XOTcl method set cmd [concat [list my upvar $lvl] $args] #set code [catch {my uplevel $lvl $args} msg] } else { # no XOTcl in sight, use tcl variant set cmd [concat [list ::xotcl::tcl_upvar $lvl] $args] } set code [catch [list ::xotcl::tcl_uplevel 1 $cmd] msg] return -code $code $msg } ./nsf2.4.0/library/xotcl/library/lib/makeDoc.xotcl000644 000766 000024 00000005407 13527046227 022633 0ustar00neumannstaff000000 000000 # -*- Tcl -*- # # XOTcl style documentation tools # set auto_path [concat [file dirname [info script]] $auto_path] package require XOTcl 2.0 namespace import ::xotcl::* @ @File { description { Documentation tool for the XOTcl distribution.
Usage: 'makeDoc docdir filename ?filename ...?'
Called by Makefile. } } package require xotcl::package package verbose 1 package require xotcl::xodoc set fileList "" puts "XOTcl Documentation Tool" puts "------------------------" if {$argc > 1} { set DOCDIR [lindex $argv 0] puts "Documenting to directory $DOCDIR:" if {![file isdirectory $DOCDIR]} { file mkdir $DOCDIR } set files [lrange $argv 1 end] foreach file $files { puts "...$file" if {[catch {XODoc documentFileAsHTML $file $DOCDIR} fb]} { puts stderr "\terror processing $file:\n[string replace $::errorInfo 400 end ...]" } else { lappend fileList $file $fb } } } else { error "usage: xodoc docdir filename ?filename ...?" } set filesHtml "" set filesDir "" ## write index page foreach {f fb} $fileList { set dir . regexp {^(.*)/[^/]*$} $f _ dir if {$fb ne "langRef-xotcl"} { set tail ", " if {$dir != $filesDir} { append filesHtml "
  • Directory '$dir':
    " set filesDir $dir set tail "" } append filesHtml "$tail[file tail $f]" } } # # # XOTcl - Documentation # # #

    Language Reference - Index

    set content { The Extended Object Tcl (XOTcl) Documentation contains the following parts:

    XOTcl Language Documentation

    Package and Script Documentation

    This section of the documentation is under work...
      $filesHtml

    Tcl Online Information

    } set content [subst -nobackslashes -nocommands $content] set f [open $DOCDIR/index.html w] puts $f $content close $f puts "Documentation finished" ./nsf2.4.0/library/xotcl/library/lib/mixinStrategy.xotcl000644 000766 000024 00000005666 13261441733 024142 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package provide xotcl::mixinStrategy 2.0 package require XOTcl 2.0 namespace eval ::xotcl::mixinStrategy { namespace import ::xotcl::* @ @File { description { These methods provide support for managing "strategies", i.e. mixin-classes, where only one kind of a family of conformant mixins should be registered. <@p> Naming conventions for strategies: All strategies must follow the naming convention 'kind=implementation'. Examples are the persistency strategy 'eager' specified as 'persistent=eager' or the persistency strategy 'lazy' (specified as 'persistent=lazy') }} @ Object instproc mixinStrategy {strategy "Strategy to be added" } { description { This method adds or replaces a new strategy from the mixin list. Strategies are named following the convention mentioned above. } return "old strategy" } Object instproc mixinStrategy {strategy} { regexp {:?([^:=]+)=} $strategy _ kind set mixins "" set oldStrategy "" foreach mixin [my info mixin] { if {[string match *${kind}=* $mixin]} { lappend mixins $strategy set oldStrategy $mixin } else { lappend mixins $mixin } } if {$oldStrategy eq ""} { lappend mixins $strategy } my mixin $mixins return $oldStrategy } @ Object instproc mixinQueryStrategy {kind "strategy kind"} { description { This method searches the mixin list for a mixin of this kind (starting with $kind=) } return "returns the matching strategy" } Object instproc mixinQueryStrategy {kind} { set m [my info mixin] return [::lindex $m [::lsearch -glob $m $kind=*]] } @ Object instproc add {construct "(inst) 'filter' or 'mixin'" args "to be added"} { description "add the specified (inst) 'filters' or 'mixins'" return "empty" } Object instproc add {kind args} { if {$kind != {instfilter} && $kind != {instmixin} && $kind != {filter} && $kind != {mixin}} { error "Usage: [self proc] ..." } ::set classes [my info $kind] eval ::lappend classes $args my $kind $classes #puts stderr "$kind of [self] are now: ´[my info $kind]´" } @ Object instproc remove {construct "(inst) 'filter' or 'mixin'" args "to be removed"} { description "remove the specified (inst) 'filters' or 'mixins'" return "empty" } Object instproc remove {kind args} { if {$kind != {instfilter} && $kind != {instmixin} && $kind != {filter} && $kind != {mixin}} { error "Usage: [self proc] ..." } ::set classes [my info $kind] foreach c $args { ::set pos [::lsearch $classes $c] if {$pos == -1} { error "$kind ´$c´ could not be removed" } else { set $classes [::lreplace $classes $pos $pos] } } my $kind $classes # puts stderr "$kind of [self] are now: ´[my info $kind]´" } } ./nsf2.4.0/library/xotcl/library/lib/trace.xotcl000644 000766 000024 00000021515 13463555762 022374 0ustar00neumannstaff000000 000000 # -*- Tcl -*- $ package provide xotcl::trace 2.0 package require XOTcl 2.0 namespace eval ::xotcl::trace { namespace import ::xotcl::* @ @File {description { Various tracing tools for the XOTcl language. } } @ Object instproc traceFilter { args "arbitrary args" } { Description { Filter to trace every method call on an object or class hierarchy. Outputs a message befora and after each call of the traced object. } return "empty string" } @ Object Trace { Description { Write trace outputs and produce statistics. Variable traceStream defines where to write trace output (default: stderr). } } @ Trace proc puts {line "output line"} { Description { Define how traceFilter writes to the output stream. Default: write to trace stream. } } @ Trace proc openTraceFile {name "file name"} { Description { Redirect trace output to file. } } @ Trace proc closeTraceFile {name "file name"} { Description { Close trace file and redirect output to stderr. } } @ Object instproc lintFilter {} { Description {Experimental lint filter} } @ Object instproc statFilter {} { Description {Experimental statistics filter} } @ Object instproc showVars {args "list of variables"} { Description {Show the values of the specified variables (or of all variables) of an object on stderr.} } @ Object instproc showMsg {msg "optional output"} { Description {Show a message msg with the form "[self] $cls->$method $msg" on stderr.} } @ Object instproc showClass {} { Description {Show classes and mixins of the object}} @ Object instproc showStack {maxDepth "max stack depth, default=100"} { Description {Show callstack up to the specified calldepth.}} @ Object instproc showCall {} { Description {Show the current call with the form "[self] $cls->$method $args" on stderr.}} @ Object instproc showTimeStart {"?handle?" "Handle object name, optional"} {Description {start a timer}} @ Object instproc showTimeEnd {"?handle?" "Handle object name, optional"} {Description {end a timer and show result}} ########################################################################## proc showCall {} { Trace deprecated-function showCall} proc showVars {} { Trace deprecated-function showVars} proc showObj {o {printObjectName 1}} { Trace deprecated-function showObj} proc showStack {{m 100}} { Trace deprecated-function showStack} Object Trace Trace set traceStream stderr Trace proc openTraceFile name { my set traceStream [open $name w] } Trace proc closeTraceFile {} { close $Trace::traceStream my set traceStream stderr } Trace proc puts line { puts $Trace::traceStream $line } Trace proc add {type obj} { if {[my isclass $obj]} { $obj instfilter add ${type}Filter } else { $obj filter add ${type}Filter } } Trace proc delete {type obj} { if {[my isclass $obj]} { $obj instfilter delete ${type}Filter } else { $obj filter delete ${type}Filter } } Trace proc statReset {} { catch {my unset stat} } Trace proc statReportClass c { if {[my exists stat($c)]} { puts "\nClass $c: [my set stat($c)] references" foreach method [$c info instprocs] { set key $c->$method if {[info exists stat($key)]} { puts "\t$key: [my set stat($key)] references" } else { puts "\t$key: not used" } } } else { puts "\nClass $c: not used" } foreach subclass [lsort [$c info subclass]] { my [self proc] $subclass } } Trace proc statReport {} { my statReportClass Object } Trace proc statCount {key} { puts stderr "[self] [self proc] '$key'" if {[my exists stat($key)]} { my incr stat($key) } else { my set stat($key) 1 } puts stderr "[self] [self proc] '$key' => [my set stat($key)]" } Trace proc deprecated-function {name} { puts stderr "Function <$name> is deprecated. Use method with same name instead." } Object instproc traceFilter args { # don't trace the Trace object if {[self] eq "::xotcl::trace::Trace"} {return [next]} set method [self calledproc] if {$method eq [self proc]} {return [next]} set context "[self callingclass]->[self callingproc]" switch -- $method { proc - instproc {set dargs [list [lindex $args 0] [lindex $args 1] ...] } default {set dargs $args } } #my showStack Trace puts "CALL $context> [self]->$method $dargs (next=[self next])" set result [next] Trace puts "EXIT $context> [self]->$method ($result)" return $result } Object instproc lintFilter args { #puts stderr c=[self class],ic[my info class],p=[self calledproc] #puts stderr " =====================METHOD='[self calledproc]'" my instvar __reported switch -exact -- [self calledproc] { instvar { set ccls [self callingclass] set method [self callingproc] #puts stderr ccls=$ccls. if {$ccls eq ""} { ;## instvar in proc set bod [my info body $method] set context "proc [self]->$method" } else { ;## instvar in instproc set bod [$ccls info instbody $method] set context "instproc $ccls->$method" } foreach v $args { set vpattern "$v\[^a-zA-Z0-9\]" if {[regexp "\[\$\]$vpattern" $bod]} continue if {[regexp " *$vpattern" $bod]} continue #if {[regexp "info *exists *$vpattern" $bod]} continue #if {[regexp "append *$vpattern" $bod]} continue #if {[regexp "array.*$vpattern" $bod]} continue if {[info exists __reported($v,$context)]} continue set __reported($v,$context) 1 puts stderr "'$v' of 'instvar $args' is NOT used in\n\ $context ... {$bod}" } } } next } Object instproc statFilter args { # don't return statistics from the Trace object #puts stderr "self=[self]" if {[self] eq "::xotcl::trace::Trace"} {return [next]} set ccls [self callingclass] set cmet [self callingproc] set met [self calledproc] #::puts stderr "cls=$ccls->$cmet, [self]->$met" Trace statCount $ccls Trace statCount $ccls->$cmet next } ###################################################################### # show**** methods # Object instproc showVars args { set msg {} if {$args == {}} { foreach var [lsort [my info vars]] { if {[my array exists $var]} { append msg "\n\t$var: " #puts stderr "ARRAY $var" #puts stderr "ARRAY names <[[self]array names $var]>" foreach i [lsort [my array names $var]] { append msg $i=[my set ${var}($i)] ", " } } elseif {[my exists $var]} { append msg "\n\t$var: " [list [my set $var]] } else { append msg "\n\t$var: " UNKNOWN } } } else { foreach var $args { if {[my array exists $var]} { lappend msg $var: ARRAY } elseif {[my exists $var]} { lappend msg $var: [my set $var] } else { lappend msg $var: UNKNOWN } } } set method [self callingproc] set cls [self callingclass] puts stderr "[self] $cls->$method $msg" #puts stderr " MIXINS: [my info mixin]" } Object instproc showMsg msg { set method [self callingproc] set cls [self callingclass] puts stderr "[self] $cls->$method $msg" } Object instproc showClass {} { set method [self callingproc] set cls [self callingclass] puts stderr "[self] $cls->$method class [my info class]\ mixins {[my info mixin]}" } Object instproc showStack {{m 100}} { set max [info level] if {$m<$max} {set max $m} puts stderr "Call Stack (level: command)" for {set i 0} {$i < $max} {incr i} { if {[catch {set s [uplevel $i self]} msg]} { set s "" } puts stderr "[format %5d -$i]:\t$s [info level [expr {-$i}]]" } } Object instproc showCall {} { set method [self callingproc] set cls [self callingclass] set args [lreplace [info level -1] 0 0] puts stderr "[self] $cls->$method $args" } Object instproc showTimeStart {{handle __h}} { upvar [self callinglevel] $handle obj set obj [Object [self]::[my autoname __time]] $obj set clicks [clock clicks] return } Object instproc showTimeEnd {{handle __h}} { upvar [self callinglevel] $handle obj set method [self callingproc] set cls [self callingclass] set elapsed [expr {([clock clicks]-[$obj set clicks])/1000000.0}] puts stderr "[self] $cls->$method: elapsed [format %.2f $elapsed]secs" $obj destroy } ###################################################################### namespace export showCall showVars showObj showStack Trace } namespace import ::xotcl::trace::* ./nsf2.4.0/library/xotcl/library/lib/xodoc.xotcl000644 000766 000024 00000026523 13717240554 022406 0ustar00neumannstaff000000 000000 # -*- Tcl -*- package require XOTcl 2.0 package provide xotcl::xodoc 2.0 package require xotcl::staticMetadataAnalyzer package require xotcl::htmllib namespace eval ::xotcl::xodoc { namespace import ::xotcl::* @ @File { description { XOTcl documentation tool. Overloads the command @, which is used as a documentation token. } } @ Class MetadataTokenHTML { description {Instmixin to provide HTML printing. Such instmixins are registered for all token types. } } Class create MetadataTokenHTML @ MetadataTokenHTML abstract instproc printHTML {} { description {Print token to HTML document object} } MetadataTokenHTML abstract instproc printHTML {} @ MetadataTokenHTML instproc getDocPropertiesHTML {} { description { Returns list of properties as HTML. } } MetadataTokenHTML instproc getDocPropertiesHTML {htmlDoc} { foreach p [my set properties] { $htmlDoc startTableRow -valign top if {[my exists $p]} { $htmlDoc startTableCell -valign top $htmlDoc addString " [my capitalize $p]:" $htmlDoc endTableCell $htmlDoc startTableCell -valign top if {$p eq "errorCodes"} { # Build table cell with list of error codes. foreach {code desc} [my set $p] { set code [string map [list < <\; > >\;] $code] set desc [string map [list < <\; > >\;] $desc] $htmlDoc addString "$code: $desc\n

    " } } else { $htmlDoc addString [my set $p] } $htmlDoc endTableCell } $htmlDoc endTableRow } } MetadataTokenHTML instproc reflowHTML {left paragraph} { #set result "" #foreach line [split $paragraph \n] { # if {![regexp {^ *$} $line]} { # append result "$left$line
    \n" # } #} #return $result return $paragraph } MetadataToken instmixin [concat [MetadataToken info instmixin] MetadataTokenHTML] @ Class FileTokenHTML -superclass MetadataTokenHTML Class create FileTokenHTML -superclass MetadataTokenHTML FileTokenHTML instproc printHTML {htmlDoc} { $htmlDoc addLineBreak $htmlDoc addString " Filename: " $htmlDoc addAnchor [my set name] -href [my set name] $htmlDoc addLineBreak $htmlDoc addLineBreak $htmlDoc startTable -border 0 my getDocPropertiesHTML $htmlDoc $htmlDoc endTable } FileToken instmixin [concat [FileToken info instmixin] FileTokenHTML] @ Class ConstraintTokenHTML -superclass MetadataTokenHTML Class create ConstraintTokenHTML -superclass MetadataTokenHTML ConstraintTokenHTML instproc printHTML {htmlDoc} { $htmlDoc addAnchor "" -name [my set name] $htmlDoc addString "

    Constraint: [my set name]

    " $htmlDoc addLineBreak $htmlDoc startTable -border 0 my getDocPropertiesHTML $htmlDoc $htmlDoc endTable } ConstraintToken instmixin [concat [ConstraintToken info instmixin] ConstraintTokenHTML] @ Class ObjTokenHTML -superclass MetadataTokenHTML Class create ObjTokenHTML -superclass MetadataTokenHTML ObjTokenHTML instproc getProcsHTML {htmlDoc} { set c "" set pl [MetadataToken sortTokenList [my procList]] if {[my istype ClassToken]} { set pl [concat [MetadataToken sortTokenList [my instprocList]] $pl] } foreach p $pl { set pn [$p set name] set label($pn) "$pn" } foreach l [lsort [array names label]] { if {$c ne ""} {append c ", "} append c $label($l) } if {$c ne ""} {append c "."} $htmlDoc addString "$c" } ObjTokenHTML instproc printHTML {htmlDoc} { $htmlDoc addAnchor "" -name [my set name] if {[my istype MetaClassToken]} { set start "

    MetaClass:" } elseif {[my istype ClassToken]} { set start "

    Class:" } else { set start "

    Object:" } $htmlDoc addString "$start [my set name]

    " if {[my exists cl]} { $htmlDoc addString "Class: [my set cl]" $htmlDoc addLineBreak } if {[my exists heritage]} { $htmlDoc addString "Heritage: [my set heritage]" $htmlDoc addLineBreak } set head "" if {[my procList] ne ""} {set head " Procs "} if {[my istype ClassToken]} { if {[my instprocList] ne ""} {set head " Procs/Instprocs: "} } $htmlDoc addString $head my getProcsHTML $htmlDoc $htmlDoc startTable -border 0 my getDocPropertiesHTML $htmlDoc $htmlDoc endTable } ObjToken instmixin [concat [ObjToken info instmixin] ObjTokenHTML] @ Class MethodTokenHTML -superclass MetadataTokenHTML Class create MethodTokenHTML -superclass MetadataTokenHTML # Prints out method information as HTML. MethodTokenHTML instproc printHTML {htmlDoc} { #my showVars set argText "\n" HtmlBuilder create args set a "Arguments:" set anchor [my set obj]-[my set name] $htmlDoc addAnchor "" -name $anchor if {[my abstract]} {$htmlDoc addString "abstract"} $htmlDoc addString "[my set name] " args set indentLevel [$htmlDoc set indentLevel] if {[my exists arguments]} { #set argText "\n" foreach {arg argDescription} [my set arguments] { if {[llength $arg] > 1} { # A default value was given to the argument. $htmlDoc addString "?[lindex $arg 0]?" set at "?[lindex $arg 0]?:$argDescription Default: \"[lindex $arg 1]\"." } else { $htmlDoc addString "$arg" set at "$arg: $argDescription" } args startTableRow -valign top args startTableCell -valign top args addString $a set a "" args endTableCell args startTableCell -valign top args addString $at args endTableCell args endTableRow } } $htmlDoc startTable -border 0 $htmlDoc addString [args toString] args destroy my getDocPropertiesHTML $htmlDoc $htmlDoc endTable #$htmlDoc endListItem } MethodToken instmixin [concat [MethodToken info instmixin] MethodTokenHTML] @ Class XODoc { description "Handler class for building a documentation database" } Class create XODoc -superclass StaticMetadataAnalyzer @ XODoc proc documentFileAsHTML { file "filename of the xotcl file to be documented" docdir "directory to which the HTML file is written" } { description "Uses the xoDoc package to produce an HTML documentation of a specified file ***.xotcl. The file is written to ***.html in docdir" return "file basename without suffix" } XODoc proc documentFileAsHTML {file docdir} { set docdb [XODoc create [XODoc autoname docdb]] ::@ set analyzerObj $docdb $docdb analyzeFile $file set ext [file extension $file] if {$ext ne ""} {set ext -[string trimleft $ext .]} set docfilename [file rootname [file tail $file]]$ext $docdb writeFile ${docdir}/$docfilename.html $file $docdb destroy return $docfilename } XODoc instproc printPackages {htmlDoc} { my instvar packageList $htmlDoc addString "

    Package/File Information

    " if {[llength $packageList] > 0} { foreach t $packageList { if {[$t type] eq "provide"} { $htmlDoc addString " Package provided: [$t name] [$t version]" } elseif {[$t type] eq "require"} { $htmlDoc addString " Package required: [$t name] [$t version]" } $htmlDoc addLineBreak } } else { $htmlDoc addString " No package provided/required " $htmlDoc addLineBreak } } XODoc instproc printExtensions {htmlDoc} { my instvar extensions if {[info exists extensions]} { # Add list of extensions. foreach extension $extensions { $htmlDoc addLineBreak $htmlDoc addString "

    Document extension: [$extension name]" $htmlDoc addString "Description: [$extension description]" $htmlDoc addLineBreak } } } XODoc instproc printObjList {htmlDoc} { set objList [MetadataToken sortTokenList [my objList]] if {[llength $objList]>0} { $htmlDoc addLineBreak $htmlDoc addString "Defined Objects/Classes: " $htmlDoc startUnorderedList foreach obj $objList { set on [$obj set name] $htmlDoc startListItem $htmlDoc addAnchor "$on:" -href "#$on" $obj getProcsHTML $htmlDoc $htmlDoc addLineBreak $htmlDoc endListItem } $htmlDoc endUnorderedList } } XODoc instproc printFileToken {htmlDoc} { if {[my exists fileToken]} { [my set fileToken] printHTML $htmlDoc } else { $htmlDoc addString " No file information. \n" } $htmlDoc addLineBreak } XODoc instproc printConstraintsList {htmlDoc} { set constraintList [MetadataToken sortTokenList [my constraintList]] if {[llength $constraintList]>0} { $htmlDoc addLineBreak $htmlDoc addString "Defined Constraints: " $htmlDoc startUnorderedList foreach c $constraintList { set cn [$c set name] $htmlDoc startListItem $htmlDoc addAnchor "$cn:" -href "#$cn" $htmlDoc addLineBreak $htmlDoc endListItem } $htmlDoc endUnorderedList } } XODoc instproc printConstraints {htmlDoc} { foreach c [my set constraintList] { $htmlDoc addHorizontalRule $htmlDoc startParagraph $c printHTML $htmlDoc $htmlDoc endParagraph } $htmlDoc addLineBreak } XODoc instproc printProcsList {htmlDoc list string} { if {[llength $list] > 0} { $htmlDoc addString "

    $string

    " $htmlDoc startUnorderedList foreach s $list { $htmlDoc startListItem $s printHTML $htmlDoc $htmlDoc endListItem } $htmlDoc endUnorderedList } } XODoc instproc printObjs {htmlDoc} { set objList [MetadataToken sortTokenList [my objList]] foreach t $objList { $htmlDoc addHorizontalRule $htmlDoc startParagraph $t printHTML $htmlDoc if {[$t istype ClassToken]} { my printProcsList $htmlDoc [$t set instprocList] Instprocs } my printProcsList $htmlDoc [$t set procList] Procs $htmlDoc endParagraph } } XODoc instproc replaceFormatTags {fc} { regsub -all <@ $fc < fc regsub -all " htmlDoc addImage -src "./logo-100.jpg" -alt "$name" -align MIDDLE htmlDoc addStringDecr "$name" htmlDoc addHorizontalRule htmlDoc startParagraph my printPackages htmlDoc my printExtensions htmlDoc my printObjList htmlDoc my printConstraintsList htmlDoc my printFileToken htmlDoc my printObjs htmlDoc my printConstraints htmlDoc htmlDoc endParagraph htmlDoc addHorizontalRule htmlDoc startParagraph htmlDoc endParagraph htmlDoc addAnchor "Back to index page." -href "./index.html" htmlDoc addLineBreak htmlDoc addHorizontalRule htmlDoc startParagraph htmlDoc endParagraph htmlDoc endDocument set r [my replaceFormatTags [htmlDoc toString]] htmlDoc destroy return $r } @ XODoc instproc writeFile { filename "filename destination" name "name of the HTML document" } { description "Create HTML docuemntation from metadata token and write to file " } XODoc instproc writeFile {filename name} { set content [my printHTML $name] set f [open $filename w] puts $f $content close $f } namespace export \ MetadataTokenHTML FileTokenHTML ConstraintTokenHTML ObjTokenHTML \ MethodTokenHTML XODoc } namespace import ::xotcl::xodoc::* ./nsf2.4.0/library/xotcl/library/COPYRIGHT000644 000766 000024 00000005037 12501766547 020746 0ustar00neumannstaff000000 000000 /* * Next Scripting Framework * * Copyright (C) 1999-2014 Gustaf Neumann (a) (b) * Copyright (C) 1999-2007 Uwe Zdun (a) (b) * Copyright (C) 2007-2008 Martin Matuska (b) * Copyright (C) 2010-2014 Stefan Sobernig (b) * * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1090, Augasse 2-6 * Vienna, Austria * * This work is licensed under the MIT License * http://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * * This software is based upon MIT Object Tcl by David Wetherall and * Christopher J. Lindblad, that contains the following copyright * message: * * "Copyright 1993 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this * software and its documentation for any purpose is hereby granted * without fee, provided that the above copyright notice appear in * all copies and that both that copyright notice and this * permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity * pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about * the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty." */ ./nsf2.4.0/library/xotcl/xotclsh.in000644 000766 000024 00000001417 13030507001 017771 0ustar00neumannstaff000000 000000 #! /bin/sh # Lookup a Tcl interpreter \ INTERP="tclsh@TCL_VERSION@"; \ INTERPS="@NSF_COMPATIBLE_TCLSH@ @TCL_EXEC_PREFIX@/bin/$INTERP"; \ for interp in $INTERPS; \ do if [ -x $interp ]; then INTERP=$interp; break; \ fi; done; \ exec $INTERP "$0" ${1+"$@"} # -*- tcl -*- # # Tiny scripted replacement of a binary xotclsh. This script can be used # as interactive shell for testing or like a regular shell with the #! # markup in the first line of a script. It is designed to work with # multiple installed shells during development. For installed # versions, it should be sufficient to remove the first line. # package require XOTcl 2 package require nx::shell 1.1 namespace import -force ::xotcl::* set exitCode [nx::shell run $argc $argv] exit $exitCode ./nsf2.4.0/library/xotcl/xowish.in000644 000766 000024 00000001442 13030507001 017624 0ustar00neumannstaff000000 000000 #! /bin/sh # Lookup a Tcl interpreter \ INTERP="tclsh@TCL_VERSION@"; \ INTERPS="@NSF_COMPATIBLE_TCLSH@ @TCL_EXEC_PREFIX@/bin/$INTERP"; \ for interp in $INTERPS; \ do if [ -x $interp ]; then INTERP=$interp; break; \ fi; done; \ exec $INTERP "$0" ${1+"$@"} # -*- tcl -*- # # Tiny scripted replacement of a binary xowish. This # script can be used as interactive shell for testing or like a # regular shell with the #! markup in the first line of a script. It # is designed to work with multiple installed shells during # development. For installed versions, it should be sufficient to # remove the first line. # package require Tk package require XOTcl 2 package require nx::shell 1.1 namespace import -force ::xotcl::* set exitCode [nx::shell run $argc $argv] exit $exitCode ./nsf2.4.0/library/xotcl/doc/logo-100.jpg000644 000766 000024 00000003252 12501766547 020511 0ustar00neumannstaff000000 000000 JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*f"7!1A"Qqa#2b$BDrt#!1Qa2A ?nj\dH&m Ӆ|%w@!#QͳjjVR-6cn%W- acop,{ssmB1m'~z{վ[[cs^g?޴+ ]!D6GBHQ*BWiHazV>eH1T.p:zULml:mt fC's-b DTLr{yw!Ny(nZ`㸱𝵴ܫڥIe k[Ha3K4D8'6Z=E䜊[GXeFdm҄3,褃 Eci-M=v2Η*nX۝ǝ[PV*ǿ|Q#5i.-P̓ s no&"ĩK]\ͳ-nI^L>ۓ y!D{]s?xGkxՌGz t>f[ib+͈i 6Dt-OKBЗM2ܧ4ūk' _oD<Sѭ4L҃J6Duhv{?1rc-S& oË#T^|Ͽ*xOZAᩑ;0O~2Q5bR*GvrBa4¤ Ved:0Ul^q%k܏4:]x8o0}$ITMԒ_Ƨa٣,8#PUo hJl.]"F3ԯ>XҬ \&## 9h-Pz$c=,wd$H7 Y\dt}dA3|Kq.N5d3򤵞|g#} z=8ԸQDZ[>7-7 <ʷSo<Xb#YG^ƞgd1%>(}&%OJ̳;+%H(6l_cV_lIuwnTM\UQԚbI =Miqj8@҉CMYd%p+fiטU4mAd[˽oQ-'ՎJ|{▶+H7(8Qm63T;; 6a-F \Z\*Y[h##b/.o",+ I۵Ƥ$cPYID&xd\B3ɫU`4~u{"8]mܟu -q5'i]Ag91*0'./nsf2.4.0/library/xotcl/doc/tutorial.html000644 000766 000024 00000577510 13523544311 021303 0ustar00neumannstaff000000 000000 XOTcl - Tutorial

    XOTcl - Tutorial - Index

    Version: 1.6.4

    Introduction

     
    Language Overview

    XOTcl [Neumann and Zdun 2000a] is an extension to the object-oriented scripting language OTcl [Wetherall and Lindblad 1995] which itself extends Tcl [Ousterhout 1990] (Tool Command Language) with object-orientation. XOTcl is a value-added replacement for OTcl and does not require OTcl to compile.

    XOTcl runs in the tclsh and provides a few extension commands. These are offered in a Tcl namespace ::xotcl, and can be imported into the current namespace to reduce typing and improve readability. All Tcl commands remain available (and are also applicable on the extension constructs).

    A central property of Tcl is, that it uses strings solely for the representation of data. Internally it uses an dynamic type system with automatic conversion (which enables efficient type handling). For that reason all components (e.g. written in C) once integrated in Tcl automatically fit together and the components can be reused in unpredicted situations without change. The evolving component frameworks provide a high degree of code reuse, rapid application development, and ease of use. The application developer may concentrate on the application task solely, rather than investing efforts in fitting components together. Therefore, in certain applications scripting languages like Tcl are very useful for a fast and high-quality development of software (see [Ousterhout 1998] for more details).

    Tcl is equipped with appropriate functionalities for the easy gluing of components, like dynamic typing, dynamic extensibility, and read/write introspection. OTcl is an object-oriented extension to Tcl, which encourages a Tcl-like programming style and is composed of language constructs with properties similar to Tcl. It offers an object-orientation with encapsulation of data and operation without protection mechanisms and single and multiple inheritance. Furthermore it enables to change the relationships dynamically, offers read/write introspection, has a three level class system based on meta-classes and offers method chaining. These abilities are integrated in XOTcl with only slight changes to OTcl visible to the programmer.

    Extended Object Tcl aims at complexity and adaptability issues that may occur in context of large (object-oriented) software structures and in the context of component glueing. In particular we added the following support:

    • Filters as a means of abstractions over method invocations to implement large program structures, like design patterns.

    • Mixin Classes, as a means to give an object or a classes' instances access to several different supplemental classes, which may be changed dynamically.

    • Dynamic Object Aggregations, to provide dynamic aggregations through nested namespaces.

    • Nested Classes, to reduce the interference of independently developed program structures.

    • Assertions, to reduce the interface and the reliability problems caused by dynamic typing and, therefore, to ease the combination of components.

    • Forwarders, to delegate calls efficiently to other objects or classes.

    • Slots, to manage values of instance variables with a common interface.

    • Meta-data and Automatic Documentation, to enhance self-documentation of objects and classes.


      

    Figure 1: Language Extensions of XOTcl

     
    Introductory Overview Example: Stack

    To give you an impression of the language before we go into the details of the extended language constructs, we present in this section a simple, classical example, familiar to many from introductory programming courses: the Stack example. In the later section, we will present the soccer club example, which focuses more on the dynamic features of the Extended Object Tcl.

    In a first step, we define a class Stack. A new class is defined in XOTcl via the command Class create yourclass. The stack will have a constructor (in XOTcl, the method init) and the methods push and pop. Methods which are inherited to objects are defined via instproc. In the following example, all predefined commands (some from Tcl, some from XOTcl) are emphasized.

    #
    # Create a stack class 
    #
    Class create Stack 
    
    Stack instproc init {} {
      # Constructor
      my instvar things
      set things ""
    }
    
    Stack instproc push {thing} {
      my instvar things
      set things [concat [list $thing] $things]
      return $thing
    }
      
    Stack instproc pop {} {
      my instvar things
      set top [lindex $things 0]
      set things [lrange $things 1 end]
      return $top
    }
    

    The definition of the class Stack is typically saved in a file (say stack.xotcl) and can be used e.g. in an interactive Tcl shell (tclsh) as follows. The percent sign indicates the prompt of the Tcl shell, the reminder of the line is typed in, the result of the command is shown in the line below. Comments are lines starting with a hash symbol #.

    % package require XOTcl
    % namespace import xotcl::*
    % source stack.xotcl
      
    # Create Object s1 of class Stack
    % Stack create s1
    ::s1
    % s1 push a
    % s1 push b
    b
    % s1 push c
    c
    % s1 pop
    c
    % s1 pop
    b
    # Delete object s1
    s1 destroy
    

    In the session above, we load XOTcl into the current shell, import the names from the xotcl namespace and we load the file stack.xotcl. At this time, the class Stack is available in the scripting session. In the next step, we create an stack object named s1 and push into the stack the values a, b and c via separate push calls. Then we pop values from the stack and we destroy finally the stack s1.

     
    Object specific methods

    This definition is pretty similar to stack definitions in many other object oriented languages. The example below shows how to define purely object specific behavior. This way we can define an object stack without the need of a class Stack. Notice that the methods of the object stack are defined via proc and not via instproc in the example of the class Stack.

    #
    # Create an object named stack
    #
    Object create stack
    
    stack set things ""
    
    stack proc push {thing} {
      my instvar things
      set things [concat [list $thing] $things]
      return $thing
    }
      
    stack proc pop {} {
      my instvar things
      set top [lindex $things 0]
      set things [lrange $things 1 end]
      return $top
    }
    

    The object stack can be used in exactly the same way as s1 (the instance of class Stack) before.

     
    Refining the behavior of objects and classes

    So far, the definition of stacks were pretty minimal. Suppose, we want to define safe stacks, that check e.g. for stack underruns (more pop the push operations are issued). Checking safety can be done mostly independent from the implementation details of the stack (usage of internal data structures). With XOTcl, one can define stack-safety as a separate class using methods with the same names as the implementations before, and "mix" this behavior later into classes or objects. The implementation of Safety uses a counter to check for stack underruns.

    #
    # Create a safety class 
    #
    Class create Safety
    Safety instproc init {} {
      my set count 0
      next
    }
    Safety instproc push {thing} {
      my incr count
      next
    }
      
    Safety instproc pop {} {
      if {[my set count] == 0} then { error "Stack empty!" }
      my incr count -1
      next
    }
    

    When we load the classes Stack and Safety into the same script, we can define e.g. a certain stack s2 as a safe stack, while all other stacks might be still "unsafe". This can be achieved via the option -mixin during object creation.

    % Stack create s2 -mixin Safety
    ::s2
    % s2 push a
    % s2 pop
    a
    % s2 pop
    Stack empty!
    
    Note that the definition of Safety can be used not only for instances of the class Stack, but for arbitrary objects supporting the same interface. Therefore we could as well make the stack object stack (that we created before) safe at any time by adding the safety at arbitrary times with the method mixin, and we can remove the safety as well at any time.
    # Add Safety to the object stack
    % stack mixin Safety
    ...
    % stack push a
    ...
    # remove Safety
    % stack mixin {}
    
    We can as well use Safety to create a new class SafeStack. In this case, all instances of SafeStack have the safety property defined above.
    #
    # Create a safe stack class by using Stack and mixin 
    # Safety 
    #
    Class create SafeStack -superclass Stack -instmixin Safety
    
    SafeStack create s3
    

     
    Stack of integers

    The definition of Stack is generic and allows all kind of elements to be stacked. Suppose, we want to use the generic stack definition, but a certain stack (say, s4) should allow only stacking of integers. This behavior can be achieved by defining an object specific method for the stack s4 that checks the values to be pushed. In case the pushed value is ok, the push definition of Stack is called via next.

    # 
    # Create a stack with a object-specific method 
    # to check the type of entries 
    #
    # s4 is a stack of integer 
     
    Stack create s4
    s4 proc  push {value} {
       if  {![ string is integer $value]} {
         error "value $value is not an integer"
      }
       next
    }
    

     
    Class specific methods

    In extended object Tcl, classes are objects as well (objects with different properties). We will come to this later in more detail. However, we can define as well methods of classes, which are not inherited to the instances, by defining class-specific methods using proc. This happens exactly like defining objects specific methods as shown before. In the following example, we will define a class-specific method available_stacks that returns the number of the currently existing stack instances.

    Class create Stack
    # ...
    Stack proc available_stacks {} {
       return [llength [my info instances]]
    }
    
    Stack create s1
    Stack create s2
    
    puts [Stack available_stacks]
    

     
    Introductory Overview Example: Soccer Club

    In our second example, we will focus on an application example where one can benefit substantially from the dynamic language constructs of XOTcl, the soccer club example (the full code can be found in the xotcl/src/scripts/soccerClub.xotcl file. All the persons and characters in this example are fictitious, and any resemblance to actual persons, living or deceased, is coincidental.

    Before we start, we introduce an instrument for making the documentation of programs more easy. In order to document source code files, we can use the @ object, which is used generally to provide any kind of information, meta-data, and documentation on a running program. Here, we just give a file description. Then the makeDoc.xotcl tool can automatically document the program file later for us.

      @ @File {
        description {
          This is a simple introductory example for the language XOTcl. 
          It demonstrates the basic language constructs on the example of
          a soccer club.
        }
      }
    

    All things and entities in XOTcl are objects. A special kind of objects are classes. Classes define common properties for other objects. For a soccer club, we firstly require a common class for all kinds of members.

    Common to all members is that they have a name. Common properties defined across all instances of a class are called 'parameter' in XOTcl. In this example the instance variable name will be initialized by default with an empty string.

      Class ClubMember -parameter {{name ""}}
    

    A special club member is a Player. Derived classes can be build with inheritance (specified through superclass). Players may have a playerRole (defaults to NONE).

      Class Player -superclass ClubMember -parameter {{playerRole NONE}}
    

    Other club member types are trainers, player-trainers, and presidents:

      Class Trainer -superclass ClubMember
      Class President -superclass ClubMember
    

    The PlayerTrainer uses multiple inheritances by being both a player and a trainer:

      Class PlayerTrainer -superclass {Player Trainer}
    

    Now we define the SoccerTeam class:

      Class SoccerTeam -parameter {name location type}
    

    We may add a player. This is done by a method. Instance methods are in XOTcl defined with instproc. All club members are aggregated in the team (denoted by :: namespace syntax).

      SoccerTeam instproc newPlayer args {
        # we create a new player who is part of the soccer team
        # "eval" is needed to pass the provided arguments to the call of new
        eval Player new -childof [self] $args
      }
    

    A player can be transferred to another team. The player object does not change internally (e.g. the playerRole stays the same). Therefore we move it to the destination team.

      SoccerTeam instproc transferPlayer {playername destinationTeam} {
        # We use the aggregation introspection option children in order
        # to get all club members
        foreach player [my info children] {
          # But we only remove matching playernames of type "Player". We do
          # not want to remove another club member type who has the same
          # name.
          if {[$player istype Player] && [$player name] == $playername} {
            # We simply 'move' the player object to the destination team.
            # Again we use a unique autoname in the new scope
            $player move [set destinationTeam]::[$destinationTeam autoname player%02d]
          }
        }
      }
    

    Finally we define two convenience to print the members/players to the stdout with puts.

      SoccerTeam instproc printMembers {} {
        puts "Members of [my name]:"
        foreach m [my info children] {puts "  [$m name]"}
      }
      SoccerTeam instproc printPlayers {} {
        puts "Players of [my name]:"
        foreach m [my info children] {
          if {[$m istype Player]} {puts "  [$m name]"}
        }
      }
    

    Now let us build to example soccer team objects.

      SoccerTeam chelsea -name "Chelsea FC" -location "Chelsea"
      SoccerTeam bayernMunich -name "F.C. Bayern München" -location "Munich"
    

    With addPlayer we can create new aggregated player objects

    Let us start some years in the past, when "Franz Beckenbauer" was still a player.

      set fb [bayernMunich newPlayer -name "Franz Beckenbauer" \
        -playerRole PLAYER]
    

    playerRole may not take any value. It may either be NONE, PLAYER, or GOALY ... such rules may be given as assertions (here: an instinvar gives an invariant covering all instances of a class). In XOTcl the rules are syntactically identical to if statements:

      Player instinvar {
          {[my playerRole] == "NONE" ||  
           [my playerRole] == "PLAYER" || 
           [my playerRole] == "GOALY"}
      }
    

    If we break the invariant and turn assertions checking on, we should get an error message:

      $fb check all
      if {[catch {$fb set playerRole SINGER} errMsg]} {
        puts "CAUGHT EXCEPTION: playerRole has either to be NONE, PLAYER, or TRAINER"
        # turn assertion checking off again and reset to PLAYER
        $fb check {}
        $fb set playerRole PLAYER
      }
    

    But soccer players may play quite different, orthogonal roles. E.g. Franz Beckenbauer was also a singer (a remarkably bad one). However, we can not simply add such orthogonal, extrinsic extensions with multiple inheritance or delegation. Otherwise we would have either to build a lot of unnecessary helper classes, like PlayerSinger, PlayerTrainerSinger, etc., or we would have to build such helper objects. This either leads to an unwanted combinatorial explosion of class or object number

    Here we can use a per-object mixin, which is a language construct that expresses that a class is used as a role or as an extrinsic extension to an object.

    First we just define the Singer class.

      Class Singer
      Singer instproc sing text {
        puts "[my name] sings: $text, lala."
      }
    

    Now we register this class as a per-object mixin on the player object:

      $fb mixin Singer
    

    And now Franz Beckenbauer is able to sing:

      $fb sing "lali"
    

    But Franz Beckenbauer has already retired. When a player retires, we have an intrinsic change of the classification. He *is* not a player anymore. But still he has the same name, is club member, and is a singer (brrrrrr).

    Before we perform the class change, we extend the Player class to support it. I.e. the playerRole is not valid after class change anymore (we unset the instance variable).

      Player instproc class args {
        my unset playerRole
        next
      }
    

    Now we can re-class the player object to its new class (now Franz Beckenbauer is President of Bayern Munich.

      $fb class President
      # Check that the playerRole isn't there anymore.
      if {[catch {$fb set playerRole} errMsg]} {
        puts "CAUGHT EXCEPTION: The player role doesn't exist anymore \
             (as it should be after the class change)"
      }
    

    But still Franz Beckenbauer can entertain us with what he believes is singing:

      $fb sing "lali"
    

    Now we define some new players for Bayern Munich:

      bayernMunich newPlayer -name "Oliver Kahn" -playerRole GOALY
      bayernMunich newPlayer -name "Giovanne Elber" -playerRole PLAYER
    

    If we enlist the players of Munich Franz Beckenbauer is not enlisted anymore:

      bayernMunich printPlayers
    

    But as a president he still appears in the list of members:

      bayernMunich printMembers
    

    Now consider an orthonogal extension of a transfer list. Every transfer in the system should be notified. But since the transfer list is orthogonal to SoccerTeams we do not want to interfere with the existing implementation at all. Moreover, the targeted kind of extension has also to work on all subclasses of SoccerTeam. Firstly, we just create the extension as an ordinary class:

      Class TransferObserver
      TransferObserver instproc transferPlayer {pname destinationTeam} {
        puts "Player '$pname' is transferred to Team '[$destinationTeam name]'"
        next
      }
    

    Now we can apply the class as a per-class mixin, which functions exactly like a per-object mixin, but on all instances of a class and its subclasses. The next primitive ensures that the original method on SoccerTeam is called after notifying the transfer (with puts to stdout):

      SoccerTeam instmixin TransferObserver
    

    If we perform a transfer of one of the players, he is moved to the new club and the transfer is reported to the stdout:

      bayernMunich transferPlayer "Giovanne Elber" chelsea
    

    Finally we verify the transfer by printing the players:

      chelsea printPlayers
      bayernMunich printPlayers
    



    Object and Class System

    In XOTcl every object is associated with a class over the class relationship. Classes are special objects with the purpose of managing other objects. ``Managing'' means that a class controls the creation and destruction of its instances and that it contains a repository of methods (``instprocs'') accessible for the instances. Object-specific methods are called ``procs'', instance methods are called ``instprocs''.

    The instance methods common to all objects are defined in the root class Object (predefined or user-defined). Since a class is a special (managing) kind of object it is managed itself by a special class called ``meta-class'' (which manages itself). Meta-Classes are used to define classes and to provides methods for these. Most classes are defined by the predefined meta-class Class. One interesting aspect of meta-classes is that by providing a constructor pre-configured classes can be derived. Meta-classes can be used to instantiate large program structures, like some design patterns (see [Neumann and Zdun 1999a] for more details), where the meta-class may holds the generic parts of the structures. Since a meta-class is an entity of the program, it is possible to collect these entities in pattern libraries for later reuse easily (more details about meta-classes are given in a later section).

    XOTcl supports single and multiple inheritance. Classes are ordered by the relationship superclass in a directed acyclic graph. The root of the class hierarchy is the class Object. A single object can be instantiated directly from this class. An inherent problem of multiple inheritance is the problem of name resolution, when for example two super-classes contain an instance method with the same name. XOTcl provides an intuitive and unambiguous approach for name resolution by defining the precedence order along a linear ``next-path'' incorporating the class and mixin hierarchies, which is modeled after CLOS. A method can invoke explicitly the shadowed methods by the predefined command next. When this command is executed a shadowed method is ``mixed into'' the execution of the current method. Method chaining without explicit naming of the targeted method is very important for languages supporting a dynamic class system, because one cannot always predict which classes are currently participating in the inheritance hierarchy at design time (often necessary in inheritance models, like C++).

    An important feature of all XOTcl objects is the read/write introspection. The reading introspection abilities of XOTcl are packed compactly into the info instance method which is available for objects and classes. All obtained information can be changed at run-time dynamically with immediate effect. Unlike languages with a static class concept, XOTcl supports dynamic class/superclass relationships. At any time the class graph may be changed entirely using the superclass method, or an object may change its class through the class method. This feature can be used for an implementation of a life-cycle or other intrinsic changes of object properties (in contrast to extrinsic properties e.g. modeled through roles and implemented through per-object and per-class mixins [Neumann and Zdun 1999c] ) . These changes can be achieved without losing the object's identity, its inner state, and its per-object behavior (procs and per-object mixins).

      

    Figure 2: Object and Class System

    Basic Functionalities

     
    Objects

    Initially XOTcl offers two new commands: Object and Class. They represent hooks to the features of the language. This section discusses both of them in detail and shows how they function in the context of XOTcl. Note that even if most of this is compatible to OTcl, a few changes occur. For this reason, this section is no introduction to plain OTcl. The Object command provides access to the Object class, which holds the common features of all objects, and allows us to define new objects. Objects are always instances of classes, therefore, objects defined with the Object command are (initially) instances of the Object class. But since they have no user-defined type, they may be referred to as singular objects. As all other objects they may be specialized by object-operations and -data.

    The object command has the following syntax:

      Object objName ?args?
    

    A command of this form is a short-cut for a message to the create instance method (forwarded automatically by the unknown mechanism, which is invoked every time the message dispatch system discovers an unknown message):

      Object create objName ?args?
    

    It creates a new object of type Object with the name objName (in fact it invokes a create call on the Object class). objName becomes a new command, which allows us to access the created object. Similar to the Object command it may be used like a normal Tcl-command (using sub-commands to access the object's methods). Therefore, this form of access is called object-command approach. A simple example is an object which holds the information of a kitchen. It is created by:

      Object kitchen
    

    An object creation calls the constructor init of the object's class. The destruction of an object is handled by the destroy instance method. The general syntax of destroy is:

      objName destroy
    

    E.g. the kitchen object is destroyed by:

      kitchen destroy
    

    To invoke a user-defined destruction process, it is possible to overload this instance method in every class derived from object.

    Note that the destruction of an object is performed by the method destroy of Object (since every object is an instance of Object, every object can call destroy). When an application class overloads destroy, this method should contain a next in order to reach the base class and to actually destroy the object.

    Data on Objects

    The Object class provides a range of operations to manage objects, including those to manipulate data-structures on the objects. They are similar to the same-named Tcl-commands:

      objName set varname ?value?
      objName unset v1 ?v2 ... vn?
    

    The set instance method with given value option allows us to manipulate an object-variable's value or to create a new one, if the variable varname does not exist on the object so far. Without value option the set operation queries the variable and returns it's value, if the variable exists, otherwise it produces an error message. The unset operation deletes one or optionally a set of variables from an object. For example the kitchen object can store information on the color of the wall-paper by:

      kitchen set wallPaperColor white
    

    Similar to Tcl-variables the object variables are dynamical; they may be set at run-time when they are needed and unset when they become obsolete. E.g. the persons in the kitchen may be stored in an array. If there are no persons in the kitchen the array is deleted:

      # Peter enters the kitchen to cook
      kitchen set persons(cook) Peter
      ...
      # Marion enters the kitchen to take one of the seats
      kitchen set persons(seat1) Marion 
      ...
      # Both Peter and Marion leave the kitchen
      # the array is deleted by unset
      kitchen unset persons
    

    Since XOTcl variables are internally realized through Tcl-variables they may be treated like all Tcl-variables. For that reason they have all Tcl-variable abilities, including the possibility to handle them as lists or arrays (as seen in the last example). The array command of Tcl is mapped to an XOTcl-command directly. An object-oriented call to an object of the form

      objName array option arrayName args
    

    forwards its arguments to an array Tcl-command for the object´s instance variable arrayName. It could be used like the same-named Tcl-command, e.g. the command

      kitchen array names persons
    

    returns all indexes currently stored in the persons array.

    Similarly Tcl´s incr command is mapped to the object system. A call with the syntax:

      objName incr varName ?value?
    

    increments varName with the given value (or without given value with 1).

    Methods for Objects

    Methods in XOTcl resemble Tcl-procedures. On objects one can define object-specific methods, called procs. Instance methods which are defined on classes are called instprocs. A new proc is defined using the proc instance method of the class Object:

      objName proc name args body
    

    The arguments of the proc instance method specify the name, the arguments as a Tcl-list, and the body of the new proc. All of them must be given, only one of args and body may be empty. An example proc would be a method to let persons enter the kitchen:

      kitchen proc enter {name} {
        [self] set persons($name) [clock seconds]
      }
    

    Here the predefined self command is used in one of three possible ways, which allow us to access useful information when working with XOTcl-methods, these are in particular:

    • self: returns the name of the object, which is currently in execution. This command is similar to this in C++. It is automatically generated on each object. If it is called from outside of an XOTcl method, it produces the error message "Can't find self".

    • self class: the self command with the argument class returns the name of the class, which holds the currently executing instproc. Note that this may be different to the class of the current object. If it is called from a proc it returns an empty string.

    • self proc: the self command with the argument proc returns the name of the currently executing method (proc or instproc).

    The method enter can be written in XOTcl as well with less syntactic overhead by using the predefined primitive my instead of [self]:

      kitchen proc enter {name} {
        my set persons($name) [clock seconds]
      }
    

    Note that there is a difference to the realization of these object information to OTcl. XOTcl uses commands in order to make XOTcl-methods compatible to Tcl-procedures and accessible via namespace-paths. OTcl uses the three variables self, class and proc, which are filled automatically with proper values by the interpreter each time a method is called. To gain backwards compatibility XOTcl can be compiled with -DAUTOVARS to provide these variables additionally. By default this option is turned off.

    Each XOTcl-method has its own scope for definition of local variables for the executing method. In most cases when a method uses object-variables, it is likely that the programmer wants to make one or more of these variables part of the method's scope. Then the Tcl-command for variable handling, like set, lindex, array, ... work also on these variables. The instvar instance method links a variable to the scope of an executing method. It has the syntax:

      objName instvar v1 ?v2 ... vn?
    

    It makes the variables v1 ... vn, which must be variables of the object, part of the current method's scope. A special syntax is:

      objName instvar {varName aliasName} ...
    

    for one of the variables. This gives the variable with the name varName the alias aliasName. This way the variables can be linked to the methods scope, even if a variable with that name already exists in the scope. Now the enter method can be adapted slightly and a leave method can be added, which uses Tcl's info command to check whether the named person is in the object's persons array. To demonstrate the alias-syntax this is done with the persons array and the alias p.

      kitchen proc enter {name} {
        my instvar persons
        set persons($name) [clock seconds]
      }
    
      kitchen proc leave {name} {
        my instvar {persons p}
        if {[info exists p($name)]} {
          puts "$name leaves after [expr {[clock seconds]-$p($name)}] seconds" 
          unset p($name) 
        } else {
          puts "$name is not in the room"
        }
      }
    
    A method defined via proc can be deleted by proc using an empty argument list and an empty body. The following example deletes the method enter:
      Room proc enter {} {}
    

    Information about Objects

    XOTcl offers reading and writing introspection. The reading introspection abilities are packed compactly into the info instance method which is available for objects and classes (there are special info options for object aggregations, nested classes, mixins, filters, meta-data and assertions, which are explained separately in the following sections).

    Options for the info method on objects

    objName info args methodName

    Returns the arguments of the specified proc (object specific method).

    objName info body methodName

    Returns the body of the specified proc.

    objName info class ?className?

    Returns the name of the class of the current object, if className was not specified. Otherwise it returns 1 if className matches the object's class and 0 if not.

    objName info commands ?pattern?

    Returns all commands defined on the object if pattern was not specified. Otherwise it returns all commands that match the pattern.

    objName info default methodName arg var

    Returns 1 if the argument arg of the specified proc has a default value, otherwise 0. If the default value exists it is stored in var.

    objName info precedence ?pattern?

    Returns all classes in the precedence order from which the specified object inherits methods. The returned list of classes contains the mixin and instmixin classes as well as the classes of the superclass chain in linearized order (i.e., duplicate classes are removed). If the pattern is specified, only matching classes are returned.

    objName info vars ?pattern?

    Returns all variables defined on the object if pattern was not specified, otherwise it returns all variables that match the pattern.


    For example on the kitchen object

      kitchen info procs
    

    returns enter and leave as a Tcl-list since these are the procs defined on the object.

    Classes

    Creating Classes and deriving Instances

    There are different ways to create a class in XOTcl. They have in common that they derive the new class from a meta-class. Initially the Class command provides access to the meta-class Class, which holds the features common to all classes. It also allows one to derive new meta-classes. The common way to create a new class is:

      Class className ?args?
    

    Similar to the object short form, this is a short form of a call to the create instance method of the meta-class Class, which is also executed by the standard unknown mechanism. This mechanism is always triggered when XOTcl does not know a method called on an object. Supposed that there is no method with the name className, defined on the class-object of Class, XOTcl looks up the method unknown (which is found on the Class Object) and executes it. The standard unknown-mechanism of XOTcl calls create with all arguments stepping one step to the right; in the general case:

      Class create className ?args?
    

    This may also be called directly. Besides the indirection when using unknown, in most cases there is no difference in the action performed: Firstly the memory is allocated, using the alloc instance method; as the next step the constructor init is called on the creating object, which is in this case the class-object of the meta-class Class. In seldom cases the programmer may want to suppress the init call. To do so the alloc instance method may also be called directly:

      Class alloc className ?args?
    

    As seen in the preceding section objects are created in the same way. The difference was, that the command Object, which accesses a class, instead of the command Class, which accesses a meta-class, was used. The user-defined classes may also be used in the same way to create new objects:

      className objName ?args?
    

    Resembling the creation of classes this creates an object objName of type className using the unknown mechanism. That means the create instance method of the class is called. If there is no other instance method defined on the class-path so far (which would mean, an user defined creation process is invoked), the create instance method of the class Object is invoked. This method is similar to the create method of the meta-class Class. It firstly calls the alloc instance method on its (of the Class class) which allocates memory for the object, and makes it an instance of it's class. Afterwards a call to the constructor init is invoked.

    Now we can specify the object for the kitchen by the class to which it belongs. In this case a kitchen is an instance of a room.

      Class Room
      Room kitchen
    

    A set call on a class creates an instance variable on the class-object. This variable is unique for all instances, therefore, it may be referred to as a class variable.

    Methods Defined in Classes

    Methods which are defined in classes and which are provided to the instances of these classes are called "instprocs". The syntax for defining an instproc is:

      className instproc procname args body
    

    It is similar to the definition of procs on objects, but uses the keyword instproc to distinguish between the methods defined on the class-object and those defined on the class. Since all rooms (in the modeled world) have ceilings, we may want to define a simple convenience instproc, which is able to set the color:

      Room instproc setCeilingColor color {
        my set ceilingColor $color
      }
    

    A special instproc, the constructor init, was mentioned already. Now we are able to define such an instproc. Defined on a class it is responsible for all initialization tasks, which needed to be performed, when constructing a new instance object of the class. The constructor of the Room can initialize a variable for the color, in which the ceiling is painted, to white as default, since this is the color of ceilings without painting.

      Room instproc init args {
        my setCeilingColor white
        next
      }
    

    After this definition, all instances derived from the Room class have an instance variable ceilingColor with the value white. The args argument used here is a special argument in Tcl which allows us to use a list of arguments which may change its length from call to call.

    An instproc can be deleted by the method instproc as well. If instproc is called with an empty argument list and an empty body, the specified method is deleted, as the following example shows:

      Room instproc setCeilingColor {} {}
    

    Information about Classes

    Resembling to objects, information on classes may be gained through the info instance method of the meta-class Class. Note that this instance method does not only support the class info options, but also the class-object info options, since the accessing command refers to the class-object, which itself is an object and, therefore, offers its information. The following table summarizes the additional info options available on classes.

    Options for the info method on classes

    className info heritage ?pattern?

    Returns a list of all classes in the precedence order of the class hierarchy matching pattern or a list of all classes, if pattern was not specified.

    className info instances ?pattern?

    Returns a list of the instances of the class matching pattern or of all instances, if pattern was not specified.

    className info instargs methodName

    Returns the arguments of the specified instproc (method provided to objects).

    className info instbody methodName

    Returns the body of the specified instproc.

    className info instcommands ?pattern?

    Returns all commands defined on the class, if pattern was not specified, otherwise it returns all commands provided to objects that match the pattern.

    className info instdefault methodName arg var

    Returns 1 if the argument arg of the specified instproc has a default value, otherwise 0. If the default value exists it is stored in var.

    className info subclass ?className2?

    Returns a list of all subclasses of the class, if className2 was not specified, otherwise it returns 1 if className2 is a subclass and 0 if not.

    className info superclass ?className2?

    Returns a list of all super-classes of the class, if className2 was not specified, otherwise it returns 1 if className2 is a superclass and 0 if not.

    The full list of info options is provided in the language reference.

    Inheritance

    Besides encapsulation of operations and state in objects, a second central ability of object-orientation is inheritance. XOTcl supports single and multiple inheritance with a directed acyclic class graph. Automatically each new class created by the instance methods create and alloc of Class inherits from Object. Therefore, it is ensured that all instances of the new class have access to the common features of objects stored in the class Object.

    To specify further inheritance relationships the instance methods superclass of Class is used:

      className -superclass classList
    

    E.g. in the example a kitchen may be seen as a special room:

      Class Room
      Class Kitchen -superclass Room
    

    Now all instances of Kitchen are able to access the operations stored in the Room and in the Kitchen class. Note the transition the kitchen was going through: firstly it was a singular object, then it was an object with a user-defined class, and now it is a class. This is possible (and not senseless) because of the per-object specialization ability and the dual shape of a class, which is at the same time object and class. Both lead to a seamless connection of the run-time properties (the object features) and their descriptive properties (the class features). It is possible to avoid the strict distinction between them, known from static typed languages, like C++, Java, etc.

    Moreover, since the syntaxes of constructs expressing the same concern are nearly identical, we can re-factor a solution with very few changes to the alternative. We will see similar "ease of refactoring" throughout the XOTcl language. E.g., we can also easily re-factor the class hierarchies or exchange class hierarchies against mixin solutions with only slight changes in the code.

    Besides single inheritance, as seen, XOTcl provides also multiple inheritance. This is syntactically solved by giving the superclass instance method a list of classes instead of a single class as argument.

      Class Room
      Class 4WallsRoom -superclass Room
      Class CookingPlace
      Class Kitchen -superclass {4WallsRoom CookingPlace}
    

    Now the kitchen class is specialized a bit more. It is a special room which has four walls and it is a cooking place. Multiple inheritance, as seen here, is as simple to apply as single inheritance.

    Most often when the disadvantages of multiple inheritance are discussed, the name resolution along the class graph is considered as the biggest problem. The question is, which method is to be chosen and which path through class graph is to be taken, if more then one method of the specified name exist on the class graph.

    In the example such questions would arise for an object of the Kitchen class, if two same-named methods are defined on CookingPlace and 4WallsRoom or if a method of the class Object is called, which is reachable through two paths (along CookingPlace or Room).

    Often - e.g. in the inheritance model of C++ - the path through the graph is not clearly determined and/or the rules are too complicated to be understood on the first glance. The programmer often can only determine by trial which method is found firstly. Than an explicit naming of the class is necessary, which means storage of non-local information in sub-classes. Often different compilers of one language behave differently. All these issues make code reuse difficult. Moreover understandability and portability are reduced.


    Figure 3: The example classes and the following next-path


    XOTcl goes an intuitive and unambiguous way to solve this problem. It resolutes the precedence order along a ``next-path''. Firstly the class of the object is searched, which is Kitchen in example. Then the super-classes are searched in definition order, which means at first 4WallsRoom, then CookingPlace. Each branch is searched completely, before changing to the next branch. That means, Room is searched, before the CookingPlace branch is visited. At last the top of the hierarchy, the class Object, is searched.

    The usage of next in XOTcl is different to OTcl: In OTcl, next is defined as a method, in XOTcl it is a primitive command. Furthermore, in OTcl, it is always necessary to provide the full argument list for every invocation explicitly. In XOTcl, a call of next without arguments can be used to call the shadowed methods with the same arguments (which is the most common case). When arguments should be changed for the shadowed methods, they must be provided explicitly in XOTcl as well. In the rare case that the shadowed method should receive no argument, the flag --noArgs must be used.

    Destruction of Classes

    Classes are destroyed by the destruction of the class-object using the destroy method of the Object class. The destruction of super-classes does not destroy the sub-classes. The super-class is simply removed from the sub-classes' super-class lists. All classes have the super-class Object, if no super-class is specified. Therefore, if all super-classes are destroyed or removed, the new super-class is Object, not: no super-class. The destruction of the class of an object does neither delete the object nor leave it without class. In XOTcl a deleted class leaves it's instances with the class Object.

    So all empty class- and superclass-relationships are automatically reset to Object. Note that this are differences to OTcl, where the destruction of a class destroys all instances and an empty super-class list remains empty.

    Method Chaining

    A special feature of XOTcl is the method chaining without explicit naming of the ``mix-in''-method. It allows one to mix the same-named superclass methods into the current method (modeled after CLOS). The previously described next-path is the basis for this functionality. At the point marked by a call to the next primitive of XOTcl the next shadowed method on the next path is searched and, when it is found, it is mixed into the execution of the current method. When no method is found, the call of next returns an empty string, otherwise it returns the result of the called method. The syntax is:

      next ?arguments|--noArgs?
    

    As stated earlier the usage of next in XOTcl differs from OTcl, since the next call without arguments in OTcl means per default that no arguments are passed. But most often all arguments are passed through to the shadowed methods (since these will most likely have the same signatures). When all variables should be passed through, in OTcl it is necessary for correct variable substitution to use:

      eval $self next $args
    

    To avoid such difficulties, we made the passing of all arguments the default case; a simple

      next
    

    performs the task of passing all arguments to the shadowed methods. These arguments are called the standard arguments. If the standard argument feature should not be used, optionally arguments can be given or the flag --noArgs could be set as sole argument, which means that the shadowed method is called with no arguments.

    E.g. the following next call ignores the standard arguments and sends the arguments 1 and 2 instead:

      next 1 2
    

    As an example all classes involved in the previous example should get a constructor instance method, which simply sets an instance variable on the object:

      Room instproc init args {
        my set roomNumber 0
        next
      }    
      4WallsRoom instproc init args {
        my set doorPosition 0
        next
      }
      CookingPlace instproc init args {
        my set stoveType electric
        next
      }
      Kitchen instproc init args {
        my set cookName -
        next
      }
    

    After creation an object of class Kitchen gets automatically four instance variables cookName, roomNumber, doorPosition and stoveType set up with default values in this order (since this is the order of the classes in the next-path). Note that the order is important, because one missing next call, in one of the init methods, means that succeeding init methods will not be executed. This mechanism functions equally on all kinds of instprocs, not only on constructors.

    The constructors use the args argument, which allows us to give a list of variable length as arguments. To ensure reusability of our classes the constructors should use args in most cases, since they may pass through arguments for constructors further up the class hierarchy.

    If a proc with the searched name exists on the object it shadows all instprocs. A next call in a proc leads to the normal next-paths search, starting with the object's class.

    By the way, an observant reader might notice that the example above can be rewritten without explicit constructors, just by using parameters with default values.

      Class Room -parameter {{roomNumber 0}}
      Class 4WallsRoom -superclass Room -parameter {{doorPosition 0}}
      Class CookingPlace -parameter {{stoveType electric}}
      Class Kitchen -superclass {4WallsRoom CookingPlace} -parameter {{cookName -}}
    

    If an instance of a Kitchen is created it will contain instance variables for doorPosition, cookName, roomNumber, and stoveType, as the following statements will show.

      Kitchen k
      puts [k info vars]
    

    Dynamic Class and Superclass Relationships

    Another property of XOTcl that distinguishes it from statically typed languages are dynamics of class relationships. The realization of the definition of super-classes as seen above with the superclass method suggests already, that it is not only available at the class definition time. In the above example its appended to the class definition with "-superclass" as a short syntax for method invocation at definition time (all other available methods can also be called with a preceding dash ("-") appended to definitions).

    At any time the class graph may be changed entirely using the superclass method. Suppose the rooms and kitchens created in modeling of a house should be displayed to a screen, but it is not determined, whether the user of the system has the possibilities for graphical outputs. Two classes TextOutput and GraphicalOutput may be defined, which handle the output. Both have an instproc paint which does the painting of the virtual world on the chosen display type. The common output requirements are handled by a derived class VirtualWorldOutput which calls the paint method of the superclass using next. In statically typed languages it would need more sophisticated constructs to change the output class at run-time. E.g. a delegation to another object handling the intrinsic task of the output object would be introduced solely for the purpose of configuring the output form. With a dynamic class system we can use the superclass method to do so easily:

      Class TextOutput
      TextOutput instproc paint args {
        # do the painting ...
      }
      Class GraphicalOutput
      GraphicalOutput instproc paint args {
        # do the painting ...
      }
    
      # initially we use textual output
      Class VirtualWorldOutput -superclass TextOutput
      VirtualWorldOutput instproc paint args {
        # do the common computations for painting ...
        next; # and call the actual output
      }
    
      # user decides to change to graphical output
      VirtualWorldOutput superclass GraphicalOutput
    

    Sometimes, such a change to new intrinsic properties should not happen for all instances of a class (or the class hierarchy), but only for one specific object. Then the usage of a dynamic super-class relationship is a too coarse-grained means. A second form of such dynamics is the changing of the relationship between object and class. This means, objects can also change their class dynamically at run-time. This feature may be used to model a life-cycle of an object, without losing the object's identity, inner state or per-object-specializations through procs. The class instance method enables this functionality.

    An example would be an agent for the virtual world. Agents may be placeholders for persons, who interactively travel the world, or programs, which act automatically. When a person decides at run-time to give a task it has performed formerly by hand to an automatic agent, the agents nature changes from interactive agent to automatic agent, but the identity and the local state (that means the parts of the task, that are already fulfilled by the person) stay the same. This is a scenario for changing class relationships, e.g.:

      Class Agent
      Class AutomaticAgent -superclass Agent
      Class InteractiveAgent -superclass Agent
    
      # create a new agent for a person
      InteractiveAgent agent1
    
      # the person does something ...
      # and decides the change to an automatic agent
      agent1 class AutomaticAgent
    

    Meta-Classes

    Meta-classes are a special kind of classes. Similar as classes are managing objects (where managing means: control the creation and destruction of instances, know what instances exist, provide methods), meta-classes are managing classes. So, meta-classes are used to define classes. In other words, every Class in XOTcl is created by a meta-class, in most cases by the meta-class named Class. New user-defined meta-classes can be defined as subclasses of the predefined meta-class Class, or by adding an instmixin class (see below) containing Class to the precedence chain of the class. By defining Object instmixin Class one can even change the object system of XOTclin a way such that every created Object is a meta-class.

    Since the concept of a meta-class are sometimes confusing to people of a background of some other programming languages, we explain meta-classes slowly with the analogy of classes and objects.

    When a class Foo is created via the command

       Class Foo
    
    it has no private variables and no special methods. This is somewhat similar as creating an object via Object:
       Object foo
    
    This plain object foo can be configured directly, or one can create a class that configures the object. Instead of writing
       Object foo 
       foo set x 1
       foo proc hi {} {puts "hello"}
    
    one can use
       Class C -superclass Object
       C instproc init {} {my set x 1}
       C instproc hi {} {puts "hello"}
    
    and create an instance and call the method.
       C c1
       c1 hi
    
    The same holds for meta-classes and classes as well: Instead of writing
       Class Foo
       Foo set x 1
       Foo proc hi {} {puts "hello"}
    
    the following can be used:
       Class MC -superclass Class
       MC instproc init {} {my set x 1}
       MC instproc hi {} {puts "hello"}
    
    The instances of meta-classes are classes which can be defined the usual way:
       MC Bar
       Bar hi
       Bar b1
    
    Now we have a class names Bar which has a class-scoped variable named x with the value of 1 (set via the constructor); the class Bar has as well a class-method named hi which prints, when called, the string "hello". The class Bar can be used to create instances of the class like b1, b2 and so on.

    Note that the command Class is a predefined definition of the most general meta-class in XOTcl. Each time we are creating a class, we use this meta-class. In order to define a specialized meta-class, we can do this the traditional object-oriented way: we subclass. Therefore, in to define a specialized meta-class, we can use:

      Class myMetaClass -superclass Class
    

    This defines a new meta-class myMetaClass, which has all the abilities of meta-classes. That means that the programmer is able to specify new class features or override old ones. Later she/he may instantiate these into new classes.

    This is a very powerful language feature, since it allows one to give some classes further abilities than the others (or to restrict classes). This way large program structures, like certain design pattern parts, may be instantiated. Meta-classes hold the common abstract parts of the structures. They allow one to form libraries of such structures very easily.

    Example 1: Overloading the info method of classes

    As a simple example we can derive a new meta-class NoClassInfo from Class. Later we override the info method of Class. Thus the classes created with NoClassInfo, have an info option that only produces an error message. All classes created with NoClassInfo, like Agent in the example below, are not capable of accessing the class info method anymore:

      Class NoClassInfo -superclass Class
      # redefine info ability
      NoClassInfo instproc info args {
        error "No class info lookup"
      }
      # derive agent class from meta-class, which
      # can not access class info
      NoClassInfo Agent
    
    Now a call like:
      Agent info superclass
    

    triggers the error message.

    Example 2: Defining Classes that Count Their Instances

    Meta-classes are frequently used to define some bookkeeping about the number of instances on the class level. In the following example we define a meta-class named CountedClass which defines classes that count their instances:

      Class CountedClass -superclass Class -parameter {{counter 0}}
      CountedClass instproc create args {
        my incr counter
        next
      }
      CountedClass instproc instdestroy args {
        my incr counter -1
        next
      }
      CountedClass Dog
    
      Dog piffie
      Dog idefix
      puts "nr of dogs: [Dog counter]"
    
      piffie destroy
      puts "nr of dogs: [Dog counter]"
    
    Note that the behavior introduced by meta-classes can be orthogonal to the behavior of the classes. One can define Dog as a specialization of Animal or defines a special kind of dog such as Poodle using the method superclass as usual.

    Example 3: The Singleton Meta-Class

    Finally, a small example, which is more practical. Some applications have the requirement that only one instance of a class might be defined at a certain time. Such a behavior is frequently called a "Singleton". In XOTcl we can define a class singleton by overloading the create method of Class: when create is called and there exists already an instance of the singleton it is returned instead of a new instance.

      Class Singleton -superclass Class
      Singleton instproc create args {
        expr {[my exists instance] ? [my set instance] : [my set instance [next]]}
      }
    
    If someone wants to have a class e.g. Manager to be a singleton, you can create it by e.g.
      Singleton Manager -superclass FOO
    

    Create, Destroy, and Recreate Methods

    XOTcl allows since version 0.84 for a flexible destroy and recreate scheme. create and alloc are both Class instprocs handling creation for their instances. I.e.:

     className alloc [self]
    
    and
     className create [self]
    

    are used for creating an instance. A similar method instdestroy exists on Class that handles physical destruction of an object. The method destroy on Object which lets an object destroy itself in fact has the following behavior:

      Object instproc destroy args {
       [my info class] instdestroy [self]
      }
    

    However, this behavior is not implemented in XOTcl, but in C. create distinguishes between the following situations:

    • Create a new object: By default create calls alloc and then doInitializations.
    • Recreate an existing object: When the specified object exists, it is recreated through the recreate method:
        givenClass recreate [self]
      

      The method recreate can be customized like all other XOTcl methods (e.g. by overloading or interception). By default recreate calls cleanup followed by doInitializations.

      Note that recreate is not called, when a someone tries to recreate a class as an object or an object as a class. In these cases, destroy + create are used.

          Class c
          Object c ;# here, "c" is downgraded to an object, no "recreate" is called
      

    For create and recreate, the method doInitializations is called automatically from C and has the following default behavior:

    • Search for parameter default values,
    • Call parameter initialization methods,
    • Call the constructor init.

    Each step has a method call that can be changed, intercepted, etc. Of course, cleanup, recreate, instdestroy, etc. can also be overloaded or intercepted.

    Consider a typical case for overloading recreate: a structure preserving recreate that cleans up the class but preserves the existing class hierarchy (subclass and instance relationships):

      Class StructurePreservingRecreate
      StructurePreservingRecreate instproc recreate {cl args} {
        if {[my isclass $cl]} {
          set subclass [$cl info subclass]
          set instances [$cl info instances]
        }
        next
        if {[my isclass $cl]} {
          foreach sc $subclass {
            $sc superclass $cl
          }
          foreach i $instances {
            $i class $cl
          }
        }
      }
      Object instmixin add StructurePreservingRecreate
    

    Now the following code does not change the superclass or instance relationships of C:

      Class A
      Class B
      Class C -superclass {A B}
      Class D
      Class E -superclass {C D}
      C c1
      C c2
    
      # recreate -> is structure preserving
      Class C -superclass {A B}
      C c2
    
      # test
      puts superclass=[C info superclass]
      puts subclass=[C info subclass]
      puts instances=[C info instances]
      puts class=[c1 info class]
      puts class=[c2 info class]
    
    Starting with XOTcl 1.4.0, xotcl provides also a user-friendly way for a structure-prevering recreate implemented in C. Since this version, one can configure "softrecreate" as follow.
    ::xotcl::configure softrecreate true
    
    This command causes that recreates are structure-conservative.

    Methods with Non-Positional Arguments

    So far we have introduced methods only with positional arguments: that is, the position of an argument in the argument list determines to which local variable the argument is bound, when the method is invoked. Sometimes non-positional arguments -- arguments that carry both a name and a value when the method is invoked -- are useful. Before a non-positional argument can be used, it must be defined in the method definition using the following syntax:

     className instproc methodName ?non-pos-args? args body ?assertions
     objName proc methodName ?non-pos-args? args body ?assertions
    

    The non-positional arguments are defined with the following syntax:

     {-name?:checkoption1, checkoption2, ...? default value} \
         {-name?:checkoption1, checkoption2, ...? ?default value?} ...
    

    Only the name of the non-positional argument is really required, all other parts of this syntax are optional.

    Let's consider a simple example, where a method with two non-positional args is defined; one has only a name ("a"), and one has a name and a default value (b):

     Object o
     o proc someproc {-a {-b {1 2 3}} x y} {
         puts "$a $b $x $y"
     }
    

    We can invoke this method as follows:

     o someproc -b {4 5} -a 1 3 4
    

    Here, the order of a and b can be changed; hence the name non-positional arguments. As b has a default value, we do not need to provide a value for it. In the following invocation b has the value "1 2 3":

     o someproc -a 1 3 4
    

    The ordinary arguments start after the last non-positional argument (here: "3 4"). We can explicitly end the non-positional arguments by using "--". This is useful if we want to provide arguments that contain dashes ("-"), e.g.:

     o someproc -a 1 -- -b -c
    

    Sometimes we want to check or control the non-positional arguments. For instance, in the above invocation, we might want to check that a is not forgotten, because otherwise the method cannot execute properly. This is the role of the checkoptions. There are three predefined checkoptions: required, boolean and switch. required checks whether a non-positional argument is given, boolean checks that a non-positional argument is of boolean type. For instance:

     Class P
     P instproc someproc {-a:required {-b:boolean true}} {
         puts "$a $b"
     }
     P p
    

    This method requires a, and b needs to be of type boolean (is has the default value true). This invocation is valid:

     p someproc -a 1 -b 0
    

    This invocation is invalid, because a is missing, and b is not a Tcl boolean type:

     p someproc -b " a b v"
    

    The checkoption switch is similar to boolean except it does not require an additional argument. If the default value is false, the switch can be turned on, if the default is true it can be switched off.

    The checkoptions are extensible. In fact, they are defined in an object ::xotcl::nonposArgs. We can extend this object with new methods. A check option method has the following syntax:

     someobject|someclass proc|instproc methodName {?optional nonpositional arguments? argName arg} {
      ...
     }
    

    argName is here used to denote the name of the argument, and arg is the provided value.

    Of course, the non-positional arguments can also be introspected. The following info options return the non-positional arguments of a method:

     objName info nonposargs methodName
     className info instnonposargs methodName
    

    Message Interception Techniques

    Even though object-orientation orders program structures around data, objects are characterized primarily by their behavior. Object-oriented programming style encourages the access of encapsulated data only through the methods of an object, since this enables data abstractions. A method invocation can be interpreted as a message exchange between the calling and the called object. Therefore, objects are at runtime only traceable through their message exchanges. At this point the message interceptors can be applied to catch and manipulate all incoming and outgoing messages of an object.

    Generally interceptors can be applied to attach additional or extrinsic concerns to an object or a class or a class hierarchy. For instance roles or aspects can be implemented this way on various levels of scale.

    We have already discussed some interception techniques implicitly. E.g., the unknown mechanism intercepts messages that have not be found on the object. It can be used as a very useful programming technique, e.g., the define a default behavior for an object. The interceptors presented in this section have a different character: They are applied before/after the original method even if the method is defined for the target object. Thus these interception techniques may be applied

    We will discuss the message interceptors in this section in detail. The table below gives an impression, when which interceptor may be applied.

    Message Interceptors Overview

    Applied When

    Primary Target Structure

    Coverage

    Per-Object Filter

    before/after a call

    object hierarchies

    all methods

    Per-Class Filter

    before/after a call

    class and class hierarchies

    all methods

    Per-Object Mixin

    before/after a call

    object

    specific methods

    Per-Class Mixin

    before/after a call

    class and class hierarchies

    specific methods

    Unknown Mechanism

    after method was not found

    object

    all unknown calls


    Filter

    The filter (see [Neumann and Zdun 1999a] for more details) is a language construct to implement broader extensional concerns either for a single object or for several classes or class hierarchies. This way large program structures at the scale of several classes or class hierarchies can be managed. It is a very general interception mechanism which can be used in various application areas. E.g. a very powerful programming language support for certain design patterns is easily achievable, but there are also several other domains which are covered, like tracing of program structures, self-documentation at run-time, re-interpretation of the running program, etc.

    A per-class filter is a special instance method that is registered for a class C. A per-object filter is a special instance method that is registered for a object o. Every time an object of class, C or the object o respectively, receives a message, the filter method is invoked automatically.

    Usage of Filters

    All messages to a filtered object must go through the filter before they reach their destination object. A simple example would be a sole filter on the class of the object. To define such a filter two steps are necessary. Firstly a filter method has to be defined, then the filter has to be registered. The filter method consists of three parts which are all optional. A filter method has the following form:

      className instproc FilterName args {
        pre-part
        next
        post-part
      }
    

    When a filter comes to execution at first the actions in the pre-part are processed. The filter is free in what it does with the message. Especially it can (a) pass the message, which was perhaps modified in the pre-part, to other filters and finally to the object. It can (b) redirect it to another destination. Or it can (c) decide to handle the message on its own. The forward passing of messages is implemented through the next primitive of XOTcl. After the filter has passed its pre-part, the actual called method is invoked through next.

    After the call of next is processed, the execution returns to the point in the filter, where the next call is located and resumes execution with the actions of the post-part. These may contain arbitrary statements, but especially may take the result of the actual called method (which is returned by the next-call) and modify it. The caller then receives the result of the filter, instead of the result of the actual called method.

    The pre- and post-part may be filled with any ordinary XOTcl-statements. The distinction between the three parts is just a naming convention for explanation purposes.

    The filter uses the args argument which lets us use a list of variable length as arguments, since it must filter a lot of different calls, which may have different argument lists. Furthermore, it may pass through arguments to other filters and the preceding filters may change the argument list.

    Since any proc/instproc may be a filter, a registration of the filter is necessary, in order to tell XOTcl, which instprocs are filters on which classes. The filter and instfilter instance methods are able to handle this task for per-object filters and per-class filters respectively. Similar to the XOTcl language introduced so far, the filter registration is dynamic at run-time. By supplying a new list of filters to filter/instfilter, the programmer can change the filters registered on a class at arbitrary times. The filter instance method has the syntax:

      className instfilter filterList
    
    for per-class filters and:
      objName filter filterList
    
    for per-object filters.

    Now a simple example should show the filter's usage. In the preceding examples we have defined several rooms. Every time a room action occurs it is likely that the graphical sub-system has to change something on the output of that particular room. Therefore, at first we need a facility to be informed every time an action on a room happens. This is quite easily done using filters:

      Class Room
      Room r1; Room r2;       # just two test objects
    
      Room instproc roomObservationFilter args {
        puts "now a room action begins"
        set result [next]
        puts "now a room action ends - Result: $result"
        return $result
      }
    
      Room instfilter roomObservationFilter
    

    Now every action performed on room objects is notified with a pre- and a post-message to the standard output stream. We return the result of the actual called method, since we don't want to change the program behavior at all. E.g. we can set an instance variable on both of the two room objects:

      r1 set name "room 1"
      r2 set name "room 2"
    

    The output would be:

      now a room action begins
      now a room action ends - Result: room 1
      now a room action begins
      now a room action ends - Result: room 2
    


      

    Figure 4: Cascaded Message Filtering



    All classes may have more than one filter. In fact they may have a whole filter chain, where the filters are cascaded through next. The next method is responsible for the forwarding of messages to the remaining filters in the chain one by one till all pre-parts are executed. Then the actual method is executed and then the post-parts come to turn. If one next-call is omitted the chain ends in this filter method. As an example for an additional filter we may register a filter that just counts the calls to rooms.

      Room set callCounter 0;  # set class variable
      Room instproc counterFilter args {
        [self class] instvar callCounter
        incr callCounter
        puts "the call number callCounter to a room object"
        next
      }
      Room instfilter {roomObservationFilter counterFilter}
    

    Filters are invoked in registration order. The order may be changed by removing them and adding them in new order. Filters are inherited by sub-classes. E.g. in the preceding example for the next path, an OvalOffice was derived from the Room class. Without a change to the program each OvalOffice object automatically produces the same filter output as rooms.


      

    Figure 5: Filter Inheritance


    Filter chains can also be combined through (multiple) inheritance using the next method. When the filter chain of the object's class is passed, the filter chains of the superclasses are invoked using the same precedence order as for inheritance. Since on the subclass there may also be a another filter chain, without sophisticated computing in the pre- and post-parts one can produce easily a powerful tracing facility. E.g. if we want to distinguish an OvalOffice from other rooms we may want to add a filter solely for rooms of the type OvalOffice:

      Class OvalOffice -superclass Room
      OvalOffice o1;  # test object
      OvalOffice instproc ovalOfficeObservationFilter args {
        puts "actions in an oval office"
        next
      }
      OvalOffice instfilter ovalOfficeObservationFilter
    

    A simple call to the o1 object, like:

      o1 set location "Washington"
    

    produces the following output:

      actions in an oval office
      now a room action begins
      the call number 3 to a room object
      now a room action ends - Result: Washington
    

    As seen already, filter registrations can be added dynamically at runtime. But they may also be removed. Perhaps the counting on rooms should stop after a while, then a simple call of the instfilter method is sufficient:

      Room instfilter roomObservationFilter
    

    Filters can be removed completely by giving an empty list to the registration method:

      Room instfilter {}
    

    Per-object filters operate on a single object. E.g. if we only want to observe a single Room object room1, we can use the filter method to register the roomObservationFilter only for this particular instance:

      room1 filter roomObservationFilter
    

    As a filter we can register any method in the precedence order of the class or object. Thus we can also register procs as per-object filters. Additionally, meta-class methods may be registered as per-class filters. Filters are linearized so that each filter is only executed once, even if it is registered multiple times.



    Introspection on Filters

    In order to gain information about the currently registered filters on a certain object/class, the class-object info option filters and the class info option instfilters may be queried. It returns a list of the currently registered filters:

      className info instfilter
      objName info filter
    

    A special call-stack info option for filters is self filterreg. It returns the name of the object or class on which the filter is registered. Since the filter may be registered on other objects/classes than the one on which it is defined, this may vary from self class in the filter. The command returns a list of the form:

      objName filter filterName
    
    or:
      className instfilter filterName
    
    respectively.



    Example: A Simple Trace Filter

    The trace example primarily demonstrates the inheritance of filter chains. Since all classes inherit from Object, a filter on this class is applied on all messages to objects. The Trace object encapsulates methods for managing the tracing:

      Object Trace
      Trace set traceStream stdout
    
      Trace proc openTraceFile name {
        my set traceStream [open $name w]
      }
    
      Trace proc closeTraceFile {} {
        close $Trace::traceStream
        my set traceStream stdout
      }
    
      Trace proc puts line {
        puts $Trace::traceStream $line
      }
    
      Trace proc add className {
        $className instfilter [concat [$className info filter] traceFilter]
      }
    

    First we define the object and set a variable for the stream to which we send the trace outputs (here: stdout). With a method for opening and a method for closing a file we can redirect the trace stream to a file. puts is helper method for the filter to print an output to the selected output stream. In add the traceFilter is appended to the existing filters of a specified class. The actual filter method (see below) displays the calls and exits of methods with an according message. The calls are supplied with the arguments, the exit traces contain the result values. We have to avoid the tracing of the trace methods explicitly.

      Object instproc traceFilter args {
        # don't trace the Trace object
        if {[string equal [self] ::Trace]} {return [next]}
        set context "[self class]->[self callingproc]"
        set method [self calledproc]
        switch -- $method {
          proc -
          instproc {::set dargs [list [lindex $args 0] [lindex $args 1] ...] }
          default  {::set dargs $args }
        }
        Trace::puts "CALL $context>  [self]->$method $dargs"
        set result [next]
        Trace::puts "EXIT $context>  [self]->$method ($result)"
        return $result
      }
    

    As trace message we write the callee´s context (class and proc), the invoked method (using calledproc), and the given arguments. In the switch statement we avoid to print whole method bodies.

    With

      Trace add Room
    

    messages to all rooms, including all instances of Room´s sub-classes, are surrounded with a CALL and an EXIT output. With

      Trace add Object
    

    messages to all objects in an XOTcl environment are surrounded with a CALL and an EXIT output. In general, it is possible to restrict the trace to instances of certain classes, or to produce trace output for only certain methods. This requires registration methods and a more sophisticated implementation of the filter method.



    Mixin Classes

    Per-object and per-class mixins (see [Neumann and Zdun 1999c] for more details) are another interception technique of XOTcl to handle complex data-structures dynamically. Here, we use mixin as a short form for mixin class. All methods which are mixed into the execution of the current method, by method chaining or through a mixin class, are called mixin methods. Mixin classes resembles the filter presented in the preceding section. While the filters work on all calls to all methods of an object/class hierarchy, the mixin classes are applied on specific methods. The filter is defined in a single method, while the mixin is composes several method in a class.

    Supplemental Classes

    Mixin classes cover a problem which is not solvable elegantly just by the method chaining, introduced so far. To bring in an addition to a class, the normal XOTcl way is to define a mixin method and chain the methods through next, e.g.:

      Class Basic
      Basic instproc someProc  {
        # do the basic computations
      }
      Class Addition
      Addition instproc someProc {
        # do the additional computations
        next
      }
    

    In order to mix-in the additional functionality of the supplemental class Addition a new helper class (sometimes called intersection class) has to be defined, like:

      Basic+Addition -superclass {Addition Basic}
    

    This is even applicable in a dynamical manner, every object of the class Basic may be changed to class Basic+Addition at arbitrary times, e.g.:

      Basic basicObj
      ...
      basicObj class Basic+Addition
    

    Now consider a situation with two addition classes. Then following set of classes has to be defined to cover all possible combinations:

      Class Basic
      Class Addition1
      Class Addition2
      Class Basic+Addition1 -superclass {Addition1 Basic}
      Class Basic+Addition2 -superclass {Addition2 Basic}
      Class Basic+Addition1+Addition2 -superclass {Addition2 Addition1 Basic}
    

    The number of necessary helper classes rises exponential. For n additions, 2n-1 (or their permutations if order matters) artificially constructed helper-classes are needed to provide all combinations of additional mix-in functionality. Furthermore it is possible that the number of additions is unlimited, since the additions may produce other additions as side-effects. This demonstrates clearly that the sub-class mechanism provides only a poor mechanism for mix-in of orthogonal functionality. Therefore we provide an extension in the form of class-object mixin classes, which are added in front of the search precedence of classes.

    Per-Object Mixins

    The mix-ins methods extend the next-path of shadowed methods. Therefore, per-object mix-in methods use the next primitive to access the next shadowed method. Consider the following example:

      Class Agent
      Agent instproc move {x y} { 
        # do the movement
      }
      Class InteractiveAgent -superclass Agent
      # Addition-Classes
      Class MovementLog
      MovementLog instproc move {x y} { 
        # movement logging
        next
      }
      Class MovementTest
      MovementTest instproc move {x y} {
        # movement testing
        next
      }
    

    An agent class is defined, which allows agents to move around. Some of the agents may need logging of the movements, some need a testing of the movements, and some both (perhaps only for a while). These functionalities are achieved through the additional classes, which we will apply through per-object mixins.

    Before we can use the per-object mix-ins on a particular object, we must register the mixins on it with the mixin instance method. It has the syntax:

      objName mixin mixinList
    

    For example we may create two interactive agents, where one is logged and one is tested:

      InteractiveAgent i1; InteractiveAgent i2
      i1 mixin MovementLog
      i2 mixin MovementTest
    

    At arbitrary times the mixins can be changed dynamically. For example i2's movements can also be logged:

      i2 mixin MovementTest MovementLog
    


      

    Figure 6: Per-Object Mix-ins: Next-Path for the Example



    The mixin option of the info instance method allows us to introspect the per-object mixins. It has the syntax:

      objName info mixin ?pattern?
    

    It returns the list of all mix-ins of the object, if pattern is not specified, otherwise it returns the matching per class-object mixin classes.

    The inverse operation of info mixin is mixinof finds out, into which objects a per-object mixin class is mixed into.
      clsName info mixinof ?pattern?
    

    Note that the constructors (init methods) of per-object mixins (and per-class mixins) are only called, if the mixin is registered already during object initialization (when init is called). For per-object mixins, one can achieve the initialization of a mixin via an idiom like

      Object o -mixin M -init
    
    that registers the mixin before init is called. When a mixin is registered after object creation and it needs initializations, it is necessary to define special methods for this. Note that the behavior described here is introduced in version 0.84 to ensure consistent behavior of intrinsic classes, per-object and per-class mixins, and to achieve predictable behavior for dynamic registration for all kind of mixins, and as well during recreations of objects having mixins registered. Older versions used heuristics for the initialization of per-object mixins.

    Per-Class Mixins

    Per-class mixins are exactly identical in their behavior to per-object mixins, but they operate on classes. Thus they are the class-specific variant of the per-object mixins, like instprocs are a class-specific variant of procs. Therefore, in the language the per-class mixins are called instmixins.

    In general a per-class mixin is a class which is mixed into the precedence order of all instances of the class and all its subclasses it is registered for. It is also searched before the object's class itself is searched, but after per-object mixins.

    Per-class mixins are linearized according to the precedence order like classes on the superclass hierarchy. I.e. from the full list of per-object mixins, per-class mixins, and intrinsic classes (and all the superclasses of all these classes) always the last occurrence is used.

    From the point of view of language expressibility instmixins are not required, because they cannot express anything that per-object mixins cannot express already (like procs can express any instproc feature). As alternative to instmixins, we could simply register the per-object mixins in the constructor of the class.

    But there at least the following reasons for instmixins as an additional language construct:

    1. we can at runtime determine with info mixin and info instmixin whether it is a class- or object-specific mixin. Thus we get a better structuring at runtime.
    2. We have not to 'pollute' the constructors with per-class mixin registrations. Therefore, the constructors get more understandable.
    3. If it is required to add (and remove) dynamically interceptors to a set of objects, which are instances of a certain type, per-class mixins are much easier to handle (e.g. add an instmixin to Object to intercept e.g. all calls to certain predefined methods).
    4. The language is more 'symmetrical', since any object-specific feature in XOTcl has a class-specific variant.

    The mix-ins methods of per-class mixins extend the next-path of shadowed methods in the same way as per-object mixin methods. Before we can use a per-class mix-in on a particular class, we must register the mixin on it with the instmixin instance method. It has the syntax:

      className instmixin mixinList
    
    The inverse operation of info inmixin is instmixinof finds out, into which objects a per-object mixin class is mixed into.
      className info instmixinof ?-closure? ?pattern?
    

    Now consider that in the given per-object mixin example all interactive agents should be tested. We could either build a subclass TestedInteractiveAgent or register the per-object mixin in the constructor of the interactive agent class. The subclass solution leads to the same combinatorial explosion of intersection classes as discussed in the previous section, if more supplemental classes are added. The per-object mixin solution pollutes the constructor and does not prevail the structural semantics that the 'tested' property belongs to the interactive agent class at runtime

    Here, we can use a per-class mixin:

      Class Agent
      Agent instproc move {x y} {# do the movement}
      Class InteractiveAgent -superclass Agent
      Class MovementTest
      MovementTest instproc move {x y} {
        # movement testing
        next
      }
    
      # now register the instmixin
      InteractiveAgent instmixin MovementTest
    
    

    The per-class mixin now operates on all interactive agent including the instances of subclasses. E.g. for interactive agents i1 and i2 we automatically have movement testing. i2 is also logged, since it has the logging class as object-specific mixin:

      InteractiveAgent i1
      InteractiveAgent i2 -mixin MovementLog
    
      i1 move 3 4
      i2 move 1 2 
    

    At arbitrary times the instmixins can be changed dynamically.

    The instmixin option of the class info instance method allows us to introspect the per-class mixins. It has the syntax:

      className info instmixin ?className2?
    

    It returns the list of all instmixins of the class, if className2 is not specified, otherwise it returns 1, if className2 is a mixin of the object, or 0 if not.

    Per-class mixins are applied transitively. That means the per-class mixin A of a per-class mixin B is also applied for an objectin B's scope. This is exactly the same as how superclasses are applied for instances. Consider the following example

      Class X11 \
         -instproc test args {
    	puts [self class]
    	next
         }
      Class X12 \
        -instproc test args {
    	puts [self class]
    	next
        }
      Class X \
        -instmixin {X11 X12} \
        -instproc test args {
    	puts [self class]
    	next
        }
    
      Class Y \
        -instmixin X
    
      Y create y -test
      X create x -test
    

    Here the application as a superclass (for x) yields the same result as the application as an instmixin (for y):

      ::X11 
      ::X12 
      ::X
    

    Precedence Order

    The precedence order is composed by the precedence order of the superclass hierarchy (as explained earlier) and the message interceptors. In general, filters precede mixins and the superclass hierarchy. They are applied in the order of the next path of the object. Thus per-object filters are ordered before per-class filters.

    Mixins are processed after the filters. Again, they are applied in the order of the next path of the object. Thus per-object mixins are ordered before per-class mixins.

    Finally, the object's own heritage order comes in the order: object, class, superclasses.

    The three precedence order lists (filters, mixins, and classes) are pre-calculated and cached.

    Filters as well as classes (mixins and ordinary classes) are linearized. That means, each filter and each class can be only once on a precedence order list. If a filter or class can be reached more than once, than the last occurrence is used.

    For instance, consider a class A is superclass, per-class mixin, and per-object mixin. On the precedence order lists only the last occurrence as a superclass is used after linearization.

    Guards for Filters and Mixins

    Message interceptors, such as filters and mixins, are applied for potentially huge number of messages. In many cases it is possible to reduce the effective number of cases in which interceptors are applied. Interceptor guards offer this functionality: they are boolean conditions with which you can specify in which cases a registered interceptor should be applied.

    Filter Guards

    A filter guard is a set of conditions that determine whether a filter is to be executed upon a certain invocation or not. Syntactically we can append a filter guard to the filter registration, or it can be registered using the methods filterguard for filters and instfilterguard for instfilters.

    Each filter guard is an ordinary condition. A filter guard is executed in the call frame of the filter to be executed, if the filter guard returns 1. Thus, the call-stack information are already set to the values of the targeted filter - and these values can be used in the filter guard.

    Let us consider a simple program:

    Class Room
    Room instproc enter {name} {puts [self proc]}
    Room instproc leave {name} {puts [self proc]}
    Room instproc loggingFilter args {
        puts [self calledproc]
        next
    }
    Room instfilter loggingFilter
    

    Now consider we only want to apply the logging filter for enter and leave, not for any other message sent to Room instances. In the following example, for instance, we do not want to log the set message:

    Room r 
    r enter Uwe
    r leave Uwe
    r set roomName "Office"
    

    In this example a filterguard can be applied to restrict the application of the filter to those two methods:

    Room instfilterguard loggingFilter {
      [self calledproc] == "enter" || 
      [self calledproc] == "leave"}
    

    Here we limit the filter application of the logging filter on rooms to calls to enter and leave. All other calls are not filtered at all. Note that the same syntax can also be applied for filterguard. Also, there is a short form to register filter guards directly during filter registration. The following code has the same semantics as the filter and filter guard definitions above:

    Room instfilter {{loggingFilter -guard {
        [self calledproc] == "enter" || 
        [self calledproc] == "leave"}}}
    

    The filter guard language construct is registration centric. It only applies for the class or object on which a filter is registered, not for all applications of the filter method. That is, if we use loggingFilter on another class we may give no or completely different filter guards.

    If no filter guard is given for a filter, we assume that it is to be applied on all methods (equivalent to the filter guard '1' which is always true).

    There are introspection options for filter guards. In particular, we can use info filterguard and info instfilterguard for getting the filter guards for a particular filter or instfilter respectively. For instance:

    puts [Room info instfilterguard loggingFilter]
    

    This prints out the content of the above guard definition. We can also append -guard to info filter or info instfilter to obtain a filter definition with guards:

    puts [Room info instfilter -guards]
    

    If we call a method from within a filter guard, as for instance callsMethod, we might require some parameters from the guard's context, such as calledproc. These parameters can be passed as references, as in the following example:

      Room instfilter loggingFilter
      Room instfilterguard loggingFilter {[my callsMethod openURL [self calledproc]]}
    

    This example works because the filterguard is already set to the scope of the guard. Now we can use this dynamic calledproc context in the called method:

      Room instproc callsMethod {method calledproc} {
        return[string match $calledproc $method]
      }
    

    We simply check whether the called method matches the given method name or not.

    Mixin Guards

    Similar to filters, there are mixin guards, defined with mixinguard and instmixinguard, or with -guard during mixin registration. Consider a simple example: there are a number of birds who have two mixins: Fly and Sing. For Fly there are limitations: a bird can only fly if it is at least two years old and is not a Penguin. Such problems are be solved with mixin guards:

      Class Fly
      Fly instproc fly {} {puts "[my signature]: yippee, fly like an eagle!"}
    
      Class Sing
      Sing instproc sing {} {puts "[my signature]: what a difference a day makes"}
    
      Class Animal -parameter age
      Animal instproc unknown args { puts "[my signature]: how should I $args?"}
      Animal instproc signature {} {
        return "[self] [my info class] ([my age] years)"
      }
    
      Class Bird -superclass Animal
      Class Penguine -superclass Bird
      Class Parrot -superclass Bird
      Class Duck -superclass Bird
    
      Parrot tweedy -age 1
      Penguine pingo -age 5
      Duck donald -age 4
      Parrot lora -age 6
    
      Bird instmixin {{Fly -guard {[my age] > 2 && ![my istype Penguine]}} Sing}
    

    An invocation like:

    foreach bird {tweedy pingo donald lora} { $bird fly }
    

    yields the following result:

    ::tweedy ::Parrot (1 years): how should I fly?
    ::pingo ::Penguine (5 years): how should I fly?
    ::donald ::Duck (4 years): yippee, fly like an eagle!
    ::lora ::Parrot (6 years): yippee, fly like an eagle!
    

    There are similar introspection options for mixin guards as those for filter guards. In particular, we can use info mixinguard and info instmixinguard for getting the mixin guards for a particular mixin or instmixin respectively.

    Querying, Setting, Altering Filter and Mixin Lists

    The methods mixin, instmixin, filter and instfilter are system slots having the same query and update interface.
    • If one of those methods is called without argument, it returns the current setting.
    • If it is called with one argument, the argument is used to set the specified list as indicated in the above examples.
    • If these methods are called with more than one argument, the first argument is used to specify the action. Possible values for the action are set, get, add and delete. See below for commonly used examples.

    obj mixin same as: obj info mixin
    obj mixin {C1 C2} same as: obj mixin assign {C1 C2}
    obj mixin assign {C1 C2}sets the mixins for obj
    obj mixin add C3 adds the mixin C3 on front of the mixin list
    obj mixin add C3 end adds the mixin C3 at the end the mixin list
    obj mixin add C3 3 adds the mixin C3 at the 3rd position
    obj mixin delete ::C3removes the mixin C3 from the mixin list. Use absolute class names. delete supports an optional flag -nocomplain that does not produce an error, when the specified class is not in the list.

    Note that the list of possible actions can be extended by extending the class ::xotcl::Relations.

    Querying Call-stack Information

    Since the presented interceptors are normal XOTcl instprocs they can access all XOTcl introspection abilities introduced so far. In instprocs all recent information is accessible within their scope. But the interceptors are mechanisms, which cover more then their sole scope. The meaningful usage of the meta-programming abilities often requires to go further and to get information from the caller's and the callee's scope (e.g. for delegation decisions). Therefore, we introduced rich call-stack information for the interceptors. Note that these are also available for ordinary methods, but the "called..." info options return empty strings.

    All call-stack information are packed compactly into the self primitive as additional options. Note, before XOTcl version 0.84 these were implemented as a part of the info method. They are part of the self command for conceptual integrity: introspection options in info can be expected to produce the same result, when they are not explicitly changed. In contrast, all information provided by self are call-stack dependent.

    Querying Call-stack Information via self

    self activelevel

    Returns the stack level from where the current command was invoked from, or where the last next was called (whatever is closer to the invocation). If the current command was invoked from an XOTcl method the absolute level is returned (e.g. #4) which can be used in the uplevel or upvar Tcl command or XOTcl method. If the current command was not invoked from an XOTcl method, the value 1 is returned.

    self calledproc

    Returns the name of the method which was invoked in the original call.

    self calledclass

    Returns the name of the class which presumably (if no dynamic class change occurs afterwards) is invoked in the original call.

    self callingclass

    Returns the name of the class from which the call was invoked (if one exists, otherwise an empty string).

    self callinglevel

    Returns the stack level from where the current command was invoked from. In contrary to activelevel next-calls are ignored in the computation. If the current command was invoked from an XOTcl method the absolute level is returned (e.g. #4) which can be used in the uplevel or upvar Tcl command or XOTcl method. If the current command was not invoked from an XOTcl method, the value 1 is returned.

    self callingproc

    Returns the name of the method from which the call was invoked (if one exists, otherwise an empty string).

    self callingobject

    Returns the name of the object from which the call was invoked (if one exists, otherwise an empty string).

    self filterreg

    In a filter: returns the name of the object/class on which the filter is registered. Returns either 'objName filter filterName' or 'className instfilter filterName'.

    self isnextcall

    Return 1 if this method was invoked via next, otherwise 0

    self next

    Return the "next" method on the path as a string, i.e. the method which will be called by [next].


    Note that three options with the prefix calling represent the values of self, self proc, and self class in the scope where the original call was invoked. In the following section we will show a simple program in which all of the info options have different values.


    Filter Call-stack Information Example

    Now we discuss a simple example that shows that all filter introspection options may have different values:

      Class InfoTrace
      InfoTrace instproc infoTraceFilter args { 
        puts "SELF:                [self]"
        puts "SELF PROC:           [self proc]"
        puts "SELF CLASS:          [self class]"
        puts "INFO CLASS:          [my info class]"
        puts "CALLED PROC:         [self calledproc]"
        puts "CALLING PROC:        [self callingproc]"
        puts "CALLING OBJECT:      [self callingobject]"
        puts "CALLING CLASS:       [self callingclass]"
        puts "REGISTRATION CLASS:  [self filterreg]"
        puts "CALLING LEVEL:       [self callinglevel]"
        puts "ACTIVE LEVEL:        [self activelevel]"
        next
      }
    
      Class CallingObjectsClass
      CallingObjectsClass callingObject
    
      Class FilterRegClass -superclass InfoTrace
      Class FilteredObjectsClass -superclass FilterRegClass 
      FilteredObjectsClass  filteredObject 
    
      CallingObjectsClass instproc callingProc args {
         filteredObject set someVar 0
      }    
      FilterRegClass instfilter infoTraceFilter

    The invocation of callingObject callingProc produces the following output:

      SELF:                ::filteredObject
      SELF PROC:           infoTraceFilter
      SELF CLASS:          ::InfoTrace
      INFO CLASS:          ::FilteredObjectsClass
      CALLED PROC:         set
      CALLING PROC:        callingProc
      CALLING OBJECT:      ::callingObject
      CALLING CLASS:       ::CallingObjectsClass
      REGISTRATION CLASS:  ::FilterRegClass instfilter infoTraceFilter
      CALLING LEVEL:       #1
      ACTIVE LEVEL:        #1

    The filter reports for self the value filteredObject, since this is the object on which the set call is invoked; infoTraceFilter is the method of the filter, and therefore, the actual proc, while the actual class is InfoTrace, the filter's class. The class of the actual object is FilteredObjectsClass.

    The called procedure is set. While the program stays in a XOTcl-instproc all calling-info-options are set, the calling procedure is callingProc, the calling class is the class, where the method is defined (namely CallingObjectsClass), and the object from which the call invoked is callingObject.

    In this example, the calling level is equal to the active level, both are #1.

    Slots

    A slot is a meta-object that manages property-changes of objects. A property is either an attribute or a role in an relation. In a nutshell, a slot has among other attributes:

    • a name (which it used to access it),
    • a domain (object or class on which it can be used) , and
    • can be multivalued or not.

    We distinguish between system slots (predefined slots like class, superclass, mixin, instmixin, filter, instfilter) and attribute slots (e.g. attributes of classes).

    System Slots

    System slots are predefined slots defining e.g. some relations between classes, or between objects and classes. The predefined system slots are:

    • superclass: every class in XOTcl has one or more superclasses. The name of this slot is superclass, the domain is ::xotcl::Class, the slot is multivalued, since one object might have multiple superclasses.

    • class: every object has a class; therefore, the domain of the slot is ::xotcl::Class, the property is not multivalued.

    • mixin: every object in XOTcl can have one or more mixin classes. The name of this slot is mixin, the domain is ::xotcl::Object , the slot is multivalued.

    • instmixin: same as above, but the domain is ::xotcl::Class.

    • filter, instfilter: similar to mixin and instmixin.

    The system slots were introduced earlier with their semantics. Here we just point out, that they have all the same interfaces for querying, setting, adding and removing of slot values.

    Every slot can be used set and query the property from its domain. The syntax for setting values is

      object property newValue
    
    and for getting its values is
       set x [object property]
    
    where property denotes the slot name. Every multivalued slot provides the methods add and delete. Here are a few examples for using the system slot mixin which we have introduced already in the section of the mixins
      Object o; Class M; Class N
      o mixin ::M      ;# replacing the per-object mixins of o with M
      o mixin reset ::M  ;# same as before
      o mixin add ::N   ;# add N to the front of the mixin list
      o mixin delete ::M ;# delete M from the mixin list
      puts [o mixin]   ;# query the current mixin list
    
    Every system slot (e.g. superclass) has the exact same interface.

    Attribute Slots

    Attribute slots are used to manage the setting and querying of instance variables. We define now a person with three attributes name, salary and projects.

      Class Person -slots {
        Attribute name
        Attribute salary -default 0
        Attribute projects -default {} -multivalued true
      }
    

    These attributes might have a default value or they might be multivalued. When an instance of class Person is created, the slot names can be used for specifying values for the slots.

      Person p1 -name "Joe"	
    

    Object p1 has three instance variables, namely name, salary and projects. Since slot projects is multivalued, we can add a value to the list of values the add subcommand.

      Project project1 -name XOTcl \
         -description "A highly flexible OO scripting language"
    
      p1 projects add ::project1
      p1 projects add some-other-value
    

    The value of the instance variable project of Person p1 is now the list {some-other-value ::project1}.

    Attribute slots are implemented via dynamic object aggregations (see below), where the Class objects contain the slot objects with the information like default etc. In order to prevent name clashes between the slot objects and the methods of a class (like e.g. create), an intermediary object named slot is used as a container of the slot objects. In the example above we create an object structure of the following form:

      Person
      Person slot name
      Person slot salary
      Person slot projects
    

    This object structure can be used to query and modify the slot properties or to add additional methods to the slot objects. One application is for example to used slot-specific methods for checking slot values, as shown in the next section.

      Person info vars  ;# results in the list of variables of ::Person
      Person slot name info vars ;# list of variables of the slot object ::Person::slot::name
    
    Since slot objects are ordinary XOTcl objects, they can have their own slots as well (such as default, name etc.). The following example sets and queries the default of the slot name of Person:

      Person slot name default "gustaf"
      ? {Person slot name default} gustaf
    

    However, due to the current implementation, it is necessary to re-init the slot object when the slot properties (such as e.g. default) are changed. This can be achieved by calling the method init of the slot object.

    Note that a statement for creating a slot object like

      ... {
        Attribute name
        ...
      }
    

    is a short hand notation for

      ... {
        Attribute create name
        ...
      }
    

    This is exactly the same situation like every where else in XOTcl, when an object/class is created. One has to use create explicitly, when a name of a slot object conflicts with a method of the class (e.g. one has to use "Attribute create class" if a slot named class is created).

    One cannot define on a meta-class an attribute named slot or slots and use then "... MetaClass Foo -slots { ::xotcl::Attribute x}... to create the slot objects. To handle this naming conflict, one has to create the slot objects outside of the aggregation and to provide the values for the properties of Attribute (domain, manager, .... ) by hand.

    Setter and Getter Methods for Slots

    When a slot is called via its name, the call is delegated to the slot object. Per default, the slot value is read via the get method of the slot and it is set the assign method. By redefining these methods, it is possible to provide custom setter and getter methods. The following example redefines the setter methods assign to check, whether an attribute value is within the range between 1 and 99.

      Class create A -slots {
        Attribute foo -default 1 -proc assign {domain var value} {
          if {$value < 0 || $value > 99} {
            error "$value is not in the range of 0 .. 99"
          }  
          $domain set $var $value
        }
      }
    
      A create a1
      ? {a1 foo 10} 10
      ? {a1 foo} 10
      ? {catch {a1 foo -1}} 1
    

    For the most common simple cases with single valued attributes, where neither setter or getter are redefined, XOTcl optimizes the slot access function and replaces the delegation to the slot object by the C-level implementation of instparametercmd.

    Note that it is possible to subclass Attribute (e.g. in order to store more properties for attributes, like when attributes are stored in a relational database) or to register mixin-classes or filters.

    Backward-compatible Short-Hand Notation for Attribute Slots

    XOTcl provides a short-hand notation for creating attribute slots, which is backward compatible for the most important options of XOTcl version prior to 1.5.0. Instead of writing

      Class Car -slots {
        Attribute owner
        Attribute doors -default 4
      }
    

    one can use as well

      Class Car -parameter {
        owner
        {doors 4}
      }
    

    The various features of the prior implementation of parameter are deprecated and will be removed in future versions.

    Experimental Slot Features

    Value Checking

    Attribute slots can have types assigned which are tested whenever the instance variable is altered. The slot salary is defined as integer whereas projects is defined to be a list of instances of the class ::Project (a list of instances, since projects is defined as multivalued).

      Class Person -slots {
        Attribute name
        Attribute salary -default 0 -type integer
        Attribute projects -default {} -multivalued true -type ::Project
        ...
      }
    
      Person p2 -name "Sue"	-salary 1000
    

    It is as well possible to define custom value checkers and to normalize the input values. We extend the previous example and define "my sex" as value for type. If the value checker consists of multiple words, the type check compiler assumes that the value is a Tcl command, to which the actual value is appended as additional argument before invocation. my refers to the slot object. In the example below, we define for the slot object an object specific method that returns 1 or 0 depending on the success of the check. This method (a) checks the values via switch and (b) normalizes and resets the value via uplevel.

      Class Person -slots {
        ...
        Attribute sex -type "my sex" -proc sex {value} {
          switch -glob $value {
            m* {my uplevel {$obj set $var m}; return 1}
            f* {my uplevel {$obj set $var f}; return 1}
            default {return 0}
          }
        }
      }
    

    The slot values are actually checked via Tcl variable traces whenever the associated variable gets a new value assigned. This means that the values are enforced now matter how the variables are set. Therefore, the checks are performed in the following two commands as well, although the slot values are not accessed via the slot names. The checks will throw an error in the second command, since 1100x is not an integer.

      p2 incr salary 100
      p2 append salary x
    

    Similarly the second command below will throw an error, since some-other-value is not an instance of ::Project.

      p2 projects add ::project1
      p2 projects add some-other-value     
    

    When a check throws an error, the instance variables are reset to the previous value. To restore the original value, an associative array __oldvalue() is kept as instance variable in the object.

    In general, checking of variables can be turned off globally by

      ::xotcl::Slot instmixin add ::xotcl::Slot::Nocheck
    

    This mixin replaces the methods check and checkall as well as mk_type_checker by no-ops. When the mixin is active and the Attribute definitions are loaded, the specified type has no effect.

    Value checking can be turned off also selectively for each slot via using ::xotcl::Slot::Nocheck as per-object-mixin; if attributes are subclassed, it is possible to register the Nocheck mixin on a subclass of Attribute.

    Init Commands and Value Commands for Slot Values

    An init command (initcmd) of a slot is similar to a default and is a command to be executed when the value of the associated variable is read the first time. That means that when an object is created the associated variable has no value. On the contrary, when a default is used, the variable is set to the default value, when the object is created.

    The primary advantage of slot init commands is Lacy initialization: When an object has many slots and the initialization of all slots is costly (e.g. the value of each slot is fetched from a relational database), and not all of the values are needed for each instance, only the relevant variables of the object are initialized on demand.
      Class C -slots {
        Attribute x -initcmd {puts {init}; set _ 101}
      }
    
      C c1
      c1 info vars  ;# ==> returns ""
      c1 set  x     ;# ==> puts init, returns 101
      c1 info vars  ;# ==> returns "x"
    

    The initcmd is executed only once, when the variable is read the first time. For later reads of the variable contents, the values are returned.

    A value command (valuecmd) of a slot is similar to a init command, except that it is executed whenever the value of the variable is read. A value command can be used e.g. to implement live updates for variables or for abstracting from sql sequences or the like.

    Finally the value changed command (valuechangedcmd) can be used to specify the behavior, whenever the value of the variable is altered. This option is used to implement the value checking described in the last section.

    The slot parameters default, initcmd and valuecmd have to be used mutually exclusively.

    Nested Classes and Dynamic Object Aggregations

    Most object-oriented analysis and design methods are based on the concepts of generalization and aggregation. Generalization is achieved through class hierarchies and inheritance, while static aggregation is provided through embedding. Since version 8.0 Tcl offers a namespace concept which can be used as a mechanism to provide dynamic aggregations.

    A namespace provides an encapsulation of variable and procedure names in order to prevent unwanted name collisions with other system components. Each namespace has a unique identifier which becomes part of the fully qualified variable and procedure names. Namespaces are therefore already object-based in the terminology of Wegner. OTcl is object-oriented since it offers classes and class inheritance. Its objects are also namespaces, but an object is more than only a namespace. Therefore, two incompatible namespace concepts have existed in OTcl in parallel.

    In XOTcl every object and every class is logically implemented as a separate Tcl namespace. The biggest benefit of this design decision aside from performance advantages is the ability to aggregate objects and nest classes. Contrary in OTcl every object has a global identifier. Through the introspection abilities of namespaces nested classes are also traceable at runtime and can be changed dynamically. In XOTcl objects are allowed to contain nested objects, which are dynamically changeable aggregates of the containing object.

    Nested Classes

    The notation for nested classes follows the syntax of Tcl namespaces by using ``::'' as a delimiter. For example the description of a oval carpet and a desk can nest inside of the OvalOffice class:

      Class OvalOffice
      # general carpet
      Class Carpet
      Class OvalOffice::Desk
      # special oval carpet - no name collision
      Class OvalOffice::Carpet -superclass ::Carpet
    

    Nested classes can be used exactly like ordinary classes, a user can sub-class it, derive instances, etc. The information about the nesting structure of classes is available through the info instance method:

      className info classchildren ?pattern?
      className info classparent
    

    The classchildren option returns a list of children, if one or more exist, otherwise it returns an empty string. classparent results in the name of the parent class, if the class is nested. Since nested classes are realized through namespaces, all functionality offered by Tcl's namespace command is usable from XOTcl as well.

    Dynamic Object Aggregations

    The nested classes only provide an aggregation of the descriptive not of the runtime properties of an object. We have pointed out the difference of object and class in XOTcl. Because of the splitting of a class into class and class-object it is possible to give each object its own namespace. The internal implementation of objects enable them to contain nested objects, which are aggregates of the containing object. In XOTcl these can be changed dynamically and introspected through the language support of dynamic object aggregations [Neumann and Zdun 2000b]. Suppose an object of the class Agent should aggregate some property objects of an agent, such as head and body:

      ClassAgent
      Agent myAgent
    
      Class Agent::Head
      Class Agent::Body
    
      Agent::Head ::myAgent::myHead
      Agent::Body ::myAgent::myBody
    

    Now the objects myHead and myBody are part of the myAgent object and they are accessible through a qualification using ``::'' (or through Tcl's namespace command). But in the common case they will be accessed, as introduced so far: the explicit full qualification is not necessary when such variables are being accessed from within XOTcl methods, since the object changes to its namespace.

    The information about the part-of relationship of objects can be obtained exactly the same way as for classes through the info interface:

      objName info children ?pattern?
      objName info parent
    

    Relationship between Class Nesting and Object Aggregation

    The classes Head and Body are children of the Agent class. It is likely that all agents, interactive or not, have properties for head and body. This implies a static or predetermined relationship between class nesting and object aggregation. Such predetermination do not exist in XOTcl, but are simply build, when specifying the relationship in the constructor, e.g.:

      Agent instproc init args {
        ::Agent::Head [self]::myHead
        ::Agent::Body [self]::myBody
      }
    

    Now all agents derived from the class have the two property objects aggregated after creation. But still they are changeable in a dynamical manner, e.g. with:

      Agent myAgent
      myAgent::myHead destroy
    

    The agent turns into a headless agent. In companion of the introspection mechanisms such constructions could be very useful. Suppose, that in the virtual world the agents heads may be slashed from their bodies. The graphical system simply needs to ask with info children on the agent's object, whether it has a head or not and can choose the appropriate graphical representation.

    Simplified Syntax for Creating Nested Object Structures

    To ease the generation of nested structures, one can use the predefined method contains. In essence, contains changes the namespace, where objects are created to the object, on which it is executed. In the example below, we create three nested rectangles, where two of these contain two more points. The outer rectangle is r0 containing rectangle r1 and r2.
      Class Point -parameter {{x 100} {y 300}}
      Class Rectangle -parameter {color}
    
      Rectangle r0 -color pink -contains {
        Rectangle r1 -color red -contains {
          Point x1 -x 1 -y 2
          Point x2 -x 1 -y 2
        }
        Rectangle r2 -color green -contains {
          Point x1
          Point x2
        }
      }
    
      ? {r0 color} pink
      ? {r0 r1 color} red
      ? {r0 r1 x1 x} 1
      ? {r0 r1 x2 y} 2
      ? {r0 r2 color} green
    

    Every object in XOTcl is realized as a Tcl command. If nested objects are created, these commands are available as object specific methods. So, instead of calling the contained rectangle r1 via the fully qualified name ::r0::r1, one can use r0 r1. This is exactly the same situation as it arises, when e.g. a global Tcl proc proc o1 {} {...} and an XOTcl object o1 (created via Object o1) is created. Both commands cannot coexist in the same namespace.

    Copy/Move

    Often an object has to be copied/moved. This is a very useful functionality when XOTcl should be used as a prototyping language. The XOTcl method move provides this functionality. Another common behavior is implemented by the copy method which clones the actual object to a destination object via a deep copy operation. The two methods have the syntax:
      objName move destination
      objName copy destination
    

    Copy and move operations work with all object/class information, i.e., information on filters, mixins, parameters, etc. are automatically copied. Copy and move are integrated with class nesting and object aggregations. All copy/move operations are deep copy operations: all nested objects/classes are automatically copied/moved, too. E.g. if we want to reuse an imperial march object of star wars for star wars 2, we can just copy the object:

      starWars::imperialMarch copy starWars2::imperialMarch
    
    Note that move is implemented in current versions of xotcl as a copy plus subsequent destroy operation.

    Method Forwarding

    As you have seen from many previous examples, XOTcl's primary command for method forwarding is the next primitive. next calls the same-named method of the current object, usually with the same argument list. However, frequently method forwarding is required between different objects as well, commonly referred to as delegation.

    In general, delegation can be achieved in XOTcl without any special construct using simple methods containing a few lines. However, In several situations, forwarding is as well needed to plain Tcl commands, for example, if object oriented stubs are implemented on base of non-oo function calls. These functions might access instance variables of the objects. XOTcl uses this functionality in various situations, such as for instance in the implementation of the set, unset, append, array methods among others.

    The forwarding functionality is supported by XOTcl be the methods forward and instforward that address these requirements and provide an efficient implementation for these tasks.

    The forwarding command specifies that whenever methodName is called, this invocation is delegated to callee, where the actual argument list (from the invocation) is appended to the argument list specified in the forwarding command. Like for procs and instprocs, we can distinguish between forward and instforward, depending on we want to the method available for a single object of for the instances of a class.

    The general form of the forwarding commands is:

      obj  forward methodName ?options? callee ?arglist? 
      cls  instforward methodName ?options? callee ?arglist? 
    
    where valid options are -objscope, -methodprefix, -earlybinding and -default. The option -objscope is used to specify that the command should be executed in the scope of the calling object (i.e. instance variables apprear as local variables), -methodprefix means that the called method should be prefixed with the specified string (to avoid name clashes), -earlybinding means that the function pointer of the specified command (callee) is take at invocation time (should only be done for (built-in) commands implemented in C), and -default provides a means for providing default methods when none are specified.

    Each of the arguments after the method name (including callee) can be be substituted an invocation time, or they are taken literally. The arguments to be substituted are starting always with a percent sign. These arguments can be %self, %proc, %1, %argclindex, or % followed by a Tcl command, and it can be prefixed with a positional prefix %@. We will introduce the usage of these options and argument substitutions based on examples.

    In our first example we define an object dog and an object tail. If the dog receives the call wag it delegates this call to the tail and returns its result. In this introductory example, the method tail simply returns its arguments.

    In this example, forwarding is achieved through the method forward that creates a forwarder command. This method receives as first argument the name, under which the forwarder is registered, followed by the object that receives the delegation (the "callee"), followed my the (optional) method name and optional arguments. More about this later. Here we register the forwarder under the name wag, the callee is tail, and the method is defined to have the name of the forwarder. We could have written here dog forward wag tail wag as well, be we use %proc which refers to the name of the forwarder. Using %proc is slightly more general in cases the forwarder is renamed.

      ###########################################
      # trivial object delegation
      ###########################################
      Object dog
      Object tail
      tail proc wag args { return $args }
      dog forward wag tail %proc
    

    With these definitions a call to "dog wag 100" calls actually "tail wag 100" which returns the result of 100.

    The following command shows the delegation to a Tcl command (instead of delegation to an object). We define a simple forwarder that forwards a call to the Tcl command expr with some arguments.

      ###########################################
      # adding 
      ###########################################
      Object obj
      obj forward addOne expr 1 +
    
    The invocation obj addOne 5 returns 6 as value.

    In our next example we want additionally that the Tcl command should to be evaluated in the context of the current object. This means that the method can easily access instance variables of the delegating object. We define a forwarder for the class X with the name Incr (to avoid confusion with the already defined method incr), we use the -objscope option and specify incr as the callee. Since the forwarder is defined via instforward the forwarder is available to all instances of the class.

      ###########################################
      # evaluating in scope 
      ###########################################
      Class X -parameter {{x 1}}
      X instforward Incr -objscope incr
      
      X x1 -x 100
      x1 Incr x
      x1 Incr x
      x1 Incr x
    
    After the three calls to Incr the call x1 x returns the value 103.

    In our next example, we show the usage of the %-substitution more advanced argument handling. This example sketches the implementation of the mixin add, mixin set methods as shown above. In order to obtain extensible subcommands (such as mixin add, mixin delete, etc.), we define an object for which the subcommands are defined as methods. We will use this object as callee for the appropriate methods. So, we define an object named mixin and define a forwarder with the name Mixin (again we capitalize Mixin to avoid name clashes with the already defined methodmixin ).

      ###########################################
      # mixin example
      ###########################################
      Object create mixin
      mixin proc unknown {m args} {return [concat [self] $m $args]}
      obj forward Mixin mixin %1 %self
    
    We define here the method unknown to see what arguments are passed. The following invocation will lead to the call in noted in the comment.
      obj Mixin add M1       ;# calls ::mixin add ::obj M1
    
    You see that %1 was substituted by the first argument of the invocation (here add) and %self was substituted by the name of the current object (here ::obj). The second argument of the invocation (here M1) was appended as usual. However, in calls like
      obj Mixin
    
    we have to deal with cases, where the used argument (%1) is not given at the invocation. In this case we get either an error message, or we can specify a default argument via the option -default:
      obj forward Mixin -default {getter setter} mixin %1 %self
    
    This definition means that if no argument is specified in the invocation we call the method getter, if one argument is given the method setter, in other cases we use the specified arguments. Therefore the following three invocations are delegated as indicated in the comments.
      obj Mixin              ;# calls ::mixin getter ::obj
      obj Mixin M1           ;# calls ::mixin setter ::obj M1
      obj Mixin add M1       ;# calls ::mixin add ::obj M1
    

    When we implement subcommands by delegating to other commands (as shown in the last example), there can be situations where naming conflicts might arise. For example, if we want to implement a subcommand method class we might not want to implement a new method class on the callee, since this would overwrite the standard definition of class. To overcome such difficulties, we provide the option -methodprefix. The following example shows how to prefix every called method with the prefix @.

      ###########################################
      # sketching extensible info
      ###########################################
      Object Info
      Info proc @mixin {o} {
        $o info mixin
      }
      Info proc @class {o} { ;# without prefix, doing here a [Info class] would be wrong
        $o info class
      }
      Info proc @help {o} { ;# define a new subcommand for info
        foreach c [my info procs] {lappend result [string range $c 1 end]}
        return $result
      }
      Object instforward Info -methodprefix @ Info %1 %self 
    
    With this definitions, the following call is rewritten as indicated in the comment.
      x1 Info class          ;# ::Info @class ::x1
    

    When a forwarder is defined, the callee (the target command) can be omitted. When the callee is not specified, the method-name is used instead. When the method-name has a namespace prefix, the method name is the tail and the callee is the fully qualified name.

      ###########################################
      # optional callee
      ###########################################
      obj set x 2
      obj forward append -objscope
      Object n; Object n::x
      obj forward ::n::x
    
    With this definitions of the forwarder append and x, the following calls are rewritten as indicated in the comment.
      obj append x y z        ;# ::append x y z ... returning  2yz
      obj x self              ;# ::n::x self    ... returning  ::n::x
    

    The forwarder append forwards the call to the Tcl command append, which accesses the instance variable x and appends the specified values.

    The list of tokens executed by the forwarder might contain Tcl commands executed during every invocations. This makes it for instance possible to pass instances variables to the callee. In the next example the object has the instvar named x which is multiplied by a factor of 10 when the method x* is invoked.

      ###########################################
      # command substitution
      ###########################################
      obj set x 10
      obj forward x* expr {%my set x} *
    
    With this definitions, the following call is rewritten as indicated in the comment.
      obj x* 10               ;# expr 10 * 10 ... returning  100
    

    In certain situations it is necessary to insert arguments always at the same position (e.g. at the second to last position). The positional addressing can be achieved by prefixing the arguments of the forward specification by %@POS , where POS is either a positive (argument positing from the beginning) or negative integer (argument counting from the end) or the constant end (denoting the last position). After POS a single space is used as a delimiter for the rest of the argument, which might be some other %-substitution or a constant. The positional arguments are evaluated from left to right and should be used in ascending order.

    The following examples show a few usages of the positional arguments in the forwarder. The forwarders f1 to f5 are created, followed by one or more usages. The first argument of the usage is the call to forewarder, the second argument is the result.

      ###########################################
      # forwarding with positional arguments
      ###########################################
      Object obj
      obj forward f1 list {%@end 13}
      ? {obj f1 1 2 3 } [list 1 2 3 13]
    
      obj forward f2 list {%@-1 13}
      ? {obj f2 1 2 3 } [list 1 2 13 3]
    
      obj forward f3 list {%@1 13}
      ? {obj f3 1 2 3 } [list 13 1 2 3]
      ? {obj f3} [list 13]
    
      obj forward f4 list {%@2 13}
      ? {obj f4 1 2 3 } [list 1 13 2 3]
    
      obj forward f5 {%@end 99} {%@0 list} 10
      ? {obj f5} [list 10 99]
      ? {obj f5 a b c} [list 10 a b c 99]
    

    The construct %argclindex LIST can be used to substitute an argument depending on the number of arguments when the forwarder is invoked. For example, it is possible to call forward to a different method depending on how many arguments are specified. The number of arguments is used as an index in the specified list. When the number of arguments is larger than the number of elements in the specified list, an error is generated.

      ###############################################
      # substitution depending on number of arguments
      ###############################################
      obj forward f %self [list %argclindex [list a b c]]
      obj proc a args {return [list [self proc] $args]}
      obj proc b args {return [list [self proc] $args]}
      obj proc c args {return [list [self proc] $args]}
      ? {obj f} [list a {}]
      ? {obj f 1 } [list b 1]
      ? {obj f 1 2} [list c {1 2}]
      ? {catch {obj f 1 2 3}} 1
    

    Finally, the concluding example defines a class chan to use the I/O-commands in an OO-manner. The proc open is used to create a chan instance. For the channel object we provide the method close (to close a channel and to destroy the channel object), puts (to write on a stream), blocked (to check whether last command exhausted all input), and fconfigure (to configure the stream). Note that for puts we specified that the actual stream should be inserted as the second to last argument.

      Class chan -parameter stream
      # create stream and object
      chan proc open args { 
        set stream [eval open $args]
        my create $stream -stream $stream  ;# make an object
      }
      # close stream and destroy object
      chan instproc close {} {
        close [my stream]
        [self] destroy
      }
      # handle other subcommands (methods) via unknown
      chan instproc unknown {m args} {
        set valid [lsort [chan info instcommands]]
        stderr puts "unknown chan method '$m' $args called; 
          	defined methods: $valid"
      }
      chan create stdout -stream stdout   ;# define standard stream
      chan create stderr -stream stderr   ;# define standard stream
    
      chan instforward puts puts {%@-1 %my stream}
      chan instforward blocked fblocked {%my stream}
      chan instforward fconfigure fconfigure {%my stream} 
    
      set c [chan open /tmp/junk w]
      $c puts -nonewline "hello"
      $c puts -nonewline " world"
      $c puts ""
      $c xxx                                       ;# trigger unknown
      # The stream instances denote the currently open streams
      stderr puts "currently open streams: [chan info instances]" 
      $c close
      stderr puts "currently open streams: [chan info instances]"
    

    Assertions

    In order to improve reliability and self documentation we added assertions to XOTcl. The implemented assertions are modeled after the ``design by contract'' concept of Bertrand Meyer. In XOTcl assertions can be specified in form of formal and informal pre- and post-conditions for each method. The conditions are defined as a list of and-combined constraints. The formal conditions have the form of normal Tcl conditions, while the informal conditions are defined as comments (specified with a starting ``#''). The lists containing the pre- and post-conditions are appended to the method definition (see example below).

    Since XOTcl offers per-object specialization it is desirable to specify conditions within objects as well (this is different to the concept of Meyer). Furthermore there may be conditions which must be valid for the whole class or object at any visible state (that means in every pre- and post-condition). These are called invariants and may be defined with following syntax for class invariants:

      className instinvar invariantList
    

    or for objects invariants:

      objName invar invariantList
    

    Logically all invariants are appended to the pre- and post-conditions with a logical ``and''. All assertions can be introspected.

    Since assertions are contracts they need not to be tested if one can be sure that the contracts are fulfilled by the partners. But for example when a component has changed or a new one is developed the assertions could be checked on demand. For this purpose the check method can be used either to test the pre- or the post-conditions. The syntax is:

      objName check ?all? ?instinvar? ?invar? ?pre? ?post?
    

    Per default all options are turned off. check all turns all assertion options for an object on, an arbitrary list (maybe empty) can be used for the selection of certain options. Assertion options are introspected by the info check option. The following class is equipped with assertions:

      Class Sensor -parameter {{value 1}}
      Sensor instinvar {
        {[regexp {^[0-9]$} [my value]] == 1}
      }
      Sensor instproc incrValue {} {
        my incr value
      } {
        {# pre-condition:} 
        {[my value] > 0}
      } {
        {# post-condition:} 
        {[my value] > 1}
      }
    

    The parameter instance method defines an instance variable value with value 1. The invariant expresses the condition (using the Tcl command regexp), that the value must be a single decimal digit. The method definition expresses the formal contract between the class and its clients that the method incrValue only gets input-states in which the value of the variable value is positive. If this contract is fulfilled by the client, the class commits itself to supply a post-condition where the variable's value is larger than 1. The formal conditions are ordinary Tcl conditions. If checking is turned on for sensor s:

      s check all
    

    the pre-conditions and invariants are tested at the beginning and the post-condition and invariants are tested at the end of the method execution automatically. A broken assertion, like calling incrValue 9 times (would break the invariant of being a single digit) results in an error message.

    In assertions we do not check methods that modify or introspect assertions. These are check,info,proc,instproc,invar, and instinvar. The reason for this is that we want to be able to recover a malicious action in a catch error handler, like:

      ...
      if {[catch {my assertionBreakingAction} errMsg]} {
        puts "CAUGHT ERROR: $errMsg"
        # remember checking options, for turning them on later again
        set check [my info check]
        my check {}
        # recover from broken assertion
        ...
        # turning checking on again 
        $fb check $check
      }
    

    Meta-Data and Automatic Documentation

    To enhance the understandability and the consistency between documentation and program it is useful to have a facility to make the documentation a part of the program. There are several kinds of meta-data which are interesting for a class, e.g. the author, a description, the version, etc.

    Older versions of XOTcl have contained a special meta-data command metadata. This command is now (from version 0.83) deprecated and replaced by an integrated solution with XOTcl's API documentation functionality. The object @ is used for documentation and metadata issues. Per default it is not evaluated at all. Everything that is send to @ is simply ignored. That way we do not waste memory/performance at runtime, if we do not require to parse the metadata/documentation.

    If we have to know the meta-data/documentation, as for instance in the xoDoc component and the makeDoc tool, that handle XOTcl's internal documentation, we have to re-define the documentation object. Alternatively, we can partially parse the source code for @ commands.

    With @ the meta-data/documentation is handled by first class XOTcl objects. By defining alternate @ implementations - as in xoDoc/makeDoc - we can evaluate the meta-data/documentation arbitrarily. xoDoc/makeDoc are only an HTML back-end, but the basic idea is to provide support for several other usages as well (e.g. XML, RDF, on-line help, documentation of dynamic structures, etc).

    The object@ handles comments via its unknown method. xoDoc adds the appropriate instprocs to t@ to produce HTML output. The appropriate command is:

      tclsh src/lib/makeDoc.xotcl DOCDIR DOCFILES
    

    The source of a documentation is structurally very similar to the XOTcl constructs being commented. E.g. one can copy an instproc and add comments at the right places, like:

        Class C
        C instproc m {a1 a2} {
           return [expr {$a1+$a2}]
        }
    

    can be commented as follows

        @ Class C { description { "my sample class"} }
        @ C instproc m {a1 "first number" a2 "second number"} {
           description "add two numbers"
           return "sum of a1 and a2"
        }
    

    One can do essentially a copy+paste of the source and add the comments via attribute value pairs. Every basic language construct can have a "description". If you want to include other properties to the description, you can add them like:

        @ C instproc m {a1 "first number" a2 "second number"} {
           author "GN+UZ"
           date "Feb 31"
           description "add two numbers"
           return "sum of a1 and a2"
        }
    

    This way, author and date are added automatically to the generated HTML file. In addition, there is a @File hook for a per file description, like:

    @ @File {
      description {
        This is a file which provides a regression test
        for the features of the XOTcl - Language. 
      }
    }
    

    Additional Functionalities

    Abstract Classes

    In XOTcl a class is defined abstract if at least one method of this class is abstract. The instance method abstract defines an abstract method and specifies its interface. Direct calls to abstract methods produce an error message. E.g. a Storage class provides an abstract interface for access to different storage forms:

      Class Storage
      Storage abstract instproc open  {name}       
      Storage abstract instproc store {key value}
      Storage abstract instproc list  {}         
      Storage abstract instproc fetch key        
      Storage abstract instproc close {}         
      Storage abstract instproc delete {k} 
    

    All kinds of storage have to implement every method from the interface. E.g. a GNU Database Access, a relational database access, and several other storage forms may be derived by sub-classing (therefore, all conform to the same storage access interface).

    Checking Commands for being Objects, Classes, or Meta-Classes

    Since XOTcl is a hybrid language containing several Tcl commands, sometimes its necessary for applications to distinguish between Tcl commands and object commands for XOTcl. method of the Object class looks up an objName and returns 1 if it is an object and 0 if not:

      objName1 isobject objName2
    

    If one can be sure that a command represents an object, it might be unsure if the command is only an object or also class or even meta-class. The two instance methods isclass and ismetaclass check in the same manner, whether a class or meta-class is given (since ever XOTcl class is an object, they also return 0, when objName is not an XOTcl object).

      objName1 isclass objName2
      objName1 ismetaclass objName2
    

    Exit Handler

    A task for a programming language, sometimes of similar importance as object creation, is the object destruction. XOTcl ensures that all objects are destroyed and their destructors are invoked when XOTcl applications terminate. For that reason objects and classes are destroyed in the order objects, classes, meta-classes. Sometimes further destruction order is of importance. For these cases, the XOTcl language provides an exit handler, which is a user-defined proc, which invokes user-defined exit handling just before the destruction of objects, classes, meta-classes is invoked. For instance, the exit handler lets the user specify objects which have to be destroyed before all other objects.

    The exit handler is defined as a proc of Object, which is per default empty:

      ::xotcl::Object proc __exitHandler {} {
        # clients should append exit handlers to this proc body
        ;
      }
    

    There are some procs of the Object class pre-defined, which let us specify an exit handler conveniently:

       Object setExitHandler body
       Object getExitHandler
       Object unsetExitHandler
    

    setExitHandler lets us specify a proc body that actually contains the user-defined exit handling:

       Object setExitHandler {
         aObj destroy
         puts "exiting"
       }
    

    destroys the object aObj before all other objects and prints the message existing to the screen. With getExitHandler the exit handler can be introspected. E.g. if we just want to append the destruction of object bObj to an existing exit handler, we use getExitHandler:

       Object setExitHandler "[Object getExitHandler]; bObj destroy"
    

    unsetExitHandler deletes the exit handler.

    
    

    Automatic Name Creation

    The XOTcl autoname instance method provides a simple way to take the task of automatically creating names out of the responsibility of the programmer. The example below shows how to create on each invocation of method new an agent with a fresh name (prefixed with agent):

      Agent proc new args {
        eval my [my autoname agent] $args
      }
    

    Autonames may have format strings as in the Tcl 'format' command. E.g.:

      objName autoname a%06d
    

    produces

      a000000, a000001, a000002, ...
    

    Integrating XOTcl Programs with C Extensions (such as TK)

    Because all XOTcl commands are in the ::xotcl namespace, it is usually no problem to integrate XOTcl with other Tcl extensions. Most often it works to import the XOTcl commands (like Object, Class) into the current namespace because there are no name-clashes with the commands defined by other extensions.

    Consider you want to perform a deeper integration of another extension and XOTcl because you want to benefit from XOTcl's object system. For instance, you might want to introduce composite TK widgets (sometimes called mega-widgets) as classes and inherit from these classes. Here, you have two options: you can change or extend the C code of that other extension to provide XOTcl classes or objects, or you can write an XOTcl wrapper in Tcl. For the first alternative, there are some examples provided in the XOTcl distribution. XOTclGdbm provides an OO Tcl interface to the GDBM database, for instance. XOTclSdbm does the same for SDBM, and the TclExpat wrapper provides a class-based interface to the TclExpat XML parser.

    Consider you do not want to change the C code of a Tcl extension. Then you can write an OO wrapper in XOTcl for the commands of the other extension. For stateless commands, you can simply write forwarder methods. If the extension maintains some state, you typically associate the state handle with an XOTcl parameter, acquire the state in the XOTcl constructor, and align the XOTcl destructor with the stateful instance.

    Consider you want to wrap the Tk button widget. You can acquire the widget in the constructor, and maintain the widget ID in a parameter. You now can forward invocations to this widget ID (e.g. when using "pack"), or register command callbacks (like buttonPressed). Note that we let the "self" command be replaced in the scope of the current method so that TK receives the correct object ID for the callback. In the destructor we destroy the widget as well (we use "catch" because sometimes widgets can destroyed by other means as well (e.g. by their parent widget, when a widget/object hierarchy is destroyed at once).

      Class MyButton -parameter {button}
      MyButton instproc buttonPressed args {
        puts "pressed [my button]"
      }
      MyButton instproc init args {
        set ID [namespace tail [self]]
        my instvar button
        set button [button .$ID \
          -text "My Button $ID" \
          -command [list [self] buttonPressed]] 
        pack $button
        next
      }
      MyButton instproc destroy args {
         catch {destroy [my button]}
         next
      }
    
      # a test -> 3 buttons, destroy one of them
      foreach b {a b c} {
        MyButton $b
      }
      b destroy
    

    The "trick" to substitute "self" within the current method scope works for all kinds of command callbacks. Extensions such as TK, however, often work with bindings to (global) variables as well. Using global variables is frowned upon in the OO community. Instead you should use instance variables of objects. As Tcl can only bind to existing namespace variables (and XOTcl acquires the namespace of an object on demand), you have to make sure that the namespace of an object exists before binding a variable. That can be done with "requireNamespace":

      GUIClass instproc buildEntry win {
        my requireNamespace
        entry $win -textvariable [self]::entryValue
        my set entryValue {Init Value}
      }
    

    Note that in the above example we have used to tail of the object ID as ID for the widget. Usually, it is a good idea to the object name, if possible, for TK (and other extensions) IDs as well. Another option is to use a autoname to get a unique name for the ID.

    Sometimes you want to simply send all invocations, not implemented by XOTcl, to the wrapped command. Here, it is tedious to write a wrapper for each of these methods. Instead you can use "unknown" to handle automatic forwarding. Consider you want to wrap TK commands like pack and replace XOTcl object names with their TK widget ID, so that you can use both IDs synonymously. You can rename the respective TK commands in the following way:

      foreach tkCommand {bell bind bindtags clipboard event 
        focus font grid image lower option pack place raise 
        selection send tk tkwait winfo wm} { 
        rename ::$tkCommand __tk_$tkCommand
        TkCommand ::$tkCommand
        ::$tkCommand set wrapped __tk_$tkCommand
      }
    

    The XOTcl class handling the ID substitution for the TK command might look as follows:

      Class TkCommand -parameter wrapped
      TkCommand instproc unknown args {
          my instvar wrapped
          set args [Widget replaceWithWidgetIDs $args]
          # now call the command
          eval $wrapped $args
      }
    

    References

    [Zdun, Strembeck, Neumann 2007] U. Zdun, M. Strembeck, G. Neumann: Object-Based and Class-Based Composition of Transitive Mixins, Information and Software Technology, 49(8) 2007 .

    [Neumann and Zdun 1999a] G. Neumann and U. Zdun. Filters as a language support for design patterns in object-oriented scripting languages. In Proceedings of COOTS'99, 5th Conference on Object-Oriented Technologies and Systems, San Diego, May 1999.

    [Neumann and Zdun 1999b] G. Neumann and U. Zdun. Implementing object-specific design patterns using per-object mixins. In Proc. of NOSA`99, Second Nordic Workshop on Software Architecture, Ronneby, Sweden, August 1999.

    [Neumann and Zdun 1999c] G. Neumann and U. Zdun. Enhancing object-based system composition through per-object mixins. In Proceedings of Asia-Pacific Software Engineering Conference (APSEC), Takamatsu, Japan, December 1999.

    [Neumann and Zdun 2000a] G. Neumann and U. Zdun. XOTCL, an object-oriented scripting language. In Proceedings of Tcl2k: The 7th USENIX Tcl/Tk Conference, Austin, Texas, February 2000.

    [Neumann and Zdun 2000b] G. Neumann and U. Zdun. Towards the Usage of Dynamic Object Aggregations as a Form of Composition In: Proceedings of Symposium of Applied Computing (SAC'00), Como, Italy, Mar 19-21, 2000.

    [Ousterhout 1990] J. K. Ousterhout. Tcl: An embeddable command language. In Proc. of the 1990 Winter USENIX Conference, January 1990.

    [Ousterhout 1998] J. K. Ousterhout. Scripting: Higher Level Programming for the 21st Century, IEEE Computer 31(3), March 1998.

    [Wetherall and Lindblad 1995] D. Wetherall and C. J. Lindblad. Extending Tcl for Dynamic Object-Oriented Programming. Proc. of the Tcl/Tk Workshop '95, July 1995. ./nsf2.4.0/library/xotcl/doc/Announce-1.6.2000644 000766 000024 00000002563 12501766547 020710 0ustar00neumannstaff000000 000000 Dear XOTcl Community, XOTcl 1.6.2 is available. See below for more details. Best regards -gustaf neumann Announcing XOTcl 1.6.2 ************************* We are pleased to announce the availability of XOTcl 1.6.2 Major changes relative to 1.6.1 are: * Functional extensions: - handle nonposargs in method "copy" properly - new command ::xotcl::finalize (for forcing cleanup and destuctor execution at a time in a multi-threaded environment, where it is still safe to execute all Tcl commands) * Extended and generalized "info" method - Added " mixinof -closure ?pattern?" Query the objects for which is used as a per-object-mixin (directly or indirectly) * Fixes for potential crashes - Implemented proper downgrading of Classes to Objects (handle cases, where something was created first as an object and is reclassed/recreated later as a class) and vice versa - Reset mixin order for per-object mixins, when the superclass of a class is deleted, which is used as per-object mixin * Improved documentation * Extended regression tests * Some code cleanup For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org ./nsf2.4.0/library/xotcl/doc/Announce-1.6.5000644 000766 000024 00000001173 14274464576 020715 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.6.5 ************************* Dear XOTcl Community, We are pleased to announce the availability of XOTcl 1.6.5 Major changes relative to 1.6.4 are: * fixed namespace visibility problem reported by Mykhaylo Sorochan * fixed var resolver/memory leak problem reported by Victor Mayevski (when XOTcl is compiled against Tcl 8.4.*, but loaded into 8.5.*) For more details about the changes, please consult the ChangeLog and documentation. The planned next release will be 2.0.0 MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org ./nsf2.4.0/library/xotcl/doc/Announce-1.4.1000644 000766 000024 00000017333 12501766547 020706 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.5.0 ************************* Hi everybody. I am pleased to announce the availability of XOTcl 1.5.0. Major changes relative to 1.4.0 are: * Improved Functionality + The C-level implementation of XOTcl create now the basic classes ::xotcl::Object and ::xotcl::Class completely without any methods. All predefined methods are now registered from the initialization script-code (predefined.xotcl) via the new command ::xotcl::alias | \ ?-objscope? ?-per-object? which is used for registering predefined Tcl commands as methods. These aliases are like zero cost forwarders, since they lookup the function pointer from the commands and used these in the methods. This change makes it possible to register the same command on different classes (with maybe different names), such that for example the predefined set method of ::xotcl::Object can be replaced with a different method and the set method can be registered on some other classes (maybe some application classes). This change makes it as well quite easy to use the XOTcl framework to develop some other object oriented frameworks. + slots TODO documentation of slots TODO remove TODO optimize via parametercmd TODO parametercmd with 3+ args TODO info parameter deprecated A slot is a meta-object that manages property-changes of objects. A property is either an attribute or a role of an relation. In a nutshell, a slot has among other attributes - a name (which it used to access it), - a domain (object or class on which it can be used) , and - can be multivalued or not We distinguish between system slots (predefined slots like class, superclass, mixin, instmixin, filter, instfilter) and application slots (e.g. attributes of classes). System Slots ======== System slots are predefined slots defining e.g. some relations between classes, or between objects and classes. The predefined system slots are: - superclass: every class in XOTcl has one or more superclasses. The name of this slot is "superclass", the domain is "::xotcl::Class", the slot is multivalued. One object might have multiple superclasses. - class: every object has a class; therefore, the domain of the slot is "::xotcl::Class", the property is not multivalued. - mixin: every object in XOTcl can have one or more mixin classes. The name of this slot is "mixin", the domain is "::xotcl::Object", the slot is multivalued. - instmixin: same as above, but the domain is "::xotcl::Class" - filter, instfilter: similar to "mixin" and "instmixin" Every slot can be used set and query the property from its domain. The syntax for setting values is newValue replace newValue and for getting its values is set x [ ] TODO "mixin set" -> "mixin assign" TODO "mixin set" -> "mixin replace" TODO "mixin set" -> "mixin reset" TODO "mixin delete" -> "mixin remove" where the first form is in both cases the short form of the second one. Every multivalued slot has as well a method "add" and "remove" Examples for using the system slot "mixin" Object o; Class M; class N o mixin ::M ;# replacing the per-object mixins of o with M o mixin reset ::M ;# same as before o mixin add ::N ;# add N to the front of the mixin list o mixin delete ::M ;# delete M from the mixin list puts [o mixin] ;# query the current mixin list Every system slot (e.g. superclass) has the exact same interface. Attribute Slots ========= Attribute slots are used to manage the setting and querying of instance variables. We define now a person with three attributes,"name", "salary" and "projects". Class Person -slots { Attribute name Attribute salary -default 0 Attribute projects -default {} -multivalued true } These attributes might have a default value or they might be multivalued. When an instance of class Person is created, the slot names can be used for specifying values for the slots. Person p1 -name "Joe" Object p1 has three instance variables, namely "name", "salary" and "projects". Since slot "projects" is multivalued, we can add values the "add" subcommand. Project project1 -name XOTcl \ -description "A highly flexible OO scripting language" p1 projects add ::project1 p1 projects add some-other-value The value of the instance variable "project" of Person p1 is now the list "some-other-value ::project1" Type Checking ========= Attribute slots can have types assigned which are tested whenever the instance variable is altered. The slot "salary" is defined as integer whereas "projects" is defined to be a list of instances of the class Project (a list, since "projects" is defined as multivalued). Class Person -slots { Attribute name Attribute salary -default 0 -type integer Attribute projects -default {} -multivalued true -type ::Project } Person p2 -name "Sue" -salary 1000 The slot types are checked via Tcl variable traces. This means that the values are enforced now matter how the variables are accessed. The checks are performed in the following two commands, and they will throw an error in the second command, since "1100x" is not an integer. p2 incr salary 100 p2 append salary x similarly the second command below will through an error, since some-other-value is not an instance of ::Project. p2 projects add ::project1 p2 projects add some-other-value When a check throws an error, the instance variables are reset to the previous value. To restore the original value, an associative array "__oldvalue()" is kept as instance variable in the object. In general, checking of variables can be turned off globally by "::xotcl::Slot instmixin add ::xotcl::Slot::Nocheck". It can be turned off selectively for each slot via a per-object-mixin; if attributes are subclassed, it is possible to register the "Nocheck" mixin on a subclass of Attribute. procsearch returns for forwarders now "forward" or "instforward", for parametercmds now "parametercmd" or "instparametercmd" and for other commands "cmd" and "instcmd" info slots TODO slow -superclass TODO king of the bongo + improved forwarding ... expr earlybinding %argclindex + improved serializer - handling of slot dependencies - - * Improved code quality: + fixed a bug with nonpositional arguments, some positional arguments and "args" + fixed a bug in nonpositional arguments when called without arguments + improved error messages in connection with nonpositional arguments + more regression tests added For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/index.html000644 000766 000024 00000004761 12155266027 020545 0ustar00neumannstaff000000 000000 The Extended Object Tcl (XOTcl) Documentation contains the following parts:

    XOTcl Language Documentation

    Package and Script Documentation

    This section of the documentation is under work...

    Tcl Online Information

    ./nsf2.4.0/library/xotcl/doc/cascaded-message-filter.gif000644 000766 000024 00000013571 12501766547 023701 0ustar00neumannstaff000000 000000 GIF87aot@sX/FcameTr-z骥N5ح,!'{$"whDmCGl~b).> g6f49; _ǂ(m~/[&/6]V0. iN}f{Sjf앻u (bE`~q% $Qsu_2DޑL$NP-y,m[A|{ET5IWt9F˟Ysh׼3򩝾,•.4VFwK։.x|Y T+m܁ >(Aݞ|8ż0gxs.:Ӥk˝T(e;欃w;zg{R%<휢+,ѳ?|LG8[&?u۶Zf?钯~.?ǯ^+EveYF:fk'H K d z IoD$K>WU/KCH(CЇ=`룺3y D qnDX7M5!<`a?IqZp2ΰX<ը $4=x,3vll (8)-H <$3661bHIZ$`@В`$'!+,fIKZ04a[9:TRn0ILa`u%KIdd0Ijl!&uif"$irV)!HOS2 *T+ns_LEE>u@(XCZU&.DӪc ~u+\ZƫUtZ!}:b] @_TBTe[g8Xd% Ps ehWĖk!C3ɚMeYu"4gQUnw[´lIZGrvc+:7mY *:JhOzfh];T%m\sQ 弁o.byj_]ʆ"pr`&XeXcCךݰahMI ^)^{t~X㌭RaSK%d8M!_^9/NL:e+?u1eH==kX31th5Q}ekigY~]3ZR6Ȍ5YZSaHז'bjz&`1:%=S',x`rNbaab:d˹=~oy G6Yl[3{nk vD^[`v0?W~ C7r}}um}9xe{o\[߱}s=Rr]u[smUmaS-x\uiNb-۪]g8ऴvINp~Gu99B'Z47 t^:nNC^ʮC٪WĞd%WF>3YvDN'%vN^ɗa Jhsgiz={ϭ.gFx9Wث!Q^fyS4 W]_ҸC=4\z{ݴo>xj7{5]\|1% ko(|k&ܼԩA-%{37(7OzD> 5X~4g{eop#3)R3-%=%!7#scѤRB6Q8's~!~~ken:""R+"w{attbwM8@h9ח A%O3b!W3xIׂ66es6r(KW壂&wTS]Z<=[gMsRIWXIt6mSrb>.W[{xуjxjXM!n(`s?D6e#wXwǓ3ψ󊀷,$h &8e<{XC|R74zG3x)2g86u $ ĒH*153(2$ $=ґ-)Ci7woUr2"yP9;Uf8@h/$s~f<27"4[HG(Ɠ?Rf!h9ijJX'2ǕE(c27&BA Ww(;vcz0 sSU::ԗ|tB Ǚ3GoHS)xu19 7$9?0PZ䒀F2ƕgƏ#E2{AwF ;4'}=j VY1YE!iș@v5ZR1ŞWV8+nzY9/a:ZXUɛ.fI9MڞZ#J;c5zi/g|(BiL˥hi| :e.bЃ}YCڜE,Yo(iOʗQjL @YH9טpo@BZ] bj;Z:<٥^`J(5j*b~)Tç駥I=ikokɨg2Jijo ^JYm j:ډ ڊZ\q$s7\D;ђ}Oq,pMp1MCK9acEM2}T]{kNJ!o8l-sNPKL- -eϫrsm;ցZ\]I 0mmmo ׎؏`YӠ+wԐHm<֫Ceos}>HkAxڎOi=&< cfv*k͝6o Eں~m}-ϭQ-@ ujMh-ڴTږn`+]Z}i ǐg8'"m$ifݲUfVd^&NXۻ5Rb' b*,^52}/d=.-f%2GbNCE:QgS~qV>nQ5[]ޡegiUbVY^<UVe9C"z{?^ay>wfۇNk_NnW(b5[%X;z,GY}*1Xg X>Uꪾnd~uVѵWV>tӛ٫==R.>AiXTNZ~J_>V㎍N7vmT.0P.nV^-KeNy]~>H~KZtI/LeKtE߇4r n,)"2^(w3n,9L;?_S5/FEQHk XMYDCSh7@?Q^%?G;L2zhnq;./nsf2.4.0/library/xotcl/doc/Announce-1.4.0000644 000766 000024 00000003116 13547037517 020676 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.4.0 ************************* Hi everybody. I am pleased to announce the availability of XOTcl 1.4.0. Major changes relative to 1.3.9 are: * Improved Functionality * new option: ::xotcl::configure softrecreate on|off if softrecreate is set, class relations (superclass, subclass, class, instances) are not affected by a recreate; this allows files with class definitions more easily to reload + easier syntax for providing commands for initializing default values + setting and querying options for ::xotcl::configure similar to set * Improved code quality: + fixed a bug in connection with nonpositional arguments and "args" + fixed a bug with adding on the fly transitive mixin classes + fixed a bug with filter states after next + fixed omitted error message after calling self with unknown subcommands + fixed a bug with variable traces on thread exit (triggered by volatile) + fixed incorrect rpm dependencies + cleaner compile for xotcl for gcc 4.* under linux + don't destroy namespace imported child objects + info children returns true children, not namespace imported objects/classes + unsetting the global variable "cmd" from predefined.xotcl + Upgraded TEA to 3.5 + more regression tests addeed For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/Announce-1.6.4000644 000766 000024 00000001033 12501766547 020701 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.6.4 ************************* Dear XOTcl Community, We are pleased to announce the availability of XOTcl 1.6.4 Major changes relative to 1.6.3 are: * 2 fixes of potential crashes introduced in 1.6.3 * Improved documentation (added "stack" as introductory example) For more details about the changes, please consult the ChangeLog and documentation. The planned next release will be 2.0.0 MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org ./nsf2.4.0/library/xotcl/doc/Announce-1.6.3000644 000766 000024 00000002603 12501766547 020704 0ustar00neumannstaff000000 000000 Dear XOTcl Community, XOTcl 1.6.3 is available. See below for more details. Best regards Gustaf Neumann Announcing XOTcl 1.6.3 ************************* We are pleased to announce the availability of XOTcl 1.6.3 Major changes relative to 1.6.2 are: * Functional improvements: - simplified and generalized handling of namespaced instance variables, where namespaced associative arrays could conflict with global variables due to Tcl's default namespace resolution. Many thanks to Stefan Sobernig for this contribution! * Fixes: - Corrected deletion of meta-classes. Before, it was possible to create undestroyable objects via complex meta-class structures * Speed improvements: - Use of new interfaces in Tcl 8.5 (when compiled with Tcl 8.5) - simplified interfaces for various C functions - Speed improvement for method invocation: * With Tcl 8.5: 10-15 % * With Tcl 8.4: 5-10 % * Improve code quality: - some more code cleanup - factoring out common code - using const in more cases * Extended regression tests * Improved documentation For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org ./nsf2.4.0/library/xotcl/doc/xo-whichPkg.html000644 000766 000024 00000003135 12155266027 021620 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/xotcl/apps/utils/xo-whichPkg

    ./library/xotcl/apps/utils/xo-whichPkg ./library/xotcl/apps/utils/xo-whichPkg


    Package/File Information

    No package provided/required

    Filename: ./library/xotcl/apps/utils/xo-whichPkg

    Description: A small sample script to show which package is loaded from where when a target package is loaded.

    Usage: "xo-whichPkg -pkg PACKAGENAME"

    Authors: Fredj Dridi dridi@nestroy.wi-inf.uni-essen.de
    Date: [::xotcl::rcs date {$Date: 2006/02/18 22:17:32 $}]



    Back to index page.

    ./nsf2.4.0/library/xotcl/doc/Announce-1.0.1000644 000766 000024 00000002733 13464226761 020676 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.0.1 ********************** WHAT IS XOTCL? XOTcl is an object-oriented extension of Tcl that was derived from OTcl. In short, XOTcl tries to provide a highly flexible, reflective, component-based, and object-oriented environment. It integrates language support for high-level concepts which are not found in other languages, with reasonable performance. It prevails the Tcl programming style and the dynamic/introspective nature of the language, rather than introducing other language's styles and rigidness (such as C++) into Tcl. CHANGES relative to 1.0 are: - fixes: * fixed installation bug on windows (when installed on drives different to c:) * fixes for AOLserver 3.5.* * fix for "object info default arg var" in connection with filters * Serializer handles filter guards now - new functionality and improvements: * improved recreate semantics, makes it easier to overload recreation logic. * new method "noinit" to create objects without calling the constructor - optimizations: * general speedup (10 to 15%) by using client data of namespace instead of Tcl_AssocData for interpreter state * faster and more flexible Serializer For more details, please consult the ChangeLog MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/langRef.xotcl000644 000766 000024 00000164370 13563204775 021212 0ustar00neumannstaff000000 000000 # -*- tcl -*- package provide XOTcl-langRef 2.0 package require XOTcl 2.0 namespace eval ::xotcl {} namespace import -force ::xotcl::@ # catch { # @ XXX x x # } msg # puts stderr $::errorInfo if {$::tcl_version >= 8.6} { # # Without this [namespace which] (or any other [namespace *] # command, the previously ::nxdoc::@ is called, rather than the # imported ::xotcl::@?!?! # namespace which @ } @ @File { description { XOTcl language reference. Describes predefined objects and classes. } "predefined primitives" { XOTcl contains the following predefined primitives (Tcl commands):
    <@tt>self<@/tt>
    computes callstack related information. It can be used in the following ways: <@UL> <@LI><@TT>self - returns the name of the object, which is currently in execution. If it is called from outside of a proc, it returns the error message ``<@TT>Can't find self''. <@LI><@TT>self class - the self command with a given argument <@TT>class returns the name of the class, which holds the currently executing instproc. Note that this may be different to the class of the current object. If it is called from a proc it returns an empty string. <@LI><@TT>self proc - the self command with a given argument <@TT>proc returns the name of the currently executing proc or instproc. <@li><@TT>self callingclass: Returns class name of the class that has called the executing method. <@li><@TT>self callingobject: Returns object name of the object that has called the executing method. <@li><@TT>self callingproc: Returns proc name of the method that has called the executing method. <@li><@TT>self calledclass: Returns class name of the class that holds the target proc (in mixins and filters). <@li><@TT>self calledproc: Returns method name of the target proc (only applicable in a filter). <@li><@TT>self isnextcall: Return 1 if this method was invoked via next, otherwise 0 <@li><@TT>self next: Return the "next" method on the precedence path as a string. <@li><@TT>self filterreg: In a filter: returns the name of the object/class on which the filter is registered. Returns either 'objName filter filterName' or 'className instfilter filterName'. <@li><@TT>self callinglevel: Returns the calling level, from where the actual proc was called from. Intermediary next calls are ignored in this computation. The level is returned in a form it can be used as first argument in <@TT>uplevel or <@TT>upvar. <@li><@TT>self activelevel: Returns the level, from where the actual proc was invoked from. This might be the calling level or a next call, whatever is higher in the stack. The level is returned in a form it can be used as first argument in <@TT>uplevel or <@TT>upvar. <@/UL> <@/p>
    <@tt>my methodName<@/tt>
    is a short form for <@tt>[self] methodName and can only be called in a context of an instproc or a method specific proc. It allows certain optimizations and shorter to write. <@/p><@p> <@tt>next <@/tt>
    invokes the next shadowed (same-named) method on the precedence path and returns its result. If <@tt>next is called without arguments, the arguments of the current method are passed through the called method. If <@tt>next is invoked with the flag <@tt>--noArgs, the shadowed method is called without arguments. If other arguments are specified for next, these will be used for the call. <@/dd>
    <@tt>myvar varName
    returns the fully qualified variable name of the specified variable.

    <@tt>myproc methodName ?args?
    calls the specified XOTcl method without the need of using "<@tt>[list [self] methodName ...]".

    <@tt>::xotcl::alias class|obj methodName ?-objscope? ?-per-object? cmdName
    can be used to register a predefined C-implemented Tcl command as method <@tt>methodName. The option <@tt>-objscope has the same meaning as for forwarder (instance variables of the calling object appear in the local scope of the Tcl command), <@tt>-per-object has the same meaning as for the method <@tt>method (when used on a class, the method is registered for the class object only, but not for the instances). This command can be used to bootstrap xotcl (when e.g. no methods are available).

    ::xotcl::configure filter ?on|off?<@/tt>
    allows one to turn on or off filters globally for the current interpreter. By default, the filter state is turned off. This function returns the old filter state. This function is needed for the serializer that is intended to serialize the objects classes independent of filter settings.

    <@tt>::xotcl::configure softrecreate ?on|off?<@/tt>
    allows one to control what should happen, when an object / a class is recreated. Per default it is set off, which means that the object/class is destroyed and all relations (e.g. subclass/superclass) to other objects/classes are destroyed as well. If <@tt>softrecreate is set, the object is reset, but not destroyed, the relations are kept. This is important, when e.g. reloading a file with class definitions (e.g. when used in OpenACS with file watching and reloading). With <@tt>softrecreate set, it is not necessary to recreate dependent subclasses etc.

    Example: e.g. there is a class hierarchy A <- B <- C Without <@tt>softrecreate set, a reload of B means first a destroy of B, leading to A <- C, and instances of B are re-classed to ::xotcl::Object. When <@tt>softrecreate is set, the structure remains unchanged.

    <@tt>::xotcl::finalize<@/tt>
    Delete all XOTcl objects and classes and free all associated memory.

    This command has the only purpose to delete all objects and classes of an interpreter in a multi-threaded environment at a safe time.

    Background: when XOTcl is used in a threaded environment such as for example in AOLserver, one has to take care that the deletion of objects and classes happens in a safe environment, where the XOTcl destructors (destroy methods) are still able to run. Without ::xotcl::finalize the deletion happens in Tcl_FinalizeThread(), after thread cleanup (where e.g. the thread local storage is freed). This can lead to memory leaks in AOLserver, which allocates e.g. some structures on demand, but since this happens after cleanup, it will leak. A simple ns_log in a destructor might lead to this problem. The solution is to call ::xotcl::finalize in the "delete trace" in AOLserver (as it happens in OpenACS).

    Note that ::xotcl::finalize is not intended for application programs.

    } } ## ## Object methods ## @ Class Object { description { This class holds the pre-defined methods available for all XOTcl objects. All these methods are also available on classes. } } @ Object instproc abstract { methtype "instproc or proc" methodName "name of abstract method" arglist "arguments" } { Description { Specify an abstract method for class/object with arguments. An abstract method specifies an interface and returns an error, if it is invoked directly. Sub-classes or mixins have to override it. } return "error" } @ Object instproc append { varName "name of variable" args "arguments to append" } { Description { Append all of the value arguments to the current value of variable varName. Wrapper to the same named Tcl command (see documentation of Tcl command with the same name for details). } return "empty string" } @ Object instproc array { opt "array option" array "array name" ?args? "args of the option" } { Description { This method performs one of several operations on the variable given by arrayName. It is a wrapper to the same named Tcl command (see documentation of Tcl command with the same name for details). } return "diverse results" } @ Object instproc autoname { ?<-instance>|<-reset>? "Optional modifiers: <@br> '-instance' makes the autoname start with a small letter.<@br> '-reset' resets the autoname index to 0." name "base name of the autoname"} { Description { autoname creates an automatically assigned name. It is constructed from the base name plus an index, that is incremented for each usage. E.g.: <@pre class='code'> $obj autoname a produces a0, a1, a2, ... Autonames may have format strings as in the Tcl 'format' command. E.g.: <@pre class='code'> $obj autoname a%06d produces a000000, a000001, a000002, ... } return "newly constructed autoname value" } @ Object instproc check { options "none, one or more of: (?all? ?pre? ?post? ?invar? ?instinvar?)" } { Description { Turn on/off assertion checking. Options argument is the list of assertions, that should be checked on the object automatically. Per default assertion checking is turned off.
    Examples:
    <@pre CLASS="code"> o check {}; <@i># turn off assertion checking on object o o check all; <@i># turn on all assertion checks on object o o check {pre post}; <@i># only check pre/post assertions } return "empty string" } @ Object instproc class { newClass "?new class?" } { Description { Changes the class of an object dynamically to <@tt>newClass. The method returns the current value of class, when it is called without arguments. } return "if <@tt>newClass is not specified return class, otherwise empty" } @ Object instproc cleanup { ?args? "Arbitrary arguments passed to cleanup" } { Description { Resets an object or class into an initial state, as after construction. Called during recreation process by the method 'recreate' } return "empty string" } @ Object instproc configure { ?args? "'-' method calls" } { Description { Calls the '-' (dash) methods. I.e. evaluates arguments and calls everything starting with '-' (and not having a digit a second char) as a method. Every list element until the next '-' is interpreted as a method argument. configure is called before the constructor init during initialization and recreation. In the following example, the variable set is called via configure before init: <@pre class='code'> Object o -set x 4 The method configure can be called with the dash-notation at arbitrary times: <@pre class='code'> o configure -set x 4 Note that if '-' is followed by a numerical, the arument is interpreted as a negative number (and not as a method). If a value of a method called this way starts with a "-", the call can be placed safely into a list (e.g. "Class c [list -strangearg -a-] -simplearg 2").

    See also create. } return "number of the skipped first arguments" } @ Object instproc contains { "?-withnew?" "Option to overload new to create new objects within the specified object. Per default, this option is turned on." "?-object?" "object, in which the new objects should be created. The default is the object, for which contains>/tt> was called." "?-class?" "In combination with option -object: If the specified object does not exist, create it from the specified class. The default is ::xotcl::Object" cmd "Tcl command to create multiple objects" } { Description { This method can be used to create nested object structures with little syntactic overhead. The method changes the namespace to the specified object and creates objects there. Optionally, a different object scope can be specified and creating new objects in the specified scope can be turned off. The following command creates a three rectangles, containing some points.

      Class Point -parameter {{x 100} {y 300}}
      Class Rectangle -parameter {color}
    
      Rectangle r0 -color pink -contains {
        Rectangle r1 -color red -contains {
          Point x1 -x 1 -y 2
          Point x2 -x 1 -y 2
        }
        Rectangle r2 -color green -contains {
          Point x1
          Point x2
        }
      }
    
    The resulting object structure looks like in the following example (simplified).
       ::r0
       ::r0::r1
       ::r0::r1::x1
       ::r0::r1::x2
       ::r0::r2
       ::r0::r2::x1
       ::r0::r2::x2
    
    } return "number of the skipped first arguments" } @ Object instproc copy { newName "destination of copy operation" } { Description { Perform a deep copy of the object/class (with all information, like class, parameter, filter, ...) to "newName". } return "empty string" } @ Object instproc destroy { ?args? "Arbitrary arguments passed to the destructor" } { Description { Standard destructor. Can be overloaded for customized destruction process. Actual destruction is done by instdestroy. "destroy" in principal does: <@pre class='code'> Object instproc destroy args { [my info class] instdestroy [self] } } return "empty string" } @ Object instproc eval { args "cmds to eval" } { Description { Eval args in the scope of the object. That is local variables are directly accessible as Tcl vars. } return "result of cmds evaled" } @ Object instproc extractConfigureArg { al "Argument List Name" name "Name of the configure argument to be extracted (should start with '-')" ?cutTheArg? "if cutTheArg not 0, it cut from upvar argsList, default is 0" } { Description { Check an argument list separated with '-' args, as for instance configure arguments, and extract the argument's values. Optionally, cut the whole argument. } return "value list of the argument" } @ Object instproc exists { var "variable name" } { Description { Check for existence of the named instance variable on the object. } return "1 if variable exists, 0 if not" } @ Object instproc filter { ?args? "filter specification" } { Description { If <@tt>$args is one argument, it specifies a list of filters to be set. Every filter must be an XOTcl proc/instproc within the object scope. If <@tt>$args it has more argument, the first one specifies the action. Possible values are <@tt>assign, <@tt>get, <@tt>add or <@tt>delete, it modifies the current settings as indicated. For more details, check the tutorial. } return "if <@tt>$args return empty current filters, otherwise empty" } @ Object instproc filterguard { filterName "filter name of a registered filter" guard "set of conditions to execute the filter" } { description { Add conditions to guard a filter registration point. The filter is only executed, if the guards are true. Otherwise we ignore the filter. If no guards are given, we always execute the filter. } return "an empty string" } @ Object instproc filtersearch { methodName "filter method name" } { description { Search a full qualified method name that is currently registered as a filter. Return a list of the proc qualifier format: 'objName|className proc|instproc methodName'. } return "full qualified name, if filter is found, otherwise an empty string" } @ Object instproc forward { methodName "name of forwarder method" ?options? "-objscope, -methodprefix string, -default names, -earlybinding, -verbose" ?callee? "named of the called command or object" ?args? "arguments" } { Description { Register an object specific method (similar to a proc) for forwarding calls to a callee (target Tcl command, other object). When the forwarder method is called, the actual arguments of the invocation are appended to the specified arguments. In callee an arguments certain substitutions can take place:
    • %proc: substituted by name of the forwarder method
    • %self: substitute by name of the object
    • %1: substitute by first argument of the invocation
    • {%@POS value}: substitute the specified value in the argument list on position POS, where POS can be a positive or negative integer or end. Positive integers specify the position from the begin of the list, while negative integer specify the position from the end.
    • {%argclindex LIST}: take the nth argument of the specified list as substitution value, where n is the number of arguments from the invocation.
    • %%: a single percent.
    • %Tcl-command: command to be executed; substituted by result.
    Additionally each argument can be prefixed by the positional prefix %@POS (note the delimiting space at the end) that can be used to specify an explicit position. POS can be a positive or negative integer or the word end. The positional arguments are evaluated from left to right and should be used in ascending order. valid Options are:
    • -objscope causes the target to be evaluated in the scope of the object,
    • -methodprefix string inserts the specified prefix in front of the second argument of the invocation,
    • -default is used for default method names (only in connection with %1)
    • -earlybinding: look up the function pointer of the called Tcl command at definition time of the forwarder instead of invocation time. This option should only be used for calling C-implemented Tcl commands, no procs etc.);
    • -verbose
    • : print the substituted command to stderr before executing
    See tutorial for detailed examples. } return "empty" } @ Object instproc hasclass { ?className? "name of a class to be tested" } { Description { Test whether the argument is either a mixin or instmixin of the object or if it is on the class hierarchy of the object. This method combines the functionalities of istype and ismixin. } return "1 or 0" } @ Object instproc incr { varName "variable name" ?increment? "value to increment" } { Description { Increments the value stored in the variable whose name is varName. The new value is stored as a decimal string in variable varName and also returned as result. Wrapper to the same named Tcl command (see documentation of Tcl command with the same name for details). } return "new value of varName" } @ Object instproc info { args "info options" } { Description { Introspection of objects. The following options can be specified: <@l> <@li><@TT>objName info args method: Returns the arguments of the specified proc (object specific method). <@li><@TT>objName info body method: Returns the body of the specified proc (object specific method). <@li><@TT>objName info class: Returns the class of objName. <@li><@TT>objName info children ?pattern?: Returns the list of aggregated objects with fully qualified names if <@TT>pattern was not specified, otherwise it returns all children where the object name matches the pattern. <@li><@TT>objName info commands ?pattern: Returns all commands defined for the object if <@TT>pattern was not specified, otherwise it returns all commands that match the pattern. <@li><@TT>objName info default method arg var: Returns 1 if the argument <@TT>arg of the proc (object specific method) <@TT>method has a default value, otherwise 0. If it exists the default value is stored in <@TT>var. <@li><@TT>objName info filter: Returns a list of filters. With -guard modifier all filterguards are integrated (<@TT> objName info filter -guards). With <@TT>-order modifier the order of filters (whole hierarchy) is printed. <@li><@TT>objName info filterguard name: Returns the guards for filter identified by name. <@li><@TT>objName info forward ?-definition name? ?pattern?: Returns the list of forwarders. One can call this method either without the optional arguments, or with the <@TT>pattern or with <@TT>-definition name. When the <@TT>pattern is specified only the matching forwarders are returned. When the <@TT>definition option is used together with a name of a forwarder, the definition of the forwarder with all flags is returned in a way that can be used e.g. for registering the forwarder on another object. <@li><@TT>objName info hasnamespace: From XOTcl version 0.9 on, namespaces of objects are allocated on demand. hasnamespace returns 1, if the object currently has a namespace, otherwise 0. The method <@TT>requireNamespace can be used to ensure that the object has a namespace. <@li><@TT>objName info info: Returns a list of all available info options on the object. <@li><@TT>objName info invar: Returns object invariants. <@li><@TT>objName info methods: Returns the list of all methods currently reachable for objName. Includes procs, instprocs, cmds, instcommands on object, class hierarchy and mixins. Modifier <@TT>-noprocs only returns instcommands, <@TT>-nocmds only returns procs. Modifier <@TT>-nomixins excludes search on mixins. <@li><@TT>objName info mixin ?-order? ?-guard? ?pattern?: Returns the list of mixins of the object. With <@TT>-order modifier the order of mixins (whole hierarchy) is printed. If <@TT>-guard is specified, the mixin guards are returned. If <@TT>pattern is specified and it contains wildcards, all matching mixins are returned. If <@TT>pattern does not contain wildcards, either the fully qualified name is returned, or empty, if no match exists. <@li><@TT>objName info nonposargs methodName: Returns non-positional arg list of methodName <@li><@TT>objName info parametercmd ?pattern?: Returns a list of registered parametercmds the object (or empty if there are none). If <@TT>pattern is specified, only the matching parametercmds are returned. <@li><@TT>objName info parent: Returns parent object name (or "::" for no parent), in fully qualified form. <@li><@TT>objName info post methodName: Returns post assertions of methodName. <@li><@TT>objName info pre methodName: Returns pre assertions of methodName. <@li><@TT>objName info procs ?pattern?: Returns all procs defined for the object if <@TT>pattern was not specified, otherwise it returns all procs that match the pattern. <@li><@TT>objName info precedence ?-intrinsic? ?pattern?: Returns all classes in the precedence order from which the specified object inherits methods. If the flag <@TT>-intrinsic is specified only the intrinsic classes (from the class hierarchy) are specified. If the flag is not specified, the returned list of classes contains the mixin and instmixin classes as well as the classes of the superclass chain in linearized order (i.e., duplicate classes are removed). If the pattern is specified, only matching classes are returned. <@li><@TT>objName info vars ?pattern?: Returns all variables defined for the object if <@TT>pattern was not specified, otherwise it returns all variables that match the pattern. <@/ul> } return "Value of introspected option as a string." } @ Object instproc instvar { v1 "name of instance variable" "?v2...vn?" "optional other names for instance variables" } { Description { Binds a variable of the object to the current method's scope. Example: <@pre class='code'> kitchen proc enter {name} { my instvar persons set persons($name) [clock seconds] } Now persons can be accessed as a local variable of the method.<@br> A special syntax is: <@tt> {varName aliasName} . This gives the variable with the name <@TT>varName the alias <@TT>aliasName. This way the variables can be linked to the methods scope, even if a variable with that name already exists in the scope. } return "empty string" } @ Object instproc invar { invariantList "Body of invariants for the object" } { Description { Specify invariants for the objects. All assertions are a list of ordinary Tcl conditions. } return "empty string" } @ Object instproc isclass { ?className? "name of a class to be tested" } { Description { Test whether the argument (or the Object, if no argument is specified) is an existing class or not. } return "1 or 0" } @ Object instproc ismetaclass { ?metaClassName? "name of a metaclass to be tested" } { Description { Test whether the argument (or the Object, if no argument is specified) is an existing metaclass or not. } return "1 or 0" } @ Object instproc ismixin { ?className? "name of a class to be tested" } { Description { Test whether the argument is a mixin or instmixin of the object. } return "1 or 0" } @ Object instproc isobject { objName "string that should be tested, whether it is a name of an object or not" } { Description { Test whether the argument is an existing object or not. Every XOTcl object has the capability to check the object system. } return "1 or 0" } @ Object instproc istype { className "type name" } { Description { Test whether the argument is a type of the object. I.e., 1 is returned if className is either the class of the object or one of its superclasses. } return "1 or 0" } @ Object instproc lappend { varName "name of variable" args "elements to append" } { Description { Append all the specified arguments to the list specified by varName as separated elements (typically separated by blanks). If varName doesn't exist, it creates a list with the specified values (see documentation of Tcl command with the same name for details). } return "empty string" } @ Object instproc mixin { ?args? "mixin specification" } { Description { If <@tt>$args is one argument, it specifies a list of mixins to be set. Every mixin must be a defined class. If <@tt>$args has more argument, the first one specifies the action. Possible values are <@tt>assign, <@tt>get, <@tt>add or <@tt>delete, it modifies the current settings as indicated. For more details, check the tutorial. } return "if <@tt>$args empty return current mixins, otherwise empty" } @ Object instproc move { newName "destination of move operation" } { Description { Perform a deep move of the object/class (with all information, like class, parameter, filter, ...) to "newName". Note that move is currently implemented as a copy plus subsequent destroy operation. } return "empty string" } @ Object instproc parametercmd { name "variable to be provided with getter/setter method" } { description { Add a getter/setter for an instance variable with the specified name as a command for the obj. Example: <@pre class='code'> Object o o parametercmd x o x 100 puts [o x] } return "empty string" } @ Object instproc noinit { } { description { flag that constructor (method <@tt>init
    ) should not be called. Example: <@pre class='code'> Class C C instproc init {} {puts hu} C c1 -noinit The object <@tt>c1 will be created without calling the constructor. This can be used to draw a snapshot of an existing object (using the serializer) and to recreate it in some other context in its last state. } return "empty string" } @ Object instproc proc { name "method name" ?non-pos-args? "optional non-positional arguments" args "method arguments" body "method body" "?preAssertion?" "optional assertions that must hold before the proc executes" "?postAssertion?" "optional assertions that must hold after the proc executes" } { Description { Specify a method in the same style as Tcl specifies procs. <@br> Optionally assertions may be specified by two additional arguments. Therefore, to specify only post-assertions an empty pre-assertion list must be given. All assertions are a list of ordinary Tcl conditions. <@br> When instproc is called with an empty argument list and an empty body, the specified instproc is deleted. } return "empty string" } @ Object instproc procsearch { procName "simple proc name" } { Description { Search which method should be invoked for an object and return the fully qualified name of the method as a list in proc qualifier format: 'objName|className proc|instproc|forward|instforward|parametercmd|instparametercmd|cmd|instcmd methodName'. The proc qualifier format reports the command used to create the method. The only exception is instcmd and cmd, which refer to commands implemented in C. E.g., <@pre class='code'> o procsearch set returns <@pre>::xotcl::Object instcmd set. } return "fully qualified name of the searched method or empty string if not found" } @ Object instproc requireNamespace { } { Description { The method <@TT>requireNamespace can be used to ensure that the object has a namespace. Namespaces are created automatically by XOTcl, when e.g. an object has child objects (aggregated objects) or procs. The namespace will be used to keep instance variables, procs and child objects. To check, whether an object currently has a namespace, <@TT>info hasnamespace can be used. Hint: In versions prior to XOTcl 0.9 all XOTcl objects had their own namespaces; it was made on demand to save memory when e.g. huge numbers of objects are created. <@TT>requireNamespace is often needed when e.g. using Tk widgets when variables are to be referenced via the namespace (with <@TT>... -variable [self]::varName ...). } return "empty string" } @ Object instproc set { varName "name of the instance variable" ?value? "optional new value" } { Description { Set an instance variable in the same style as Tcl sets a variable. With one argument, we retrieve the current value, with two arguments, we set the instance variable to the new value. } return "Value of the instance variable" } @ Object instproc subst { options "?-nobackslashes? ?-nocommands? ?-novariables?" string "string to be substituted" } { Description { Perform backslash, command, and variable substitutions in the scope of the given object (see documentation of Tcl command with the same name for details). } return "substituted string" } @ Object instproc trace { varName "name of variable" } { Description { Trace an object variable (see documentation of Tcl command with the same name for details). } return "empty string" } @ Object instproc unset { "?-nocomplain?" "possible error messages are suppressed" v1 "Variable to unset" "?v2...vn?" "Optional more vars to unset" } { Description { The unset operation deletes one or optionally a set of variables from an object. } return "empty string" } @ Object instproc uplevel { ?level? "Level" command ?args? "command and arguments to be called" } { Description { When this method is used without the optional level, it is a short form of the Tcl command <@pre class='code'> uplevel [self callinglevel] command ?args?<@/pre> When it is called with the level, it is compatible with the original Tcl command. } return "result of the command" } @ Object instproc upvar { ?level? "Level" otherVar localVar "referenced variable and variable in the local scope" ?otherVar localVar? "optional pairs of referenced and local variable names" } { Description { When this method is used without the optional level, it is a short form of the Tcl command <@pre class='code'> upvar [self callinglevel] otherVar localVar ?...?<@/pre>. When it is called with the level, it is compatible with the original Tcl command. } return "result of the command" } @ Object instproc vwait { varName "name of variable" } { Description { Enter event loop until the specified variable is set (see documentation of Tcl command with the same name for details). } return "empty string" } # procs of Object @ Object proc getExitHandler {} { Description "Retrieve the current exit handler procedure body as a string." return "exit handler proc body" } @ Object proc setExitHandler {body "procedure body"} { Description { Set body for the exit handler procedure. The exit handler is executed when XOTcl is existed or aborted. Can be used to call cleanups that are not associated with objects (otherwise use destructor). On exit the object destructors are called after the user-defined exit-handler. } return "exit handler proc body" } # class @ Class Class -superclass Object { description { This meta-class holds the pre-defined methods available for all XOTcl classes. } } @ Class instproc alloc { obj "new obj/class name" ?args? "arguments passed to the new class after creation" } { description { Allocate an uninitialized XOTcl object or class. Alloc is used by the method <@tt>create<@/tt> to allocate the object. Note that <@tt>create<@/tt> also calls as well configure and init to initialized the object. Only in seldom cases the programmer may want to suppress the <@tt>create<@/tt> mechanism and just allocate uninitiaized objects via <@tt>alloc<@/tt>. } return "new class name" } @ Class instproc allinstances { } { description { Compute all immediate and indirect instances of a class } return "fully qualified list of instances" } @ Class instproc create { objName "name of a new class or object" ?args? "arguments passed to the constructor" } { description { Create user-defined classes or objects. If the class is a meta-class, a class is created, otherwise an object. The method <@tt>create<@/tt> is responsible for allocating and initializing objects. The method can be overloaded e.g. in a metaclass if other initialization behavior is wanted.

    The standard behavior of <@tt>create<@/tt> is as follows:

    1. Call the method <@tt>alloc<@/tt> to create an uninitialized object.
    2. Call the method <@tt>searchDefaults<@/tt> to set default values for instance attributes-
    3. Call the method <@tt>configure<@/tt> to configure the object with the values provided at object creation time. The method <@tt>configure<@/tt> interprets the arguments with leading dashes as method calls.
    4. Call the method <@tt>init<@/tt> to allow initialization by the class. The argument passed to init are the values from the passed argument list containing the arguments up to the first '-'.<@p>

    Create firstly calls <@tt>alloc in order to allocate memory for the new object. Then default values for parameters are searched on superclasses (an set if found). Finally the constructor <@tt>init is called on the object with all arguments up to the first '-' arg.<@p> The <@tt>create method is often called implicitly through the <@tt>unknown mechanism when a class (meta-class) is called with an unknown method. E.g. the following two commands are equivalent <@pre class='code'> Car herby -color red Car create herby -color red <@/pre> When a users may want to call the constructor <@tt>init before other '-' methods, one can specify '-init' explicitly in the left to right order of the '-' method. Init is called always only once. e.g.: <@pre class='code'> Class Car -init -superclass Vehicle <@/pre> } return "name of the created instance (result of alloc)" } @ Class instproc info { args "info options" } { Description { Introspection of classes. All options available for objects (see <@a href="#Object-info">info object) is also available for classes. The following options can be specified: <@ul> <@li><@TT>ClassName info classchildren ?pattern?: Returns the list of nested classes with fully qualified names if <@TT>pattern was not specified, otherwise it returns all class children where the class name matches the pattern. <@li><@TT>ClassName info classparent: Returns the class ClassName is nesting to. <@li><@TT>ClassName info heritage ?pattern?: Returns a list of all classes in the precedence order of the class hierarchy. If pattern is specified, only matching values are returned. <@li><@TT>ClassName info instances ?-closure? ?pattern?: Returns a list of the instances of the class. If <@TT>-closure is specified, the resultet contains as well the instances of subclasses. If <@TT>pattern is specified and it contains wildcards, all matching instances are returned. If <@TT>pattern does not contain wildcards, either the fully qualified name is returned, or empty, if no match exists. <@li><@TT>ClassName info instargs method: Returns the arguments of the specified instproc (instance method). <@li><@TT>ClassName info instbody method: Returns the body of the specified instproc (instance method). <@li><@TT>ClassName info instcommands ?pattern?: Returns all commands defined for the class. If pattern is specified it returns all commands that match the pattern. <@li><@TT>ClassName info instdefault method arg var: Returns 1 if the argument <@TT>arg of the instproc (instance method) <@TT>method has a default value, otherwise 0. If it exists the default value is stored in <@TT>var. <@li><@TT>ClassName info instfilter: Returns the list of registered filters. With -guard modifier all instfilterguards are integrated (<@TT> ClassName info instfilter -guards). <@li><@TT>objName info instfilterguard name: Returns the guards for instfilter identified by name. <@li><@TT>objName info instforward ?-definition name? ?pattern?: Returns the list of instforwarders. One can call this method either without the optional arguments, or with the <@TT>pattern or with <@TT>-definition name. When the <@TT>pattern is specified only the matching instforwarders are returned. When the <@TT>definition option is used together with a name of a isntforwarder, the definition of the instforwarder with all flags is returned in a way that can be used e.g. for registering the instforwarder on another class. <@li><@TT>ClassName info instinvar: Returns class invariants. <@li><@TT>ClassName info instmixin ?pattern?: Returns the list of instmixins of this class. If <@TT>pattern is specified and it contains wildcards, all matching mixin classes are returned. If <@TT>pattern does not contain wildcards, either the fully qualified name is returned, or empty, if no match exists. <@li><@TT>ClassName info instmixinof ?-closure? ?pattern?: Returns the list of classes, into which this class was mixed in via instmixin. This is the inverse function of <@TT>ClassName info instmixin. If <@TT>-closure is specified, also the classes are returned, for which the class is indirectly mixed in via instmixin. If <@TT>pattern is specified and it contains wildcards, all matching mixin classes are returned. If <@TT>pattern does not contain wildcards, either the fully qualified name is returned, or empty, if no match exists. <@li><@TT>ClassName info instnonposargs methodName: returns list of non-positional args of methodName <@li><@TT>objName info instparametercmd ?pattern?: Returns a list of registered instparametercmds the class (or empty if there are none). If <@TT>pattern is specified, only the matching instparametercmds are returned. <@li><@TT>ClassName info instpost methodName: Returns post assertions of methodName. <@li><@TT>ClassName info instpre methodName: Returns pre assertions of methodName. <@li><@TT>ClassName info instprocs ?pattern?: Returns all instprocs defined for the class. If pattern is specified it returns all instprocs that match the pattern. <@li><@TT>ClassName info mixinof ?-closure? ?pattern?: Returns the list of classes, into which this class was mixed in via per object mixin. This is the inverse function of <@TT>Object info mixin. If <@TT>-closure is specified, also the classes are returned, for which the class is indirectly mixed in as a per-object mixin. If <@TT>pattern is specified and it contains wildcards, all matching mixin classes are returned. If <@TT>pattern does not contain wildcards, either the fully qualified name is returned, or empty, if no match exists. <@li><@TT>ClassName info parameter: Returns parameter list. <@li><@TT>ClassName info subclass ?-closure? ?pattern?: Returns a list of all subclasses of the class. If <@TT>-closure is specified, the result contains as well the subclasses of the subclasses. If <@TT>pattern is specified and it contains wildcards, all matching subclasses are returned. If <@TT>pattern does not contain wildcards, either the fully qualified name is returned, or empty, if no match exists. <@li><@TT> ClassName info superclass ?-closure? ?superclassname?: Returns a list of all super-classes of the class. If <@TT>-closure is specified, the result contains as well the superclasses of the superclasses. If <@TT>pattern is specified and it contains wildcards, all matching superclasses are returned. If <@TT>pattern does not contain wildcards, either the fully qualified name is returned, or empty, if no match exists. <@/ul> } return "Value of introspected option as a string." } @ Class instproc instdestroy { obj "obj/class name" ?args? "arguments passed to the destructor" } { Description { Standard destructor. Destroys XOTcl object physically from the memory. Can be overloaded for customized destruction process. <@p> In XOTcl objects are not directly destroyed, when a destroy is encountered in a method. Beforehand, the interpreter looks up whether the object is still referenced on the method callstack or not. If not, the object is directly destroyed. Otherwise every occurrence of the object on the callstack is marked as destroyed. During popping of the callstack, for each object marked as destroyed, the reference count is decremented by one. When no more references to the object are on the callstack the object is physically destroyed. This way we can assure that objects are not accessed with [self] in running methods after they are physically destroyed. } return "empty string" } @ Class instproc instfilter { ?args? "instfilter specification" } { Description { If <@tt>$args is one argument, it specifies a list of instfilters to be set. Every filter must be an XOTcl proc/instproc within the object scope. If <@tt>$args it has more argument, the first one specifies the action. Possible values are <@tt>assign, <@tt>get, <@tt>add or <@tt>delete, it modifies the current settings as indicated. For more details, check the tutorial. } return "if <@tt>$args return empty current instfilters, otherwise empty" } @ Class instproc instfilterguard { filterName "filter name of a registered filter" guard "set of conditions to execute the filter" } { description { Add conditions to guard a filter registration point. The filter is only executed, if the guards are true. Otherwise we ignore the filter. If no guards are given, we always execute the filter. } return "empty string" } @ Class instproc instforward { methodName "name of forwarder method" ?options? "-objscope, -methodprefix string, -default names, -earlybinding, -verbose" ?callee? "named of the called command or object" ?args? "arguments" } { Description { Register a method for the instances of a class (similar to an instproc) for forwarding calls to a callee (target Tcl command, other object). When the forwarder method is called, the actual arguments of the invocation are appended to the specified arguments. In callee an arguments certain substitutions can take place:

    • %proc: substituted by name of the forwarder method
    • %self: substitute by name of the object
    • %1: substitute by first argument of the invocation
    • {%@POS value}: substitute the specified value in the argument list on position POS, where POS can be a positive or negative integer or end. Positive integers specify the position from the begin of the list, while negative integer specify the position from the end.
    • {%argclindex LIST}: take the nth argument of the specified list as substitution value, where n is the number of arguments from the invocation.
    • %%: a single percent.
    • %Tcl-command: command to be executed; substituted by result.
    Additionally each argument can be prefixed by the positional prefix %@POS (note the delimiting space at the end) that can be used to specify an explicit position. POS can be a positive or negative integer or the word end. The positional arguments are evaluated from left to right and should be used in ascending order. valid Options are:
    • -objscope causes the target to be evaluated in the scope of the object,
    • -methodprefix string inserts the specified prefix in front of the second argument of the invocation,
    • -default is used for default method names (only in connection with %1)
    • -earlybinding: look up the function pointer of the called Tcl command at definition time of the forwarder instead of invocation time. This option should only be used for calling C-implemented Tcl commands, no procs etc.);
    • -verbose
    • : print the substituted command to stderr before executing
    See tutorial for detailed examples. } return "empty" } @ Class instproc instinvar { invariantList "Body of invariants for the class" } { Description { Specify invariants for the class. These are inherited by sub-classes. The invariants must hold for all instances. All assertions are a list of ordinary Tcl conditions. } return "empty string" } @ Class instproc instmixin { ?args? "instmixin specification" } { Description { If <@tt>$args is one argument, it specifies a list of instmixins to be set. Every instmixin must be a defined class. If <@tt>$args has more argument, the first one specifies the action. Possible values are <@tt>assign, <@tt>get, <@tt>add or <@tt>delete, it modifies the current settings as indicated. For more details, check the tutorial. } return "if <@tt>$args empty return current instmixins, otherwise empty" } @ Class instproc instparametercmd { name "variable to be provided with getter/setter method" } { description { Add a getter/setter command for an instance variable with the specified name. This method is used for example by the <@A href="#Class-parameter">parameter method. Example: <@br> <@pre class='code'> Class C C instparametercmd x C c1 -x 100 puts [c1 x] } return "empty string" } @ Class instproc instproc { name "instance method name" ?non-pos-args?" "optional non-positional arguments" args "instance method arguments" body "instance method body" "?preAssertion?" "optional assertions that must hold before the proc executes" "?postAssertion?" "optional assertions that must hold after the proc executes" } { Description { Specify an instance method in the same style as Tcl specifies procs. <@br> Optionally assertions may be given by two additional arguments. Therefore, to specify only post-assertions an empty pre-assertion list must be given. All assertions are a list of ordinary Tcl conditions. <@br> When instproc is called with an empty argument list and an empty body, the specified instproc is deleted. } return "empty string" } @ Class instproc new { "?-childof obj? ?args?" "args passed to create" } { description { Convenience method to create an autonamed object. E.g.: <@pre class='code'> HTTP new creates ::xotcl::__#0, a subsequent call creates ::xotcl::__#1, ...<@br> If <@tt>-childof obj is specified, the new object is created as a child of the specified object. } return "new object name" } @ Class instproc parameter { parameterList "list of parameter definitions" } { description { Specify parameters automatically created for each instance. Parameters denote instance variables which are available on each class instance and that have a getter/setter method with their own name. Parameters are specified in a parameter list of the form {p1 p2 ... pn}. p1 ... pn may either be parameter names or definitions of the form {parameterName defaultValue}. If a default value is given, that parameter is created during creation process of the instance object, otherwise only the getter/setter method is created (and the parameter does not exist). The getter/setter method has the same name as the parameter. It gets and returns the parameter, if no argument is specified. With one argument, the parameter is set to the argument value. <@br> Example: <@pre class='code'> Class Car -parameter {{doors 4} color} Car herby -doors 2 -color green <@/pre> } return "empty string" } @ Class instproc parameterclass { class "parameter class name" } { description { Set the parameter class. The parameter class specifies how parameters are stored and maintained internally. Per default, a method "default" is called, to set the parameter with a default value. I.e., <@pre class='code'> Class Car -parameter { {doors 4} }<@/pre> is a short form for <@pre class='code'> Class Car -parameter { {doors -default 4} }<@/pre> For specialized parameter classes other methods can be called, e.g.<@br> <@pre class='code'> {doors -default 3 -updateWidget car}<@/pre> } return "empty string" } @ Class instproc recreate { obj "obj to be recreated" ?args? "arbitrary arguments" } { description { Methods called upon recreation of an object. Recreate is called, when an object/class is created, but a same-named object/class exists already. "recreate" is not called, when an object is trying to be recreated as a class or vice versa. In these cases, recreating is realized via destroy+create. The Methods "recreate" performs standard object initialization, per default. May be overloaded/-written. It calls another method cleanup which handles actual cleanup of the object during next. That means, if you overload recreate, in the pre-part the object still contains its old state, after next it is cleaned up. } return "obj name" } @ Class instproc superclass { classList "?list of classes?" } { description { Specify super-classes for a class. "superclass" changes the list of superclasses dynamically to <@tt>classList. The method returns the current value of superclass, when it is called without arguments. } return "if <@tt>classList is not specified return superclass(es), otherwise empty" } @ Class instproc unknown { ?args? "arbitrary arguments" } { description { Standard unknown mechanism. This mechanism is always triggered when XOTcl does not know a method called on an object. Supposed that there is no method with the called name, XOTcl looks up the method "unknown" (which is found on the Class Object) and executes it. The standard unknown-mechanism of XOTcl calls create with all arguments stepping one step to the right; in the general case: <@pre class='code'> ClassName create ClassName ?args?<@/pre> Unknown can be overloaded in user-defined subclasses of class. } return "Standard unknown mechanism returns result of create" } @ Object instproc volatile { "" "" } { description { This method is used to specify that the object should be deleted automatically, when the current Tcl-proc/object-proc/instproc is left. Example: <@pre class='code'> set x [Object new -volatile] } return "empty string" } @ Class proc __unknown { "name" "name of class to be created" } { description { This method is called, whenever XOTcl references a class, which is not defined yet. In the following example: <@tt>Class C -superclass D D is not defined. Therefore, <@tt>Class __unknown D is called. This callback can be used to perform auto-loading of classes. After this call, XOTcl tries again to resolve D. If it succeeds, XOTcl will continue; otherwise, an error is generated. <@p> This method is called on mixin/instmixin definition calls, istype, ismixin, class, superclass and parameterclass } return "empty string" } @ Class ::xotcl::Slot -superclass Object { description { A slot is a meta-object that manages changes of properties of objects. A property is either an attribute or a relation (defined in the system slots). The predefined system slots are class, superclass, mixin, instmixin, filter, instfilter. These slots appear as methods of Object or Class.

    The slots provide a common query and setting interface. Every multivalued slot provides e.g. a method add to add a value to the list of values, and a method delete which removes it. See for example the documentation of the slot mixin.

    Parameters:

    -name Name of the slot to access from an object the slot
    -domain domain (object or class) of a slot on which it can be used
    -multivalued boolean value for specifying single or multiple values (lists)
    -defaultmethods list of two elements for specifying which methods are called per default, when no slot method is explicitly specified
    -manager the manager object of the slot (per default [self])
    -per-object specify whether a slot should be used per class or per object; note that there is a restricted usage if applied per class, since defaults etc, work per initialization

    For more details, consult the tutorial.

    } } @ Class Attribute -superclass ::xotcl::Slot { description { Attribute slots are used to manage the setting and querying of instance variables. Parameters:

    -default specify a default value
    -type specify the type of a slot
    -initcmd specify a Tcl command to be executed when the value of the associated variable is read the first time; allows lazy initialization
    -valuecmd specify a Tcl command to be executed whenever the variable is read
    -valuechangedcmd specify a Tcl command to be executed whenever the variable is changed

    Example of a class definition with three property slots:

    <@pre CLASS="code"> <@tt>Class Person -slots { Attribute name Attribute salary -default 0 Attribute projects -default {} -multivalued true } Person p1 -name "John Doe"

    The slot parameters default, initcmd and valuecmd have to be used mutually exclusively. For more details, consult the tutorial.

    } } #Class::Parameter instproc values {param args} #proc xotcl_mkindex #proc xotcl_load ./nsf2.4.0/library/xotcl/doc/Announce-1.3.9000644 000766 000024 00000002750 13331303364 020674 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.3.9 ************************* Hi everybody. I am pleased to announce the availability of XOTcl 1.3.9. Major changes relative to 1.3.8 are: * Improved Functionality + new subcommand for self: [self args] return the full argument list of the current call + " info vars" does not trigger read traces on each variable anymore + Serializer: exportMethods accepts forwards/instforwards now as well + new switch -nocomplain for "mixin|instmixin|filter|instfilter delete" to avoid error messages when deleting entries not there (similar unset) + require automatically a namespace when a childobject is added + new command ::xotcl::__qualify: convert an relative name into an command name (exactly as create does it, ignoring namespaces from transparent interceptors) * Improved code quality: + fixing version numbers for package require + Upgraded TEA to 3.4 + updated rpm build (many thanks to Ildiko Schmidt and Alexander Bergolth) + fixed bug with error propagation when getter/setter methods are used for parameters (many thanks to Manfred Stelzhammer for pointing this out) For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/Announce-1.3.7000644 000766 000024 00000004313 14274464576 020713 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.3.7 ************************* I am pleased to announce XOTcl 1.3.7. Major changes relative to 1.3.6 are: * Improved Functionality + new option "switch" for non positional arguments to be used to toggle the default value. A switch is a non positional argument without extra argument. + new option "isnextcall" for self + new command "::xotcl::configure filter on|off" to turn off filters. needed for serializing objects/classes with active filters + several improvements for serializer to handle e.g. application methods on Object/Class (needed for ad_instproc in oacs) + improving namespace resolving in for object/class references + moving all library packages into namespaces + preventing "new" from overwriting objects + allow xotcl to be used in slave interpreters * Improved code quality: + fixed namespace confusion in forward to expression calling XOTcl methods + fixed possible crash in instvar when empty variable names are used + some code cleanup + improved documentation * new method "method" for defining methods (experimental): Instead of using e.g. Object o1 Class C o proc m1 {} {....} C instproc m2 {} {....} C proc m3 {} {....} one can use now o method m1 {} {....} C method m2 {} {....} C method -per-object m3 {} {....} in general, we can support options for method definitions, which can be used as well for mixins, filters or info (instead of the "inst" prefix). This way the problem of finding appropriate names for distinguishing between object or class matters can be solved, in rather rare cases (when referring the to class object) "-per-object" can be used. The according name changes will happen in xotcl 2.0. For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/Announce-1.3.0000644 000766 000024 00000006040 13464226761 020673 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.3.0 ********************** WHAT IS XOTCL? XOTcl is an object-oriented extension of Tcl that was derived from OTcl. In short, XOTcl tries to provide a highly flexible, reflective, component-based, and object-oriented environment. It integrates language support for high-level concepts which are not found in other languages, with reasonable performance. It prevails the Tcl programming style and the dynamic/introspective nature of the language, rather than introducing other language's styles and rigidness (such as C++) into Tcl. Major changes relative to 1.2.0 are: - Qualitative Improvements * Improved portability: + TEA3 compatible build + Much more polished configure+makefile (many thanks to Jim Lynch for his help) * Improved code quality: + fixed 2 possible segmentation violations (error handling) + fixed free memory reads (many thanks to Zoran Vasiljevic for his help with purify) * Less intrusive usage of XOTcl components: + XOTcl procs and instprocs use now the namespace in which they were defined. One can use XOTcl packages without having the need to import xotcl globally or to use the xotcl-prefix in all xotcl procs/instprocs. - Functional Improvements * New forwarding mechanisms for fast delegation: new methods 'forward' and 'instforward' (many thanks to Bryan Schofield for fruitful discussions and suggestions). This method is a superset of tclcmd/insttclcmd, which has been marked as deprecated. See the tutorial for more details. * Nonpositional arguments for xotcl procs/instprocs; this is a flexible way to check arguments, to provide defaults etc for every xotcl proc/instproc. It uses a similar syntax as ad_proc and ad_page_contract in OACS. See the tutorial for more details. * Extended methods filter, mixin, instfilter, instmixin as discussed in the XOTcl mailing list. These commands can be used more flexibly as follows obj mixin same as: obj info mixin obj mixin {C1 C2} same as: obj mixin set {C1 C2} obj mixin set {C1 C2} sets the mixins for obj obj mixin get same as: obj info mixin obj mixin add C3 adds a mixin on front of the mixin list obj mixin add C3 end adds a mixin at the end the mixin list obj mixin add C3 3 adds a mixin at the 3rd position obj mixin delete ::C3 removes the mixin from the mixin list The same semantics are available as well for filter, instmixin and instfilter. This change is fully backward compatible. {filter,instfilter,mixin,instmixin}append are deprecated now. For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/Announce-1.5.2000644 000766 000024 00000002237 12501766547 020705 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.5.2 ************************* Hi everybody. We are pleased to announce the availability of XOTcl 1.5.2. Major changes relative to 1.5.2 are: * Improved Functionality + allowing to trace objects as well as classes via the package xotcl::trace (many thanks to jima for suggesting this) * Improved code quality: + terminating all vararg lists in C by ..., (char *) NULL There was a problem with this on 64bit AMD on FreeBSD, as some lists were terminated previously by an integer typed zero-value. + better handling of Tcl result objects. Make sure that no changes happen on shared objects. Removed all occurrences of Tcl_AppendResult() from xotcl.c + Fixed memory corruption (accessing feed memory) in the invalidation of transitive mixins (many thanks to Don Porter for reporting) For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/Announce-1.5.5000644 000766 000024 00000002662 12501766547 020712 0ustar00neumannstaff000000 000000 Dear XOTcl Community, XOTcl 1.5.5 is available. The main change is to achieve binary compatibility between Tcl 8.5 and XOTcl compiled with Tcl 8.4. This is essential achieved through a small emulation layer based on C-structures that will be available in Tcl 8.5. best regards -gustaf neumann Announcing XOTcl 1.5.5 ************************* We are pleased to announce the availability of XOTcl 1.5.5. Major changes relative to 1.5.4 are: * Improved binary compatibility: It is now possible to load XOTcl compiled for Tcl 8.4 into a tclsh8.5 (again, substantial change). One can now test now 4 versions: a) a native version for Tcl 8.4 (without compatibility layer) b) a native version for Tcl 8.5 c) a version compiled for Tcl 8.4 with compatibility layer in tclsh8.4 d) a version compiled for Tcl 8.4 with compatibility layer in tclsh8.5 Tests showed that the overhead is for the compatibility layer is between 1.1% and 2.3%, the difference between tcl8.5 and tcl8.4 is much larger. The forward compatibility behavior behavior can be turned off by setting FORWARD_COMPATIBLE to 0 during compilation (xotcl.h) to get a small performance improvement. For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org ./nsf2.4.0/library/xotcl/doc/Announce-1.3.1000644 000766 000024 00000000540 12501766547 020675 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.3.1 ********************** This is a minor fix release relative to 1.3.0. This fixes a few problems introduced in 1.3.0 (invocation of checking procs in nonpositional argument) and has a better build support for building XOTcl outside of the source tree, the tar files are now dist-cleaned. Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/Announce-1.3.6000644 000766 000024 00000004263 13560527131 020676 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.3.6 ********************** WHAT IS XOTCL? XOTcl is an object-oriented extension of Tcl that was derived from OTcl. In short, XOTcl tries to provide a highly flexible, reflective, component-based, and object-oriented environment. It integrates language support for high-level concepts which are not found in other languages, with reasonable performance. It prevails the Tcl programming style and the dynamic/introspective nature of the language, rather than introducing other language's styles and rigidness (such as C++) into Tcl. Major changes relative to 1.3.5 are: * Improved Functionality + new info subcommand: info precedence + simplified meta class definitions: every class can be changed into a metaclass by adding an instmixin of Class (or one of its subclasses) to it. In order to define that every class should be a metaclass, one can use now Object instmixin Class instead of the rather complicated solution i posted on the xotcl mailing list not long ago. * Improved code quality: + fixed possible crashes when - objects are called with class methods (e.g. due to instmixins) - when instmixins are defined recursively (e.g. Class instmixin Class) - objects are turned into classes by changing the class relationship + improved namespace resolution when mixin classes are defined in namespaces (::xotcl:: namespace is skipped, since a helper method that calls the primitive setting command is defined there) + fixed passing of error code from init methods (thanks to Fabrice Pardo for noting it) + returning PACKAGE_VERSION after a package require (e.g. 'package req XOTcl' returns now 1.3.6) + some code refactoring, fixed erroneous documentation of c code + improved documentation For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/Announce-1.3.8000644 000766 000024 00000004476 14274464576 020726 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.3.8 ************************* I am pleased to announce XOTcl 1.3.8 Major changes relative to 1.3.6 are: * Improved Functionality + new option "switch" for non positional arguments to be used to toggle the default value. A switch is a non positional argument without extra argument. + new option "isnextcall" for self + new command "::xotcl::configure filter on|off" to turn off filters. needed for serializing objects/classes with active filters + several improvements for serializer to handle e.g. application methods on Object/Class (needed for ad_instproc in oacs) + improving namespace resolving in for object/class references + moving all library packages into namespaces + preventing "new" from overwriting objects + allow xotcl to be used in slave interpreters * Improved code quality: + fixed namespace confusion in forward to expression calling XOTcl methods + fixed possible memory leak with instmixins + fixed possible crash in instvar when empty variable names are used + fixed namespace related bug in __unknown resolver hook + some code cleanup + improved documentation * new method "method" for defining methods (experimental): Instead of using e.g. Object o1 Class C o proc m1 {} {....} C instproc m2 {} {....} C proc m3 {} {....} one can use now o method m1 {} {....} C method m2 {} {....} C method -per-object m3 {} {....} in general, we can support options for method definitions, which can be used as well for mixins, filters or info (instead of the "inst" prefix). This way the problem of finding appropriate names for distinguishing between object or class matters can be solved, in rather rare cases (when referring the to class object) "-per-object" can be used. The according name changes will happen in xotcl 2.0. For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/filter-inheritance.gif000644 000766 000024 00000015430 12501766547 023015 0ustar00neumannstaff000000 000000 GIF87a^PPPoFt@sX/XFcFameTra-я dB<75OdIc#ɆCgBhy '!NpPT!*_9n)#m\ 1IvӘ[H2K4r$]*3e yMo*4'/IqҎݼCYNy_qgjYbfA }r(5Du\1P.@krh'Fim H MHSm<Pqr6Ԓ~Y3ԥ,7NJj&J$"E,_M] g1Vԛ e4o \aVD1tkcƉ Ob&W>璺$o b%,oU*#[Z9eV̝1F 'WYrќ4yC2NX)i@PFe%[dȯIaBce='w1\C4. {"#yaݑ' V[}6h[[ؘ~ۓuD"H[wFv3y[^v%-wa\tcs3/FtVl7ZZ4j\6M%&bsЌIX+#__`ٵMIa556glyX"sW5tɣXˉq?/[\5t]e櫮 . {wvO]uWWN,Lj 㵮S wͅ^5g| /_1,Ou̓]B ֜糞x-q8<;x ĒyԡEGë+iŭc\&kq7KlidB};ە| j7C@}RBză~f#G}>!886&FjVD> 5@qX$b^!zR zs6Xk{$؀сÑ*.(n#61LcBRÃ+Ȃ97ǖHr 9R~[vTr53-~y1H[=l0s.X\x۱%I!@Ç43g%ic"jgA*,)n!x $~@7{Ґ|;@d{0~AR3DH5K95}|7<'+sINKȄqr1ɈyC(J^I|GƏ%vq)L@/k1JD+ Lw 86ʹzv;' 1wrwr'\>>s96WyD~7+ك yYؑ=Zr)E)r|)BRF2HW+:^|&}ÕĞrӳ mVrr)_'3Msw~aݩYV0[?A$jxw'yNnPZ3:#^ Z=W>tAb*dfha1W*ewYգlw4w{*\jc nSJv*j+kz[*oq*y:zczZڪ~*F~*::}e*ڦZzojyZګڤ:Qz*"ex zǺmgCZ*2hsϪʮJjfҘ8Zzj-2\a9nzz!:v:Ѱ&$rG{+% z}TWҳ! A+YkkIX& Ke !K0}5mei*S+Z]kJJ9%*+},XM>w*'׫NU OҕEl큼8>}:u8CB{>H~H˂s0H?厰Y-2v%9Ϯ52؇R!h' ") ,/%Fi _Bh{(0)n_G}" U$oޘDF n-eS&|T}:)];۩C6:ֳm 6>3`23p+[mCx<iЙH89 t`W;1HrE N;x^)C{3 H<+ɁLx+ ޾3VžÛ O}hFit>#o+>PTa|'YZҿXBF3fO_ O͈$1Fm<<럝0]|ZA@ DPB >QDcA=~RH%MDRJ-] Sf5; SI $4EEEZFM>UTgʬRgΒLf1Xe.UZmݾy+ܐ[w\h,ot FXqH4iЏBIL8愙>Z認EG6稘=;vaҵmcШ%\pߚmKƝ?:޾KǞ]WO[ٜxͯ9ZyTݿ?1xǟ_?KO0@A?~H5> J%Cl.\m# }jDkC>1P\jLpbQF!o\'<1,$ '\*H"1#d& lo .+D3ͬh|%qdR8{l$RM=RA0/LG@mN;TL>eԽ;k4RI'5 QJ/4G!ʹSOܔOG%PE-5UU{8E\5VUtWeT< ״(,P?͵XMAVA1C756ZiK6v'o[oP#u6E7]6, PsեdY=^U2AU3`u_օ[bY)b7c?9dG&dOF9eWfe_9fgfo9gwg:h&hF:ifi;./nsf2.4.0/library/xotcl/doc/Announce-1.5.4000644 000766 000024 00000002642 12501766547 020707 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.5.4 ************************* Hi everybody. We are pleased to announce the availability of XOTcl 1.5.4. Originally, this release was planned as a small bug fix release. However, the total size of the (unified) diff between 1.5.3 and 1.5.4 is more than 5000 lines, mostly due to the varRefom changes (see first item below). Major changes relative to 1.5.4 are: * Improved code quality: + provided compatibility with Tcl 8.5 (currently, this requires the version of Tcl 8.5 from CVS head, including the changes for VarReform (For details, see http://groups.google.at/group/comp.lang.tcl/browse_frm/thread/bff391a7f1bd8f6c/3f214d088a28ed13?hl=de#3f214d088a28ed13) + improved serializer (handling var traces for instances variables) + several small bug-fixes (e.g. fixing empty variable names, error message propagation for configure, fixing potential crashes, when namespaces are added to objects during eval, etc.) + improved portablility for more platforms (more portable shell tests for e.g. FreeBSD) + extended regression test For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/Announce-1.5.3000644 000766 000024 00000002026 14274464577 020711 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.5.3 ************************* Hi everybody. We are pleased to announce the availability of XOTcl 1.5.3. Major changes relative to 1.5.2 are: * Improved code quality: + provided compatibility with Tcl 8.5 + provided compatibility with Tcl 8.4.14 (fixed a nasty bug caused by a change in tcl 8.4.14, could led to a crash due to freed Tcl_Objs in OpenACS, although the xotcl regression test passed correctly) + reduced calling overhead of methods with nonpositional arguments by about 10 percent by avoiding shimmering. + fixed handling of "return -code break" from XOTcl methods (thanks to Artur Trzewik for the bug report) + library/comm/Access.xotcl: fixed handling of chunked encoding For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/obj_class_system.gif000644 000766 000024 00000005350 12501766547 022604 0ustar00neumannstaff000000 000000 GIF87aXF@XFT@<0MNM,@L @ܤv& @@tXXFF XFT4 TM@tjcMvTX~vF @nL @Xk&F 伀M@h@fLl\X~F@n& HX Fk@KM@HhLM\TlX&F @L& @@tX6Xn FKTlLcUXmEFt] Zs@$||Mu/& @[XaFg X0Fs$T/XF|;mTN/& NR)n@OT#|@@6H &O @THXF,H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻ Ũwߦ}N ,pQ†"N %7!;d/' 78rʝrOCwz-}}yV=?=vt=~ݹ|ѧqg]gy!i5}ga[!>቙1Usa^rvx^zY"x!txU͍x#$CBPF)TViW.q`$]ci[yj^$tu|矀*蠄j衈&:莌Ib6bdIb 馜vz*#Lu\n jĵ*R G뮦ڊ밚Yl&jb֤r#I2 \:]fmvT-B~-t߆ֺ n Hz4.sˮh!jw 0n+ oqE:\cV _,ԓlP%|\1 E1 8r =EIǫM>d&?]/[]Yu}"#uP 2̥mhzBٝ5wu{7T3/O4VVVxn=yK$GZ灧Nنj0ƴs1;PN$ ˿H E/aAG VMCm_!7IjUk#ųД! ԑ*cihfc4?`*<+g XOTcl - Documentation -- ./library/xotcl/apps/utils/xo-daemon

    ./library/xotcl/apps/utils/xo-daemon ./library/xotcl/apps/utils/xo-daemon


    Package/File Information

    No package provided/required

    Filename: ./library/xotcl/apps/utils/xo-daemon

    Description: This script can be used to start/stop/restart xotcl daemons and maintains the process IDs, log files and means for easy restart.

    It receives as first parameter the name of the xotcl script to be executed followed by the desired action and optional parameters. The specified action can be

    • start: the specified script is started in the background, an entry to restart is generated in the run-directory as well as the process id of the started script. In addition a logfile is created in the log directory. If the start of the script fails, the error messages are shown.
    • startall: all scripts that were started before via this script, are started
    • stop terminates the specified script.
    • stopall terminates all scripts started via this command
    • restart tries to restart the specified script.
    The optional parameters are:
    • -logir specifies the directory for logging. The default is ~/.xotcl/log.
    • -rundir specifies the directory where the information about the running processes is kept. The default is ~/.xotcl/run.
    Authors: Gustaf Neumann, Gustaf.Neumann@wu-wien.ac.at
    Date: [::xotcl::rcs date {$Date: 2006/02/18 22:17:32 $}]



    Back to index page.

    ./nsf2.4.0/library/xotcl/doc/pkgIndex.tcl000644 000766 000024 00000000174 14276141440 021014 0ustar00neumannstaff000000 000000 package ifneeded XOTcl-langRef 2.0 "[list source [file join $dir langRef.xotcl]]; [list package provide XOTcl-langRef 2.0]" ./nsf2.4.0/library/xotcl/doc/xotcl-doc.css000644 000766 000024 00000001463 12501766547 021161 0ustar00neumannstaff000000 000000 BODY { font-family: Verdana, Arial, Helvetica, sans-serif; font-weight: normal; background-color : white; color: black; } tt { font-family: courier, monospace; } A { font-family: Verdana, Arial, Helvetica, sans-serif; font-weight: 100; background-color : white; } A em { font-weight: 900; } pre.code { font-size: 90%; font-family: courier, monospace; PADDING-RIGHT: 10px; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; PADDING-TOP: 10px; BORDER: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee; MARGIN-BOTTOM: 15px; } pre em { font-family: cursive; color: #888888; } pre tt { font-family: helvetica; font-weight: 900; } pre it { font-style: italic; color: green; } tt em { font-family: cursive; color: #888888; } table { font-size: 80%; } ./nsf2.4.0/library/xotcl/doc/features.gif000644 000766 000024 00000015365 12501766547 021066 0ustar00neumannstaff000000 000000 GIF87azXF@XFT@< 0MOM,@L @ܤv& @@tXXFF XFT4 TM@tbcMvTX~vF @HL @XE&F xM@h@fLl\X~F@H& HX FE@KM@HhLM\TlX&F @L& @@tX6XH FKTFLcUXfEFt] Zs@$||Mu'& @[XaFg X0Fs$T'XF|;fTO'& NR)nOT#|@@zH&M @THXF,zH*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sϟ@ JѣH*]ʴӧPJJիXׯ`ÊKٳhӪ]˶۷pʝKݻb}߿ L_r䋸ǐ#KLY-+k̹ϕ/c ӨS*"հc˞M[._׵s{퉯{ Nxa+_μ[;N:q[ν;ѽO~3ӫ_?4z}YfϿ{%VT~>gPy~F(g 2 X vd.ta ڈ"^!*≯U+h]-&bnX 7)d[9"#06L2YA/҈MVi%YO28`6eA[h"ayYbPI)glxY@wg{矄V蠅&Jg}*ꨞ.jJWZCj5z J Jي K챹첱+pBKW@Q[> cfb(:m'Rk.xn1. .&of弧kkbKp30Ngrˡ,{o*+$;l.wr3,b!ЇmHҳ6 Ej!Xk&u\ht#\cI6fci]Wݷ6s=:G,ˌqac8_,9t7zɇ[ùy{ˉgLnwrz0;x̸_o޶a3&dG/3k/{ͰW7 (&zITY li1Ry "qi&;-L*8ʜ G]-,hNp34]3e :ۙr,$CA4Q;yf잣 FYEq1C[P43~[hHwӂs/Mj':4AӟNugS8ȍtuG8+kXGխgd^_zñ>p_ n:lo}ml/+moVm]nm7\]l;vM${}s:vŜss^y\\<Wc+015xdUw`@ϻ}Cjяt&}M]j[]OүuTaAWh`ɕr*%j9Sly8fi'iI?xR*'7u 9yǐY٤ⶦ*tnI :t)lnyF* cI 'cf-X֬ Ǎ@&gE̙ytzuںPPexf>6 5׊Zw_GdJ_jZzqW؀;mYدNƯG5IgzI EFkJ b U򚣊ڝ J$FhJXZ8:8a'O k~Z 튦im;[rpڧv|gHưU=Zp˖z*{fII:ke*/*WVtwޘ)EqٱI{k=˸&븃ǭY ;J{zƮN7xK/lAX{tkO[Tv[AǼUUgjGh&x+rGk+Y X\NG14},Ena|b7p&:1v9k@zy7٥Ef|$y۹Q{T uylLCLakLVε{ܫ[~z^ͿcN6RKؗ#\Nf:L]\}>^kJîN>bJ|펼~֕C|+.A\~{jՑkkK꥖H/ыf&,$gwf . nV+\2=A)*/|XbO|vH\ޢ-|7ଥ?.]1=ݦW{=}T[m[8[۳;=}jOl>TnNl*+*>m{}ޭ^nʈk{M\gY`u 6/őٴ;mm,/l?*<__g?կӿُ/iM7N݄w@Xiߟ>c@@ ` A LP!B:xF=r@%MDRJ-] 3G5męSN=}n\1"A=V̘t Eb$ꔩRKF8T̟GEVXeevEVZmb-5*P[l4Uo゜{W^n~5Xb&Yd52*q_uA>[t]9 rȑ]1eڵmwJ/̧#;3g5[0QjY]:淭_ӄ}j%\ϧ/zv?=[ӝ*K?Tnr/>LiA&а*İ jB0CGiCG4?dqOcpƵVl1^G'u$R1D2I%iH':rI)&(K/Ӻ2K1eL3ϼ1liK4߄0٤89\<В 4QEPGIBtQI'mkPB-4RJ7t'K1}TNG%ZPKeՏ,4L]֎ :UY]V_5Xwu4cE6YeeYg6ZiZkMX]U[o7\q%\sE7]ue]w[yI^{7_}_a_&``OBa8wb/8c7c?9dG&dOF9eWfe_9fI ;./nsf2.4.0/library/xotcl/doc/Announce-1.2.0000644 000766 000024 00000014301 13464226762 020672 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.2.0 ********************** WHAT IS XOTCL? XOTcl is an object-oriented extension of Tcl that was derived from OTcl. In short, XOTcl tries to provide a highly flexible, reflective, component-based, and object-oriented environment. It integrates language support for high-level concepts which are not found in other languages, with reasonable performance. It prevails the Tcl programming style and the dynamic/introspective nature of the language, rather than introducing other language's styles and rigidness (such as C++) into Tcl. CHANGES relative to 1.1.1 are: - Qualitative Improvements * improved performance (up to more than 30% faster) * reduced dependency on Tcl internals (stack rewritings removed) * less C-code (code reduction of about 500 lines c code) * defined macros to access Tcl's internal structures Due to the speedup, an emulation of an itcl like language in XOTcl can be faster than itcl itself (see below). - Functional Improvements * new subcommands of self: self callinglevel: returns the scope of the proc/instproc calling the current method (ignoring filters and next) self activelevel: returns the scope of the proc/instproc preceding the current method (might be a next call, ignoring filters) the returned level can be used in uplevel/upvar as first argument * new methods upvar/uplevel "my uplevel set x 1" is a short form of "uplevel [self callinglevel] set x 1" * sub-objects can be called like methods (potential incompatibility) If an object named o has a sub-object q (i.e. o::q) it is now possible to invoke the sub-object via "o q ?method args?". This change makes it possible to - to redefine tcl sub-commands via procs/instprocs by defining the command with subcommands as an object (instead of defining a command as a proc and its subcommands via a large and hard-to-refine switch statement) - to use the same approach for defining subcommands of subcommands (and so on) in the same way; it would be possible to define e.g. the xotcl info methods via an object), - to use interceptors (filters/mixins) for some or all subcommands (maybe you are only interested in "file delete") - to extend a tcl command on the fly by defining new subcommands (by defining new procs/instprocs) - to use the unknown mechanism to produce dynamic error messages about valid subcommands (via introspection commands). As a simple example, one define the a specialized version of Tcl's file-command (say ns::file) like the following: namespace eval ns { Object file file proc tail name { set tail [file tail $name] regexp {[^/\\]+$} $tail tail return $tail } file proc unknown {subcmd args} { return eval ::file $subcmd $args } } For more details, please consult the ChangeLog MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun #======================================================================= # extract from the logfile of oobench (in oo-bench.tar.gz, # see http://media.wu-wien.ac.at/download.html) XOTcl methcall: 0.470u 0.000s 0:00.41 114.6% 0+0k 0+0io 347pf+0w ITcl emulation in XOTcl methcall: 0.590u 0.000s 0:00.62 95.1% 0+0k 0+0io 351pf+0w itcl methcall: 0.870u 0.020s 0:00.92 96.7% 0+0k 0+0io 347pf+0w #======================================================================= package require XOTcl; namespace import -force xotcl::* ########################################################### ## Small example to emulate a itcl-like language in XOTcl ## -gustaf neumann Jan. 2004 ########################################################### namespace eval itcl { Class create class -superclass Class class instproc instvars {} { set vars [list]; set c [self] for {} {[string compare ::xotcl::Object $c]} {set c [$c info superclass]} { eval lappend vars [$c set __autovars] } return "\n\tmy instvar [lsort -unique $vars]" } class proc constructor {args} { if {[llength $args]==2} { foreach {arglist body} $args break } else { foreach {arglist construct body} $args break set body $construct\n$body } my parameter [list {this [self]}] my proc constructor args {uplevel next $args} my instproc init $arglist [my instvars]\n$body } class proc method {name arglist body} { my proc $name args {uplevel next $args} my instproc $name $arglist [my instvars]\n$body } class proc inherit {class} { my superclass $class } class proc variable {arglist} { foreach v $arglist {my lappend __autovars $v} } class instproc init {classdef} { my set __autovars this namespace eval [self class] $classdef my class Class } } ########################################################### # Two Demo classes from oo-bench ########################################################### itcl::class Toggle { variable state constructor {start_state} { set state $start_state } method value {} { return $state } method activate {} { set state [expr {!$state}] return $this } } itcl::class NthToggle { inherit Toggle variable count_max variable counter constructor {start_state max_counter} { Toggle::constructor $start_state } { set count_max $max_counter set counter 0 } method activate {} { if {[incr counter] >= $count_max} { Toggle::activate set counter 0 } return $this } } proc main {} { set n [lindex $::argv 0] set val 1 set toggle [Toggle t1 $val] for {set i 0} {$i < $n} {incr i} { set val [[$toggle activate] value] } if {$val} {puts "true"} else {puts "false"} set val 1 set ntoggle [NthToggle t2 1 3] for {set i 0} {$i < $n} {incr i} { set val [[$ntoggle activate] value] } if {$val} {puts "true"} else {puts "false"} } main ./nsf2.4.0/library/xotcl/doc/Announce-1.6.6000644 000766 000024 00000001346 12501766547 020712 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.6.6 ************************* Dear XOTcl Community, We are pleased to announce the availability of XOTcl 1.6.6 Major changes relative to 1.6.5 are: * improved 64-bit compatibility (expat) * fixed minor memory leaks (info methods, forward error case) * fixed potential cyclic dependencies via namespace imports during cleanup * fixed potential crash with var-traces being fired twice * compatibility with Tcl 8.6b1 * fix for debian packaging For more details about the changes, please consult the ChangeLog and documentation. The planned next release will be 2.0.0 MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org ./nsf2.4.0/library/xotcl/doc/Announce-1.6.1000644 000766 000024 00000002262 13331303364 020665 0ustar00neumannstaff000000 000000 Dear XOTcl Community, XOTcl 1.6.1 is available. This release provides in short: - improved orthogonality for introspection, - improvements in the serializer - some minor fixes See below for more details. Best regards -gustaf neumann Announcing XOTcl 1.6.1 ************************* We are pleased to announce the availability of XOTcl 1.6.1 Major changes relative to 1.6.0 are: * Extended and generalized "info" method * Generalized serializing package: when deserializing code, now consistently no constructors are called. In previous versions, constructors were called on slots; due to the point above, this is not needed; background: the previous solution had problems in aolserver ns_eval, when a slot-constructor called db-functions, since during ns_eval, the database handles are non-functional) * Fixes for potential crashes when methods were called with invalid arguments * Improved documentation * Extended regression tests For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org ./nsf2.4.0/library/xotcl/doc/next-path-mixin-movement.gif000644 000766 000024 00000005411 12501766547 024121 0ustar00neumannstaff000000 000000 GIF87a3XF@XFT@<0MNM,@L @ܤv& @@tXXFF XFT4 TM@t^cMvTX~vF @"L @X&F tM@h@fLl\X~F@"& HX F@|KM@HhLM\TlX&F @L& @@tX6X" FKT LcUX4EFt] Zs@$||Mu& @[XaFg X0Fs$TXF|;4TN& NR)nHOT#|@@>H&O @THXF,3H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH XʴӧPJJiҫXׯ`ÊKWYӪUj۷pѮu+ܻxʥרݼ۷pп &l1OārE YWƎ3߬wV΃cLZ&跔HVzՑK˦ymϯ]^<7m]fmW͎ͼdr嫣.[t(/};-嶺(-*E2T7< l-jLqˬں4KtB3^lf+Yh0?\OE sugX .&>#̠>(g:!T^CeaBVG*<4"n 1L4dXp@nXHG]" wX09,!}H/"od`ؙx1eMhQK#q*(F1QF5,aks?Lт4K=$ E "3$rы8]6*hE(^0b4ArC|(DhAsP$ԡ bCџ)OwJҞ>eT RyjPЭNC_%;F5Wڨr:UnX*=zŹƎC|J^ZǤ<|aϓXScXsZ#;2RYeGf2UdYN EhYlK[^e<9KZl8Ԗ } [6bpŶRrKOw1]^%TqZ. eiEkv6b5>uo3Bj/쵷E`9GTn;&1#`KR{_}gVy^C*-~\gN$lcIl7E63xH=2K e)oWŏEʷ[p,!*S8 s 1YLrEK !9\ْwZTܣ+|njDm41hѲ>+f95-c C3Bf7^c.\E;՜ k)SWŦo.9 5;}+=rSm][=M *qLy{l7*ߛNjܰ;'N[8;./nsf2.4.0/library/xotcl/doc/Announce-1.0.2000644 000766 000024 00000004056 13464226762 020700 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.0.2 ********************** WHAT IS XOTCL? XOTcl is an object-oriented extension of Tcl that was derived from OTcl. In short, XOTcl tries to provide a highly flexible, reflective, component-based, and object-oriented environment. It integrates language support for high-level concepts which are not found in other languages, with reasonable performance. It prevails the Tcl programming style and the dynamic/introspective nature of the language, rather than introducing other language's styles and rigidness (such as C++) into Tcl. CHANGES relative to 1.0.1 are: - fixes: * fixes for copying/moving objects to same name * works out of the box with AOL-server 4.0 (no patch for AOL-server needed) * various small fixes and code cleanup * new directory structure (no nested version numbers) * improved object and class serializer - new functionality and improvements: * new method "ismixin": Test whether the argument is a mixin or instmixin of the object. * new method "hasclass": Test whether the argument is either a mixin or instmixin of the object or if it is on the class hierarchy of the object. This method combines the functionalities of istype and ismixin. * arguments of configure methods can start now with a leading "-" without ambiguity. In previous versions Class C -parameter {name counter} C c1 -name -x -counter 123 the configuration of c1 was interpreted as follows method argc name 0 x 0 counter 1 Starting with XOTcl 1.0.2 arguments can be protected by putting it into a list: C c1 [list -name -x] -counter 123 which is interpreted as follows: method argc name 1 counter 1 For more details, please consult the ChangeLog MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/serializer-tcl.html000644 000766 000024 00000027036 13463555432 022373 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/serialize/serializer.tcl

    ./library/serialize/serializer.tcl ./library/serialize/serializer.tcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./library/serialize/serializer.tcl

    Description: This package provides the class Serializer, which can be used to generate a snapshot of the current state of the workspace in the form of XOTcl source code.
    Authors: Gustaf Neumann, Gustaf.Neumann@wu-wien.ac.at


    Class: Serializer

    Procs/Instprocs: all, deepSerialize, exportMethods, methodSerialize, serialize.

    Instprocs

    • serialize entity
      Arguments: entity: Object or Class
      Description: Serialize the specified object or class.
      Return: Object or Class with all currently defined methods, variables, invariants, filters and mixins

    Procs

    • all ?-ignoreVarsRE RE? ?-ignore obj1 obj2 ...?
      Arguments: ?-ignoreVarsRE RE?: provide regular expression; matching vars are ignored
      ?-ignore obj1 obj2 ...?: provide a list of objects to be omitted
      Description: Serialize all objects and classes that are currently defined (except the specified omissions and the current Serializer object).

      Examples:

      Serializer all -ignoreVarsRE {::b$}
      Do not serialize any instance variable named b (of any object).

      Serializer all -ignoreVarsRE {^::o1::.*text.*$|^::o2::x$}
      Do not serialize any variable of c1 whose name contains the string "text" and do not serialze the variable x of o2.

      Serializer all -ignore obj1 obj2 ... 
      do not serizalze the specified objects
      Return: script
    • deepSerialize ?-ignoreVarsRE RE? ?-ignore obj1 obj2 ...? ?-map list? objs
      Arguments: ?-ignoreVarsRE RE?: provide regular expression; matching vars are ignored
      ?-ignore obj1 obj2 ...?: provide a list of objects to be omitted
      ?-map list?: translate object names in serialized code
      objs: Objects to be serialized
      Description: Serialize object with all child objects (deep operation) except the specified omissions. For the description of ignore and ignoreVarsRE see Serizalizer all. map can be used in addition to provide pairs of old-string and new-string (like in the tcl command string map). This option can be used to regenerate the serialized object under a different object or under a different name, or to translate relative object names in the serialized code.

      Examples:

      Serializer deepSerialize -map {::a::b ::x::y} ::a::b::c
      Serialize the object c which is a child of a::b; the object will be reinitialized as object ::x::y::c, all references ::a::b will be replaced by ::x::y.

      Serializer deepSerialize -map {::a::b [self]} ::a::b::c
      The serizalized object can be reinstantiated under some current object, under which the script is evaluated.

      Serializer deepSerialize -map {::a::b::c ${var} ::a::b::c}
      The serizalized object will be reinstantiated under a name specified by the variable var in the recreation context.
      Return: script
    • methodSerialize object method prefix
      Arguments: object: object or class
      method: name of method
      prefix: either empty or 'inst' (latter for instprocs)
      Description: Serialize the specified method. In order to serialize an instproc, prefix should be 'inst'; to serialze procs, it should be empty.

      Examples:

      Serializer methodSerialize Serializer deepSerialize ""
      This command serializes the proc deepSerialize of the Class Serializer.

      Serializer methodSerialize Serializer serialize inst
      This command serializes the instproc serialize of the Class Serializer.

      Return: Script, which can be used to recreate the specified method
    • exportMethods list
      Arguments: list: list of methods of the form 'object proc|instproc methodname'
      Description: This method can be used to specify methods that should be exported in every Serializer all. The rationale behind this is that the serializer does not serialize objects from the namespaces of the basic object systems, which are used for the object system internals and volatile objects. TODO It is however often useful to define methods on ::xotcl::Class or ::xotcl::Objects, which should be exported. One can export procs, instprocs, forward and instforward

      Example:

            Serializer exportMethods {
      	::xotcl::Object instproc __split_arguments
      	::xotcl::Object instproc __make_doc
      	::xotcl::Object instproc ad_proc
      	::xotcl::Class  instproc ad_instproc
      	::xotcl::Object forward  expr
            }



    Back to index page.

    ./nsf2.4.0/library/xotcl/doc/Announce-1.6.0000644 000766 000024 00000007475 13463556670 020717 0ustar00neumannstaff000000 000000 % \section Dear XOTcl Community, XOTcl 1.6.0 is available. This release provides in short: - orthogonality improvements for introspection, - more introspection methods (one can now e.g. query, into which classes a mixin class is mixed into) and - performance improvements (some methods are significantly faster. e.g. by a factor of 1000 for larger systems). In addition, the XOTcl source code follows now closer the Tcl source code guidelines (e.g. variable naming), a few potential crashes have been fixed. See below for more details. Best regards -gustaf neumann Announcing XOTcl 1.6.0 ************************* We are pleased to announce the availability of XOTcl 1.6.0. Major changes relative to 1.5.6 are: * Provide a uniform interface to the following info subcommands info superclass ?-closure? ?pattern? info subclass ?-closure? ?pattern? info instances ?-closure? ?pattern? info instmixin ?-closure? ?pattern? The new option "-closure" returns the transitive set of the relation (e.g. .. info subclass -closure) returns the subclasses and the subclasses of the subclasses. For "info instances -closure" the instances of the subclasses are returned as well. For more details, please see the language reference manual. In cases, where a pattern is specified, and the pattern contains meta-characters, a list of results is returned matching the pattern (like "string match"). When no matching value is found, an empty list is returned. In cases, where a pattern is specified, and the pattern contains no meta-characters, a single value is returned corresponding to the specified value. The pattern is used to lookup an object or class, such it is not necessary to provide fully qualified names). if there is no match, empty is returned. Previously, "info superclass" and "info subclass" returned a boolean value and performed always a transitive search. Returning "" is more consistent and more in line with Tcl. Note that " info superclass -closure" is a replacement for " info heritage", and " info instances -closure" is a replacement for " allinstances". The old commands will be marked as deprecated in the near future. Please note that the behavior of the match pattern has changed and is therefore not completely compatible with prior versions. * New info subcommands: info instmixinof ?-closure? ?pattern? info mixinof ?pattern? These info subcommands are used to determine, into which classes a mixin class was mixed into. These inverse functions of mixin and instmixin are used as well internally. These functions help to speed certain operations (e.g. superclass, or registering a mixin class) up by a factor of 1000 (!) or more, when a large number of objects exist. This functionality was primarily implemented by Martin Matuska. Many thanks! * Made the behavior "pattern" in the following calls identical concerning wild cards and object lookups mixin delete pattern instmixin delete pattern superclass delete pattern info mixin ?pattern? * Fix to preserve var traces when copying objects (Many thanks to Florian Murr for reporting) * Fix problem in Tcl 8.5.* when setting variables from C (problem with Tcl_ObjSetVar2()?); many thanks to Florian Murr and Neophytos Demetriou for reporting) * Improved documentation * Extended regression tests For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org ./nsf2.4.0/library/xotcl/doc/Announce-1.5.6000644 000766 000024 00000003440 13221467131 020671 0ustar00neumannstaff000000 000000 Dear XOTcl Community, XOTcl 1.5.6 is available. This version is mostly a fix release for some problems that were apparently quite long in the code and could cause crashes for threaded applications. best regards -gustaf neumann Announcing XOTcl 1.5.6 ************************* We are pleased to announce the availability of XOTcl 1.5.6. Major changes relative to 1.5.4 are: * Fixes for treating global volatile objects (many thanks to Zoran for his concise reports). The problem was that XOTcl uses C-level var traces containing object pointers to objects. If for some reason, these objects are destroyed earlier, this results in dangling references. This problem caused especially problems in the automatic cleanup of variables at the end of a thread. * Fix for Tcl 8.4.* for situations, where Tcl variables contained references to deleted XOTcl objects. The problem was introduced by the VarReform changes between 1.5.3 and 1.5.4 by a bad side effect of a Tcl_Obj based command to look up Tcl command structures. The problem did not exist for xotcl compiled against Tcl 8.5 and is as well fixed on the Tcl side in CVS (might become available, when one more Tcl 8.4 release is eventually released) * Serializer: - Added dependency rule in serializer to ensure slots of super-classes are listed before subclasses. (Thanks to Stefan Sobernig for reporting the problem) - Moved deactivation of traces into "Serializer all" to get simpler results on "o serialize". * Extended regression tests For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org ./nsf2.4.0/library/xotcl/doc/Announce-1.5.1000644 000766 000024 00000004764 12501766547 020713 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.5.1 ************************* Hi everybody. We are pleased to announce the availability of XOTcl 1.5.1. Major changes relative to 1.5.0 are: * Improved Functionality + Improved interface to develop XOTcl methods in C (Many thanks to Scott Gargash for the constructive discussions and suggestions). New functions imported through the XOTcl's stub interface: - XOTclNextCmd() - XOTclCallMethodWithArgs New constant XOTCL_NONLEAF_METHOD to allow C-implemented methods to call next. This constant can be passed as 5th argument to XOTclAddIMethod (or ...AddPMethod). The following is a short example for defining and registering a C-implemented constructor "init" to a class. static int MyClassInit( ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ) { int rc; /*** before next ***/ rc = XOTclNextObjCmd(cdata, interp, objc,objv); /*** after next ***/ return rc; } ... MyClass = XOTclGetClass(interp, "MyClass" ); XOTclAddIMethod(interp, MyClass, "init", MyClassInit, XOTCL_NONLEAF_METHOD, 0 ); * Improved code quality: + fixed a bug with the backward-compatible and deprecated "setter" interface (many thanks to Manfred Stelzhammer for reporting the bug) + fixed a bug in parsing nonpositional arguments, when e.g. square brackets are used in type declarations for parameters (Many thanks to Stefan Sobernig for reporting) + fixed autoname crash under Windows NT (Many thanks to Mark Janssen for reporting and providing a patch) + fixed serializer to handle deeper stratification layers + simplification and speedup of dispatcher + Makefile.in improvements for genstubs + Changed "test -e" to "test -f" in Makefile.in, since the standard test command in Solaris does not understand "test -e" (Many thanks to Andreas Kupries for reporting) + improved 64-bit compatibility on POWER5+ For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/Announce-0.9.4000644 000766 000024 00000006565 13464226762 020721 0ustar00neumannstaff000000 000000 Announcing XOTcl 0.9.4 ********************** WHAT IS XOTCL? XOTcl is an object-oriented extension of Tcl that was derived from OTcl. In short, XOTcl tries to provide a highly flexible, reflective, component-based, and object-oriented environment. It integrates language support for high-level concepts which are not found in other languages, with reasonable performance. It prevails the Tcl programming style and the dynamic/introspective nature of the language, rather than introducing other language's styles and rigidness (such as C++) into Tcl. CHANGES relative to 0.9.3 are: - fixes: * separate reference counting for XOTcl objects and classes to avoid references from tcl_obj's internal representation to freed memory * fixes for AOL-Server (many thanks to Zoran Vasiljevic for that and for his great help during fixing the problems above) * improved portability: horrible macro substitution bug, when USE_ALLOCA or USE_MALLOC was specified; these are used for some platforms such as AIX * fixing path search for XOTcl library (bug was introduced in 0.9.3 in connection with TEA compliance) * fixed a bug in copy/move (many thanks for Artur Trzewik for reporting this) in connection with constructors (constructors are not called automatically in copy/move operations anymore) * various small fixes in libraries (e.g. HTTP support, generation of pkgIndex-files, using "my", ...) - enhancements: * new global command "my": one can use now: Class Counter -parameter {{n 0}} Counter instproc ++ {} { my incr n } Counter instproc print {} { puts "actual value: [my n]"} Counter c1 c1 ++ c1 print In earlier versions it was necessary to use "[self]" instead of "my". This change reduces the number of special characters in XOTcl programs. "[self]" will continue to be supported by XOTcl. * extended semantics of "new" a) Object new ... b) Object new -childof ... c) Object new -volatile ... d) Object new -volatile -childof ... where (a) creates now "global" objects not in the global namespace anymore, but in the ::xotcl namespace, (b) can be used to create objects as child of other objects (e.g. as children of the actual object [self]; the objects are deleted, when the specified object is deleted). (c) creates are "global" objects as in (a), but they are deleted, when the scope of the current tcl-proc/object-proc/instproc is left and (d) is a combination of (b) and (c). - optimizations: * XOTcl is trying to keep Tcl_Objs of type tclCmdNameType instead of converting it to XOTclObjectType aggressively. * A patch for Tcl 8.4a3 is available from the XOTcl web site for performance hungry applications to provide special byte-code-support for xotcl, that yields for classical benchmark programs up to 40%. This patch is not likely to be integrated into the general Tcl core in the new or distant future. For more details, please consult the ChangeLog MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/Announce-0.9.3000644 000766 000024 00000003702 13464226762 020706 0ustar00neumannstaff000000 000000 Announcing XOTcl 0.9.3 ********************** WHAT IS XOTCL? XOTcl is an object-oriented extension of Tcl that was derived from OTcl. In short, XOTcl tries to provide a highly flexible, reflective, component-based, and object-oriented environment. It integrates language support for high-level concepts which are not found in other languages, with reasonable performance. It prevails the Tcl programming style and the dynamic/introspective nature of the language, rather than introducing other language's styles and rigidness (such as C++) into Tcl. RECENT CHANGES relative to 0.9 are: - A "more or less" TEA compliant build process and its directory structure (aligend it as far as possible to Tcl, sample extension and other extensions) * We started building an XOTcl stub lib. * We separated xotcl from its library/applications (there is an xotcl- directory in the full distribution that just builds, installs, etc. the XOTcl libraries ... this can for instance be used in other distributions using and shipping XOTcl, but not using the shells). * The full distribution still builds shells, but they are using "package require" to load the XOTcl libraries now. * For building xowish (the XOTcl Tk shell) you do only require an installed Tk version on Unix now. - On Windows we still use nmake due to problems with VCC 6.0 in all TEA compliant extensions we have checked, but we use a completely new build process (more or less one-to-one the Unix build process). - A few minor bugfixes. - We have tested this release on platforms we have access to (Linux, Win NT, Solaris). Please inform us, if there are some problems on your platform so that we can eliminate them in future releases. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/Announce-1.1.0000644 000766 000024 00000005632 13464226762 020700 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.1.0 ********************** WHAT IS XOTCL? XOTcl is an object-oriented extension of Tcl that was derived from OTcl. In short, XOTcl tries to provide a highly flexible, reflective, component-based, and object-oriented environment. It integrates language support for high-level concepts which are not found in other languages, with reasonable performance. It prevails the Tcl programming style and the dynamic/introspective nature of the language, rather than introducing other language's styles and rigidness (such as C++) into Tcl. CHANGES relative to 1.0.2 are: - New functionality and improvements: * Transitive instmixins (thanks to a suggestion of Neophytos Demetriou): The new version supports a tree of mixins (mixins of mixins); when a mixin-class X has instmixins Y registered, and X is registered as instmixin for a class C, the mixin classes Y are applied to C as well. * Conditional mixins (thanks to a suggestion of Neophytos Demetriou): mixins and instmixins can have now guards similar to filters that define when they should be applied * New composition strategy for (filter- and mixin-)guards: when a guard is defined more than once for the same interceptor the most specific guard is used, the others are overridden. * Creation of sub-objects via parameter: XOTcl's parameter method supports now a switch named "-Class" which can be used to create and configure sub-objects (see tutorial for details) * New predefined method: __unknown This method is called, whenever XOTcl references a class, which is not defined yet (e.g.: Class C -superclass UNKNOWNCLASS) This method is used for Zoran's wonderful ttrace package (for AOLserver and tcl-Threads) * Improved documentation: - extended tutorial (Meta-Classes, Tk, ...) - beautified tutorial (style files, distinction between literals and placeholders, ...) - fixed hundreds of typos * some speed improvements - fixes: * New build system: - per default no shells are built - new configure switches e.g. --with-xotclsh, -with-actiweb --with-all * Fixes for https in connection with some versions of IE * Fixed a few issues with purify and mt (many thanks to Zoran!) * Fixes for proc-scoped variable in connections with mixins * Fixed passing of error codes from constructors * various small fixes and code cleanup - with newer versions of autoconf - various fixes for stubs - improved build under windows - starkit compliance (many thanks to MichaelL@frogware.com) For more details, please consult the ChangeLog MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/Announce-1.3.3000644 000766 000024 00000003253 13464226762 020702 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.3.3 ********************** WHAT IS XOTCL? XOTcl is an object-oriented extension of Tcl that was derived from OTcl. In short, XOTcl tries to provide a highly flexible, reflective, component-based, and object-oriented environment. It integrates language support for high-level concepts which are not found in other languages, with reasonable performance. It prevails the Tcl programming style and the dynamic/introspective nature of the language, rather than introducing other language's styles and rigidness (such as C++) into Tcl. Major changes relative to 1.3.1 are: - Qualitative Improvements * Improved code quality: + fixed possible segmentation violations in free memory reads (many thanks to Zoran Vasiljevic for his help with purify) + fixed "self callinglevel" when uplevel was called from uplevel + fixed nonposargs + fixed configure in connection with enable-symbols and for AOLserver configuration + extended regression test * Improved Functionality + Producing error message when a non-existing proc/instproc is tried to be deleted + fixed exists method for objects with namespaces by using a namespace resolver + fixed return code for unknown handling in next + reduced memory consumption for objects and classes with procs/instprocs of about 14% * Improved Documentation For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/Announce-1.3.4000644 000766 000024 00000003350 13464226762 020701 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.3.4 ********************** WHAT IS XOTCL? XOTcl is an object-oriented extension of Tcl that was derived from OTcl. In short, XOTcl tries to provide a highly flexible, reflective, component-based, and object-oriented environment. It integrates language support for high-level concepts which are not found in other languages, with reasonable performance. It prevails the Tcl programming style and the dynamic/introspective nature of the language, rather than introducing other language's styles and rigidness (such as C++) into Tcl. Major changes relative to 1.3.3 are: - Qualitative Improvements * Improved code quality: + fixed possible segmentation violations in free memory reads (many thanks to Zoran Vasiljevic for his help with purify) + fixed "self callinglevel" when uplevel was called from uplevel + Improved portability (many thanks to Jeffrey Hobbs) + fixed nonposargs + fixed configure in connection with enable-symbols and for AOLserver configuration + extended regression test * Improved Functionality + Producing error message when a non-existing proc/instproc is tried to be deleted + fixed exists method for objects with namespaces by using a namespace resolver + fixed return code for unknown handling in next + reduced memory consumption for objects and classes with procs/instprocs of about 14% * Improved Documentation For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/next-path.gif000644 000766 000024 00000006663 12501766547 021161 0ustar00neumannstaff000000 000000 GIF87aUB -@path.gif'?@dD@@] 4tdP @t!@@d_P@! @@ltP @d|\$t@@@t\  @: @@Ȑɼ_ @\5čKoؕkmlwOϰ}œ|ggΞ5'@_6 ׁ!NeW{Y~eg( WasZ3!;ƢD!dg $r9dTf?n)Sv\hhf\eU?9'x)UzEНcJY{j'O▃yhB=S\.(|>%^ŅRZ~ZT8НMBk+:JkG+EZӯ.K +2L֚곷2K-fю'eHvif-PQ&r$/I[/{f~H'0Xp50đ&.FS\Dy1ǘ-hxf)y*ch'rܲ2; sk<>< 3ƥ3& =}3K/M?wDLoX+iF'5cw676[vLM0uylGfvnܦ.\`~L+ĉ;t[mcsy.褗~8#k^>i?+:>-HIċYȗ.`Y{dW_0՟HYlw|W^O~z~}к/d ?F?Zod d(-Q## BA JVyx D!H %! .O{#"~'#hBp>$BPA ü!J'p86L  Q/"D$# p hGGo%Gx"E& WH9&'T̤&W()6ȿBj}l Xz|*[½bze)[[R%_)처%2e4G4dLmߺ, N fS')fUƳ*PVNs35S?3K}??%_e( -2 e=-O/E-Q%WDTɧ9C~XqCFczM";Lc禬T=\N#DSu%5+VS'TC**T?ͮ^ +[fxRV*WeQTsTZk׵ Pʱ-I+b٨ {vU(-{ضդQk]eZ֢*WkTd+:[Ѷ[.mnf wA Z&}e?TZR,R^nt;!enlV{ݝ喔YWnZigZ;shVk/ <'s-^3F8kXj 'hU-WVjp}ŖDyZO5 [ʼz]j&nLt0{ _2mq,=!M~DmZޜAjG7RbЕ[8"175,ܴR"C1,N)(*239s=y \I&:'+qc$HE07,Xd7V)+ ԓ}t6c'+U[8l3|FFT>3K+Bg6$z# ETfVf;9smaBJg =B!4jKs)tiEgT]tlTmAV؁±lv0wbgc&&('0uA j6DH0 (3i.kh7|>rP2Wq؆XTgF(i}b36U:X]LYwu8{뵉\剢O\WE8ietxҦxxx؋<88xY懌HW,HM՘ڸ؍8Xx蘎긎؎@;./nsf2.4.0/library/xotcl/doc/Announce-1.5.0000644 000766 000024 00000024114 14274464600 020673 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.5.0 ************************* Hi everybody. We are pleased to announce the availability of XOTcl 1.5.0. Major changes relative to 1.4.0 are: * Improved Functionality + The C-level implementation of XOTcl creates now the basic classes ::xotcl::Object and ::xotcl::Class completely without any methods. All predefined methods are now registered from the initialization script-code (predefined.xotcl) via the new command ::xotcl::alias | \ ?-objscope? ?-per-object? which is used for registering predefined Tcl commands as methods. These aliases are like zero cost forwarders, since they lookup the function pointer from the commands and used these in the methods. This change makes it possible to register the same command on different classes (with maybe different names), such that for example the predefined set method of ::xotcl::Object can be replaced with a different method and the set method can be registered on some other classes (maybe some application classes). This change makes it as well quite easy to develop some other object oriented languages based on the XOTcl framework, since all methods can be rearrange from the Tcl layer . + Slots A slot is a meta-object that manages property-changes of objects. A property is either an attribute or a role of an relation. In a nutshell, a slot has among other attributes - a name (which it used to access it), - a domain (object or class on which it can be used) , and - can be multivalued or not Every slot defines a uniform interface to access its content. So has for example, every multivalued slot a method "add" to add a value to the list of values and a method "remove" to remove it again. We distinguish between system slots (predefined slots like class, superclass, mixin, instmixin, filter, instfilter) and application slots (e.g. attributes of classes). System Slots ======== System slots are predefined slots defining e.g. some relations between classes, or between objects and classes. The predefined system slots are: - superclass: every class in XOTcl has one or more superclasses. The name of this slot is "superclass", the domain is "::xotcl::Class", the slot is multivalued. One object might have multiple superclasses. - class: every object has a class; therefore, the domain of the slot is "::xotcl::Class", the property is not multivalued. - mixin: every object in XOTcl can have one or more mixin classes. The name of this slot is "mixin", the domain is "::xotcl::Object", the slot is multivalued. - instmixin: same as above, but the domain is "::xotcl::Class" - filter, instfilter: similar to "mixin" and "instmixin" Every slot can be used set and query the property from its domain. The syntax for setting values is newValue and for getting its values is set x [ ] Every multivalued slot has as well a method "add" and "remove" Examples for using the system slot "mixin" Object o; Class M; class N o mixin ::M ;# replacing the per-object mixins of o with M o mixin add ::N ;# add N to the front of the mixin list o mixin delete ::M ;# delete M from the mixin list puts [o mixin] ;# query the current mixin list Attribute Slots ========= Attribute slots are used to manage the setting and querying of instance variables. We define now a person with three attributes,"name", "salary" and "projects". Class Person -slots { Attribute name Attribute salary -default 0 Attribute projects -default {} -multivalued true } Examples for using the slots are Person p1 -name "Joe" p1 projects add project1 Some additional features of the slots are: - Support for value checking for * primitive types (all types from "string is", like integer, boolean, ...) * instances of Classes (e.g. value must be an instance of Person) * custom value checkers * uniform interface for single and multi-valued slots - Support for lazy initialization (e.g. when costly commands (like SQL) are used to initialize instance variables, not all variables are used for each object) - more experimental low-level functionality, like * initcmd (executed, whenever the variable is read the first time) * valuecmd (executed, whenever the variable is read) * valuechangedcmd (executed, whenever the variable is altered) For more details, see http://media.wu-wien.ac.at/doc/tutorial.html#slots + Re-implementation of the method "parameter" based on slots. All forms except ... -parameter {name1 {name2 default2}} ... (I.e. pure accessor parameters and parameters with defaults) are deprecated, since slots are the much more powerful and orthogonal construct. The old c-based parameter support based on "parameterclass" is deprecated. It is still in the C-code (the method "parameter" is redefined in predefined.xotcl). If someone urgently needs it, please remove the parameter instproc from predefined for the time being, and write an email to me, in case you really need it). The C code for parameter will be removed in the next release. + Improved introspection though the procsearch method. This method reports now in its second argument not only [inst]proc but as well [inst]forward, [inst]parametercmd and [inst]cmd (the latter for methods implemented in C. * Improved introspection through "info" - new subcommand "info slots" - implemented backwards bug-compatible "info parameter", deprecated + Improved serializer - better handling of cyclical dependencies, when mixins are involved - fix for namespace handling to make the XOTcl communication library classes working with the aolserver (thanks for Stefan Sobernig for pointing this out) - Now other ::xotcl::* objects can be included in the aolserver blueprint (e.g. non positional argument handlers) - handling of slot dependencies - more convenient calling of the serializer: Method "serialize" for Object is defined when the package xotcl::serializer is loaded. + Improved forwarding commands - New option for the argument substitution. When the argument list of the forward command contains "%argclindex {a b c}", then depending of the number of arguments at invocation "a", "b" or "c" is substituted. If more arguments are used at the invocation of the forwarder than values are contained in the list after %argclindex, an error is generated. - New options for forwarder: * The option -earlybinding can be used to look up the function pointer of the called Tcl command at definition time of the forwarder instead of invocation time. This option should only be used for calling C-implemented Tcl commands) * The option -verbose prints the substituted command in the forwarder prior to invocation. + New snit-like utility functions: - ::xotcl::myvar varName: return the fully qualified variable name of the specified variable. - ::xotcl::myproc methodName ?args?: call an XOTcl method without the need of using "[list [self] methodName ...]" Both commands are namespace exported + added "subst" to the set of Tcl imported methods (like e.g. incr, append, ...) On can do now: % Object o ::o % o subst {I am [self]} I am ::o + added new method for ::xotcl::Object named "contains": This method is essentially a value added back-port of the OpenACS version. It allows one to create a nested object structure with little syntactic overhead. See tutorial or language reference for more details. * Improved code quality: + fixed a bug with nonpositional arguments, some positional arguments and "args" + fixed a bug in nonpositional arguments when called without arguments + tested with Tcl 8.4.13 and 8.5a4 + improved error messages in connection with nonpositional arguments + fixed a bug in the xotcl trace module (many thanks to jima for reporting) + fixed a namespace bug in ::xotcl::package require in connection with xotclide (many thanks to Bill Paulsen and Artur Trzewik for identifying the problem and suggesting a fix) + improved documentation (e.g. new sections added, some sections deleted, spelling improved, in total 8 pages longer) + fixed documentation bugs (many thanks for Kristoffer for reporting) + more regression tests added For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/Announce-1.3.5000644 000766 000024 00000004011 14274464600 020670 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.3.5 ********************** WHAT IS XOTCL? XOTcl is an object-oriented extension of Tcl that was derived from OTcl. In short, XOTcl tries to provide a highly flexible, reflective, component-based, and object-oriented environment. It integrates language support for high-level concepts which are not found in other languages, with reasonable performance. It prevails the Tcl programming style and the dynamic/introspective nature of the language, rather than introducing other language's styles and rigidness (such as C++) into Tcl. Major changes relative to 1.3.4 are: - Qualitative Improvements * Improved code quality: + fixed possible segmentation violations in non positional argument handling + moved the Serializer into a namespace such that % package req XOTcl % package req xotcl::serializer Serialize .... works without namespace imports (the Serializer is still auto-exported, but this will change in the future) + * Improved Functionality + Non-positional arguments can be used in the same argument list as positional ones (more compliant with OpenACS). One can write now % Object o % o proc foo {-x:boolean -y a b} { ...} instead of % ... % o proc foo {-x:boolean -y} {a b} { ...} All introspection commands will work like before. The old syntax (with the additional argument) is deprecated and will be dropped in the future. + Serializer: support for objects with parent namespaces, which are not XOTcl objects + additional instproc for ::xotcl::Class allinstances to return all instances for the actual class For more details about the changes, please consult the ChangeLog and documentation. MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/doc/Announce-1.1.1000644 000766 000024 00000003222 13464226762 020672 0ustar00neumannstaff000000 000000 Announcing XOTcl 1.1.1 ********************** WHAT IS XOTCL? XOTcl is an object-oriented extension of Tcl that was derived from OTcl. In short, XOTcl tries to provide a highly flexible, reflective, component-based, and object-oriented environment. It integrates language support for high-level concepts which are not found in other languages, with reasonable performance. It prevails the Tcl programming style and the dynamic/introspective nature of the language, rather than introducing other language's styles and rigidness (such as C++) into Tcl. CHANGES relative to 1.1.0 are: - Improved portability * for macOS (many thanks to Daniel Steffen) * FreeBSD 4.9 (many thanks to Marc Spitzer) - configure can run outside of xotcl-tree and can install to a different directory. Example: % mkdir -p /tmp/xotcl/unix % cd /tmp/xotcl/unix % ~/xotcl-1.1.1/unix/configure --with-all % make % make test % make install DESTDIR=/tmp - several fixes and improvements such as * added option --with-tkinclude for configure (only needed, when built with optional --with-xowish) * made gdbm work when compiled with threads enabled * fix for initialization of stubtables in gdbm * fixes for HTTP support (return format of values in HTTP OPTION command made windows explorer hang) * easy provision for redirects in HTTP server For more details, please consult the ChangeLog MORE INFO General and more detailed information about XOTcl and its components can be found at http://www.xotcl.org Best regards, Gustaf Neumann Uwe Zdun ./nsf2.4.0/library/xotcl/COPYRIGHT000644 000766 000024 00000005037 12501766547 017302 0ustar00neumannstaff000000 000000 /* * Next Scripting Framework * * Copyright (C) 1999-2014 Gustaf Neumann (a) (b) * Copyright (C) 1999-2007 Uwe Zdun (a) (b) * Copyright (C) 2007-2008 Martin Matuska (b) * Copyright (C) 2010-2014 Stefan Sobernig (b) * * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1090, Augasse 2-6 * Vienna, Austria * * This work is licensed under the MIT License * http://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * * This software is based upon MIT Object Tcl by David Wetherall and * Christopher J. Lindblad, that contains the following copyright * message: * * "Copyright 1993 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this * software and its documentation for any purpose is hereby granted * without fee, provided that the above copyright notice appear in * all copies and that both that copyright notice and this * permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity * pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about * the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty." */ ./nsf2.4.0/library/xotcl/apps/comm/secure-webserver.xotcl000755 000766 000024 00000003716 12501766547 024255 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh package require XOTcl 2.0; namespace import -force xotcl::* @ @File { description { This small secure web server that provides its documents via SSL (https, port 8443) and plain http (port 8086).
    This file requires TLS. If you experice problems with versions obtained from the Web, contact gustaf.neumann@wu-wien.ac.at for a patch. } } # # We load the following packages: # package require xotcl::trace package require xotcl::comm::httpd # # we set the default for document root to ../../src/doc and port to 8443 # set root ../../doc set port 8443 set class Httpsd set cb callback ;# use this for triggering the callbacks #set cb "" foreach {att value} $argv { switch -- $att { -root {set root $value} -port {set port $value} -class {set class $value} -cb {set cb $value} } } # # now we can start the web-server instance with these settings # Httpd h0 -port 8086 -root $root $class h1 -port $port -root $root -infoCb $cb \ -requestCert 1 -requireValidCert 0 # Start des HTTP-Servers mit port 8086 und dem angegebenen Verzeichnis #Httpd h2 -port 9086 -root $root \ -mixin {Responder BasicAccessControl} \ -addRealmEntry test {test test} -protectDir test "" {} Object callback callback proc error {chan msg} { puts stderr "+++TLS/$chan: error: $msg" } callback proc verify {chan depth cert rc err} { array set c $cert if {$rc != "1"} { puts stderr "+++TLS/$chan: verify/$depth: Bad Cert: $err (rc = $rc)" } else { puts stderr "+++TLS/$chan: verify/$depth: $c(subject)" } return $rc } callback proc info {chan state minor msg} { # For tracing #upvar #0 tls::$chan cb #set cb($major) $minor #puts stderr "+++TLS/$chan: $major/$minor: $state" puts stderr "+++TLS/$chan $state $minor: $msg" } callback proc unknown {option args} { return -code error "bad option \"$option\": must be one of error, info, or verify" } # # and finally call the event loop... # vwait forever ./nsf2.4.0/library/xotcl/apps/comm/ftp.xotcl000755 000766 000024 00000000420 12501766547 021543 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh package require XOTcl 2.0; namespace import -force xotcl::* @ @File {description { A tiny FTP client }} package require xotcl::comm::ftp SimpleRequest r1 -url ftp://prep.ai.mit.edu/README if {[r1 success]} { puts "Got:" puts [r1 getContent] } ./nsf2.4.0/library/xotcl/apps/comm/filename.key000644 000766 000024 00000001703 12501766547 022173 0ustar00neumannstaff000000 000000 -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,075071A5AF5C1D8A qmihZRxmNNlGCx9lVC4QQPQS25e4aAg3oHjxDaZ0yyDSKsWz4J04lo2x63QT/88i z9YUQqyC8ry53D5y3aQKiFuXlDDvX6PtPS+cQANA8g5qOIHsMF3yINfrVEmWkPjx xOYF2qIGI0ISPTT5AkTN3KVmYE7rbFvqgQMklj/SlNBqeUmKvn1rhUCFAd0jYXa9 imaKVMj08q4GItLAqPoJNY4K73IHZeaW8GEWAJ5E/KEzYFBnYUiPUN8UPCCQsC+b ViRF226hCFSu8yDBah8R/u6W9rEa+Vs/T7Cyklnot2FDyCU0EW/lhKBKfEKTmXAe sBzN7F1hrLFifUD7VzJ2K7zKh7pMy3X+D+0PUjVaIyZWDIH3nOiTzfK6kxksjoE5 P+fp5IL4okEJgD6MoLJHGWTwfhH9K6QBX01My3s22q5zuiJ3SajRCFlLDn7jTTPV 2OQ9+2FksxJYa5Z5/n63Vslz0+yKv9AVTbrtfrbbRJtmpbElCPrvhzVsuWksRS3A biZxD5PkWiYDvNm34eOAOARb7n0awTOZ1bqdccT+rhcvo7c+MypIY0/AfZKZK4hN bWxHR3wZUv+wffx1CBxvsBBomV8XqcqJliVHgdvwDdzl3Z2HbYK3w92RXNY36FYw C1iqALuxE9nhzyEv0ARfjcXTu0lUmFZOfi4oizzMVj7u2q4mGt0+ZuKBs/fTEEm1 3L1nLnalGb5ko5OTZ4DMQlP1HCU3UZslImAcc3FFa/WNzhG07/YAlcTS18YUbJYF 19Yx6qrYfrZA2UZq0+8DFa8XgOHCFO0KqQHRfRB/7tGNGxX5md8+9w== -----END RSA PRIVATE KEY----- ./nsf2.4.0/library/xotcl/apps/comm/webserver.xotcl000644 000766 000024 00000007326 13527046346 022764 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh array set opts {-root ../../doc -port 8086 -protected-port 9096 -pkgdir .} array set opts $argv lappend auto_path $opts(-pkgdir) #if {$::tcl_platform(platform) eq "windows"} {lappend auto_path .} package require XOTcl 2.0; namespace import -force ::xotcl::* proc ! string { set f [open [::xotcl::tmpdir]/log w+]; puts $f "[clock format [clock seconds]] $string" close $f } @ @File { description { This small demo program starts two different webservers:
    • Firstly, it provides a sample web server that povides the documents in ../../src/doc (or the files specified with -root) at port 8086 (or at the port specified via the -port option) as unprotected resources.

    • Secondly, it starts a second webserver with basic access control (it accepts test/test as user/password) on port 9096 (or on the port specified via -protected-port). If it receives a request for an resource named "exit", it terminates. For all other requests it returns actual information about the user and the issued request.
    To see, how it works, contact it e.g. from netscape. } } ! "#### webserver starting" # We load the following packages: # #::xotcl::package import ::xotcl::comm::httpd package require xotcl::comm::httpd ! "#### httpd required" # now we can start the web-server instance with these settings # Httpd h1 -port $opts(-port) -root $opts(-root) @ Httpd h1 {description "unprotected web server"} ! "#### h1 started" # specialized worker, which executes tcl commands in web pages @ Class SpecializedWorker { description { Specialized worker that can be passed to any webserver }} Class SpecializedWorker -superclass Httpd::Wrk @ SpecializedWorker instproc respond {} { description { This method handles all responses from the webserver to the client. We implement here "exit", and we return the information about the actual request and user in HTML format for all other requests.

    This method is an example, how to access on the server side request specific information. }} SpecializedWorker instproc respond {} { if {[my set resourceName] eq "exit"} { set ::forever 1 #my showVars #my set version 1.0;### ???? #puts stderr HERE } # return for all other requests the same response foreach {a v} [my array get meta] { append m $a$v\n } set content {

    Request Info

    method:[my set method]
    resource:[my set resourceName]
    user:[my set user]
    version:HTTP/[my set version]
    response port:[my set port]
    request comes from:[my set ipaddr]

    Request Header Fields

    $m
    } set c [subst $content] my replyCode 200 [self]::connection puts "Content-Type: text/html" [self]::connection puts "Content-Length: [string length $c]\n" [self]::connection puts-nonewline $c my close } @ Httpd h2 { description "Web server with basic authentication using the specialized worker"} if {[info exists env(USER)]} { set USER "$env(USER)" } elseif {[info exists env(USERNAME)]} { set USER "$env(USERNAME)" } else { set USER unknown } if {$::tcl_platform(platform) eq "windows"} { set USER unknown } Httpd h2 -port $opts(-protected-port) -root $opts(-root) \ -httpdWrk SpecializedWorker \ -mixin Httpd::BasicAccessControl \ -addRealmEntry test "u1 test $USER test" -protectDir test "" {} ! "#### h2 started" # # and finally call the event loop... # vwait forever ./nsf2.4.0/library/xotcl/apps/comm/get-regression.xotcl000644 000766 000024 00000012170 13331302503 023665 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh package require XOTcl 2.0; namespace import -force xotcl::* package require xotcl::comm::httpAccess package require xotcl::trace persistentCache clear proc assert {f r} { set got [eval $f] if {$got ne $r } { puts stderr "assertion failed: \[$f\] == $r (got $got)" quit } else { puts stderr "OK $r = $f" } } proc head msg { puts stderr "" puts stderr "---------------------------- $msg" } proc test {msg cmd} { set r [Object autoname r] head $msg if {[catch {eval $cmd} msg]} { puts stderr "ERROR: $::errorInfo" quit } $r destroy } Object userPwd userPwd proc user {u} { my set user $u } userPwd proc show {realm userVar pwVar} { upvar $userVar u $pwVar pw set u [my set user] set pw jogl return 1 } # test "simple request" { # SimpleRequest $r -caching 0 \ # -url http://localhost/index.html # assert "$r getContentLength" 81 # } # test "simple request" { # SimpleRequest $r -caching 1 \ # -url http://localhost/index.html # assert "$r getContentLength" 81 # } # test "simple request" { # SimpleRequest $r -caching 1 \ # -url http://localhost/index.html # assert "$r getContentLength" 81 # } # test "simple request" { # persistentCache invalidate \ # http://localhost/index.html # SimpleRequest $r -caching 1 \ # -url http://localhost/index.html # assert "$r getContentLength" 81 # } # test "simple request" { # SimpleRequest $r -caching 0 \ # -url http://localhost/muster-d1klausur.ps # assert "$r getContentLength" 163840 # } proc parallelRequests {URLs} { JoinSink joinsink -requests [llength $URLs] set i 0 foreach url $URLs { TimedMemorySink sink$i set t$i [Access [Access autoname a] -url $url \ -informObject [list joinsink sink$i] \ -caching 0] incr i } set i 0 foreach url $URLs { sink$i reportTimes;incr i} joinsink destroy } # parallelRequests { # http://localhost/muster-d1klausur.ps # http://localhost/muster-d1klausur2.ps # } # quit foreach c {0 1 2 2} { test "caching $c" { SimpleRequest $r -caching $::c \ -url http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps assert "$r getContentLength" 349970 } } test "simple request" { SimpleRequest $r -caching 0 \ -url http://nestroy.wi-inf.uni-essen.de/Raumplan.html assert "$r getContentLength" 662 } test "simple request, larger file" { SimpleRequest $r -caching 0 \ -url http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps assert "$r getContentLength" 349970 } test "use cache" { SimpleRequest $r -caching 1 \ -url http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps assert "$r getContentLength" 349970 } test "specify filename, use cache and validate request" { persistentCache invalidate \ http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps exec rm -f test.ps SimpleRequest $r -caching 1 -fileName test.ps \ -url http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps assert "$r getContentLength" 349970 assert "file size test.ps" 349970 assert {lindex [exec md5sum test.ps] 0} c6029c987e841430f3ca9bab157da12f } test "specify filename, and use cache and a validated file" { exec rm -f test.ps SimpleRequest $r -caching 1 -fileName test.ps \ -url http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps assert "$r getContentLength" 349970 assert "file size test.ps" 349970 assert {lindex [exec md5sum test.ps] 0} c6029c987e841430f3ca9bab157da12f } test "specify filename, and do not use cache" { exec rm -f test.ps SimpleRequest $r -fileName test.ps -caching 0 \ -url http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps assert "$r getContentLength" 349970 assert "file size test.ps" 349970 assert {lindex [exec md5sum test.ps] 0} c6029c987e841430f3ca9bab157da12f } test "specify filesink and use cache; no copying necessary" { persistentCache invalidate \ http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps SimpleRequest $r -useFileSink 1 -caching 1 \ -url http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps assert "$r getContentLength" 349970 assert "file size test.ps" 349970 } test "load a large file to the cache" { persistentCache clearEntry http://swt.wi-inf.uni-essen.de/lx2.1.55 SimpleRequest $r -caching 1 \ -url http://swt.wi-inf.uni-essen.de/lx2.1.55 assert "$r getContentLength" 522411 } test "load a validated large file" { SimpleRequest $r -caching 1 \ -url http://swt.wi-inf.uni-essen.de/lx2.1.55 assert "$r getContentLength" 522411 } test "pure loading test without cache" { SimpleRequest $r -caching 0 \ -url http://swt.wi-inf.uni-essen.de/lx2.1.55 assert "$r getContentLength" 522411 } test "redirect" { SimpleRequest $r -caching 1 \ -url http://mohegan.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps assert "$r getContentLength" 349970 } test "authentication" { SimpleRequest $r -caching 1 \ -url http://nestroy.wi-inf.uni-essen.de/cgi-bin/w3-msql/Forschung/Publikationen/protected/index.html assert "$r getContentLength" 1164 } puts stderr after quit ### request joining ### load to file depending on content type ./nsf2.4.0/library/xotcl/apps/comm/server.key000644 000766 000024 00000001567 12501766547 021731 0ustar00neumannstaff000000 000000 -----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQDVg+HdA4RAKyYRaxKRSdAw7mQpephZslIf/ZR7Oe3RKZjxu7Sj PYG56GSc8y6hiaKuGnDmJcEGXZCXWNtUuACVsNlFrlVbGSEfAbXbz6H4eaaX2d2P KzrjOc//8+5emaFZRelVTYY4sWNLcCuWV2FIhwMJMblYieXM6iEQg4XzdQIDAQAB AoGAVdY2OC8QvOdb34bHKSeejf1YwSArHWxF/dxpE/0e8YaimRQYM8QnYgDeagaN yZ1WjF3O44dsCU4WMfIkAvQSL19RLSgT+jPb3Uu9Aotwmg4x+55BKctRphXKiIfu +a0IfAFDIt8FMRS08AoSB6eBgOBlhTZM2Y0IuC6QTqaBcwUCQQD5XSiEzh44uMOl N4FbO0MI2NC3pbPg5u1fEJtIawoYOYxbeGHrlOYO2ZN3ZP6+2g5V0kX5tMMeObhE qQLlmNETAkEA2zJ/Tk3IE5ByEBcGjG26nJ1zLlY13NaiIg+AoSP+7rHg5TPhoQp1 VVwcqd4ZWCyqgYDFl2TsiiZwKcEIFJBCVwJBANoLpZSLD04V8a2UXV5C8ZjYzZjo IeP0yXco9D9cqZUJLTwGhckTiB9QDWyHOWH1FjfhCCMS9tKFMiWHi+rrt1UCQQDC rlvxURX1gmI8NicjzEVk2la1fe5C4QKJW9lzxUOj/qpvB6BK5r4FfVUb7d32uV0K vjNAXmvT24XdH8usb9/rAkBR1sqUkqwwm0CSe0Rz9IhSlkwWlmvEzSmEguqrd7Zb rbYJ9NTnV1uFSAX9vcU7lDRp69il6XmyhOL06FYLRaNa -----END RSA PRIVATE KEY----- ./nsf2.4.0/library/xotcl/apps/comm/link-checker.xotcl000644 000766 000024 00000011034 13463555603 023306 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh # -gn july 2000 package require XOTcl 2.0; namespace import -force xotcl::* @ @File { description { A simple link checking program that checks in parallel pages of a site.

    Options:

    -url Start-URL
    -foreign 0 or 1, specifies, whether foreign links of local pages should be checked (default 1)
    -local A string match pattern to decide which url should be treated as local e.g. -local *wu-wien.ac.at/* Per default the locality filter is set to the name of the host followed by '/*'
    -restrict 0 or 1, sets the locality filter to the subtree implied by the URL
    -verbose 0 or 1 or 2, verbosity level (default 0)
    } } if {$tcl_version<8.2} { puts stderr "This script requires Tcl 8.2 or newer" exit -1 } set opt(-url) http://localhost:8000/ set opt(-url) http://nm.wu-wien.ac.at/Lehre/ set opt(-verbose) 0; # 0, 1 (show check), or 2 (show ignore) set opt(-foreign) 1; # 0, 1 (check foreign links on local pages) set opt(-restrict) 0; # 0, 1 ## per default, lc checks the array set opt $argv if {$opt(-restrict)} { regexp {://(.*)$} $opt(-url) _ opt(-local) set opt(-local) [string trimright $opt(-local) /]* puts stderr "locality filter set to '$opt(-local)'" } if {![info exists opt(-local)]} { regexp {http://([^/:]+)} $opt(-url) _ opt(-local) append opt(-local) /* puts stderr "locality filter set to '$opt(-local)'" } #package require xotcl::package; package verbose 1 package require xotcl::comm::httpAccess package require xotcl::trace proc printError {m} {} Class Checker -superclass ParallelSink \ -parameter {verbose foreign local} Checker array set ref {A HREF IMG SRC} Checker set ref_re {[[:space:]]*=[[:space:]]*([[:graph:]]+)} Checker instproc report {msg {level 1}} { my instvar verbose if {$verbose>$level} {puts stderr $msg} return 0 } Checker instproc isLocal {url} { my instvar local string match *://$local $url } Checker instproc isToCheck {url request methodvar} { my instvar foreign upvar $methodvar method if {![regexp -nocase {http://([^/:]+)} $url _ host]} { return [my report "ignored, no http: $url"] } set method GET if {![my isLocal $url]} { if {$foreign} { #puts stderr "parenturl: [$request set parentUrl] -> [my isLocal [$request set parentUrl]]" if {[$request info vars parentUrl] ne "" && ![my isLocal [$request set parentUrl]]} { return [my report "ignored, nor local: $url"] } else { set method HEAD } } else { return [my report "ignored, nor local: $url"] } } if {[regexp -nocase {[.](gif|jpg|ps|pdf|gz)$} $url]} { set method HEAD #return [my report "ignored due to extension: $url"] } return 1 } Checker instproc checkLink {request link} { set resolved [resolve $link [$request set url]] if {[my isToCheck $resolved $request method]} { my instvar checked if {![info exists checked($resolved)]} { my report "checking .......... $resolved" 0 set checked($resolved) 1 my scheduleRequest $method $resolved [$request set url] } else { #puts stderr "already checked $resolved" } } } Checker instproc checkText {request} { if {![my isLocal [$request set url]]} return [self class] instvar ref ref_re set content [$request getContent] set start 0 while {[regexp -nocase -indices -start $start -- \ {<(A|IMG)([^>]*?)} $content a b c]} { set elem [string toupper \ [string range $content [lindex $b 0] [lindex $b 1]]] set attribs [string range $content [lindex $c 0] [lindex $c 1]] #regsub -all {[\n ]+} $attribs " " attribs if {[regexp -nocase $ref($elem)$ref_re $attribs _ i]} { my checkLink $request [string trim $i '\"] } set start [lindex $c 1] } } Checker instproc endCb r { #showObj $r switch [$r set contentType] { text/html {my checkText $r} } next } Checker instproc cancelCb r { #$r showVars puts stderr "ERROR in page [$r set parentUrl]" puts stderr " Link: [$r set url]" puts stderr " cause [$r set errormsg]\n" next } Checker csink \ -verbose $opt(-verbose) -foreign $opt(-foreign) -local $opt(-local) \ -sinkClass MemorySink -httpVersion 1.0 -maxsimultaneous 30 csink requests $opt(-url) puts stderr "sumbytes: [csink set sumbytes] requests: [csink set numrequests]" csink destroy ./nsf2.4.0/library/xotcl/apps/comm/test-tls-client.xotcl000755 000766 000024 00000004230 12501766547 024010 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh # -*- Tcl -*- package require XOTcl 2.0; namespace import ::xotcl::* package require tls proc bgerror {err} { global errorInfo puts stderr "BG Error: $errorInfo" } array set opts { -port 8443 -host localhost } array set opts $argv proc readCB {CHAN} { #puts stderr "*** CALL: readCB $CHAN" if {![eof $CHAN]} { set rData [gets $CHAN] puts stderr "\nREADING ..." puts stderr "------------------------------------------------------" puts stderr <$rData> puts stderr "------------------------------------------------------" #fileevent $CHAN writable [list writeCB $CHAN] } else { catch {close $CHAN} puts stderr "\nSocket ($CHAN) is closed." exit } } proc writeCB {CHAN} { #puts stderr "*** CALL: writeCB $CHAN" #puts stderr "fileevent $CHAN writable {}" fileevent $CHAN writable {} set wData "GET / HTTP/1.1\r\nHost: localhost\r\nAccept: */*\r\n\r\n" #set wData "GET\n" puts -nonewline $CHAN $wData flush $CHAN #puts stderr "\nfileevent $CHAN readable [list readCB $CHAN]" fileevent $CHAN readable [list readCB $CHAN] } puts stderr "\n\n\n~~~~~~~~~~~~ Trying $opts(-host):$opts(-port)" # # Create socket # set chan [socket -async $opts(-host) $opts(-port)] tls::import $chan -command callback -cafile cacert.pem -certfile client.pem -server 0 -keyfile client.key -request 1 -require 1 puts stderr "setting channel to auto binary" fconfigure $chan -translation {auto binary} puts stderr "fileevent $chan writable [list writeCB $chan]" fileevent $chan writable [list writeCB $chan] Object callback callback proc error {chan msg} { puts stderr "+++TLS/$chan: error: $msg" } callback proc verify {chan depth cert rc err} { array set c $cert if {$rc != "1"} { puts stderr "+++TLS/$chan: verify/$depth: Bad Cert: $err (rc = $rc)" } else { puts stderr "+++TLS/$chan: verify/$depth: $c(subject)" } return $rc } callback proc info {chan state minor msg} { puts stderr "+++TLS/$chan $state $minor: $msg" } callback proc unknown {option args} { my showCall return -code error "bad option \"$option\": must be one of error, info, or verify" } vwait forever ./nsf2.4.0/library/xotcl/apps/comm/server.pem000644 000766 000024 00000006764 12501766547 021726 0ustar00neumannstaff000000 000000 issuer :/C=DE/ST=NRW/L=Essen/O=University of Essen/OU=SWT/CN=Fredj Dridi/Email=Fredj.Dridi@uni-essen.de subject:/C=DE/ST=NRW/L=Essen/O=University of Essen/OU=SWT/CN=tp600e.wi-inf.uni-essen.de/Email=dridi@tp600e.wi-inf.uni-essen.de serial :01 Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: md5WithRSAEncryption Issuer: C=DE, ST=NRW, L=Essen, O=University of Essen, OU=SWT, CN=Fredj Dridi/Email=Fredj.Dridi@uni-essen.de Validity Not Before: Apr 28 08:21:19 2000 GMT Not After : Apr 28 08:21:19 2001 GMT Subject: C=DE, ST=NRW, L=Essen, O=University of Essen, OU=SWT, CN=tp600e.wi-inf.uni-essen.de/Email=dridi@tp600e.wi-inf.uni-essen.de Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:d5:83:e1:dd:03:84:40:2b:26:11:6b:12:91:49: d0:30:ee:64:29:7a:98:59:b2:52:1f:fd:94:7b:39: ed:d1:29:98:f1:bb:b4:a3:3d:81:b9:e8:64:9c:f3: 2e:a1:89:a2:ae:1a:70:e6:25:c1:06:5d:90:97:58: db:54:b8:00:95:b0:d9:45:ae:55:5b:19:21:1f:01: b5:db:cf:a1:f8:79:a6:97:d9:dd:8f:2b:3a:e3:39: cf:ff:f3:ee:5e:99:a1:59:45:e9:55:4d:86:38:b1: 63:4b:70:2b:96:57:61:48:87:03:09:31:b9:58:89: e5:cc:ea:21:10:83:85:f3:75 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Authority Key Identifier: keyid:D2:B8:E3:2D:A2:5A:22:78:3A:38:F1:1F:F5:7C:AD:8D:A6:C4:41:0F X509v3 Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication, Microsoft Server Gated Crypto, Netscape Server Gated Crypto X509v3 Basic Constraints: critical CA:FALSE Signature Algorithm: md5WithRSAEncryption 38:b5:a1:1c:93:c4:aa:6e:3f:d6:ea:11:7f:7b:2b:11:db:7b: 22:b3:d2:a8:b3:f3:20:64:6a:25:b4:fe:0d:ac:12:49:a0:6e: 6d:ef:fb:99:a2:7c:bc:50:b0:eb:42:ef:0a:32:fa:a9:69:e0: 11:10:9b:00:05:15:97:59:ac:dc:5f:f2:cd:81:28:3e:e6:96: 86:f4:d7:99:71:52:c3:ca:0f:4a:48:d8:66:b0:da:e8:d1:45: 84:c4:12:b2:43:ec:63:b6:25:e8:0a:5a:4c:fb:e2:ec:03:36: 6f:cd:f9:2a:5c:52:ba:02:29:92:f5:bf:c4:96:ff:9e:ed:a3: cf:02 -----BEGIN CERTIFICATE----- MIIDIjCCAougAwIBAgIBATANBgkqhkiG9w0BAQQFADCBljELMAkGA1UEBhMCREUx DDAKBgNVBAgTA05SVzEOMAwGA1UEBxMFRXNzZW4xHDAaBgNVBAoTE1VuaXZlcnNp dHkgb2YgRXNzZW4xDDAKBgNVBAsTA1NXVDEUMBIGA1UEAxMLRnJlZGogRHJpZGkx JzAlBgkqhkiG9w0BCQEWGEZyZWRqLkRyaWRpQHVuaS1lc3Nlbi5kZTAeFw0wMDA0 MjgwODIxMTlaFw0wMTA0MjgwODIxMTlaMIGtMQswCQYDVQQGEwJERTEMMAoGA1UE CBMDTlJXMQ4wDAYDVQQHEwVFc3NlbjEcMBoGA1UEChMTVW5pdmVyc2l0eSBvZiBF c3NlbjEMMAoGA1UECxMDU1dUMSMwIQYDVQQDExp0cDYwMGUud2ktaW5mLnVuaS1l c3Nlbi5kZTEvMC0GCSqGSIb3DQEJARYgZHJpZGlAdHA2MDBlLndpLWluZi51bmkt ZXNzZW4uZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANWD4d0DhEArJhFr EpFJ0DDuZCl6mFmyUh/9lHs57dEpmPG7tKM9gbnoZJzzLqGJoq4acOYlwQZdkJdY 21S4AJWw2UWuVVsZIR8BtdvPofh5ppfZ3Y8rOuM5z//z7l6ZoVlF6VVNhjixY0tw K5ZXYUiHAwkxuViJ5czqIRCDhfN1AgMBAAGjZzBlMB8GA1UdIwQYMBaAFNK44y2i WiJ4OjjxH/V8rY2mxEEPMDQGA1UdJQQtMCsGCCsGAQUFBwMBBggrBgEFBQcDAgYK KwYBBAGCNwoDAwYJYIZIAYb4QgQBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEE BQADgYEAOLWhHJPEqm4/1uoRf3srEdt7IrPSqLPzIGRqJbT+DawSSaBube/7maJ8 vFCw60LvCjL6qWngERCbAAUVl1ms3F/yzYEoPuaWhvTXmXFSw8oPSkjYZrDa6NFF hMQSskPsY7Yl6ApaTPvi7AM2b835KlxSugIpkvW/xJb/nu2jzwI= -----END CERTIFICATE----- ./nsf2.4.0/library/xotcl/apps/comm/client.pem000644 000766 000024 00000006340 12501766547 021664 0ustar00neumannstaff000000 000000 issuer :/C=DE/ST=NRW/L=Essen/O=University of Essen/OU=SWT/CN=Fredj Dridi/Email=Fredj.Dridi@uni-essen.de subject:/CN=Fredj Dridi/Email=fredj_dridi@yahoo.com serial :02 Certificate: Data: Version: 3 (0x2) Serial Number: 2 (0x2) Signature Algorithm: md5WithRSAEncryption Issuer: C=DE, ST=NRW, L=Essen, O=University of Essen, OU=SWT, CN=Fredj Dridi/Email=Fredj.Dridi@uni-essen.de Validity Not Before: Apr 28 08:24:43 2000 GMT Not After : Apr 28 08:24:43 2001 GMT Subject: CN=Fredj Dridi/Email=fredj_dridi@yahoo.com Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:e4:df:a7:f3:ed:61:df:30:ad:d9:6f:63:f2:d1: 85:9b:72:b2:c6:e4:fd:50:11:c5:0a:29:59:02:60: 29:f6:2c:6a:35:08:89:49:ad:d4:44:1d:7f:14:18: 61:4d:e8:66:87:30:01:52:cd:7d:16:72:0e:24:38: 19:a5:a7:dc:cf:7a:5d:79:ea:48:c6:c4:ae:52:a6: 94:36:7f:f3:24:43:b0:21:5a:f2:d5:6d:66:38:4c: b7:7a:0e:ce:12:01:b0:46:4b:ea:08:b4:e0:aa:b8: 96:dc:3e:15:e0:24:92:84:1f:77:d0:8d:73:d2:f3: ac:82:b0:61:60:1a:6a:fc:b9 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Alternative Name: email:fredj_dridi@yahoo.com X509v3 Basic Constraints: critical CA:FALSE X509v3 Authority Key Identifier: keyid:D2:B8:E3:2D:A2:5A:22:78:3A:38:F1:1F:F5:7C:AD:8D:A6:C4:41:0F X509v3 Extended Key Usage: TLS Web Client Authentication, E-mail Protection Signature Algorithm: md5WithRSAEncryption 01:88:26:35:b9:c7:c9:5a:90:ff:b8:9c:37:fa:48:0e:03:82: b4:18:df:49:e7:5d:42:3a:48:e3:e4:84:c7:b6:ef:cc:91:4c: 47:9d:34:f9:51:0b:63:d0:35:f9:ad:a5:a9:3d:ef:75:23:0c: 14:77:59:79:59:58:c8:74:df:01:b8:de:f2:78:47:64:1a:7e: 4b:09:31:5e:f5:34:e2:ad:5e:e8:81:00:f1:af:fe:48:31:0b: a9:b1:4d:53:51:9a:15:1f:55:ba:30:e4:0e:02:05:20:4b:de: 9c:d9:86:f1:e4:d9:18:c4:93:03:19:06:a5:f3:cb:2a:28:a0: fd:de -----BEGIN CERTIFICATE----- MIICuzCCAiSgAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBljELMAkGA1UEBhMCREUx DDAKBgNVBAgTA05SVzEOMAwGA1UEBxMFRXNzZW4xHDAaBgNVBAoTE1VuaXZlcnNp dHkgb2YgRXNzZW4xDDAKBgNVBAsTA1NXVDEUMBIGA1UEAxMLRnJlZGogRHJpZGkx JzAlBgkqhkiG9w0BCQEWGEZyZWRqLkRyaWRpQHVuaS1lc3Nlbi5kZTAeFw0wMDA0 MjgwODI0NDNaFw0wMTA0MjgwODI0NDNaMDwxFDASBgNVBAMTC0ZyZWRqIERyaWRp MSQwIgYJKoZIhvcNAQkBFhVmcmVkal9kcmlkaUB5YWhvby5jb20wgZ8wDQYJKoZI hvcNAQEBBQADgY0AMIGJAoGBAOTfp/PtYd8wrdlvY/LRhZtyssbk/VARxQopWQJg KfYsajUIiUmt1EQdfxQYYU3oZocwAVLNfRZyDiQ4GaWn3M96XXnqSMbErlKmlDZ/ 8yRDsCFa8tVtZjhMt3oOzhIBsEZL6gi04Kq4ltw+FeAkkoQfd9CNc9LzrIKwYWAa avy5AgMBAAGjcjBwMCAGA1UdEQQZMBeBFWZyZWRqX2RyaWRpQHlhaG9vLmNvbTAM BgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFNK44y2iWiJ4OjjxH/V8rY2mxEEPMB0G A1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDANBgkqhkiG9w0BAQQFAAOBgQAB iCY1ucfJWpD/uJw3+kgOA4K0GN9J511COkjj5ITHtu/MkUxHnTT5UQtj0DX5raWp Pe91IwwUd1l5WVjIdN8BuN7yeEdkGn5LCTFe9TTirV7ogQDxr/5IMQupsU1TUZoV H1W6MOQOAgUgS96c2Ybx5NkYxJMDGQal88sqKKD93g== -----END CERTIFICATE----- ./nsf2.4.0/library/xotcl/apps/comm/filename.crt000644 000766 000024 00000002432 12501766547 022173 0ustar00neumannstaff000000 000000 -----BEGIN CERTIFICATE----- MIIDmDCCAwGgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBlTELMAkGA1UEBhMCYXQx EDAOBgNVBAgTB0F1c3RyaWExDzANBgNVBAcTBlZpZW5uYTEQMA4GA1UEChMHV1Ut V2llbjELMAkGA1UECxMCV0kxHjAcBgNVBAMTFW1vaGVnYW4ud3Utd2llbi5hYy5h dDEkMCIGCSqGSIb3DQEJARYVbmV1bWFubkB3dS13aWVuLmFjLmF0MB4XDTAyMDQw MjEwNDUwN1oXDTAyMDUwMjEwNDUwN1owgZUxCzAJBgNVBAYTAmF0MRAwDgYDVQQI EwdBdXN0cmlhMQ8wDQYDVQQHEwZWaWVubmExEDAOBgNVBAoTB1dVLVdpZW4xCzAJ BgNVBAsTAldJMR4wHAYDVQQDExVtb2hlZ2FuLnd1LXdpZW4uYWMuYXQxJDAiBgkq hkiG9w0BCQEWFW5ldW1hbm5Ad3Utd2llbi5hYy5hdDCBnzANBgkqhkiG9w0BAQEF AAOBjQAwgYkCgYEA5iT1aT1zU5mfqabGQWcdLyGVFlJBuiKnD2wCVDBIJFVYk6EJ FrFadKgUXNa0Sxrav/5BJyG2ObOrS4BH6yAl8f90QbAokFp9HeW5wkkAhjkSe1Rw vcts9F+R6OhcBxO+tQ6maR9wIGfWoK+vWDyfO7wnHjiL2YZFW73mDBUuHO8CAwEA AaOB9TCB8jAdBgNVHQ4EFgQUbnmEzLNHBNqySdNmPzLSf+yjEc8wgcIGA1UdIwSB ujCBt4AUbnmEzLNHBNqySdNmPzLSf+yjEc+hgZukgZgwgZUxCzAJBgNVBAYTAmF0 MRAwDgYDVQQIEwdBdXN0cmlhMQ8wDQYDVQQHEwZWaWVubmExEDAOBgNVBAoTB1dV LVdpZW4xCzAJBgNVBAsTAldJMR4wHAYDVQQDExVtb2hlZ2FuLnd1LXdpZW4uYWMu YXQxJDAiBgkqhkiG9w0BCQEWFW5ldW1hbm5Ad3Utd2llbi5hYy5hdIIBADAMBgNV HRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4GBANj6u54TmwEJg/Ldvfx+Qrax+66n zh1EYzxrlYp6eNQVPEyOsF1DJh150Lci1Mm/i71D87yJRVjagTv5dAUdupy9Zf6c AMMv6KvK5G7q6LC9ArwNiBObsmQUlN7+PzRmG9CerRJ6W8eEYnYB0EHhYVKc8cED F4mixcF1HGQJI/qN -----END CERTIFICATE----- ./nsf2.4.0/library/xotcl/apps/comm/test-tls-server.xotcl000755 000766 000024 00000004204 12501766547 024041 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh # -*- Tcl -*- # # sample secure server that reflect all incoming data to the client # It uses tls1.3 package of Matt Newman # Fredj Dridi package require XOTcl 2.0; namespace import ::xotcl::* package require tls proc bgerror {err} { global errorInfo puts stderr "BG Error: $errorInfo" } # # Sample callback - just reflect data back to client # proc reflectCB {chan {verbose 0}} { puts stderr "\n*** reflectCB $chan $verbose" fconfigure $chan -translation {auto crlf} set data {} if {[catch {set n [::gets $chan data]} msg]} { set error $msg puts stderr "\nEOF ($data)" catch {close $chan} return 0 } puts stderr n=<$n> if {$verbose && $data ne ""} { puts stderr "data=<$data>" } if {[eof $chan]} { ;# client gone or finished puts stderr "\nEOF" close $chan ;# release the servers client channel return } #puts -nonewline $chan $data #flush $chan } proc acceptCB { chan ip port } { puts stderr "\n*** acceptCB $chan $ip $port" tls::import $chan -cafile cacert.pem -certfile server.pem \ -server 1 -request 1 -require 1 -keyfile server.key -command callback if {![tls::handshake $chan]} { puts stderr "\nHandshake pending" return } array set cert [tls::status $chan] puts stderr "\n" parray cert fileevent $chan readable [list reflectCB $chan 1] } set chan [socket -server acceptCB 8443] puts stderr "Server waiting connection on $chan (8443)" ## Sample Callback that gives SSL information Object callback callback proc error {chan msg} { puts stderr "+++TLS/$chan: error: $msg" } callback proc verify {chan depth cert rc err} { array set c $cert if {$rc != "1"} { puts stderr "+++TLS/$chan: verify/$depth: ** Bad Cert **: $err (rc = $rc)" } else { puts stderr "+++TLS/$chan: verify/$depth: $c(subject)" } return $rc } callback proc info {chan state minor msg} { puts stderr "+++TLS/$chan $state $minor: $msg" } callback proc unknown {option args} { my showCall return -code error "bad option \"$option\": must be one of error, info, or verify" } # Go into the eventloop vwait forever ./nsf2.4.0/library/xotcl/apps/comm/get-regression-nb.xotcl000644 000766 000024 00000030553 13524464627 024313 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh package require XOTcl 2.0; namespace import -force xotcl::* # ./get-regression-nb.xotcl -host swt -parallel 0 # ./get-regression-nb.xotcl -host swt -sequential 0 # # mit ~/wafe/src/cineast/webserver.xotcl (benotigt ~/wafe/test/*) # ./get-regression-nb.xotcl -port 8086 # # Vergleich webserver.xotcl mit Apache: # 1) installation von Apache auf port 80 # # 2) installation vom webserver.xotcl auf port 8086 # # 3) von beiden server sollend die files in wafe/test/* unter # http://SERVER+PORT/test/* # erreichbar sein. # # 4) test der installation # apache: # cd wafe/src/cineast # get-regression-nb.xotcl -sequential 0 # die ausgabe sollte mit totalbytes=6536120 # abgeschlossen werden # # webserver.xotcl: # cd wafe/src/cineast # get-regression-nb.xotcl -port 8086 -sequential 0 # die Ausgabe sollte mit totalbytes=6536120 # abgeschlossen werden # # 5) grosser testlauf: # rsh muss funktionieren: z.B.: rsh localhost date # # apache: # cd wafe/src/cineast # time get-regression-nb.xotcl -sequential 0 -clients 1 # # webserver.xotcl: # cd wafe/src/cineast # time get-regression-nb.xotcl -port 8086 -sequential 0 -clients 1 # # Results on my PC # # the xotcl webserver is about 20% slower than Apache. # Deactivate logging (instproc log) costs a few more percent. # -gn # # mohegan:~/wafe/src/cineast> time ./get-regression-nb.xotcl -port 8086 -sequential 0 -clients 1 # Loading source file ~/wafe/src/cineast/Access.xotcl # Loading source file ~/wafe/src/cineast/PCache.xotcl # Loading source file ~/wafe/src/cineast/Connection.xotcl # Loading source file ~/wafe/src/cineast/trace.xotcl # 1 clients: 3.07 seconds (per client 3.07 seconds, 2127.31 KB/sec) server: 2127.31 KB/sec # 2 clients: 6.36 seconds (per client 3.18 seconds, 1028.10 KB/sec) server: 2056.20 KB/sec # 3 clients: 7.71 seconds (per client 2.57 seconds, 847.74 KB/sec) server: 2543.22 KB/sec # 4 clients: 11.21 seconds (per client 2.80 seconds, 582.92 KB/sec) server: 2331.66 KB/sec # 5 clients: 10.57 seconds (per client 2.11 seconds, 618.49 KB/sec) server: 3092.45 KB/sec # 10 clients: 25.07 seconds (per client 2.51 seconds, 260.68 KB/sec) server: 2606.79 KB/sec # 20 clients: 45.48 seconds (per client 2.27 seconds, 143.73 KB/sec) server: 2874.58 KB/sec #0.420u 0.450s 1:49.65 0.7% 0+0k 0+0io 113263310pf+0w # # # # mohegan:~/wafe/src/cineast> time ./get-regression-nb.xotcl -port 80 -sequential 0 -clients 1 # Loading source file ~/wafe/src/cineast/Access.xotcl # Loading source file ~/wafe/src/cineast/PCache.xotcl # Loading source file ~/wafe/src/cineast/Connection.xotcl # Loading source file ~/wafe/src/cineast/trace.xotcl # 1 clients: 1.85 seconds (per client 1.85 seconds, 3542.58 KB/sec) server: 3542.58 KB/sec # 2 clients: 4.71 seconds (per client 2.36 seconds, 1387.02 KB/sec) server: 2774.03 KB/sec # 3 clients: 4.09 seconds (per client 1.36 seconds, 1596.58 KB/sec) server: 4789.74 KB/sec # 4 clients: 7.74 seconds (per client 1.94 seconds, 844.43 KB/sec) server: 3377.71 KB/sec # 5 clients: 9.46 seconds (per client 1.89 seconds, 690.67 KB/sec) server: 3453.33 KB/sec # 10 clients: 20.91 seconds (per client 2.09 seconds, 312.52 KB/sec) server: 3125.24 KB/sec # 20 clients: 39.01 seconds (per client 1.95 seconds, 167.55 KB/sec) server: 3351.08 KB/sec #0.410u 0.360s 1:27.95 0.8% 0+0k 0+0io 112251994pf+0w # # set CACHE_DIR [::xotcl::tmpdir] package require xotcl::comm::httpAccess package require xotcl::trace set port "" set host localhost set cachingopts {0 1 2 2} set parallel 1 set sequential 0 set clients 0 set local 1 foreach {att val} $argv { switch -exact -- $att { -port {set port $val} -host {set host $val} -memory {set cachingopts 0} -parallel {set parallel $val} -sequential {set sequential $val} -clients {set clients $val} -local {set local $val} } } set hosts { R2H2-11 R2H2-12 R2H2-13 R2H2-21 R2H2-22 R2H2-23 R2H2-31 R2H2-32 R2H2-33 R2H2-41 R2H2-42 R2H2-43 R2H2-51 R2H2-52 R2H2-53 R2H2-61 R2H2-62 R2H2-63 R2H2-73 matush nashawag sagumumpsketuck wawog willimantic wonkituck mashipaug watuppa } #set hosts { # matush nashawag sagumumpsketuck wawog willimantic wonkituck mashipaug # R2H2-11 R2H2-12 R2H2-13 R2H2-21 R2H2-22 R2H2-23 R2H2-31 R2H2-32 # R2H2-33 R2H2-41 R2H2-42 R2H2-43 R2H2-51 R2H2-52 R2H2-53 R2H2-61 # R2H2-62 R2H2-63 R2H2-73 # watuppa #} set totalbytes 6536120 set totalbytes 1293240;# ohne 5m request if {$clients} { proc readable {handle rhost} { if {[eof $handle]} { incr ::running -1 if {[catch {close $handle} output]} { if {![string match *$::totalbytes $output]} { puts stderr "invalid output on client on host $rhost" puts stderr "***********************************" puts stderr $output puts stderr "***********************************" } } #puts stderr clients=$::running if {$::running == 0} { set ::xxx 1 } } else { gets $handle } } proc clients {clients} { append cmd "[pwd]/$::argv0 -host $::host " \ "-parallel $::parallel -sequential $::sequential" if {$::port ne ""} {append cmd " -port $::port"} set starttime [clock clicks] set ::running $clients for {set s 0} {$s < $clients} {incr s} { if {$::local} { set rhost localhost } else { set rhost [lindex $::hosts $s] } #puts stderr "rsh $rhost $cmd" puts -nonewline stderr "$rhost " set f($s) [open "| rsh $rhost $cmd"] fconfigure $f($s) -blocking 0 fileevent $f($s) readable "readable $f($s) $rhost" } puts stderr "" vwait ::xxx set secs [expr {([clock clicks] -$starttime)/1000000.0}] puts stderr "[format %3d $clients] clients: [format %6.2f $secs] seconds \ (per client [format %6.2f [expr {$secs/$clients}]] seconds,\ [format %7.2f [expr {$::totalbytes/($secs*1000.0)}]] KB/sec)\ server: [format %7.2f [expr {$::totalbytes*$clients/($secs*1000.0)}]] KB/sec" } clients 1 clients 2 clients 3 clients 4 clients 5 clients 10 clients 20 exit } persistentCache clear proc assert {f r} { set got [eval $f] if {$got ne $r } { puts stderr "assertion failed: \[$f\] == $r (got $got)" quit } else { puts stderr "OK $r = $f" } } proc head msg { puts stderr "" puts stderr "---------------------------- $msg" } proc test {msg cmd} { set r [Object autoname r] head $msg if {[catch {eval $cmd} msg]} { puts stderr "ERROR: $::errorInfo" quit } $r destroy } Object userPwd userPwd proc user {u} { my set user $u } userPwd proc show {realm userVar pwVar} { upvar $userVar u $pwVar pw set u [my set user] set pw jogl return 1 } # test "simple request" { # SimpleRequest $r -caching 0 \ # -url http://localhost/index.html # assert "$r getContentLength" 81 # } # test "simple request" { # SimpleRequest $r -caching 1 \ # -url http://localhost/index.html # assert "$r getContentLength" 81 # } # test "simple request" { # SimpleRequest $r -caching 1 \ # -url http://localhost/index.html # assert "$r getContentLength" 81 # } # test "simple request" { # persistentCache invalidate \ # http://localhost/index.html # SimpleRequest $r -caching 1 \ # -url http://localhost/index.html # assert "$r getContentLength" 81 # } # test "simple request" { # SimpleRequest $r -caching 0 \ # -url http://localhost/muster-d1klausur.ps # assert "$r getContentLength" 163840 # } set total 0 proc parallelRequests-1.0 {URLs} { ParallelSink psink -httpVersion 1.0 -init -requests $URLs incr ::total [psink set totalbytes] psink destroy } proc parallelRequests-1.1 {URLs} { ParallelSink psink -init -requests $URLs incr ::total [psink set totalbytes] psink destroy } if {$port ne ""} {set port :$port} if {$parallel} { parallelRequests-1.0 [list \ http://$host$port/test/file500.html \ http://$host$port/test/file5k.html \ http://$host$port/test/file50k.html \ http://$host$port/test/file500k.html \ http://$host$port/test/file5m.html \ http://$host$port/test/file500.html \ http://$host$port/test/file5k.html \ http://$host$port/test/file5k.html \ http://$host$port/test/file500.html \ http://$host$port/test/file500.html \ http://$host$port/test/file5k.html \ http://$host$port/test/file5k.html \ http://$host$port/test/file500.html \ http://$host$port/test/file5k.html \ http://$host$port/test/file5k.html \ http://$host$port/test/file500.html \ ] for {set i 1} {$i<10} {incr i} { parallelRequests-1.1 [list \ http://$host$port/test/file50k.html \ http://$host$port/test/file5k1.html \ http://$host$port/test/file5k2.html \ http://$host$port/test/file5k3.html \ http://$host$port/test/file5k4.html \ http://$host$port/test/file5k5.html ] } puts stderr totalbytes=$::total } if {$sequential} { set doc http://$host$port/test/suexec.html set size 20680 foreach c $cachingopts { test "caching $c $doc" { SimpleRequest $r -caching $::c -url $::doc assert "$r getContentLength" $::size #puts stderr c=<[$r getContent]> } } set doc http://$host$port/test/xvdocs.ps set size 3678303 foreach c $cachingopts { test "caching $c" { SimpleRequest $r -caching $::c -url $::doc assert "$r getContentLength" $::size } } } exit test "simple request" { SimpleRequest $r -caching 0 \ -url http://nestroy.wi-inf.uni-essen.de/Raumplan.html assert "$r getContentLength" 662 } test "simple request, larger file" { SimpleRequest $r -caching 0 \ -url http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps assert "$r getContentLength" 349970 } test "use cache" { SimpleRequest $r -caching 1 \ -url http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps assert "$r getContentLength" 349970 } test "specify filename, use cache and validate request" { persistentCache invalidate \ http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps exec rm -f test.ps SimpleRequest $r -caching 1 -fileName test.ps \ -url http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps assert "$r getContentLength" 349970 assert "file size test.ps" 349970 assert {lindex [exec md5sum test.ps] 0} c6029c987e841430f3ca9bab157da12f } test "specify filename, and use cache and a validated file" { exec rm -f test.ps SimpleRequest $r -caching 1 -fileName test.ps \ -url http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps assert "$r getContentLength" 349970 assert "file size test.ps" 349970 assert {lindex [exec md5sum test.ps] 0} c6029c987e841430f3ca9bab157da12f } test "specify filename, and do not use cache" { exec rm -f test.ps SimpleRequest $r -fileName test.ps -caching 0 \ -url http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps assert "$r getContentLength" 349970 assert "file size test.ps" 349970 assert {lindex [exec md5sum test.ps] 0} c6029c987e841430f3ca9bab157da12f } test "specify filesink and use cache; no copying necessary" { persistentCache invalidate \ http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps SimpleRequest $r -useFileSink 1 -caching 1 \ -url http://nestroy.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps assert "$r getContentLength" 349970 assert "file size test.ps" 349970 } test "load a large file to the cache" { persistentCache clearEntry http://swt.wi-inf.uni-essen.de/lx2.1.55 SimpleRequest $r -caching 1 \ -url http://swt.wi-inf.uni-essen.de/lx2.1.55 assert "$r getContentLength" 522411 } test "load a validated large file" { SimpleRequest $r -caching 1 \ -url http://swt.wi-inf.uni-essen.de/lx2.1.55 assert "$r getContentLength" 522411 } test "pure loading test without cache" { SimpleRequest $r -caching 0 \ -url http://swt.wi-inf.uni-essen.de/lx2.1.55 assert "$r getContentLength" 522411 } test "redirect" { SimpleRequest $r -caching 1 \ -url http://mohegan.wi-inf.uni-essen.de/Lv/muster-d1klausur.ps assert "$r getContentLength" 349970 } test "authentication" { SimpleRequest $r -caching 1 \ -url http://nestroy.wi-inf.uni-essen.de/cgi-bin/w3-msql/Forschung/Publikationen/protected/index.html assert "$r getContentLength" 1164 } puts stderr after quit ### request joining ### load to file depending on content type ./nsf2.4.0/library/xotcl/apps/comm/secure-webclient.xotcl000755 000766 000024 00000002715 13076354120 024207 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh package require XOTcl 2.0; namespace import -force xotcl::* @ @File { description { A sample secure web client that queries an secure web-server. It needs to be adopted with different https URLs for testing... } } # package require xotcl::comm::httpAccess package require xotcl::comm::ftp package require xotcl::trace #set version 1.1 set hostport localhost:8086 set http_server http://localhost:8086/ set https_server https://localhost:8443/ set slowURL "http://quote.yahoo.com/q?s=^DJI&d=1d" set ftpURL "ftp://mohegan.wi-inf.uni-essen.de/welcome.msg" set secureURL "https://wawog.wi-inf.uni-essen.de/" set secureURL "https://test17.wu-wien.ac.at:1234/" proc printError msg {puts stderr !!!$msg!!!} puts "\nTrying to get a secure page ..... <$https_server>" SimpleRequest r0 -url $https_server puts stderr "\n content = {[r0 getContent]}" puts -nonewline "\nTrying to load image logo-100.jpg ... (not secure)" SimpleRequest r2 -url $http_server/logo-100.jpg if {[r2::sink set contentLength] == 1706} { puts "succeeded! Loaded 1706 bytes!" } else { puts "failed! Loaded [r2::sink set contentLength] (!= 1706) bytes" exit } puts -nonewline "\nTrying to load image logo-100.jpg secure ... " SimpleRequest r1 -url $https_server/logo-100.jpg if {[r1::sink set contentLength] == 1706} { puts "succeeded! Loaded 1706 bytes!" } else { puts "failed! Loaded [r1::sink set contentLength] (!= 1706) bytes" exit } exit ./nsf2.4.0/library/xotcl/apps/comm/webclient.xotcl000755 000766 000024 00000000442 12501766547 022732 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh # -*- Tcl -*- package require XOTcl 2.0; namespace import ::xotcl::* @ @File {description {For a sample webclient, see packages/comm/xocomm.test}} package require xotcl::comm::httpAccess set hostport localhost:8086 SimpleRequest r0 -url http://$hostport/logo-100.jpg ./nsf2.4.0/library/xotcl/apps/utils/xo-daemon000755 000766 000024 00000012210 13547037636 021717 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh package require XOTcl 2.0; namespace import -force xotcl::* @ @File { description { This script can be used to start/stop/restart xotcl daemons and maintains the process IDs, log files and means for easy restart. <@p> It receives as first parameter the name of the xotcl script to be executed followed by the desired action and optional parameters. The specified action can be <@UL> <@LI> <@EM>start: the specified script is started in the background, an entry to restart is generated in the run-directory as well as the process id of the started script. In addition a logfile is created in the log directory. If the start of the script fails, the error messages are shown. <@LI> <@EM>startall: all scripts that were started before via this script, are started <@LI> <@EM>stop terminates the specified script. <@LI> <@EM>stopall terminates all scripts started via this command <@LI> <@EM>restart tries to restart the specified script. The optional parameters are: <@UL> <@LI> <@EM>-logir specifies the directory for logging. The default is ~/.xotcl/log. <@LI> <@EM>-rundir specifies the directory where the information about the running processes is kept. The default is ~/.xotcl/run. } authors { Gustaf Neumann, Gustaf.Neumann@wu-wien.ac.at } date "[::xotcl::rcs date {$Date: 2006/02/18 22:17:32 $}]" } array set opt [list \ -rundir $::xotcl::confdir/run \ -logdir $::xotcl::confdir/log \ ] if {$argc < 2} { puts "Usage:\n\t$argv0 \ ?options?\nOptions:\n\ \t-logdir dirname (default: $::opt(-logdir))\n\ \t-rundir dirname (default: $::opt(-rundir))\n" exit -1 } lassign $argv daemon action array set opt [lreplace $argv 0 1] # The daemon scripts should be # - location independent (if the script assumes to be started from # a certain directory, it should cd to it) # - parameter less (required for restart, startall, etc.) # # configuration set ::kill /bin/kill set ::ps /bin/ps set ::ln /bin/ln set ::sleep /bin/sleep set ::xotclsh /usr/bin/xotclsh Class Daemon -parameter progname Daemon instproc readfile {n} { set f [open $n r] set c [read $f] close $f return [string trim $c \n] } Daemon instproc init {} { if {![file isdirectory $::opt(-rundir)]} {file mkdir $::opt(-rundir)} if {![file isdirectory $::opt(-logdir)]} {file mkdir $::opt(-logdir)} } Daemon instproc progname name { set n [file tail $name] set n [file rootname $n] [self] set pidfile $::opt(-rundir)/$n.pid [self] set logfile $::opt(-logdir)/$n.log [self] set shortname $n [self] set progname $name } Daemon instproc report string { puts stderr "[[self] set shortname]: $string" } Daemon instproc running pid { set r [catch {exec $::ps -h $pid} msg] #if {$r} { [self] report "msg=$msg" } #[self] report "running returns $r" return [expr {!$r}] } Daemon instproc kill {sig pid} { #[self] report "kill $sig $pid" exec $::kill $sig $pid } Daemon instproc start {} { [self] instvar pidfile logfile progname if {[file exists $pidfile]} { set pid [[self] readfile $pidfile] [self] report "seems already running $pid" if {[[self] running $pid]} { [self] report "... no need to restart" return } else { [self] report "... but disappeared $pid" } } set linkname $::opt(-rundir)/[file tail $progname] if {[string match *~* $linkname]} { # file dirname ~ -> requires env(HOME) regsub ^~ $linkname [file dirname ~]/$::env(USER) linkname } if {$progname != $linkname} { #puts stderr "exec $::ln -sf $progname $linkname" exec $::ln -sf $progname $linkname } set pid [exec $::xotclsh $progname >>& $logfile &] set F [open $pidfile w] puts $F $pid close $F exec sleep 1 if {![[self] running $pid]} { [self] report "start of $pid failed" set size [file size $logfile] set F [open $logfile] if {$size > 500} {seek $F [expr {$size-500}]} puts [read $F] close $F } else { [self] report "started $pid" } } Daemon instproc stop {} { [self] instvar pidfile logfile if {[file exists $pidfile]} { set pid [[self] readfile $pidfile] #[self] report "Got PID $pid" if {[[self] running $pid]} { [self] report "stopping $pid" [self] kill -KILL $pid #if {[running $pid]} {kill -KILL $pid} } else { [self] report "not running $pid" } file delete $pidfile } else { [self] report "was not started before" } } Daemon instproc restart {} { [self] stop [self] start } Daemon instproc stopall {} { foreach pidfile [glob -nocomplain $::opt(-rundir)/*.PID] { set n [file rootname [file tail $pidfile]] [self] configure -progname $n -stop } } Daemon instproc startall {} { foreach file [glob -nocomplain $::opt(-rundir)/*] { if {[string match *.PID $file]} continue [self] configure -progname $file -start } } Daemon d -init -progname $daemon -$action ./nsf2.4.0/library/xotcl/apps/utils/xo-whichPkg000755 000766 000024 00000001072 12501766547 022223 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh package require XOTcl 2.0; namespace import -force xotcl::* @ @File { description { A small sample script to show which package is loaded from where when a target package is loaded. <@p> Usage: "xo-whichPkg -pkg PACKAGENAME" } authors { Fredj Dridi dridi@nestroy.wi-inf.uni-essen.de } date "[::xotcl::rcs date {$Date: 2006/02/18 22:17:32 $}]" } array set opts { -pkg xotcl::comm::httpd } array set opts $argv package require xotcl::package package verbose 1 puts stderr [package require $opts(-pkg)] ./nsf2.4.0/library/xotcl/apps/COPYRIGHT000644 000766 000024 00000005037 12501766547 020245 0ustar00neumannstaff000000 000000 /* * Next Scripting Framework * * Copyright (C) 1999-2014 Gustaf Neumann (a) (b) * Copyright (C) 1999-2007 Uwe Zdun (a) (b) * Copyright (C) 2007-2008 Martin Matuska (b) * Copyright (C) 2010-2014 Stefan Sobernig (b) * * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1090, Augasse 2-6 * Vienna, Austria * * This work is licensed under the MIT License * http://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * * This software is based upon MIT Object Tcl by David Wetherall and * Christopher J. Lindblad, that contains the following copyright * message: * * "Copyright 1993 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this * software and its documentation for any purpose is hereby granted * without fee, provided that the above copyright notice appear in * all copies and that both that copyright notice and this * permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity * pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about * the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty." */ ./nsf2.4.0/library/pkgIndex.tcl000644 000766 000024 00000000465 12776662116 017134 0ustar00neumannstaff000000 000000 set __dir__ $dir foreach index [concat \ [glob -nocomplain [file join $dir * pkgIndex.tcl]] \ [glob -nocomplain [file join $dir * * pkgIndex.tcl]] \ [glob -nocomplain [file join $dir * * * pkgIndex.tcl]]] { set dir [file dirname $index] source $index } set dir $__dir__ unset __dir__ ./nsf2.4.0/library/nx/plain-object-method.tcl000644 000766 000024 00000006711 12501766547 021634 0ustar00neumannstaff000000 000000 package provide nx::plain-object-method 1.0 # # Provide a convenience layer to define/introspect object specific # methods without having to use the "object" modifier. By using this # package, one can use instead of # # nx::Object create o { # :public object method foo args {....} # :object property p:integer # :object mixins add M # #... # puts [:info object methods] # } # # simply # # package require nx::plain-object-method # # nx::Object create o { # :public method foo args {....} # :property p:integer # :mixins add M # #... # puts [:info methods] # } # # Note that for object specific methods of classes, one has still to # use "object method" etc. (see also package nx::plass-method). # namespace eval ::nx { # # Define a method to allow configuration for tracing of the # convenience methods. Use # # nx::configure plain-object-method-warning on|off # # for activation/deactivation of tracing. This might be # useful for porting legacy NX programs or for testing # default-configuration compliance. # nx::configure public object method plain-object-method-warning {onoff:boolean,optional} { if {[info exists onoff]} { set :plain-object-method-warning $onoff } else { if {[info exists :plain-object-method-warning]} { if {${:plain-object-method-warning}} { uplevel {::nsf::log warn "plain object method: [self] [current method] [current args]"} } } } } nx::Object eval { # # Definitions redirected to "object" # foreach m { alias filters forward method mixins property variable } { :public method $m {args} { nx::configure plain-object-method-warning :object [current method] {*}[current args] } } # # info subcommands # foreach m { method methods slots variables filters mixins } { :public method "info $m" {args} [subst -nocommands { nx::configure plain-object-method-warning :info object $m {*}[current args] }] } # # deletions for object # foreach m { "property" "variable" "method" } { nx::Object public method "delete $m" {args} { nx::configure plain-object-method-warning :delete object [current method] {*}[current args] } } } Object eval { # # method require, base cases # :method "require method" {methodName} { nx::configure plain-object-method-warning ::nsf::method::require [::nsf::self] $methodName 1 return [:info lookup method $methodName] } # # method require, public explicitly # :method "require public method" {methodName} { nx::configure plain-object-method-warning set result [:require object method $methodName] ::nsf::method::property [self] $result call-protected false return $result } # # method require, protected explicitly # :method "require protected method" {methodName} { nx::configure plain-object-method-warning set result [:require object method $methodName] ::nsf::method::property [self] $result call-protected true return $result } # # method require, private explicitly # :method "require private method" {methodName} { set result [:require object method $methodName] ::nsf::method::property [self] $result call-private true return $result } } } ./nsf2.4.0/library/nx/class-method.tcl000644 000766 000024 00000007525 12501766547 020376 0ustar00neumannstaff000000 000000 package provide nx::class-method 1.0 # # Provide a convenience layer to class methods/variables by using # "class method" rather than "object method". This reflects the naming # conventions of NX 2.0b4 and earlier. By using this package, one can # use instead of # # nx::Class create C { # :public object method foo args {....} # :object property p:integer # :object mixins add M # #... # puts [:info object methods] # } # # a terminology closer to text book vocabulary # # package require nx::class-method # # nx::Object create o { # :public class method foo args {....} # :class property p:integer # :class mixins add M # #... # puts [:class info methods] # } # # Note that for object specific methods of object, have still to be # defined via "object method" etc. (see also package # nx::plain-object-method). # # # make "class" an accepted method defining method # namespace eval ::nsf { array set ::nsf::methodDefiningMethod { class 1 } } namespace eval ::nx { # # Define a method to allow configuration for tracing of the # convenience methods. Use # # nx::configure class-method-warning on|off # # for activation/deactivation of tracing. This might be # useful for porting legacy NX programs or for testing # default-configuration compliance. # nx::configure public object method class-method-warning {onoff:boolean,optional} { if {[info exists onoff]} { set :class-method-warning $onoff } else { if {[info exists :class-method-warning]} { if {${:class-method-warning}} { uplevel {::nsf::log warn "class method: [self] [current method] [current args]"} } } } } nx::Class eval { # # Definitions redirected to "object" # foreach m { alias filters forward method mixins property variable } { :public method "class $m" {args} { nx::configure class-method-warning :object [current method] {*}[current args] } } # # info subcommands # foreach m { method methods slots variables filters mixins } { :public method "class info $m" {args} [subst -nocommands { nx::configure class-method-warning :info object $m {*}[current args] }] } } # # Deletions # foreach m { property variable method } { nx::Class public method "class delete $m" {args} { nx::configure class-method-warning :delete object [current method] {*}[current args] } } ###################################################################### # Provide method "require" ###################################################################### Object eval { # # method require, base cases # :method "require class method" {methodName} { nx::configure class-method-warning ::nsf::method::require [::nsf::self] $methodName 1 return [:info lookup method $methodName] } # # method require, public explicitly # :method "require public class method" {methodName} { nx::configure class-method-warning set result [:require class method $methodName] ::nsf::method::property [self] $result call-protected false return $result } # # method require, protected explicitly # :method "require protected class method" {methodName} { nx::configure class-method-warning set result [:require class method $methodName] ::nsf::method::property [self] $result call-protected true return $result } # # method require, private explicitly # :method "require private class method" {methodName} { nx::configure class-method-warning set result [:require class method $methodName] ::nsf::method::property [self] $result call-private true return $result } } } ./nsf2.4.0/library/nx/pkgIndex.tcl000644 000766 000024 00000000602 14276141440 017537 0ustar00neumannstaff000000 000000 package ifneeded nx 2.4.0 "[list source [file join $dir nx.tcl]]; [list package provide nx 2.4.0]" package ifneeded nx::class-method 1.0 "[list source [file join $dir class-method.tcl]]; [list package provide nx::class-method 1.0]" package ifneeded nx::plain-object-method 1.0 "[list source [file join $dir plain-object-method.tcl]]; [list package provide nx::plain-object-method 1.0]" ./nsf2.4.0/library/nx/COPYRIGHT000644 000766 000024 00000005037 12501766547 016576 0ustar00neumannstaff000000 000000 /* * Next Scripting Framework * * Copyright (C) 1999-2014 Gustaf Neumann (a) (b) * Copyright (C) 1999-2007 Uwe Zdun (a) (b) * Copyright (C) 2007-2008 Martin Matuska (b) * Copyright (C) 2010-2014 Stefan Sobernig (b) * * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1090, Augasse 2-6 * Vienna, Austria * * This work is licensed under the MIT License * http://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * * This software is based upon MIT Object Tcl by David Wetherall and * Christopher J. Lindblad, that contains the following copyright * message: * * "Copyright 1993 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this * software and its documentation for any purpose is hereby granted * without fee, provided that the above copyright notice appear in * all copies and that both that copyright notice and this * permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity * pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about * the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty." */ ./nsf2.4.0/library/nx/nx.tcl000644 000766 000024 00000347206 14275672256 016446 0ustar00neumannstaff000000 000000 # -*- Tcl -*- ############################################################ # nx.tcl -- # # Implementation of the Next Scripting Language (NX) object # system, based on the Next Scripting Framework (NSF). # # Copyright (C) 2010-2018 Gustaf Neumann # Copyright (C) 2010-2019 Stefan Sobernig # # Vienna University of Economics and Business # Institute of Information Systems and New Media # A-1020, Welthandelsplatz 1 # Vienna, Austria # # This work is licensed under the MIT License https://www.opensource.org/licenses/MIT # # Copyright: # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # package req nsf package provide nx 2.4.0 namespace eval ::nx { namespace eval ::nsf {} ;# make pkg-indexer happy namespace eval ::nsf::object {} ;# make pkg-indexer happy namespace eval ::nsf::parameter {} ;# make pkg-indexer happy namespace eval ::nx::internal {} ;# make pkg-indexer happy namespace eval ::nx::trait {} ;# make pkg-indexer happy # # By setting the variable bootstrap, we can check later, whether we # are in bootstrapping mode # set ::nsf::bootstrap ::nx # # First create the ::nx object system. The internally called methods, # which are not defined by in this script, must have method handles # included. The methods "create", "configure", "destroy", "move" and # "__objectcoonfigureparameter" are defined in this script (either scripted, or # via alias). # ::nsf::objectsystem::create ::nx::Object ::nx::Class { -class.alloc {__alloc ::nsf::methods::class::alloc 1} -class.create create -class.dealloc {__dealloc ::nsf::methods::class::dealloc 1} -class.configureparameter __class_configureparameter -class.recreate {__recreate ::nsf::methods::class::recreate 1} -object.configure __configure -object.configureparameter __object_configureparameter -object.defaultmethod {defaultmethod ::nsf::methods::object::defaultmethod} -object.destroy destroy -object.init {init ::nsf::methods::object::init} -object.move move -object.unknown unknown } # # get frequently used primitiva from the next scripting framework # namespace export next current self configure namespace import ::nsf::next ::nsf::current ::nsf::self ::nsf::dispatch # # provide the standard command set for ::nx::Object # ::nsf::method::alias Object upvar ::nsf::methods::object::upvar ::nsf::method::alias Object destroy ::nsf::methods::object::destroy ::nsf::method::alias Object uplevel ::nsf::methods::object::uplevel # # provide ::eval as method for ::nx::Object # ::nsf::method::alias Object eval -frame method ::eval ###################################################################### # Default Methods (referenced via createobjectsystem) ###################################################################### namespace eval ::nsf::methods {} ;# make pkg-indexer happy namespace eval ::nsf::methods::object {} ;# make pkg-indexer happy # Actually, we do not need an unknown handler, but if someone # defines his own unknown handler we define it automatically proc ::nsf::methods::object::unknown {m args} { return -code error "[::nsf::self]: unable to dispatch method '$m'" } # The default constructor proc ::nsf::methods::object::init args {} # This method can be called on invocations of the object without a # specified method. proc ::nsf::methods::object::defaultmethod {} {::nsf::self} ###################################################################### # Class methods ###################################################################### # provide the standard command set for Class ::nsf::method::alias Class create ::nsf::methods::class::create ::nsf::method::alias Class new ::nsf::methods::class::new # set a few aliases as protected # "__next", if defined, should be added as well foreach cmd {uplevel upvar} { ::nsf::method::property Object $cmd call-protected 1 } unset cmd # protect some methods against redefinition ::nsf::method::property Object destroy redefine-protected true ::nsf::method::property Class create redefine-protected true # # Use method::provide for base methods in case they are overloaded # with scripted counterparts ::nsf::method::provide __alloc {::nsf::method::alias __alloc ::nsf::methods::class::alloc} ::nsf::method::provide __dealloc {::nsf::method::alias __dealloc ::nsf::methods::class::dealloc} ::nsf::method::provide __recreate {::nsf::method::alias __recreate ::nsf::methods::class::recreate} ::nsf::method::provide __configure {::nsf::method::alias __configure ::nsf::methods::object::configure} ::nsf::method::provide unknown {::nsf::method::alias unknown ::nsf::methods::object::unknown} # # The method __resolve_method_path resolves a space separated path # of a method name and creates from the path the necessary ensemble # objects when needed. # ::nsf::method::create Object __resolve_method_path { -per-object:switch -verbose:switch path } { set object [::nsf::self] set methodName $path set regObject "" if {[string first " " $path] > -1} { set methodName [lindex $path end] set regObject $object foreach w [lrange $path 0 end-1] { set scope [expr {[::nsf::is class $object] && !${per-object} ? "class" : "object"}] if {[::nsf::is class $object] && !${per-object}} { set scope class set ensembleName [::nx::slotObj ${object} __$w] if {[: ::nsf::methods::class::info::method exists $w] && [: ::nsf::methods::class::info::method type $w] ne "alias"} { return -code error "refuse to overwrite method $w; delete/rename method first." } } else { set scope object if {[: ::nsf::methods::object::info::method exists $w] && [: ::nsf::methods::object::info::method type $w] ne "object"} { return -code error "refuse to overwrite object method $w; delete/rename object method first." } set ensembleName ${object}::$w } #puts stderr "NX check $scope $object info methods $path @ <$w> cmd=[info command $w] obj?[nsf::object::exists $ensembleName] " if {![nsf::object::exists $ensembleName]} { # # Create dispatch/ensemble object and accessor method (if wanted) # set o [nx::EnsembleObject create $ensembleName] if {$scope eq "class"} { if {$verbose} {puts stderr "... create object $o"} # We are on a class, and have to create an alias to be # accessible for objects ::nsf::method::alias $object $w $o if {$verbose} {puts stderr "... create alias $object $w $o"} } else { if {$verbose} {puts stderr "... create object $o"} } set object $o } else { # # The accessor method exists already, check, if it is # appropriate for extending. # set type [::nsf::directdispatch $object ::nsf::methods::${scope}::info::method type $w] set definition [::nsf::directdispatch $object ::nsf::methods::${scope}::info::method definition $w] if {$scope eq "class"} { if {$type eq ""} { # In case of a copy operation, the ensemble object might # exist, but the alias might be missing. ::nsf::method::alias $object $w $ensembleName set object $ensembleName } else { if {$type ne "alias"} {error "can't append to $type"} if {$definition eq ""} {error "definition must not be empty"} set object [lindex $definition end] } } else { if {$type ne "object"} {error "can't append to $type"} if {[llength $definition] != 3} {error "unexpected definition '$definition'"} append object ::$w } } } #puts stderr "... final object $object method $methodName" } return [list object $object methodName $methodName regObject $regObject] } ::nsf::method::property Object __resolve_method_path call-protected true ###################################################################### # Define default method and property protection ###################################################################### ::nsf::method::create Object __default_method_call_protection args {return false} ::nsf::method::create Object __default_accessor args {return public} ::nsf::method::property Object __default_method_call_protection call-protected true ::nsf::method::property Object __default_accessor call-protected true ###################################################################### # Define method "method" for Class ###################################################################### ::nsf::method::create Class method { -debug:switch -deprecated:switch name arguments:parameter,0..* -checkalways:switch -returns body } { set p [:__resolve_method_path $name] set p [dict filter $p script {k v} {expr {$k in {object regObject methodName}}}] dict with p { #puts "class method $object.$methodName [list $arguments] {...}" set r [::nsf::method::create $object \ -checkalways=$checkalways \ {*}[expr {$regObject ne "" ? "-reg-object [list $regObject]" : ""}] \ $methodName $arguments $body] if {$r ne ""} { # the method was not deleted ::nsf::method::property $object $r call-protected \ [::nsf::dispatch $object __default_method_call_protection] if {[info exists returns]} {::nsf::method::property $object $r returns $returns} if {$debug} {::nsf::method::property $object $r debug true} if {$deprecated} {::nsf::method::property $object $r deprecated true} } return $r } } ###################################################################### # Define method "unknown" ###################################################################### Class eval { # define unknown handler for class :method unknown {methodName args} { return -code error "method '$methodName' unknown for [::nsf::self];\ in order to create an instance of class [::nsf::self], consider using\ '[::nsf::self] create $methodName ?...?'" } # protected is not yet defined ::nsf::method::property [::nsf::self] unknown call-protected true } ###################################################################### # Remember names of method defining methods ###################################################################### # Well, class is not a method defining method either, but a modifier array set ::nsf::methodDefiningMethod { method 1 alias 1 forward 1 object 1 ::nsf::classes::nx::Class::method 1 ::nsf::classes::nx::Object::method 1 ::nsf::classes::nx::Class::alias 1 ::nsf::classes::nx::Object::alias 1 ::nsf::classes::nx::Class::forward 1 ::nsf::classes::nx::Object::forward 1 } ###################################################################### # Provide method modifiers for ::nx::Object ###################################################################### Object eval { # method modifier "public" :method public {args} { if {![info exists ::nsf::methodDefiningMethod([lindex $args 0])]} { return -code error "'[lindex $args 0]' is not a method defining method" } elseif {[lindex $args 0] eq "object" && ![info exists ::nsf::methodDefiningMethod([lindex $args 1])]} { return -code error "'[lindex $args 1]' is not a method defining method" } set r [: -system {*}$args] if {$r ne ""} {::nsf::method::property [self] $r call-protected false} return $r } # method modifier "protected" :method protected {args} { if {![info exists ::nsf::methodDefiningMethod([lindex $args 0])]} { return -code error "'[lindex $args 0]' is not a method defining method" } elseif {[lindex $args 0] eq "object" && ![info exists ::nsf::methodDefiningMethod([lindex $args 1])]} { return -code error "'[lindex $args 1]' is not a method defining method" } set r [: -system {*}$args] if {$r ne ""} {::nsf::method::property [self] $r call-protected true} return $r } # method modifier "private" :method private {args} { if {![info exists ::nsf::methodDefiningMethod([lindex $args 0])]} { return -code error "'[lindex $args 0]' is not a method defining method" } elseif {[lindex $args 0] eq "object" && ![info exists ::nsf::methodDefiningMethod([lindex $args 1])]} { return -code error "'[lindex $args 1]' is not a method defining method" } set r [: -system {*}$args] if {$r ne ""} {::nsf::method::property [self] $r call-private true} return $r } } # Provide a placeholder for objectparameter during the bootup # process. The real definition is based on slots, which are not # available at this point. Object protected method __object_configureparameter {} {;} ###################################################################### # Define forward methods ###################################################################### # # We could do this simply as # # ::nsf::method::forward Object forward ::nsf::method::forward %self -per-object # ::nsf::method::forward Class forward ::nsf::method::forward %self # # but then, we would loose the option to use compound names # Class public method forward { -debug:switch -deprecated:switch methodName -default -prefix -frame -onerror -returns -verbose:switch target:optional args } { set pathData [:__resolve_method_path $methodName] set arguments [lrange [::nsf::current args] 1 end] set object [dict get $pathData object] if {[info exists target] && [string index $target 0] eq "-"} { error "target '$target' must not start with a dash" } if {[info exists frame] && $frame ni {object default}} { error "value of parameter -frame must be 'object' or 'default'" } if {[info exists returns]} { set nrPreArgs [expr {[llength $arguments]-[llength $args]}] # search for "-returns" in the arguments before $args and remove it set p [lsearch -exact [lrange $arguments 0 $nrPreArgs] -returns] if {$p > -1} {set arguments [lreplace $arguments $p $p+1]} } set r [::nsf::method::forward $object [dict get $pathData methodName] {*}$arguments] ::nsf::method::property $object $r call-protected \ [::nsf::dispatch $object __default_method_call_protection] if {[info exists returns]} {::nsf::method::property $object $r returns $returns} if {$debug} {::nsf::method::property $object $r debug true} if {$deprecated} {::nsf::method::property $object $r deprecated true} return $r } ###################################################################### # Provide method "alias" # # -frame object|method make only sense for c-defined cmds, ###################################################################### Class public method alias { -debug:switch -deprecated:switch methodName -returns {-frame default} cmd } { set pathData [:__resolve_method_path $methodName] set object [dict get $pathData object] #puts "class alias $object.[dict get $pathData methodName] $cmd" set r [::nsf::method::alias $object [dict get $pathData methodName] -frame $frame $cmd] ::nsf::method::property $object $r call-protected \ [::nsf::dispatch $object __default_method_call_protection] if {[info exists returns]} {::nsf::method::property $object $r returns $returns} if {$debug} {::nsf::method::property $object $r debug true} if {$deprecated} {::nsf::method::property $object $r deprecated true} return $r } ###################################################################### # Basic definitions for slots ###################################################################### # # The function isSlotContainer tests, whether the provided object is # a slot container based on the method property slotcontainer, used # internally by the serializer. # proc ::nx::isSlotContainer {object} { return [::nsf::object::property $object slotcontainer] } # # The function nx::internal::setSlotContainerProperties set the method # properties for slot containers # proc ::nx::internal::setSlotContainerProperties {baseObject containerName} { set slotContainer ${baseObject}::$containerName $slotContainer ::nsf::methods::object::requirenamespace ::nsf::method::property $baseObject -per-object $containerName call-protected true ::nsf::method::property $baseObject -per-object $containerName redefine-protected true #puts stderr "::nsf::method::property $baseObject -per-object $containerName slotcontainer true" #::nsf::method::property $baseObject -per-object $containerName slotcontainer true ::nsf::object::property $slotContainer slotcontainer true } # # The function nx::slotObj ensures that the slot container for the # provided baseObject exists. It returns either the name of the # slotContainer (when no slot name was provided) or the fully # qualified name of the slot object. # ::nsf::proc ::nx::slotObj {{-container slot} baseObject name:optional} { # Create slot container object if needed set slotContainer ${baseObject}::$container if {![::nsf::object::exists $slotContainer]} { ::nx::Object ::nsf::methods::class::alloc $slotContainer ::nx::internal::setSlotContainerProperties $baseObject $container if {$container eq "per-object-slot"} { ::nsf::object::property $baseObject hasperobjectslots true } } if {[info exists name]} { return ${slotContainer}::$name } return ${slotContainer} } ###################################################################### # Allocate system slot containers ###################################################################### ::nx::slotObj ::nx::Class ::nx::slotObj ::nx::Object ###################################################################### # Define the EnsembleObject with its base methods ###################################################################### Class create ::nx::EnsembleObject ::nx::EnsembleObject eval { # # The EnsembleObjects are called typically with a "self" bound to # the object, on which they are registered as methods. This way, # only method registered on the object are resolved (ensemble # methods). Only for the methods "unknown" and "defaultmethod", # self is actually the ensemble object. These methods are # maintenance methods. We have to be careful here ... # # a) not to interfere between "maintenance methods" and "ensemble # methods" within the maintenance methods. This is achieved # via explicit dispatch commands in the maintenance methods. # # b) not to overload "maintenance methods" with "ensemble # methods". This is achieved via the object-method-only policy # (we cannot call "subcmd " when "subcmdName" is a # method on EnsembleObject) and via a skip object-methods flag # in nsf when calling e.g. "unknown" (such that a subcmd # "unknown" does not interfere with the method "unknown"). # :protected method init {} { ::nsf::object::property [self] keepcallerself true ::nsf::object::property [self] perobjectdispatch true } :protected method unknown {callInfo args} { set path [lrange $callInfo 1 end-1] set m [lindex $callInfo end] set obj [lindex $callInfo 0] #::nsf::__db_show_stack #puts stderr "CI=<$callInfo> args <$args>" #puts stderr "### [list $obj ::nsf::methods::object::info::lookupmethods -path \"$path *\"]" if {[catch {set valid [$obj ::nsf::methods::object::info::lookupmethods -path "$path *"]} errorMsg]} { set valid "" puts stderr "+++ UNKNOWN raises error $errorMsg" } set ref "\"$m\" of $obj $path" return -code error "unable to dispatch sub-method $ref; valid are: [join [lsort $valid] {, }]" } :protected method defaultmethod {} { if {[catch {set obj [::uplevel ::nsf::current]}]} { error "ensemble dispatch called outside of method context" } set path [::uplevel {::nsf::current methodpath}] set l [string length $path] set submethods [$obj ::nsf::methods::object::info::lookupmethods -path "$path *"] foreach sm $submethods {set results([lindex [string range $sm $l+1 end] 0]) 1} return -code error "valid submethods of $obj $path: [lsort [array names results]]" } # end of EnsembleObject } ###################################################################### # Now we are able to use ensemble methods in the definition of NX ###################################################################### Object eval { # # Define method defining methods for Object. # # These are: # - "method" # - "alias" # - "forward" :public method "object method" { -debug:switch -deprecated:switch methodName arguments:parameter,0..* -checkalways:switch -returns body } { set pathData [:__resolve_method_path -per-object $methodName] set object [dict get $pathData object] set regObject [dict get $pathData regObject] # puts "object method $object.[dict get $pathData methodName] [list $arguments] {...}" set r [::nsf::method::create $object \ -checkalways=$checkalways \ {*}[expr {$regObject ne "" ? "-reg-object [list $regObject]" : ""}] \ -per-object \ [dict get $pathData methodName] $arguments $body] if {$r ne ""} { # the method was not deleted ::nsf::method::property $object $r call-protected \ [::nsf::dispatch $object __default_method_call_protection] if {[info exists returns]} {::nsf::method::property $object $r returns $returns} if {$debug} {::nsf::method::property $object $r debug true} if {$deprecated} {::nsf::method::property $object $r deprecated true} } return $r } :public method "object alias" { -debug:switch -deprecated:switch methodName -returns {-frame default} cmd } { set pathData [:__resolve_method_path -per-object $methodName] set object [dict get $pathData object] #puts "object alias $object.[dict get $pathData methodName] $cmd" set r [::nsf::method::alias $object -per-object [dict get $pathData methodName] \ -frame $frame $cmd] ::nsf::method::property $object -per-object $r call-protected \ [::nsf::dispatch $object __default_method_call_protection] if {[info exists returns]} {::nsf::method::property $object $r returns $returns} if {$debug} {::nsf::method::property $object $r debug true} if {$deprecated} {::nsf::method::property $object $r deprecated true} return $r } :public method "object forward" { -debug:switch -deprecated:switch methodName -default -prefix -frame -onerror -returns -verbose:switch target:optional args } { set arguments [lrange [::nsf::current args] 1 end] set pathData [:__resolve_method_path -per-object $methodName] set object [dict get $pathData object] if {[info exists target] && [string index $target 0] eq "-"} { error "target '$target' must not start with a dash" } if {[info exists frame] && $frame ni {object default}} { error "value of parameter '-frame' must be 'object' or 'default'" } if {[info exists returns]} { set nrPreArgs [expr {[llength $arguments]-[llength $args]}] # search for "-returns" in the arguments before $args ... set p [lsearch -exact [lrange $arguments 0 $nrPreArgs] -returns] # ... and remove it if found if {$p > -1} {set arguments [lreplace $arguments $p $p+1]} } set r [::nsf::method::forward $object -per-object \ [dict get $pathData methodName] {*}$arguments] ::nsf::method::property $object -per-object $r call-protected \ [::nsf::dispatch $object __default_method_call_protection] if {[info exists returns]} {::nsf::method::property $object $r returns $returns} if {$debug} {::nsf::method::property $object $r debug true} if {$deprecated} {::nsf::method::property $object $r deprecated true} return $r } } # # Method for deletion of properties, variables and plain methods # Object eval { :public method "delete object method" {name} { ::nsf::method::delete [self] -per-object $name } :public method "delete object property" {name} { # call explicitly the per-object variant of "info::slotobjects" set slot [: ::nsf::methods::object::info::slotobjects -type ::nx::Slot $name] if {$slot eq ""} { return -code error \ "[self]: cannot delete object-specific property '$name'" } $slot destroy nsf::var::unset -nocomplain [self] $name } :public method "delete object variable" {name} { # First remove the instance variable and complain, if it does # not exist. if {[nsf::var::exists [self] $name]} { nsf::var::unset [self] $name } else { return -code error \ "[self]: object does not have an instance variable '$name'" } # call explicitly the per-object variant of "info::slotobjects" set slot [: ::nsf::methods::object::info::slotobjects -type ::nx::Slot $name] if {$slot ne ""} { # it is not a slot-less variable $slot destroy } } } Class eval { :public method "delete method" {name} { ::nsf::method::delete [self] $name } :public method "delete property" {name} { set slot [:info slots $name] if {$slot eq ""} { return -code error "[self]: cannot delete property '$name'" } $slot destroy } :public method "delete variable" {name} { set slot [:info slots $name] if {$slot eq ""} { return -code error "[self]: cannot delete variable '$name'" } $slot destroy } } ###################################################################### # Provide method "require" ###################################################################### Object eval { :method "require namespace" {} { ::nsf::directdispatch [::nsf::self] ::nsf::methods::object::requirenamespace } # # method require, base cases # :method "require object method" {methodName} { ::nsf::method::require [::nsf::self] $methodName 1 return [:info lookup method $methodName] } # # method require, public explicitly # :method "require public object method" {methodName} { set result [:require object method $methodName] ::nsf::method::property [self] $result call-protected false return $result } # # method require, protected explicitly # :method "require protected object method" {methodName} { set result [:require object method $methodName] ::nsf::method::property [self] $result call-protected true return $result } # # method require, private explicitly # :method "require private object method" {methodName} { set result [:require object method $methodName] ::nsf::method::property [self] $result call-private true return $result } } nx::Class eval { :method "require method" {methodName} { return [::nsf::method::require [::nsf::self] $methodName 0] } :method "require public method" {methodName} { set result [:require method $methodName] ::nsf::method::property [self] $result call-protected false return $result } :method "require protected method" {methodName} { set result [:require method $methodName] ::nsf::method::property [self] $result call-protected true return $result } :method "require private method" {methodName} { set result [:require method $methodName] ::nsf::method::property [self] $result call-private true return $result } } ###################################################################### # Info definition ###################################################################### # we have to use "eval", since objectParameters are not defined yet Object eval { :alias "info lookup filter" ::nsf::methods::object::info::lookupfilter :alias "info lookup filters" ::nsf::methods::object::info::lookupfilters :alias "info lookup method" ::nsf::methods::object::info::lookupmethod :alias "info lookup methods" ::nsf::methods::object::info::lookupmethods :alias "info lookup mixins" ::nsf::methods::object::info::lookupmixins :method "info lookup slots" {{-type:class ::nx::Slot} -source pattern:optional} { set cmd [list ::nsf::methods::object::info::lookupslots -type $type] if {[info exists source]} {lappend cmd -source $source} if {[info exists pattern]} {lappend cmd $pattern} return [: {*}$cmd] } :method "info lookup parameters" {methodName pattern:optional} { return [::nsf::cmd::info \ parameter \ -context [self] \ [:info lookup method $methodName] \ {*}[expr {[info exists pattern] ? $pattern : ""}] ] } :method "info lookup syntax" {methodName pattern:optional} { return [::nsf::cmd::info \ syntax \ -context [self] \ [:info lookup method $methodName] \ {*}[expr {[info exists pattern] ? $pattern : ""}] ] } :method "info lookup variables" {pattern:optional} { return [: info lookup slots -type ::nx::VariableSlot {*}[current args]] } :alias "info baseclass" ::nsf::methods::object::info::baseclass :alias "info children" ::nsf::methods::object::info::children :alias "info class" ::nsf::methods::object::info::class :alias "info has mixin" ::nsf::methods::object::info::hasmixin :alias "info has namespace" ::nsf::methods::object::info::hasnamespace :alias "info has type" ::nsf::methods::object::info::hastype :alias "info name" ::nsf::methods::object::info::name :alias "info object filters" ::nsf::methods::object::info::filters :alias "info object methods" ::nsf::methods::object::info::methods :alias "info object mixins" ::nsf::methods::object::info::mixins :method "info object slots" {{-type:class ::nx::Slot} pattern:optional} { set method [list ::nsf::methods::object::info::slotobjects -type $type] if {[info exists pattern]} {lappend method $pattern} return [: {*}$method] } :method "info object variables" {pattern:optional} { return [: info object slots -type ::nx::VariableSlot {*}[current args]] } # # Parameter extractors # # :method "info parameter default" {p:parameter varName:optional} { # if {[info exists varName]} { # uplevel [list ::nsf::parameter::info default $p $varName] # } else { # ::nsf::parameter::info default $p # } # } # :method "info parameter name" {p:parameter} {::nsf::parameter::info name $p} # :method "info parameter syntax" {p:parameter} {::nsf::parameter::info syntax $p} # :method "info parameter type" {p:parameter} {::nsf::parameter::info type $p} :alias "info parent" ::nsf::methods::object::info::parent :alias "info precedence" ::nsf::methods::object::info::precedence :alias "info vars" ::nsf::methods::object::info::vars :method "info variable definition" {handle:object,type=::nx::VariableSlot} { return [$handle definition] } :method "info variable name" {handle:object,type=::nx::VariableSlot} { return [$handle cget -name] } :method "info variable parameter" {handle:object,type=::nx::VariableSlot} { return [$handle parameter] } } ###################################################################### # Create the ensemble object for "info" here manually to prevent the # replicated definitions from Object.info in Class.info. # Potentially, some names are overwritten later by Class.info. Note, # that the automatically created name of the ensemble object has to # be the same as defined above. ###################################################################### # # The following test is just for the redefinition case, after a # "package forget". We clear "info method" for ::nx::Object to avoid # confusions in the copy loop below, which uses method "method". # if {[::nsf::directdispatch ::nx::Object::slot::__info ::nsf::methods::object::info::methods "method"] ne ""} { Object method "info method" {} {} } # # There is not need to copy the "info object" ensemble to # ::nx::Class since this is reached via ensemble "next" in # nx::Object. # Class eval { # :alias "info lookup" ::nx::Object::slot::__info::lookup :alias "info filters" ::nsf::methods::class::info::filters # :alias "info has" ::nx::Object::slot::__info::has :alias "info heritage" ::nsf::methods::class::info::heritage :alias "info instances" ::nsf::methods::class::info::instances :alias "info methods" ::nsf::methods::class::info::methods :alias "info mixins" ::nsf::methods::class::info::mixins :alias "info mixinof" ::nsf::methods::class::info::mixinof :method "info slots" {{-type ::nx::Slot} -closure:switch -source:optional pattern:optional} { set cmd [list ::nsf::methods::class::info::slotobjects -type $type] if {[info exists source]} {lappend cmd -source $source} if {$closure} {lappend cmd -closure} if {[info exists pattern]} {lappend cmd $pattern} return [: {*}$cmd] } :alias "info subclasses" ::nsf::methods::class::info::subclass :alias "info superclasses" ::nsf::methods::class::info::superclass :method "info variables" {pattern:optional} { set cmd {info slots -type ::nx::VariableSlot} if {[info exists pattern]} {lappend cmd $pattern} return [: {*}$cmd] } } ###################################################################### # Define "info info" and "info unknown" ###################################################################### ::nsf::proc ::nx::internal::infoOptions {-asList:switch obj {methods ""}} { # puts stderr "INFO INFO $obj -> '[::nsf::directdispatch $obj ::nsf::methods::object::info::methods -type all]'" foreach name [::nsf::directdispatch $obj ::nsf::methods::object::info::methods] { if {$name in $methods || $name eq "unknown"} continue lappend methods $name } if {$asList} { return $methods } else { return "valid options are: [join [lsort $methods] {, }]" } } Object method "info info" {-asList:switch} { ::nx::internal::infoOptions -asList=$asList ::nx::Object::slot::__info } Class method "info info" {-asList:switch} { ::nx::internal::infoOptions -asList=$asList ::nx::Class::slot::__info [next {info -asList}] } # finally register method for "info method" (otherwise, we cannot use "method" above) Class eval { #:alias "info method" ::nsf::methods::class::info::method :method "info method args" {name} {: ::nsf::methods::class::info::method args $name} :method "info method body" {name} {: ::nsf::methods::class::info::method body $name} if {[::nsf::pkgconfig get development]} { :method "info method disassemble" {name} {: ::nsf::methods::class::info::method disassemble $name} } :method "info method definition" {name} {: ::nsf::methods::class::info::method definition $name} :method "info method exists" {name} {: ::nsf::methods::class::info::method exists $name} :method "info method handle" {name} {: ::nsf::methods::class::info::method definitionhandle $name} :method "info method registrationhandle" {name} {: ::nsf::methods::class::info::method registrationhandle $name} :method "info method definitionhandle" {name} {: ::nsf::methods::class::info::method definitionhandle $name} :method "info method origin" {name} {: ::nsf::methods::class::info::method origin $name} :method "info method parameters" {name pattern:optional} { set defs [: ::nsf::methods::class::info::method parameter $name] if {[info exists pattern]} {return [::nsf::parameter::filter $defs $pattern]} return $defs } :method "info method syntax" {name} { return [string trimright "/cls/ [namespace tail $name] [: ::nsf::methods::class::info::method syntax $name]" { }] } :method "info method type" {name} {: ::nsf::methods::class::info::method type $name} :method "info method submethods" {name} {: ::nsf::methods::class::info::method submethods $name} :method "info method returns" {name} {: ::nsf::methods::class::info::method returns $name} :method "info method callprotection" {name} { if {[::nsf::method::property [self] $name call-protected]} { return protected } elseif {[::nsf::method::property [self] $name call-private]} { return private } else { return public } } :method "info method deprecated" {name} {::nsf::method::property [self] $name deprecated} :method "info method debug" {name} {::nsf::method::property [self] $name debug} } Object eval { #:alias "info object method" ::nsf::methods::object::info::method :method "info object method args" {name} {: ::nsf::methods::object::info::method args $name} :method "info object method body" {name} {: ::nsf::methods::object::info::method body $name} :method "info object method definition" {name} {: ::nsf::methods::object::info::method definition $name} if {[::nsf::pkgconfig get development]} { :method "info object method disassemble" {name} {: ::nsf::methods::object::info::method disassemble $name} } :method "info object method exists" {name} {: ::nsf::methods::object::info::method exists $name} :method "info object method handle" {name} {: ::nsf::methods::object::info::method definitionhandle $name} :method "info object method registrationhandle" {name} {: ::nsf::methods::object::info::method registrationhandle $name} :method "info object method definitionhandle" {name} {: ::nsf::methods::object::info::method definitionhandle $name} :method "info object method origin" {name} {: ::nsf::methods::object::info::method origin $name} :method "info object method parameters" {name pattern:optional} { set defs [: ::nsf::methods::object::info::method parameter $name] if {[info exists pattern]} {return [::nsf::parameter::filter $defs $pattern]} return $defs } :method "info object method syntax" {name} { return [string trimright "/obj/ [namespace tail $name] [: ::nsf::methods::object::info::method syntax $name]" { }] } :method "info object method type" {name} {: ::nsf::methods::object::info::method type $name} :method "info object method submethods" {name} {: ::nsf::methods::object::info::method submethods $name} :method "info object method returns" {name} {: ::nsf::methods::object::info::method returns $name} :method "info object method callprotection" {name} { if {[::nsf::method::property [self] -per-object $name call-protected]} { return protected } elseif {[::nsf::method::property [self] -per-object $name call-private]} { return private } else { return public } } :method "info object method deprecated" {name} {::nsf::method::property [self] -per-object $name deprecated} :method "info object method debug" {name} {::nsf::method::property [self] -per-object $name debug} } ###################################################################### # Provide Tk-style methods for configure and cget ###################################################################### Object eval { :public alias cget ::nsf::methods::object::cget :public alias configure ::nsf::methods::object::configure #:public method "info configure" {} {: ::nsf::methods::object::info::objectparameter syntax} } #nsf::method::create ::nx::Class::slot::__info::configure defaultmethod {} { # uplevel {: ::nsf::methods::object::info::objectparameter syntax} #} ###################################################################### # Definition of "abstract method foo ...." # # Deactivated for now. If we like to revive this method, it should # be integrated with the method modifiers and the method "class" # # Object method abstract {methtype -per-object:switch methName arglist} { # if {$methtype ne "method"} { # error "invalid method type '$methtype', must be 'method'" # } # set body " # if {!\[::nsf::current isnextcall\]} { # error \"abstract method $methName $arglist called\" # } else {::nsf::next} # " # if {${per-object}} { # :method -per-object $methName $arglist $body # } else { # :method $methName $arglist $body # } # } ###################################################################### # MetaSlot definitions # # The MetaSlots are used later to create SlotClasses ###################################################################### # # We are in bootstrap code; we cannot use slots/parameter to define # slots, so the code is a little low-level. After the definition of # the slots, we can use slot-based code such as "-parameter" or # "objectparameter". # Class create ::nx::MetaSlot ::nsf::relation::set MetaSlot superclass Class MetaSlot object method requireClass {required:class old:class,0..1} { # # Combine two classes and return the more specialized one # if {$old eq "" || $old eq $required} {return $required} if {[$required info superclasses -closure $old] ne ""} { #puts stderr "required $required has $old as superclass => specializing" return $required } elseif {[$required info subclasses -closure $old] ne ""} { #puts stderr "required $required is more general than $old => keep $old" return $old } else { return -code error "required class $required not compatible with $old" } } # # Translate substdefault bitpattern to options passed to the Tcl # "subst" command # MetaSlot public object method substDefaultOptions { bitPattern } { # backslashes, variables, commands set options {} if {($bitPattern & 0b100) == 0} { lappend options -nobackslashes } if {($bitPattern & 0b010) == 0} { lappend options -novariables } if {($bitPattern & 0b001) == 0} { lappend options -nocommands } return $options } # # Given a dict of parameter options, translate this into a spec # which can be passed to nsf::is for value checking # MetaSlot public object method optionsToValueCheckingSpec { options } { set noptions "" if {[dict exists $options -type]} { set type [dict get $options -type] if {[string match "::*" $type]} { lappend noptions object type=$type } elseif {$type eq "switch"} { lappend noptions boolean } else { lappend noptions $type } } if {[dict exists $options -arg]} { lappend noptions arg=[dict get $options -arg] } if {[dict exists $options -multiplicity]} { lappend noptions [dict get $options -multiplicity] } return [join $noptions ,] } MetaSlot public object method parseParameterSpec { {-class ""} {-defaultopts ""} {-target ""} spec default:optional } { array set opt $defaultopts set opts "" set colonPos [string first : $spec] if {$colonPos == -1} { set name $spec set parameterOptions "" } else { set parameterOptions [string range $spec [expr {$colonPos+1}] end] set name [string range $spec 0 [expr {$colonPos -1}]] foreach property [split $parameterOptions ,] { if {$property in [list "required" "convert" "noarg" "nodashalnum"]} { if {$property eq "convert" } {set class [:requireClass ::nx::VariableSlot $class]} lappend opts -$property 1 } elseif {$property eq "noconfig"} { set opt(-configurable) 0 ;# TODO } elseif {$property eq "incremental"} { return -code error "parameter option incremental must not be used; use non-positional argument -incremental instead" } elseif {[string match "type=*" $property]} { set class [:requireClass ::nx::VariableSlot $class] set type [string range $property 5 end] if {$type eq ""} { unset type } elseif {![string match "::*" $type]} { set type [namespace qualifier $target]::$type } } elseif {[string match "arg=*" $property]} { set argument [string range $property 4 end] lappend opts -arg $argument } elseif {[string match "substdefault*" $property]} { if {[string match "substdefault=*" $property]} { set argument [string range $property 13 end] } else { set argument 0b111 } lappend opts -substdefault $argument } elseif {[string match "method=*" $property]} { lappend opts -methodname [string range $property 7 end] } elseif {$property eq "optional"} { lappend opts -required 0 } elseif {$property in [list "alias" "forward" "cmd" "initcmd"]} { lappend opts -disposition $property set class [:requireClass ::nx::ObjectParameterSlot $class] } elseif {[regexp {([01])[.][.]([1n*])} $property _ minOccurrence maxOccurrence]} { lappend opts -multiplicity $property } else { set type $property } } } if {[info exists type]} { #if {$type eq "switch"} {error "switch is not allowed as type for object parameter $name"} lappend opts -type $type } lappend opts {*}[array get opt] #puts stderr "[self] *** parseParameterSpec [list $name $parameterOptions $class $opts]" return [list $name $parameterOptions $class $opts] } MetaSlot public object method createFromParameterSpec { target -per-object:switch {-class ""} {-initblock ""} {-private:switch} {-incremental:switch} {-defaultopts ""} spec default:optional } { lassign [:parseParameterSpec -class $class -defaultopts $defaultopts -target $target $spec] \ name parameterOptions class opts if {[string first , $name] > -1} { nsf::log warning "slot name '$name' contains suspicious characters" } lappend opts -incremental $incremental if {[info exists default]} { lappend opts -default $default } if {${per-object}} { lappend opts -per-object true set scope object set container per-object-slot } else { set scope class set container slot } if {$private} { regsub -all : __$target _ prefix lappend opts -settername $name -name __private($target,$name) set slotname ${prefix}.$name } else { set slotname $name } if {$class eq ""} { set class ::nx::VariableSlot } else { #puts stderr "*** Class for '$target $name' is $class // [$class info heritage]" } set slotObj [::nx::slotObj -container $container $target $slotname] #puts stderr "[self] SLOTCREATE *** [list $class create $slotObj] {*}$opts <$initblock>" set r [$class create $slotObj {*}$opts $initblock] #puts stderr "[self] SLOTCREATE returned $r" return $r } } namespace eval ::nx { ###################################################################### # Slot definitions ###################################################################### MetaSlot create ::nx::Slot MetaSlot create ::nx::ObjectParameterSlot ::nsf::relation::set ObjectParameterSlot superclass Slot MetaSlot create ::nx::MethodParameterSlot ::nsf::relation::set MethodParameterSlot superclass Slot # Create a slot instance for dispatching method parameter specific # value checkers MethodParameterSlot create ::nx::methodParameterSlot # Define a temporary, low-level interface for defining slot # values. Normally, this is done via slot objects, which are defined # later. The proc is removed later in this script. proc createBootstrapVariableSlots {class definitions} { foreach att $definitions { if {[llength $att]>1} {lassign $att att default} set slotObj [::nx::slotObj $class $att] #puts stderr "::nx::BootStrapVariableSlot create $slotObj" ::nx::BootStrapVariableSlot create $slotObj if {[info exists default]} { #puts stderr "::nsf::var::set $slotObj default $default" ::nsf::var::set $slotObj default $default unset default } # # register the standard setter # #::nsf::method::setter $class $att # # make setter protected # #regexp {^([^:]+):} $att . att #::nsf::method::property $class $att call-protected true # # set for every bootstrap property slot the position 0 # ::nsf::var::set $slotObj position 0 ::nsf::var::set $slotObj configurable 1 } #puts stderr "Bootstrap-slot for $class calls parameter::cache::classinvalidate" ::nsf::parameter::cache::classinvalidate $class } ObjectParameterSlot protected method namedParameterSpec {-map-private:switch prefix name options} { # # Build a pos/nonpos parameter specification from name and option list # if {${map-private} && [info exists :accessor] && ${:accessor} eq "private"} { set pName ${:settername} } else { set pName $name } if {[llength $options]>0} { return $prefix${pName}:[join $options ,] } else { return $prefix${pName} } } ###################################################################### # Define slots for slots ###################################################################### # # We would like to have property slots during bootstrap to # configure the slots itself (e.g. a relation slot object). This is # however a chicken/egg problem, so we use a very simple class for # defining slots for slots, called BootStrapVariableSlot. # MetaSlot create ::nx::BootStrapVariableSlot ::nsf::relation::set BootStrapVariableSlot superclass ObjectParameterSlot BootStrapVariableSlot public method getParameterSpec {} { # # Bootstrap version of getParameter spec. Just bare essentials. # if {[info exists :parameterSpec]} { return ${:parameterSpec} } set name [namespace tail [self]] set prefix [expr {[info exists :positional] && ${:positional} ? "" : "-"}] set options [list] if {[info exists :default]} { if {[string match {*\[*\]*} ${:default}]} { lappend options substdefault } set :parameterSpec [list [list [:namedParameterSpec $prefix $name $options]] ${:default}] } else { set :parameterSpec [list [:namedParameterSpec $prefix $name $options]] } return ${:parameterSpec} } BootStrapVariableSlot protected method init {args} { # # Empty constructor; do nothing, intentionally without "next" # } ###################################################################### # configure nx::Slot ###################################################################### createBootstrapVariableSlots ::nx::Slot { } Slot protected method getParameterOptionSubstdefault {} { if {${:substdefault} eq "0b111"} { return substdefault } else { return substdefault=${:substdefault} } } ###################################################################### # configure nx::ObjectParameterSlot ###################################################################### createBootstrapVariableSlots ::nx::ObjectParameterSlot { {name "[namespace tail [::nsf::self]]"} {domain "[lindex [regexp -inline {^(.*)::(per-object-slot|slot)::[^:]+$} [::nsf::self]] 1]"} {manager "[::nsf::self]"} {per-object false} {methodname} {forwardername} {defaultmethods {}} {accessor public} {incremental:boolean false} {configurable true} {noarg} {nodashalnum} {disposition alias} {required false} {default} {initblock} {substdefault} {position 0} {positional} {elementtype} {multiplicity 1..1} {trace} } # TODO: check, if substdefault/default could work with e.g. alias; otherwise, move substdefault down # # Default unknown handler for all slots # ObjectParameterSlot protected method unknown {method args} { # # Report just application specific methods not starting with "__" # set methods [list] foreach m [::nsf::directdispatch [::nsf::self] \ ::nsf::methods::object::info::lookupmethods -source application] { if {[string match __* $m]} continue lappend methods $m } return -code error "method '$method' unknown for slot [::nsf::self]; valid are: {[lsort $methods]}" } ObjectParameterSlot protected method init {args} { # # Provide a default depending on :name for :methodname. When slot # objects are created, invalidate the object parameters to reflect # the changes # if {${:incremental} && [:info class] eq [current class]} { return -code error "flag incremental must not be used for this slot type" } if {![info exists :methodname]} { set :methodname ${:name} } if {${:per-object}} { ::nsf::parameter::cache::objectinvalidate ${:domain} } else { ::nsf::parameter::cache::classinvalidate ${:domain} } nsf::object::property [self] initialized 1 # # plain object parameter have currently no setter/forwarder # } ObjectParameterSlot public method destroy {} { if {[info exists :domain] && ${:domain} ne ""} { # # When slot objects are destroyed, flush the parameter cache and # delete the accessors # #puts stderr "*** slot destroy of [self], domain ${:domain} per-object ${:per-object}" if {${:per-object}} { ::nsf::parameter::cache::objectinvalidate ${:domain} if {[${:domain} ::nsf::methods::object::info::method exists ${:name}]} { ::nsf::method::delete ${:domain} -per-object ${:name} } } elseif {[::nsf::is class ${:domain}]} { ::nsf::parameter::cache::classinvalidate ${:domain} if {[${:domain} ::nsf::methods::class::info::method exists ${:name}]} { ::nsf::method::delete ${:domain} ${:name} } } elseif {[::nsf::is object ${:domain}]} { nsf::log warning "ignore improper domain ${:domain} during destroy (maybe per-object not set?)" } else { # # Depending on the deletion order, the object denoted in # ${:domain} might be already deleted. # } } ::nsf::next } # # Define a forwarder directing accessor calls to the slot # ObjectParameterSlot protected method createForwarder {name domain} { set dm [${:manager} cget -defaultmethods] ::nsf::method::forward $domain \ -per-object=${:per-object} \ $name \ -prefix "value=" \ -onerror [list ${:manager} onError] \ ${:manager} \ [expr {$dm ne "" ? [list %1 $dm] : "%1"}] %self \ ${:forwardername} } ObjectParameterSlot public method onError {cmd msg} { #puts stderr "==== DEBUG AppVeyor behavior <$cmd> <$msg>" if {[string match "%1 requires argument*" $msg]} { set template {wrong # args: use \"$cmd [join $methods |]\"} } elseif {[string match "*unknown for slot*" $msg]} { lassign $cmd slot calledMethod obj . regexp {=(.*)$} $calledMethod . calledMethod regexp {::([^:]+)$} $slot . slot set template {submethod $calledMethod undefined for $slot: use \"$obj $slot [join $methods |]\"} } if {[info exists template]} { set methods "" foreach m [lsort [:info lookup methods -callprotection public value=*]] { lappend methods [lindex [split $m =] end] } return -code error [subst $template] } return -code error $msg } ObjectParameterSlot protected method makeForwarder {} { # # Build forwarder from the source object class ($domain) to the slot # to delegate read and update operations. # # This method is intended to be called on RelationSlot or VariableSlot. # if {![info exists :forwardername]} { set :forwardername ${:methodname} } #puts stderr "makeforwarder --> '${:forwardername}'" if {[info exists :settername]} { set d [nsf::directdispatch ${:domain} \ ::nsf::classes::nx::Object::__resolve_method_path \ {*}[expr {${:per-object} ? "-per-object" : ""}] ${:settername}] :createForwarder [dict get $d methodName] [dict get $d object] } else { :createForwarder ${:name} ${:domain} } } ObjectParameterSlot protected method getParameterOptions { {-withMultiplicity 0} {-forObjectParameter 0} } { # # Obtain a list of parameter options from slot object # set options [list] if {[info exists :elementtype] && ${:elementtype} ne {}} { lappend options ${:elementtype} #puts stderr "+++ [self] added elementtype ${:elementtype}" } if {${:disposition} eq "slotset"} { lappend options slot=[::nsf::self] ${:disposition} if {${:forwardername} ne ${:name}} { lappend options method=${:forwardername} } } else { lappend options ${:disposition} } if {${:name} ne ${:methodname}} { lappend options method=${:methodname} } if {${:required}} { lappend options required } elseif {[info exists :positional] && ${:positional}} { lappend options optional } if {$forObjectParameter} { # # Check, if get or set methods were overloaded # if {[:info lookup method value=set] ni {"" "::nsf::classes::nx::RelationSlot::value=set"}} { # In case the "set" method was provided on the slot, ask nsf to call it directly lappend options slot=[::nsf::self] slotset } elseif {[:info lookup method value=get] ni {"" "::nsf::classes::nx::RelationSlot::value=get"}} { # In case the "get" method was provided on the slot, ask nsf to call it directly lappend options slot=[::nsf::self] } } if {[info exists :noarg] && ${:noarg}} {lappend options noarg} if {[info exists :nodashalnum] && ${:nodashalnum}} {lappend options nodashalnum} if {$withMultiplicity && [info exists :multiplicity] && ${:multiplicity} ne "1..1"} { #puts stderr "### [self] added multiplicity ${:multiplicity}" lappend options ${:multiplicity} } if {[info exists :substdefault]} { lappend options [:getParameterOptionSubstdefault] } return $options } ObjectParameterSlot public method getParameterSpec {} { # # Get a full object parameter specification from slot object # if {![info exists :parameterSpec]} { set prefix [expr {[info exists :positional] && ${:positional} ? "" : "-"}] set options [:getParameterOptions -withMultiplicity true -forObjectParameter true] if {[info exists :initblock]} { if {[info exists :default]} { if {[llength $options] > 0} { # # In case the parameter options contain a "slotset", this # would not be allowed by nsf::is. Therefore, we # remove this option before testing (we are already in the # slot object). # set p [lsearch -exact $options "slotset" ] if {$p > -1} { set check_options [lreplace $options $p $p] } else { set check_options $options } ::nsf::is -complain [join $check_options ,] ${:default} #puts stderr "::nsf::is -complain [join $options ,] ${:default} ==> OK" } append initblock "\n::nsf::var::set \[::nsf::self\] ${:name} [list ${:default}]\n" #puts stderr ================append-default-to-initblock-old=<${:initblock}> } lappend options initcmd append initblock ${:initblock} set :parameterSpec [list [:namedParameterSpec $prefix ${:name} $options] $initblock] } elseif {[info exists :default]} { set :parameterSpec [list [:namedParameterSpec $prefix ${:name} $options] ${:default}] } else { set :parameterSpec [list [:namedParameterSpec $prefix ${:name} $options]] } } #puts stderr [self]================${:parameterSpec} return ${:parameterSpec} } ObjectParameterSlot public method getPropertyDefinitionOptions {parameterSpec} { #puts "accessor <${:accessor}> configurable ${:configurable} per-object ${:per-object}" set mod [expr {${:per-object} ? "object" : ""}] set opts "" if {${:configurable}} { lappend opts -accessor ${:accessor} if {${:incremental}} {lappend opts -incremental} if {[info exists :default]} { return [list ${:domain} {*}$mod property {*}$opts [list $parameterSpec ${:default}]] } set methodName property } else { lappend opts -accessor ${:accessor} if {${:configurable}} {lappend opts -configurable true} if {[info exists :default]} { return [list ${:domain} {*}$mod variable {*}$opts $parameterSpec ${:default}] } set methodName variable } return [list ${:domain} {*}$mod $methodName {*}$opts $parameterSpec] } ObjectParameterSlot public method definition {} { set options [:getParameterOptions -withMultiplicity true] if {[info exists :positional]} {lappend options positional} #if {!${:configurable}} {lappend options noconfig} return [:getPropertyDefinitionOptions [:namedParameterSpec -map-private "" ${:name} $options]] } ###################################################################### # We have no working objectparameter yet, since it requires a # minimal slot infrastructure to build object parameters from # slots. The above definitions should be sufficient as a basis for # object parameters. We provide the definition here before we refine # the slot definitions. # # Invalidate previously defined object parameter (built with the # empty objectparameter definition. # ::nsf::parameter::cache::classinvalidate MetaSlot ###################################################################### # Define objectparameter method ###################################################################### Object protected method __object_configureparameter {} { set slotObjects [nsf::directdispatch [self] ::nsf::methods::object::info::lookupslots -type ::nx::Slot] return [::nsf::parameter::specs $slotObjects] } Class protected method __class_configureparameter {} { set slotObjects [nsf::directdispatch [self] ::nsf::methods::class::info::slotobjects -closure -type ::nx::Slot] return [::nsf::parameter::specs $slotObjects] } } namespace eval ::nx { ###################################################################### # class nx::RelationSlot ###################################################################### MetaSlot create ::nx::RelationSlot ::nsf::relation::set RelationSlot superclass ObjectParameterSlot createBootstrapVariableSlots ::nx::RelationSlot { {accessor public} {multiplicity 0..n} {settername} } RelationSlot protected method init {} { ::nsf::next if {${:accessor} ne ""} { :makeForwarder } } # # create methods for slot operations set/get/add/clear/delete # ::nsf::method::alias RelationSlot value=set ::nsf::relation::set ::nsf::method::alias RelationSlot value=get ::nsf::relation::get RelationSlot public method value=clear {obj prop} { set result [::nsf::relation::set $obj $prop] ::nsf::relation::set $obj $prop {} return $result } RelationSlot protected method delete_value {obj prop old value} { # # Helper method for the delete operation, deleting a value from a # relation slot list. # if {[string first * $value] > -1 || [string first \[ $value] > -1} { # # Value contains globbing meta characters. # if {[info exists :elementtype] && ${:elementtype} eq "mixinreg" && ![string match ::* $value]} { # # Prefix glob pattern with ::, since all object names have # leading "::" # set value ::$value } return [lsearch -all -not -glob -inline $old $value] } elseif {[info exists :elementtype] && ${:elementtype} eq "mixinreg"} { # # Value contains no globbing meta characters, and elementtype could be # fully qualified # if {[string first :: $value] == -1} { # # Obtain a fully qualified name. # if {![::nsf::object::exists $value]} { return -code error "$value does not appear to be an object" } set value [::nsf::directdispatch $value -frame method ::nsf::self] } } set p [lsearch -exact $old $value] if {$p > -1} { return [lreplace $old $p $p] } else { # # In the resulting list might be guards. If so, do another round # of checking to test the first list element. # set new [list] set found 0 foreach v $old { if {[llength $v]>1 && $value eq [lindex $v 0]} { set found 1 continue } lappend new $v } if {!$found} { return -code error "$value is not a $prop of $obj (valid are: $old)" } return $new } } RelationSlot public method value=add {obj prop value {pos 0}} { set oldSetting [::nsf::relation::get $obj $prop] #puts stderr [list ::nsf::relation::set $obj $prop [linsert $oldSetting $pos $value]] # # Use uplevel to avoid namespace surprises # ::uplevel [list ::nsf::relation::set $obj $prop [linsert $oldSetting $pos $value]] } RelationSlot public method value=delete {-nocomplain:switch obj prop value} { ::uplevel [list ::nsf::relation::set $obj $prop \ [:delete_value $obj $prop [::nsf::relation::get $obj $prop] $value]] } ###################################################################### # Register system slots ###################################################################### # # Create relation slots # # on nx::Object for # # object-mixin # object-filter # # and on nx::Class for # # mixin # filter ::nx::RelationSlot create ::nx::Object::slot::object-mixins \ -multiplicity 0..n \ -defaultmethods {} \ -disposition slotset \ -forwardername object-mixin \ -settername "object mixins" \ -elementtype mixinreg ::nx::RelationSlot create ::nx::Object::slot::object-filters \ -multiplicity 0..n \ -defaultmethods {} \ -disposition slotset \ -forwardername object-filter \ -settername "object filters" \ -elementtype filterreg ::nx::RelationSlot create ::nx::Class::slot::mixins \ -multiplicity 0..n \ -defaultmethods {} \ -disposition slotset \ -forwardername "class-mixin" \ -elementtype mixinreg ::nx::RelationSlot create ::nx::Class::slot::filters \ -multiplicity 0..n \ -defaultmethods {} \ -disposition slotset \ -forwardername class-filter \ -elementtype filterreg # # Define "class" as a ObjectParameterSlot defined as alias # ::nx::ObjectParameterSlot create ::nx::Object::slot::class \ -methodname "::nsf::methods::object::class" -elementtype class # # Define "superclass" as a ObjectParameterSlot defined as alias # ::nx::ObjectParameterSlot create ::nx::Class::slot::superclasses \ -methodname "::nsf::methods::class::superclass" \ -elementtype class \ -multiplicity 1..n \ -default ::nx::Object # # Define the initblock as a positional ObjectParameterSlot # ::nx::ObjectParameterSlot create ::nx::Object::slot::__initblock \ -disposition cmd \ -nodashalnum true \ -positional true \ -position 2 # # Make sure the invalidate all ObjectParameterSlots # ::nsf::parameter::cache::classinvalidate ::nx::ObjectParameterSlot # # Define method "guard" and "methods" for object filters # ::nx::Object::slot::object-filters object method value=guard {obj prop filter guard:optional} { if {[info exists guard]} { ::nsf::directdispatch $obj ::nsf::methods::object::filterguard $filter $guard } else { lindex [$obj info object filters -guards $filter] 0 2 } } ::nx::Object::slot::object-filters object method value=methods {obj prop pattern:optional} { if {[info exists pattern]} { $obj info object filters $pattern } else { $obj info object filters } } # # Define method "guard" and "methods" for filters # ::nx::Class::slot::filters object method value=guard {obj prop filter guard:optional} { if {[info exists guard]} { ::nsf::directdispatch $obj ::nsf::methods::class::filterguard $filter $guard } else { lindex [$obj info filters -guards $filter] 0 2 } } ::nx::Class::slot::filters object method value=methods {obj prop pattern:optional} { if {[info exists pattern]} { $obj info filters $pattern } else { $obj info filters } } # # object mixins # ::nx::Object::slot::object-mixins object method value=classes {obj prop pattern:optional} { if {[info exists pattern]} { $obj info object mixins $pattern } else { $obj info object mixins } } ::nx::Object::slot::object-mixins object method value=guard {obj prop mixin guard:optional} { if {[info exists guard]} { ::nsf::directdispatch $obj ::nsf::methods::object::mixinguard $mixin $guard } else { lindex [$obj info object mixins -guards $mixin] 0 2 } } # # mixins # ::nx::Class::slot::mixins object method value=classes {obj prop pattern:optional} { if {[info exists pattern]} { $obj info mixins $pattern } else { $obj info mixins } } ::nx::Class::slot::mixins object method value=guard {obj prop filter guard:optional} { if {[info exists guard]} { ::nsf::directdispatch $obj ::nsf::methods::class::mixinguard $filter $guard } else { lindex [$obj info mixins -guards $mixin] 0 2 } } #::nsf::method::alias ::nx::Class::slot::object-filters guard ::nx::Object::slot::object-filters::guard # # With a special purpose eval, we could avoid the need for # reconfigure for slot changes via eval (two cases in the regression # test). However, most of the eval uses are from various reading # purposes, so maybe this is an overkill. # #::nx::ObjectParameterSlot public method eval {cmd} { # set r [next] # #puts stderr "eval on slot [self] $cmd -> $r" # :reconfigure # return $r #} ###################################################################### # Variable slots ###################################################################### ::nsf::parameter::cache::classinvalidate MetaSlot MetaSlot create ::nx::VariableSlot -superclass ::nx::ObjectParameterSlot createBootstrapVariableSlots ::nx::VariableSlot { {arg} {convert false} {incremental:boolean false} {multiplicity 1..1} {accessor public} {type} {settername} {trace none} } ::nx::VariableSlot public method setCheckedInstVar {-nocomplain:switch -allowpreset:switch object value} { if {!$allowpreset && [::nsf::var::exists $object ${:name}] && !$nocomplain} { return -code error "object $object has already an instance variable named '${:name}'" } # # For checking the default, we do not want substdefault to be # passed to is, or is would have to do the subst.... # set options [:getParameterOptions -withMultiplicity true -withSubstdefault false] if {[llength $options]} { ::nsf::is -configure -complain -name ${:name}: [join $options ,] $value } set restore [:removeTraces $object *] # was: ::nsf::var::set $object ${:name} ${:default} ::nsf::var::set $object ${:name} $value if {[info exists restore]} { {*}$restore } } ::nx::VariableSlot protected method setterRedefinedOptions {} { # # In the :trace = "set" case, the slot will be set via the trace # triggered from the direct assignment. Otherwise, when the # "value=set" method is provided, tell nsf ot call it (e.g. in # configure). # if {${:trace} ne "set" && [:info lookup method value=set] ne "::nsf::classes::nx::VariableSlot::value=set"} { return [list slot=[::nsf::self] slotset] } if {[:info lookup method value=get] ne "::nsf::classes::nx::VariableSlot::value=get"} { # In case the "get" method was provided on the slot, ask nsf to call it directly return [list slot=[::nsf::self]] } } ::nx::VariableSlot protected method getParameterOptions { {-withMultiplicity 0} {-withSubstdefault 1} {-forObjectParameter 0} } { set options "" set slotObject "" if {[info exists :type]} { set type ${:type} if {$type eq "switch" && !$forObjectParameter} {set type boolean} if {$type in {cmd initcmd}} { lappend options $type } elseif {[string match ::* $type]} { lappend options [expr {[::nsf::is metaclass $type] ? "class" : "object"}] type=$type } else { lappend options $type if {$type ni [list "" \ "boolean" "integer" "object" "class" \ "metaclass" "baseclass" "parameter" \ "alnum" "alpha" "ascii" "control" "digit" "double" \ "false" "graph" "lower" "print" "punct" "space" "true" \ "wideinteger" "wordchar" "xdigit" ]} { lappend options slot=[::nsf::self] } } } if {$forObjectParameter} { foreach o [:setterRedefinedOptions] { if {$o ni $options} {lappend options $o} } } if {[:info lookup method initialize] ne "" && $forObjectParameter} { if {"slot=[::nsf::self]" ni $options} {lappend options slot=[::nsf::self]} lappend options slotinitialize } if {[info exists :arg]} {lappend options arg=${:arg}} if {$withSubstdefault && [info exists :substdefault]} { lappend options [:getParameterOptionSubstdefault] } if {${:required}} { lappend options required } elseif {[info exists :positional] && ${:positional}} { lappend options optional } if {${:convert}} {lappend options convert} if {$withMultiplicity && [info exists :multiplicity] && ${:multiplicity} ne "1..1"} { lappend options ${:multiplicity} } if {$forObjectParameter} { if {[info exists :configurable] && !${:configurable}} { lappend options noconfig } } #puts stderr "[self]*** getParameterOptions $withMultiplicity $withSubstdefault $forObjectParameter [self] returns '$options'" return $options } ::nx::VariableSlot protected method isMultivalued {} { return [string match {*..[n*]} ${:multiplicity}] } # # When there are accessors defined, we use always the forwarders in # NX. XOTcl2 has a detailed optimization. # ::nx::VariableSlot protected method needsForwarder {} { return 1 } ::nx::VariableSlot protected method makeAccessor {} { if {${:accessor} eq "none"} { #puts stderr "*** Do not register forwarder ${:domain} ${:name}" return 0 } if {[:needsForwarder]} { set handle [:makeForwarder] :makeIncrementalOperations } else { set handle [:makeSetter] } if {${:accessor} eq "protected"} { ::nsf::method::property ${:domain} {*}[expr {${:per-object} ? "-per-object" : ""}] \ $handle call-protected true set :configurable 0 } elseif {${:accessor} eq "private"} { ::nsf::method::property ${:domain} {*}[expr {${:per-object} ? "-per-object" : ""}] \ $handle call-private true set :configurable 0 } elseif {${:accessor} ne "public"} { set msg "accessor value '${:accessor}' invalid; might be one of public|protected|private or none" :destroy return -code error $msg } return 1 } ::nx::VariableSlot public method reconfigure {} { #puts stderr "*** Should we reconfigure [self]???" unset -nocomplain :parameterSpec if {${:incremental}} { if {${:accessor} eq "none"} { set :accessor "public" } if {![:isMultivalued]} { set :multiplicity [string range ${:multiplicity} 0 0]..n } } :makeAccessor if {${:per-object} && [info exists :default]} { :setCheckedInstVar -nocomplain=[info exists :nocomplain] ${:domain} ${:default} } if {[::nsf::is class ${:domain}]} { ::nsf::parameter::cache::classinvalidate ${:domain} } } ::nx::VariableSlot public method parameter {} { # This is a shortened "lightweight" version of "getParameterSpec" # returning less (implicit) details. Used e.g. by "info variable parameter" set options [:getParameterOptions -withMultiplicity true] set spec [:namedParameterSpec -map-private "" ${:name} $options] if {[info exists :default]} {lappend spec ${:default}} return $spec } ::nx::VariableSlot protected method checkDefault {} { if {![info exists :default] || [string match {*\[*\]*} ${:default}]} { return } # # For checking the default, we do not want substdefault to be # passed to is, or is would have to do the subst.... # set options [:getParameterOptions -withMultiplicity true -withSubstdefault false] if {[llength $options] > 0} { if {[catch {::nsf::is -complain -configure -name ${:name}: [join $options ,] ${:default}} errorMsg]} { #puts stderr "**** destroy [self] - $errorMsg" :destroy return -code error $errorMsg } } } ::nx::VariableSlot protected method init {} { if {${:incremental}} { if {${:accessor} eq "none"} { set :accessor "public" } if {![:isMultivalued]} { set :multiplicity [string range ${:multiplicity} 0 0]..n } } next :makeAccessor :checkDefault :handleTraces } ::nx::VariableSlot protected method makeSetter {} { set options [:getParameterOptions -withMultiplicity true -withSubstdefault false] set setterParam ${:name} if {[llength $options]>0} {append setterParam :[join $options ,]} ::nsf::method::setter ${:domain} {*}[expr {${:per-object} ? "-per-object" : ""}] $setterParam } ::nx::VariableSlot protected method defineIncrementalOperations {options_single options} { # # Just define these setter methods, when these are not defined # yet. We need the methods as well for e.g. private properties, # where the setting of the property is handled via slot. # if {[:info lookup method value=set] eq "::nsf::classes::nx::VariableSlot::value=set"} { set args [list obj var [:namedParameterSpec {} value $options]] :public object method value=set $args {::nsf::var::set $obj $var $value} } if {[:isMultivalued] && [:info lookup method value=add] eq "::nsf::classes::nx::VariableSlot::value=add"} { set slotObj "slot=[::nsf::self]" # lappend options_single slot=[::nsf::self] if {$slotObj ni $options_single} {lappend options_single $slotObj} set vspec [:namedParameterSpec {} value $options_single] set addArgs [list obj prop $vspec {pos 0}] :public object method value=add $addArgs {::nsf::next [list $obj $prop $value $pos]} set delArgs [list obj prop -nocomplain:switch $vspec] :public object method value=delete $delArgs {::nsf::next [list $obj $prop -nocomplain=$nocomplain $value]} } else { # TODO should we deactivate add/delete? } } ::nx::VariableSlot protected method makeIncrementalOperations {} { set options_single [:getParameterOptions -withSubstdefault false] #if {[llength $options_single] == 0} {} if {![info exists :type]} { # No need to make per-slot methods; the general rules on # nx::VariableSlot are sufficient return } #puts "makeIncrementalOperations -- single $options_single type ${:type}" #if {[info exists :type]} {puts ".... type ${:type}"} set options [:getParameterOptions -withMultiplicity true -withSubstdefault false] set slotObj "slot=[::nsf::self]" if {$slotObj ni $options} {lappend options $slotObj} :defineIncrementalOperations $options_single $options } ###################################################################### # Handle variable traces ###################################################################### ::nx::VariableSlot protected method removeTraces {object matchOps} { #puts stderr "====removeTraces ${:name} $matchOps" set restore "" set traces [::nsf::directdispatch $object -frame object ::trace info variable ${:name}] foreach trace $traces { lassign $trace ops cmdPrefix if {![string match $matchOps $ops]} continue #puts stderr "====remove trace variable ${:name} $ops $cmdPrefix" ::nsf::directdispatch $object -frame object ::trace remove variable ${:name} $ops $cmdPrefix append restore "[list ::nsf::directdispatch $object -frame object ::trace add variable ${:name} $ops $cmdPrefix]\n" } return $restore } ::nx::VariableSlot protected method handleTraces {} { # # This method assembles the __initblock, which might be used at # creation time of instances, or immediately for per-object slots. # set __initblock "" set traceCmd {::nsf::directdispatch [::nsf::self] -frame object ::trace} #puts stderr "instance variable trace has value <${:trace}>" if {"default" in ${:trace}} { if {"get" in ${:trace}} { return -code error \ "'-trace default' and '-trace get' can't be used together" } } # There might be already default values registered on the # class. If so, the default trace is ignored. if {[info exists :default]} { if {"default" in ${:trace}} { return -code error \ "'-trace default' can't be used together with default value" } #if {"get" in ${:trace}} { # return -code error \ # "'trace get' can't be used together with default value" #} } if {"default" in ${:trace}} { #puts stderr "DEFAULTCMD [self] trace=${:trace}" append __initblock "::nsf::directdispatch [::nsf::self] -frame object :removeTraces \[::nsf::self\] read\n" append __initblock "$traceCmd add variable [list ${:name}] read \ \[list [::nsf::self] __trace_default \[::nsf::self\]\]\n" } if {"get" in ${:trace}} { #puts stderr "VALUECMD [self] trace=${:trace}" append __initblock "::nsf::directdispatch [::nsf::self] -frame object :removeTraces \[::nsf::self\] read\n" append __initblock "$traceCmd add variable [list ${:name}] read \ \[list [::nsf::self] __trace_get \[::nsf::self\]\]\n" } if {"set" in ${:trace}} { #puts stderr "VALUECHANGED [self] trace=${:trace}" append __initblock "::nsf::directdispatch [::nsf::self] -frame object :removeTraces \[::nsf::self\] write\n" append __initblock "$traceCmd add variable [list ${:name}] write \ \[list [::nsf::self] __trace_set \[::nsf::self\]\]\n" } if {$__initblock ne ""} { if {${:per-object}} { ${:domain} eval $__initblock } #puts stderr initblock=$__initblock set :initblock $__initblock } } # # Implementation of methods called by the traces # ::nx::VariableSlot method __default_from_cmd {obj cmd var sub op} { #puts "GETVAR [::nsf::current method] obj=$obj cmd=$cmd, var=$var, op=$op" ::nsf::directdispatch $obj -frame object \ ::trace remove variable $var $op [list [::nsf::self] [::nsf::current method] $obj $cmd] ::nsf::var::set $obj $var [$obj eval $cmd] } # TODO: remove me # ::nx::VariableSlot method __value_from_cmd {obj cmd var sub op} { # #puts stderr "GETVAR [::nsf::current method] obj=$obj cmd=$cmd, var=$var, op=$op" # ::nsf::var::set $obj [string trimleft $var :] [$obj eval $cmd] # } #::nx::VariableSlot method __value_changed_cmd {obj method var sub op} { # #puts "valuechanged obj=$obj cmd=$cmd, var=$var, op=$op" # eval $cmd #} ::nx::VariableSlot method __trace_default {obj var sub op} { #puts stderr "trace_default call obj=$obj var=$var, sub=<$sub> op=$op" ::nsf::directdispatch $obj -frame object \ ::trace remove variable $var $op [list [::nsf::self] [::nsf::current method] $obj] ::nsf::var::set $obj $var [:value=default $obj $var] } ::nx::VariableSlot method __trace_get {obj var sub op} { #puts stderr "trace_get call obj=$obj var=$var, sub=<$sub> op=$op" :value=get $obj [string trimleft $var :] } ::nx::VariableSlot method __trace_set {obj var sub op} { #puts stderr "trace_set call obj=$obj var=$var, sub=<$sub> op=$op" set var [string trimleft $var :] :value=set $obj $var [::nsf::var::get $obj $var] } ###################################################################### # Implementation of (incremental) forwarder operations for # VariableSlots: # - set # - get # - add # - delete ###################################################################### ::nsf::method::alias ::nx::VariableSlot value=get ::nsf::var::get ::nsf::method::alias ::nx::VariableSlot value=set ::nsf::var::set ::nx::VariableSlot public method value=unset {obj prop -nocomplain:switch} { ::nsf::var::unset -nocomplain=$nocomplain $obj $prop } ::nx::VariableSlot public method value=exists {obj prop} { ::nsf::var::exists $obj $prop } ::nx::VariableSlot public method value=add {obj prop value {pos 0}} { if {![:isMultivalued]} { #puts stderr "... vars [[self] info vars] // [[self] eval {set :multiplicity}]" return -code error "property $prop of [set :domain] is not multivalued" } if {[::nsf::var::exists $obj $prop]} { ::nsf::var::set $obj $prop [linsert [::nsf::var::set $obj $prop] $pos $value] } else { ::nsf::var::set $obj $prop [list $value] } } ::nx::VariableSlot public method value=delete {obj prop -nocomplain:switch value} { set old [::nsf::var::get $obj $prop] set p [lsearch -glob $old $value] if {$p > -1} { ::nsf::var::set $obj $prop [lreplace $old $p $p] } elseif {!$nocomplain} { return -code error "$obj: '$value' is not in variable '$prop' (values are: '$old')" } else { return $old } } ###################################################################### # Define methods "property" and "variable" ###################################################################### nx::Object method "object variable" { {-accessor "none"} {-class ""} {-configurable:boolean false} {-incremental:switch} {-initblock ""} {-nocomplain:switch} {-trace} spec:parameter defaultValue:optional } { # # This method creates sometimes a slot, sometimes not # (optimization). We need a slot currently in the following # situations: # - when accessors are needed # (serializer uses slot object to create accessors) # - when initblock is non empty # #puts stderr "Object variable $spec accessor $accessor nocomplain $nocomplain incremental $incremental" # get name and list of parameter options lassign [::nx::MetaSlot parseParameterSpec -class $class -target [self] $spec] \ name parameterOptions class options #puts "[self] object variable $spec name <$name> parameterOptions <$parameterOptions> class <$class> options <$options>" if {[dict exists $options -configurable]} { set configurable [dict get $options -configurable] } if {![info exists trace] && [info exists :trace] && ${:trace} ne "none"} { set trace ${:trace} } #puts "[self] object variable $spec haveDefault? [info exists defaultValue] opts <$parameterOptions> options <$options>" if {[info exists defaultValue] && [dict exists $options -substdefault] && [string match {*\[*\]*} $defaultValue] } { if {![info complete $defaultValue]} { return -code error "substdefault: default '$defaultValue' is not a complete script" } set substDefaultOptions [::nx::MetaSlot substDefaultOptions [dict get $options -substdefault]] set defaultValue [subst {*}$substDefaultOptions $defaultValue] } # # Check for slot-less variables # if {$initblock eq "" && !$configurable && !$incremental && $accessor eq "none" && ![info exists trace] } { # # The variable is slot-less. # #puts "[self]... slotless variable $spec" # The following tasks have to be still performed: # - If there is an explicit default value, the value has to # be checked. # - if the type is a switch, we have to set the implicit # default value, when there is not explicit default # set isSwitch [expr {[dict exists $options -type] && [dict get $options -type] eq "switch"}] if {[info exists defaultValue]} { if {[info exists :$name] && !$nocomplain} { return -code error \ "object [self] has already an instance variable named '$name'" } if {$parameterOptions ne ""} { #puts stderr "*** ::nsf::is $parameterOptions $defaultValue // opts=$options" # # Extract from the options a spec for value checking, and # let "nsf::is" perform the actual checking. In case, the # check fails, "nsf::is" will raise an error with and error # message communicating the failure. # set nspec [::nx::MetaSlot optionsToValueCheckingSpec $options] ::nsf::is -complain $nspec $defaultValue } else { set name $spec } set :$name $defaultValue } elseif {$isSwitch} { set :$name 0 } else { return -code error \ "variable definition for '$name' (without value and accessor) is useless" } return } #puts "[self]... slot variable $spec" # # create variable via a slot object # set defaultopts [list -accessor $accessor] if {[info exists trace]} {lappend defaultopts -trace $trace} set slot [::nx::MetaSlot createFromParameterSpec [self] \ -per-object \ -class $class \ -initblock $initblock \ -incremental=$incremental \ -private=[expr {$accessor eq "private"}] \ -defaultopts $defaultopts \ $spec \ {*}[expr {[info exists defaultValue] ? [list $defaultValue] : ""}]] if {$nocomplain} {$slot eval {set :nocomplain 1}} if {!$configurable} {$slot eval {set :configurable false}} if {[info exists defaultValue]} { # # We could consider calling "configure" instead, but that would # not work for true "variable" handlers. # # In case a "get" trace is activated, don't complain about # pre-existing variables, which might be set via traces. # set allowpreset [expr {"get" in [$slot cget -trace] && [nsf::var::exists [self] $name]}] $slot setCheckedInstVar -allowpreset=$allowpreset -nocomplain=$nocomplain [self] $defaultValue #set :__initblock($name) 1 } if {[$slot eval {info exists :settername}]} { set name [$slot cget -settername] } else { set name [$slot cget -name] } #puts "[self]... $slot cget DONE" return [::nsf::directdispatch [self] ::nsf::methods::object::info::method registrationhandle $name] } Object method "object property" { {-accessor ""} {-class ""} {-configurable:boolean true} {-incremental:switch} {-nocomplain:switch} {-trace} spec:parameter {initblock ""} } { if {$accessor eq ""} { set accessor [::nsf::dispatch [self] __default_accessor] #puts stderr "OBJECT [self] got default accessor ${accessor}" } set traceSpec [expr {[info exists trace] ? [list -trace $trace] : ""}] set r [[self] object variable \ -accessor $accessor \ -incremental=$incremental \ -class $class \ -initblock $initblock \ -configurable $configurable \ -nocomplain=$nocomplain \ {*}$traceSpec \ {*}$spec] return $r } nx::Class method variable { {-accessor "none"} {-class ""} {-configurable:boolean false} {-incremental:switch} {-initblock ""} {-trace} spec:parameter defaultValue:optional } { set defaultopts [list -accessor $accessor -configurable $configurable] if {[info exists trace]} { foreach t $trace { if {$t ni {none get set default}} { return -code error "invalid value '$t' for trace: '$trace'" } } lappend defaultopts -trace $trace } lassign [::nx::MetaSlot parseParameterSpec -class $class -target [self] $spec] \ pname parameterOptions _ options if {[info exists defaultValue] && [dict exists $options -substdefault] && [string match {*\[*\]*} $defaultValue] && ![info complete $defaultValue] } { return -code error "substdefault: default '$defaultValue' is not a complete script" } set slot [::nx::MetaSlot createFromParameterSpec [::nsf::self] \ -class $class \ -initblock $initblock \ -incremental=$incremental \ -private=[expr {$accessor eq "private"}] \ -defaultopts $defaultopts \ $spec \ {*}[expr {[info exists defaultValue] ? [list $defaultValue] : ""}]] if {[$slot eval {info exists :settername}]} { set name [$slot cget -settername] } else { set name [$slot cget -name] } #puts stderr handle=[::nsf::directdispatch [self] ::nsf::methods::class::info::method registrationhandle $name] return [::nsf::directdispatch [self] ::nsf::methods::class::info::method registrationhandle $name] } nx::Class method property { {-accessor ""} {-class ""} {-configurable:boolean true} {-incremental:switch} {-trace} spec:parameter {initblock ""} } { if {$accessor eq ""} { set accessor [::nsf::dispatch [self] __default_accessor] } set traceSpec [expr {[info exists trace] ? [list -trace $trace] : ""}] set r [[self] ::nsf::classes::nx::Class::variable \ -accessor $accessor \ -incremental=$incremental \ -class $class \ -configurable $configurable \ -initblock $initblock \ {*}$traceSpec \ {*}$spec] return $r } ###################################################################### # Define method "properties" for convenience to define multiple # properties based on a list of parameter specifications. ###################################################################### # #proc ::nx::internal::addProperties {arglist} { # foreach arg $arglist {:property $arg} #} #::nx::ObjectParameterSlot create ::nx::Object::slot::properties \ # -methodname "::nx::internal::addProperties" ###################################################################### # Minimal definition of a value checker that permits every value # without warnings. The primary purpose of this value checker is to # provide a means to specify that the value can have every possible # content and not to produce a warning when it might look like a # non-positional parameter. ###################################################################### ::nx::Slot method type=any {name value} { } ::nsf::method::property ::nx::Slot type=any call-protected true ###################################################################### # Now the slots are defined; now we can defines the Objects or # classes with parameters more easily than above. ###################################################################### # remove helper proc rename ::nx::createBootstrapVariableSlots "" ###################################################################### # Define a scoped "new" method, which is similar to plain new, but # uses the current namespace by default as root of the object name. ###################################################################### Class create ::nx::NsScopedNew { :public method new {-childof args} { if {![info exists childof]} { # # Obtain the namespace from plain uplevel to honor the # namespace provided by apply # set childof [::uplevel {namespace current}] } # # Use the uplevel method to assure that e.g. "... new -volatile ..." # has the right scope # :uplevel [list [self] ::nsf::methods::class::new -childof $childof {*}$args] } } ###################################################################### # The method 'contains' changes the namespace in which objects with # relative names are created. Therefore, 'contains' provides a # friendly notation for creating nested object # structures. Optionally, creating new objects in the specified # scope can be turned off. ###################################################################### Object public method contains { {-withnew:boolean true} -object {-class:class ::nx::Object} cmds } { if {![info exists object]} {set object [::nsf::self]} if {![::nsf::object::exists $object]} {$class create $object} # This method is reused in XOTcl which has e.g. no "require"; # therefore use nsf primitiva. ::nsf::directdispatch $object ::nsf::methods::object::requirenamespace if {$withnew} { # # When $withnew is requested we replace the default new method # with a version using the current namespace as root. Earlier # implementations used a mixin on nx::Class and xotcl::Class, # but frequent mixin operations on the most general meta-class # are expensive when there are many classes defined # (e.g. several ten thousands), since the mixin operation # invalidates the mixins for all instances of the meta-class # (i.e. for all classes) # set infoMethod "::nsf::methods::class::info::method" set plainNew "::nsf::methods::class::new" set mappedNew [::nx::NsScopedNew $infoMethod definitionhandle new] set nxMapNew [expr {[::nx::Class $infoMethod origin new] eq $plainNew}] if {$nxMapNew} {::nsf::method::alias ::nx::Class new $mappedNew} if {[::nsf::is class ::xotcl::Class]} { set xotclMapNew [expr {[::xotcl::Class $infoMethod origin new] eq $plainNew}] if {$xotclMapNew} {::nsf::method::alias ::xotcl::Class new $mappedNew } } # # Evaluate the command under catch to ensure reverse mapping # of "new" # set errorOccurred [catch \ [list ::apply [list {} $cmds $object]] \ result errorOptions] # # Remove the mapped "new" method, if it was added above # if {$nxMapNew} {::nsf::method::alias ::nx::Class new $plainNew} if {[::nsf::is class ::xotcl::Class]} { if {$xotclMapNew} {::nsf::method::alias ::xotcl::Class new $plainNew} } # # Report the error with message and code when necessary # if {$errorOccurred} { dict incr errorOptions -level dict unset errorOptions -errorinfo } return -options $errorOptions $result } else { ::apply [list {} $cmds $object] } } ###################################################################### # copy/move implementation ###################################################################### Class create ::nx::CopyHandler { :property {targetList ""} :property {dest ""} :property objLength :method makeTargetList {t} { if {[::nsf::is object,type=::nx::EnsembleObject $t]} { # # we do not copy ensemble objects, since method # introspection/recreation will care about these # return } lappend :targetList $t #puts stderr "COPY makeTargetList $t targetList '${:targetList}'" # if it is an object without namespace, it is a leaf if {[::nsf::object::exists $t]} { if {[::nsf::directdispatch $t ::nsf::methods::object::info::hasnamespace]} { # make target list from all children set children [$t info children] } else { # ok, no namespace -> no more children return } } # now append all namespaces that are in the obj, but that # are not objects foreach c [namespace children $t] { if {![::nsf::object::exists $c]} { lappend children [namespace children $t] } } # a namespace or an obj with namespace may have children # itself foreach c $children { :makeTargetList $c } } # construct destination obj name from old qualified ns name :method getDest {origin} { if {${:dest} eq ""} { return "" } else { set tail [string range $origin [set :objLength] end] return ::[string trimleft [set :dest]$tail :] } } :method copyTargets {} { #puts stderr "COPY will copy targetList = [set :targetList]" set objs {} array set cmdMap {alias alias forward forward method create setter setter} foreach origin [set :targetList] { set dest [:getDest $origin] if {[::nsf::object::exists $origin]} { if {$dest eq ""} { #set obj [[$origin info class] new -noinit] set obj [::nsf::object::alloc [$origin info class] ""] #nsf::object::property $obj initialized 1 set dest [set :dest $obj] } else { # # Slot container are handled separately, since # ::nx::slotObj does already the right thing. We have just # to copy the variables (XOTcl keeps the parameter # definitions there). # if {[::nsf::object::property $origin slotcontainer]} { ::nx::slotObj -container [namespace tail $origin] \ [namespace qualifiers $dest] ::nsf::nscopyvars $origin $dest continue } else { # # create an object without calling init # #set obj [[$origin info class] create $dest -noinit] set obj [::nsf::object::alloc [$origin info class] $dest] #nsf::object::property $obj initialized 1 #puts stderr "COPY obj=<$obj>" } } # copy class information if {[::nsf::is class $origin]} { # obj is a class, copy class specific information ::nsf::relation::set $obj superclass [$origin ::nsf::methods::class::info::superclass] ::nsf::method::assertion $obj class-invar [::nsf::method::assertion $origin class-invar] ::nsf::relation::set $obj class-filter [::nsf::relation::get $origin class-filter] ::nsf::relation::set $obj class-mixin [::nsf::relation::get $origin class-mixin] ::nsf::nscopyvars ::nsf::classes$origin ::nsf::classes$dest foreach m [$origin ::nsf::methods::class::info::methods -path -callprotection all] { set rest [lassign [$origin ::nsf::methods::class::info::method definition $m] . protection what .] # remove -returns from reported definitions set p [lsearch -exact $rest -returns] if {$p > -1} {set rest [lreplace $rest $p $p+1]} set pathData [$obj eval [list :__resolve_method_path $m]] set object [dict get $pathData object] # # Create a copy of the instance method and set the method # properties with separate primitive commands. # set r [::nsf::method::$cmdMap($what) $object [dict get $pathData methodName] {*}$rest] ::nsf::method::property $object $r returns [$origin ::nsf::methods::class::info::method returns $m] ::nsf::method::property $object $r call-protected [::nsf::method::property $origin $m call-protected] ::nsf::method::property $object $r call-private [::nsf::method::property $origin $m call-private] } } # copy object -> might be a class obj ::nsf::object::property $obj keepcallerself [::nsf::object::property $origin keepcallerself] ::nsf::object::property $obj perobjectdispatch [::nsf::object::property $origin perobjectdispatch] ::nsf::object::property $obj hasperobjectslots [::nsf::object::property $origin hasperobjectslots] ::nsf::method::assertion $obj check [::nsf::method::assertion $origin check] ::nsf::method::assertion $obj object-invar [::nsf::method::assertion $origin object-invar] ::nsf::relation::set $obj object-filter [::nsf::relation::get $origin object-filter] ::nsf::relation::set $obj object-mixin [::nsf::relation::get $origin object-mixin] # reused in XOTcl, no "require namespace" there, so use nsf primitiva if {[::nsf::directdispatch $origin ::nsf::methods::object::info::hasnamespace]} { ::nsf::directdispatch $obj ::nsf::methods::object::requirenamespace } } else { namespace eval $dest {} } lappend objs $obj ::nsf::nscopyvars $origin $dest foreach m [$origin ::nsf::methods::object::info::methods -path -callprotection all] { set rest [lassign [$origin ::nsf::methods::object::info::method definition $m] . protection . what .] #if {$what eq ""} { # puts stderr "COPY <$m> can't handle [$origin ::nsf::methods::object::info::method definition $m] -> what '$what'" # continue #} # remove -returns from reported definitions set p [lsearch -exact $rest -returns]; if {$p > -1} {set rest [lreplace $rest $p $p+1]} set pathData [$obj eval [list :__resolve_method_path -per-object $m]] set object [dict get $pathData object] # # Create a copy of the object method and set the method # properties with separate primitive commands. # set r [::nsf::method::$cmdMap($what) $object -per-object \ [dict get $pathData methodName] {*}$rest] ::nsf::method::property $object -per-object $r \ returns [$origin ::nsf::methods::object::info::method returns $m] ::nsf::method::property $object -per-object $r \ call-protected [::nsf::method::property $origin -per-object $m call-protected] ::nsf::method::property $object -per-object $r \ call-private [::nsf::method::property $origin -per-object $m call-private] } # # transfer the traces # foreach var [$origin info vars] { set cmds [::nsf::directdispatch $origin -frame object ::trace info variable $var] #puts stderr "COPY $var <$cmds>" if {$cmds ne ""} { foreach cmd $cmds { lassign $cmd op def #$origin trace remove variable $var $op $def set domain [lindex $def 0] if {$domain eq $origin} { set def [concat $dest [lrange $def 1 end]] } #puts stderr "COPY $var domain $domain [::nsf::object::exists $domain] && [$domain info has type ::nx::Slot]" #if {[::nsf::object::exists $domain] && [$domain info has type ::nx::Slot]} { # slot traces are handled already by the slot mechanism #continue #} # # handle the most common cases to replace $origin by $dest in trace command # if {[lindex $def 2] eq $origin} { set def [lreplace $def 2 2 $dest] } elseif {[lindex $def 0] eq $origin} { set def [lreplace $def 0 0 $dest] } ::nsf::directdispatch $dest -frame object ::trace add variable $var $op $def } } } } # # alter 'domain' and 'manager' in slot objects # foreach origin [set :targetList] { set dest [:getDest $origin] set slots [list] # # get class specific slots # if {[::nsf::is class $origin]} { set slots [$origin ::nsf::methods::class::info::slotobjects -type ::nx::Slot] } # # append object specific slots # foreach slot [$origin ::nsf::methods::object::info::slotobjects -type ::nx::Slot] { lappend slots $slot } #puts stderr "replacing domain and manager from <$origin> to <$dest> in slots <$slots>" foreach oldslot $slots { set container [expr {[$oldslot cget -per-object] ? "per-object-slot" : "slot"}] set newslot [::nx::slotObj -container $container $dest [namespace tail $oldslot]] if {[$oldslot cget -domain] eq $origin} {$newslot configure -domain $dest} if {[$oldslot cget -manager] eq $oldslot} {$newslot configure -manager $newslot} $newslot eval :init } } return [lindex $objs 0] } #:public object method mapSlot {newslot origin dest} { # if {[$oldslot cget -domain] eq $origin} {$newslot configure -domain $dest} # if {[$oldslot cget -manager] eq $oldslot} {$newslot configure -manager $newslot} # $newslot eval :init #} :public method copy {obj {dest ""}} { #puts stderr "[::nsf::self] copy <$obj> <$dest>" set :objLength [string length $obj] set :dest $dest :makeTargetList $obj :copyTargets } } Object public method copy {{newName ""}} { if {[string trimleft $newName :] ne [string trimleft [::nsf::self] :]} { set h [CopyHandler new] set r [$h copy [::nsf::self] $newName] $h destroy return $r } } Object public method move {newName} { if {[string trimleft $newName :] ne [string trimleft [::nsf::self] :]} { if {$newName ne ""} { :copy $newName } ### let all subclasses get the copied class as superclass if {[::nsf::is class [::nsf::self]] && $newName ne ""} { foreach subclass [: ::nsf::methods::class::info::subclass] { set scl [$subclass ::nsf::methods::class::info::superclass] if {[set index [lsearch -exact $scl [::nsf::self]]] != -1} { set scl [lreplace $scl $index $index $newName] ::nsf::relation::set $subclass superclass $scl } } } :destroy } } ###################################################################### # Methods of meta-classes are methods intended for classes. Make # sure, these methods are only applied on classes. ###################################################################### foreach m [Class info methods] { ::nsf::method::property Class $m class-only true } if {[info exists m]} {unset m} ###################################################################### # some utilities ###################################################################### # # Provide mechanisms to configure nx # ::nx::Object create ::nx::configure { # # Set the default method protection for nx methods. This # protection level is used per default for all method definitions # of scripted methods, aliases and forwarders without explicit # protection specified. # :object method defaultMethodCallProtection {value:boolean,optional} { if {[info exists value]} { ::nsf::method::create Object __default_method_call_protection args [list return $value] ::nsf::method::property Object __default_method_call_protection call-protected true } return [::nsf::dispatch [::nx::self] __default_method_call_protection] } # # Set the default method accessor handling nx properties. The configured # value is used for creating accessors for properties in nx. # :object method defaultAccessor {value:optional} { if {[info exists value]} { if {$value ni {"public" "protected" "private" "none"}} { return -code error {defaultAccessor must be "public", "protected", "private" or "none"} } ::nsf::method::create Object __default_accessor args [list return $value] ::nsf::method::property Object __default_accessor call-protected true } return [::nsf::dispatch [::nx::self] __default_accessor] } } # # Make the default protected methods # ::nx::configure defaultMethodCallProtection true ::nx::configure defaultAccessor none # # Provide an ensemble-like interface to the ::nsf primitiva to # access variables. Note that aliasing in the next scripting # framework is faster than namespace-ensembles. # Object create ::nx::var { :public object alias exists ::nsf::var::exists :public object alias get ::nsf::var::get :public object alias import ::nsf::var::import :public object alias set ::nsf::var::set } #interp alias {} ::nx::self {} ::nsf::self set value "add /class/|classes ?/pattern/?|clear|delete /class/|get|guard /class/ /?expr?/|set /class .../" set "::nsf::parameter::syntax(::nx::Object::slot::__object::object mixins)" $value set "::nsf::parameter::syntax(::nsf::classes::nx::Class::mixins)" $value # set "::nsf::parameter::syntax(::nsf::classes::nx::Class::superclasses)" $value set "::nsf::parameter::syntax(::nsf::classes::nx::Object::class)" "?/className/?" set value "add /filter/|clear|delete /filter/|get|guard /filter/ ?/expr/?|methods ?/pattern/?|set /filter .../" set "::nsf::parameter::syntax(::nx::Object::slot::__object::object filters)" $value set "::nsf::parameter::syntax(::nsf::classes::nx::Class::filters)" $value set "::nsf::parameter::syntax(::nsf::classes::nx::Object::eval)" "/arg/ ?/arg/ ...?" unset value ::nsf::configure debug 1 } namespace eval ::nx { ###################################################################### # Define exported Tcl commands ###################################################################### # export the main commands of ::nx namespace export Object Class next self current set ::nx::confdir ~/.nx set ::nx::logdir $::nx::confdir/log unset ::nsf::bootstrap } if {[info command ::lmap] eq ""} { # provide a simple forward compatible version of Tcl 8.6's lmap proc lmap {_var list body} { ::upvar 1 $_var var set res {} foreach var $list {lappend res [::uplevel 1 $body]} return $res } } # # When debug is not deactivated, tell the developer, what happened # if {[::nsf::configure debug] > 1} { foreach ns {::nsf ::nx} { puts "vars of $ns: [info vars ${ns}::*]" puts stderr "$ns exports: [namespace eval $ns {lsort [namespace export]}]" } puts stderr "======= nx loaded" } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/lib/nx-pp.tcl000644 000766 000024 00000020241 13217712615 017154 0ustar00neumannstaff000000 000000 package require nx package provide nx::pp 1.0 # @package nx::pp # # A simple pretty printer for Tcl/XOTcl/NX # that converts a script into HTML output. # # Usage: # package require nx::pp # set html [nx::pp render { your script }] # # Designed to be usable from asciidoc like gnu source-highligt, # ignores options. # # Gustaf Neumann, Dez 2010 namespace eval ::nx::pp { # # The pretty printer is implemented via several States objects that # represent different context for input processing. Such states are # for example "comment" or "quoted strings". Every state contains # the parsed content, and a CSS class for HTML rendering. # nx::Class create State { :property {text ""} :property {cssClass:substdefault "[namespace tail [nx::self]]"} :property {prevState:substdefault "[default]"} :public method start {char} { # Start output in a state by initializing the text buffer. set :text $char return [nx::self] } :public method cssWrap {html} { if {${:cssClass} ne ""} { return "$html" } else { return $html } } :public method flush {} { # Flush the current text in the buffer using the css class set html [string map [list & {&} < {<} > {>}] ${:text}] ::nx::pp puts -nonewline [:cssWrap $html] set :text "" } :method new_state {new lastChar firstChar} { # Switch from one state to another state if {[$new eval {info exists :escape}]} { $new configure -prevState [nx::self] append :text $lastChar return [$new] } else { $new configure -prevState [default] append :text $lastChar :flush return [$new start $firstChar] } } :public method process {char} { # Process a single character in the current state append :text $char return [nx::self] } } # # Below, we define the state objects for processing the input # State create default -cssClass "" { # # The State "default" is processing bare Tcl words. In this state, # we perform substitutions of keywords and placeholders. # :public object method process {char} { switch $char { "\#" { return [:new_state comment "" $char]} "\"" { return [:new_state quoted "" $char]} "\$" { return [:new_state variable "" $char]} default {return [nx::next]} } } set keywords { after append apply array binary break catch cd chan clock close concat continue dict else encoding eof error eval exec exit expr fblocked fconfigure fcopy file fileevent flush for foreach format gets glob global if incr info interp join lappend lassign lindex linsert list llength load lrange lrepeat lreplace lreverse lsearch lset lsort namespace open pid proc puts read regexp regsub rename return scan seek set socket source split stdin stderr stdout string subst switch tell trace unset uplevel update upvar variable vwait while package public protected private method alias property forward delete require my next new self current dispatch objectparameter defaultmethod create init new destroy alloc dealloc recreate unknown move cget configure class object superclass mixin filter guard metaclass methods lookup ::nx::Class nx::Class ::xotcl::Class xotcl::Class Class ::nx::Object nx::Object ::xotcl::Object xotcl::Object Object ::nx::VariableSlot nx::VariableSlot Attribute } set :re(keyword1) (\[^:.-\])(\\m[join $keywords \\M|\\m]\\M) set :re(keyword2) (\[^:\])(\\m:[join $keywords \\M|:\\m]\\M) set :re(placeholder1) {([/][a-zA-Z0-9:]+?[/])} set :re(placeholder2) {([?][^ ][-a-zA-Z0-9: .]+?[?])} :public object method flush {} { set html [string map [list & {&} < {<} > {>}] ${:text}] regsub -all [set :re(keyword1)] " $html" {\1\2} html regsub -all [set :re(keyword2)] $html {\1\2} html set html [string range $html 1 end] regsub -all [set :re(placeholder1)] $html {\1} html regsub -all [set :re(placeholder2)] $html {\1} html nx::pp puts -nonewline [:cssWrap $html] set :text "" } } State create quoted -cssClass "string" { # # The State "quoted" is for content between double quotes. # :public object method process {char} { switch $char { "\"" {return [:new_state ${:prevState} $char ""]} "\\" {return [:new_state escape $char ""]} default {return [nx::next]} } } } State create comment { # # The State "comment" is for Tcl comments (currently, only up to # end of line) # :public object method process {char} { switch $char { "\n" {return [:new_state default $char ""]} default {return [nx::next]} } } } State create variable { # # The State "variable" is for simple Tcl variables (without curley # braces) # :public object method process {char} { switch -glob -- $char { {\{} {return [:new_state quoted_variable $char ""] } {[a-zA-Z0-9_:]} {return [nx::next]} default {return [:new_state default "" $char]} } } } State create quoted_variable -cssClass "variable" { # # The State "quoted_variable" is for Tcl variables, where the # names are quoted with curley braces. # :public object method process {char} { switch -glob -- $char { {\}} {return [:new_state default $char ""] } default {return [nx::next]} } } } State create escape -cssClass "" { # # The State "escape" is for simple backslash handling. # # Set an instance variable to ease identification of the state set :escape 1 # When a character is processed in the escape state, it is suffed # into the previous state and returns immediately to it. # :public object method process {char} { ${:prevState} eval [list append :text $char] return ${:prevState} } } } # # Finally, we create a simple pretty-printer as an object. The # method render receives a Tcl script as input and writes the HTML # output to stdout # nx::Object create nx::pp { :public object method toHTML {block} { set state [self]::default set l [string length $block] for {set i 0} {$i < $l} {incr i} { set state [$state process [string index $block $i]] } $state flush } :public object method numbers {block} { set nrlines [regsub -all \n $block \n block] incr nrlines set HTML "" for {set i 1} {$i<=$nrlines} {incr i} { append HTML [format %3d $i]\n } return $HTML } :public object method render {{-linenumbers false} -noCSSClasses:switch block} { set :output "" :toHTML $block set HTML ${:output} set :output "" :puts "" if {$linenumbers} { :puts -nonewline "" :puts -nonewline "
    [:numbers $block]
    $HTML
    " } else { :puts -nonewline "

    $HTML
    " } return ${:output} } :public object method puts {{-nonewline:switch} string} { append :output $string if {!$nonewline} {append :output \n} } } # pp render { # set x "hello\ngoodbye" # # a comment line # set b $c($a).b # foo a ${:text} b "hello \"$x" world # } # exit ./nsf2.4.0/library/lib/nx-zip.tcl000644 000766 000024 00000025722 14132556035 017347 0ustar00neumannstaff000000 000000 # # Zip file generator - Create a Zip-file from a list of input filenames # # This implementation is based on the zip file builder of Artur # Trzewik (https://wiki.tcl-lang.org/15158), but was simplified, refactored, # commented and extended, based on Trf and translated to NX; for # details about the format, see # https://www.pkware.com/documents/casestudies/APPNOTE.TXT # # by Gustaf Neumann (June 2011) # package require nx # # In case, we have not Tcl 8.6, fall back to the package Trf. # if {[info commands ::zlib] eq ""} { package require Trf } package provide nx::zip 1.3 namespace eval ::nx::zip { nx::Class create Archive { # # The public interface of the class archive contains the methods # # - addFile (add a file from the filesystem to the archive) # - addString (add the file-content from a string to the archive) # # - writeToZipFile (produce a Zip file) # - ns_returnZipFile (return a zip file via AOLserver ns_return) # # - writeToStream (for already opened and configured # output streams) # :property name ;# so far not used internally, but useful for # applications to pass the name around # # Add a file from the filesystem to the zip archive # :public method addFile {inputFileName outputFileName:optional} { # inputFileName - source file to archive # outputFileName - name of the file in the archive if {![file readable $inputFileName] || [file isdirectory $inputFileName]} { error "filename $inputFileName does not belong to a readable file" } if {![info exists outputFileName]} {set outputFileName $inputFileName} lappend :files file $inputFileName $outputFileName } # # Add a filecontent provided as string to the zip archive # :public method addString {string outputFileName} { # string - content to be added # outputFileName - name of the file in the archive lappend :files string $string $outputFileName } # # Write the added files to a zip file # :public method writeToZipFile {zipFileName} { set fout [open $zipFileName w] fconfigure $fout -translation binary set :writer [list puts -nonewline $fout] :writeToStream $fout close $fout } # # return the added files via aolserver/NaviServer to the client # :public method ns_returnZipFile {zipFileName} { append header \ "HTTP/1.0 200 OK\r\nContent-type: application/zip\r\n" \ "Content-Disposition: attachment;filename=\"$zipFileName\"\r\n" \ "\r\n" # # Check, if we have "ns_connchan status". If so, use ns_connchan # to write to the client. This has the advantage that we can use # the buffered "connchan write" method capable of handling # partial writes also for HTTPS. # if {[info commands ::ns_connchan] ne "" && [info commands ::acs::cmd_has_subcommand] ne "" && [::acs::cmd_has_subcommand ns_connchan status]} { set channel [ns_connchan detach] set :writer [list ns_connchan write -buffered $channel] ns_connchan write -buffered $channel $header :writeToStream $channel while {1} { set status [ns_connchan status $channel] if {[dict get $status sendbuffer] > 0} { ns_connchan write -buffered $channel "" ns_sleep 1ms } else { break } } ns_connchan close $channel } else { ns_write $header set channel [ns_conn channel] fconfigure $channel -translation binary set :writer [list puts -nonewline $channel] :writeToStream $channel # AOLserver closes the channel automatically } } # # Write the added files to an already open stream # :public method writeToStream {outputStream} { set :outputStream $outputStream # # Write all files to the output stream # set descriptionList [list] foreach {type in fnOut} ${:files} { lappend descriptionList [:addSingleFile $type $in $fnOut] } # # we have no # - archive description header # - archive extra data record # # Add the central directory # set :cdOffset ${:written} foreach {type in fnOut} ${:files} desc $descriptionList { array set "" $desc # For every file, it contains again part of the information of # the local file headers, but with some additional information # such as the "version made by", comment, ... set comment "" set platform 0 ;# dos/windows #if {$::tcl_platform(platform) ne "windows"} { # set platform 3 ;# unix #} # central file header signature binary scan \x02\x01\x4B\x50 I CFH_SIG :writeLong $CFH_SIG # version made by (os + zip version) :writeShort [expr { (($platform << 8) | 20) }] :writeFileHeaderBlock $desc # file comment length :writeShort [string length $comment] # disk number start :writeShort 0 # internal file attributes :writeShort 0 # external file attributes :writeLong 0 # relative offset of local header :writeLong $(offset) # filename :writeString $(fileNameInternal) :writeExtraFieldUPATH $(fileName) $(fileNameInternal) # file comment :writeString $comment } set :cdLength [expr {${:written} - ${:cdOffset}}] # # End of Central Directory record # binary scan \x06\x05\x4B\x50 I EOCD :writeLong $EOCD # disk numbers :writeShort 0 :writeShort 0 # number of entries set filenum [expr {[llength ${:files}] / 3}] :writeShort $filenum :writeShort $filenum # length and location of CD :writeLong ${:cdLength} :writeLong ${:cdOffset} # zip file comment set comment "" # comment length :writeShort [string bytelength $comment] :writeString $comment } # # Constructor # :method init {} { set :files [list] set :cdLength 0 set :cdOffset 0 set :written 0 } if {[info commands ::zlib] eq ""} { # # Fallback implementation based on Trf # :method crc32 {data} { return [::crc-zlib -- $data] } :method compress {data} { return [string range [::zip -mode compress -- $data] 2 end-4] } } else { # # Implementation based on Tcl 8.6 builtin support. # :method crc32 {data} { return [binary format i [::zlib crc32 $data]] } :method compress {data} { return [string range [::zlib compress $data] 2 end-4] } } # # Output content file to the output stream # :method addSingleFile {type in fnOut} { set (offset) ${:written} if {$type eq "file"} { set fdata [open $in r] fconfigure $fdata -encoding binary -translation binary set data [read $fdata] close $fdata set mtime [file mtime $in] } else { set data [encoding convertto utf-8 $in] set mtime [clock seconds] } # # local file header # binary scan \x04\x03\x4B\x50 I LFH_SIG :writeLong $LFH_SIG set datacompressed [:compress $data] set (dosTime) [:toDosTime $mtime] set (crc) [:crc32 $data] set (csize) [string length $datacompressed] set (size) [string length $data] set (fileName) [encoding convertto utf-8 $fnOut] set (fileNameInternal) $(fileName) #set (fileNameInternal) [encoding convertto cp850 $fnOut] set (extraFieldLength) [expr {9+[string length $(fileName)]}] :writeFileHeaderBlock [array get ""] # filename :writeString $(fileNameInternal) :writeExtraFieldUPATH $(fileName) $(fileNameInternal) # # file data # :writeString $datacompressed return [array get ""] } :method writeFileHeaderBlock {pairs} { array set "" $pairs # version needed to extract :writeShort 20 # general pupose bit flag :writeShort [expr {1<<11}] #:writeShort 0 # compression method :writeShort 8 # last modification time and date :writeLong $(dosTime) :writeString $(crc) :writeLong $(csize) :writeLong $(size) # filename length :writeShort [string length $(fileNameInternal)] # extra field length :writeShort $(extraFieldLength) } # # Convert the provided timestamp to DOS time. # :method toDosTime {time} { foreach {year month day hour minute second} \ [clock format $time -format "%Y %m %e %k %M %S"] {} set RE {^0([0-9]+)$} regexp $RE $year . year regexp $RE $month . month regexp $RE $day . day regexp $RE $hour . hour regexp $RE $minute . minute regexp $RE $second . second set value [expr {(($year - 1980) << 25) | ($month << 21) | ($day << 16) | ($hour << 11) | ($minute << 5) | ($second >> 1)}] return $value } # # Extra field UPath: Info-ZIP Unicode Path Extra Field # :method writeExtraFieldUPATH {fileName fileNameInternal} { # extra field UPATH binary scan \x70\x75 S EPEF :writeShort $EPEF :writeShort [expr {5 + [string length $fileName]}] :writeByte 1 :writeString [:crc32 $fileNameInternal] :writeString $fileName } # # Write the provided integer in binary form as a long value (32 bit) # :method writeLong {long:integer} { {*}${:writer} [binary format i $long] incr :written 4 } # # Write the provided integer in binary form as a short value (16 bit) # :method writeShort {short:integer} { {*}${:writer} [binary format s $short] incr :written 2 } # # Write the provided integer in binary form as a single byte (8 bit) # :method writeByte {byte:integer} { {*}${:writer} [binary format c $byte] incr :written 1 } # # Write the provided string to the output stream and increment # byte counter. # :method writeString {string} { {*}${:writer} $string incr :written [string length $string] } :method writeStringBytes {string} { {*}${:writer} $string incr :written [string bytelength $string] } } } if {0} { set z [::nx::zip::Archive new] $z addFile README.aol $z addFile COPYRIGHT $z addFile nsfUtil.o $z addFile doc/nx.css $z addString "This is a file\nthat может be from a string\n" README $z addString "-Avec 3,2% des parts de marché, la France est le sixième plus grand pays fournisseur de l’Autriche. " franz.txt $z writeToZipFile /tmp/test.zip $z destroy } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/lib/nx-test.tcl000644 000766 000024 00000017745 13305426671 017535 0ustar00neumannstaff000000 000000 package provide nx::test 1.0 package require nx namespace eval ::nx { # @file Simple regression test support for XOTcl / NX nx::Class create nx::test { # # Class Test is used to configure test instances, which can # be configured by the following parameters: # # @param cmd the command to be executed # @param expected the expected result # @param count number of executions of cmd # @param pre a command to be executed at the begin of the test (before cmd) # @param post a command to be executed after the test (after all cmds) # @param namespace in which pre, post and cmd are evaluated; default "::" # # The defined tests can be executed by [:cmd "Test run"] :property {name ""} :property cmd :property {namespace ::} :property {verbose:boolean 0} :property {expected:any 1} :property {count:integer 1} :property msg :property setResult :property errorReport :property pre :property post :object property {count:integer 1} :object property {verbose:boolean 0} :object variable success 0 :object variable failure 0 :object variable testfile "" :object variable ms 0 :object variable case "test" :public object method success {} { incr :success } :public object method failure {} { incr :failure } :public object method ms {ms:double} { set :ms [expr {${:ms} + $ms}] } :public object method destroy {} { lappend msg \ Test-set [file rootname [file tail ${:testfile}]] \ tests [expr {${:success} + ${:failure}}] \ success ${:success} \ failure ${:failure} \ ms ${:ms} puts "Summary: $msg\n" array set "" $::argv if {[info exists (-testlog)]} { set f [open $(-testlog) a]; puts $f $msg; close $f } next } :public object method case {name arg:optional} { # # Experimental version of Test case, which (1) accepts test case as argument # and (2) destroys all created objects on exit (auto cleanup) # # General limitation: namespace resolving differs in nested evals # from global evals. So, this approach is not suitable for all tests # (but for most). # # Current limitations: # - cleanup for nx::Objects, # - no method/mixin cleanup # - no var cleanup # set :case $name nsf::log notice "Running test case: [info script] $name" if {[info exists arg]} { foreach o [Object info instances -closure] {set pre_exist($o) 1} # namespace eval :: [list [current] eval $arg] apply [list {} $arg ::] foreach o [Object info instances -closure] { if {[info exists pre_exist($o)]} continue if {$o eq "::xotcl::Attribute"} continue if {[namespace tail $o] in {slot per-object-slot}} continue if {[string match {*::slot::__*} $o]} continue if {[::nsf::object::exists $o]} {$o destroy} } } } :public object method new args { set testfile [file rootname [file tail [info script]]] set :testfile $testfile if {![info exists :ccount(${:case})]} {set :ccount(${:case}) 0} set :name $testfile/${:case}.[format %.3d [incr :ccount(${:case})]] :create ${:name} -name ${:name} -count ${:count} -verbose ${:verbose} {*}$args } :public object method run {} { set startTime [clock clicks -milliseconds] foreach example [lsort [:info instances -closure]] { $example run } set ms [expr {[clock clicks -milliseconds]-$startTime}] puts stderr "Total Time: $ms ms" } :public method call {msg cmd} { if {${:verbose}} {puts stderr "$msg: $cmd"} return [::namespace eval ${:namespace} $cmd] } :public method run args { set startTime [clock clicks -milliseconds] :exitOn if {[info exists :pre]} {:call "pre" ${:pre}} if {![info exists :msg]} {set :msg ${:cmd}} #set gotError [catch {:call "run" ${:cmd}} r] if {[catch { set r [:call run ${:cmd}] } errorMsg opts]} { set errorCode [dict get $opts -errorcode] if {$errorCode ne "NONE"} { set r $errorMsg } else { set r $errorMsg } set gotError 1 } else { set gotError 0 set errorCode "NONE" } # # When 8.5 support is dropped, use: # # try { # :call run ${:cmd} # } on error {errorMsg opts} { # set errorCode [dict get $opts -errorcode] # if {$errorCode ne "NONE"} { # set r $errorMsg # } else { # set r $errorMsg # } # set gotError 1 # } on ok {r} { # set gotError 0 # set errorCode "NONE" # } #puts stderr "gotError = $gotError // $r == ${:expected} // [info exists :setResult]" if {[info exists :setResult]} {set r [eval [set :setResult]]} if {$r eq ${:expected} || $errorCode eq ${:expected}} { if {$gotError} { set c 1 if {$errorCode ne "NONE" && $errorCode ne ${:expected}} { puts stderr "[set :name] hint: we could compare with errorCode: $errorCode" } } else { if {[info exists :count]} {set c ${:count}} {set c 1000} } #puts stderr "running test $c times" if {${:verbose}} {puts stderr "running test $c times"} if {$c > 1} { # # The following line was used to calculate calling-overhead. # deactivated for now, since sometimes the reported calling # overhead was larger than the call. # #set r0 [time {time {::namespace eval ${:namespace} ";"} $c}] #regexp {^(-?[0-9]+) +} $r0 _ mS0 set r1 [time {time {::namespace eval ${:namespace} ${:cmd}} $c}] #puts stderr "running {time {::namespace eval ${:namespace} ${:cmd}} $c} => $r1" regexp {^(-?[0-9]+) +} $r1 _ mS1 #set ms [expr {($mS1 - $mS0) * 1.0 / $c}] set ms [expr {$mS1 * 1.0 / $c}] # if for some reason the run of the test is faster than the # body-less eval, don't report negative values. #if {$ms < 0} {set ms 0.0} #puts stderr "[set :name]:\t[format %6.2f $ms]\tmms, ${:msg} (overhead [format %.2f [expr {$mS0*1.0/$c}]])" puts stderr "[set :name]:\t[format %6.2f $ms]\tmms, ${:msg}" } else { puts stderr "[set :name]: ${:msg} ok" } ::nx::test success } else { puts stderr "[set :name]:\tincorrect result for '${:msg}', expected:" puts stderr "'${:expected}', got\n\"$r\"" puts stderr "\tin test file [info script]" if {[info exists :errorReport]} {eval [set :errorReport]} ::nx::test failure # # Make sure that the script exits with an error code, but # unwind the callstack via return with an error code. Using # [exit -1] would leave us with a partially unwinded callstack # with garbage complicating debugging (e.g. MEM_COUNT # statistics would indicate unbalanced refCounts, etc.). :exit -1 } if {[info exists :post]} {:call "post" ${:post}} ::nx::test ms [expr {[clock clicks -milliseconds]-$startTime}] :exitOff } :public method exit {{statuscode "1"}} { array set map {1 ok -1 error} set errorcode $map($statuscode) :exitOff set lvls [info level] # for {set i 0} {$i<=$lvls} {incr i} {puts $i-->[info level $i]} return -code $errorcode -level $lvls "Test was exited with code $statuscode" } :public method exitOn {} { interp hide {} exit; interp alias {} ::exit {} [current] exit } :public method exitOff {} { interp alias {} ::exit {} interp expose {} exit; } } ::namespace export Test } proc ? {cmd expected {msg ""}} { set namespace [uplevel {::namespace current}] #puts stderr "eval in namespace $namespace" if {$msg ne ""} { set t [nx::test new -cmd $cmd -msg $msg -namespace $namespace] } else { set t [nx::test new -cmd $cmd -namespace $namespace] } $t configure -expected $expected $t run nsf::__db_run_assertions } # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/lib/nx-help.tcl000644 000766 000024 00000002743 12501766547 017504 0ustar00neumannstaff000000 000000 package provide nx::help 1.0 package require nx namespace eval ::nx { proc help {args} { set l [llength $args] if {$l == 0} { nsf::log info "Usage: help /nsf-tcl command/" return } if {[nsf::is object [lindex $args 0]]} { set obj [nsf::dispatch [lindex $args 0] eval self] if {$l == 1} { nsf::log info "$obj /method/ ..." return } set w [lrange $args 1 end] set h [$obj ::nsf::methods::object::info::lookupmethod $w] if {$h eq ""} { nsf::log warn "$obj has no method \"$w\"" return } set origin [nsf::cmd::info origin $h] if {$origin eq ""} { # # Since "info object ..." is not a true ensemble, we # have to use the definition handle. # set origin [nsf::cmd::info definitionhandle $h] } if {[nsf::is object $origin]} { nsf::log info "$obj $w [join [lsort [nsf::cmd::info submethods $origin]] |] ..." } else { nsf::log info "$obj $w [nsf::cmd::info syntax -context $obj $h]" } return } # # catch-all # set cmd [namespace origin [lindex $args 0]] nsf::log info "[lindex $args 0] [nsf::cmd::info syntax $cmd]" return } } return nx::help nx::Object nx::help nx::Object configure nx::help nx::Object create nx::help nx::Object new nx::help nx::Object newx nx::help nx::Object info nx::help nx::Object info precedence nx::help nx::Object info vars nx::help nx::Object info object nx::help nx::Object info object mixin nx::help nx::Object info object methods nx::help nsf::cmd::info ./nsf2.4.0/library/lib/nx-volatile.tcl000644 000766 000024 00000001065 12501766547 020367 0ustar00neumannstaff000000 000000 # # Package to add configure-parameter "-volatile" # package require nx package provide nx::volatile 1.0 namespace eval ::nx { ::nx::ObjectParameterSlot create ::nx::Object::slot::volatile -noarg true ::nsf::method::create ::nx::Object::slot::volatile value=set {object var value} { $object ::nsf::methods::object::volatile } ::nsf::method::create ::nx::Object::slot::volatile value=get {object var} { ::nsf::object::property $object volatile } } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/lib/pkgIndex.tcl000644 000766 000024 00000002042 14276141440 017660 0ustar00neumannstaff000000 000000 package ifneeded nx::help 1.0 "[list source [file join $dir nx-help.tcl]]; [list package provide nx::help 1.0]" package ifneeded nx::pp 1.0 "[list source [file join $dir nx-pp.tcl]]; [list package provide nx::pp 1.0]" package ifneeded nx::shell 1.1 "[list source [file join $dir nx-shell.tcl]]; [list package provide nx::shell 1.1]" package ifneeded nx::test 1.0 "[list source [file join $dir nx-test.tcl]]; [list package provide nx::test 1.0]" package ifneeded nx::trait 0.4 "[list source [file join $dir nx-traits.tcl]]; [list package provide nx::trait 0.4]" package ifneeded nx::trait::callback 1.0 "[list source [file join $dir nx-callback.tcl]]; [list package provide nx::trait::callback 1.0]" package ifneeded nx::volatile 1.0 "[list source [file join $dir nx-volatile.tcl]]; [list package provide nx::volatile 1.0]" package ifneeded nx::zip 1.3 "[list source [file join $dir nx-zip.tcl]]; [list package provide nx::zip 1.3]" # -*- Tcl -*- namespace eval ::nsf { set traitIndex(nx::trait::callback) {script {package require nx::trait::callback}} } ./nsf2.4.0/library/lib/nx-shell.tcl000644 000766 000024 00000014430 14164662337 017656 0ustar00neumannstaff000000 000000 # -*- Tcl -*- ############################################################ # nx-shell.tcl -- # # Scripted shell (REPL) infrastructure for NX and XOTcl2. # # Copyright (C) 2010-2012 Gustaf Neumann # Copyright (C) 2016 Stefan Sobernig # # Vienna University of Economics and Business # Institute of Information Systems and New Media # A-1020, Welthandelsplatz 1 # Vienna, Austria # # This work is licensed under the MIT License https://www.opensource.org/licenses/MIT # # Copyright: # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # package require nx package provide nx::shell 1.1 nx::Object create ::nx::shell { :public object method onRead {{chan stdin}} { append :line [read $chan] if {[eof $chan]} { set :forever 0 fileevent $chan readable {} } if {${:line} eq "\n"} { unset :line :prompt return } if {[info complete ${:line}]} { :evalScript ${:line} unset :line if {![info exists :forever]} { :prompt } } } :protected object method evalScript {-exit:switch script} { set script [list interp invokehidden {} catch [string trim $script] [current]::result [current]::opts] set r [uplevel #0 $script] if {$r == 1} { puts stderr [dict get ${:opts} -errorinfo] if {$exit} { :onExit -shell 1 } else { unset :opts; } } elseif {$r == 2 && [info exists :statusCode]} { set sc ${:statusCode} unset :statusCode if {$exit} { :onExit -shell $sc } else { set :forever $sc } } else { if {${:result} ne ""} { puts stdout ${:result} } unset :result } } :protected object method prompt {{chan stdout}} { puts -nonewline $chan "% " flush $chan } :public object method run {argc argv} { :exitOn if {$argc == 0} { # interactive mode :prompt stdout fconfigure stdin -blocking 0 -buffering line fileevent stdin readable [list [current] onRead] vwait :forever fileevent stdin readable {} :onExit -shell ${:forever} } else { # noninteractive modes :nonInteract {*}$argv } :exitOff return 0 } :protected object method nonInteract {-c:switch args} { if {$c} { # noninteractive mode: arg command xor stdin if {[llength $args]} { # arg command plus argc/argv set args [lassign $args script] set ::argv $args set ::argc [llength $args] } else { # stdin set ::argv "" set ::argc 0 set script [gets stdin] } :evalScript -exit $script } else { # noninteractive mode: script set ::argv [lassign $args argv0] incr ::argc -1 if {[catch {uplevel #0 [list source $argv0]} msg opts]} { puts [dict get $opts -errorinfo] exit 1 } } } :public object method onExit {-shell:switch {statusCode 0}} { if {$shell} { :exitOff # outer (shell) exit return -code ok -level [info level] $statusCode } else { # inner (script) exit set :statusCode $statusCode return -code return -level [info level] } } :public object method onCatch {args} { set r [uplevel 1 [list interp invokehidden {} catch {*}$args]] if {$r == 2 && [info exists :statusCode]} { return -code return } return $r } # 8.6 only if {[info commands ::try] ne ""} { :public object method onHandler {script} { if {[info exists :statusCode]} { return -code return -level 2 } uplevel 1 $script } :public object method onTry {script args} { set l [llength $args] for {set i 0; set j 1} {$i < $l} {incr i; set j [expr {$i + 1}]} { # watch out for the finally handler if {$i == $l - 2 && [lindex $args $i] eq "finally"} { set finallyScript [lindex $args $j] lset args $j [list [current] onHandler $finallyScript] break } # watch out for on-return handlers if {$i < $l - 3 && [lindex $args $i] eq "on" && [lindex $args $j] in {return 2}} { # imputate a wrapped return script set idx [expr {$i + 3}] set returnScript [lindex $args $idx] lset args $idx [list [current] onHandler $returnScript] incr i 3 } } uplevel 1 [list interp invokehidden {} try $script {*}$args] } } :public object method exitOn {} { if {[info commands ::_exit] eq ""} { # # exit is already aliased/hidden by nx::test # rename ::exit ::_exit proc ::exit {{exitCode 0}} "[current] onExit \$exitCode" interp hide {} catch; interp alias {} ::catch {} [current] onCatch } if {[info commands ::try] ne ""} { # 8.6 only interp hide {} try; interp alias {} ::try {} [current] onTry } } :public object method exitOff {} { if {[info commands ::_exit] ne ""} { rename ::exit "" rename ::_exit ::exit interp alias {} ::catch {} interp expose {} catch; if {[interp alias {} ::try] ne ""} { # 8.6 only interp alias {} ::try {} interp expose {} try; } } } } package provide nx::shell 1.1 # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/lib/nx-callback.tcl000644 000766 000024 00000000646 13030507001 020260 0ustar00neumannstaff000000 000000 package require nx package require nx::trait package provide nx::trait::callback 1.0 nx::Trait create nx::trait::callback { # # A small support trait to ease syntactically the reference to # instance variables and the registration of callbacks. # :method bindvar {name} { :require namespace return [nx::self]::$name } :method callback {name args} { return [list [nx::self] $name {*}$args] } } ./nsf2.4.0/library/lib/nx-callback.add000644 000766 000024 00000000175 13030507001 020223 0ustar00neumannstaff000000 000000 # -*- Tcl -*- namespace eval ::nsf { set traitIndex(nx::trait::callback) {script {package require nx::trait::callback}} } ./nsf2.4.0/library/lib/nx-traits.tcl000644 000766 000024 00000013741 13076355505 020056 0ustar00neumannstaff000000 000000 package require nx package provide nx::trait 0.4 # @package nx::trait # # Minimal trait framework with checking in NX, based on # # S. Ducasse, O. Nierstrasz, N. Schärli, R. Wuyts, A. Black: # Traits: A Mechanism for Fine-grained Reuse, # ACM transactions on Programming Language Systems, Vol 28, No 2, March 2006 # # Gustaf Neumann (Aug 2011) # # Traits are a mechanism for the reuse of methods. In contrary to # other forms of reuse (e.g. inheritance of methods in a class # hierarchy or via mixin classes), the methods defined in traits are # materialized in the target objects and classes. This gives more # fine-grained control over the reuse of methods and overcomes the # "total composition ordering" limitation of mixins. # # The current implementation does not handle overwrites (conflicting # definition from several traits), be we handle renames (aliases) and # we check required methods. "requiredVariables" (not part of the # ducasse paper) are not checked yet. # # In essence, the package provides a class "nx::Trait" to define # Traits and a method "useTrait" to reuse a trait in trait consumer # (e.g. a class or another trait). # # Usage: # package require nx::trait # nx::Trait create .... { # ... # } # nx::Class create .... { # ... # :useTrait ... # } # # # Define a method to allow configuration for verbosity of the # trait operations: # # nx::configure trait-verbosity on|off # # This might be useful for debugging of complex trait compositions. # nx::configure public object method trait-verbosity {onoff:boolean,optional} { if {[info exists onoff]} { set :trait-verbosity $onoff } else { set :trait-verbosity } } nx::configure trait-verbosity off namespace eval ::nx::trait { # # nx::trait::provide and nx::trait::require implement a basic # auto-loading mechanism for traits # nsf::proc provide {traitName script} { set ::nsf::traitIndex($traitName) [list script $script] } nsf::proc require {traitName} { if {[::nsf::object::exists $traitName]} {return} set key ::nsf::traitIndex($traitName) if {[info exists $key]} { array set "" [set $key] if {$(script) ne ""} { eval $(script) } } if {[::nsf::object::exists $traitName]} {return} error "cannot require trait $traitName, trait unknown" } # # The function nx::trait::add adds the methods defined in the # specified trait to the obj/class provided as first argument. # nsf::proc add {obj -per-object:switch traitName {nameMap ""}} { array set map $nameMap if {${per-object} || ![::nsf::is class $obj]} { error "per-object traits are currently not supported" } foreach m [$traitName info methods -callprotection all -path] { if {[info exists map($m)]} {set newName $map($m)} else {set newName $m} # do not add entries with $newName empty if {$newName eq ""} continue set traitMethodHandle [$traitName info method definitionhandle $m] $obj public alias $newName $traitMethodHandle if {[nx::configure trait-verbosity]} { puts "...trait: $obj public alias $newName" } } foreach slot [$traitName info variables] { #puts "$obj - will define: [$traitName info variable definition $slot]" $obj {*}[lrange [$traitName info variable definition $slot] 1 end] if {[nx::configure trait-verbosity]} { puts "...trait: $obj [lrange [$traitName info variable definition $slot] 1 end]" } } } # # The function nx::trait::checkObject checks, whether the target # object has the method defined that the trait requires. # nsf::proc checkObject {obj traitName} { foreach m [$traitName cget -requiredMethods] { #puts "$m ok? [$obj info methods -closure $m]" if {[$obj info lookup method $m] eq ""} { error "trait $traitName requires $m, which is not defined for $obj" } } } # # The function nx::trait::checkClass checks, whether the target # class has the method defined that the trait requires. # nsf::proc checkClass {obj traitName} { foreach m [$traitName cget -requiredMethods] { #puts "$m ok? [$obj info methods -closure $m]" if {[$obj info methods -closure $m] eq ""} { error "trait $traitName requires $m, which is not defined for $obj" } } } } # # The require methods for traits extend the predefined ensemble with # trait-specific subcommands. # nx::Class public method "require trait" {traitName {nameMap ""}} { # adding a trait to a class if {[nx::configure trait-verbosity]} { puts "trait: [self] requires $traitName" } nx::trait::require $traitName nx::trait::checkClass [self] $traitName nx::trait::add [self] $traitName $nameMap } #nx::Object public method "require object trait" {traitName {nameMap ""}} { # puts "[self] require object trait $traitName -- MAYBE OBSOLETE" # # adding a trait to an object # nx::trait::require $traitName # nx::trait::checkObject [self] $traitName # nx::trait::add [self] -per-object $traitName $nameMap #} # # The class "nx::Trait" provides the basic properties and methods needed for # the trait management. # nx::Class create nx::Trait -superclass nx::Class { :property {package} :property {requiredMethods:0..n ""} :property {requiredVariables:0..n ""} ::nsf::method::setter [self] requiredMethods:0..n ::nsf::method::setter [self] requiredVariables:0..n :public method "require trait" {traitName {nameMap ""}} { # adding a trait to a trait nx::trait::require $traitName nx::trait::add [self] $traitName $nameMap set finalReqMethods {} # remove the methods from the set of required methods, which became available foreach m [lsort -unique [concat ${:requiredMethods} [$traitName cget -requiredMethods]]] { if {[:info methods $m] eq ""} {lappend finalReqMethods $m} } #puts "final reqMethods of [self]: $finalReqMethods // defined=[:info methods]" set :requiredMethods $finalReqMethods } } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/library/lib/COPYRIGHT000644 000766 000024 00000005037 12501766547 016717 0ustar00neumannstaff000000 000000 /* * Next Scripting Framework * * Copyright (C) 1999-2014 Gustaf Neumann (a) (b) * Copyright (C) 1999-2007 Uwe Zdun (a) (b) * Copyright (C) 2007-2008 Martin Matuska (b) * Copyright (C) 2010-2014 Stefan Sobernig (b) * * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1090, Augasse 2-6 * Vienna, Austria * * This work is licensed under the MIT License * http://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * * This software is based upon MIT Object Tcl by David Wetherall and * Christopher J. Lindblad, that contains the following copyright * message: * * "Copyright 1993 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this * software and its documentation for any purpose is hereby granted * without fee, provided that the above copyright notice appear in * all copies and that both that copyright notice and this * permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity * pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about * the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty." */ ./nsf2.4.0/library/lib/make.tcl000644 000766 000024 00000013474 13670420514 017036 0ustar00neumannstaff000000 000000 ### ### Utility for the build process. Main purpose currently: ### ### - Build the pkgIndex in each directory ### # adjust the paths; # - auto_path is needed, when nx is loaded via good old pkgIndex.tcl # - tcl::tm::roots is needed when nx is provided as a Tcl module (.tm) lappend auto_path .. ::tcl::tm::roots [pwd] #puts stderr TM-LIST=[ ::tcl::tm::path list ] set verbose 0 package require nx namespace eval ::nx {}; # make pkg_mkIndex happy ### nx::Object create make { # # shared lib add files for pkgIndex.tcl # :object method mkIndex {name} { if {$::verbose} {puts stderr "+++ mkIndex in [pwd]"} set fls {} foreach f [glob -nocomplain *tcl] { if {![file isdirectory $f]} { set F [file open $f]; set c [read $F]; close $F if {[string match "*package provide*" $c]} { lappend fls $f } } } set so [glob -nocomplain *[info sharedlibextension]] set version $::nsf::version # loading libnext into nextsh might cause problems on some systems foreach lib [list libnext$version[info sharedlibextension] \ next$version.dll] { set p [lsearch -exact $so $lib] if {$p != -1} { set so [lreplace $so $p $p] puts stderr "new so=<$so>" } } #puts stderr "[pwd]: call so=<$so>" lappend fls {*}$so if {$fls ne ""} { if {[file exists pkgIndex.tcl]} { file delete -force pkgIndex.tcl } #puts stderr "callinglevel <[current callinglevel]> $fls" # # redefine the logging behavior to show just error or warnings, # preceded by the current directory # #set ::current [pwd] proc ::tclLog msg { if {[regexp {^(error|warning)} $msg]} { if {[regexp -nocase error $msg]} { error $msg } puts stderr "$msg ([pwd])" } } set flags "-verbose -direct -load nsf" # the following test is just an approximization, loading nsf + # nx does not seem to work for binary extensions (e.g. mongodb) if {$fls ne "nx.tcl" && ![string match "*[info sharedlibextension]" $fls]} { append flags " -load nx" } #package prefer latest if {$::verbose} {puts stderr "[pwd]:\n\tcall pkg_mkIndex $flags . $fls"} pkg_mkIndex {*}$flags . {*}$fls if {$::verbose} {puts stderr "[pwd] done"} } foreach addFile [glob -nocomplain *.add] { if {[file exists $addFile]} { puts stderr "Appending $addFile to pkgIndex.tcl in [pwd]" set OUT [file open pkgIndex.tcl a] set IN [file open $addFile] puts -nonewline $OUT [read $IN] close $IN; close $OUT } } #puts stderr "+++ mkIndex name=$name, pwd=[pwd] DONE" } :public object method inEachDir {path cmd} { if {$::verbose} {puts stderr "[pwd] inEachDir $path (dir [file isdirectory $path]) $cmd"} if { [file isdirectory $path] && ![string match *CVS $path] && ![string match *SCCS $path] && ![string match *Attic $path] && ![string match *dbm* $path] } { set olddir [pwd] cd $path if {[catch {make {*}$cmd $path} errMsg]} { error "$errMsg (in directory [pwd])" } set files [glob -nocomplain *] cd $olddir foreach p $files { :inEachDir $path/$p $cmd } if {$::verbose} {puts stderr "+++ change back to $olddir"} } } :object method in {path cmd} { if {[file isdirectory $path] && ![string match *CVS $path]} { set olddir [pwd] cd $path make {*}$cmd $path cd $olddir } } } ### Tcl file-command rename file tcl_file nx::Object create file { :require namespace array set :destructive { atime 0 attributes 0 copy 1 delete 1 dirname 0 executable 0 exists 0 extension 0 isdirectory 0 isfile 0 join 0 lstat 0 mkdir 1 mtime 0 nativename 0 owned 0 pathtype 0 readable 0 readlink 0 rename 1 rootname 0 size 0 split 0 stat 0 tail 0 type 0 volumes 0 writable 0 } foreach subcmd [array names :destructive] { :public object method $subcmd args { #puts stderr " [pwd] call: '::tcl_file [current method] $args'" ::tcl_file [current method] {*}$args } } } rename open file::open proc open {f {mode r}} { file open $f $mode } ### minus n option nx::Class create make::-n foreach f [file info object methods] { if {$f eq "unknown" || $f eq "next" || $f eq "self"} continue if {![file exists destructive($f)] || [file eval [list set :destructive($f)]]} { #puts stderr destruct=$f make::-n method $f args { puts "--- [pwd]:\t[current method] $args" } } else { #puts stderr nondestruct=$f make::-n method $f args { set r [next] #puts "??? [current method] $args -> {$r}" return $r } } } ### command line parameters if {![info exists argv] || $argv eq ""} {set argv -all} if {$argv eq "-n"} {set argv "-n -all"} nx::Class create Script { :public object method create args { lappend args {*}$::argv set s [next] set method [list] foreach arg [lrange $args 1 end] { switch -glob -- $arg { "-all" {$s all} "-n" {$s n} "-*" {set method [string range $arg 1 end]} default { puts "$s $method $arg" $s $method $arg } } } } :object method unknown args { puts stderr "$::argv0: Unknown option ´-$args´ provided" } :public method n {} {file mixin make::-n} :public method all {} {make inEachDir . mkIndex} :public method dir {dirName} {cd $dirName} :public method target {path} {make eval [list set :target $path]} if {[catch {:create main} errorMsg]} { puts stderr "*** $errorMsg" # Exit silently, although we are leaving from an active stack # frame. ::nsf::configure debug 0 exit -1 } } #puts stderr "+++ make.tcl finished." #exit $::result ./nsf2.4.0/library/lib/mkIndex.tcl000644 000766 000024 00000004652 14274463622 017526 0ustar00neumannstaff000000 000000 ### ### Utility for the build process. Main purpose currently: ### ### - Build the pkgIndex in each directory ### # adjust the paths; # - auto_path is needed, when nx is loaded via good old pkgIndex.tcl # - tcl::tm::roots is needed when nx is provided as a Tcl module (.tm) lappend auto_path .. # Is support for Tcl modules available (>= Tcl 8.5)? if {[info commands ::tcl::tm::roots] ne ""} { ::tcl::tm::roots [pwd] } set verbose 0 proc mkIndex {} { if {$::verbose} { puts stderr "+++ mkIndex in [pwd]" } set fls {} foreach f [glob -nocomplain *tcl] { if {![file isdirectory $f] && $f ne "pkgIndex.tcl"} { set F [open $f]; set c [read $F]; close $F if {[string match "*package provide*" $c]} { lappend fls $f #puts "provide in $f" foreach l [split $c \n] { #puts stderr "check $l" if {[regexp {^\s*package\s+provide\s+(\S+)\s+([0-9]\S+)\s*$} $l _ pkg version]} { #puts stderr "found package $pkg $version in $f" set pkg_file($pkg) $f set pkg_version($pkg) $version break } } } } } set pkgIndex "" foreach pkg [lsort [array names pkg_file]] { append pkgIndex "package ifneeded $pkg $pkg_version($pkg)\ \"\[list source \[file join \$dir $pkg_file($pkg)\]\];\ \[list package provide $pkg $pkg_version($pkg)\]\"\n" } foreach addFile [glob -nocomplain *.add] { if {[file exists $addFile]} { puts stderr "Appending $addFile to pkgIndex.tcl in [pwd]" set IN [open $addFile] append pkgIndex [read $IN]\n close $IN } } if {$pkgIndex ne ""} { if {$::verbose} { puts stderr "Write [pwd]/pkgIndex.tcl" } set OUT [open pkgIndex.tcl w] puts -nonewline $OUT $pkgIndex close $OUT } #puts stderr "+++ mkIndex pwd=[pwd] DONE" } proc inEachDir {path cmd} { if {$::verbose} { puts stderr "[pwd] inEachDir $path (dir [file isdirectory $path]) $cmd" } if { [file isdirectory $path] && ![string match *CVS $path] && ![string match *SCCS $path] && ![string match *Attic $path] && ![string match *dbm* $path] } { set olddir [pwd] cd $path if {[catch $cmd errMsg]} { error "$errMsg (in directory [pwd])" } set files [glob -nocomplain *] cd $olddir foreach p $files { inEachDir $path/$p $cmd } if {$::verbose} { puts stderr "+++ change back to $olddir" } } } inEachDir . mkIndex ./nsf2.4.0/library/COPYRIGHT000644 000766 000024 00000005037 12501766547 016151 0ustar00neumannstaff000000 000000 /* * Next Scripting Framework * * Copyright (C) 1999-2014 Gustaf Neumann (a) (b) * Copyright (C) 1999-2007 Uwe Zdun (a) (b) * Copyright (C) 2007-2008 Martin Matuska (b) * Copyright (C) 2010-2014 Stefan Sobernig (b) * * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1090, Augasse 2-6 * Vienna, Austria * * This work is licensed under the MIT License * http://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * * This software is based upon MIT Object Tcl by David Wetherall and * Christopher J. Lindblad, that contains the following copyright * message: * * "Copyright 1993 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this * software and its documentation for any purpose is hereby granted * without fee, provided that the above copyright notice appear in * all copies and that both that copyright notice and this * permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity * pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about * the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty." */ ./nsf2.4.0/library/tcl-cool/tcl-cool.tcl000644 000766 000024 00000021525 13270042525 020575 0ustar00neumannstaff000000 000000 set auto_path [concat . $auto_path] ######################################################################### # # Implementation of the Tcl Core Object Oriented Language (TclCOOL) # based on the Next Scripting Framework # ######################################################################### # # This script consists of three major parts: # # 1. The definition of TclCOOL (Tcl Core Object Oriented Language) # based on the Next Scripting Framework (::nsf). TclCOOL is # simple but powerful object language. # # 2. Sample TclCOOL program # # In a first step, we load nsf package require nsf # Now we have the following commands and methods defined in the ::nsf # namespace (among more functionality not needed here): # # Two un-exported commands for OO-language designer # ::nsf::alias # ::nsf::objectsystem::create # ::nsf::forward # ::nsf::method # ::nsf::relation::set # # Three exported commands to be used by in the languages # ::nsf::my # ::nsf::current # ::nsf::next # # An unregistered (unattached) set of methods that can be used for # objects. We use here just: # instvar # lookupmethods # # An unattached method can be attached to an object or class by the # ::nsf::alias # # ::nsf::method::alias class|obj ?-per-object? methodName cmdName # # The command registers a command ("cmdName") under a certain name # ("methodName") to an object or class (1st argument) to make the # command available as a method. ###################################################################### # # 1. TclCOOL language definition based on the Next Scripting Framework # ###################################################################### namespace eval tcl-cool { # In a first step, we create two base classes of TclCOOL, # namely "object" and "class" in the current namespace: ::nsf::objectsystem::create object class # We have now the two base classes defined as Tcl commands. Now we # can define methods for these newly defined classes # (tcl-cool::object and tcl-cool::class). # # We define as well [self] as a synonym of "nsf::current object" # interp alias {} ::tcl-cool::self {} ::nsf::current object # We define 2 methods for "class" (actually "::tcl-cool::class) # based on the method set for classes # # - "method" is a means to define the methods, which are provided # by the class to the instances of the class # - "forward" is a forwarder for instances of the class # # These methods are defined by the means of ::nsf::forward ::nsf::method::forward class method ::nsf::method::create %self ::nsf::method::forward class forward ::nsf::method::forward %self # We could have defined the methods "method" and "forward" as well # by the means of ::nsf::method, such as # # ::nsf::method::create class method {methodName arguments body} { # return [::nsf::method::create [self] $methodName $arguments $body] # } # ::nsf::method::create class forward {methodName args} { # return [::nsf::method::forward [self] $methodName {*}$args] # } # # Sometimes using method is better to be selective on the arguments # and the provided switches. # Next, we define 3 methods for "object" (actually "::tcl-cool::object) # based on the method set for objects # # - "variable" is a means to import instance variables into # the current scope ("instvar" in XOTcl) # - "forward" is a method for delegating calls to different objects # - "methods" is an introspection method for showing the methods of an object # ::nsf::method::alias object variable ::nsf::methods::object::instvar ::nsf::method::forward object forward ::nsf::method::forward %self -per-object ::nsf::method::alias object methods ::nsf::methods::object::info::lookupmethods # # The method "create" defines, what happens, when a class or object # is created. First the object is allocated, then the constructor is called. # class method create {name args} { set obj [::nsf::dispatch [self] ::nsf::methods::class::alloc $name] $obj init {*}$args return $obj } # provide primitive commands; we use these from nsf namespace import ::nsf::next ::nsf::my # a small helper proc for processing the body of the constructor proc pop vn {upvar $vn v; set r [lindex $v 0]; set v [lreplace $v 0 0]; return $r} # When we create classes without specifying a superclass, we have to # choose a default class. This is achieved by setting an instance # variable in the meta-class "class" with the name # "__default_superclass" to the newly defined object. In XOTcl, this # is integrated with the slot objects that provide a uniform # interface. Slot objects would need more support from other # commands in TclCOOL, so they are left out for the time being.... # # The following method is the constructor for classes. It sets the # default superclass and provides easy means for specifying methods # and superclasses during initialization class method init {spec} { my variable __default_superclass set __default_superclass [namespace current]::object while {[llength $spec]} { set m [pop spec] switch $m { method {my method [pop spec] [pop spec] [pop spec]} superclass {my superclass [pop spec]} default {error "unknown argument '$m'"} } } } # Call the constructor on "class" to set the default superclass as # well for this class, and define a convenience routine for defining # superclasses class init { method superclass {sc} { ::nsf::relation::set [self] superclass $sc } } # Finally, we provide a few methods for all objects in TclCOOL: # - "unknown": provide an error message, when unknown methods are called # - "filter": convenience routine to set filters though object method unknown {m args} {error "[self]: unknown method '$m' called"} # Provide users a convenient way to register/deregister per-object # filters and mixins object forward filter ::nsf::relation::set %self object-filter object forward mixin ::nsf::relation::set %self object-mixin # finally, export a few commands namespace export object class my self next } ###################################################################### # # 3. Sample TclCOOL program # ###################################################################### namespace import tcl-cool::* class create dog { method init {} { tail create [self]::tail my forward wag [self]::tail wag my forward rise [self]::tail rise } method bark {} { puts "[self] Bark, bark, bark." } } # we can extend the class incrementally dog method chase {thing} { puts "Chase $thing!" } class create tail { method init {} { my variable length set length 5 } method wag {} { return Joy } method rise {} { return Attention } } dog create fido puts "wag means [fido wag]" fido chase tweedy! # The output is: # wag means Joy # Chase tweedy!! puts "\n============ filter ================" # # define a filter method.... # object method tracer args { puts "* call [self] [::nsf::current calledmethod] [::nsf::current args]" set r [next] puts "* exit [self] [::nsf::current calledmethod], returns '$r'" return $r } # # ... and register the filter on the object: # fido filter tracer # # invoke the methods again # puts "wag means [fido wag]" fido chase tweedy! # The output is: # > ============ filter ================ # > * call ::fido wag # > * exit ::fido wag, returns 'Joy' # > wag means Joy # > * call ::fido chase tweedy! # > Chase tweedy!! # > * exit ::fido chase, returns '' # > * call ::fido filter {} # > * exit ::fido filter, returns '' # # remove the filter # fido filter "" puts "\n============ mixin class ================" # # define a class, which should be mixed in into instances of dogs # class create lazydog { method wag {} { puts "... well, if i have to...." next } method chase thing { puts "... [self] does not like to chase $thing" } } # # ... and register the filter on the object: # fido mixin lazydog # # invoke the methods again # puts "wag means [fido wag]" fido chase tweedy! # The output is: # > ============ mixin class ================ # > ... well, if i have to.... # > wag means Joy # > ... ::fido does not like to chase tweedy! # # remove the mixin class again # fido mixin "" puts "\n============ subclass ================" class create terrier { superclass dog method chase thing { puts "[self]: Yippy, I'll get that wicked $thing!" } } terrier create frido frido chase tweedy # The output is: # > ============ subclass ================ # >Yippy, I'll get that wicked tweedy!! puts "\nApplication specific methods of fido: [fido methods -source application]" puts "System specific methods of fido: [fido methods -source baseclasses]" puts "All methods of fido: [fido methods]\n" foreach cmd {{fido wag} {fido rise}} { puts "$cmd [time {eval $cmd} 10000]" } ./nsf2.4.0/library/store/XOTclSdbm/Makefile000644 000766 000024 00000044717 13553530231 021244 0ustar00neumannstaff000000 000000 # Makefile.in -- # # This file is a Makefile for Sample TEA Extension. If it has the name # "Makefile.in" then it is a template for a Makefile; to generate the # actual Makefile, run "./configure", which is a configuration script # generated by the "autoconf" program (constructs like "@foo@" will get # replaced in the actual Makefile. # # Copyright (c) 1999 Scriptics Corporation. # Copyright (c) 2002-2003 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: Makefile.in,v 1.5 2007/08/14 16:38:26 neumann Exp $ #======================================================================== # Add additional lines to handle any additional AC_SUBST cases that # have been added in a customized configure script. #======================================================================== #SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@ #======================================================================== # Nothing of the variables below this line should need to be changed. # Please check the TARGETS section below to make sure the make targets # are correct. #======================================================================== #======================================================================== # The names of the source files is defined in the configure script. # The object files are used for linking into the final library. # This will be used when a dist target is added to the Makefile. # It is not important to specify the directory, as long as it is the # $(srcdir) or in the generic, win or unix subdirectory. #======================================================================== PKG_SOURCES = hash.c pair.c sdbm.c xotclsdbm.c PKG_OBJECTS = hash.o pair.o sdbm.o xotclsdbm.o PKG_STUB_SOURCES = PKG_STUB_OBJECTS = #======================================================================== # PKG_TCL_SOURCES identifies Tcl runtime files that are associated with # this package that need to be installed, if any. #======================================================================== PKG_TCL_SOURCES = #======================================================================== # This is a list of public header files to be installed, if any. #======================================================================== PKG_HEADERS = #======================================================================== # "PKG_LIB_FILE" refers to the library (dynamic or static as per # configuration options) composed of the named objects. #======================================================================== PKG_LIB_FILE = libxotclsdbm1.2.dylib PKG_STUB_LIB_FILE = libxotclsdbmstub1.2.a lib_BINARIES = $(PKG_LIB_FILE) BINARIES = $(lib_BINARIES) SHELL = /bin/sh srcdir = . prefix = /usr/local exec_prefix = /usr/local/ bindir = ${exec_prefix}/bin libdir = ${exec_prefix}/lib datadir = ${prefix}/share mandir = ${prefix}/share/man includedir = ${prefix}/include DESTDIR = PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_VERSION) pkgdatadir = $(datadir)/$(PKG_DIR) pkglibdir = $(libdir)/$(PKG_DIR) pkgincludedir = $(includedir)/$(PKG_DIR) top_builddir = . INSTALL = /usr/bin/install -c INSTALL_PROGRAM = ${INSTALL} INSTALL_DATA = ${INSTALL} -m 644 INSTALL_SCRIPT = ${INSTALL} PACKAGE_NAME = xotclsdbm PACKAGE_VERSION = 1.2 CC = gcc CFLAGS_DEFAULT = -g CFLAGS_WARNING = -Wall -Wno-implicit-int CLEANFILES = pkgIndex.tcl EXEEXT = LDFLAGS_DEFAULT = -prebind -headerpad_max_install_names -Wl,-search_paths_first MAKE_LIB = ${SHLIB_LD} -o $@ $(PKG_OBJECTS) ${SHLIB_LD_LIBS} MAKE_SHARED_LIB = ${SHLIB_LD} -o $@ $(PKG_OBJECTS) ${SHLIB_LD_LIBS} MAKE_STATIC_LIB = ${STLIB_LD} $@ $(PKG_OBJECTS) MAKE_STUB_LIB = ${STLIB_LD} $@ $(PKG_STUB_OBJECTS) OBJEXT = o RANLIB = : RANLIB_STUB = ranlib SHLIB_CFLAGS = -fno-common SHLIB_LD = ${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT} -Wl,-single_module SHLIB_LD_FLAGS = @SHLIB_LD_FLAGS@ SHLIB_LD_LIBS = ${LIBS} -L/usr/local/src/tcl8.5.13/unix -ltclstub8.5 STLIB_LD = ${AR} cr TCL_DEFS = -DPACKAGE_NAME=\"tcl\" -DPACKAGE_TARNAME=\"tcl\" -DPACKAGE_VERSION=\"8.5\" -DPACKAGE_STRING=\"tcl\ 8.5\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DNO_VALUES_H=1 -DHAVE_LIMITS_H=1 -DHAVE_SYS_PARAM_H=1 -DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 -D_THREAD_SAFE=1 -DHAVE_PTHREAD_ATTR_SETSTACKSIZE=1 -DHAVE_PTHREAD_GET_STACKSIZE_NP=1 -DTCL_THREADS=1 -DTCL_CFGVAL_ENCODING=\"iso8859-1\" -DMODULE_SCOPE=extern\ __attribute__\(\(__visibility__\(\"hidden\"\)\)\) -DMAC_OSX_TCL=1 -DHAVE_COREFOUNDATION=1 -DHAVE_CAST_TO_UNION=1 -DTCL_SHLIB_EXT=\".dylib\" -DTCL_TOMMATH=1 -DMP_PREC=4 -DTCL_WIDE_INT_IS_LONG=1 -DHAVE_GETCWD=1 -DHAVE_OPENDIR=1 -DHAVE_STRTOL=1 -DHAVE_WAITPID=1 -DHAVE_GETADDRINFO=1 -DHAVE_GETPWUID_R_5=1 -DHAVE_GETPWUID_R=1 -DHAVE_GETPWNAM_R_5=1 -DHAVE_GETPWNAM_R=1 -DHAVE_GETGRGID_R_5=1 -DHAVE_GETGRGID_R=1 -DHAVE_GETGRNAM_R_5=1 -DHAVE_GETGRNAM_R=1 -DHAVE_MTSAFE_GETHOSTBYNAME=1 -DHAVE_MTSAFE_GETHOSTBYADDR=1 -DUSE_TERMIOS=1 -DHAVE_SYS_TIME_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_GMTIME_R=1 -DHAVE_LOCALTIME_R=1 -DHAVE_MKTIME=1 -DHAVE_TM_GMTOFF=1 -DHAVE_TIMEZONE_VAR=1 -DHAVE_STRUCT_STAT_ST_BLOCKS=1 -DHAVE_STRUCT_STAT_ST_BLKSIZE=1 -DHAVE_BLKCNT_T=1 -DHAVE_INTPTR_T=1 -DHAVE_UINTPTR_T=1 -DHAVE_SIGNED_CHAR=1 -DHAVE_LANGINFO=1 -DHAVE_CHFLAGS=1 -DHAVE_GETATTRLIST=1 -DHAVE_COPYFILE_H=1 -DHAVE_COPYFILE=1 -DHAVE_LIBKERN_OSATOMIC_H=1 -DHAVE_OSSPINLOCKLOCK=1 -DHAVE_PTHREAD_ATFORK=1 -DUSE_VFORK=1 -DTCL_DEFAULT_ENCODING=\"utf-8\" -DTCL_LOAD_FROM_MEMORY=1 -DTCL_WIDE_CLICKS=1 -DHAVE_AVAILABILITYMACROS_H=1 -DHAVE_WEAK_IMPORT=1 -D_DARWIN_C_SOURCE=1 -DHAVE_FTS=1 -DHAVE_SYS_IOCTL_H=1 -DHAVE_SYS_FILIO_H=1 -DTCL_UNLOAD_DLLS=1 -DHAVE_CPUID=1 TCL_BIN_DIR = /usr/local/src/tcl8.5.13/unix TCL_SRC_DIR = /usr/local/src/tcl8.5.13 # This is necessary for packages that use private Tcl headers #TCL_TOP_DIR_NATIVE = @TCL_TOP_DIR_NATIVE@ # Not used, but retained for reference of what libs Tcl required TCL_LIBS = ${DL_LIBS} ${LIBS} ${MATH_LIBS} #======================================================================== # TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our # package without installing. The other environment variables allow us # to test against an uninstalled Tcl. Add special env vars that you # require for testing here (like TCLX_LIBRARY). #======================================================================== EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR) TCLSH_ENV = TCL_LIBRARY=`echo $(TCL_SRC_DIR)/library` \ DYLD_LIBRARY_PATH="$(EXTRA_PATH):$(DYLD_LIBRARY_PATH)" \ PATH="$(EXTRA_PATH):$(PATH)" \ TCLLIBPATH="$(top_builddir)" TCLSH_PROG = /usr/local/src/tcl8.5.13/unix/tclsh TCLSH = $(TCLSH_ENV) $(TCLSH_PROG) SHARED_BUILD = 1 INCLUDES = -I/Users/neumann/src/nsf2.0b4/generic -I./generic -I"/usr/local/src/tcl8.5.13/generic" EXTRA_CFLAGS = # TCL_DEFS is not strictly need here, but if you remove it, then you # must make sure that configure.in checks for the necessary components # that your library may use. TCL_DEFS can actually be a problem if # you do not compile with a similar machine setup as the Tcl core was # compiled with. #DEFS = $(TCL_DEFS) -DPACKAGE_NAME=\"xotclsdbm\" -DPACKAGE_TARNAME=\"xotclsdbm\" -DPACKAGE_VERSION=\"1.2\" -DPACKAGE_STRING=\"xotclsdbm\ 1.2\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DNO_VALUES_H=1 -DHAVE_LIMITS_H=1 -DHAVE_SYS_PARAM_H=1 -DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 -D_THREAD_SAFE=1 -DTCL_THREADS=1 -DTCL_WIDE_INT_IS_LONG=1 -DUSE_TCL_STUBS=1 $(EXTRA_CFLAGS) DEFS = -DPACKAGE_NAME=\"xotclsdbm\" -DPACKAGE_TARNAME=\"xotclsdbm\" -DPACKAGE_VERSION=\"1.2\" -DPACKAGE_STRING=\"xotclsdbm\ 1.2\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DNO_VALUES_H=1 -DHAVE_LIMITS_H=1 -DHAVE_SYS_PARAM_H=1 -DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 -D_THREAD_SAFE=1 -DTCL_THREADS=1 -DTCL_WIDE_INT_IS_LONG=1 -DUSE_TCL_STUBS=1 $(EXTRA_CFLAGS) CONFIG_CLEAN_FILES = Makefile CPPFLAGS = LIBS = -L/Users/neumann/src/nsf2.0b4 -lxotclstub1.6.8 -L/Users/neumann/src/nsf2.0b4 -lxotcl1.6.8 AR = ar CFLAGS = -pipe ${CFLAGS_DEFAULT} ${CFLAGS_WARNING} ${SHLIB_CFLAGS} COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) #======================================================================== # Start of user-definable TARGETS section #======================================================================== #======================================================================== # TEA TARGETS. Please note that the "libraries:" target refers to platform # independent files, and the "binaries:" target includes executable programs and # platform-dependent libraries. Modify these targets so that they install # the various pieces of your package. The make and install rules # for the BINARIES that you specified above have already been done. #======================================================================== all: binaries libraries doc #======================================================================== # The binaries target builds executable programs, Windows .dll's, unix # shared/static libraries, and any other platform-dependent files. # The list of targets to build for "binaries:" is specified at the top # of the Makefile, in the "BINARIES" variable. #======================================================================== binaries: $(BINARIES) pkgIndex.tcl libraries: doc: @echo "If you have documentation to create, place the commands to" @echo "build the docs in the 'doc:' target. For example:" @echo " xml2nroff sample.xml > sample.n" @echo " xml2html sample.xml > sample.html" install: all install-binaries install-libraries install-doc install-binaries: binaries install-lib-binaries install-bin-binaries if test "x$(SHARED_BUILD)" = "x1"; then \ $(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir); \ fi #======================================================================== # This rule installs platform-independent files, such as header files. #======================================================================== install-libraries: libraries @mkdir -p $(DESTDIR)$(includedir) @echo "Installing header files in $(DESTDIR)$(includedir)" @if test -n "$(PKG_HEADERS)" ; then \ for i in "$(PKG_HEADERS)" ; do \ echo "Installing $(srcdir)/$$i" ; \ $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir) ; \ done; \ fi #======================================================================== # Install documentation. Unix manpages should go in the $(mandir) # directory. #======================================================================== install-doc: doc #install-doc: doc # @mkdir -p $(DESTDIR)$(mandir)/mann # @echo "Installing documentation in $(DESTDIR)$(mandir)" # @for i in $(srcdir)/doc/*.n; do \ # echo "Installing $$i"; \ # rm -f $(DESTDIR)$(mandir)/mann/`basename $$i`; \ # $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \ # done test: binaries libraries $(TCLSH) `echo $(srcdir)/tests/all.tcl` $(TESTFLAGS) shell: binaries libraries @$(TCLSH) $(SCRIPT) gdb: $(TCLSH_ENV) gdb $(TCLSH_PROG) $(SCRIPT) depend: #======================================================================== # $(PKG_LIB_FILE) should be listed as part of the BINARIES variable # mentioned above. That will ensure that this target is built when you # run "make binaries". # # The $(PKG_OBJECTS) objects are created and linked into the final # library. In most cases these object files will correspond to the # source files above. #======================================================================== $(PKG_LIB_FILE): $(PKG_OBJECTS) -rm -f $(PKG_LIB_FILE) ${MAKE_LIB} $(RANLIB) $(PKG_LIB_FILE) $(PKG_STUB_LIB_FILE): $(PKG_STUB_OBJECTS) -rm -f $(PKG_STUB_LIB_FILE) ${MAKE_STUB_LIB} $(RANLIB_STUB) $(PKG_STUB_LIB_FILE) #======================================================================== # We need to enumerate the list of .c to .o lines here. # # In the following lines, $(srcdir) refers to the toplevel directory # containing your extension. If your sources are in a subdirectory, # you will have to modify the paths to reflect this: # # sample.$(OBJEXT): $(srcdir)/generic/sample.c # $(COMPILE) -c `echo $(srcdir)/generic/sample.c` -o $@ # # Setting the VPATH variable to a list of paths will cause the makefile # to look into these paths when resolving .c to .obj dependencies. # As necessary, add $(srcdir):$(srcdir)/compat:.... #======================================================================== VPATH = $(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win .c.o: $(COMPILE) -c `echo $<` -o $@ #======================================================================== # Create the pkgIndex.tcl file. # It is usually easiest to let Tcl do this for you with pkg_mkIndex, but # you may find that you need to customize the package. If so, either # modify the -hand version, or create a pkgIndex.tcl.in file and have # the configure script output the pkgIndex.tcl by editing configure.in. #======================================================================== #pkgIndex.tcl: # ( echo pkg_mkIndex . $(PKG_LIB_FILE) \; exit; ) | $(TCLSH) pkgIndex.tcl: (echo 'package ifneeded xotcl::store::sdbm $(PACKAGE_VERSION) \ [list load [file join $$dir $(PKG_LIB_FILE)]]'\ ) > pkgIndex.tcl #======================================================================== # Distribution creation # You may need to tweak this target to make it work correctly. #======================================================================== #COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar COMPRESS = gtar zcvf $(PKG_DIR).tar.gz $(PKG_DIR) DIST_ROOT = /tmp/dist DIST_DIR = $(DIST_ROOT)/$(PKG_DIR) dist-clean: rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.* dist: dist-clean mkdir -p $(DIST_DIR) cp -p $(srcdir)/ChangeLog $(srcdir)/README* $(srcdir)/license* \ $(srcdir)/aclocal.m4 $(srcdir)/configure $(srcdir)/*.in \ $(DIST_DIR)/ chmod 664 $(DIST_DIR)/Makefile.in $(DIST_DIR)/aclocal.m4 chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.in cp -p $(srcdir)/*.[ch] $(DIST_DIR)/ mkdir $(DIST_DIR)/tclconfig cp $(srcdir)/tclconfig/install-sh $(srcdir)/tclconfig/tcl.m4 \ $(DIST_DIR)/tclconfig/ chmod 664 $(DIST_DIR)/tclconfig/tcl.m4 chmod +x $(DIST_DIR)/tclconfig/install-sh list='demos doc generic library mac tests unix win'; \ for p in $$list; do \ if test -d $(srcdir)/$$p ; then \ mkdir $(DIST_DIR)/$$p; \ cp -p $(srcdir)/$$p/*.* $(DIST_DIR)/$$p/; \ fi; \ done (cd $(DIST_ROOT); $(COMPRESS);) #======================================================================== # End of user-definable section #======================================================================== #======================================================================== # Don't modify the file to clean here. Instead, set the "CLEANFILES" # variable in configure.in #======================================================================== clean: -test -z "$(BINARIES)" || rm -f $(BINARIES) -rm -f *.$(OBJEXT) core *.core -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean: clean -rm -f *.tab.c -rm -f $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log config.status #======================================================================== # Install binary object libraries. On Windows this includes both .dll and # .lib files. Because the .lib files are not explicitly listed anywhere, # we need to deduce their existence from the .dll file of the same name. # Library files go into the lib directory. # In addition, this will generate the pkgIndex.tcl # file in the install location (assuming it can find a usable tclsh shell) # # You should not have to modify this target. #======================================================================== install-lib-binaries: @mkdir -p $(DESTDIR)$(pkglibdir) @list='$(lib_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p; \ stub=`echo $$p|sed -e "s/.*\(stub\).*/\1/"`; \ if test "x$$stub" = "xstub"; then \ echo " $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p"; \ $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p; \ else \ echo " $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p"; \ $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p; \ fi; \ ext=`echo $$p|sed -e "s/.*\.//"`; \ if test "x$$ext" = "xdll"; then \ lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \ if test -f $$lib; then \ echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \ $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib; \ fi; \ fi; \ fi; \ done @list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ if test -f $(srcdir)/$$p; then \ destp=`basename $$p`; \ echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \ fi; \ done #======================================================================== # Install binary executables (e.g. .exe files and dependent .dll files) # This is for files that must go in the bin directory (located next to # wish and tclsh), like dependent .dll files on Windows. # # You should not have to modify this target, except to define bin_BINARIES # above if necessary. #======================================================================== install-bin-binaries: @mkdir -p $(DESTDIR)$(bindir) @list='$(bin_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \ fi; \ done .SUFFIXES: .c .$(OBJEXT) Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status uninstall-binaries: list='$(lib_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ p=`basename $$p`; \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(bin_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(bindir)/$$p; \ done .PHONY: all binaries clean depend distclean doc install libraries test # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ./nsf2.4.0/dtrace/timestamps.d000644 000766 000024 00000001532 12501766547 017003 0ustar00neumannstaff000000 000000 /* -*- D -*- * * Measure time between method-entry and method-returns * * Activate tracing between * ::nsf::configure dtrace on * and * ::nsf::configure dtrace off * */ nsf*:::configure-probe /!self->tracing && copyinstr(arg0) == "dtrace" / { self->tracing = (arg1 && copyinstr(arg1) == "on") ? 1 : 0; } nsf*:::configure-probe /self->tracing && copyinstr(arg0) == "dtrace" / { self->tracing = (arg1 && copyinstr(arg1) == "off") ? 0 : 1; } /* * Measure time differences */ nsf*:::method-entry /self->tracing/ { self->start = timestamp; } nsf*:::method-return /self->tracing && self->start/ { @[copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)] = avg(timestamp - self->start); self->start = 0; } /* * Print aggregate with own format (less wide than the default) */ END { printa("\n%-35s %-35s %-40s = %@d", @); } ./nsf2.4.0/dtrace/object-create.d000644 000766 000024 00000000246 12501766547 017325 0ustar00neumannstaff000000 000000 /* -*- D -*- * * check, if every object is freed. */ nsf*:::object-alloc { @[copyinstr(arg0)] = sum(1); } nsf*:::object-free { @[copyinstr(arg0)] = sum(-1); } ./nsf2.4.0/dtrace/sample.tcl000644 000766 000024 00000000311 12501766547 016427 0ustar00neumannstaff000000 000000 package require nx ::nsf::configure dtrace on nx::Object create o { :public object method foo {x y} { [self] ::incr x 1 return [expr {$x + $y}] } } o foo 1 2 ::nsf::configure dtrace off ./nsf2.4.0/dtrace/execution-flow-args.d000644 000766 000024 00000005306 12501766547 020522 0ustar00neumannstaff000000 000000 /* -*- D -*- * * Execution flow trace with arguments * * Activate tracing between * ::nsf::configure dtrace on * and * ::nsf::configure dtrace off * * Since this D script accesses the C data structures it is sensitive * to the representation sizes of the data structures (e.g. pointers). * Make sure to call the script with the appropriate architecture flag * on Mac OS X; on SunOS, there is apparently a -32 or -64 flag. * * Example: * * sudo dtrace -arch x86_64 -x bufsize=20m -F -s dtrace/execution-flow-args.d \ * -c "./nxsh dtrace/sample.tcl" * * -gustaf neumann */ enum {maxstrlen = 50}; /* * Needed data structures to access the content of Tcl_Objs. */ typedef struct Tcl_Obj Tcl_Obj; typedef struct Tcl_ObjType { char *name; void *freeIntRepProc; void *dupIntRepProc; void *updateStringProc; void *setFromAnyProc; } Tcl_ObjType; struct Tcl_Obj { int refCount; char *bytes; int length; Tcl_ObjType *typePtr; union { long longValue; double doubleValue; void *otherValuePtr; int64_t wideValue; struct { void *ptr1; void *ptr2; } twoPtrValue; struct { void *ptr; unsigned long value; } ptrAndLongRep; } internalRep; }; /* * Handling "nsf::configure dtrace on|off". */ nsf*:::configure-probe /!self->tracing && copyinstr(arg0) == "dtrace" / { self->tracing = (arg1 && copyinstr(arg1) == "on") ? 1 : 0; } nsf*:::configure-probe /self->tracing && copyinstr(arg0) == "dtrace" / { self->tracing = (arg1 && copyinstr(arg1) == "off") ? 0 : 1; } /* * Output object, class, method, number of arguments and first two * arguments upon method invocation. */ nsf*:::method-entry /self->tracing/ { this->objv = arg3 ? ((Tcl_Obj**)copyin((user_addr_t)((Tcl_Obj**)arg4), sizeof(Tcl_Obj*) * arg3)) : NULL; this->i = 0; this->o = arg3 > this->i && *(this->objv + this->i) ? (Tcl_Obj*)copyin((user_addr_t)*(this->objv + this->i), sizeof(Tcl_Obj)) : NULL; this->s0 = this->o ? (this->o->bytes ? copyinstr((user_addr_t)this->o->bytes, maxstrlen) : lltostr(this->o->internalRep.longValue)) : ""; this->i = 1; this->o = arg3 > this->i && *(this->objv + this->i) ? (Tcl_Obj*)copyin((user_addr_t)*(this->objv + this->i), sizeof(Tcl_Obj)) : NULL; this->s1 = this->o ? (this->o->bytes ? copyinstr((user_addr_t)this->o->bytes, maxstrlen) : lltostr(this->o->internalRep.longValue)) : ""; printf("%s %s.%s (%d) %s %s", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3, this->s0, this->s1); } /* * Output object, class, method and return code upon method return. */ nsf*:::method-return /self->tracing/ { printf("%s %s.%s -> %d", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); } ./nsf2.4.0/dtrace/timestamps-q.d000644 000766 000024 00000001471 12501766547 017243 0ustar00neumannstaff000000 000000 /* -*- D -*- * * Quantize time between method-entry and method-returns for calls on ::nx::Object * * Activate tracing between * ::nsf::configure dtrace on * and * ::nsf::configure dtrace off * */ nsf*:::configure-probe /!self->tracing && copyinstr(arg0) == "dtrace" / { self->tracing = (arg1 && copyinstr(arg1) == "on") ? 1 : 0; } nsf*:::configure-probe /self->tracing && copyinstr(arg0) == "dtrace" / { self->tracing = (arg1 && copyinstr(arg1) == "off") ? 0 : 1; } /* * Measure time differences */ nsf*:::method-entry /self->tracing && copyinstr(arg1) == "::nx::Object"/ { self->start = timestamp; } nsf*:::method-return /self->tracing && copyinstr(arg1) == "::nx::Object" && self->start/ { @[copyinstr(arg1), copyinstr(arg2)] = quantize(timestamp - self->start); self->start = 0; } ./nsf2.4.0/dtrace/README000644 000766 000024 00000014725 13322632446 015330 0ustar00neumannstaff000000 000000 DTrace provider for the Next Scripting Language This is an implementation of a DTrace provider for the Next Scripting Language (NSF). The NSF provider is designed to be used with and without the DTrace support for Tcl. Therefore, NSF can be configured with --with-dtrace also in cases where Tcl was compiled without it. To enable DTrace, run configure with the flag --with-dtrace configure flag. The DTrace support for NSF was developed under macOS, other platforms might require some fine tuning to get it running. Please report improvements back to the NSF developers. In macOS version including System Integrity Protection (SIP), one must deactivate SIP for DTrace, first: 1) Boot into Recovery OS 2) Open Terminal 3) Run: "csrutil disable" 4) Run: "csrutil enable --without dtrace" Once SIP has been disarmed, and once DTrace support is compiled into NSF, one can run D scripts like so: 1) (Terminal window 1): sudo dtrace -q -F -s dtrace/timestamps.d -W tclsh 2) (Terminal window 2): ./nxsh dtrace/sample.tcl (Note: The "dtrace -c" option, as shown below, is not operative unless SIP is fully disabled: Run "csrutil disable" only, omit the fourth step.) DTrace requires normally that the dtrace command is run with root permissions. In case the provided sample scrips in the dtrace directory don't work out of the box, the following hints might help: * Make sure that a "package require nx" works for root as well (install nx, or provide a TCLLIBPATH, etc.). You might want to add e.g. the following line set auto_path [concat . $auto_path] to the begin of the nxsh script, or add the path to the dtrace invocation (see below) * If dtrace compilation fails (e.g. "... nsf*:::method-entry does not match any probes"), start an nxsh in a different window to make the nsf provider and the probes known to the kernel. -gustaf neumann Examples % sudo TCLLIBPATH=. dtrace -arch x86_64 -x bufsize=20m -F -s dtrace/execution-flow.d -c "./nxsh dtrace/sample.tcl" dtrace: script 'dtrace/execution-flow.d' matched 8 probes dtrace: pid 65393 has exited CPU FUNCTION 0 -> MethodDispatchCsc ::nx::Object ::nx::Class.create (2) 0 -> MethodDispatchCsc ::o ::nx::Object.public (4) 0 -> MethodDispatchCsc ::o ::nx::Object.method (3) 0 -> MethodDispatchCsc ::o ::nx::Object.__resolve_method_path (2) 0 <- ObjectDispatch ::o ::nx::Object.__resolve_method_path -> 0 0 -> MethodDispatchCsc ::o ::nx::Object.__default_method_call_protection (0) 0 <- ObjectDispatch ::o ::nx::Object.__default_method_call_protection -> 0 0 <- ObjectDispatch ::o ::nx::Object.method -> 0 0 <- ObjectDispatch ::o ::nx::Object.public -> 0 0 -> MethodDispatchCsc ::o ::nx::Object.init (0) 0 <- ObjectDispatch ::o ::nx::Object.init -> 0 0 <- ObjectDispatch ::nx::Object ::nx::Class.create -> 0 0 -> MethodDispatchCsc ::o ::o.foo (2) 0 -> MethodDispatchCsc ::o ::o.::incr (2) 0 <- ObjectDispatch ::o ::o.::incr -> 0 0 <- ObjectDispatch ::o ::o.foo -> 0 % sudo TCLLIBPATH=. dtrace -arch x86_64 -x bufsize=20m -F -s dtrace/execution-flow-args.d -c "./nxsh dtrace/sample.tcl" dtrace: script 'dtrace/execution-flow-args.d' matched 8 probes dtrace: pid 65419 has exited CPU FUNCTION 1 -> MethodDispatchCsc ::nx::Object ::nx::Class.create (2) o :public method foo {x y} { [self] ::incr x 1 -> MethodDispatchCsc ::o ::nx::Object.public (4) method foo 1 -> MethodDispatchCsc ::o ::nx::Object.method (3) foo x y 1 -> MethodDispatchCsc ::o ::nx::Object.__resolve_method_path (2) -per-object foo 1 <- ObjectDispatch ::o ::nx::Object.__resolve_method_path -> 0 1 -> MethodDispatchCsc ::o ::nx::Object.__default_method_call_protection (0) 1 <- ObjectDispatch ::o ::nx::Object.__default_method_call_protection -> 0 1 <- ObjectDispatch ::o ::nx::Object.method -> 0 1 <- ObjectDispatch ::o ::nx::Object.public -> 0 1 -> MethodDispatchCsc ::o ::nx::Object.init (0) 1 <- ObjectDispatch ::o ::nx::Object.init -> 0 1 <- ObjectDispatch ::nx::Object ::nx::Class.create -> 0 1 -> MethodDispatchCsc ::o ::o.foo (2) 1 2 1 -> MethodDispatchCsc ::o ::o.::incr (2) x 1 1 <- ObjectDispatch ::o ::o.::incr -> 0 1 <- ObjectDispatch ::o ::o.foo -> 0 % sudo TCLLIBPATH=. dtrace F -s dtrace/timestamps.d -c "./nxsh tests/object-system.test" CPU FUNCTION 0 | :END ::C ::C class = 4249 ::M ::M class = 4347 ::o ::o class = 4435 ::m2 ::m2 class = 4444 ::M2 ::M2 class = 4462 ::C0 ::C0 class = 4501 ::c1 ::c1 class = 4611 .... % sudo TCLLIBPATH=. dtrace -F -s dtrace/timestamps-q.d -c "./nxsh tests/object-system.test" .... ::nx::Object info value ------------- Distribution ------------- count 4096 | 0 8192 |@@@@@@@@@@@@@@@@@@@@@@@@@ 16 16384 |@@@@@@@@@@@@@@@ 10 32768 | 0 ::nx::Object objectparameter value ------------- Distribution ------------- count 32768 | 0 65536 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 4 131072 |@@@@@@@@ 1 262144 | 0 ./nsf2.4.0/dtrace/nsf_calltime.d000644 000766 000024 00000010757 13244511101 017241 0ustar00neumannstaff000000 000000 /* -*- D -*- * * nsf_calltime.d -- * * Measure time between method-entry and method-returns * * Activate tracing between * ::nsf::configure dtrace on * and * ::nsf::configure dtrace off * * FIELDS: * PROVIDER Object/class providing the method called. * SCOPE Scope for which the method called is provided (per-class, per-object, direct) * NAME Name of called method * TOTAL Total count of calls or elapsed time for calls (us) * * Copyright (c) 2018 Stefan Sobernig * * Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License http://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * Based on https://github.com/opendtrace/toolkit/blob/master/Tcl/tcl_calltime.d * * COPYRIGHT: Copyright (c) 2007 Brendan Gregg. * * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at Docs/cddl1.txt * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * CDDL HEADER END * * 09-Sep-2007 Brendan Gregg Created this. */ dtrace:::BEGIN { printf("Tracing... Hit Ctrl-C to end.\n"); top = 20; } nsf*:::configure-probe /!self->tracing && copyinstr(arg0) == "dtrace" / { self->tracing = (arg1 && copyinstr(arg1) == "on") ? 1 : 0; } nsf*:::configure-probe /self->tracing && copyinstr(arg0) == "dtrace" / { self->tracing = (arg1 && copyinstr(arg1) == "off") ? 0 : 1; } /* * Measure time differences */ nsf*:::method-entry /self->tracing/ { self->depth++; self->exclude[self->depth] = 0; self->proc[self->depth] = timestamp; } nsf*:::method-return /self->tracing && self->proc[self->depth] / { this->elapsed_incl = timestamp - self->proc[self->depth]; this->elapsed_excl = this->elapsed_incl - self->exclude[self->depth]; self->proc[self->depth] = 0; self->exclude[self->depth] = 0; this->name = copyinstr(arg2); this->scope = (copyinstr(arg1) != "") ? ((copyinstr(arg0) == copyinstr(arg1)) ? "object" : "class") : "direct"; @num[copyinstr(arg1), this->scope, this->name] = count(); @num["", "total", "-"] = count(); @types_incl[copyinstr(arg0), this->scope, this->name] = sum(this->elapsed_incl); @types_excl[copyinstr(arg0), this->scope, this->name] = sum(this->elapsed_excl); @types_excl["", "total", "-"] = sum(this->elapsed_excl); self->depth--; self->exclude[self->depth] += this->elapsed_incl; } /* * Print aggregate with own format (less wide than the default) */ END { trunc(@num, top); printf("\nTop %d counts,\n", top); printf(" %48s %-10s %-48s %8s\n", "PROVIDER", "SCOPE", "NAME", "COUNT"); printa(" %48s %-10s %-48s %@8d\n", @num); trunc(@types_excl, top); normalize(@types_excl, 1000); printf("\nTop %d exclusive elapsed times (us),\n", top); printf(" %48s %-10s %-48s %8s\n", "PROVIDER", "SCOPE", "NAME", "TOTAL"); printa(" %48s %-10s %-48s %@8d\n", @types_excl); trunc(@types_incl, top); normalize(@types_incl, 1000); printf("\nTop %d inclusive elapsed times (us),\n", top); printf(" %48s %-10s %-48s %8s\n", "PROVIDER", "SCOPE", "NAME", "TOTAL"); printa(" %48s %-10s %-48s %@8d\n", @types_incl); } ./nsf2.4.0/dtrace/execution-flow.d000644 000766 000024 00000001556 12501766547 017573 0ustar00neumannstaff000000 000000 /* -*- D -*- * * Execution flow trace without arguments * * Activate tracing between * ::nsf::configure dtrace on * and * ::nsf::configure dtrace off * */ nsf*:::configure-probe /!self->tracing && copyinstr(arg0) == "dtrace" / { self->tracing = (arg1 && copyinstr(arg1) == "on") ? 1 : 0; } nsf*:::configure-probe /self->tracing && copyinstr(arg0) == "dtrace" / { self->tracing = (arg1 && copyinstr(arg1) == "off") ? 0 : 1; } /* * Output object, class, method and number of arguments upon method * invocation. */ nsf*:::method-entry /self->tracing/ { printf("%s %s.%s (%d)", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); } /* * Output object, class, method and return code upon method return. */ nsf*:::method-return /self->tracing/ { printf("%s %s.%s -> %d", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); } ./nsf2.4.0/README000644 000766 000024 00000000455 13322633617 014062 0ustar00neumannstaff000000 000000 # Next Scripting Framework # ## Compilation of Source Distribution: ## On Unix-like environments (including macOS), do ```` ./configure make sudo make install ````` For more details, and build instructions, binary releases, community support etc. consult: http://next-scripting.org/ ./nsf2.4.0/TODO000644 000766 000024 00000757050 13445201105 013671 0ustar00neumannstaff000000 000000 # This file is similar to a weblog an shows activities and certain # discussions during the development of the next scripting framework, # starting around march 2008. we keep it as a potential source for # explaining development, changes and chosen design options. # # The actual todos start in the line with the string "TODO:" # <- handle change in tcl 8.5.8: http://tcl.cvs.sourceforge.net/viewvc/tcl/tcl/generic/tclObj.c?sortby=date&r1=1.139.2.1&r2=1.139.2.2&pathrev=core-8-5-branch in xotcl: * when e.g. the parent namespace is deleted with a "namespace delete", the change above causes, the no xotcl methods could be resolved (and called) anymore. * therefore, e.g. a "C dealloc c1" did not work, since dealloc passes c1 via tcl_obj, and the tcl_obj is as well converted to an xotcl object via Tcl_GetCommandFromObj(), which fails as well. - to bypass this problem, xotcl has now a C-function DoDealloc(), which is called, when this situation is detected. - some more cases, where xotcl could reference already freed memory were fixed (thanks to enable-symbols=mem) - as collateral damage, parts of the regression test don't work currently - added refcounting in ObjectDispatch() to make sure, obj survives until the end of the function - added existence test for slot extractor (needed for 8.5.8) - added refcounting CallStackDoDestroy() to ensure existence of object until end of function - make sure to call PrimitiveDestroy() before DeleteCommandFromToken(), otherwise e.g. unset traces on this object cannot be executed - regression test works again - get rid of rst->deallocCalled (not needed due to reference counting on xotcl objects) - reduce verbosity - reactivated XOTclErrInProc() - renamed "ClassName info instmixinof ?-closure? ?pattern?" into "ClassName info class-mixin-of ?-closure? ?pattern?" - renamed "ClassName info mixinof ?-closure? ?pattern?" into "ClassName info object-mixin-of ?-closure? ?pattern?" - added emulation "ClassName info instmixinof|mixinof" for xotcl1 - update to TEA 3.7 (from TEA 3.5) - use of INT2PTR to avoid warnings about different sizes on 64bit architectures - defined HAVE_INTPTR_T as a macro to make definition of INT2PTR working - use INT2PTR and PTR2INT macros in generated stubs - handle HAVE_UINTPTR_T like HAVE_INTPTR_T - use ::xotcl::setinstvar instead of ::xotcl::setinstvar in serializer - change and rename cmd instvar ::xotcl::instvar -object someObject newVar into ::xotcl::importvar someObject newVar Rationale of change: only needed in xotcl2 for importing variables from different objects - changed assertions: old (xotcl1) interface: 3 methods + 3 info methods * check Options * info check * invar Conditions * info invar * instinvar Conditions * info instinvar new (xotcl2) interface: 1 cmd (similar to ::xotcl::relation) ::xotcl::assertion check|object-invar|class-invar ?arg? - added emulation for xotcl1 - deleted name-specific C macros: isInfoString, isInstinvarString, isInvarString, isInstprocString, isProcString - made some more xotcl2 methods protected (no big need to call these from different objects): unknown, uplevel, upvar - added ::xotcl::exists as cmd - added ::xotcl::method as cmd instead of methods object-method and class-method - added ::xotcl::forward as cmd instead of method now, all method-defining-methods (alias, method, forward, setter) are defined as cmds (this should make life of serializer easier) - moved "-per-object" consequently immediately after obj in the following commands : ::xotcl::alias, ::xotcl::methodproperty, ::xotcl::setter to achieve conformance with ::xotcl::forward and ::xotcl::method -per-object nach methodName: vor methodName: alias forward method methodproperty setter - added experimental flag for alias "-noleaf" to force a stack frame to be written (e.g. necessary for "next"). makes only sense for aliases to c-implemented cmds - fix inconsistent behaviour of dotVarResolver "o eval {set .x 1}" was setting var ".x" instead of "x" The problem was due to a interaction between the namespace varResolver() and the DotVarResolver() - fix for DotCmdResolver during compilation of a proc by Tcl. - extended regression text - found 2 potential bugs (not fixed yet) - fix eval method with requirenamespace - removed dependency on proc/instproc in copy/move. code is now independent of class system - changed results of "filtersearch" and "self next" to new naming Caveat: for xotcl1, there is no mapping for the names to the old style in "self next" and "self filterreg" - backwards compatible mapping of filtersearch in xotcl1 - removed XOTclInstVar from the C-level API. still todo add all xotcl*cmds to C api, including importvar - removed all unreferenced entries from XOTE_* - regrouped XOTE_* for easier comprehension - used XOTE_* on more occasions - used XOTclCallCommand() for calling Tcl "format" and "interp" - added option "arg=.." to parameter options; this argument can be passed to converter; used currently for "type=relation" to flag, that the relation type is different from the parameter name - extended "objectparameter" to handle such cases - removed relationtypes "mixin", "filter", "instfilter" and "instmixin" since not needed due to converterArg - xotcl.c: removed all names starting with "inst" (exception: instvar) - added option "-application" to "info callable" to omit methods from base classes - extended regression test - changed naming of methodtype "system" to "builtin" - added "info methods" to migration guide - added "info method" to migration guide - modernize test a little: all local definitions of proc "?" are gone. - added interface to test: "Test parameter count SOMEVALUE" to specify conveniently e.g. the number of tests the be executed - add XOTCL_CM_NO_UNKNOWN to dispatch of defaultmethod - added option "objectsystems" to ::xotcl::configure to obtain the currently defined object systems - added option "baseclass" to ::xotcl::is to check, whether a class is a baseclass of an object system (root class or root meta-class of object system) - changed result of "... info methods -methodtype scripted" to return only truly scripted methods (no aliases) - some more cleanup in regression tests - first version of serializer for xotcl1 + xotcl2 - serializer: move checking of the requested objects to be exported to the invocation of "Serializer all" - replace "namespace import ::xotcl::*" by "xotcl::use xotcl1" - make allocation sizes for dynamically allocated parameterContexts consistent between alloc and realloc - added sanity check in getAllClassMixinsOf() It seems as it would be possible with __defaultSupeclass to define a class which has itself als a subclass. Just a quick fix, we have investigate more on this. - improved naming of resolvers: use InterpDot*Resolver and NsDot*Resolver for interp wide and namespace specific resolvers - added possibility to escape the call of commands starting with a dot from method bodies by prefixing with a second dot. - make sure to have an xotcl frame pushed, when byte-code-compiler is invoked. This is necessary for providing the context for dotCmd resolvers - use uplevel in slot add/delete to evaluate in calling namespace (for not fully qualified object names) - determine namespace in test method "?" to allow its execution in an "namespace eval" - added regression tests - NsDotVarResolver: don't create variables on CMETHOD frames when their names do not start with a "." - general overhaul of XOTcl_PushFrame()XOTcl_PopFrame(): new functions: * XOTcl_PushFrameCsc()/XOTcl_PopFrameCsc(): for CMETHOD fames * XOTcl_PushFrameObj()/XOTcl_PopFrameObj(): for OBJECT frames (objscope) - preallocate obj->vartable in XOTcl_PushFrameObj() to avoid situations where to non-existing vartable is created on demand at different places (e.g. on stack and in var resolver) - caller of convertToRelationtype(): make sure that last argument keeping the result is large enough to held pointer (in case of sizeof(void) != sizeof(int) - Serializer: include ObjectSystemSerializer in "Serializer all" - Serializer: use class-mixin in dependency order - Serializer: add appropriate "::xotcl::use xotcl1|xotcl2" - Serializer: fix syntax in exportMethods - Serializer: provide limited support for exporting aliases for xotcl1 objects - add calltype to tcl85showStack - keep orignial objc/objc in call stack context such that next/self args works with canonical args (allow e.g. different order of nonpos args in a next) - make naming in xotcl.c more consistent - ensure to return empty, when "info callable -which" fails - extend regression test - exithandler is different in xotcl2 -> comment, check OpenACS - ensure relation filter/instfilter etc. mit guards - extended migration guide - defined eval in predefined via "-nonleaf", used at various places - added "info mixinof ?-scope all|object|class? ?pattern?", dropped "object-mixin-of" and "class-mixin-on" from registered method - extended regression test - xotcl1: make "-volatile" invoked via unknown behave correctly - provide minimal xotcl2 compatibility - added non positional parameter "type" to "get_parameter" - removed "required" from parameters, which is in XOTcl 1 just a comment - minor cleanup - experimental change of resolver name prefix char from dot to single colon - making methodDefinitions NULL terminated - passing optional arg to user-defined argument converter - refuse to redefine type converters for a single parameter - adding regression test for parameters - added instance variable arg for interfacing with parameter interface. "arg" acts like a clientdata for type converter - added multiple parameter options handling to method "parameter" to obtain similar functionality from object parameters as from method parameters - added convenience method "??" to test to indicated test that should fail with an error - added severity type converters to achieve same object type checking as in ::xotcl::is (these are currently in the regression test, should move finally into predefined.xotcl) - extended regression test - new function ::xotcl::parameterFromSlot (used in argument checker as well) - use ::xotcl::forward in Slot constructor (instead of dispatch) - checking methods on slots for single- and multivalued slots (can be optimized) - extended regression test - don't run multiple queries in "??" - fixed last changes to regression test as usual - added "multivalued" to parameter options - made error message produced by XOTclObjErrType look like Tcl's error messages - extended regression test - test utility: changed "?" to return error msg in case of error - checking multivalued types in "-parameters" by using argument checker - some cleanup - extend regression test valuecheck.001: 5.27 mms, ::xotcl::valuecheck object o1 valuecheck.002: ::xotcl::valuecheck object 1 ok valuecheck.003: 3.06 mms, ::xotcl::is o1 object - new cmd "::xotcl::valuecheck " where "valueConstraints" is whatever is allowed in e.g. parameters (including user defined types) - new Tcl_ObjType "xotclParam" - parameterFromSlot returns now pair object-param & method-param - define disallowed parameter options for object parameter, method parameter and value-check command - make canonical table of parameter options (currently in tests/parameter.xotcl) - extend regression test - systematic checking, what value constraints should be allowed/not allowed in valuecheck - pass arg from objectparameter as first argument to objparms (similar to client data) - support for parameter spec of form "type=XXX" to denote that the parameter must be an object of the specified type (class; directly or indirectly) - new built-in converter: convertToObjectOfType() - keep parameterObj (source for conversion to XOTclParam) for making introspection less work. However, this is only used for XOTclParams generated via ParamParse(). - extending regression test - name XOTclObjects always "object" instead of "obj" to avoid potential confusion with Tcl_Objs - remove unneeded push and pop operations in ListChildren() and ObjectHasChildren() - allow syntax "object,type=::SomeClass" and "class,type=::SomeMetaClass" (currently identical, we should as well check for class/meta-class in case of "class,type=SomeClass") - define everything concerning basic slot setup in a single "namespace eval ::xotcl {...}" - undefine ::xotcl::createBootstrapAttributeSlots after this block - fix default DefaultSuperClass() with isMeta==1 in cases, where we are already at the root meta class - use "-parameter" in xotcl1 instead of createBootstrapAttributeSlots - cleanup of legacy stuff in slot management. * merged InfoSlot and InterceptorSlot into RelationSlot * get rid of legacy "mixin set ...." command - renamed "parameterSlot" into "methodParameterSlot" to avoid potential confusions - refactor Slot class hierarchy - new methods in ObjectParameterSlot "toParameterSyntax" and "createFromParameterSyntax" - some more cleanup - removed legacy syntax for "-parmeters" - moved slot optimizer from ::xotcl::ObjectParameterSlot::Optimizer to ::xotcl::Attribute::Optimizer - support for all string constraints provided by "string is ... $value" in object and method parameters ("alum", "alpha", ..., "xdigit"). Technically, these types are tclobjs (using converter convertToTclobj) having pParm->converterArg set to the constraints. - extended regression test - get rid of convertToObjectOfType(), make convertToClass() and converterToObject() more general, accepting type constraints - predefined.xotcl: move toParameterSyntax and objectparameter to a position, where basic slot definitions are provided - fixed default value setting in bootstrap code - provide more precise error message in converter, when object type are used - extend regression test - added error message when substdefault is specified without a default value - extend regression test - added parameter option slot= to pass slotobj to a certain parameter - use slot option to keep relation between parameter and slot - object parameter dispatch type checker on slot objects - allow transformation via user-defined converter (can be use to standardize parameter values) experimental implementation, refcounting has to be looked in detail, maybe we need a different interface for the converters - provide checker-methods for -> objectParameter -> methodParameter - slotobject specific checker-methods - treat currently unknown converters in valuecheckcmd as error - fix the regression test from the last changes - added argument for converter to return the converted tcl_obj, which should be passed on (currently only used for viaCmd); this way, we could remove the kludge of querying the converter after the conversion for special handling. - handle multivalued + values converted viaCmd converter the new output list is only built when needed via ArgumentCheckHelper() - fix counter initialization in ::xotcl::importvar - register alternate "new" method in "contains" for xotcl2 and (if available) for xotcl1 objects - provide error message for cases, where parameter options are not allowed (or ignored) - move methodParameter checkers for "mixin", "baseclass" and "metaclass" to predefined. - deactivated checkMethods in gentclAPI.decls and in xotcl.c - renamed "::xotcl::is ... mixin ..." to "::xotcl::is ... hasmixin ..." (effects parametertypes as well) - made error messages for failed conversions more consistent (note that tcl does not provide the parameter name in the error message, but user-defined converters do) - fixed valuecheck in connection with modifying converters - extended regression test - fixed compilation for tcl 8.6b1 - Allowed parameter specification for setters. One can define now a setter with constraints like e.g. ::xotcl::setter o a:integer to define a setter named "a" for object "o" which has to be integer. - Extended regression test - Followed naming conventions for several structures - setterCmd(): Do not allow methodNames start with "-" - setterCmd(): Do not allow defaults for setters - extend regression test - removed duplicate error message in "hasmixin" converter - fixed refcounting in converting user-types in case of errors - extended regression test - added a "-nocomplain" option to ::xotcl::valuecheck - changed semantic of ::xotcl::valuecheck: per default, valuecheck raises an error or returns true. If "-nocomplain" is used, valuecheck returns 0 or 1 like implemented befor this change - extended regression test - added parameter "incremental" to ::xotcl::Attribute: when set, one can use "object paramname add|delete $value" etc. - use setters with parameter constraints in slot optimizer - as a consequence, setting attributes via slot names is about twice as fast as before, when parameter constraints are used. - extended regression test - fixed returned method name when setter was used on objects - reduce verbosity - implemented "info method definition|parameter|args $name" for settercmds (with parameter constraints) - extended regression test - fixed result resetting for user defined converters - ::xotcl::valuecheck: moved "-nocomplain" to first position (similar to e.g. unset) - experimental: allow to shadow built-in types provided that a) slot= is specified explicitly, and b) the specified slot is not the default slot. This should guarantee that we do not interfere with the predefined converters for the c-level interface. - incremented ref count on results of all-level converter - extended regression test - new methods for MetaSlot to factor out common code: + slotName (to ease name-construction, care about slot container) + createFromParameterSyntax: essentially move from ::xotcl::Attribute to the meta class - test environment: make sure to avoid confusions between the "namespace" method and command - added a version of the "attribute" method to predefined - removed the following classes and methods ::xotcl::Attribute->check_single_value ::xotcl::Attribute->check_multiple_values ::xotcl::Attribute->mk_type_checker class ::xotcl::Attribute::Nocheck - centralize fetching of tcl-obj-types in xotcl_init - support for method modifier "object", "protected" and "public" for method "attribute". One can use now e.g. Class create C { :attribute a :public attribute b :protected attribute c :object attribute A :public object attribute B :protected object attribute C } "protected" and "public" refers to the registered accessor functions - experimental checking function ::xotcl::is2 implemented, which generalizes between ::xotcl::is and ::xotcl::valuecheck (it is a valuecheck -nocomplain with an ::xotcl::is syntax and switched arguments) - Unified on c-level "info class-mixin-of" and "info object-mixin-of" to "info mixinof ?-scope all|object|class? ?-closure? ?pattern? The former "info class-mixin-of" is now "info mixinof -scope class" - adapted xotcl1 layer for this change - extended experimental ::xotcl::is2 to handle flags -type and -hasmixin ::xotcl::is2 object ?-type ? ?-hasmixin ? - renamed old "xotcl::is" -> "xotcl::objectproperty" - renamed old "xotcl::is2" -> "xotcl::is" - we have now is tests for objects in ::xotcl::objectproperty ::xotcl::objectproperty $obj object ::xotcl::objectproperty $obj class ::xotcl::objectproperty $obj baseclass ::xotcl::objectproperty $obj metaclass ::xotcl::objectproperty $obj type XXXX ::xotcl::objectproperty $obj hasmixin XXXX - "::xotcl::is" is the higher level command, supporting string constraints "e.g. upper", user defined type checkers and as well object properties (every parameter type supported for object and method parameter). Examples: ::xotcl::is $obj object ?-type $type? ?-hasmixin $mixin? ::xotcl::is $cl class ?-type $type? ?-hasmixin $mixin? ::xotcl::is obj metaclass ::xotcl::is $num integer ::xotcl::is $string upper - implemented 2nd level reference counting for paramObjType - defined "info is" as alias of "::xotcl::objectproperty" - renamed ::xotcl::valuecheck -> ::xotcl::parametercheck - replaced in predefined occurrences of ::xotcl::is by ::xotcl::objectproperty - fixed namespace handling on stack for objects with namespaces (before, it was possible that a variable was created in an object's namespace without -objscope) - as a consequence, ListChildren() had to be adjusted, since it depended on the previous namespace handling on the stack - fixed object resolving in NsDotVarResolver() (before, it was possible that NsDotVarResolver could create variables in the wrong namespace) - simplified NsDotVarResolver() - more cleanup in name resolver * USE_DOT is gone * XOTclDotDotCmd() removed * improved performance of InterpCompiledDotVarResolver() * made LookupVarFromTable() obsolete and removed it * renamed DotVarResolver() and friends to ColonVarResolver() etc. - extended regression test - call XOTclObject always "object" instead of "obj" - initcmd: use for initcmds CMETHOD frames instead of OBJECT stack frames - initcmd: skip parent-stack frame's objscope for initcmd - changed hash-based lookup of children into a cmd-based lookup - extended regression test - cleanup in stack handlers (naming, arguments) - XOTclCallStackFindLastInvocation(): return last scripted invocation - use xotcl1 in webserver test to make rull regression test working - make xotcl::use silent - added option "-nonleaf" for method alias - added introspection (for "info method definition") for "alias ... -nonleaf ..." - removed obsolete ::xotcl::configure option "cacheinterface" - removed XOTclCreateClass() and XOTclDeleteClass(); both are identical with XOTclCreateObject() and XOTclDeleteObject() - renaming of instance variable specific primitiva for more consistency with ::xotcl::importvar: ::xotcl::exists -> ::xotcl::existsvar ::xotcl::setinstvar -> ::xotcl::setvar - requireNameSpace: * fix potential crash in requireNameSpace in objscoped methods by swapping all vartable references in objscopes on stack to the vartable in the namespace, when it is created - extending regression test - working towards KEEP_VARS_IN_CMETHOD_FRAME - enable compilation with assertion turned on (via NDEBUG) - fix potentially uninitialized flags for ArgumentCheck() - some further cleanup, tested with 32 bit under Mac OS X 10.6 - removed obsolete generic/xotclAppInit.c - changed loading method in xotclsh from Xotcl_Init() to Tcl_PkgRequire() - updating tcl.m4 to the actual version (TEA 3.7) - minor cleanup (varresolution test and comment) - defined "xotcl::current" as synonym for "::xotcl::self" - new options for ::xotcl::current current object == current current method == current proc current callingmethod == current callingproc - "self proc" and friends are for backward compatibility for xotcl1, "current method" and friends are for xotcl2 - namespace exported "::xotcl::current" - use "::xotcl::current" instead of "xotcl::self" in predefined - use "CONST char *" in generated interface and below - further cleanup using "CONST char *" - remove dependency from xotcl1 in handling of forwarders in method "copy" - further cleanup using "CONST char *", improving on naming conventions - added an experimental "info frame" handler, which appends "object" and "class" pairs - fixed wrong name for per-object filter in RelationSlot - fixed condition in filter-invocation to top-level frames - added frametype to information returned by "info frame" - change frametype in "info frame" form bit-pattern to symbolic names - use a more recent version of unix/tclAppInit.c - fix syntax in predefined - let serializer call "init" of attributes, even if it is protected - fixing "-parameter" with empty content - more variable naming cleanup - fix line breaking in serializer for "exportedObjects" - call c-implemented methods directly, when this is safe (implemented for XOTE_ALLOC, XOTE_CLEANUP, XOTE_CONFIGURE, XOTE_CREATE, XOTE_DEALLOC); this improves create/destroy speed by up to 15% - allocate namespaces for objects less eager - make naming more consistent (change newObj into newObject when variable is an xotcl object) - get rid of misleading RCS: lines - passing --prefix to subdirs - regenerated configure files - added stefan's expat library linking extension - define RecreateObject() for internal call via direct invocation - doCleanup is just called by recreate; merge it into XOTclCRecreateMethod. Is method cleanup necessary? is recreate not sufficient? Delete "cleanup" from internally called methods in next, keep it for compatibility in XOTcl - make XOTcl_FrameDecls transparent (use variable declarations in place instead of the macro) - fix variable shadowing bug in error handling (could cause crashes when initcmd lead to errors) - call all truly essential methods directly if possible (Object.destroy, Class.alloc, Class.dealloc, Class.create) The basics of XOTcl can work now also in cases, when these are not defined as methods. - handling OBJECT-frames in CallStackPopAll() (for handling exit with active stack frames) - deactivate filters in finalize - new method InvokeMethodObj() to replace finally CanInvokeDirectly() - remove some more obsolete RCS Ids - call Tcl_Objs "Obj", not "Object" - replace all CanInvokeDirectly() by InvokeMethodObj() - block call-stack deletes during XOTCL_EXITHANDLER_ON_SOFT_DESTROY; however, this seems to create a small leak during exit (relevant for threads); so currently, debug still turned on - fix last issue, with freeing objects, when exit happens from higher stack frames - first part of allowing arbitrary named internally called methods. - move refcount fixing logic for exit from higher stack-frames to new function: finalObjectDeletion() - created new functions: ObjectSystemFree(), ObjectSystemAdd(), ObjectSystemsCheckSystemMethod(), ObjectSystemsCleanup(), GetObjectSystem(), CallDirectly() for better separation of systems. We keep track which essential system methods are defined and which which methods are potentially overloaded. - replaced hard-coded method calls for XOTE_DEFAULTMETHOD, XOTE_INIT, XOTE_OBJECTPARAMETER with MethodObj() - renamed MethodObj() to XOTclMethodObj() (it is an exported symbol) - eliminated XOTE_MOVE - eliminated XOTE_RESIDUALARGS - eliminated XOTE_UNKNOWN - eliminated XOTE___UNKNOWN - renamed __unknown to requireobject - provide prefix for internally called methods to distinguish between methods called on objects or classes - handling of minimal object systems. For example, the following three command create an object system around ::object and ::class ... ::xotcl::createobjectsystem ::object ::class ::xotcl::alias ::class + ::xotcl::cmd::Class::create ::xotcl::alias ::object - ::xotcl::cmd::Object::destroy ... where no internal message dispatch are used (e.g. no constructor "init", and where just two methods ("+" and "-") are used to create and destroy objects - extended regression test - get rid of reminder of tcl 8.4 compatibility and remove range of ifdefs, such as PRE85, FORWARD_COMPATIBLE, TCL85STACK, CANONICAL_ARGS, USE_COMPILED_VAR_RESOLVER - rename CallStackPush() to CscInit() - rename CallStackPop() to CscFinish() - remove "buffer" from compiled var structures - remove xotcl1 dependency from aol-tcl - removed conditional var table creation by assertion - make clean compile with assertions turned on - xotcl 1.6.6: make sure to load always xotcl 1 versions when needed - xotcl 1.6.6: make compilation clean when compiled with assertions on - xotcl 1.6.6: more cases for the regression test, where we want to load xotcl1 not 2 - xotcl 1.6.6: one more cases for the packaging, where we want to load xotcl1 not 2 - replace hash-lookup in namespace in ObjectHasChildren() by pointer lookup to reduce namespace dependency. - fix memcpy size - add check for optional match arguments in tcl stub generator - fix potential memory leaks all "definitely losts" from valgrind (except 24 bytes from Tcl_PkgRequire) gone - fix a potential ordering problem with cyclic dependencies created by namespace import commands - Handle cases, where objects/classes are created with the name of pre-exiting namespaces. Cases, where pre-existing namespaces contained classes/objects lead to problems, since xotcl did not see the object/classes of the pre-exiting namespace as children of the new object/class. - Allow to specify last arg of objectparameter to replace scripted init block. The redefinition of objectparameter allows us to specify whether no/some/classical/altered/additional arguments should be allowed during object creation - Naming namespaces: ::next ::next-core file extension: options: .tcl .xotcl .next .nxt file names: composite words with - instead of capitalization package names next::pkgname next::doc-tools # use - instead of _ or capitalization Classes use first name capitalized to distinguish from objects Objects typically, first charaction small - next::core as namespace name not perfect for addressing variables: set ::xotcl::version ${::next-core::version} set ::xotcl::patchlevel ${::next-core::patchlevel} do we need: checkMethod "::next::core::cmd::ParameterType" - namespace changes: mostly due to marketing reasons, the naming of the top-level namespace changed from "xotcl2" to "next". reasons: xotcl is hard to pronounce for beginners, sounds like "exotic" (but who wants to program in an exotic language) has a certain stigma of strange naming (e.g. "instproc"), is seen as a precursor of tcloo, the top-level namespace ::xotcl2:: is not very nice either, the separation of framework and language is not clear. We have now: ::next (the new object system, former ::xotcl2) ::next::core (framework, primitives) ::xotcl (former xotcl1) - "::xotcl::use" no longer needed, use Tcl standard mechanisms instead (e.g. "package req next"; "package req XOTcl", "namespace import ::next*") - [self next] returns instead of "proc" and "instproc" => "method" instead of "parametercmd" and "instparametercmd" => "setter" instead of "instforward" => "forward" instead of "instcmd" => "cmd" prefixed with the modifier "object" when needed - [self filterreg] returns instead of "instforward" => "forward" prefixed with the modifier "object" when needed - We have now: ::nx (the new object system, former ::xotcl2) ::nx::core (framework, primitives) ::xotcl (former xotcl1) - naming next scripting framework ::nx::core::existsvar <==> nx::var exists ::nx::core::importvar <==> nx::var import ::nx::core::setvar <==> nx::var set - copied infoObjectMethod and infoClassMethod decls as comments to xotcl.c, aligned order of method definitions - removed "[o exists varname]" from next scripting language - reanimated "info vars" to show locals in eval method - provide error messages for [objectproperty ... type ...] - replace 0 by NULL in calls to GetClassFromObj() - extended regression test - use size_t where appropriate - added nonnull annotations - Implemented "Class info parameter" in Tcl, aliases for xotcl. Now both definition of parameters and setting of __parameter are in Tcl. - get rid of ":::xotcl::use" - renamed tests based on next from .xotcl to .tcl - extended regression tests - use namespace ::nx::test instead of ::xotcl::test - use namespace ::nx::serializer instead of ::xotcl::serializer - rename xotcl1.xotcl to xotcl.tcl - some cleanup (version variables, etc.) in xotcl.tcl - renamed tests/method-modifiers.xotcl to tests/method-modifiers.tcl - changed "require xotcl::test" to "... next::test" - changed "require next" to "... nx" - changed "require next::test" to "... nx::test" - changed "require next::doc" to "... nx::doc" - added missing ./tests/var-access.tcl to git - added section about registering filters and mixin to migration guide - moved and transformed to next tests/mixinoftest.xotcl -> tests/mixinoftest.tcl - moved and transformed to next tests/object-system.xotcl -> tests/object-system.tcl - changed pkgIndex reference for .so file from next ot nx - changed stubs from xotcl to nx - first part of OpenACS updates - changed "Serializer.xotcl" to "serializer.tcl" (package name from xotcl::serializer to nx::serializer) - added stub for xotcl::serializer for backward compatibility - changed serializer to new namespaces - renamed xotcl.tcl to xotcl2.tcl - added proc finalize to xotcl2.tcl - renamed mk_predefined.xotcl -> mk_predefined.tcl - renamed predefined.xotcl -> predefined.tcl - additional subcommand "info method parametersyntax " returns parameters in a syntax similar to the tcl man pages - added ability to pass syntax for forwarded methods via set ::nx::core::signature(::nx::Object-method-forward) (experimental) - fixed documentation system to work with actual version - added undocumented methods for quality control in documentation - added checks for documented, but unavailable methods in documentation - added comparison of documented parameters vs. actual parameters in documentation - added @properties and has_property to the documentation classes. Current primary purpose: define, which methods are internally-called - added internally-called to the method object template - added redefine-protected to the object template - added methodtype to object template - some documentation updates - some indentation/spacing improvements on xotcl.c - let ".... info method .... METHOD" return values, when METHOD contains namespace prefix. This can be used to obtain the parmeter definitions from nx::core - get forward definition from the original command - created own directory structure xotcl under library containing doc, tests, apps, lib etc. and moved obvious content here. - adjusted regression test and old documentation system to work with new structure old structure xotcl apps actiweb comm persistence scripts utils xml config doc library lib comm patterns rdf registry serialize store xml man tests unix win new structure nx config doc library lib serialize xotcl apps actiweb comm persistence scripts utils xml doc library comm lib patterns rdf registry store xml tests man tests unix win - moved some more xotcl specific tests to library/xotcl - transformed forwardtest from xotcl to next - moved slottest to library/xotcl - added new Makefile target test-xotcl - finished test migration for now - deactivated __next for now - iterated through doc.tcl-TODOs - changed CheckVarName to allow array names like e.g. a(::b) - extended regression test - fixed serializer to handle sub-objects of explicitly exported objects - xotcl.c: * new function GetObjectFromNsName() to obtain object or class from a fully qualified namespace name used in method handles (such as e.g. ::nx::core::classes::X) * new function MethodHandleObj() to return a tcl_obj containing the method handle * removed obsolete method getFullProcQualifier() * info methods obtain now object and/or class from fully qualified method names (method handles) if possible * return message handles in "current next", "current filterreg" and "... info filter ... -order", which can be used in "info method .... " for obtaining more details. * change all occurrences of "self" in next regression tests to current. - xotcl2.tcl * implemented "self" as a proc to provide extensibility and full backward compatibility; this opens opportunity to replace now e.g. "self proc" by "current method", etc. * provide full compatibility for "self next", "self filterreg" and "... info filter ... -order", returning old-style multiword method handles (such as e.g. "::C instproc foo") - changed "next" to current in documentation framework and templates - updated migration guide, added section for call-stack introspection - updated serializer for new names - Introduced $xotcl_target_doc_dir for generated xotcl documentation. Generate xotcl documentation in this directory. - moved more (hopefully all) xotcl doc components into library/xotcl/doc - added interp alias "nx::self" to "nx::core::current method" - changed "current proc" into "current method" in scripts and tests - file extension for next scripting .tcl DONE - changed ::nx::core to ::nsf - made the "next scripting language" a own, loadable tcl package (currently named nx, name is subject of change) - predefined.tcl is now pretty minimal. - updated to TEA 3.8 - moved all exports of nsf to predefined.tcl - made imports in xotcl2 and nx explicit - adjusted path in documentation system for nx/nx.tcl - Implemented "interp alias" support for classes. In some cases. interp-aliased classes worked already without additional code, but e.g. in "... -superclass C ..." it failed. Without this feature, one could not reuse a class with a different namespace, unless it was explicitly "namespace exported" in the source. The problem was the implementation of "::nx::Attribute", which should not be exported in nx (most people do a "namespace import ::nx::*") because there is no need to do so, but ::xotcl::Attribute should reuse it - without subclassing). .... However, we still seem to have a problem, when the interp-aliased Class is exported and imported to a different namespace. - info methods shows finally "slots" and "slot". Wanted? Actually no. - removed definition of slots from nx, changed regression tests examples from slots to ::attribute - replaced several occurrences of "eval" in nx.tcl and xotcl2.tcl - implemented parameter option "allowempty" - extended regression test - commented out XOTCL_CMD_NOT_FOUND, since it seems to be obsolete by now - extended regression test to avoid CallDirectly on dealloc (the last place, where XOTCL_CMD_NOT_FOUND was used) - implemented return value checker (for scripted and c-implemented methods) - additional methodproperty returns (for registering a return value checker) - support for incrementally adding stuff to paramDefs (such as slotobj or return value) - new c-function ParamDefsNew() - added regression test for return value checker - upgraded to TEA 3.9 - nsf: provided scripted support for "require/provide methods" - nx: new method ":require namespace" ":require method" "require object method" - added regression test method-require - removed requireNamespace from nx.tcl (still exists in xotcl) - replaced "requireNamespace" by "require namespace" in nx regression tests - updated migration guide - removed method "autoname" from nx.tcl - added "method require autoname" - added "method require exists" - removed method "filtersearch" from nx.tcl - added "obj info method filter methodName" to nx - updated xotcl2 to use new filtersearch implementation - updated migration guide - renamed "info method name ..." into "info method handle ...", since it returned already the handle - renamed ListMethodName() to ListMethodHandle() - changed output of "info callable -which ..." from definition to method handle - renamed "info callable -which ..." into "info callable method ..." - updated regression test to reflect the changes - changed "info method filter ...." into "info callable filter ..." - fixed "o info callable method" in some cases with mixins - extended regression test - updated migration guide - made Class.info, Class.mixin, Class.filter robust against per-object mixins from meta-classes - extended regression test - checked safety of Class.method, Class.alias, Class.setter, Class.forward - made Class.filterguard, Class.mixinguard, Class.attribute robust against per-object mixins from meta-classes - fixed mixin/filter delete methods with guarded operations - extended regression test - all methods defined on both, Object and Class are now safe in respect to per-object mixins with meta-classes - make slot optimizer more robust - removed methods object-mixin and object-filter from the interface. (Caused some duplication of logic in the method "object") _ added option noforwarder to RelationSlots - some minor cleanup - removed XOTCL_METHODTYPE_OBJECT from XOTCL_METHODTYPE_BUILTIN - default methodtype returns now everything, which is a true method (except objects) - methodtype -all includes objects - the object "slot" does not appear now in the method listing per default for classes having slots - changed __invalidateobjectparameter from a method of class to framework primitiv ::nsf::invalidateobjectparameter - experimental method-property "class-only": this allows to make object save against per-object mixins of meta-classes. the flag is only used in the mixin-resolver - used for the time being in nx only for Class.info, but would apply as well for methods defined on both Object and Class. - use now class-only for all methods methods of meta-classes. Methods of meta-classes are intended to be applied on classes, one should not change this via per-object mixins. - respect class-only in "info callable methods|method" - extended regression test - provided relation name "object-filter" to slot filter. - replaced "obj|cls filterguard name cond" by "obj|cls filter guard name cond" - replaced "obj|cls info filterguard name" by "obj|cls info filter -guard name" - replaced "cls object info filterguard name" by "cls object info filter -guard name" - removed XOTclObjInfoFilterguardMethod() - removed XOTclClassInfoFilterguardMethod() - extended regression test - updated migration guide - replaced "obj|cls mixinguard name cond" by "obj|cls mixin guard name cond" - replaced "obj|cls info mixinguard name" by "obj|cls info mixin -guard name" - replaced "cls object info mixinguard name" by "cls object info mixin -guard name" - removed XOTclObjInfoMixinguardMethod() - removed XOTclClassInfoMixinguardMethod() - extended regression test - updated migration guide - deactivated "abstract" - implemented experimental delegating version of "object as method" that keeps the original self. - changed requireNamespace to "require namespace" in lib/make.tcl - use prefix sub= for methods invoked on "object as method" - change further instances of "my connection" to "[self]::connection" in xo*comm* - implemented "object-methods-only" as alternative for prefix for invoke "object as a method" - added option "-returns" to Object.method - added option "-returns" to Class.method - added subcmd to method/object method in nx - delete class methods in freeAllXOTclObjectsAndClasses() explicitly to handle potential double-deletes - extended regression test for subcmds - started new interface bundles, objectInfoMethod and classInfoMethod for using new infrastructure - added object info methods filterguard, filtermethods, vars to objectInfoMethod - added class info methods filterguard, filtermethods to classInfoMethod - built a temporary solution for dispatcher "filter", since forward mangles args - nx: we have now "obj info filter guard name" instead of "obj info filter -guard name" - nx: we have now "obj info filter methods ...." instead of "obj info filter ...." - added object info methods mixinguard, mixinclasses to objectInfoMethod - added class info methods mixinguard, mixinclasses to classInfoMethod - built a temporary solution for dispatcher "mixin", since forward mangles args - nx: we have now "obj info mixin guard name" instead of "obj info filter -guard name" - nx: we have now "obj info mixin classes ...." instead of "obj info filter ...." - updated migration guide - changed info to new interface (partly done for nx, migration for xotcl to be done) - fixed "info methods" and added "-methodtype all" for setting class-only - regression test works now until first XOTcl reference - Changed handling of "child objects": now, they are shown by default. - At the same time, the subobject "slot" was made protected to avoid its listing per default in "info methods" - unified slot parent-object creation handling - changed XOTcl info to new interface - reanimated 5 tests in xotcl/tests/testx.xotcl - reanimated 5 tests in tests/destroytest.tcl - changed resolve_method_path to __resolve_method_path and made it protected - fix requiredness of last argument in parametercheck - return "object" for "info method type ...." when method is an object. - return valid creation command in "info method definition ...." when method is an object. - extend regression test - eliminated "info classparent" and "info classchildren" - added tests to xotcl/tests/testx.xotcl to assure equivalence - back-ported fix for xotcl 1.6.6 reported by kristoffer lawson, which helps just partly here - extended regression test - added class ::nx::EnsembleObject - factored out DispatchUnknownMethod() - added flag XOTCL_CM_NO_OBJECT_METHOD to ObjectDispatch() and friends - added tests/subcmd.tcl - added methods "defaultmethod" and "unknown" to ::nx::EnsembleObject (together with a set of helper methods to provide user-friendly information) - scripted "info slotobjects" to return only objects of class ::nx::Slot - fixed test with UnknownClass in xotcl/tests/testx.xotcl - fixed silent (scripted) unknown handler. - reactivated corresponding regression test - extended regression tests (call unknown method with filter with and without unknown handlers) - make sure to test next to non-existing shadowed method in connections with filters and unknown handlers - documented incompatibility of object-invocation via method interface (due to ensemble objects) in migration guide - implemented XOTclObjInfoHasMixinMethod() and XOTclObjInfoHasTypeMethod() - renamed "$obj info hasnamespace" to "$obj info has namespace" - added "$obj info has mixin $class" - added "$obj info has type $class" - extended regression test for parametercheck/objectproperty/is - updated interface definitions for info methods, sort these alphabetically - removed "objectproperty .... hasmixin" - removed "nsf::is ... -hasmixin ...." - removed type-converter "type=hasmixin" - adopted emulation layer in xotcl2 accordingly - added two tests for "info has mixin" to regression tests - removed "objectproperty .... type" - renamed isSubType() to IsSubType() - adopted emulation layer in xotcl2 accordingly - added two tests for "info has type" to regression tests - removed "nsf::is ... -type ...." - adopted emulation layer in xotcl2 accordingly - extended regression test - introduced ::nsf::isobject - replaced in all scripts "::nsf::objectproperty ... object" by isobject - removed "infoObjectMethod" and "infoClassMethod" - replaced ::nsf::cmd::ClassInfo2 by ::nsf::cmd::ClassInfo - replaced ::nsf::cmd::ObjectInfo2 by ::nsf::cmd::ObjectInfo - changed argument order on objectproperty to make it conformant with Tcl conventions - updated migration guide - changed argument order on nsf::is to make it conformant with Tcl conventions - removed objectproperty, replaced it by ::nsf::is - move functionality of objectproperty to make "obj info is ..." more efficient - report "invalid parameter" in nsf::is and parametercheck, even when no-complain is used. - fixed reference counting problem with user-defined converters - added flag -complain to ::nsf::is - removed ::nsf::parametercheck - new parameter option "convert" to signal that an application specific parameter checker should convert the value (takes the result of the methods as conversion result) - added parameters for slots "allowempty" and "convert" - extended regression test - added handling of parameter options "allowempty" and "convert" in createFromParameterSyntax - renamed slot attribute "noforwarder" to "nosetter" - method parameter can now use option "nosetter" to allow object parameterization without providing a setter method (example: "Class create C -parameter {x:integer,nosetter}") - extended regression test to include "nosetter" - new flag for configure: "nx::configure checkresult on|off" - turn off result-checking for non-converters, when checking is off (per default, it is on) - extended regressi - new flag for configure: "nx::configure checkarguments on|off" - turn off argument-checking for non-converters, when checking is off (per default, it is on) - extended regression test for optional argument checking - reflected changes in /is/objectproperty/info has/info is/ in migration guide - changed stub naming from "[Nn][Xx]*" to nsf (for next scripting framework) - checked "my" vs. "nsf::dispatch" in nx.tcl and xotcl2.tcl - "child objects" are showed per default in "info methods" - big renaming orgy (BRO): - changed filenames starting to "xotcl" into filename starting with "nsf" - adopted Makefile infrastructure accordingly - removed compile flag XOTCL_METADATA and generic/xotclMetaData.c - changed compile flag PROFILE into NSF_PROFILE - BRO continues: - changed all XOTCL_ into NSF_ - changed all XOTCLINLINE into NSF_INLINE - changed all XOTCLOBJ_TRACE into NSFOBJ_TRACE - changed all XOTcl_ into Nsf_ - changed all XOTcl([A-Z]) into Nsf\1 - changed all xotcl into nsf - changed changeClass into ChangeClass - changed XOTclpGetObject into GetObjectFromString - changed XOTclpGetClass into GetClassFromString - changed callDestroyMethod into DispatchDestroyMethod - BRO continues: - overworked function prototype definitions in nsf.c - renamed some static definitions on the way to follow Tcl conventions (start with a capital character) - added flag "-type" to NsfObjInfoChildrenMethod - added flag "-type" to NsfObjInfoSlotObjectsMethod - removed dummy argument "pattern" from NsfObjInfoSlotObjectsMethod - removed NsfClassInfoSlotsMethod (implemented via "children ... -type ...") - moved "info slots" from nx::Class to nx::Object (to report e.g. per-object attributes) - extended regression test - [::nx::Object info method parameter info] returns now empty instead of error. - extended regression test - splitted "info callable" into an ensemble (submethods have quite different signatures) - added "info callable slots" with functionality of "info slotobjects" - removed "info slotobjects" - handle aliases to (sub)ensemble objects during final cleanup to improve sharing of logic. - share definition of "info callable" and "info has" ensemble between object info and class info - new function AliasDeleteObjectReference() to delete aliases to objects - removed some obsolete functions - changed "info available" into "info lookup" (and accordingly c definitions, migration guide) - pass tclobj instead of string to NsfObjInfoMethodMethod and NsfObjInfoMethodsMethod - first part of ensemble name resolver. We can resolve now e.g. [nx::Object info method parameter "info lookup methods"] - second part of ensemble name resolver, distinguish between registration object and definition object - new functions: GetRegObject() - extended regression test - fixed handles with subcommands used on objects without namespaces - new functions: GetRegObject() - fixed handles with subcommands for class methods when called on classes or objects - extended regression test - changed "cls object method ..." and friends into "cls class-object method ..." - added "info method subcommands ..." to return list of subcommands (of the ensemble) - extended regression test - use always NULL instead of 0 when assigning to a pointer variable - improve comments in nsf.c - follow closer naming of Tcl style guide - removed overhead on ::nsf::dispatch when called with absolute paths - absolute paths have to start with ":". - checked equivalence of the following two commands in respect to fully-qualified names ::nsf::dispatch $obj ::nsf::cmd::ObjectInfo2::hastype $class ::nsf::parametercheck object,type=$class $obj extended regression test (parameters.tcl) - renamed "parameter" into "attributes" in nx - renamed "info parameter" into "info attributes" in nx - updated migration guide - fixed several common typos - documented behavior of upvar/uplevel with aliases on scripted procs through regression test - implemented next within ensemble methods - added regression tests for next within ensembles - added regression tests for upvar with ensembles - refactored next and argument passing (new methods NextGetArguments(), NextSearchAndInvoke() and CallStackFindEnsembleCsc()) - doing an internal next in cases where a method ensemble does not contain the called submethod - added regression tests for partial ensembles - renamed "... info ... subcommands ..." into "... submethods ..." - renamed tests/subcmd.tcl info tests/submethods.tcl - moved relevant tests from tests/parameters into tests/submethods.tcl - renamed functions in nsfStack.c to follow Tcl naming guidelines - call internal NextSearchAndInvoke (without NextGetArguments) from the implicit next in ensemble methods - made NsfNextMethod() obsolete to ease different noarg handling policies - new nsf::next cmd. receives 0 or 1 argument, which might be a list of arguments. This avoids ambiguity of ::xotcl::next with "--noArgs". - renamed namespace_copycmds and namespace_copyvars to nscopycmds and nscopyvars (we don't use "_" in nsf::*-names as delimiters elsewhere) - renamed __qualify to qualify (it is a non-exported cmd) - handle next in ensemble with arguments - extended regression test - removed obsolete code - made methods (for now just scripted methods) by default protected. - provide methode __default_method_protection to obtain the default method protection when neither protected or public is used. - per default methods are now protected - provide ::nx::configure defaultMethodProtection true|false as convenient interface - update regression test and serializer to handle default protection - decide on paths for documentation of next and xotcl 2, with version numbers; what should be included in distro, what on web-site - decide on syntax subcomponent. Candidates are * Object.method * Object->method * Object#method - handling namespaces in documentation # @object ::nx::Slot vs. # @object Slot (best allow both variants, write fully qualified name via introspection) - why only @object? there seems to be no @class. what to do with metaclasses? - systematic way of specifying results of methods - systematic way of reporting results in documentation - handle line-breaking in long @definitions (e.g. @param; e.g. via indented next line) - danger, tcl-commands in comments (see :method get_unqualified_name) especially for code commented out.... - kann man "[:? {[$attr eval {info exists :default}]}" durch "[:?var :@param ..." ausdrücken? oder vielleicht besser die variablen mit leerstring initialisieren + infrastruktur anpassen? - listing von methoden im left-bar, ähnlich http://developer.yahoo.com/yui/docs/YAHOO.util.Connect.html - "Objects" im left-bar irreführend, sollten eher "Classes" sein. Allerdings sollten auch objekte dokumentierbar sein - doc-tools: was machen die argumente von :? (bspw. ops?); ich nehme an, das ist work in progress. sinnvoll wäre: [:?var obj varname body], da viele (die meisten) operationen auf anderen objeken ausgeführt werden - die Dokumentation der Objekt- und Klassenmethoden muss aus gentclapi weg und in predefined.tcl und xotcl2.tcl hineinwandern. Es werden nicht alle möglichen methoden in next und/oder xotcl2 registiert, ein paar namen sind anders, etc. - fixed a crash for tcl 8.6b1 in return value checking. now it complains about missing cmdPtr; it is not clear, why this is missing at the first place in 8.6b1 while working in 8.5 - improved library/lib/make.tcl once more - fixed handling of TclNRRunCallbacks, such that coroutines can be easily used (more testing required) - added temporary routine ::nsf::yieldcheck for coro debugging - renamed Tcl85showStack() to TclShowStack() - Big internal changes for handling nre-enabled procs in more situations. Handles now all nx regression tests, but fails in testx.xotcl (just nre-enabled) - passing part of dispatch flags in cscPtr->callType - runs now full regression test NRE enabled, but still much debugging and options for less conservative behaviour - some cleanup concerning TCL_STACK_ALLOC_TRACE - make ::nsf::next and ::xotcl::next NRE-enabled - make coloncmd are NRE-enabled - make every internal method invokation (NsfCallMethodWithArgs() and CallMethod()) NRE-configurable - use "Nsf" prefix for global vars to avoid potential conflicts - minimal support for sane-NRE patch - failed so far to make my NRE-enabled - new compile-flag for tracing: NRE_CALLBACK_TRACE - extended regression test (added test for 8.6 apply) - renamed tests/coroutines.tcl to tests/tcl86.tcl - some refactoring for making code structure more sane for NRE (but not done yet) - save snapshot; refactoring in order to ease NRE development with unified method and dispatch exit. - named debugging cmds __db_* - new cmd __db_run_assertions to perform checking of the internal state - simplification and unification of unknown handling and method finalization - some cleanup - make "createobjectsystem" more robust (allow to provided not fully qualified names). - added tcl-cool as an additional sample-object-system for nsf - changed internal method name requireNamespace to "require_namespace" - changed debug command __db_yield (unportable between various 8.6b* version) into __db_show_stack - some more cleanup - provide flag for DispatchDefaultMethod() to control immediate execution. - nre-enable DispatchDefaultMethod() for simple cases - removed TCL85STACK_TRACE - renamed cscPtr->callType to cscPtr->flags, since this is now more appropriate - some more minor cleanup - changed "info method lookup -application" into "info method lookup -source application" - introduced "info method lookup -source application|baseclasses|all" - updated migration guide - extended regression test - provide debugging output when varFramePtr in GetSelfObj() is NULL - filter misleading "proc" entry for "info frame" for nsf-stack entries - add "method" for "info frame" for nsf-stack entries - defined SKIP_LEVELS to omit optionally skipping of tcl-stack entries in GetSelfObj() - added scripted replacement for binary nxsh - new define SKIP_LAMBDA to make apply tests working without SKIP_LEVELS - renamed ::nsf::cmd::ObjectInfo into ::nsf::methods::object::info - renamed ::nsf::cmd::ClassInfo into ::nsf::methods::class::info - renamed ::nsf::cmd::Object into ::nsf::methods::object - renamed ::nsf::cmd::Class into ::nsf::methods::class - removed capitalization from exit handler interface - reduced interface of exithandler to ::nsf::exithandler set|get|unset ?arg? - renamed/removed remaining ::nsf::commands with capitalized names: parametersFromSlots ==> parametersFromSlots unsetUnknownArgs ==> __unset_unknown_args infoError removed - renamed predefined.tcl into nsf.tcl - remaining cmds in nsf (except __*) containing "_": ::nsf::provide_method, ::nsf::require_method - removed DISPATCH_TRACE - moved return-value checking into ObjectDispatchFinalize() - perform invariants checking after cmd execution, not additionally before - commented dispatch machinery - added nxwish.in (scripted replacement for former xowish) - added xotclsh.in (scripted replacement for former xotclsh) - added xowish.in (scripted replacement for former xowish) - added error handling to all scripted shells - removed old xotclsh.in and xowish.in (from apps/utils) - altered xotcl.m4 to nsf.m4 in ., library/xotcl/library/store/XOTclGdbm/, library/xotcl/library/store/XOTclSdbm/, library/xotcl/library/xml/TclExpat-1.1/ - removed traces of xotcl.m4 - removed build flags with-nxsh, with-xowish (since these are scripted now) - removed flag --with-tk (not needed anymore) - removed NXSH and XOWISH from Makefile.in - used Tcl_ObjCmdProc in prototypes - allow CMETHOD to be target of calling-object/calling-level - added NSF_CSC_CALL_IS_TRANSPARENT to handle proc aliases transparently - access self in NsfProcAliasMethod() from tcl->object; - added public|protected to output of "info method definition" (needed to make serializer more sane, necessary on the longer range) - reduce size of output of serializer - make nx::Object.serialize public - XOTcl 2: allow info slots for objects as well - serializer: * added support for ordering on aliases referencing other objects/classes * provide shared version of the method warn via alias and removed direct output to stderr - slots: * change name "initcmd" of "experimental slot features" to "defaultcmd" to avoid naming conflict the the initcmd executed at the initialization of a slot object (effects XOTcl as well) * make defaultcmd/valuecmd/valuechangedcmd working for nx (absence of trace method) * provide error message, when default/defaultcmd/valuecmd are used non-exclusively * make sure to init per-object slots after copy operations * make nx::Attribute.destroy more defensive * extend test cases - nsf: added flag NSF_DESTROY_CALLED_SUCCESS in addition to NSF_DESTROY_CALLED to distinguish between attempted and successful destroy method invocations (important for cleanup) - fix potential crash in ::nx::Object info method definition ::nsf::methods::object::instvar - "info method submethods": return all submethods, independent from protection - serializer: experimental code to serialize submethods - new option "-expand" for "obj|class info methods" to return compound names (i.e. it lists the full ensemble names) Example: ::nx::Object info methods -expand "*filter*" returns filter {info filter guard} {info filter methods} {info lookup filter} - allow ensemble names in nsf::methodproperty - fix compound name lookups when aliases link to shared ensemble objects - make objectName() NULL-safe - fix option "-source application" when applied directly on base-classes - extend regression test - nsf.c: use name "varTablePtr" instead of "varTable" when referring to the table - new option "slotcontainer" for "methodproperty" to flag slotcontainer to make them easier to process in the serializer . don't report slot container in "info methods -expand" - new function "::nx::isSlotContainer" to centralize checking for slotcontainers (used by serializer) - support export of method ensembles in serializer - "info lookup methods": order of non-pos parameters alphabetically - added option "-expand" to "info lookup methods ". It collects ensemble methods along the precedence path - added support for ensemble methods in "info lookup method" - extended regression test - provide full set of ensemble methods from EnsembleObject.unknown (i.e. from all classes along the precedence order. It was necessary to pass calling object as first argument) - "info method parametersyntax" returns now for all nonpos args the type instead of "arg" when possible (eg ..... ?-x object? ....) - extended regression test - factored out ParamGetType() to obtain from a paramPtr a type string - parametersyntax: * changed "... -x arg ..." into ".... -x value ..." * changed multiple values notation from "list" to "..." - nsf::current: new option "methodpath", returns the full name of an ensemble method starting from the ensemble root. - documented functions in nfsStack.c - removed obsolete CallStackGetFrame(), replaced by CallStackGetTopFrame() - push stack frame before calling the defaultcmd of an ensemble object to make implementation more simple. - simplified EnsembleObject.defaultcmd and EnsembleObject.unknown significantly, scripted support methods are removed. - extended regression test for "current methodpath" - allow %method in forwarder. - defined unknown methods as call-protected - make __default_method_protection protected - added syntax "?arg ...?" in parameter syntax output for "args" - removed "info forward" from nx::Object and nx::Class (can be replaced by "info methods" and "info method") - Methodpaths can be used now in the definition of "method", "alias" and "forward." We do not support it for "setter" and "attribute", since these require a parameter spec, which does not have clear semantics for a method path. - scripted definition of nx::Object.forward and nx::Class.forward - cleanup of __resolve_method_path - change TclShowStack into NsfShowStack() to avoid possible interference with the Tcl* namespace - made the following function static to avoid pollution of the global link namespace: CompiledColonVarFree(), GetRegObject(), ParamGetType() - changed option -expand in "info methods" and "info lookup methods" into "-path" to associate with the method path - changed method property name from "protected" to "call-protected" - changed nx::defaultMethodProtection to nx::defaultMethodCallProtection - nx::defaultMethodCallProtection is used for scripted methods, forwarders and aliases - added nx::defaultAttributeCallProtection, used for setter and attributes - call scripted converters without checking protection - removed defaultMethodCallProtection from tests/parameters.tcl - Implemented built-in-converter for "baseclass" and "metaclass". Change in performance for this call. >8 times faster before: parameters/parametercheck.007: 19.49 mms, ::nsf::is baseclass C after: parameters/parametercheck.007: 2.32 mms, ::nsf::is baseclass C - remove scripted definition of "baseclass" and "metaclass" - keep track of defaultMethodCallProtection and defaultAttributeCallProtection in serializer - cleanup aol-xotcl.tcl and document usage in aolserver and naviserver - iteration over TODO file - removed obsolete entries from generic/nsf.decls und generic/nsfInt.decls - removed NSF_CMD_NOT_FOUND - fixed aliasing warning for gcc 4.4.4 - removed CheckAllInstances() - added functionality to show enumerated values in "info parametersyntax" - extended regression test - added experimental code to avoid "variable :x" crash based on shadowCommands, but this does not work, when variable is bytecompiled. deactivated for now. - added support for aolserver (essentially Makefile + aol-xotcl.tcl) - removed unneeded content from serializer output - the two flags "-objscope" and "-nonleaf" are for adding frames, and they are mutual exclusive. Make them a single flag? check if both options are in every case sensible. possible realizations: -scope object|method -varscope instance|proc -varscope instance|resolver|none -frame object|method|default * instance|object: within this method, all non-prefixed var names refer to instance variables; the method can use most probably not "next" (actually, only needed for XOTcl) * method|proc|resolver: within this method, we can use colon-prefixed variables; the method can use "next" "object" könnte mit dem -per-object (dem registierungpunkt) leicht verwechselt werden. es ginge auch -varscope instance|method allerdings, meint method eigentlich "scripted method". "none" would be dangerous for "-frame", since it could imply to avoid frame stacking at all. effected are: alias, forward, dispatch für "alias" betrifft das in gleicher form auch die cmds, bei "dispatch" und "forward" gibt es dzt. kein "-nonleaf" - replaced "-objscope" and "-nonleaf" by "-frame object|method|default" for nsf::alias and nsf::default - added functionality for "-frame method" to nsf::dispatch - made the order of argument in ::nsf::alias and method "alias" the same (always first the method, then "-frame ...") - extended regression test - renamed some arguments of tcl interface to increase consistency - make requiredness explicit for nsf::cmds - introduce ::nsf::parametersyntax to provide syntax for potentially missing definitions - provided ::nsf::parametersyntax for 3 ::nsf commands and 7 nx methods (from relationslots) - fix requiredness of several info methods - added "nsf::configure debug ?level?" - use "nsf::configure debug" for value 1: complain about protected value >1: provide load messages for nx and xotcl - unset unneeded variables in ::nx namespace - copied decls for objectMethod and classMethod as comments to nsf.c, fixed order - documented a few functions - enabled nsf::__db_run_assertions in nx::test (lead before to false positives in destroy-test) - eliminated deleted objects and objects from deleted namespaces in GetAllInstances() - added handling of unstacked csc entries (removed all DEBUG warnings). - made handling of unstacked entries optional by defining macro CHECK_ACTIVATION_COUNTS) - added macro NSF_DEVELOPMENT for toplevel handling if NDEBUG and CHECK_ACTIVATION_COUNTS - cleanup of method-modifiers.tcl - updated next migration guide - follow current Tcl convention for patchlevel var: - changed name of ::nsf::patchlevel to ::nsf::patchLevel - changed content ::nsf::patchLevel from eg .0 to full number including release details - fixed bug in ::variable with colon-prefixed name (shadowCommands does not help, see above) - removed traces of Nsf_VariableObjCmd() - extended regression test - provided parametersyntax definitions for XOTcl 2.0 similar to nx for all methods without a spec (e.g. fur builtin Tcl cmds, forwarders) - make sure not to return CompiledLocal vars from InterpColonVarResolver() when TCL_NAMESPACE_ONLY is requested. - delegate always from InterpColonVarResolver() to other resolvers, when TCL_NAMESPACE_ONLY is requested. - implemented exported command ::nsf::self as fast convenience replacement for "::nsf::current object". - removed bug-alert from nx.tcl (wrong false-positives for compiled locals in slots) - added a few small optimization. nsf appears to run on the shootout benchmark the same speed like a year ago (which much less functionality) - added a few more small optimization. - code-generator: don't call argument parser, when no arguments are specified - fixed bug when calling aliased proc not via method interface - fixed bug when calling destroy in initcmd - allowed public|protected for method deletion such as "Object public method foo {} {}" - removed defaultMethodCallProtection in alias test - extended regression tests for aliases to procs - renamed nx regression tests .test to follow tcl conventions - added regression tests for destroy-during-init - removed debugging from NsfCleanupObject when compiled without DEVELOPMENT - removed debugging from CscFinish when compiled without DEVELOPMENT - changed CallStackGetActiveProcFrame() to return also CMETHD frames This allows to execute :volatile in a initcmd and to delete the object at its end. As a consequence, code like [CopyHandler new -volatile] copy [::nsf::self] $newName has to be changed to CopyHandler new { :copy [:uplevel ::nsf::self] [uplevel set newName] :destroy } - renamed CallStackUseActiveFrames() to CallStackUseActiveFrame() and ctx->framesSaved to ctx->frameSaved to reflect implementation - new function MethodNameString() to obtain name without colon prefix from tcl_obj - fix bad interaction between filters and cmd name resolvers - output object frame to ease interpretation of [info frame] - fixed scoping issue, when "-volatile" was used for object creation - added regression test for interaction between filters and function resolver (and volatile) - reactivated new volatile test in destroy.test - undone temporary fixes for volatile in serializer and nx.tcl - improved NsColonVarResolver, made some assumptions explicit - gentclApi.tcl: added optimizer rule for single argument of type tclobj - improved speed of CompiledLocalsLookup slightly - added an experimental code for setting parent namespace path as default for child-objects. At the time when an object namespace is created, the namespace path of the parent object is copied to the child as default value. - added new contains definition based on "apply" instead of "namespace eval". Main intention is to replace SKIP_LEVELS by SKIP_LAMBDA - added functionality to use ":attribute contains:method,nosetter" - added regression test for contains and attributes of type method - activated SKIP_LAMBDA in nsfCallstack. As a consequence, we disallow resolving self/my ... from tcl-proc frames (use uplevel if necessary, avoid "namespace eval") - improving error messages from argument parser - test "namespace current" and "self" in "contains" and "slots" regression test - added "nosetter" automatically, when attribute ":method" is used - fix a bug, where "o configure" (without arguments) resetted initialized values to the defaults. - show "unwind unstacked entry" message appear only when debug level>0 - removed fixed TODO entries - New function NsfNamespaceInit() to initialize pre-existing namespaces in PrimitiveOInit() and in RequireObjNamespace() - provide error message, when provided setter name starts with a colon - Make sure that DispatchDestroyMethod() calls as well protected destructors - New function NSCheckNamespace() as replacement for NSCheckForParent() - pass parentNsPtr around instead of recomputing it in NSCheckForParent() - removed unneeded argument from NSGetFreshNamespace() - switched to DString operations in NameInNamespaceObj() (seems slightly faster) - factored out NSRequireParentObject() - by the measures above, we obtained some speed improvements - moved some more debug output to be controlled by the debug-level - extended regression test with testcases for creation of parent objects via method "__unknown" - disallow object parameter of type "switch" to avoid possible confusion between (a) providing a value for the o.p., (b) calling it as a setter, and (c) calling it as a getter. For providing a value, no arg is used for switch. For calling a setter, it is necessary to provide a value even for a switch. - disallow type "switch" in setter definition (use boolean instead) - disallow type "switch" for positional arguments (use boolean instead) - extended regression test - configure.in: removed --with-tclinclude option, since it appears to be included in tcl.m4 (since a while). Many thanks to Victor Guerra for noticing it. - perform relation handling in objectparameters outside of object-frame - For preexisting namespaces, we do not set the deleteProc. Is this desired? Should nsPtr->deleteProc be moved to NsfNamespaceInit()? .... It is ok on the current labor distribution between object and namespace: if an object is deleted, it takes care about the deletion of sub-objects, not the namespace. However, it might be an option in the future to overthink this strategy and to bush (sub)object deletion into the namespace deletion. - work on replacing SKIP_LEVELS by SKIP_LAMBDA for OpenACS (works with regression test, has problems with OrderedComposite::ChildManager.init) Note concerning treating CMETHOD_FRAME like METHOD_FRAMES: we did this change for NsfCallStackFindLastInvocation(), but nsfStack.c has still several occurrences, where they are treated differently. - changed relation handling by evaluating the relationcmd in the parent context to keep evaluation order. - extend introspection "nsf::configure objectsystem": the command returns now all system methods in the syntax of nsf::createobjectsystem - "nsf::createobjectsystem" creates now a warning when an existing objectsystem is redefined and ignores the new definition attempt. This was done with the purpose to allow "package forget nx; package require nx" - Allow overwriting of redefine protected method during bootstrap to ease "package forget nx; package require nx" - forward had just "-objscope", no general "-frame method|object". Since forwarder have client data, they always push a method frame. So, the situation is different to nsd::alias and ::nsf::dispatch. Therefore, the flag "-objscope" was renamed to "-objectframe" to provide better consistency with "-frame object" - fixed bug, where error handling of invalid options in ForwardProcessOptions() could lead to a crash - return forwardoption "-earlybinding" via introspection - extended regression test - provide a more explicit way to handle resourcing after a "package forget" in the info methods (similar to Stefan's suggestion). - xotcl2.tcl: added empty namespace eval to make package indexer happy - nx.tcl: removed debugging output - nx.tcl: added syntactic sugar to "method" and "alias" for return value checking. One can write now: Class create C { :public method foo {a:int b:int} -> int { return [expr {$a + $b}] } } - extended regression test - changed returns syntax from '->' to '-returns' - xotcl2: fixed and completed results of "info instforward" and "info forward" - serializer: fixed handling of nsf::configure options - nx: added "-returns" to forwarder - added regression test for forwarder and returns - rebuild pkgIndex.tcl more eagerly - added error handler to pkg_mkIndex when called via "make libraries-pkgindex" * just show warning and errors when rebuilding pkgIndex files * stop make in case of errors in pkg_mkIndex - don't leave error message when __default_superclass (or __default_metaclass) is not set - Fixed switching between INACTIVE_MIXIN frames to ACTIVE_MIXIN frames - Extended regression test - make handling of redefinitions in system methods more robust - follow Tcl naming convention (uppercase functions) - Don't allow to call objects as methods (for the time being) via absolute names. Otherwise, in line {2} below, ::State is interpreted as an ensemble object, and the method "unknown" won't be called (in the XOTcl tradition). {1} Class ::State {2} Class ::State -parameter x - Converted migration guide to asciidoc - Overhaul of several sections in asciidoc - Developed styles for nx for migration guide (.css and source-highlight) - fixed bug in xotcl 2.0 "info forward" - extended regression test - NSDeleteChildren: delete objects before classes - NSDeleteChildren: delete here aliases as well - fix potential crash when "next" is called from a non-proc frame. - nx.tcl: cleanup of forward implementation - xotcl2.tcl: cleanup of forward implementation - xotcl2.tcl: provide debug version of default init method - nsf.c: acquire parameter structure for returns more lazily (otherwise, a serializer handling returns would acquire the structure for every argument) - extend regression test - xotcl2.tcl: fix the default init handler - nsf.c: provide warnings when unchecked parameter values might conflict with nonpos args - provide a generic logging interface * predefined for plain Tcl and aolserver/naviserver * C-level: NsfLog() * Tcl-level: ::nsf::log - quote name of referenced parameter in error message to ease reading - new parameter checker "parameter", performing an approximate checking for valid parameter specs - set NSF_ARG_CHECK_NONPOS only when there are multiple arguments - remove space checking in values for NSF_ARG_CHECK_NONPOS in favor of parameter checker - make "... info children ?pattern?" compliant with XOTcl 1; if pattern contains no wildcard and is no absolute path, nsf completes it. (eg. Object create o; Object create o:x; o info children x" will return ::o::x) - extended regression test - introduced a few forms of multiplicity * 0..1 allow empty value * 0..* list, can be empty (equivalent to 0..n) * 1..* list, cannot be empty (equivalent to 1..n) - deprecate multivalued in parameter specs in favor of multiplicity - deprecate allowempty in parameter specs in favor of multiplicity - adjust regression test - fixed bug with required last object parameter without provided value - extended regression test - new printf-style error message generator: NsfPrintError() - simplified error handling: removed NsfVarErrMsg() and NsfErrMsg() and replaced it by NsfPrintError() - testx.xotcl: fix messages when test fails - further cleanup of error procs: eliminated NsfObjErrArgCnt() - improve error message, when too many arguments are passed - extended und overworked migration guide (added e.g. multiplicity) - extended regression test - added returns handling for nx in serializer - extended regression test - provide warning if non-positional argument is passed more than once - made error messages more consistent - improved error messages for "returns" and "nsf::is" (omit parameter name) - streamlined error messages - removed NsfErrBadVal() and replaced it with a generalized version of NsfObjErrType() - "/obj/ info method parametersyntax /method/": return results of ::nsf::parametersyntax in case, the parametersyntax cannot obtained from a parameter definition (e.g. the method is a forwarder to a tcl cmd). doctools - interfaces in documentation for slots (see for more details ::nx::Class#superclass in nx.tcl) - handle object methods as well in quality checks - why does one have to specify @superclass rather than determining the superclass via introspection? - use tcl parametersyntax for short description of commands/methods - deal with internally called methods (can be overloaded by the application) * user-called and internally called (e.g. from "create" or "new") XO_c_create_idx, XO_o_destroy_idx, XO_o_move_idx, * not documented yet: XO_c_requireobject_idx, XO_o_defaultmethod_idx, XO_o_init_idx, XO_o_objectparameter_idx, XO_o_unknown_idx * only XOTCL2: XO_o_cleanup_idx, XO_o_residualargs_idx, text - use term "callprotection" in documentation for public|protected (to be consistent with "... info methods ...") - reduce indenting for code examples in documentation (high indentation makes readability worse). i use usually just 2, 4 are ok as well; we should decide. - removed method "setter" from nx - removed method "setter" from migration guide - nx method "attribute": changed name of nonposarg from "slotclass" to "class" - fix bug for "C class-object attribute foo" (incorrect forwarder) - extended regression test - doctools: changed "-slotclass" to "-class" - nx::test: made differences in regression test easier to read - serializer: updated serializer to avoid calls to "setter" - extended regression test - fixed in bug in ensemble-next (removed colon-prefix from methodname in next) - extended regression test - Experimental Object-System specific resolver in method bodies (allows resolving to the "right" next, self, etc. without namespace imports/paths) - deactivated automatic namespace path copying for child-objects - extended regression test - added deletion functionality to nsf::mixin - moved handling of methodNames of c-cmds to ResolveMethodName() - extended regression test - nsf.c: renamed MethodNameString() to MethodName() (for consistency with ObjectName() and ClassName()) - raise error, when "obj :method ..." is invoked (colon misleading und not necessary) - remove colon from method name in error message "unable to dispatch method ...." - extended regression test - nsf.c: code cleanup and documentation improvements - made assertion code optional - added and renamed additions compile flags NSF_WITH_INHERIT_NAMESPACES NSF_WITH_OS_RESOLVER NSF_WITH_ASSERTIONS - added flag NSF_WITH_VALUE_WARNINGS - defined nsf::deprecated as tcl proc, using ::nsf::log - some minor refactoring - "info parameter": return :switch as parameteroption for C-defined cmds, when a nonpos-arg gets no arguments - updated regression test - added experimental ::nsf::proc for realization of procs with next scripting argument passing. These nsf::procs improve the orthogonality of the code (using e.g. nonpos args and value checker for procs) and allows the same introspection interface (info method parameter|parametersyntax, ...) - removed unneeded functions: NsfComputePrecedence(), NsfComputeDependents(), Nsf_SetVar2Ex(), NsfOSetInstVar(), Nsf_ObjGetVar2(), NsfOGetInstVar(), qNsfCreateObject() - removed unneeded external declarations: NsfClassListAdd() NsfClassListFree() - make extern declarations explicit - grouped most extern definitions together - improved documentation - moved variable declarations to inner scopes - removed warning from cppcheck() - added block for none-one-liner if statements - added methodtype "nsfproc" to "... info methods ...", to be used with namespace qualified names - return "nsfproc" as methodtype for nsfprocs - refactored InvokeShadowedProc() - some minor code cleanup and improved documentation - added flag "-ad" to ::nsf::proc for obtaining the semantics of ad_proc in OpenACS (boolean with no arguments, append "_p" to variable names) - added "... info method definition ..." for nsfprocs - new function DStringAppendQualName() to append qualified name to a DString - removed obsolete function NSCmdFullName() - serializer.tcl: export nsf::procs via "Serializer all" - nsf::proc: alloc shadowed methods in ::nsf::procs - new helper function ::proc strip_proc_name to strip nsf::procs prefix - improve error messages - reduce verbosity - removed the following obsolete macros: ALLOC_NAME_NS, ALLOC_TOP_NS, ALLOC_DSTRING - some refactoring of the argument parser - argument parser handles now as well OpenACS like single-word parameter values (such as ... -flag=1 ....) - improve error messages and warnings for nsfprocs - extended regression test - no need to define "-class" as objectparameter - no need to define "Object.cleanup" as a method - let "obj class NEWCLASS" return NEWCLASS - doc-tools: added "-where" to !get - doc-tools: title to internal links, provided css class, added nicer label - updated reference doc - removed leftover -public flag in nsf::method - general cleanup: removed unused arguments - defined UNUSED macro to get more checking on unused arguments - nx::pp: added flag "-linenumbers on|off" to render method - added first version of next-tutorial.[txt|html] - xotcl2.tcl: defined ::xotcl::MetaSlot - make sure, that classes of the intrinsic class hierarchy are of the same object system - add regression test - removed c-implementation of method vwait, it was replaced by "vwait :varName". We had to allow flag TCL_GLOBAL_ONLY in InterpColonVarResolver(), since Tcl vwait implementation calls it with that flag. - added a scripted implementation for vwait in xotcl2 - added regression test for vwait - removed TCL_VWAIT from the code, since we have it in git - nx.tcl: defined method unknown as protected - nx.tcl: never pass "substdefault" to a setter - nx.tcl: define a minimal value-checker any to suppress warnings for potential conflicts with non-positional parameters, when the values start with a dash - doc-tools.tcl: make -name parameter of method new always required and "any" - doc-tools.tcl: make object parameter of Entity of type "any" - nsf.c: added wideinteger to list of value-checkers - nsf.c: provide context for warning messages - extended regression test - next-tutorial: documentation updates - add explicit reference counting for oacs-style flag value passing - parameter specs: use "arg=" in object parameter type "method" as name of a called method to allow to call unregistered methods - eliminate protected method "noinit" for nx and allow it just as an object parameter - added first implementation of object parameter type "forward" - renamed object parameter type "method" to "alias" - removed parameter option "slotobj=" in toParameterSyntax - renamed to [from|to]parameterSyntax to [from|to]parameterSpec - serializer.tcl: reactivated methodSerialize (used in api-browser of OpenACS) - nx.tcl: * new method requireClass to Combine two classes and return the more specialized one * make slot objects for parameter aliases and parameter forwarder instances of ObjectParameterSlot * get rid of attributes "isforward" and "isalias" and replace it by "disposition" * complete list of predefined value checkers * we have now three approaches for providing parameter -object-filter and -object-method Approach 1: create RelationSlot with nosetter Approach 2: use parameter forwarder Approach 3: use parameter alias we switched from approach 1 to approach 3 - extended regression test - fixed potential crash with missing parent namespace - added shadowing for ::tcl::info::body to allow "info body" to be called on ::nsf::procs - commented nsfShadow.c - added regression test - removed NSF_INFO - fixed potential access to freed memory (actually when checking if namespace was removed by Tcl); found this problem when compiling Tcl with SYSTEM_MALLOC (own modified version of tclThreadAlloc.c) - fixed memory leak (namespace names and structures) - nx.tcl: * full rewrite of slot machinerie, much simpler structure * relation handling via parameter aliases instead of pseudo converter * mixinclass SlotOptimizer removed * new class BootStrapAttributeSlot - ConvertToRelation() and handling of parametertype "relation" - Make CompiledColonVarFetch() more robust in case of half initialized objects (create vartable on the fly if needed) - allow empty parameter options in parameter parser - removed nsf::parametersfromslots (became simple, part of objectparameter now) - removed hardcoded objectparameter (attributes, volatile and noinit) - updated regression test - updated class diagram - nx.tcl: needsForwarder is true, when method "get" is specified on a slot - nx.tcl: Don't generate per-slot add/assign handlers, when not needed - nsf.c: fixed a nasty bug within namespace deletion, when a deletion of one tcl cmd caused implicit deletions of other cmds in the same namespace. The classical idiom for looking over hash tables with Tcl_GetHashValue() and Tcl_NextHashEntry(hSrch) can lead to crashes (and has different behavior depending on the number of buckets). - added regression test - nx.tcl: added default/initcmd for ObjectParameterSlot - added ::nx::Object as default for "superclass" slot to make default superclass explicit - unified interface for getParameterOptions - extended regression test - update class diagram of slots - new function Nsf_NextHashEntry() simular Tcl_NextHashEntry(), but handles triggered hash entry deletions - fixed reference count in AliasDeleteObjectReference() - nsf.c: changed handling of cmdPtrs in call-stack content. * we use now explicit reference counting using NsfCommandPreserve/NsfCommandRelease * as a consequence, we do not need the following functions Nsf_DeleteCommandFromToken() and CallStackClearCmdReferences() any more. * the flag NSF_CSC_OBJECT_ACTIVATED is not needed anymore and was removed - removed a small memory leak when a destroy method of an object o deletes its grandparents namespace, containing also this class of o (and its methods). Significantly eased by the change above. - use NsfCommandPreserve/NsfCommandRelease for tcd->aliasCmd as well. In case of epoched cmdPointers, refetch the cmd and it client data. - added regression tests - added flag to AliasGet() to leave optional error message if alias data is removed - some cleanup in NsfProcAliasMethod(): handle not existing alias data, more careful refcounting - added experimental flag WITH_IMPORT_REFS to deactivate automated alias deletion (seems, that this solves all issues we had before) - added flushing of bytecode on alias registration - added regression test - update slot UML diagram - fixed incorrect (unwanted) call to unknown that caused creation of objects names __unknown when classes could not be resolved - nsf::relation: fixed error message when receiving and invalid class for relation type "class" - updated documentation - reanimated NSF_PROFILE (when activated, needs more stack and slows execution slightly down) - fixed a problem with object-level alias - nsf.c: provide low-level commands for managing profile data - nsfStack.c: provide hook to obtain callers information in profiling code - nx.tcl: provide caching for computed values of object slots to make method objectparameter nearly twice as fast; direct changes on slots require a reconfigure call. - nsf.c: removed SUBST from shadow commands (does not appear to be necessary any more) - nsf.c: fixing a memory leak (some substituted values were not freed correctly) - nsf.c: fix potential crash for epoched cmds - some minor updates for profiling support - The fix of yesterdays subst reference counting bug triggered an other problem: If the last arg was "args", the flags array for checking the need for decr of refcounts was not extended. There are multiple possible fixes, i have just extended the flags array for now as well. - When profiling is activated, perform now a more sane shutdown order, all hash tables are now correctly freed. - Improve behavior, when object system creation fails - Drop function NsfProfilePrint() - Altered Nsf_NextHashEntry() to re-init hSrchPtr when the number of expected entries differs from the number of real entries. This fixes a bug that Michael Aram detected, that happens when multiple hash buckets exist, but on deletion of an hash entries triggers some other deleted from the same hash table. - extended regression test. - made default setting more compatible with XOTcl 1 * set variables to defaults only when not set already * flag init_called already before init is called, not afterwards (a call to "configure" within init does not clear the already set instance variables) - extend regression test - configure: added flag --with-profile to enable profiling support - cleanup and documentation of nsf-specific interp state - nsf::configure: added an option "profile on|off" (per default off) - profiling: return object data with method information - the following is obsolete since valgrind 3.6 =========== reminder for valgrind testing svn co svn://svn.valgrind.org/valgrind/tags/VALGRIND_3_5_0 valgrind curl http://bugsfiles.kde.org/attachment.cgi?id=36999 > 10.6.patch mv 10.6.patch ./valgrind cd valgrind patch -p0 < 10.6.patch ./autogen.sh ./configure ./configure --build=amd64-darwin make sudo make install ==================== - doc: * This package contains 12 classes.... 3 objects .... Why are all these marked with "mismatch"? * (optional) protected method elimination in left bar * heading "Glossary" missing. It ist not clear, what the list of items is, when one sees index.html * make quality checks (missing documentation, ...) optional? how to deal with non-resolvable quality checks? * provide a renderer for XOTcl @-notation to produce object structure for the new doctool (makes the old documentation usable, eg. for XOTcl2) - first steps towards DTrace support - DTrace: * track objects in method invocations * trace result codes in method-return * add some DTrace sample scripts * add DTrace header file dependency * add --enable-dtrace flag for configure * --enable-dtrace sets DTRACE_OBJ on mac os x empty (since not needed for mac os x DTrace) * added "nsf::configure dtrace on|off" for skipping package initialization (to be handled in D script) * make compilation clean * extended README file * handle self->tracing in D scripts (and in dtrace/sample.tcl, tests/object-system.tcl) * add probes for object creation and freeing * add sample d-script for object bookkeeping * renamed object-create into object-alloc (counterpart of object-free, no confusion with create) * fire probes as well for classes created by the object system - configure * make "configure --help" more pretty * simplify configure.in - added first version of "nsf::methoddelete" - extended regression test - updated TODO - fixed potential crash with -param:switch - added "... info method exists ...." - updated migration guide - changed names of method handling commands in nsf: ::nsf::methodproperty => ::nsf::method::property ::nsf::method => ::nsf::method::create ::nsf::methoddelete => ::nsf::method::delete ::nsf::alias => ::nsf::method::alias ::nsf::forward => ::nsf::method::forward ::nsf::setter => ::nsf::method::setter ::nsf::provide_method => ::nsf::method::provide ::nsf::require_method => ::nsf::method::require (updated regression test, docs, ...) - Fixed cases of -flag=$value for type switch outside the context of "nsf::procs -ad" - extended regression test - removed hardcoded name "init" from CallConfigureMethod() - improved documentation - removed isInitString() - changed names of var handling commands in nsf: ::nsf::existsvar => ::nsf::var::exists ::nsf::importvar => ::nsf::var::import ::nsf::setvar => ::nsf::var::set - improved misleading error message for method modifiers "public" and "protected", as well as for "class-object" - extended regression test - serializer: catch for object-level alias apparently not needed anymore (search for ns_cache_flush) - silence compilation when compiled without DTrace - nx: * removed methods ::nx::Class.alloc and ::nx::Class.dealloc from predefined method-set * added definitions such that these methods can be loaded via ::nsf::method::require ::nx::Class alloc ::nsf::method::require ::nx::Class dealloc * make explicit that "method ... require" returns a method-handle * removed misleading reference in error message, when a class-spefic method was called on an object; solution is somewhat dangerous for potentially unknown client data * added regression tests * removed methods ::nx::Class.recreate and ::nx::Class.recreate from predefined method-set ::nx::Object.configure from predefined method-set * added definitions such that these methods can be loaded via ::nsf::method::require ::nx::Class recreate ::nsf::method::require ::nx::Object configure nsf: * added CallDirectly() wrapper for calls to "init" * reactivated "configure", since we plan to use it more prominently * added a configure flag for "class" * removed method "class" (should be used via "/obj/ configure -class ...") * removed method residualargs from nx * added C-implemented method "init" for orthogonality * allow specification of system method handles in nsf::createobjectsystem * automatically register alias, when system-method handle was provided and a same-named method is defined * provided a fast path implementation for "defaultmethod" * provided default system methods for "init", "defaultmethod" and "unknown" * provided handles for system methods "alloc", "dealloc", "recreate", and "defaultmethod" * strip in dispatch invocations of "unknown" potential leading colons * removed c-level implementation of init again, since scripted one can be used now as well in registration of createobjectsystem * reduced verbosity * added definitions such that these methods can be loaded via ::nsf::method::require ::nx::Object unknown * added methods ::nsf::methods::object::class and ::nsf::methods::class::superclass in order to make faster and nicer looking objectparameters (compared with forwarders) * nx: changed parameter -class to use ::nsf::methods::object::class * ns: fixed chicken egg problem of method objectparameter needing objectparameter by creating/destroying slot Class::slot::dummy; otherwise default values for slots would not be available * reduced verbosity of parameter forwarder * Hopefully the last big naming change: Instead of writing "C class-object method foo {} {...}" one can write now "C class method foo {} {...}" to define a class method named "foo" for class "C". This naming change became possible by defining XOTcl's "class" (and "superclass") as object parameter only. To change a class of an object o, one has to use "o configure -class NEWCLASS". The term "object-class" looks alien to language beginners, the term "class" is much more straightforward. Changing classes or superclasses is seldom used by typical application programs. For already existing nx scripts, changing "object-class" into class should be straightforward. * various documentation updates (migration guide, nx tutorial) * fixed bad interaction between filter and parameter alias * some documentation/todo updates * fix compilation for tcl-head in fossil * deactivate coro regression test, since it is apparently broken for tcl-head in fossil (stack frame seems to be lost after a yield) * make sure to create the cmds for objects with Tcl_NRCreateCommand() to choose trampoline-path in the trunk version of Tcl * The newest trunk version of Tcl in fossil has TclStackFree() and TclStackAlloc() removed We had to substitute this functions. Unfortunately, the lifetime of the strack structures has changed, so we had shuffle some internals around. - nsf.c: remove unnecessary test when compiled without NRE - nsf.c: make sure, validCscPtr is always initialized - tested all regression tests with valgrind against tcl-trunk - gentclAPI.tcl: * renamed "nsfCmd" to simply "cmd", since the code can generate arbitrary tcl commands * allow type "int" in the .decl files - nsf.c * move several functions from "static" to "external" to make the code generator usable for submodules as well - added flag ?-type ...? to "info lookup slots" - made all useful converters external symbols - added flag ?-type ...? to "info slots" - delete accessor when slot is destroyed - added pattern to "info slots" - added to "info slot /attName/" - Fixed dispatch of defaultmethod for ensemble methods - Added compile flag DISPATCH_ALWAYS_DEFINED_METHODS (deactivated). So far, nx just uses dispatch on overloads or filters, but not on defines (possible to call e.g. "destroy" from a script, but internally the direct dispatch is used, as long there is no overload). The compileflag would force to use the slower dispatch always. - Extended regression test - Improve locality - Let "info slot" return the slot object - nx::mongo: Initial commit of the experimental mongoDB interface for nx - nx.tcl: fix handling of arg in converter - nx::mongo: * first step towards handling embedded objects * one more example script: example-nx-bi.tcl - nsf:c: fix dispatch of setter without current method - extended regression tests - nsf.c: added nsf::var::unset (provided so far just var::set) - nx::mongo: * added mongo::count * obtain _id from mongo::insert * added mongo::Object.delete method for embedded and non-embedded objects * handling of mongo-embedded objects when destroying objects * simple bson pretty print function * extended examples * handle fetch of embedded objects * added method count for mongo mapped classes * improve documentation * added handling of bson types for timestamps and dates * provide setup based on mongo_db, mongo_collection and mongo_ns * implemented type "reference" similar to "embedded" * all referenced objects are for the time being auto-dereferenced * new method "show" for mongo mapped classes * added two new example files example-nx-reference-many.tcl and example-nx-reference-one.tcl * replaced "arg" by "type" in spec for mongo attributes to make spec less strange - nsf.c: made potentially unknown clientData more safe (error message, when something is passed via clientData to a method expecting an object/class as clientData). - renamed NsfNoDispatchObjectError() to NsfDispatchClientDataError(), extended interface - Makefile.in: fixed name methods.test - nsf: renamed nsf::isobject to nsf::object::exists - nsf: renamed nsf::qualify to nsf::object::qualify - nx.tcl: added support for positional object parameter and removed special handling of the last argument for the init block; added attributes "position" and "positional" to ObjectParameterSlots, removed last argument of method "objectparameter" - nx.tcl: simplified createBootstrapAttributeSlots (second round of default value setting seems not necessary) - nx.tcl: some cleanup - test.tcl: * don't export Test per-default * define Test as nx::Test * make Test parameter count 1 the default, change to higher numbers where needed - nsfmongo.c: * upgrade to newest c-driver (version 0.3) from git. * support connection to replica sets * support attribute selection lists for ::mongo::query (positive and negative selection) - nx-mango.tcl: * support for unique indices * support for query operators "in" and "all" - extended migration guide (introduction, feature lists, etc.) - serializer: * prefix warnings to ease tracking of warnings * some cleanup for handling aliased methods - nsf.c: * moved implementation of ::nsf::method::delete to C * produce same error messages when methods are delete via nsf::method::delete and nsf::method::create {} {} * Prohibit deletion of methods during shutdown. Otherwise when destructors delete methods, some other destructors depending on these methods will fail. Cleanup deletes all methods anyway. * Provided alternative (faster) way of dispatching nsf::procs (can be tured off with NSF_INVOKE_SHADOWED_TRADITIONAL) * renamed NsfMethodCmd() into NsfMethodCreateCmd() for consistency * nsf works with OpenACS again (requires new nstrace.tcl, aolserver-openacs.tcl, and 01-debug-procs.tcl). - nsf.c: * factor out NsfClassListAddPerClassMixins() * factor out NsfClassListFind() * let result of "cls info heritage" return per-class mixins as well, otherwise it would be useless, since "cls info superclass -closure" would return the same * replaced loops with NsfClassListFind() - nsf.c: * handle direct dispatches for aliased methods * new generalized error message: NsfNoCurrentObjectError() - nx.tcl: replace loops ::nsf::methods::[object|class]::* by explicit command registrations - nsf.c: * added NsfClassListNoDup() to allow just single inserts * added NsfClassListPrint() for debugging * info heritage returns no duplicates * added prototype for NsfNoCurrentObjectError() * report "no current object" when no object is passed to a method. * code cleanup - extended regression test - nsf.c: * ensure that explicit per-object-mixins are kept at the front in "info heritage" order and in "info precedence" when classes are added as POMs and PCMs * extended regression test - nsf.c: * renamed old flag "-order" of "info mixin classes" to "-heritage" since it computes same heritage as in "info heritage" (but potentially for a list of classes) * added compatibility layer for xotcl2 * added lost option "-heritage" to "/cls/ info mixin classes" (was only there for "/obj/ info mixin classes") * extended regression test - nsf.c * first version of c-bases "info slots" for classes * switch "-closure" just for class info method * added switch "-source" to "info slots -closure" and "info lookup slots" (similar to "info lookup methods") * extended regression test * base objectparameter on "info slots" - nsf.c * added "pattern" to "info lookup slots" * added "pattern" to "info slots" * extended regression test - nx.tcl, xotcl2.tcl: removed unsafe {*}$pattern - added: "info slot handle /name/" "info slot parameter /name/" - nsf.c: Since the method "objectparameter" is just based on the class (and object parameters are invalidates as well over the class), we moved the method from obj to class to avoid potential confusions - nsf:c * added C-implemented class level method "info objectparameter list|name|parameter|parametersyntax" * added enum to handle different print styles for parameters * renamed ParamDefsList() to ParamDefsNames(), added true ParamDefsList() - nx.tcl: * removed "info slot handle" and "info slot parameter" * added "info parameter spec", "info parameter list", "info parameter name", and "info parameter syntax" * extended regression test - nsf.c: * Added argument "-reg-object" to ::nsf::method::create to distinguish between a registration and a definition object for ensemble methods, similar as on other places. If no reg-object is provided, it is the same as the definition object. One should take care that the registration objects are deleted after the definition objects, which is the case for the usages of the reg-objects in nx/xotcl. * The namespaces within plain scripted methods and scripted ensemble objects are now the same. * Extended regression test * Code cleanup and documentation - nx.tcl: * added method "delete" to delete methods and attributes * extended regression test - nsf.c: removed all but one occurrence of Tcl_AppendElement() - nsf.c: removed all occurrences of Tcl_AppendElement() - nsf.c: passed around resultObj explicitly - nsf.c: fix and document GetMatchObject() - extend regression test - nx.tcl: * splitted method "delete" into a "delete method" and "delete attribute" * remove flag "-per-object" in method "delete" * delete per-object methods of classes with "/cls/ class delete method name" and "/cls/ class delete attribute name" * extended regression test - added test cases for "info slots" - nsf.c: * handling of same named per-object and provided slots for Class objects * per-object slots are saved now under ::per-object-slot::* * returning correct results when per-object slots are used * removed obsolete functions: NsfObjectListFree(), NsfObjectListAdd() * removed obsolete type NsfObjects * transformed ComputeSlotObjects() into a more generic AddSlotObjects() that can handle per-object slots as well - nx.tcl: * generalized slot object handling. * extended regression test - xotcl2:tcl * made "info heritage" in xotcl2 compatible with xotcl1 * fixed "info slots" in xotcl2 * extended regression test - nsf.c: require NSF_IS_SLOT_CONTAINER for slot-container - nx.tcl: ne proc ::nx::setSlotContainerProperties to handle slot container properties in a uniform way - reduce verbosity - nx.tcl: improve code documentation -nsf.c: added c-implementation of "/object/ info slots" to share implementation details and reduce scattering - migration guide * included change in "info heritage" * included "info slots" * included "info parameter" * included "delete method" * included "delete attribute" - nsf.c: NsfRelationCmd() returns per default list of actual values, therefore mixin add|... return now as well the actual values - nx.tcl: added "info parameter slot" to return slotobject(s) - added "info parameter slot" to migration guide - extended regression test - nsf.c: changes to use trunk-branch with and without TclStackAlloc() - migration-guide: add third level to toc - fix regression test for 8.6 to use nx prefix - nsf.c: added cmd "::nsd::method::registered /handle/" that returns the object on which the method identified by the handle was registered, or empty. - extended regression test - bring defined commands in the source code in alphabetical order - generate interface for NsfUnsetUnknownArgsCmd() - delete some obsolete code - added "link" from 2.4 (parameters) to "info parameters" in migration guide - remove alias warnings from gcc under ubuntu (4.2.4) - nsf.c: fixed possible crash in tcl8.6 with nsfprocs, still one inconsistency - nsf.c: fixed bad interaction between mixins and ensembles in tcl8.6 - nsf.c: document two more functions - nsf.c: removed unneeded casts to (ClientData) - nsf.c: generalized disposition handling (forward, alias, initcmd) for object parameter * disposition is now an option for object parameters rather than than an own type. Therefore, one can check the arguments passed to the disposition cases * changed specification of name of method from arg= to method= * this way "type" info in "info parameter syntax" is handled automatically - nsf.c: * added a new converter for converting mixins with guards (named mixinspec) * used mixinspec in nx.tcl and xotcl2.tcl * extended nx regression test. * added profiling support for nsf::proc when NSF_INVOKE_SHADOWED_TRADITIONAL is turned off. - removal of unneeded flags "-incontext" and "-nomixins" from * /obj/ info methods * /cls/ info methods These flags are correct for "info lookup", but unneeded for "info methods" - cleanup of ListDefinedMethods() - nsf.c: use NsfObjectRefCountIncr() instead of object->refCount++ - nsf.c: fix small memory leak for nsf::is in error cases - renamed converter from "mixinspec" to "mixinreg" - Use mixinregObjType as well in NsfRelationCmd(), so this is the only place, where mixin and guards are processed. - Since the type converter converts Tcl-Objs, we have less context information (e.g. we have no base class, on which we can decide to call e.g. __unknown on on of the objects systems). - because of the point above, i removed ::xotcl::Class->__unknown and ::nx::Class->__unknown in favor of a global proc ::nsf::unknown, for which unknown handlers can be registered - GetClassFromObj() receives as last argument "withUnknown" instead of baseClass to indicate, when unknown should be tried. - new function NsfCallUnknownHandler() - moved mixin reg type converter to a new file (nsfObj.c) - added NsfFilterregObjType, to provide a converter for filter registration similar to mixin registrations - replaced dummy dupIntRepProc and updateStringProc in nsfObj.c by NULL - fixed memory leak in "... info mixin classes -heritage" - added tests for integer, wideinteger and bignums - added value checker type int32 (similar to "string is integer") and changed value checker "integer" to accept all integers - library/mongodb: * use type int32 * updated to new nx/nsf interfaces * updated for mongo-c-driver post 0.3 (supporting result MONGO_OK for mongo_cursor_next) * factored out "mongo cond" from "mongo query" - fixing part of the memory leak introduced for bignum handling above (for some unknown reasons, we see crashes from mp_clear) - extend regression test - improve bignum conversion handling further - found memory leak in tcl - provided nicer registration and inspection interface for unknown handlers - added documentation for unknown handlers in tutorial - cleanup of __unknown - added handling for provided arguments to positional object parameters with disposition alias and forward - provided better error messages for unknown parameter options - provided error messages for multiple disposition parameters - reduce redundancy by introducing macro NSF_ARG_METHOD_INVOCATION - gentclAPI.tcl: * renamed "nrArgs" to "nrParams" * switched default for nrargs from 0 to 1 - gentclAPI.decls: * added "-nrargs 0" where needed -nsf.c: * switched parameter logic from default for nrargs from 0 to 1 * simplified logic to detect additional arguments in argument parser * improved error message for missing required argument - regression tests: * added disposition.test * extended regression test - xotcl2: use filterreg instead of plain arg for registration of filters - nsf.c: * improved source code documentation * added parameter option "args" in order to get eventually rid of hard-wired call to residualargs. * improved a few error messages * fixed object parameters consisting only of plain parameters (previously, no parameters were returned in this case, e.g. for method parameters; but object parameter code depends on it) - extended and updated regression tests - nsf.c: * added refcounting to parameter definitions (needed, when aliased object parameter redefined the actual objectparameters) * removed hardcoded call to remaining args * switched implementation of xotcl2 to use object parameter with parameter option "args" * removed residualargs from object system definition * extended regression test - nsf.c: * Don't output non-consuming procs (which are always called) via parametersyntax (shows, what a user can input) * additional command ::nsf::object::initialized to check whether an object is already initialized * new function DispatchInitMethod() similar to DispatchDefaultMethod() * let residualargs call init directly instead of doing it the indirect way * provided ability to call init with object parameters at arbitrary times * switch from Tcl_ObjCmdProc style interface (ClientData first) to a C style interface for DispatchDefaultMethod(), DispatchUnknownMethod() * bring cmd definitions for nsf::object in right order - extended regression test - genAPI.decls and nsf.c: bring cmds in same order - nsf.c: align naming conventions - renamed gentclAPI.decls to nsfAPI.decls - renamed tclAPI.h to nsfAPI.h - added nsf.m4 to git for the time being - mongodb: * added preliminary gridfs interface * refactored some code * added new types for "gridfs" and "gridfile" * added new example file example-nsf-gridfs.tcl - nsf.c: no good reason to disallow user defined types for for alias, forward or initcmd - library/nx/nx-zip.tcl: added a zip file generator as package - nsf.c: * new file nsfPointer.c * generic new value checker ConvertToPointer to handle c-level conversions (which can be registered from nsf extensions) * extern defined interface for the pointer converter: Nsf_PointerTypeLookup(), Nsf_PointerTypeRegister(), Nsf_PointerAdd(), Nsf_PointerDelete(), Nsf_PointerInit(), Nsf_PointerExit(). - library mongodb * changed mongoAPI to pointer converter interface - C-code generator: * additional parameter "-withObj" to allow passing of internal representation and the according TclObj * * c-implemented methods: report types in "info parameter" for more builtin types. * use "-withObj" in mongodb interface * adapted regression test - mongodb interface: * mongo::gridfile::seek: added a seek command for gridfiles * added example for the low-level interface to show how to access gridfs via the plain mongodb interface, how to add some additional metadata (e.g. dublin core meta data) and how to retrieve this via the gridfile interface - nsf.c: * report only fully initialized slot objects via "info slots" to avoid chicken-egg problem during method "objectparameter" * added flag -array to ::nsf::var::exists to check, whether the variable is an array (to avoid "o eval {array exists ...}" in the serializer. * provided flags to VarExists instead of multiple args * don't add new pointer entries in Nsf_PointerTypeLookup() - preliminary fix for volatile called through residual args - new regression test file volatile.test - fix the comparison with "unknown" in residual args - provide backward compatibility for unknown method (when method contains spaces). - some minor cleanup - extended regression test - fix typos in string "unknown" - reduce verbosity - reduce scope of variables - renamed ObjectParameterSlot attribute from nosetter => accessor (positive formulation) - nsf.c: make sure to always initialize variables - first draft of separation of attribute -> variable + accessor - library/mongodb: * updated to current interface in git HEAD * added flag timeout to mongo::connect * added new index options "-sparse" and "-background" - regularized more nsf::* names: renamed "nsf::createobjectsystem" => "nsf::objectsystem::create" renamed "nsf::unknown" => "nsf::object::unknown" renamed "nsf::dispatch" => "nsf::object::dispatch" - generalized "nsf::object::initialized" to nsf::object::property objectName initialized|class|rootmetaclass|rootclass|slotcontainer - nx: factor out method createFromParameterSpec - method variable: * check default value * added shortcut, when no slot object is needed * extended regression test - nx::Attribute: changed method 'checkInstVar' to 'setCheckedInstVar' - set only fresh variables via per-object method "variable" and "attribute" - added flag -noncomplain to per-object method "variable" and "attribute" - extended regression test - added support for "class variable" - added tests for "variable" + multiplicity and "class variable" - provide error message, when method variable is a noop (e.g. no value provided and no accessor is wanted) - added tests for object specific "variable" and "attribute + application defined value checker - library/mongodb: * updated to current interface in git HEAD - nx.tcl: added switch "incremental" to "variable" and "attribute" - added regression test - nsf.c: improve performance (branch prediction) by using likely/unlikely macros for gcc - nx.tcl: * added support for "variable" on the class-level * added flag "noconfig" to object parameter options * parameters with "noconfig" are omitted in "info parameter syntax" and "info parameter list" * used switches for all configurable boolean options for "variable" and "attribute" * regularized the interface of "variable" and "attribute" * extended regression test - fixed a possible crash in the ExitHandler: Object create o {exit -1} - nsf.c: * added flag "-array" to nsf::var::set such we have now "::nsf::var::set ?-array? object varName ?value?" With "-array", nsf::var::set behaves like "array get" or "array set" (on instance variables) * use "::nsf::var::set -array" in serializer symmetrically to scalar case * extended regression test - nsf.c: * fixing compilation with NSF_MEM_COUNT * New function DeleteProcsAndVars() to trigger deletion of ParamDefs (fixes a small memory leak); * improved comments * improved INCR_REF_COUNT/DECR_REF_COUNT for easier tracking of potential refcount errors * added macros DECR_REF_COUNT2() and INCR_REF_COUNT2() for easing the association of refcounts to locations in the code by providing names for refcounts. * fixed a refcount bug for valueObjs in non-NRE-enabled versions in the argument vector of scripted methods (found via INCR_REF_COUNT2/DECR_REF_COUNT2) - nsf.c: * refined refcounting debugging * fixed various refcounting bugs, especially in error cases. * added explicit INCR_REF_COUNTs on Tcl_Objs with 0-refCount to ease debugging * added explicit names for refcounting for "paramDefsObj" * added explicit names for refcounting for "freeList" (for forwarders) * provide debug-refcounts for "NSNamespace" * provide debug-refcounts for "nextArgumentVector" nsf.c: * change DeleteProcsAndVars, such it deletes procs and vars explicitly in all namespaces * added more sanity checks for parameterContexts, testing in ParseContextRelease() in DEBUG mode * provide debug-refcounts for "pcPtr.objv" * provide debug-refcounts for "pcPtr.clientData" nsf.c: * provide debug-refcounts for "class.activationCount" * provide debug-refcounts for "object.activationCount" * deactivated CHECK_ACTIVATION_COUNTS oer default * tested refcounts with Tcl 8.6b2, found bug in Tcl and submitted patch to sourceforge http://sourceforge.net/tracker/?func=detail&aid=3383616&group_id=10894&atid=110894 - nsf.c: * fixed a bug in "info parameter list|... name" when the named parameter is not found (returns now empty, before, it was returning the full list). * added flag "-nocomplain" to nsf::var::unset - nx.tcl * added "delete variable" analogous to "delete attribute" * unset instance variable for object-level "delete attribute" * extended regression test - library/mongodb: * updated to current interface in git HEAD (resp. "git checkout v0.4") - nx.tcl: * fixed copy for object created with new * copy returns now the fully qualified name of the copied object * extended regression test - library/mongodb:updated to current interface in git HEAD - nx.tcl: implemented copy without a provided name. If argument of copy is omitted, the copied object is created with a fresh name (i.e. created with the method "new"). Example set x [o copy] - extended regression test - nx.tcl: * added protected and public for "require method" The following forms are now valid "... require public method" "... require protected method" "... require method" "... require public class method" "... require protected class method" "... require class method" * extended regression test - library/mongodb: * replaced NsfMongoGetHostPort() with the newly available function mongo_parse_host() * updated error codes according to git head * factored out mapping of error code to string - nsf.c: added cmd __db_compile_epoch for compile-epoch introspection - Mystery solved, why in the script below the interp>compileEpoch is incremented, when D is redefined, but in other cases not. In the script below the method D.init is compiled by tcl, since it has a trivial body. Therefore, a redefinition of D will remove this compiled body and all its potential usages. Therefore the interp->epoch is incremented. If the body is e.g. "return", the epoch is not incremented (observed with Tcl 8.5.10) ================================================= # -*- Tcl -*- package require XOTcl; namespace import -force ::xotcl::* package require nx::test; namespace import nx::Test Class C; C c Class D -superclass C D instproc init args {} Test new \ -count 100 \ -pre { puts stderr ===create-D;Class create D; puts stderr ===D-created; Class E; Class E1; Class X -instmixin {D E E1}} \ -cmd {X info instmixin ::E*} \ -expected {::E ::E1} \ -post {foreach o {D E E1 X} {$o destroy}} Test new \ -count 100 \ -pre {Class D; Class E; Class X -instmixin {D E}} \ -cmd {X info instmixin ::E*} \ -expected {::E} \ -post {foreach o {D E X} {$o destroy}} Test run; exit ================================================= - nsf.c: * enabled MEM_COUNT debugging for multi-threaded apps. We collect the MEM_COUNT statistics now per interp. Therefore, we have to pass around "interp" in case where alloc() and free() or refCount functions are used (textually, a big change) * verified, that nsf runs clean in aolserver/naviserver (all INCR_REF_COUNTS all balanced) * added paramPtr->name to MEM_COUNT tracing * renamed NEW_STRING to STRING_NEW * added STRING_FREE, calling MEM_COUNT macros * checked all ckfree in nsf.c, everything allocated is covered by the MEM_COUNT macros - nsf.c: fixed autoname problem with code from tcl trunk - fixed book-keeping for TclNamespace refcounting such that now alias.test, destroy.test and test.xotcl run now clean, 2 test are still open with tcl 8.5.10 (contains.test and xotcomm.test) - documented functions in nsfTrace.c - updated next-tutorial to the current naming conventions - added tests for using submethod handles - changed Stack example in tutorial from constructor to :variable - allow just valid specs for :attribute and :variable methods - improved error message for invalid parameter specs (with leading colons) - extended regression test - library/mongodb:updated to current interface in git HEAD -nsf.c: * move to greedy assert to an inner scope ("info method ...") * allow testwise "switch" as object parameter (when it is used, accessors are deactivated for this attribute) * extended regression test - nx.tcl: extended object-parameter "switch" implementation: now, accessors of type boolean are created, when type "switch" is used. - nsf.c: implemented "... info method origin ..." which returns the implementation handle (in contrast to the registration handle) of a method. - nx.tcl * renamed "attribute" to "property" * renamed "defaultAttributeCallProtection" to "defaultPropertyCallProtection" * renamed "nx::Attribute" to ""nx::VariableSlot" * renamed "BootStrapAttributeSlot" to "BootStrapVariableSlot" * renamed "createBootstrapAttributeSlots" to "createBootstrapVariableSlots" * removed method attributes * implemented old "attributes" definition in xotcl2 as method "parameter" - nx.tcl * renamed "info parameter name" to "info parameter names" (since it returns a list of names) * renamed "info parameter name" to "info parameter names" (since it returns a list of names) * renamed "info slots" to "info slot objects" * additional method "info slot definition" * additional method "info slot name" * additional method "info properties" (alias to "info slot definition") * removed "info parameter slot" * use term "noaccessor" and "noconfig" to deactivate accessors or object-parameters in property definitions * don't show slots with noconfig in "info parameter names" * don't show slots with noconfig in "info parameter definition" * renamed slot property "configparam" to "config" * renamed "::nsf::methods::class::info::slots" to "::nsf::methods::class::info::slotobjects" * additional public method ObjectParameterSlot.getPropertyDefinition * updated and extended regression test - nx.tcl: * added "/obj/ info slot definition" * added "/obj/ info slot name" * added "/obj/ info properties" (alias to "/obj/ info slot definition") * extended regression test - nx.tcl: * added parameter option incremental for "property" and "variable" * removed the nonpos argument "-incremental" from "property" and "variable" * adapted regression test for these cases - new folder example-scripts * Added 8 of the rosetta examples and one classical OTcl example * all examples are tested via regression test * all examples are pretty-printed via asciidoc * added example rosetta-abstract-type.tcl * added example rosetta-unknown-method.tcl * added ./apps/utils/source-doc-beautifier.tcl * fixed the file-handle output/formatting in rosetta-serialization.tcl; using proc "!" - nsf.c: * fixed next path computation in cases where command handles are used to refer to methods in the current mixin order. * extended regression test - nx.tcl: * made "/cls/ class ..." using ensemble methods and therefore extensible. * This introduces some definition order dependencies in nx.tcl and some redundancy ("class filter" and "class mixin"), but maybe this can be eliminated. - nsf.c: * fixed "nsf::my -local ..." (never worked in nsf) * added regression test - documenting current behavior * test method-handle + next + dispatch (unwanted) * test "my -local" vs my + method handle * test "my -local" vs dispatch + method handle - nsf.c: * added preliminary/minimal "private" support * private can be called via "my -local", direct dispatches are forbidden, ignored in mixins and next; * extended regression test * fixed name path in unknown called from ensemble methods (erroneous colon could show up) * added -system flag to: - ordinary dispatch (e.g. "o1 -system info vars") - nsf::object::dispatch with plain methodName - nsf::my (mutual exclusive with -local) - nsf.c: * change mem-count statistics from per-interp to per-thread * generalized GetObjectFromCmdTable() to ReverseLookupCmdFromCmdTable() * changed GetObjectScreenedByCmdName() to GetHiddenObjectFromCmd() * modularized interp.test to locate potential problems faster * partly simplified interp.test syntactically * deactivated a few tests in interp.test for the time being (runs commands after finalize) * re-established assertion checking for deleted cmds in cmd lists * added flag "-keepvars" to nsf::finalize for handling cases in interp.test * reactivated tests and simplified interp.test - disposition.test: * remove/check exit (see comments in the file) * handle exit from eval/inticmd with proper refcounts - nsf.c: * integrated "-local" and fully qualified handling with ObjectDispatch to ensure proper behavior of mixins/next etc. * added "/obj/ -local ..." similar to "/obj/ -system ..." * added "nsf::object::dispatch /obj/ -local ..." similar to "/obj/ -local ..." * extended regression test (next from -local, fully qualified names, private methods, "...dispatch -local") * provide error message for "/obj/ -system" - nx.tcl: * make calls from "protected", "public", and "private" system calls, such that "obj -system protected method foo {} ..." works, even when obj has a method named "method". * extended regression test - nsf.c: * added "/obj/ -intrinsic ..." similar to "/obj/ -system ..." * added "nsf::my /obj/ -intrinsic ..." similar to "/obj/ -intrinsic ..." * added "nsf::object::dispatch /obj/ -intrinsic ..." similar to "/obj/ -intrinsic ..." * extended regression test - nsf.c: * simplified permission handling * made private/protected mutual exclusive * extended regression test for private methods * per-thread MEM_COUNT tested with aolserver/naviserver * removed INTERP macros for MEM_COUNT (since we use now per-thread tables instead of per-interp tables as in the first implementation) * re-enabled transparency of private method in mixins * added transparency for per-object private methods * extended regression test - nsf.c: * allow protected and private methods to be used as filters * added regression tests * some cleanup in regression tests * added support for calling private methods via -local and filters * extended regression test for private + filters * removed "-local", "-system" and "-intrinsic" from plain dispatch (like e.g. "o1 -system method") * removed flag "-local" from nsf::object::dispatch * made nsf::my and nsf::object::dispatch available in the nx namespace - nsf.c: * factored out CmdIsNsfObject() for NRE handling with slave interpreters. * added flag ZSE_NRE_PROC for using nreProc instead of objProc - nsf.c * implemented NsfObjDispatchNRE and NsfObjDispatch * this fixed all issues of tcl8.6 and interp.test (xocomm still hangs in 8.6) - nsf.c: * "private" implies now "protected". This means, setting "private" sets as well "protected", unsetting "protected" unsets "private" * make sure the "... method definition" of private methods is returned as "private" * extended regression test - nsf.c: * removed warning about resetting cmd to 0 for private method invocations. - fixed interp.test for tcl 8.6 - fixed xocomm.test for tcl 8.6 - fixed mem_count on xocomm.test (was 26 / 26) - nsf.c: small performance improvements - nsf.c: experimental implementation of ::nsf::method::dispatch - renamed "nsf::method::dispatch" to "nsf::directdispatch" - renamed "nsf::object::dispatch" to "nsf::dispatch" - nsf.c: * added permissible value "private" to flag "-callprotection" for "info lookup method" and "info methods". * extended regression test - doc: * fixed naming of "attribute" in migration guide * added "private" to migration guide * some textual improvements in migration guide * fixed spacing in documentation * fixed documentation of "info slot objects", "info slot names", "info slot definition" - nx: * added namespace "nx::internal" * delete procs via "rename to empty" instead of "defining procs with empty argumentes and body" * provided "-properties" as a replacement for -attributes, but without magic variable * extended regression test * changed "info slot name" to "info slot names" (like "info parameter names") - library/lib/pp.tcl: improved handling of placeholders - doc: * added section about ":variable" to the tutorial * fixed a few outdated places in tutorial - nsf.c: * reduce eagerness of methodName computation in ResolveMethodName() and GetRegObject() * reduce eagerness of DString computation in ResolveMethodName() * use conditional assignments in ResolveMethodName() * make use of Tcl_Obj type in ResolveMethodName() to reduce number of string operations - gentclAPI.tcl: * added option handling for every cmd/method/... * added option "-nxdoc" for outputting an index to ease maintenance in nxdoc - nsf.nxd: * adapted to new naming * tend to use fully qualified names (make maintenance easier) * bring cmds to an alphabetical order (make maintenance easier) * add optical separators between doc items to ease reading - fixed mem_count on contains.test - nsf.c: * minor cleanup * added regression tests * fixed recreation of object alias with a alias to a different cmd - xotcl2.tcl: * added a backward compatible ::xotcl::alias method - Switched to the tcl numbering scheme. Version is now 2.0a1 Warning: From the Tcl point of view, this is a regression in numbering relative to the previous 2.0.0. Make sure to remove old releases from you installation path like e.g. rm -rf /usr/local/lib/libnsf2.0.0* /usr/local/lib/nsf2.0.0 - use same version numbers in nsf, nx and xotcl2 - library/lib/nx-zip.tcl: refactored implementation, improved utf-8 file-name handling (which is a mess in pkzip) - configure options: * improved and extended configure options to reduce necessity to switch features on and off in the nsf.h. Optional Features: --enable-profile build nsf with profile support (default disabled) --enable-memcount=yes|trace build nsf with memcount debug support (default disabled) --enable-development build nsf with development support (assertion checking, etc.; default disabled) Optional Packages: --with-dtrace build nsf with DTrace (default: without) - nsf.c: * report configuration options via "parray nsf::config" sample output % parray nsf::config nsf::config(development) = 1 nsf::config(dtrace) = 0 nsf::config(memcount) = 0 nsf::config(memtrace) = 0 nsf::config(profile) = 0 - build-environment: * make configure.in Makefile.in more in line with the TEA sample app (removing leftovers from prior versions of TEA) * remove GNU-Makefile-isms from Makefile.in - nsf.c: * provide an intermediary fix for the final memcount problem of elements in on the iPtr->errorStack * improve iPtr cleanup for memcount debugging - added configure option: enable-assertions (default on) - nsf.c: * allowed to call ":" like "my" or "self" Object create o o public method bar2 {} {return bar2-[: foo]} o public method bar5 {} {return [self]::bar5} o public method bar6 {} {return [:]::bar6} * extended regression test - nx.tcl: moved "properties" from nx::Class to nx::Object - nsf.c: make ":" a full equivalent vor nsf::my (i.e. support -local, -system and -intrinsic) - extend regression test nsf.c: - reform of argument parse. new parser uses NsfFlagObjType to reuse earlier parse results. Improved speed for for methods with primitive bodies: 5%-25%. - added regression tests for argument parsing - nsf.c - added experimental parameter option noleadingdash - additional regression test file method-parameter.test - provide selective error messages for unknown nonpos args nsf.c: - reform of method lookup. new code uses NsfInstanceMethodObjType and NsfObjectMethodObjType to reuse earlier lookup results. Improved speed for for methods with primitive bodies (over version before argument parse reform: 10%-43%. - additional compile-time option: METHOD_OBJECT_TRACE - experimentation version of unknown handler for non-pos args - extending regression test nsf.c: - moved methodEpochCounters from global vars to the interp state to improve reuse in multi threaded apps - separated objectMethodEpoch and instanceMethodEpoch - bump version number to 2.0a2 nsf.c: - new cmd for debugging: nsf::__db_show_obj - added MethodDupInternalRep() and FlagDupInternalRep() since they appear to be required in Tcl 8.6b2. tests: - added "package prefer latest" to avoid confusions of alpha and beta releases with install versions nsf.c: - added MixinregDupInternalRep() and FilterregDupInternalRep - perform more eager invalidation on objectMethodEpochs - cleanup on nsfObj.c nsf.c: - don't convert obj types tclCmdName and parsedVarNameType to instanceMethodObjType nx: added traits package noleadingdash handling: - doc: added "noleadingdash" to UML class diagram - nsf.c: added error message, when "noleadingdash" is used on non-positional parameters - nsf.c: use same logic for "noleadingdash" to "value in argument" - nsf.c: deactivated rudimentary unknown handler non nonpos args for the time being - nx.tcl: added handling of parameter option "noleadingdash" in objectParameterSlots - doc: * integrated ::nx::doc::make with Makefile.in (provide shell calls and, targets and dependencies) * provided a different flag for the generation of the documentation (-develop, .... or -final) to show/hide it. * separated entries for methods and hooks (can't be called if not defined)? hooks: * recreate should only be called internally, similarly "init" etc. * __unknown unknown is a hook for Object but a method for Class - fixed strange ref-counting bug in 8.6b2 bug-is-86.tcl where 2 ref-counted items are not freed (value:class, issued from nx.tcl around line 120). Compile with DEBUG86B2 for more info ================================================= # -*- Tcl -*- package req nx package require nx::test nx::Test case ensemble-next-with-colon-prefix { nx::Object create obj { :public method foo {} { return [:info class] } #:public method bar {} { return [:info] } :method info {} {;} } ? {obj foo} {wrong # args: should be ":info"} } ================================================= - nsf.c: cleanup on DEBUG86B2 - nx.tcl: * do not namespace import my into ::nx * replace usages of "my" by colon invocations - doc: * extended method resolution section * documented invocation flags for colon - nsf.c: * add flags "-closure" and "-source" to "/cls/ info methods" (the cases for "/obj/ info methods" are already covered by "/obj/ info lookup methods") * extend regression test - nx-traits: * use "info methods -closure" instead of instantiating a class at trait-insertion time * added trait as package nx::callback - example scripts: added tk-mini and tk-horse-race - make "/object/ require" an ensemble method - traits: renamed "useTrait" into "require trait" - added per-object traits (and per-class-object traits) - added tk-spread and tk-locomotive to example scripts - altered default handling to honor side effects of aliased object parameters. This slows down evaluation a little. Side-effects from aliased parameters are discouraged, since the order of the evaluation should not matter of an declarative evaluation of the argument vector. - extended regression test - library/mongo: * updated interface to current nx * updated to mongo-c-driver 0.4 (current version) * The mongo c-driver does not allow to add DBRefs, since it refuses to accept field names with leading '$'. So we skip these tests for the time being. -nsf.c: - remove quadratic behavior when adding many classes (10 thousands) - deletion is still for huge number of classes quite slow. - nx.tcl, xotcl.tcl: * remove proc "register_system_slots" since 'rename register_system_slots ""' fails on aolserver * bump version number to 2.0b1 - nsf.c: extended "new": * nonpos-arg "-childof" accepts now a namespace (required an object before). Therefore, one can use now "... new -childof [namespace current]", even when the current namespace is not an object - nx.tcl: simplified ::nx::ScopedNew to ::nx::NsScopedNew: before it was necessary to create a new volatile class for every invocation of contains. - extended regression test - nx.tcl: don't use mixins in method "contains", but remap the new implementation. If there are ten thousands of classes defined, adding mixins to the root meta-class degrades linearly on the number of classes defined (the mixin paths for all classes must be invalidated). This might be a problem for frequent "contains" invocations. - bump version numbers for nx, xotcl2 and nsf to 2.0b2 - rename "info method handle /methodName/" into "info method registrationhandle /methodName/" - rename "info method origin /methodName/" into "info method definitionhandle /methodName/" - added "info method handle" as short form of "info method definitionhandle" - added "info method origin" to return the target of an alias (or empty) - update migration guide and tutorial - cleanup "//" in sources nsf.c: - adding method epoch incr to NsfAddObjectMethod() and NsfAddClassMethod() - added function CmdListAddSorted() to improve mixinof management serializer.tcl: - Use directdispatch to query existing traces without the need of an extra method. By this change, the serializer works in constant time independent on the number of existing objects. nsf.c: - reduce number of RUNTIME_STATE(interp) in favor of a variable. - make time of the definition of a method independent on the number of defined instances (unless, when filters are defined) nsf.c: - fixed bug with recursive aliases - extended regression test - updated and shorted README.aol and TODO - removed the following files from the repository. deleted: COMPILE deleted: COMPILE.win deleted: ChangeLog deleted: unix/xotcl.spec.in deleted: win/Makefile.vc These files should be probably added again at some later time, but need some rework. Old versions are still available from the 2.0.0-develop branch - Replaced hash-table for GetAllInstances() with a linear list. As a result, mass-destroy on exit is now much faster. Valgrind reports that the full circle of creating 100.000 objects and destroying it on exit became about 15% faster. - added additional argument adEnd to CmdListAdd() - renamed CmdListRemoveList() to CmdListFree() - improved code documentation - removed unneeded AddInstance() and RemoveInstance() - deactivated uncalled ReverseLookupCmdFromCmdTable() and GetHiddenObjectFromCmd() since apparently not needed any more nsf.c: - removed conditionals in AddInstance() and RemoveInstance() - dropped result from RemoveInstance() nsf.c: - added method NsfMethodNamePath() to compute the ensemble path in error messages - reduce verbosity - extended regression test - nsf.c: fix call of DispatchDefaultMethod() in cases it triggers an error for 8.6b - nx.tcl: give a slightly better error message in case the root-object of an ensemble is called directly nsf.c: - handle duplicates in the cmd-list during cleanup - Avoid duplicate entries in instance lists for diamond inheritance by maintaining the set of already processed entries in NsfClassInfoInstancesMethod1() and GetAllInstances(). - extended regression test - removed "namespace import" in object-system test nsf.c: - Reform of subclass/superclass handling. * unifying transitive subclass handling * localizing and documenting caching of subclass/superclass lists * eliminating repetitious computation of subclass lists * re-factored code, renamed some functions to better reflect their purpose * improved documentation - fixed a potential crash for class deletion triggering implicit deletions further deletions referencing the parent class - extended regression test nsf.c, nsf.h, nsfStack.c, nx.tcl, tcl-cool.tcl, xotcl2.tcl - fix spelling in comments - strip unneeded space - fixed potential crash when generating error message about argument usage when called without a call-stack - added regression test nsf.c: - change argument of IsMetaClass() to type *NsfObject - provide basic protection against most likely unintended deletion/overwriting of base classes. - extend regression test - fix typos - extend regression test to improve coverage - improve branch prediction - simplify macro handling with __WIN32__ - regroup some macro definitions - "info method": missing an option to return the "-returns specification". Also: "-returns" spec is not included in "info method definition". - simplified usage of ObjectName() and ClassName() macros (no caller parenthesis needed) - added experimental object property keepcallerself (currently only evaluated by aliased objects) - removed TODOs from keepcallerself in destroy.test; calls were truly recursive, behavior was correct. - Added experimental object property "allowmethoddispatch" for child-objects to be called from parent objects via method interface. Background: both, per-object methods and child objects are implemented via cmds in the same tcl namespace. Without special care, both are callable via the standard dispatch. Apparently, this is not always wanted. - handled allowmethoddispatch and keepcallerself in copy/move - set allowmethoddispatch per-default in XOTcl - removed visibility of objects with "allowmethoddispatch" false in "info methods" and "info search methods" - extended regression test - improve handling of multiple error messages in a single command - alias reform: instead of calling first an alias with a stack frame followed by the dispatched of the aliased cmd, resolve aliases internally in dispatch. This has the advantage that we do not have to ignore the "transparent" stack frame in some situations, and we have much less problems with the names of the aliased cmds (e.g. objects) in the introspection methods. Additionally, several problem cases disappeared from the regression test cases. In addition, the new approach is faster. - eliminating obsolete flag NSF_CSC_CALL_IS_TRANSPARENT - use alias-stubs for aliases pointing to objects. This allows us to distinguish between cases, where an object is dispatch-able due to the alias or due to allowmethoddispatch (when the object happens to be a subobject and has therefore its cmd in the same namespace). The semantics are now: - aliases to objects are always dispatch-able, no matter, how allowmethoddispatch is set. - direct sub-objects of objects are currently on dispatch-able when allowmethoddispatch is set. Note, that this could be seen as a method-property of the method-name, which could be made "private" as well to avoid such direct dispatches. - nsf.c: start all error messages with a lower case word for consistency and to follow closer to Tcl's conventions - deactivate for the time being allowmethoddispatch (make it behave always like true) - added instead new flag "perobjectdispatch" to make behavior of ensemble objects configurable. - The behavior for keepcallerself is currently only activated for the method-interface for object dispatch, since otherwise the following would be dangerous, since "o2 foo" would destroy o2 nx::Object create o1 nsf::object::property o1 keepcallerself true nx::Object create o2 { ::public method foo {} {o1 destroy} } o2 foo - fixed potential crash from method caching, when permissions on cmds are changed and become e.g. unresolvable - removed flag allowmethoddispatch, since behavior can be archived via private flag. - extended regression test - extend regression test for interactions between "keepcallerself" and "perobjectdispatch" - some minor cleanup - fixed NRE memory management (for Tcl 8.6) by refactoring alias handling - removed documentation about incompatibility to XOTcl1 in respect of the method interface for object invocations - doc fixed line-number handling locally - changed object->flags from "unsigned short" to "unsigned int" - reintroduced NSF_TCL_DELETE to address bug flagged from memdebug - extended regression test - Cleanup for compilation under MSC (avoid unsupported forward declaration of array) - further documentation of functions, better grouping of functions - use fixed array size for method_definitions for MSC - Don't export symbols in the general case just because of MSC/C89 compliance - Forward setting of object parameters to the slot object, when assign method is user-defined on the slot object - Cleanup and extend regression test - additional object parameter option "invokesetter" managed by nx.tcl This was necessary, since the previously implemented strategy called the setter whenever slot= was provided. This has the problem, that values could be converted twice (once by "configure", once by the setter method", which lead for the converter to a double refcounting on the value. - use Tcl's EXTERN macro instead of "extern" - treating incompatible forwarding to slot vs. slot option noaccessor - extended regression test - don't allow object creation to overwrite non-object cmds (e.g. procs) - don't allow method to overwrite child object - extended regression test - documented cmd overwrite protection feature as incompatibility with XOTcl 1 - documented dependencies between configure flags and feature activation cpp macros nsf.c: - Fixed a bad interaction between Tcl's apply (pushing lambda frames) and the variable resolvers. The variable resolver was not able to resolve variables, while the command resolver was still working correctly. - Extended regression test nsf.c: - added object parameter option "slotinitialize" - renamed object parameter option "invokesetter" -> "slotassign" - call slot.assign instead of setter of object - removed restriction on nosetter/invokesetter: nosetter can be used in connection with slotassign - added regression test for slot.initialize nsf.c: - pass property name to slot "initialize" method to conform with the interface to "assign", "get" ... (all these receive the property name as well) - allow slot "initialize" method to be protected (handled similarly to "init") - extended regression tests for yield - implemented "next" for ruby-like enumerators (each needs still more work) - tcl86.test: better implementation of method "each", cleanup and extension of enumerator tests - fix compilation when compiled without threads (many thanks for r.zaumseil for noting this). - protect serial generation for parameters via mutex - added compile macro NSF_STACKCHECK to provide stack monitoring/debugging (especially useful for multi threaded programs, where stack is more limited) - make ::nsf::log more robust for aolserver/naviserver, since ::ns_log is not always around when an output is needed - serializer: * make [::Serializer deepSerialize -ignoreVarsRE "" $o] behave like [::Serializer deepSerialize $o], since learn@wu depends on that, and a value for ignoreVarsRE of empty looks more like an omitted value than a regular expression, that should match everything. * extended regression test nsf.c: - generalize stack monitor by handling growing and shrinking stacks - refactor into function CheckCStack() - serializer: * pertain perobjectdispatch and keepcallerself in serializer * extend regression test nsf.c: - refactor ObjectCmdMethodDispatch() for clarity - prepare work on object method dispatches with KEEP_CALLER_SELF and no NSF_PER_OBJECT_DISPATCH - explorative implementation of object method dispatches with KEEP_CALLER_SELF and no NSF_PER_OBJECT_DISPATCH - extend regression test nsf.c: - implement escaping for comma in value of parameter options: escaping in values can be achieved via duplicating the comma. In the following example is the value for arg "1,3" D public method foo {a:commaRange,arg=1,,3,optional} {..} Escaping via \ would actually require 4 backslashes due to Tcl's escaping rules (two, to get a single backslash, another two due to list-splitting to obtain default from arg). - extend regression test nsf.c: - allow parens in property names (array syntax) - added "/obj/ info name" (as alternative to "namespace tail [self]") nx.tcl: - added "private property foo" - extended regression test - start error messages with a lower case word for consistency and to follow closer to Tcl's conventions Documentation: - added design study ruby-mixins.tcl to example-docs and regression test - added documentation for "/obj/ info name" to migration guide and .nxd file - adding more comments to examples in migration guide - document private properties in tutorial and migration guide - improve wording in documenting - extend regression test nsfShadow.c - bump MethodEpoch when a tcl ::rename command happens on a nsf method (which might be cached in a Tcl_Obj) This fixes a crash reported by Arthur Schreiber nsf.c: - make NsfInstanceMethodEpochIncr() and NsfObjectMethodEpochIncr() accessible from all files using nsfInt.h - remove experimental code (backslash escaping for "," in parameter option parse nsf.c: - added a SlotContainerCmdResolver() to avoid interaction of slot names with names of callable tcl commands. Without the SlotContainerCmdResolver() the call to "list" in a property named "list" leads to a call to the container object ::Test2::slot::list instead to the intended ::list. The implementation is not perfect, since it ignores the namespace path inside the slot container. - added regression test. nsf.c: - ignore in internal calls to "dealloc" protection settings - handle cyclical class dependencies during object system finalize - extend regression test nsf.c: - handle cyclical superclassclass dependencies during object system finalize - extend regression test nx.tcl: - set multiplicity for mixins and filters by default from 1..n to 0..n to avoid error messages, when e.g. empty mixin lists are configured. Setting empty mixin-lists is strictly speaking not necessary, but this eases the code in cases the lists are sometimes empty. nx::test: - added summary at the end of "make test" via log file - updated .gitignore nsf.c - rename nx::Object.configure to nx::Object.__configure to free method name "configure" for an e.g. tk-like configure - refactored code to allow to parameterize handling of required flag for parameters - don't flag an error when configure is called on an initialized object (logic: if the object is initialized, configure must have been called before, and the required action must have been already taken). nx.tcl: - rename the following internally called methods (not for XOTcl). alloc -> __alloc dealloc -> __dealloc objectparameter -> __objectparameter recreate -> __recreate - from these methods, only __objectparameter is defined per default, the others are defined on demand - updated 34 copyright notices nsf.c: - extended nsf::method::delete to handle ensemble names nx.tcl: - added tk/incr-tcl style cget methods on class/object levels as ensemble methods. - improve copy handling with other child-types of the slot container working - make sure to ignore non-slot-type objects in slot introspection - worked on regression test until "methods.test". others are missing, but maybe reconsideration nsf.c: - implemented cget as a configure-like method, dropped ensemble method variant nx.tcl: - simplified "/obj|cls/ delete method" due to resolving capabilities in nsf::delete::method xotcl2.tcl: - made destructor of Connection more robust such it does not depend on accessor methods. - fixed regression test to run all test again correctly nsf.c: - made argument of cget required nx.tcl: - added Tk-style methods "configure" and "cget" - added additional regression test set for cget and configure - renamed testlog file, remove it on "make clean" nx.tcl: - remove debugging output nsf.c: - fixed parmeter syntax for required nonpos args - deactivate deletion of methods via nsf::object::delete during shutdown to avoid missing slot forwarders called from destructors nx::Class create C { :property {b b1} :public property {c c1} :protected property -accessor {d d1} :variable foo } Property reform part 1: - disallow protection modifiers for "properties" and add new flag "-accessor" to "property" and "variable" This changes definitions like Class create C { :property {a a1} :public property {b b1} :protected property {c c1} :private property {d d1} } to Class create C { :property {a a1} :property -accessor public {b b1} :property -accessor protected {c c1} :property -accessor private {d d1} } since "properties" are always public accessible over the "configure" and "cget" interface, but the accessors methods might not be public. The value of the accessor might be also "none" (specifying explicitly that no accessor is wanted) or "", which means: use the default. Same holds for "variable" - disallow parameter option "incremental" and change it to a flag of the property or variable. The motivation for this is due to the fact, that "incremental" is a property of the accessor, and not of the value. old: Class create C { :property foo:int,incremental :variable bar:int,incremental } new: Class create C { :property -incremental foo:int :variable -incremental bar:int } - disallow "public class property" and friends since these are not needed - removed parameter property "noaccessor" - removed "nx::configure defaultPropertyCallProtection" and method hook "__default_property_call_protection" - introduced "nx::configure defaultAccessor" and method hook "__default_accessor" - for the time being, "defaultAccessor" is "public" for NX and XOTcl, will be changed to "none" in NX - extended regression test (new file properties.test) Property Reform Part 2: better handling of per-object properties nsf.c: - changed "/class/ __objectconfigure" to "/obj/ __objectconfigure" to be able to handle per-object properties on classes properly. - renamed "info method parametersyntax" -> "info method syntax" - renamed "/obj|cls/ info method parametersyntax" into "/obj|cls/ info method syntax" - replaced "::nsf::methods::class::info::objectparameter" by "::nsf::methods::object::info::objectparameter" - new command "::nsf::parameter::specs ?-configure? ?-noposargs? slotobjs": convert provided slotobjs into a list of parameter specs - new command "::nsf::parameter::get list|name|syntax parameterspec": convert parameter spec into syntax form, or retrieve pieces of information from it (can be extended in the future) - added more or less generic list handling functions TclObjListFreeList(), TclObjListNewElement() and TclObjListAdd() used by "::nsf::parameter::specs" - replaced "::nsf::method::property /obj/ -per-object /name/ slotcontainer ?value?" by "::nsf::object::property /obj/ slotcontainer ?value?" - added "::nsf::object::property /obj/ hasperobjectslots ?value?" nx.tcl: - new info methods * "/obj/ info lookup parameter definitions" * "/obj/ info lookup parameter names" * "/obj/ info lookup parameter list" * "/obj/ info lookup parameter syntax" - changed "/cls/ info parameter definition ?name?" into "/cls/ info parameter definitions ?name?" since ir returns a list. Still, "list" or "syntax" won't be plural XOTcl 2 - don't blindly register all object/class methods for XOTcl nsf.c: - fix potential bad interaction between per-object mixins and per-class caching of object-parameters - first draft of per-object parameter caching (for per-object-mixins and per-object properties). nsf.c: - rename invalidateobjectparameter -> parameter:invalidate::classcache - rename invalidateobjobjectparameter -> parameter:invalidate::objectcache - bring cmds into alphabetical order - NsfObjInfoObjectparameterMethod(): return not only the first matching parameter, but the list of all matching ones. The last optional argument was renamed from "name" to "pattern" accordingly - invalidation of per-object parameter cache * on mixin changes and * on deletion/adding of per-object slots - activate PER_OBJECT_PARAMETER_CACHING per default (flipping this parameter makes regression test more than 20 faster). - extended regression test nsf.c - added functionality for "cget" to call parameter-methods (e.g. "... cget -class"). The method cget calls either "/slot/ get ..." (when slot=... is provided in the parameter spec) or it assumes that the method without argument returns the value - added "::nsf::object::property /obj/ volatile" to query whether a object is volatile or not - "/obj/ cget -volatile" returns now the volatile state of the object - factored out ParameterMethodDispatch() from OConfigureMethod() - extended regression test nx.tcl: - change parameter name in "/cls/ info parameter ... ?pattern?" from "name" to "pattern" - changed name "/obj|cls/ slot info definition" to "/obj|cls/ slot info definition" since result is a set - dropped parameter method "properties" - dropped "/obj/ info properties" (since "properties" or "variables" are returned") - extended regression test nsf.c: - factored out ParameterMethodForwardDispatch() to call a parameter method defined as a forwarder the same way from "configure" and "cget" - extended regression test nx.tcl: - property has now a boolean non-positional argument "-config" /obj|cls/ property ?-accessor value? ?-config boolean? ?-incremental? ?-class value? spec ?initblock? in symmetry with "-accessor" (parameter option "noconfig" is still needed to flag nsf for variables that should be initialized, which are not configurable - "/obj|cls/ info slot definitions" returns a full command (containing flags and property|variable) - extended regression test nsf.c: - handling of method names in error messages from nsfAPI.h. Make sure that error message is generated with the actual method name. Object-method Reform: - changed interface to object specific commands by requiring an ensemble named "object". The rational behind is essentially to use always the same info command to retrieve object specific methods, no matter whether these are defined on a plain object or an a class object (does not break the "contract" what e.g. "info method" returns). Now we define methods via: /cls/ method foo {args} {...body...} /cls/ object method foo {args} {...body...} /obj/ object method foo {args} {...body...} Similarly, aliases, forwards and mixins are defined, e.g. /cls/ mixin add ... /cls/ object mixin add ... /obj/ object mixin add ... /obj/ require object method ... /obj/ object property ... /obj/ object variable ... The same change propagated as well to the "info" method. Now we have: /cls/ info methods ... /cls/ info object methods ... /obj/ info object methods ... Similar, the object parametererization uses /cls/ create obj -object-mixin M /cls/ create obj -object-filter f /metacls/ create cls -mixin M1 -object-mixin M2 /metacls/ create cls -filter f1 -object-filter f2 - as a consequence, a) "/cls/ class method ..." "/cls/ class alias ..." "/cls/ class forward ..." "/cls/ class filter ..." "/cls/ class filterguard ..." "/cls/ class mixin ..." "/cls/ class mixinguard ..." "/cls/ class info ..." "/obj/ class method require method ..." "/obj/ class method require public method ..." "/obj/ class method require protected method ..." "/obj/ class method require private method ..." "/cls/ class property ..." "/cls/ class variable ..." "/cls/ class delete property ..." "/cls/ class delete variable ..." "/cls/ class delete method ..." "/cls/ require class method ..." "/cls/ require public class method ..." "/cls/ require protected class method ..." "/cls/ require private class method ..." were dropped b) "/obj/ method ...." "/obj/ alias ...." "/obj/ forward ...." "/obj/ filter ...." "/obj/ mixin ...." "/obj/ info method*" "/cls/ create obj -mixin M" "/cls/ create obj -filter f" "/obj/ require method ..." "/obj/ require public method ..." "/obj/ require protected method ..." "/obj/ require private method ..." were dropped - added package nx::class-method to allow optionally the "class" notation "/cls/ class method ..." (and friends, see (a)), and "/cls/ class info ... - added package nx::plain-object-method to allow optionally plain method b) "/obj/ method ...." (and friends, see (b)) - added support to slots to use ensemble methods as setters - added "/obj/ object variable" and "/obj/ object property" - bumped version number to 2.0b5 - tested with NaviServer and OpenACS (new version of nx needs as well a newest NaviServer, since ns_cache implementation needs to be objectified; newest NaviServer version works as well with older nx) - moved "/obj/ info slot definition|..." to "/obj/ info object slot definition|..." for consistency - provided "parametersyntax()" for "object mixin" and "object filter" Method and configure parameter reform: - unify handling / naming / parameterization of method parameters and configure parameters - New Interface: /cls/ info configure parameters ?pattern? -> list of params /cls/ info configure syntax -> syntax output /obj/ info method parameters /methodName/ ?/pattern/? -> list of params /obj/ info method syntax -> syntax output /obj/ info lookup configure parameters ?/pattern/? -> list of params /obj/ info lookup configure syntax -> syntax output /cls/ info parameter list|name|syntax /param/ -> value "... method syntax" and "... configure syntax" return the full method/configure call, and not only the parameters as in previous versions. Therefore, providing a pattern could lead to unexpected results, therefore the argument was dropped. - Replacements relative to 2.0b4: {/cls/ info parameter definitions} -> {/cls/ info configure parameters} {/cls/ info parameter definitions x} -> {/cls/ info configure parameters x} {/cls/ info parameter syntax ?pattern?} -> {/cls/ info configure syntax} {/obj/ info lookup parameter definitions ?pattern?} -> {/obj/ info lookup configure parameters ?pattern?} {/obj/ info lookup parameter syntax ?pattern?} -> {/obj/ info lookup configure syntax} - Dropped calls: /cls/ info parameter list ?/pattern/? /cls/ info parameter names ?/pattern/? syntax of a single parameter via this interface /cls/ info configure syntax ?/pattern/? /obj/ info lookup parameter names ?/pattern/? /obj/ info lookup parameter list ?/pattern/? Method and configure parameter reform, Part 2: In order to streamline the interface further, we tried to follow the idea to use "... info /plural word/" to obtain a set of handles, and then a separate call to obtain the details. Therefore, we replaced /cls/ info slot objects /cls/ info slot definitions /cls/ info slot names /obj/ info object slot objects /obj/ info object slot definitions /obj/ info object slot names /obj/ info lookup slots by /cls/ info slots ?-type /type/? ?-closure? ?-source all|application|baseclasses? ?/pattern/? /obj/ info object slots ?-type /type/? ?/pattern/? /obj/ info lookup slots ?-type /type/? ?-source all|application|baseclasses? ?/pattern/? - nx.tcl: handle "incremental" in slot reconfigure - nx.tcl: change defaultAccessor to "none" - dropped "/obj/ info slot definition /slotobj/" in favor of "/slotobj/ definition" Method and configure parameter reform, Part 3: - added /obj/ info lookup variables -> list of handles /obj/ info lookup object variables -> list of handles /obj/ info variable definition|name|parameter /handle/ - nx.tcl: added forward compatible scripted implementation of "lmap" - nsf.c: handle names for private slots in pattern provided to AddSlotObjects(), used e.g. in "info lookup slots /pattern/" - added new regression test info-variables.test - nx-pp.tcl: fixed changed accessor handling, added cget to highlight words - updated next-migration guide to reflect changes from the configure reform - "info method syntax" returns now "/cls/ ...." - "info object method syntax" returns now "/obj/ ...." - hopefully the last changes for ?object? method|variable|property: defined * "/obj/ delete object method" * "/obj/ delete object property" * "/obj/ delete object variable" - extended parameter extractor: new functionality ::nsf::parameter get default /parameter/ ?/varname/? ::nsf::parameter get type /parameter/ /obj/ info parameter get default /parameter/ ?/varname/? /obj/ info parameter get type /parameter/ - nsf.c: handle full-qualified name for private slots (AddSlotObjects()) - extended regression test - C-code Generator: added "-typeName" for enumeration types that allows for disambiguation of enumerations with different argument names. Before that, the argument name determined the c-type of the enumeration. Therefore it was not possible to use argName "-type" for two different functions with a different list of enumerators. - changed "-methodtype" to simply "-type" in /obj/ info methods ... ?-type all|scripted|builtin|alias|forwarder|object|setter|nsfproc? ... /obj/ info object methods ... ?-type all|scripted|builtin|alias|forwarder|object|setter|nsfproc? ... /obj/ info lookup methods ... ?-type all|scripted|builtin|alias|forwarder|object|setter|nsfproc? ... - removed some TODOs from tests/parameters.test - parameter dispositions: We differentiate now between "initcmd" and "cmd": an "initcmd" is only evaluated once, but one can provide configure values for this parameter later. a "cmd" is executed on every evaluation, it is only possible to pass cmds to it. The trailing argument of the configure parameters (used e.g. for scripted object/class definitions) is now of type "cmd". Implementation not yet complete (object cases are not correct). - nsf.c: fix crash when "nsf::my" is called with a single argument outside the object context. - fixed cases, where valuechangedcmd (and the other traces) did not work with "configure" method. When slot traces are used, it cleans other traces for the same operations. - extended regression test - added implementation for slots with traces+types for classes - exception for incorrect defaults are thrown during slot creation - extended nsf::is, added parameter * ?-configure? -- accept configure parameter options * ?-name /name/? -- provide a parameter name for error message - simplified nx.tcl by using new nsf::is - extended regression test - changed ::nsf::parametersyntax(..) to ::nsf::parameter::syntax(..) - xotcl2: adjusted manual parameter syntax entries to new conventions Cleanup of nsfAPI.decls - remove unneeded enumeration types - use "typeName" to shorten reported names of parameters - use camel case for reported names Traits: - changed from traits-as-objects to traits-as-classes. This allows for higher orthogonality of traits and class definitions and allows in principle traits for object-specific methods (not fully implemented/tested) - fixed property/variable inheritance in traits. nsf.c: - changed enumeration values for "-source" in "info lookup methods" "info lookup slots" "info methods" "info slots" of "all|application|baseclasses" to "all|application|system" for consistency with "nsf::my" and "nsf::dispatch" which uses "-system" as well nx.tcl: - removed "info is .." since it might raise more questions than it solves - renamed initblock parameter from __initcmd to __initblock - renamed nsf::configure parameter from "keepinitcmds" to "keepcmds" - saving "keepcmds" in an associative array named "__cmd(/parameternName)" to allow saving of multiple parmeters with less name clash danger (when application stays away from variables stating with double underscore) - completed coverage if plain-object-method.tcl - provided warnings via plain-object-method.tcl via "nsf::log warn ..." nsf.c - fixed potential infinite loop in pattern matching for precedence lists - cget: make error message closer to tcl conventions - extended regression test package nx::plain-object-method: - made warnings configurable via nx::configure plain-object-method-warning on|off - completed coverage and test cases package nx::class-method: - convenience package similar to nx::plain-object-method - allow for usage "C class method ..." in addition to "C object method". - made warnings configurable via nx::configure class-method-warning on|off - completed coverage and test cases nx.tcl: - replaced functionality of "/obj/ configure" by "/obj/ info configure" to re-enable semantics of the plain configure method, even when called without arguments. "/obj/ info configure" is actually a convenience method to allow to write o1 info configure instead of o1 info lookup configure syntax - traits: added ability to turn on verbosity for traits by using nx::configure trait-verbosity on|off nx.tcl: - renamed variable option "-config" to "-configurable" to make its intention clearer - changed multiplicity of mixin, object-mixin, filter, object-filter from 1..n to 0..n; rationale: when one has a list of eg. mixins, which should be passed, one has to test for the length before passing it, otherwise the empty list would generate an error. Allowing 0..n makes the usage simpler and the program shorter. Removed oboslete item. At least in this concrete form, the warning does not show up. - NSF_WITH_VALUE_WARNINGS: Right now, value warnings are also fired for arg vectors with a delimiting "--"; right now, this gives a warning: Object create o { :public object method foo {-np1 -np2 p1} { return $p1 } } ? {o foo -np1 1 -np2 2 -- -X} "-X" nsf.c: - when creation with an required configure parameter failed, delete the half-baked object to avoid confusing states. - improved handling of required configure parameters when classes are changed dynamically. When configure parameter are defined required, checking for the absence of required parameter was only performed at creation time. When objects were re-classed or their classes extended with required parameters, later calls to configure did not trigger exceptions. Now we check for the existence of the instance variable which addresses most of these points, but in future we might wish a more general solution (see comment for futures releases) nx::test: - deactivate calling overhead calculation, since this is not reliable (sometimes larger than the call). - Old TODO maybe obsolete: handling of recreate (see regression test for class-level properties) Could not find references about this in the parameters or properties tests. nsf.m4: - nsf.m4 currently unused (SC_PATH_NSFCONFIG and SC_LOAD_NSFCONFIG) We can delete it from the current version. nsf.c - fixed a bug in "info methods returns" in cases, where no returns info was available. - we can "/obj/ copy" now objects/classes containing * aliases * setter * ensemble methods * method protections Instead of handling cmd copying in NsfNSCopyCmdsCmd, it is replaced now by introspection. - extended regression test nsf.c - fixed a potential crash on destroy for objects having a wrapper-less alias defined - removed obsolete function AssertionAppendPrePost() - removed obsolete function NsfNSCopyCmdsCmd() and ::nsf::nscopycmd (handled now more general on scripting level in the "copy" method) nx.tcl: - "copy" method: fixed copying of class-level per-object methods - extended regression tests serializer.tcl - added flag -objmap to Serialzer.deepSerialize to make serializer usable for copying (-map is to coarse) - extended regression test nsf.c: - Eliminate all use of Tcl_GetStringFromObj() function. nx::test: - use the standard configure interface for configuring instead of own version - changed from nx::Test to nx::test (user never has to know that nx::Test is a class). - change test cases to newer interface - don't use "namespace import nx::*" in test cases when not required nsf.c: - reduce variable scopes - fix a bug in SlotContainerCmdResolver() when NSF_MEM_COUNT is activated - fix a small memory leak for PER_OBJECT_PARAMETER_CACHING - all cases detectable with --enable-memcount=yes are fixed - recheck Announce - concatenate Changelog - update next-scripting doc + examples, pdf-files? - build tar etc. as in README.release nsf.c: - dont't use the default of a invocation parameter in "configure" when the object is already initialized. The default is in general only used when the parameter is not specified. We do not want e.g. superclass to be reset to ::nx::Object, when configure is called on a class without arguments. - extended regression test - prepare for providing nx as a tcl module (.tm file). this is just a preparation, since for testing, one cannot set up a path that prefers a local copy over a global installed one (the global tcl-site is preferred over the one specified in e.g. TCL8_5_TM_PATH) Moving to tcl modules works in essence via git mv library/nx/nx.tcl tcl8/site-tcl/nx-2.0b5.tm This is really usable, when http://core.tcl.tk/tcl/tktview?name=86ceb4e2b6 is through mongodb: - updated to most recent version of c-driver (0.7.1) - adapted to nx 2.0b5 (use everywhere cget interface) - tested with mongodb 2.4.5 - added example scripts rosetta-sudoku.{tcl,html} and tk-ludo.{tcl,html} - added sample script doc/example-scripts/tk-geo.tcl mongodb: - integrated configuration of mongodb into toplevel config file option: --with-mongodb=MONGO_INCLUDE_DIR,MONGO_LIB_DIR - added regression test files for mongodb support (low-level (tcl-only) and highlevel (nx based oo support)) - integrated mongodb-testfiles with "make test" - reduced verbosity of nx-mongo.tcl (added verbosity variable) nsf.c - don't call postcondition, when the command/invariant have returned already an error - fixed a bug where turning on assertions could swallow result-codes - fix potential crash when preconditions are empty - extended regression test serializer - fix object method serializeExportedMethod: targetName might have been uninitialized nsf.c - reduce variable scope - remove uncalled static function nsf.c - fixed a bug where turning on assertions could swallow result-codes - extended regression test nsf.c: - added flag -checkalways to nsf::proc and nsf::asm::proc (for the latter just a placeholder for now). If the flag is used, it will cause argument testing independently from the "configure checkarguments" setting. To force argument checking always is useful e.g. for checking external values (e.g. in a web server) - nsf: added switch "-checkalways" to nsf::method::create - nx: added switch "checkalways" to "method" and "object method" - extended regression test xotcl2: - fixed "... info defaults ..." and "... info instdefaults ..." emulation in XOTcl 2 - fixed error message - extended regression test - bumped revision of nsf/xotcl/nx to 2.0b6 gentclAPI.tcl, generic/nsf.decls - make converter usable from c-based packages compiled with subs activated - add parameter parser and converter to stub tables generic/nsfStubLib.c: - change base stub table from XOTcl to NSF. - improve wording of error messages. generic/nsfPointer.c: - add reference counter to avoid double-inits and double-frees in case the table of converters is used from multiple interpreters generic/nsf.c: - made linearization monotonic (for multiple inheritance) via single-inheritance linearization merging while preserving overall linearization rules - added flag NSF_LINEARIZER_TRACE - extended regression test library/lib/make.tcl: - don't try to load nx when building pkgindex for a binary package (.so or dylib) mongodb - upgrade to mongo-c-driver to 0.8.1 - added new flag "-ttl" to mongo::index - there seems to be now a differen mongo-c-driver to be the preferred one, the old one is renamed to mongo-c-driver-legacy - link against nsf-stublib - bump version number to 0.2 generic/nsf.c: - add more assertions - ensure computation of requires orders for recursive merges mongodb: - add flag "-puts" to method "show" of nx::mongo::Class to turnoff output to stdout - handle empty find operations for "find first" - added method pretty_variables to output available variables of a class in a similar style as in the definition - added low-level method "close" to nx::mongo nsf.c: - new command ::nsf::object::alloc /class/ /obj/ ?/script/? alloc an object and execute script in the context. Can be used to regenerate an object in a old state. serializer: - fixed loading of objects with required data in the blueprint (many thanks for david hopfmueller for reporting this) - make use of nsf::object::alloc (1 command instead of 1 create + 2 evals) - these changes improved loading time of blueprint by about 25% for OpenACS+xowiki - don't rely on the existence of a "trace" method nsf.c: - when ::nsf::object::alloc is passed an empty name (2nd argument), behave like "new" method nx: - allow copy of objects with required arguments - use ::nsf::object::alloc in "copy" method - don't depend on method "trace", use directdispatch instead - remove method "-noinit" (nsf::object::alloc makes it obsolete) - extend regression test serializer: - restore traces after object-serialize nsf.c: - fix stub provisioning for Tcl 8.6 - reduce verbosity for FreeUnsetTraceVariable - return TCL_OK, even when FreeUnsetTraceVariable() fails (warning stays) nx-mongo: - implement simple persistent handle management based on per-thread objects -nsf.c: - fix bug in interaction between uplevel method and interceptor transparency - fix bug in interaction between uplevel method from tcl procs - extend regression test build-system: - provide datarootdir to get rid of warning during configure nx-mongo: - updated documentation (switch back to mongo-c-driver, but comment usage of tagged version v0.8.1) - added support for rep types (allow for mappings between certain instance variables such as arrays or dicts to customizable representations in MongoDB) - added nx-serialize to test cases (simple state persistence for nx objects) - added nx-rep to test cases (rep types for "array" and "dict") - improve performance of mongo->tcl conversion by using predefined global strings nx-monogo: - Updated the mongo-c-driver and libbson to the actual tip version from github (this is a significant change, since 10gen essentially changed the officially supported c-driver of MongoDB) - mongo-c-driver was more or less new-implementation, since structure and names changed in the mongo-c-driver substantially, several functions were added, several were dropped. The new interface supports now e.g. mongo URIs, and should be faster (by using collection objects instead of connection handles) - Although the low-level nsf interface changed significantly, the high level (nx level) interface remained unaffected. - Configure has now --with-mongoc=... and --with-bson instead of --with-mongodb - New commands: mongo::collection::open /mongoConn/ /dbName/ /collectionName/ mongo::collection::close /collection/ mongo::gridfs::store_string /content/ /name/ /contentType/ - Make use of the new collection handle mongo::count /mongoConn/ /ns/ ... -> mongo::collection::count /collection/ ... mongo::index /mongoConn/ /ns/ ... -> mongo::collection::index /collection/ ... mongo::insert /mongoConn/ /ns/ ... -> mongo::collection::insert /collection/ ... mongo::query /mongoConn/ /ns/ ... -> mongo::collection::query /collection/ ... mongo::remove /mongoConn/ /ns/ ... -> mongo::collection::delete /collection/ ... mongo::update /mongoConn/ /ns/ ... -> mongo::collection::update /collection/ ... mongo::cursor::find /mongoConn/ /ns/ ... -> mongo::cursor::find /collection/ ... - nsf::mongo::connect receives now a mongoc_uri https://github.com/mongodb/mongo-c-driver/blob/master/doc/mongoc_uri.txt - The gridfs interface allows now to store multiple revisions of a file - The gridfs interface allows now upload files from a string - The gridfs interface allows to refer to files by other attributes than just the filename (e.g. the mongo id). - Modified/new gridfile functions mongo::gridfile::create ?-source file|string? /gridfs/ /value/ /name/ /contentType/ mongo::gridfile::delete /gridfs/ /query/ mongo::gridfile::open /gridfs/ /query/ - Updated README - Updated regression test - Added editor hints for a more uniform appearance nsf.c: - change name of enumeratorConverterEntry to Nsf_EnumeratorConverterEntry, move it with NSF_ARG_* flags to tcl.h to make it available in derived modules using the converter - Added editor hints for a more uniform appearance nx.tcl: - raise an error, when an ensemble methods redefined a plain method nsf.c: - fix small memory leak in multiple inheritance code. - all regression tests run cleanly with --enable-memcount=yes - let [current methodpath] return full path (similar to -path option in "info methods" - handle collateral damage in regression test due to changed result of "current methodpath" nx::traits: - handle ensemble methods correctly (use full method path for resolution) - add new regression tests for traits nx-mongo: - optional support for mongodb connection pools (compile time macro USE_CLIENT_POOL controls this, per default, this is on) - allow to pass "-metadata" to gridfile::create to ease metadata attachment to gridfiles - some convenience improvements in nx-mongo.tcl (ability to ignore attributes in "bson encode", ability to unset attributes in gridfs, ...) - bump version numbers of nsfmongo to 0.3 and nx-monogo to 0.5 - represent BSON_TYPE_REGEX as pairs (regex + options) in the Tcl representation to preserve regular expression options - update to newest version of mongo-c-driver and libbson from github - tested with mongodb-c-driver 0.93.0 nx-mongo: - fixed surprising compiler message "alignment of array elements is greater than element size" when using e.g. "bson_iter_t i[1]" - some c-code cleanup - tested with mongodb-c-driver 0.92.3 - added mongo::collection::stats - added mongo::cursor::aggregate - extended regression test nsf.c: - fix case, where NsfDStringPrintf() failed (when print llength including \0 was 1 byte longer than print buffer) - make sure, that the list kept for the cached parameter is just built from unshared objects; otherwise Tcl append will abort nx.tcl: - new package "nx::volatile" - don't define configure parameter "-volatile" per default; use "package req nx::volatile" instead - don't define per method "volatile" per default; use "::nsf::method::require ::nx::Object volatile" instead - get rid of -volatile in nx.tcl and serializer - updated/extended regression test nx-mongo: - added command "::mongo::status /mongoConn/" - extended regression test nsf.c: - invalidate parameter caches of subclasses on NsfParameterInvalidateClassCacheCmd unless during shutdown. Otherwise some classes might not become aware of properties added later to superclasses. - extend regression test nsf.c: - remove redundant NULL tests - improve safety mof macro ObjStr() build-process: - replace make.tcl by the much simpler mkIndex.tcl: * Does not use pkg_mkIndex * Does not load binary files (problem for cross compiling) * Requires package provide with constant in one line. small introspection reform: - Introspection for commands and arguments did not work for cmds defined in sub-packages (such as mongodb). We keep now this information in hash-tables and maintain a slim interface for this. - fix generation of pkgIndex.tcl for mongodb Configuration: - stick closer to TEA conventions (keep tclconfig-sh in tclconfig directory) - remove obsolete version of install-sh, copy manifested version to mongodb library - fix configure.ac quoting forwarders: - RFE "provide %method" as keyword like %proc" was already implemented. Dropping %proc would break XOTcl2 compatibility. - adding a test case - use for output of forward ... -verbose NsfLog(...NSF_LOG_NOTICE...) instead of fprintf() to make it redirect-able - use in forwarders "-frame object" instead of "-objframe" in nx for consistency with other calls (e.g. dispatch). Other values for "-frame" are not allowed. (btw, XOTcl has "-objscope") - deactivated "-onerror", since its semantics are expressible via try/catch, and there are no regression tests for xotcl and nx, and we could not find any script that uses this - renamed "-methodprefix" to "-prefix" in nx, since the prefix can be applied as well applied to a cmd. - use nx rather than xotcl2 terminology in nsf::method::forward nsf.c: - de-spaghetti precedence computations for multiple inheritance and improve documentation - get rid of // comments - use nonnull variable attributes for prototypes (nsf.h, nsfInt.h, nsf.c) - add returns_nonnull assertion - simplify few inner code pieces based on assertions - add several more assertions based on nonnull specifications. - made nsf::is using the "-strict" option when tcl's "string is" is called. - let the c-code generator produce as well nonnull assertions - simplify FilterInvalidateObjOrders() and FilterRemoveDependentFilterCmds() - simplify SuperclassAdd() - improve code documentation nx.tcl: - Define method "value" as a slot forwarder to allow for calling value-less slot methods like e.g. "get" despite of the arity-based forward dispatcher. - extend regression test - added more test cases for multiplicity and incremental - preserve lower bound of multiplicity when incremental is added - added log-level Info which prints always, e.g. for "-verbose" flag of forwarder nsf.c: - add flag "-onerror" to nsf::forward::method to handle errors during dispatch of a forwarder (not all error messages of forwarder are already transformed) - added log-level Info which prints always, e.g. for "-verbose" flag of forwarder - drop setter-rule from properties (use always forwarder) - drop "/obj/ /prop/" and "/obj/ /prop/ /value/" in favor of "/obj/ /prop/ get" and "/obj/ /prop/ set /value/" to achieve better orthogonality with e.g. incremental properties - allow parameter option "method=" for slotassign as well. rationale: this allows to use the parameter "forwardername" to specify a different forwarder target method (e.g. in case of object-mixins). The method is used both in "configure" and "cget". - allow methodname to consist of max two words in relation slots (e.g. "-methodname {mixin set}"} - allow configuration of internally called "slot.get" and "slot.assign" methods via objectsystem::create - rename default slot methods add/get to value=add/value=get - provide an error message, when referring to a non-existing slot object - added likely/unlikely to result == TCL_OK etc. - fix one more subtle case of an error being swallowed: for xotcl, the constructor returns the list of residual arguments. In case there was an error, it was possible that the returned residual arguments overwrote the error message in the interp result - finish implementation of NsfForwardPrintError() - use NsfForwardPrintError() in ForwardArg() for all error messages nx.tcl: - replace empty-named arrays by dicts - remove setter methods from BootstrapVariableSlots - reducing interface of BootstrapVariableSlots by setting methods protected - use value=* as names for internally called and forwarder-called accessor methods - enforce using "set" for filter/object-filter in slot operations (same as for mixins) - add "set" as a method name for relation slots - implemented relation slot "mixin" and "object-mixin" via "slotassign" to disallow "/obj/ mixin /value/" and "/obj/ object mixin /value/" to use instead "/obj/ mixin set /value/" and "/obj/ object mixin set /value/" while keeping "configure" and "cget" working. This has the advantage that "/obj/ mixin set" does not try to replace the mixin chain by "set" - disallow "assign" for nx::variableSlots - use set/get/add as slot methods for get/configure/incremental operations - de-mangle slots for nx/xotcl2 further - enforce usage of "get" for all slots in nx - put test cases for all kind of mix setter / getter together in one test case xotcl2.tcl: - use object system configuration for -slot.get and -slot.set - use value=set instead of value=assign - simplify "-parameter" implementation - add setters for "name", "domain", and "default" to xotcl::Attribute for backward compatibility mongodb - by directing calls to the setter, it is now more complex to determine the true calling object for an converter, since the set operation might be routed though the slot object. It would be nice to have framework support for this. - fix 2 error messages - provide shorter tracebacks by using "return -code error ..." rather than "error ..." nx::test: - don't delete system slot ::xotcl::Attribute on cleanup nx.tcl: - add slot method value=unset to nx::RelationSlot and nx::VariableSlot - extended regression test - reworked error message generation of slot-forwarder (list all available slot methods with prefix value=) - cleaned up relation slot mixin variants xotcl2: - use xotcl::RelationSlot instead of nx::Relationslot in xotcl2 (we can more value=assign here). Makefile: - fix load paths for sublibs (e.g. mongodb) in regression test nsf.c: - added nsf::var::get and "::nx::var get" to provide selector based interface for variable reading (used in slot-method get of nx::VariableSlot) - renamed nsf::relation to nsf::relation::set and added nsf::relation::get in accordance with nsf::var::get - fixed unary argument passing notation for "-nocomplain" of nsf::var and for 42 other options of other commands nx.tcl: - added flag -nocomplain to "/obj/ /prop/ unset ?-nocomplain?" - use "mixin|filter clear" instead of "mixin|filter unset" - name parameter option "slotset" instead of "slotassign" - have "filter|mixin clear" return the list of former|removed filters|mixins. nsfObj.c: - allow to omit "-guard" within arguments to flag definition of a filter/mixin guard - extended regression test nsf.c: - improve handling of space in object names - added methods "info lookup filters ?-guards? ?/pattern/?" and "info lookup methods ?-guards? ?/pattern/?" nsf.c - force again literal "-guard" in a "mixinreg" type to avoid potential confusions - Base nsfRelationSet for mixins on cmds rather than TclObjs to avoid confusions and duplication of guard detection logic - Add interp to NsfMixinregGet() and NsfFilterregGet() to be able to return error messages - return more error message from mixinreg converter - provide at least minimal support for "funny class names" (i.e. containing spaces) - FinalObjectDeletion: don't enforce namespace = 1 for cases with weird namespace deletion order - extended regression test nx.tcl - switch from "/obj/ info parameter" -> "nsf::parameter::get" to reduce potential semantic confusion of info options. "info parameter" was not object/class specific at all, but is just a syntax extractor nsf.c: - extend nsf::parameter::get to obtained more detailed information for objects/classes/metaclasses/baseclasses and specified types - extend regression test - Updated tutorial and migration guide nx.tcl - drop short form "/obj/ info configure" for now - make output of "/obj/ info lookup configure syntax" equivalent to "/obj/ info configure" gentclAPI.tcl: - handle duplicated domains by folding these to a single definition nsf.c: - added command nsf::method::get. Rationale: provide a central place to obtain information about all kind of method handles, which might be - scripted and c-based methods - nsf::procs - plain tcl procs - cmds (with and without parameter definitions) - make results of ListMethod() robust against missing information (e.g. plain tcl cmds, missing object registrations, etc.) - factor out common code for ListMethod call sites for per-object methods, instance methods and procs/cmds to ListMethodResolve() - return errors from failing converter registrations - extend regression test (new test set nsf-method.test) nsf.c - renamed parameter::get -> parameter::info - renamed method::get -> cmd::info nsf.c, gentclAPI.tcl: - new argument types "virtualobjectargs" and "virtualclassargs" for context-specific argument resolutions: when a context object is provided, arguments of type "virtualobjectargs" are determined based on the slots applicable for the object (like "... lookup ..."), arguments of type "virtualclassargs" are resolved against a class. These types are used as follows: /obj/ configure /virtualobjectargs/ /cls/ create /name/ /virtualclassargs/ /cls/ recreate /name/ /virtualclassargs/ /cls/ new ?-childof /obj/? /virtualclassargs/ This new feature allows us to provide better error messages and to make much of the "... info ... configure parameter ..." infrastructure much less important. - For "virtualclassargs" we need the functionality to obtain from the C-Code based on a class the configure parameters applicable to objects of this class. - add argument "-context ..." to "cmd::info" to pass the context object (so far the only place where the context-object is used) - object system configuration parameters changes: new: -class.configureparameter new: -object.configureparameter removed: -class.objectparameter nsf.c: - added options to filter output from ::nsf::cmd::info parameter options (args, syntax, parameter) - deleted: - "/obj/ info lookup configure parameters ?pattern?" - "/obj/ info lookup configure syntax" - added: - "/obj/ info lookup parameters /methodName/ ?pattern?" - "/obj/ info lookup syntax /methodName/ ?pattern?" This covers as well - "/obj/ info lookup parameters configure|create|new|... ?pattern?" - extend regression test mongo: - upgrade to the newly released version 0.96 of the c-driver - replace deprecated function mongoc_collection_delete by mongoc_collection_remove - tested with MongoDB v2.6.1 nx.tcl: - removed /cls/ info configure parameters /cls/ info configure /cls/ info syntax Use e.g. "/cls/ info lookup parameters create" instead moved block here for keeping arguments ===== - configure parameters: we have to cleanup Given: nx::Class create Person { :property name :create p1 } Person info configure says, how object "Person" can be configured Person info configure syntax says, how instances of "Person" can be configured p1 info configure says, how object p1 can be configured p1 info lookup configure syntax says, how object p1 can be configured (long form of above) p1 configure -help gives a reasonable error message, "p1 configure" does not work, since no args are needed Person new -help gives a reasonable error message, except, that "configure" is not perfect Person create just complains about missing name, does not know about configure arguments Person create -help creates an object named "-help" Person create foo -help gives a reasonable error message, except, that "configure" is not perfect possible path: 1) "Person info configure" is dangerous, too close to "Person info configure syntax" but completely different. maybe: use "Person info configure" as short form of "Person info configure syntax", or drop it, since the lookup variant is at least not surprising. 2) It would be nice if we would be not to need the "info" at all but improve the errors in 5-9, maybe special switch "-?" or "--" 3) another possible path: p1 info lookup syntax configure (short form of nsf::method::get syntax [p1 info lookup method configure]) where "configure" is a method name, would work the same way as "p1 info lookup syntax create|foo|..." (under the assumption, we get the "right" syntax for configure). Similar: p1 info lookup parameter configure (short form of nsf::method::get parameter [p1 info lookup method configure]) this way, we would not need "info configure" and friends at all. Tk uses "/obj/ configure" for obtaining possible values Furthermore: The command p1 info method definition [p1 info lookup method configure] gives an error, since "info method" is not defined for p1, we could have used p1 info object method definition [p1 info lookup method configure] which is somewhat strange, since configure is not an object method. Probably: nsf-level command for handles. ==== nsf.c: - Let "/cls/ info mixinof -closure" return as well implicit mixin classes to make it easier to determine class dependencies. Example: nx::Class create M0 nx::Class create M1 -superclass M0 nx::Class create M2 -superclass M1 nx::Class create C nx::Class create D -superclass C C mixin add M2 # M2 is mixed into C, and implicitly into D # # Since M2 is a subclass of M1, classes C and D depend as well # on M1 and M0, as seen in the heritage: ? {C info heritage} ":M2 ::M1 ::M0 ::nx::Object" ? {D info heritage} ":M2 ::M1 ::M0 ::C ::nx::Object" # previously, only "M2 info mixinof -closure" showed the # mixin relations, even with "-closure", while M1 and M0 did not. ? {M2 info mixinof -closure} "::C ::D" # now these show the same relations (in this example). ? {M1 info mixinof -closure} "::C ::D" ? {M0 info mixinof -closure} "::C ::D" - adapt mixinof.test to the additional information - transform mixinof.test to newer style regression test with automated object deletion - updated migration guide and tutorial to reflect recent changes nsf.c: - cleanup of NsfParameterInvalidateClassCacheCmd(): performance improvements. After the fixing of indirect mixin validation, performance of invalidation went up by a factor of 5. At least, in some important cases (invalidation of root-classes like nx::Object / xotcl::Object), we are again on the same level as before (actually slightly faster). - use functions IsRootClass(), IsRootMetaClass() and IsBaseClass() to access object/class properties - add gcc attribute "pure" - rename nsf::parameter:invalidate::classcache -> nsf::parameter::cache::classinvalidate nsf::parameter:invalidate::objectcache -> nsf::parameter::cache::objectinvalidate reasons: (a) remove single colon inside the name, (b) put verb to the end - fixed error message for forward ... onerror and method paths. The command "C object mixin" returns now "::C object mixin add|clear|delete|get|guard|set" and not "::C mixin add|clear|delete|get|guard|set" as before. nsf.c: - new function DependentSubClasses() to determine all classes that inherit from a given class. The result extend TransitiveSubClasses() by including class mixin relationships. - simplify NsfParameterCacheClassInvalidateCmd() by using the new function DependentSubClasses(). With the new implementation, NsfParameterCacheClassInvalidateCmd() is as efficient as before without to MostGeneralSuperclass optimization (but being complete now) when working on the root classes (an more efficient on subclasses). - added experimental code feature CYCLIC_MIXIN_ERROR nsf.c: - improve performance of MixinInvalidateObjOrders() by about 30% by recompiling the list of the dependent classes over and over again, since MixinInvalidateObjOrders() iterates over the full list already. - Document NsfRelationClassMixinsSet() and add nonnull declarations and the usual assertions() nsf.c - base MixinInvalidateObjOrders() on DependentSubClasses() and avoid the need of using a separate hash table for class-mixin handling. The new implementation is several times faster and improves the speed of the functions CleanupDestroyClass(), SuperclassAdd() and NsfRelationClassMixinsSet(). Adding a class-mixin to ::xotcl::Object in OpenACS is more than 4x faster. - remove obsolete function MixinResetOrderForInstances() - rename ResetOrderOfClassesUsedAsMixins() to ResetOrderOfObjectsUsingThisClassAsObjectMixin() - used consistently DependentSubClasses() instead of TransitiveSubClasses() for invalidations. - extended regression test nsf.c: - added option "-dependent" to "info subclass" - extended regression test nsf.c: - move NsfMethodNamePath() out of NsfObjWrongArgs() - move NsfMethodNamePath() out of NsfUnexpectedArgumentError() and NsfUnexpectedNonposArgumentError() - fix name paths in error messages triggered from ArgumentParse() - use 3-argument version of NsfMethodNamePath() - don't invalidate class-level param caches during shutdown nsf.c: parameter passing reform - don't pass full argument list for filtering methods calle further methods from C (such as new/create/... ) to allow processing of e.g. "--" in "new" to separate arguments to "new" cleanly from arguments passed to "create". Now we can use e.g. "C new -- -childof 123" in case class C has a property "childof". - extend c-generator to accept option "-objv0" to pass the original "objv[0]" to the called command. Since we had previously "allargs", we have to pass the objv[0] now differently - more thorough checking ISOBJ(someObj) macro for asserts (use "assert(ISOBJ(someObj))" instead of just "assert(someObj)") - extend regression test nsf.c: - checked, that all CallDirectly() cases, where method is dispatched (no direct call) are covered by the regression tests - avoid double memcpy() in dispatch recreate by using ObjectDispatch() rather than CallMethod() - removed memcpy() in call-directly for "create" - some more cleanup gentclAPI.tcl: - added option "-flags", which can be used for every parameter. example: .... -flags NSF_ARG_NOLEADINGDASH .... - experimental: use NSF_ARG_NOLEADINGDASH for pattern "info subclass" to improve error messages. - extended regression test nsf.c: - relax the meaning of noleadingdash to allow negative numbers - rename noleadingdash to e.g. nodashalnum nsf.c: - define means to protect "undefined" internally-directly called methods __alloc and __dealloc in nx. This is achieved mostly via a an additional value in a method declaration in ::nsf::objectsystem::create. Example: -class.dealloc {__dealloc ::nsf::methods::class::dealloc 1} - extend regression test nsf.c: - allow abbreviated nonpos args - change name of relation slot "superclass" to "superclasses". (part of a planned change to use plural for set-valued parameters, "info superclasses" and similar changes for mixins/filters will probably follow) nx.tcl: pluralism reform part 2 - changed methods /cls/ info subclass -> /cls/ info subclasses /cls/ info superclass -> /cls/ info superclasses /cls/ mixin ... -> /cls/ mixins /cls/ filter ... -> /cls/ filters /cls/ object mixin ... -> /cls/ object mixins /cls/ object filter ... -> /cls/ object filters - changed configure parameters /cls/ configure -mixin -> /cls/ configure -mixins /cls/ configure -filter -> /cls/ configure -filters /obj/ configure -object-mixin -> /obj/ configure -object-mixins /obj/ configure -object-filter -> /obj/ configure -object-filters - added handling for calling relation slot with unknown sub method nx.tcl: - make all __* system methods in nx redefine-protected - let "nsf::configure objectsystem" return handles and protections as well nx.tcl: pluralism reform part 3 - introduced simple plural form "mixins" and "filters" for introspection - moved differentiated interface into slot methods. the slot methods "get" stay symmetrically to "set", but additional methods "classes" or "methods" are used like "guard" to obtain partial results of the mixin and filter specs - changed info methods /cls/ info mixin classes -> /cls/ info mixins /cls/ info filter methods -> /cls/ info filters /obj/ info object mixin classes -> /obj/ info object mixins /obj/ info object filter methods -> /obj/ info object filters - dropped /cls/ info mixin guard /cls/ info filter guard /obj/ info object mixin guard /obj/ info object filter guard - added /cls/ mixins classes /cls/ filters methods /obj/ object filters methods /obj/ object mixins classes - asymmetry between "/obj/ info lookup mixins" vs. "/obj/ info ?object? mixin classes" resolved. nsf.c: - dropped unused object::info::is - renamed ::nsf::methods::class::info::filtermethods -> ::nsf::methods::class::info::filters ::nsf::methods::object::info::filtermethods -> ::nsf::methods::object::info::filters ::nsf::methods::class::info::mixinclasses -> ::nsf::methods::class::info::mixins ::nsf::methods::object::info::mixinclasses -> ::nsf::methods::object::info::mixins nsf.c: - provide error messages for ambiguous abbreviations - extend regression test (now 5460 tests) nsf.c: - see no need, why we should "set nodashalnum for int types" - extended regression test nsf.c: - remove redundant null check for object and add assertion documentation: - add current args to migration guide - fix cut&paste error: replace "current currentclass" by "current calledclass" Migration guide and tutorial: - updated "/cls/ info superclasses" and "/cls/ info subclasses" - updated "/cls/ info mixins" and "/obj/ info object mixins" - updated "/cls/ info filters" and "/obj/ info object filters" - dropped "/cls/ info mixin guard" and "/obj/ info object mixin guard" dropped "/cls/ info filter guard" and "/obj/ info object filter guard" (use "-guard option instead) - updated "/cls/ mixins ...", "/obj/ object mixins ...", "/cls/ filteres ...", "/obj/ object filters ..." nsf.h - In Tcl 8.6.1 it might be that a Tcl_Obj has length > 0 but bytes == NULL. We have to relax out tcl_obj-sanity test for this case from assertions. nsf.c: - remove redundant definition - reduce variable scope - make sure to follow nonnull assumptions nsf.c: - implement a new approach to error reporting in ensembles: instead of trying to find the "right" place to report the best "error", compute the longest valid ensemble prefix from all the stack frames. nx.tcl: - simplify the info ensembles on nx::Object or nx::Class significantly, by making use if ensemble-next. - delete "info unknown", since this is not called. nsf.c: - make types for bit operations unsigned (mostly flags) build system: - don't call genstubs from configure, since Debian does not seem to have genstubs.tcl installed. Now, we pre-generate the stub files for tcl8.5 and tcl8.6 and copy the "right" version depending on the configured version. - Make dtplite configurable in Makefile, e.g. make "DTPLITE=/usr/local/ns/bin/tclsh8.5 /usr/local/ns/bin/dtplite" man - regenerate documentation - bump version number to 2.0.0 (also in .man files) - write body-blocks of if on separate lines - change variable name "validCscPtr" to "isValidCsc", since it is a boolean and not a ptr (tcl coding guidelines) - prefer explicit comparisons - remove test, since it is covered already by assertions - Is NsfParamDefs.slotObj obsolete? Right now, the slot objs responsible for (method) parameters are stored along with each Nsf_Param, and not as a NsfParamDefs.slotObj. NsfParamDefs.slotObj is not used actively, ::nsf::method::property slotobj is dysfunctional (expects extra argument, which cannot be provided + control-flow issue CID 88767). pt. 1: For the time being, I removed ::nsf::method::property slotobj entirely (also to fix CID 88767). Seems harmless, not tested explicitly, not required by object-system scripts, ... pt. 2: NsfParamDefs.slotObj and its memory-management statements all over remain in place, to be reviewed. - removed NsfParamDefs.slotObj (and single occurrence for memory-management) since it is not used for the time being - fix potential bug on tcl-triggered cmd-delete operations, where destroy returns non-TCL_OK and name of the object could not be retrieved anymore in error message. - move dereferencing of members after assertions - improve robustness of destroy: in case an error happened in a destroy method in implicit delete operations, a crash was possible, since the state of the object to be delete was somewhat unclear (it might or might not have been deleted). Now, the object is explicitly kept longer around to allow proper handling). - update licenses - reduce implicit conversions - write body of if-statements as blocks - whitespace changes - prefer boolean expressions - add likely/unlikely hints - added optional parameter "-target" for serializer to ease changing name of object in serialization - new command nsf::method::forward::property in analogy to nsf::method::property for reading+writing introspection of forwarders (important for serializer, when different target objects are specified, to map the per-object forwarder) - extended regression test - bumped version number of serializer to 2.1 - Fixed a bug that disallowed the combination of valuecmd and valuechangedcmd for a single property (many thanks to Zoran for pointing this out) Removed implicit substdefault for configure parameters in nx: - The syntax of substdefault for method parameters and configure parameters was different. For method parameters, it was necessary to specify :substdefault per parameter to activate it, for configure parameter is was based in the XOTcl tradition on the content of the default (whether it contains [...]) One problem is, that there was no easy way to turn this feature off. If one wants to provide a script block as a default, it was necessary to escape all square brackets. - Now, in nx, one has to specify :substdefault for configure parameter explicitly as well, syntax for configure and method parameters is the same. - XOTcl 2.0 keeps implicit substdefaults (backward compatible) - fix bug: never try to substdefault, when there is no default given. - don't swallow errors triggered from variable write traces in configure - handle result of Tcl_ObjSetVar2() in all cases - Use standard logging for nsf::__profile_trace ... -verbose true ... By using the standard logging mechanism, we can redefining ::nsf::log to output e.g. trace in a GUI. - Add argument "-dontsave" to nsf::__profile_trace to avoid saving trace in memory - Refactor trace and debug output to deliver lists. This makes it easier to postprocess the results from Tcl. Profile trace enhancements: - add optional argument "-builtins" to nsf::__profile_trace to trace a selected list of builtins. Every element of the list passed to "-builtins" might contain a cmd name and optionally a maximum number of arguments to be shown (typically 0 or 1) - generalized NsfReplaceCommand* logic to become more general usable (e.g. for the builtins mechanism of nsf::__profile_trace) - New macros NSF_nonnull_assert() and nonnull_assert() Background: The unreleased gcc6 with "-pedantic" complaints since recently about asserts, in which nonnull conditions implied by nonnull declarations are explicitly tested, and spits out warnings like ... warning: nonnull argument ... compared to NULL ... The new macros turns off asserts, when gcc6 is used. - new introspection methods: "/obj/ info object method callprotection /m/" "/cls/ info method callprotection /m/" "/obj/ info baseclass" - extended regression test - added nsf::method::property /obj/ /method/ debug ?0|1? when debug is activated, a debug line written to the log file when the function is called and exited - added nsf::method::property /obj/ /method/ deprecated ?0|1? when deprecated is activated, a warning written to the log file when the function is called - added flags to nsf::proc: -debug and -deprecated (can als be set via nsf::method::property with an arbitrary object and proc passed fully qualified) - bumped version number to 2.0.1 - handling flags "-deprecated" and "-debug" properties for nsf::proc (in "nsf::cmd::info definition /proc/" and serializer) - extended regression test for introspecting nsf::cmd::info definition and flags "-deprecated" and "-debug" - nx: added new introspection options /cls/ info method debug /cls/ info method deprecated /obj/ info object method debug /obj/ info object method deprecated - nx: added flag "-debug" and "-deprecated" to methods "method" "object method" "alias" "object alias" "forward" "object forward" such one can use e.g. /cls/ public alias -deprecated|-debug /method/ ... /cls/ public forward -deprecated|-debug /method/ ... /cls/ public method -deprecated|-debug /method/ ... /obj/ public object alias -deprecated|-debug /method/ ... /obj/ public object forward -deprecated|-debug /method/ ... /obj/ public object method -deprecated|-debug /method/ ... - added new cmd: nsf::method::property /obj/ ?-per-object? /method/ exists to check, whether a method is defined for an object. - output triggered via "-debug" is now generated via the tcl functions "nsf::debug::call" and "nsf::debug::exit", that can be redefined (similar to e.g. nsf::deprecated) - cleanup of nsfProfile.c commands - defined macros ObjectName_() and ClassName_() that behave like the versions without "_", but do not check the passed arg against NULL. This avoids warnings in newest versions of gcc6 and cppcheck. - extended regression test serializer: - added handling of "-debug" and "-deprecated" in serializer - allow export of nsfprocs via "exportMethods declaration" in order to keep otherwise excluded cmds in the result. this allows us to keep nsf::debug::* or nsf::deprecated definitions in the blueprint in OpenACS. - hardened serializer (use e.g. "::namespace" instead of "namespace" when there is a potential conflict with a method named "namespace", prefer nsf::directdispatch, etc.) - extended regression test - fix potential memory corruption bug in NsfDStringVPrintf() - replace all remaning ObjectName and ClassName with variant with trailing "_" when appropriate - allow nsf::procs with zero arguments or plain arguments (when "-debug" is used - extended regression test - bump version number to 2.1 - make use of Tcl_SaveInterpState() and friends for saving results in NsfDStringEval() - added results in debug exit calls - changed interface of NsfDStringEval to control behavior via bitflags (this is after all more readable than a argument list of "0" and "1"s) - added optional recursion prevention for functions called via NsfDStringEval (handling NSF_EVAL_DEBUG, NSF_EVAL_LOG, NSF_EVAL_DEPRECATED) - added regression tests for potential recursive calls - added flags "-debug" and "-deprecated" to XOTcl 2 "instproc", "proc", "instforward" and "forward" methods - turned all for-loops controlled over a nonnull value into while loops - updated TODO, copyright notices, version number - Let nsf create classes with ::nsf::object::unknown handler in the fly, when c-function are called with objects of type class. This is necessary for triggering creation attempts in ttrace via ::nsf::object::alloc SOMECLASS SOMEOBJ - added Tcl_HashKeyType cmdPtrHashKeyType for command pointers - gcc6: * gcc6 seems to have a bug: when e.g. a variable "foo" is declared as nonnull, then the construct do { ... foo = foo->nextPtr; } while (foo != NULL); will raise a warning, despite of the fact that foo is overwritten. This was reported and confirmed as a false positive; to be fixed in future gcc6. - Re-factored new hash-table infrastructure (based on function-pointer keys) to support method-definitions (and future uses as well). - Allow combination of "-trace get" with default value (was previously disallowed) - Extend regression test xotcl2: - added "-returns" flag to XOTcl's instprocs/procs and methods, very similar to "-returns" in nx - extended serializer to handle "-returns" flag - extended regression test cmd resolver work - fix test, when OS specific cmd resolver is used from a NSF_CSC_CALL_IS_COMPILE frame - improved output from __db_show_obj: put results into one line instead of multiple lines - new debug function __db_get_obj: return into about a tcl_obj in form of a dict (in general, one should not rely on Tcl_Obj internals, especially when upgrading over major Tcl versions, but for testing/understanding behavior etc., such a command is helpful). - extend regression test - make effects of namespace-imported classes more local remove various code smells: - add const declarations - prefer boolean tests - don't write "for" loops without a block - don't pass non-initialized value in an array on index [0] - reduce variable scope - prefer single returns statements in functions - dont't use CONST unless defined by Tcl-API code generator changes: - create enum types instead of enum values for nsf API - use enum types in code - improve variable for logging from "debugLevel" to "logSeverity" (print logging messages which have a severity larger equal the then given value; so; "nsf::configure debugLevel 0" will print everything, and "nsf::configure debugLevel 3" will print just error messages and omit warnings etc.) - this is not a change in sematics, but removes some confusion in the code. therefore the configure name was not changed - Remove occurrences of deprecated Tcl Call Tcl_AppendResult() in overall code - Remove unused NsfObjInfoObjectparameterMethod() (:nsf::methods::object::info::objectparameter). Makes CID 88775 obsolete. Entails removal of the then unused NsfParamDefsFilter() (which has been effectively replaced by performed by ::nsf::parameter::filter at the script level). - Added Rosetta example: https://rosettacode.org/wiki/Tokenize_a_string_with_escaping - Added Rosetta example: https://rosettacode.org/wiki/Tree_traversal - Added Rosetta example: https://rosettacode.org/wiki/Multiple_distinct_objects - Added Rosetta example: https://rosettacode.org/wiki/Add_a_variable_to_a_class_instance_at_runtime - Improve error message with {*} operator, not 'unknown'. Object new { :object method foo {a b c args} { puts --[current method]} {*}[list :foo 1 2 3 4 5 6]; : {*}[list foo 1 2 3 4 5 6]; catch {:{*}[list foo 1 2 3 4 5 6]} msg; puts msg=$msg } proc =foo {a b c args} { puts foo } catch {={*}[list foo 1 2 3 4 5 6]} msg; puts msg=$msg - Added Rosetta example: https://rosettacode.org/wiki/Polymorphic_copy#Tcl - Added Rosetta example: https://rosettacode.org/wiki/Inheritance/Multiple#Tcl - make nsf compilable with "-DTCL_NO_DEPRECATED" - Why is the following warning popping up? % Object info method parameters configure x* Warning: Could not find value checker type=virtualobjectargs defined on ::nx::methodParameterSlot ParamOptionParse(): 'virtualobjectargs' and 'virtualclassargs' defaulted to ConvertViaCmd when parsed from Tcl spec; explicitly set ConvertToNothing to match the intended semantics and to avoid false warnings (e.g., missing type=virtualobjectargs type checker) - Added Rosetta example: https://rosettacode.org/wiki/Inheritance/Single - new subcommand "nsf::current level", returns empty, if we are not on a nsf frame/level. - improve sanity test in ISOBJ(): obj->bytes might only be NULL when type is given. - under core-8-5-branch, nxsh yields on exit: % exit Warning: RefCount for obj 0x7fc98a050890 4 (name ::nx::shell2) > 1 - don't call tcl eval operations from NsfLog() in phyical destroy round - extend regression test for shell with tests in [info nameofexecutable] rather than in nxhs - hint: > SS the 'consider' recommendation of nx::Class->unknown message is irritating: > > % Class create Book > ::Book > % Book price set 10 > method 'price' unknown for ::Book; consider '::Book create price set 10' instead of '::Book price set 10' > ::Book ::nx::Class->unknown > invoked from within > "Book price set 10" > ... > As this is only relevant for someone with XOTcl legacy in mind, NX is > not about source compatibility with XOTcl anyways. GN: in XOTcl, it is hard to avoid NX (e.g. slots). we have this mix there. Reality shows, that users are confused, if they want to create an instance, but they receive just an error message. Mybe on the longer range, we can drop the hint. For the time being, I've made the hint even more verbose. - Investigate NsfMethodContext mem-bookkeeping/ possible leak: Turned out to be false positives due to Tcl history retaining references beyond NsfFinalizeCmd. An explicit script [exit] in interactive Tcl shells will still lead to unbalanced refcounts (NsfMethodContext), no way around that. But at least for exit-free scripts in tclshs, we should be fine. $ tclsh % package req nx; nx::Object new ::nsf::__#0 % exit ******** NSF MEM Count ********* * count peak * 0 1 INCR_REF_COUNT-converterNameObj * 0 14 Tcl_InitHashTable * 0 1 INCR_REF_COUNTkeyObj * 0 7 INCR_REF_COUNTtcd->onerror * 0 6 INCR_REF_COUNTcmdName * 0 1 INCR_REF_COUNTfullParamObj * 0 12 object.activationCount * 0 1 NsfClass** * 0 56 NsfParamDefs * 0 2 INCR_REF_COUNTnameObj * 1 18 NsfMethodContext (without "nx::Object new", "package req" only, the NsfMethodContext counts are balanced) ======================================================================== TODO: - /obj/ uplevel + upvar should behave different when being provided a relative level specifier, to provide filter/ mixin transparency at all times, and then move upwards as requested: /obj/ uplevel 1 set x 1 should be equal to /obj/ uplevel {uplevel 1 set x 1} It is rather pointless to provide for TclObjGetFrame resolution in uplevel/upvar methods, because then this use is just unnecessary sugar for using uplevel/ upvar commands directly. However, this would be a change that potentially breaks exisiting client code. - add value=isSet as a new VariableSlot method, to wrap around [info exists] and others. - DTrace: --with-dtrace vs. --enable-dtrace (as in Tcl)? generate header file only for distributions, auto-generated otherwise? -G option not supported anymore on Mac OS X (although man dtrace maintains references to it?) - coloncmd reform: * memcheck * use free list rather then obj list for freeing NsfColonCmdContext since the Tcl_Obj might be changed * maybe merge approach with Tcl obj type nsfInstanceMethod (and nsfObjectMethod) - IsObjectOfType(): the error messages provided could be improved: rather than saying "expected object of type ::C but got "::nsf::__#6" for parameter "s2"" one could report "expected object of type ::C but got "::nsf::__#6" of type ::D (::A ::B ::C ::nx::Object) for parameter "s2"" Otherwise, the instance name ::nsf::__#6 can be easily confused for the (sought) type name. - Refactoring option: Why not use ParameterCheck for setters? That is, rather than ParamParse on setter definition time, call ParameterCheck() when calling the setter (and have the param structure build lazily, on first use). Tcl_Obj intrep will do good, in most cases. And we gain a more unified interface (stripping away one unique path to Param* machinery)? - nsf::proc should also have a -returns option, right? % ::nsf::proc x required argument 'arguments' is missing, should be: ::nsf::proc ?-ad? ?-checkalways? ?-debug? ?-deprecated? /procName/ /arguments/ /body/ % nsf::proc x {-a:integer} -returns alnum {;} invalid argument 'alnum', maybe too many arguments; should be "nsf::proc ?-ad? ?-checkalways? ?-debug? ?-deprecated? /procName/ /arguments/ /body/" - nsf::parseargs would need some more love: * what is the intended behavior, in these edge cases? # TODO: Are the below cases intended? ? {apply {{} {nsf::parseargs {a} {}; llength [info vars];}}} 0 ? {apply {{} {nsf::parseargs {} {1}; llength [info vars];}}} 0 Right now, parseargs is more or less a NOOP in these cases (which is not consistent with arg-handling otherwise). * Should the behavior in the Tcl-only case be more like [lassign] or procedure-like record checking? * dependency inversion: parseargs is provided by nsf, but requires nx, occasionally. See: % package req nsf 2.1.0 % nsf::parseargs a:foo b non-existing slot object "::nx::methodParameterSlot" - Refactor: on the property/variable-creation paths, parseParameterSpec is currently called twice. once before createFromParameterSpec, once within. This should not be needed. - 1. extract the parseParameterSpec call out, and pass a parse result to createFromParameterSpec? 2. handle all cases requiring the early call to parseParameterSpec in createFromParameterSpec? My preference is 1. - various on slots: * RelationSlot value=delete -nocomplain is dead API. * value=delete semantics: I think we should provide a full-pass deletion, rather than the first occurrence of an element only (too specific); a capture-all deletion is more in line with a multivalued, which is a not necessarily unique list of elements: return [lsearch -glob -inline -all -not $l $value] * custom value checkers (type=*) inconsistency: Depending on whether the type=* method is called directly (configure, ArgumentCheck) or indirectly (per-slot value=* methods), the method parameter "prop" gets different values: * direct calls: name of the variable/parameter * indirect calls: name of the value=* method parameter which is the hardcoded 'value' error messages using $prop (rather than ${:name} of the type=* method-hosting slot) then turn out different depending on the call context. a) drop the 'prop' parameter of type= methods, because we can get the info from the slot. b) change the value=* method generator from hardcoding 'value' to substitute ${:name}, e.g.: set vspec [:namedParameterSpec {} ${:name} $options_single] in any way, this will require changing many test for errorm essages in the test suite. - XOTcl2, creates via unknown "fails" (does not trigger create/recreate) if intercepted by filters (because ::c1 is considered an existing cmd and ::c1 defaultmethod is dispatched): package req XOTcl xotcl::Class create C xotcl::Object instproc f args { puts f([self calledproc]); next } xotcl::Object instfilter f; # turn off to see regular behavior. puts [C ::c1]; # Class->unknown is called! puts --- puts [C ::c1]; # With filter 'f' on, Class->unknown is *not* called anymore. It should, otherwise (re-)create etc. is never triggered ... Some background: NextSearchAndInvoke() on a filter next does not check for dispatches based on object commands (as ObjectDispatch() *after* filter processing), but introducing a: if (cmd != NULL && CmdIsNsfObject(cmd)) { /* ... */ cmd = NULL; } leads to unwanted interactions with ensemble objects/methods. - Should we add exists to the Variableslot-Interface, to surface ::nsf::var::exists. + ::nx::VariableSlot public method value=exists {obj prop} { + ::nsf::var::exists $obj $prop + } Right now, one has to resort to a "low-level" /obj/ eval {info exists :/propVar/} or the like for checks before calling /obj/ /prop/ get|set ... - Add Rosetta examples: (more substantial) https://rosettacode.org/wiki/Active_object ? https://rosettacode.org/wiki/Window_creation/X11 ? https://rosettacode.org/wiki/Scope_modifiers - maybe add "nsf::configure logSeverity" as a new name for "debugLevel" and mark the latter as deprecated. - Shouldn't we add debug/deprecated filters for "info methods", i.e.: ... info methods ?-debug? ?-deprecated? ?-callprotection all|public|protected|private? ?-closure? ?-type all|scripted|builtin|alias|forwarder|object|setter|nsfproc? ?-path? ?-source all|application|system? ?/pattern/?" - add to doc: "-returns" flag for instproc/proc in XOTcl2 # in case, when similar cmds are commented, add: # nsf::proc -debug /name/ ... nsf::proc -deprecated /name/ ... nsf::method::property /obj/ ?-per-object? /method/ exists nsf::method::property /obj/ ?-per-object? /method/ debug ?0|1? nsf::method::property /obj/ ?-per-object? /method/ deprecated ?0|1? - maybe better handling of single-colon prefixed vars in trace procs, when passing values to nsf::var::set/get/... - maybe more complete handling of other forward "properties" - should we change "/obj/ info lookup syntax /methodName/" to return obj and method as well? (similar to "info method syntax /methodName/") - we could drop methods::object::info::objectparameter - check deactivated tests in tests/serialize.test C(One), C(IgnoreAll), C(None2) and xlloc fix Stefan: doc items - make rough comparison table with NX, XOTcl, tclOO, itcl, Ruby, Python comparison NX vs. TclOO is most probably the most important Most general superclass Metaclass Per-object methods Per-Object mixins -- none, class, or class hierarchy Per-Class mixins -- none, class, or class hierarchy transitive mixins classes Per-object filters Per-class filters aliases Traits Composite Traits Method protection public/protected/private positional arguments none, leading args, arbitrary argument value checkers Create objects classes with no callable methods - doc/tutorial2.html - warnings for "numeric" names for args and nonpos-args? - special handling of values looking like nonpos-flags, but which are not ones (-1, "- a b c", ....) in detection when to throw unknown. - interface of "variable" and "attribute": * add switch -array for "variable"? (Just setting is trivial, handling setters and incremental setter is more work) - extend mongo::gridfs::store_file with a switch -metadata to pass metadata together at gridfs file creation time - do we have to adjust the documentation in xotcl2 for object initialization? - maybe optional arg (true) to ::nsf::object::initialized to generalize -noinit - maybe: add a disposition=pipe - maybe: add "-asHTML" as style option to parametersyntax - MixinComputeOrderFullList() could receive a flag to store source classes in checkList - if the check on eg. info-heritage-circular in test/info.method.tcl reports a warning on exit, if we get an exception. - what to do with metadata analyzer? Still needed? Already replaced by new doctool? Does it have to run on make? Can doctool run on Make? - Higher binary compatibility for future versions: * It is not nice to have the full Nsf_Param structure in nsf.h (required for Nsf_methodDefinition in the c code generator) * It is not nice to have the full ParseContext structure in nsfmongo (required for the allocation of the parse context in the stubs) Adding fields to these structures would kill alder binaries - when alloc|dealloc are loaded via require, we have no redefined-protection on those. Since the script does not know, on which class|object these are defined one cannot make assumption on these. Problem? - The structure of the script body requires currently that "class|object ?-per-object?" is inserted at the 1st pos. This is not sufficient, if we would like to test in this script, whether the first arg is e.g. a class. - document value added replacements of Tcl functions - configure parameter type forward: - regression test - get rid of eager tcd creation (optimization, can go to future releases) - slotmachinerie 2 - should we deactivate add/delete for non-multivalued cases? - allow noarg+default/initcmd ? - default/initcmd/subsdefault: can we simplify these? or add messages for conflicting usages. - Makefile/::nsf::config: Integrate git meta-data (commit hash, branch/tag labels) - doc: * no-accessor properties/slots are still reported as methods: class * method parameters need indentation ... * method ensembles are reported as "Implementation details: alias", is this ok? * doc validator reports weird info submethods: info definition, info names, info objects -> mean "info slot *" ... smells like generator garbage ... * inconsistency: "info slot *" are built on "slotsobjects" which does not take -source and -closure parameters ... still, they are in the NX method interfaces ... review and document accordingly. * sub-method cross-references per @use does not work (parameters are not reproduced, probably no [:origin] resolution is performed: See the case for "info properties" -> "info slot definition" * "info method": elaborate on the options, right now the doc is minimal ... * "info method" -> why does the parameter syntax does not report all enumeration literals, rather than ?infomethodsubcmd? ??? * fix sub methods validation reporting -> mismatch? * Ensemble methods: obj info & friends ... there is no parametersyntax reported; add something literal in the template: ? * Object|Class mixin|filter guard -> how to document (and not reported by nxdoc as missing either, as their as slot-specific)? And link to Class class filterguard|mixinguard ... Why not defining the latter as ensembles "Class class filter|mixin guard"? * Ensemble methods, i.e. intermediate ones, should not be filter by inheritance in the nxdoc output. For example, info() in Class shares many details of info in Object, but it does not visualize this quasi-inheritance * @package.@require(): really needed? * @package.@version: fix validation mode ... expected/actual version numbers are not compared ... * NextScriptingLanguage/index.html: glossary entries in nsf.nxd should be sorted (in the source) ...... Maybe, a single glossary.nxd file? SS: Right now, the name of the nxd file derives from the the script name. I mark this as TODO for the future. * doc/langRef2.xotcl vs library/xotcl/doc/langRef.xotcl * @author: how to visualise the authorship in the generated markup (yuidoc)? - do we need contains in nx? - nsf::proc * check, if there are parameter types that should not be applicable for nsf::proc * toplevel (object less) introspection - documentation * migration guide 3.8. Dispatch, Aliases, etc.: to be done or omitted - check performance implications of value checker - library + XOTcl apps - work on binary packages of xotcl (store + xml) - nicht gewartete/nicht getestete library aus distro entfernen? - migration von einzelnen paketen nach next? von welchen? Ein paar Punkte im folgenden könnten obsolet sein: TODO "Kleinigkeiten" - should we continue to work on the problem of the interp-aliased class, exported from one ns, imported into another one? - constants in type converter (in and out) #if 1 /* the following check operations is xotcl1 legacy and is not generic. it should be replaced by another methodproperty. Most of the is*String() definition are then obsolete and should be deleted from xotclInt.h as well. */ if (isCheckString(methodName)) { return TCL_OK; } #endif For future releases (after first alpha/beta release) - cmd introspection: nsf defines a commands (e.g. nsf::proc) and unregistered methods. The interfaces of these commands can be queried via methods % nx::Object info method parameters ::nsf::proc -ad:switch procName arguments body % nx::Object info method syntax ::nsf::proc /cls/ proc ?-ad? /procName/ /arguments/ /body/ % nx::Object info method definition ::nsf::proc Warning: Could not obtain alias definition for proc... which return only partially correct results (the first is correct, the second one is misleading, the error message can be improved for the third case. maybe ::nsf::info command parameters|syntax /cmd/ might make sense, but there might be more candidates for nsf::info around. OTOH, we have already nsf::object::exists, nsf::is, etc. * generalizing parameter-specific per-object info Now we have __initcmd(varname) for init-cmds of variable traces __cmd(varname) for the eval-ed cmds (mostly for documentation purposes to postprocess the init block We could need __required_satisfied(varname) to handle required parameter aliases As generalization, we could use a dict __parameterstate(varname) or even __parameterstate with a dict to collect the various aspects. for performance reasons, we do not want to set this variable too frequent, serialization and blueprint aspects have to be considered. This would as well address cases, where the parameter has a different name than the associated variable (e.g. private properties) * Currently, in NX, specifying mandatory parameters may break object construction as init won't receive any arguments (no residual args). We should provide a warning when a user defines arguments for init (or provide some other syntactic sugar) * extend traits (object-specific traits, test cases, etc.) * RFE: forwarders/aliases: -checkalways is missing. Issues: 1) limit to -returns only? checkalways affects only input-parameters, not return. (purpose: make it possible to rely on parameter checking from external sources, no matter whether checking is turned on/off). furthermore, it effects only checking for procs. For C-implemented commands, there is no way to avoid e.g. checking if something is an integer, since the binary representation of the integer is passed. so i don't understand "limit to -returns". 2) cover value checkers of method parameters also, effectively overruling -checkalways settings of the aliased/forwarded nsf::proc or method? i guess that this is based on the assumption, there would be value-checkers for forwarders or aliases. Then one would have to handle the conflicts. However, forwarders and aliases pass arguments around without having any knowledge about parameter definitions. They don't check anything by design. * RFE Revisit nsf::*::assertion interface? Why does nsf::method::assertion allow for setting invariants. One would rather expect a ::nsf::object|class::assertion or the like? The reason for the current naming is simply that assertions are only implemented for scripted methods. * pre/post conditions are just checked for scripted methods, since only these have stack frames, which are necessary to access self or the resolver variables. * invariants are only checkable during scripted methods, there is no way to intercept c-based functions. Checking these before/after c-implemented functions should be possible though. * REF: feature request 'remove "-guard" from mixin and filter specs, just have two-element lists' would require to have different sets of converters for slots depending on object system * add maybe "::nsf::object::property /obj/ volatile 0|1" to alter volatile state. * Reduce / remove hard-code names. Right now, "method"/"alias"/ "forward" is returned by "info definition" introspection. This is not serious, since e.g. XOTcl handles this on the script level by mapping these names to the XOTcl counterparts. We could as well make this configurable via the object-system parameters. * Consider alternate method name/place for subcmds (and/or slots) on classes - currently, there are potential conflicts between slots and ensemble objects - provide a different place in the namespaces could simplify this * Cleanup the set of active filters when filters are removed (only relevant for the speed of scripts with filters and a high number of instances) * Ensembles - It could be possible to reduce stack frames in ensembles. Just a top ensemble frame could be sufficient. - The full names for ensemble methods could be stored in the cmd tables to make lookup faster. * Serializer: handing of xo::at_cleanup in serializer (either generalization or move to OpenACS/aolserver init/naviserver init) * Parameter/argument handling - Add an unknown handler for unknown non-pos args to Argument parser. The problem is to find a way to avoid method deletions or redefinitions or to recover from these gracefully (when e.g. the unknown handler deletes the parameters currently being worked on). - Canonical parameter representations: "p:integer,multivalued" => "-name p -type integer -multivalued" "x:type,arg=::D d1" => "-name x -type type -arg ::D -default d1" - Argument passing of C functions is currently based on an interpreter of the argument lists. It should be possible to turn the interpreter into a compiler to speed up argument passing. But maybe, this would bloat the code-size. - Use parameter syntax in genTclAPI - better handling of "c1 cget -noinit" ? * experimental features: - document/extend/generalize/remove the experimental object properties perobjectdispatch and keepcallerself - behavior on keepcallerself on ordinary dispatches with implicit/explicit receiver (currently the flag is ignored, the code just commented out) * C-Code * Several of the tracing options in nsf.h could be replaced by DTrace * Rework implicit namespace completion (NameInNamespaceObj(), maybe based on BeginOfCallChain()). * Rework C-interface (maybe for post-alpha, but we have be first clear on scope and intention. A possibility would be to provide all entries from gentclAPI, but we would loose most likely static property and the newly achieved ease of changing is effectively frozen by the stubs interface, which has to be stable. * NsfClassListAdd() and friends could be made generic * Coroutines - extend coro regression test - coro-enable nsf::proc * reenable/translate deleted XOTcl demo scripts, such as e.g. those from library/xotcl/apps/scripts observation: - [current isnextcall] does not work for ensemble next: ... but should probably not, since this is an implicit next call just for resolving an ensemble call. Object create o { :public object method foo {} {return [current isnextcall]} :public object method "x y" {} {return [current isnextcall]} } Class create M { :public method foo {} {next} :public method "x y" {} {next} } ? {o foo} 0 ? {o x y} 0 o object mixins add M ? {o foo} 1 ? {o x y} 1; # gives 0 ..../nsf2.4.0/README.md000644 000766 000024 00000000453 13323154001 014441 0ustar00neumannstaff000000 000000 # Next Scripting Framework # ## Compilation of Source Distribution: ## On Unix-like environments (including macOS), do ```` ./configure make sudo make install ````` For more details, and build instructions, binary releases, community support etc. consult: [https://next-scripting.org/] ./nsf2.4.0/ChangeLog-2.0b3-2.0b5.log000644 000766 000024 00000132741 14064565727 017020 0ustar00neumannstaff000000 000000 2013-06-07 Gustaf Neumann - fix typo - remove doc target from "install-doc" since this takes a while in a "make install" - document tricky trace script setting in regression test - use tcl8.5 commands instead of 8.4 idioms - don't build doc always, since it takes a long time - documentation update and regeneration of html docs - add all tcl 8.5 cmds, nx methods + info methods - add missing tcl-keywords to nx-mode.el - adjust style files for document generation - added rules for generating pdf to ease release management - code cleanup - updated HTML renderings of examples 2013-06-06 Gustaf Neumann nsf.c: - fix a bug in SlotContainerCmdResolver() when NSF_MEM_COUNT is activated - fix a small memory leak for PER_OBJECT_PARAMETER_CACHING - all cases detectable with --enable-memcount=yes are fixed - fix git command in release instructions - fix label for debugging reference counts - updated TODO - reduce variable scopes nx::test: - change test cases to newer interface - don't use "namespace import nx::*" in test cases when not required nx::test: - use the standard configure interface for configuring instead of own version - changed from nx::Test to nx::test (user never has to know that nx::Test is a class). 2013-06-05 Gustaf Neumann - Eliminate all use of Tcl_GetStringFromObj() function. - fix typos, example code - further release work 2013-06-05 ssoberni Fixed some typos and suggesting some rewording 2013-06-05 Gustaf Neumann - initial checkin of nx-mode.el - preparing 2.0b5 release 2013-06-04 Stefan Sobernig Left a to-do in the nxdoc backend Completed update of nxdoc for NX 2013-06-04 Gustaf Neumann serializer.tcl - added flag -objmap to Serialzer.deepSerialize to make serializer usable for copying (-map is to coarse) - extended regression test 2013-06-04 Stefan Sobernig Adjusted nxdoc for the recent changes to NSF/NX 2013-06-03 Gustaf Neumann nsf.c - removed obsolete function AssertionAppendPrePost() - removed obsolete function NsfNSCopyCmdsCmd() and ::nsf::nscopycmd (handled now more general on scripting level in the "copy" method) nx.tcl: - "copy" method: fixed copying of class-level per-object methods - extended regression tests nsf.c - fixed a potential crash for objects having a wrapper-less alias defined 2013-06-03 ssoberni nsf.c - Make sure that the original error message is preserved when calling destroy after a failed CMD or INITCMD 2013-06-03 Gustaf Neumann nsf.c - fixed a bug in "info methods returns" in cases, where no returns info was available. - we can "/obj/ copy" now objects/classes containing * aliases * setter * ensemble methods * method protections Instead of handling cmd copying in NsfNSCopyCmdsCmd, it is replaced now by introspection. - extended regression test 2013-06-02 Gustaf Neumann nx::test: - deactivate calling overhead calculation, since this is not reliable (sometimes larger than the call). - improved handling of required configure parameters when classes are changed dynamically. When configure parameter are defined required, checking for the absence of required parameter was only performed at creation time. When objects were re-classed or their classes extended with required parameters, later calls to configure did not trigger exceptions. Now we check for the existence of the instance variable which addresses most of these points, but in future we might wish a more general solution (see comment for futures releases) - when creation with a required configure parameter failed, delete the half-baked object to avoid confusing states. - nx::test: show msg at start of test file 2013-06-01 Gustaf Neumann - changed multiplicity of mixin, object-mixin, filter, object-filter from 1..n to 0..n; rationale: when one has a list of e.g. mixins, which should be passed, one has to test for the length before passing it, otherwise the empty list would generate an error. Allowing 0..n makes the usage simpler and the program shorter. nx.tcl: - renamed variable option "-config" to "-configurable" to make its intention clearer 2013-05-31 Gustaf Neumann - traits: added ability to turn on verbosity for traits by using nx::configure trait-verbosity on|off nx.tcl: - replaced functionality of "/obj/ configure" by "/obj/ info configure" to re-enable semantics of the plain configure method, even when called without arguments. "/obj/ info configure" is actually a convenience method to allow one to write o1 info configure instead of o1 info lookup configure syntax package nx::class-method: - convenience package similar to nx::plain-object-method - allow for usage "C class method ..." in addition to "C object method". - made warnings configurable via nx::configure class-method-warning on|off - completed coverage and test cases package nx::plain-object-method: - made warnings configurable via nx::configure plain-object-method-warning on|off - completed coverage and test cases 2013-05-30 Gustaf Neumann nsf.c - fixed potential infinite loop in pattern matching for precedence lists - cget: make error message closer to tcl conventions - extended regression test 2013-05-29 Gustaf Neumann - adapt to object methods - prevent default value checking, when it is determined by a command - completed coverage if plain-object-method.tcl - provide warnings via plain-object-method.tcl via "nsf::log warn ..." 2013-05-28 Gustaf Neumann - renamed initblock parameter from __initcmd to __initblock - renamed nsf::configure parameter from "keepinitcmds" to "keepcmds" - saving "keepcmds" in an associative array named "__cmd(/parameternName)" to allow saving of multiple parameters with less name clash danger (when application stays away from variables stating with double underscore) nx.tcl: - removed "info is .." since it might raise more questions than it solves - changed enumeration values for "-source" in "info lookup methods" "info lookup slots" "info methods" "info slots" from "all|application|baseclasses" to "all|application|system" for consistency with "nsf::my" and "nsf::dispatch" which uses "-system" as well 2013-05-26 Gustaf Neumann Traits: - changed from traits-as-objects to traits-as-classes. This allows for higher orthogonality of traits and class definitions and allows in principle traits for object-specific methods (not fully implemented/tested) - fixed property/variable inheritance in traits. - remove spurious debug line Cleanup of nsfAPI.decls - remove unneeded enumeration types - use "typeName" to shorten reported names of parameters - use camel case for reported names - changed ::nsf::parametersyntax(..) to ::nsf::parameter::syntax(..) - xotcl2: adjusted manual parameter syntax entries to new conventions 2013-05-24 Gustaf Neumann - added implementation for slots with traces+types for classes - exception for incorrect defaults are thrown during slot creation - extended nsf::is, added parameter * ?-configure? -- accept configure parameter options * ?-name /name/? -- provide a parameter name for error message - simplified nx.tcl by using new nsf::is - extended regression test - added partly implementation for slots with traces+types for classes - fixed cases, where valuechangedcmd (and the other traces) did not work with "configure" method. When slot traces are used, it cleans other traces for the same operations. - extended regression test 2013-05-23 Gustaf Neumann nsf.c: - fix crash when "nsf::my" is called with a single argument outside the object context. - fix assert - removed some TODOs from tests/parameters.test - parameter dispositions: We differentiate now between "initcmd" and "cmd": an "initcmd" is only evaluated once, but one can provide configure values for this parameter later. a "cmd" is executed on every evaluation, it is only possible to pass cmds to it. The trailing argument of the configure parameters (used e.g. for scripted object/class definitions) is now of type "cmd". Implementation not yet complete (object cases are not correct). - streamline documentation C-code Generator: - added "-typeName" for enumeration types that allows for disambiguation of enumerations with different argument names. Before that, the argument name determined the c-type of the enumeration. Therefore, it was not possible to use argName "-type" for two different functions with a different list of enumerators. - renamed option "-methodtype" to "-type" in /obj/ info methods ... ?-type all|scripted|builtin|alias|forwarder|object|setter|nsfproc? ... /obj/ info object methods ... ?-type all|scripted|builtin|alias|forwarder|object|setter|nsfproc? ... /obj/ info lookup methods ... ?-type all|scripted|builtin|alias|forwarder|object|setter|nsfproc? ... - minor code cleanup 2013-05-22 Gustaf Neumann - streamlined AddSlotObjects() - cleanup of TODOs - nsf.c: handle full-qualified name for private slots (AddSlotObjects()) - extended regression test 2013-05-21 Gustaf Neumann - updated next-tutorial: * bring definitions of properties and variables up to date * fix "object methods" - XOTcl2: ensure public accessor when "-parameter ..." is used - extended parameter extractor: new functionality ::nsf::parameter get default /parameter/ ?/varname/? ::nsf::parameter get type /parameter/ /obj/ info parameter get default /parameter/ ?/varname/? /obj/ info parameter get type /parameter/ 2013-05-20 Gustaf Neumann - hopefully the last changes for ?object? method|variable|property: defined * "/obj/ delete object method" * "/obj/ delete object property" * "/obj/ delete object variable" - "info method syntax" returns now "/cls/ ...." - "info object method syntax" returns now "/obj/ ...." - updated next-migration guide to reflect changes from the configure reform - make name fully qualified for symmetry reasons - minor cleanup - nx-pp.tcl: fixed changed accessor handling, added cget to highlight words 2013-05-19 Gustaf Neumann - added new regression test info-variables.test 2013-05-19 Gustaf Neumann Method and configure parameter reform, Part 3: - added /cls/ info lookup variables -> list of handles /obj/ info lookup object variables -> list of handles /obj/ info variable definition|name|parameter /handle/ - nx.tcl: added forward compatible scripted implementation of "lmap" - nsf.c: handle names for private slots in pattern provided to AddSlotObjects(), used e.g. in "info lookup slots /pattern/" 2013-05-18 Gustaf Neumann - dropped "/obj/ info slot definition /obj/" in favor of "/slotobj/ definition" 2013-05-17 Gustaf Neumann - nx.tcl: handle "incremental" in slot reconfigure - nx.tcl: change defaultAccessor to "none" 2013-05-17 Gustaf Neumann - Method and configure parameter reform, Part 2: In order to streamline the interface further, we tried to follow the idea to use "... info /plural word/" to obtain a set of handles, and then a separate call to obtain the details. Therefore, we replaced /cls/ info slot objects /cls/ info slot definitions /cls/ info slot names /obj/ info object slot objects /obj/ info object slot definitions /obj/ info object slot names /obj/ info lookup slots by /cls/ info slots ?-type /type/? ?-closure? ?-source all|application|baseclasses? ?/pattern/? /obj/ info object slots ?-type /type/? ?/pattern/? /obj/ info slot definition /obj/ /obj/ info lookup slots ?-type /type/? ?-source all|application|baseclasses? ?/pattern/? 2013-05-16 Gustaf Neumann - Method and configure parameter reform /cls/ info configure parameters ?pattern? -> list of params /cls/ info configure syntax -> syntax output /obj/ info method parameters /methodName/ ?/pattern/? -> list of params /obj/ info method syntax -> syntax output /obj/ info lookup configure parameter ?/pattern/? -> list of params /obj/ info lookup configure syntax -> syntax output /cls/ info parameter list|name|syntax /param/ -> value 2013-05-14 Gustaf Neumann - avoid crash in case NsfParameterGetCmd() is passed a plain value 2013-05-13 Gustaf Neumann - minor documentation updates 2013-05-10 Gustaf Neumann - initialize stub-tables only once - syntax formatter: use /value/ for denoting placeholder in "... info method syntax ..." 2013-05-07 Gustaf Neumann - parametersyntax: make placeholders explicit - moved "/obj/ info slot definition|..." to "/obj/ info object slot definition|..." for consistency - provided "parametersyntax()" for "object mixin" and "object filter" 2013-05-05 Stefan Sobernig - win/makefile.vc: have the install target copy the public headers as well 2013-05-04 Stefan Sobernig - MinGW toolchains do not provide support _vscprintf(), so we limit the use of it to MSVC; tested NsfDStringPrintf under MinGW - Provide tcl library path to summary.tcl and remove intermediate file from repo - Fixed the Win32 logic for computing the Tcl_DString in NsfDStringPrintf(), tested for MSVC under x86 and amd64 2013-05-04 Gustaf Neumann - updating next-tutorial to object method syntax 2013-05-03 Gustaf Neumann - updated migration guide - update to new naming 2013-05-03 ssoberni - Fix the 86-specific tests to reflect the object-modifier reform 2013-05-03 Gustaf Neumann - try to print arguments in one sweep in NsfDStringPrintf() - remove "extern" declarations 2013-05-02 ssoberni - Revised NsfDStringPrintf() for portability to non-C99-compliant C runtimes (MSVC); remains to be tested 2013-05-02 Gustaf Neumann - first and incomplete update of migration guide to new syntax 2013-05-01 Stefan Sobernig - Re-enabling deletion of intermediate file in makefile - Remove legacy build artifacts - Provide native Win build support for MSVC++ and MSVC, using the Tcl 8.6 name templates. Tested using Visual Studio 12 (VC and name in version 11). See makefile.vc for build instructions for Win32 and Win64. 2013-04-29 Gustaf Neumann - bumped version number to 2.0b5 - tested with NaviServer and OpenACS (new version of nx needs as well a newest NaviServer, since ns_cache implementation needs to be objectified; newest NaviServer version works as well with older nx) - fix xotcl instance method serialization (still not covered in regression test) - renamed "package require nx::class" to "package require nx::class-method" in analogy to "nx::plain-object-method" - added "/obj/ object variable" and "/obj/ object property" 2013-04-28 Gustaf Neumann MongoDB - added "nx::mongo::db drop collection /name/" - returning status from "nx::mongo::db remove" as success (0 or 1) - adjust to object interface - reduce verbosity - add error messages for slot lookup failures Updated MongoDB interface - upgraded to c-driver 0.7.1 - tested with MongoDB 2.4.4-pre - new commands: * mongo::run * mongo::cursor::find * mongo::cursor::next * mongo::cursor::close - adapted interface for c-driver 0.7.1 (e.g. new optional name for mongo::index - nsfPointer.c: add parameter to Nsf_PointerDelete() for allowing optional freeing - reduced default verbosity - moved NsfConfigEnabled from nsf.h to nsfInt.h (no need to be part of the public interface) - moved NSF_ARGPARSE_* macros to nsf.h (since arg parser is public and uses these flags) 2013-04-23 Gustaf Neumann Object-method Reform: - changed interface to object specific commands by requiring an ensemble named "object". The rational behind is essentially to use always the same info command to retrieve object specific methods, no matter whether these are defined on a plain object or a class object (does not break the "contract" what e.g. "info method" returns). Now we define methods via: /cls/ method foo {args} {...body...} /cls/ object method foo {args} {...body...} /obj/ object method foo {args} {...body...} Similarly, aliases, forwards and mixins are defined, e.g. /cls/ mixin add ... /cls/ object mixin add ... /obj/ object mixin add ... /obj/ require object method ... The same change propagated as well to the "info" method. Now we have: /cls/ info methods ... /cls/ info object methods ... /obj/ info object methods ... Similar, the object parameterization uses /cls/ create obj -object-mixin M /cls/ create obj -object-filter f /metacls/ create cls -mixin M1 -object-mixin M2 /metacls/ create cls -filter f1 -object-filter f2 - as a consequence, a) "/cls/ class method ...", "/cls/ class alias ...", "/cls/ class forward ...", "/cls/ class filter ...", "/cls/ class mixin ...", "/cls/ class info ..." "/obj/ class method require method ..." "/obj/ class method require public method ..." "/obj/ class method require protected method ..." "/obj/ class method require private method ..." were dropped b) "/obj/ method ....", "/obj/ alias ....", "/obj/ forward ...." "/obj/ filter ...." "/obj/ mixin ...." "/obj/ info method*" "/cls/ create obj -mixin M" "/cls/ create obj -filter f" "/obj/ method require method ..." "/obj/ method require public method ..." "/obj/ method require protected method ..." "/obj/ method require private method ..." were dropped - added package nx::class to allow optionally the "class" notation "/cls/ class method ..." (and friends, see (a)), and "/cls/ class info ... - added package nx::plain-object-method to allow optionally plain method b) "/obj/ method ...." (and friends, see (b)) - add support to slots to use ensemble methods as setters 2013-04-17 Gustaf Neumann - allow explicit unsetting of -per-object flag in 0-argument -flag=value notation 2013-04-05 Gustaf Neumann - reduce variable scope 2013-03-25 ssoberni - Improved wording in comment on NsfConfigEnabled() - Irgh. Had forgotten about two-level stringification to provide configuration macro expansions as strings in NsfReportVars() 2013-03-25 Stefan Sobernig - Adding a helper macro NsfConfigEnabled() to test for active/inactive build-time configurations; rewrote NsfReportVars() accordingly. This makes NSF compilable under MSVC (VC11). Thanks are due to Stephan Adelsberger for reporting the issue. 2013-02-19 Gustaf Neumann - ByteCompiled(): fix indentation of preprocessor #if statements - ByteCompiled(): ensure result setting in case HAVE_TCL_COMPILE_H is not defined - improve wording in rosetta example 2013-01-22 Gustaf Neumann - more code cleanup - reduce variable scopes - remove EXTERN declarations from function definitions 2013-01-08 Gustaf Neumann - Update to latest TEA. - Follow new naming convention for auto-tools (using configure.ac) - silence compiler warnings 2012-12-12 Gustaf Neumann - replace Tcl_GlobalEval by Tcl_Eval, since Tcl_GlobalEval will be removed in futures versions of Tcl 2012-11-26 Stefan Sobernig - Checked built and test suite against Tcl 8.6rc2 (core-8-6-0-rc) under MinGW32; removed temporary fix for bug #3401422 2012-11-19 Gustaf Neumann - quote filename in content disposition 2012-11-16 Gustaf Neumann - replace nx::configure option defaultPropertyCallProtection by defaultAccessor - protect trf against leading dashes 2012-11-15 Gustaf Neumann - deactivate tests in library file 2012-11-14 Gustaf Neumann - add additional "convertto" when generating zip files from strings 2012-10-30 Stefan Sobernig - The asciidoc-related configuration artifacts, especially for Tcl/NSF-specific code highlighting, are now contained in the source distribution and integrated with the respective make targets. Besides a running asciidoc installation, there is no further configuration need. Tested with asciidoc 8.6.8 2012-10-28 Stefan Sobernig - Extending test case to cover slotassign issue - Adding a test and a temporary fix for the ::nsf::is issue in setCheckedInstVar 2012-10-13 Gustaf Neumann - Make sure to NS_EXPORT Ns_ModuleVersion for people using still the old-style AolServer module. 2012-10-04 Gustaf Neumann - make assumptions in code explicit 2012-10-03 Gustaf Neumann nsf.c: - handling of method names in error messages from nsfAPI.h. Make sure that error message is generated with the actual method name. 2012-10-02 Gustaf Neumann nx.tcl: - property has now a boolean non-positional argument "-config" /obj|cls/ property ?-accessor value? ?-config boolean? ?-incremental? ?-class value? spec ?initblock? in symmetry with "-accessor" (parameter option "noconfig" is still needed to flag nsf for variables that should be initialized, which are not configurable - "/obj|cls/ info slot definitions" returns a full command (containing flags and property|variable) - extended regression test 2012-09-30 Gustaf Neumann - remove debug output nsf.c: - factored out ParameterMethodForwardDispatch() to call a parameter method defined as a forwarder the same way from "configure" and "cget" - extended regression test - improve comment 2012-09-29 Gustaf Neumann - extended regression test - changed name "/obj|cls/ slot info definition" to "/obj|cls/ slot info definition" since result is a set - dropped parameter method "properties" - dropped "/obj/ info properties" (since "properties" or "variables" are returned") nx.tcl: - change parameter name in "/cls/ info parameter ... ?pattern?" from "name" to "pattern" 2012-09-28 Gustaf Neumann - added functionality for "cget" to call parameter-methods (e.g. "... cget -class"). The method cget calls either "/slot/ get ..." (when slot=... is provided in the parameter spec) or it assumes that the method without argument returns the value - added "::nsf::object::property /obj/ volatile" to query whether an object is volatile or not - "/obj/ cget -volatile" returns now the volatile state of the object - factored out ParameterMethodDispatch() from OConfigureMethod() - extended regression test 2012-09-27 Gustaf Neumann - invalidation of per-object parameter cache * on mixin changes and * on deletion/adding of per-object slots - deactivate PER_OBJECT_PARAMETER_CACHING per default (flipping this parameter makes regression test more than 20 faster). - extended regression test - NsfObjInfoObjectparameterMethod(): return not only the first matching parameter, but the list of all matching ones. The last optional argument was renamed from "name" to "pattern" accordingly - rename invalidateobjectparameter -> parameter:invalidate::classcache - rename invalidateobjobjectparameter -> parameter:invalidate::objectcache - bring cmds into alphabetical order 2012-09-26 Gustaf Neumann - first draft of per-object parameter caching (for per-object-mixins and per-object properties). nsf.c: - fix potential bad interaction between per-object mixins and per-class caching of object-parameters 2012-09-25 Gustaf Neumann - don't blindly register all object/class methods for XOTcl Property Reform Part 2: better handling of per-object properties nsf.c: - changed "/class/ __objectconfigure" to "/obj/ __objectconfigure" to be able to handle per-object properties on classes properly. - renamed "info method parametersyntax" -> "info method syntax" - renamed "/obj|cls/ info method parametersyntax" into "/obj|cls/ info method syntax" - replaced "::nsf::methods::class::info::objectparameter" by "::nsf::methods::object::info::objectparameter" - new command "::nsf::parameter::specs ?-configure? ?-noposargs? slotobjs": convert provided slotobjs into a list of parameter specs - new command "::nsf::parameter::get list|name|syntax parameterspec": convert parameter spec into syntax form, or retrieve pieces of information from it (can be extended in the future) - added more or less generic list handling functions TclObjListFreeList(), TclObjListNewElement() and TclObjListAdd() used by "::nsf::parameter::specs" - replaced "::nsf::method::property /obj/ -per-object /name/ slotcontainer ?value?" by "::nsf::object::property /obj/ slotcontainer ?value?" - added "::nsf::object::property /obj/ hasperobjectslots ?value?" nx.tcl: - new info methods * "/obj/ info lookup parameter definitions" * "/obj/ info lookup parameter names" * "/obj/ info lookup parameter list" * "/obj/ info lookup parameter syntax" - changed "/cls/ info parameter definition ?name?" into "/cls/ info parameter definitions ?name?" since ir returns a list. Still, "list" or "syntax" won't be plural 2012-09-22 Gustaf Neumann - renamed timing variable from "time" to "ms" - added timing statistics 2012-09-21 Gustaf Neumann - generalize handling for per-object-properties - added additional file for regression test 2012-09-19 Gustaf Neumann Property reform part 1: - disallow protection modifiers for "properties" and add new flag "-accessor" to "property" and "variable" This changes definitions like Class create C { :property {a a1} :public property {b b1} :protected property {c c1} :private property {d d1} } to Class create C { :property {a a1} :property -accessor public {b b1} :property -accessor protected {c c1} :property -accessor private {d d1} } since "properties" are always public accessible over the "configure" and "cget" interface, but the accessors methods might not be public. The value of the accessor might be also "none" (specifying explicitly that no accessor is wanted) or "", which means: use the default. Same holds for "variable" - disallow parameter option "incremental" and change it to a flag of the property or variable. The motivation for this is due to the fact, that "incremental" is a property of the accessor, and not of the value. old: Class create C { :property foo:int,incremental :variable bar:int,incremental } new: Class create C { :property -incremental foo:int :variable -incremental bar:int } - disallow "public class property" and friends since these are not needed - removed parameter property "noaccessor" - removed "nx::configure defaultPropertyCallProtection" and method hook "__default_property_call_protection" - introduced "nx::configure defaultAccessor" and method hook "__default_accessor" - for the time being, "defaultAccessor" is "public" for NX and XOTcl, will be changed to "none" in NX - extended regression test (new file properties.test) 2012-09-15 Gustaf Neumann nsf.c: - fixed parameter syntax for required nonpos args - deactivate deletion of methods via nsf::object::delete during shutdown to avoid missing slot forwarders called from destructors nx.tcl: - remove debugging output - renamed testlog file, remove it on "make clean" nsf.c: - made argument of cget required nx.tcl: - added Tk-style methods "configure" and "cget" - added additional regression test set for cget and configure nsf.c: - implemented cget as a configure-like method, dropped ensemble method variant nx.tcl: - simplified "/obj|cls/ delete method" due to resolving capabilities in nsf::delete::method - fixed regression test to run all test again correctly xotcl2.tcl: - made destructor of Connection more robust such it does not depend on accessor methods. 2012-09-14 Gustaf Neumann nsf.c: - extended nsf::method::delete to handle ensemble names nx.tcl: - added tk/incr-tcl style cget methods on class/object levels. - improve copy handling with other child-types of the slot container working - make sure to ignore non-slot-type objects in slot introspection - worked on regression test until "methods.test". others are missing, but maybe reconsideration 2012-09-13 Gustaf Neumann - updated 34 copyright notices nx.tcl: - rename the following internally called methods (not for XOTcl). alloc -> __alloc dealloc -> __dealloc objectparameter -> __objectparameter recreate -> __recreate - from these methods, only __objectparameter is defined per default, the others are defined on demand changes to allow efficient tk/incr tcl compatible configure/cget - refactored code to allow one to parameterize handling of required flag for parameters - don't flag an error when configure is called on an initialized object (logic: if the object is initialized, configure must have been called before, and the required action must have been already taken). - rename nx::Object.configure to nx::Object.__configure to free method name "configure" for an e.g. tk-like configure 2012-09-10 Gustaf Neumann - finalize transition from old code 2012-08-28 Gustaf Neumann - fix frame scoping for myvar/myproc 2012-08-10 Gustaf Neumann - allow one to change title of a scripted document - make doc beautifier more robust for invalid lists - use explicit return in tutorial example scripts 2012-08-01 Gustaf Neumann - improve documentation - use "nsf::relation $cl superclass" instead of "$cl configure -superclass" - minor documentation updates nx::test: - added summary at the end of "make test" via log file - updated .gitignore 2012-07-31 Gustaf Neumann nx.tcl: - set multiplicity for mixins and filters by default from 1..n to 0..n to avoid error messages, when e.g. empty mixin lists are configured. Setting empty mixin-lists is strictly speaking not necessary, but this eases the code in cases the lists are sometimes empty. - handle cyclical superclass/class dependencies during object system finalize - extend regression test 2012-07-18 Gustaf Neumann nsf.c: - ignore in internal calls to "dealloc" protection settings - handle cyclical class dependencies during object system finalize - extend regression test 2012-07-18 Stefan Sobernig - library/nx/nx.tcl: Following the code review, implemented a first scheme for handling traces in setCheckedInstVar. This gives us consistent behavior for defaults and traces (valuechangedcmd) across classes and objects. - tests/parameters.test: Adjusted the relevant tests - Pending: setCheckedInstVar currently uses ::nsf::is to validate the value (e.g., default value) to be set. However, it might get passed parameter options which do not fit the NSF_DISALLOWED_ARG_VALUECHECKED filter. 2012-07-17 Gustaf Neumann - define method "proc" of ::xotcl::Attribute in terms of ::xotcl::Object proc - make sure to have gcc branch hints in generated code - honor default type in "info slot names" 2012-07-17 ssoberni - Addressed a number of issues in the NX slot infrastructure (which revealed themselves when running Mark's BusinessActivities implementation in XOTcl2 mode): - generic/nsf.c: Initcmd blocks (as set for registering per-class slot traces) were subjected to argument checks causing unexpected behavior (e.g., attempts of unboxing initcmds as Tcl lists or of checking initcmds against value types). This was fixed by exempting NSF_ARG_INITCMD params from argument checking in ArgumentCheck() explicitly. - library/nx/nx.tcl: For per-class parameters, the use of valuechangedcmd effectively overruled the default value specified (simply because the generated initcmd holding the trace statements took the place of the default value). While for defaultcmd and for valuecmd the parallel use of default is forbidden, the valuechangedcmd semantics allow for specifying a default, in principle. This was fixed by providing a default-setting statement in the initcmd. - tests/parameters.test: Added tests to cover the above (and beyond). - library/xotcl/library/xotcl2.tcl: Extended the backwards compatibility of the hybrid XOTcl2/NX slots infrastructure to the XOTcl 1 interface: This includes support for inline -proc statements and instvar. This compatibility level corresponds to the slot interface as documented (by examples) in the XOTcl language ref and the manual. - library/xotcl/tests/slottest.xotcl: Added tests for the above compatibility enhancements. 2012-07-16 Gustaf Neumann - allow instance property inheritance for traits 2012-07-11 Gustaf Neumann - Don't advertise to use "configure" method for calling class/superclass in documentation sice we have better ways. 2012-06-27 ssoberni - Replaced erroneous check using the object-specific rather than the class-specific options in the query mode of ::nsf::relation with class-filter. This prevented [::nsf::relation /cls/ class-filter] from returning any filter info. As a consequence, the incremental interface of the filter slot failed (e.g., [/cls/ filter add aFilterProc] effectively reset the class-filter cmd list instead of adding to it). Thx are due to Markus Moldaschl for reporting the issue. - Aligning class-filter and object-filter behavior on errors during filter additions to the state-preserving behavior of object-mixin and class-mixin. - Adding basic tests on object-filter/class-filter (::nsf::relation, filter slot interface) and specific ones to cover the above issues. 2012-06-25 Gustaf Neumann - added a SlotContainerCmdResolver() to avoid interaction of slot names with names of callable tcl commands. Without the SlotContainerCmdResolver() the call to "list" in a property named "list" leads to a call to the container object ::Test2::slot::list instead to the intended ::list. The implementation is not perfect, since it ignores the namespace path inside the slot container. - added regression test. - adding gcc helper files to ignore list - cosmetical documentation changes 2012-06-01 Gustaf Neumann nsfShadow.c - bump MethodEpoch when a tcl ::rename command happens on a nsf method (which might be cached in a Tcl_Obj) This fixes a crash reported by Arthur Schreiber nsf.c: - make NsfInstanceMethodEpochIncr() and NsfObjectMethodEpochIncr() accessible from all files using nsfInt.h - remove experimental code (backslash escaping for "," in parameter option parse 2012-05-22 Gustaf Neumann - remove dependency of generated stub file from nsfInt.h - fix compilation when dtrace is activated (missing parenthesis, many thanks to Victor Guerra for noticing) - document private properties in tutorial and migration guide - improve wording in documenting - extend regression test 2012-05-22 Stefan Sobernig - configure, configure.in: Under win, the CLEANFILES missed a pattern for object files - nsfInt.h: Based on the BUILD_nsf convention, the internal header introduced a TCL_STORAGE_CLASS macro placing the dllimport attribute (under Win/MinGW builts). As a consequence, shared and stub builds ended up with function declarations annotated with dllimport (which for these cases is either unnecessary or even breaks builds because the dllexport counterpart is missing, obviously). As nsf.h includes a sane DLLIMPORT/DLLEXPORT handling (copied over from tcl.h), I simply removed the special macro handling from nsfInt.h. - NsfProcStub(): Use the EXTERN macro rather than extern directly 2012-05-21 Gustaf Neumann - added documentation for "/obj/ info name" to migration guide and .nxd file - adding more comments to examples in migration guide - added design study ruby-mixins.tcl to example-docs and regression test - minor polishing 2012-05-17 Gustaf Neumann - change "#!/bin/env" into "#!/usr/bin/env" 2012-05-14 Gustaf Neumann - increase backward compatibility for ::xotcl::Attribute by defining the public methods "set", "exists" and "istype" 2012-05-14 ssoberni - apps/utils/nxdoc: fix shebang path to env ... - generic/nsf.c, ObjectDispatch(): Re-arranged the handling of fully-qualified method dispatches with the selectors resolving to existing objects and, in particular, nested (namespace-qualified) objects. Prior to that, dispatches such as "::C ::parent::child" were not covered appropriately: ::parent was reported as valid regObj and so the dispatcher continued to dispatch to the cmd "::parent::child" in the self-context ::parent::child ... with unwanted side-effects (e.g., XOTcl's unknown handling was bypassed). - tests/methods.test: Added basic tests on the (current) handling for such ::* dispatches and a specific test set on the intended XOTcl behavior. 2012-05-13 Gustaf Neumann - start error messages with a lowercase word for consistency and to follow closer to Tcl's conventions - added "private property foo" - extended regression test - allow parens in property names (array syntax) - added "/obj/ info name" (as alternative to "namespace tail [self]") - use newer style of tcl-obj interface instead of sprintf 2012-05-11 Gustaf Neumann - implement escaping for comma in value of parameter options: escaping in values can be achieved via duplicating the comma. - extend regression test 2012-05-04 ssoberni - library/xotcl/library/xotcl2.tcl: Provided a virtual slot "multivalued" to establish backward compatibility with XOTcl1; also, allow old-style class creation based on unknown for ::xotcl::Attribute - library/xotcl/tests/slottest.xotcl: Added some tests on backward compatibility for XOTcl slots 2012-04-20 Gustaf Neumann - explorative implementation of object method dispatches with KEEP_CALLER_SELF and no NSF_PER_OBJECT_DISPATCH - extend regression test 2012-04-16 Gustaf Neumann nsf.c: - refactor ObjectCmdMethodDispatch() for clarity - prepare work on object method dispatches with KEEP_CALLER_SELF and no NSF_PER_OBJECT_DISPATCH - remove debug line 2012-04-11 Gustaf Neumann - fix off-by-one error - add regression test for keepcallerself with and without perobjectdispatch - fix typo 2012-04-10 Gustaf Neumann - serializer: * pertain perobjectdispatch and keepcallerself in serializer * extend regression test nsf.c: - generalize stack monitor by handling growing and shrinking stacks - refactor into function CheckCStack() - serializer: * make [::Serializer deepSerialize -ignoreVarsRE "" $o] behave like [::Serializer deepSerialize $o], since learn@wu depends on that, and a value for ignoreVarsRE of empty looks more like an omitted value than a regular expression, that should match everything. * extended regression test - extended regression test 2012-04-05 Gustaf Neumann - added compile macro NSF_STACKCHECK to provide stack monitoring/debugging (especially useful for multi threaded programs, where stack is more limited) - make ::nsf::log more robust for AOLserver/NaviServer, since ::ns_log is not always around when an output is needed - don't hide call to make.tcl 2012-03-09 Gustaf Neumann - protect serial generation for parameters via mutex - fix compilation when compiled without threads (many thanks for r.zaumseil for noting this). 2012-03-05 Gustaf Neumann - tcl86.test: better implementation of method "each", cleanup and extension of enumerator tests 2012-02-29 Gustaf Neumann - extended regression tests for yield - implemented "next" for ruby-like enumerators (each needs still more work) 2012-02-27 Gustaf Neumann - pass property name to slot "initialize" method to conform with the interface to "assign", "get" ... (all these receive the property name as well) - allow slot "initialize" method to be protected (handled similarly to "init") 2012-02-24 Gustaf Neumann nsf.c: - added object parameter option "slotinitialize" - renamed object parameter option "invokesetter" -> "slotassign" - call slot.assign instead of setter of object - removed restriction on nosetter/invokesetter: nosetter can be used in connection with slotassign - added regression test for slot.initialize 2012-02-22 Gustaf Neumann - Fixed a bad interaction between Tcl's apply (pushing lambda frames) and the variable resolvers. The variable resolver was not able to resolve variables, while the command resolver was still working correctly. - Extended regression test - Improve wording in instructions - Improve comments - Documented dependencies between configure flags and feature activation cpp macros 2012-02-17 Gustaf Neumann - improve error message to indicate, that nsf refuses to overwrite (redefine) some cmds - don't allow method to overwrite child object - extended regression test - documented new feature as incompatibility with XOTcl 1 2012-02-16 Gustaf Neumann - don't allow object creation to overwrite non-object cmds (e.g. procs) - improve debug line 2012-02-16 ssoberni - library/lib/nxdoc-xowiki.tcl: Finished and polished the xowiki backend for nxdoc. Some tests regarding relative paths and the tree-view generation are pending ... - library/lib/nxdoc-xowiki.tcl: Use the built-in base64 facility if running under Tcl 8.6 - Due to re-introducing nested-object-as-method semantics lately, nxdoc started stumbling over name conflicts between nested entity hierarchies (i.e., the entity object representing "/cls/ class info class" ...) and equally-named introspection calls on such entities (e.g., a "info class" call). I made these calls more robust my using -system dispatches; which is fine as long as we do not have sth. like "/obj/ info eval". Generally speaking, the risk of such naming conflicts discredits the use of object nesting in nxdoc; should eventually be revised. Or, as work-around: Using a filter on Entity instances to protect/redirect critical calls. - tests/serialize.test: Added some basic regression tests, in particular to challenge the filter options provided by Serializer->deepSerialize() and Serializer->all(). - Included a test for commit 595e6a2. - Along the line, two minor issues where fixed: 1) Set Serializer->ignore() to public, otherwise the various external message sends to this method would fail; 2) Object-serialize() did not distinguish between serializing a per-object or per-class container properly; as a consequence, per-object containers were not restored at all. Add a test covering this. - library/serialize/serializer.tcl: Due to the split between serializer and object system serializer, the ignore settings (passed as object variables, i.e., ignoreVarRE) got lost. This is fixed now ... 2012-02-16 Gustaf Neumann - treating incompatible forwarding to slot vs. slot option noaccessor - extended regression test - use Tcl's EXTERN macro instead of "extern" 2012-02-04 Gustaf Neumann update release procedure 2012-02-03 Gustaf Neumann - mv next-tutorial (source, images) into own subdirectory doc/next-tutorial/ - Bump version number of head to 2.0b4 - improve wording in documentation ./nsf2.4.0/unix/nxsh000755 000766 000024 00000002345 12577754746 015115 0ustar00neumannstaff000000 000000 #! /bin/sh # Lookup a Tcl interpreter \ INTERP="tclsh8.5"; \ INTERPS="/usr/local/ns/bin/tclsh8.5 /usr/local/ns/bin/$INTERP"; \ for interp in $INTERPS; \ do if [ -x $interp ]; then INTERP=$interp; break; \ fi; done; \ exec $INTERP "$0" ${1+"$@"} # -*- tcl -*- puts [info nameofexecutable] # # Tiny scripted replacement of a binary nxsh. This script can be used # as interactive shell for testing or like a regular shell with the !# # markup in the first line of a script. It is designed to work with # multiple installed shells during development. For installed # versions, it should be sufficient to remove the first line. # package require nx namespace import ::nx::* if {$argc == 0} { set prefix "" set line "" while {1} { if {$line eq ""} { puts -nonewline "% " flush stdout } append line [gets stdin] if {[info complete $line]} { if {[catch $line result]} { puts $::errorInfo } else { puts $result } set line "" continue } append line \n } } else { set argv0 [lindex $argv 0] set argv [lreplace $argv 0 0] incr argc -1 source $argv0 #if {[catch [list source $argv0] errorMsg]} { # return -code error -level 1 $errorMsg #} } ./nsf2.4.0/unix/nxwish000755 000766 000024 00000002266 12577754746 015457 0ustar00neumannstaff000000 000000 #! /bin/sh # Lookup a Tcl interpreter \ INTERP="tclsh8.5"; \ INTERPS="/usr/local/ns/bin/tclsh8.5 /usr/local/ns/bin/$INTERP"; \ for interp in $INTERPS; \ do if [ -x $interp ]; then INTERP=$interp; break; \ fi; done; \ exec $INTERP "$0" ${1+"$@"} # -*- tcl -*- puts [info nameofexecutable] # # Tiny scripted replacement of a binary nxwish (former xowish). This # script can be used as interactive shell for testing or like a # regular shell with the !# markup in the first line of a script. It # is designed to work with multiple installed shells during # development. For installed versions, it should be sufficient to # remove the first line. # package require Tk package require nx namespace import ::nx::* if {$argc == 0} { set prefix "" set line "" while {1} { update if {$line eq ""} { puts -nonewline "% " flush stdout } append line [gets stdin] if {[info complete $line]} { if {[catch $line result]} { puts $::errorInfo } else { puts $result } set line "" continue } append line \n } } else { set argv0 [lindex $argv 0] set argv [lreplace $argv 0 0] incr argc -1 source $argv0 } ./nsf2.4.0/unix/pkgIndex.unix000644 000766 000024 00000000366 14270756102 016642 0ustar00neumannstaff000000 000000 if {[package vsatisfies [package provide Tcl] 9]} { package ifneeded nsf 2.4.0 \ [list load [file join $dir libtcl9nsf2.4.0.dylib] Nsf] } else { package ifneeded nsf 2.4.0 \ [list load [file join $dir libnsf2.4.0.dylib] Nsf] } ./nsf2.4.0/ChangeLog-2.2.0-2.3.0.log000644 000766 000024 00000050561 14275417766 016647 0ustar00neumannstaff000000 000000 2019-05-09 Stefan Sobernig * doc/example-scripts/*.html: Regenerated asciidoc examples [629aa9a6] * configure.ac, configure: Fix package version to include patch level (was dropped unintentionally); regenerated docs [6e30c554] 2019-05-08 Stefan Sobernig * Update copyright years [71889f2d, 5a44ade2] * ChangeLog-2.2.0-2.3.0.log, Announce2.3.0: Updated changelog and announcement [c2fd7720] 2019-05-08 Gustaf Neumann * nsf.c (NsfOUplevelMethod): Minor cleanup and extended regression test; reduced returns before end of function; reduced variable scopes; don't use variable for different purposes. [fe42ee0c] 2019-05-07 Stefan Sobernig * nsf.c (NsfOUplevelMethod): Add some comments to NsfOUplevelMethod; and clean up after rework. [bf73e549] * nsf.c, methods.test: Cont'd uplevel reform to sanitize the single-arg case (in light of recent changes to 8.7, TIP 515 and for the sake of XOTcl 1 compatibility): A single arg to uplevel won't be inspected for a level specifier anymore; added tests and TODOs [e3150993] 2019-05-07 Gustaf Neumann * nsf-gridfs.test: Made gridfs test more robust [1aebb8d6] * next-migration.txt, next-tutorial.txt: Updated documentation with correct version numbers [b2778d3a] * README.release: update one more version number [3c3fe1f5] * Announce2.3.0: final polishing on announcement [055758ab] * xotcl2.tcl: Bump version number [fa6ed320] * mongodb/README.md: Improve spelling consistency [699b2e94] * README.release: Update release steps [21f46288] * nsf.c (ComputeLevelObj): Silence clang 8 static checker [7b03a547] * Improve documentation [4e80fb68] 2019-05-06 Stefan Sobernig * ChangeLog-2.2.0-2.3.0.log, Announce2.3.0: Updated changelog, fixed stats and indentation in announcement [e7552732] 2019-05-05 Gustaf Neumann * generic/*.c: Made spaces after comma regular [62dc2923] * Documentation: Improve grammar and spelling [2352fb1a] * nsf.c (NsfClassListAddNoDup): Avoided one-liner loop [b6e483e0] 2019-05-06 Stefan Sobernig * nsf-gridfs.test: Add one more piece of harness to test suite [ce93f504] * library/mongodb/*: Ran NSF MongoDB tests, against MongoDB 4.0.9 and Mongo-C driver 1.14.0 (both, latest stable); updated README.md accordingly, and fixed gridfs tests that hadn't been corrected for renaming README to README.md [c1f4cdc0] 2019-05-03 Stefan Sobernig * nx.tcl, properties.test: Add exists accessor to properties and variables; incl. tests and documentation [fc11b238] * Updated changelog, fixed stats in announcement [63fa3171] 2019-05-03 Stefan Sobernig * Regenerated documentation [6cbeef2d] * Object.man: Remove line break in script evaluation [f7541b47] * Bump version number from 2.3a0 to 2.3 [77a193c1] 2019-05-02 Gustaf Neumann * nsf.c (MergeInheritanceLists, NsfNSCopyVarsCmd) (NsfCallStackFindCallingContext): Reduce dead store operations and null after dereference [e89a635d] 2019-05-01 Gustaf Neumann * nsfObj.c (FilterregDupInternalRep, CscListAdd, CscAlloc): Improve spelling [7aad1f9b] 2019-04-30 Stefan Sobernig * tests/*.test: Add 'package prefer latest' to remaining test files. [8e2e356e] * ChangeLog-2.2.0-2.3.0.log, Announce2.3.0: Fix typos [6630359b], fix a remainder in changelog [1997fa85], done content-wise [4a1f3640] 2019-04-26 Stefan Sobernig * forward.test: Constrain the max recursion depth around recursive forwards, so that we do not run into early crashes on systems with limited stack sizes (when the stack is saturated before a recursion limit is hit). This fixes test runs on MinGW/ gcc builds at AppVeyor. [6debf965] 2019-04-23 Stefan Sobernig * forward.tests: Provide some background comment on platform-dependent error messages as test conditions (infinite loop) and make sure tests under 8.6 are executed as intended. [e760812b] * Continued work in changelog and announcement (still WIP) [22becf70] 2019-04-21 Gustaf Neumann * nsf.c: Added "pure" declarations [0d57967b] * nsf.c, nsfObj.c, nsfProfile.c, nsfStack.c, nsfShadow.c: Removed null test after dereferences, avoid potential null dereferences in error cases [1f532a9d, ef01bf0b] 2019-04-20 Gustaf Neumann * nsf.c (NsfObjectPropertyCmd): Improve code safety and remove dead statement [727ef73d] * nsf.c (DispatchDefaultMethod): Get rid of warning of static checker, reduce number of returns before end of function [3c3c372b] 2019-04-19 Gustaf Neumann * nsf.c, nsfError.c: Minor code cleanup [9333a832] * nsf.c (ForwardArg): Add asserts [dcbc76a2] 2019-04-19 Stefan Sobernig * ChangeLog-2.2.0-2.3.0.log, Announce2.3.0: Continued work in changelog and announcement (still WIP) [4f0774c0] 2019-04-18 Gustaf Neumann * nsf.c (NsfCCreateMethod): Revised fix for memory leak on "hyper-volatile" objects. it seems, we have to set the _is_autonamed flag in advance of obj initialization [0aabdb62] 2019-04-17 Gustaf Neumann * nsf.c (NextSearchAndInvoke): Addressing Coverity defect 337829 (dereference before null check) [f5000938] 2019-04-15 Gustaf Neumann * nsf.c: Make spelling more consistent [7b2d369f] * next-migration.txt: Fix typo [b568b39b] * nsf.c (NsfCCreateMethod): Provide a more conservative change for setting autonamed flag [ecda5a16] * object-system.test: Provide more context info when the version mismatch test fails [ff219acd] * Makefile.in: Remove "-Wabi" for standard intense checking, more troubles then benefits [b55cf93e] * nsfInt.h: Improve consistency of naming parameters denoting NSF objects [6dc8e9ad] 2019-04-15 Stefan Sobernig * nsf.c (NsfCCreateMethod): Fix access of potentially freed object to set the autonamed property (indicated by valgrind). When destroyed and cleaned during DoObjInitialization, "newObject" will remain as a dangling pointer. Besides, setting the property before DoObjInitialization will make the object property available from within the initcmd or init method. [08bf8cbe] * nsf.c (NsfProcStubDeleteProc): Plug leakage of command structure (found by valgrind) [545663bd] 2019-04-14 Stefan Sobernig * ChangeLog-2.2.0-2.3.0: Add changelog and announcement files (WIP) [13bbfb85] 2019-04-12 Gustaf Neumann * nsf.c: Muniro formatting changes [5e7610d4] 2019-04-12 Stefan Sobernig * appveyor.yml: Provide 2.2 builds on Appveyor [955967fa, 034ea94d] * .travis.yml: Provide for 2.2.0 builds, and fix allowed failures [25d6f9a3] * appveyor.yml: Deploy mode for Appveyor builds [fb2a31e7] 2019-04-11 Stefan Sobernig * appveyor.yml: Prepare deploy mode for [1d6dbca6, f7f11897, f9090473, ebaa3d49, b2825a79] 2019-04-10 Stefan Sobernig * .travis.yml: Remove context noise (directory tree) from the tarballs [585904b1] * configure, configure.ac: Make sure 'git describe' uses --always, to not fail on truncated checkouts without tags in reach (as on Travis) [168c4584] * build.tcl: Provide some harness around 'make test', to avoid swallowing failing test suites in light of the write-error condition [e97d7fb1] * nsf.c (NsfDebugShowObj): For consistency, stick with %x using PRIxPTR [eb1d421a, e270ccdb] 2019-04-09 Stefan Sobernig * .travis.yml: Refined build matrix, included actual gcc for macOS into build matrix [31aa3666, 66f716d0]; made tarball names more explanatory [7dcde484]; NONBLOCK fix for write error [aed8ea31, bf3b3810] * Change http:// occurrences to https://, if applicable (URLs tested) [a963e889] * .travis.yml: Fix ssh/scp calls [76e8cc2b], avoid host check [260b0eab], Fix permissions [aef46edc] 2019-04-08 Stefan Sobernig * .travis.yml: Provide for automated deployment of build artifacts on Travis CI [1eacec29 - 56752f08] * apps/build.tcl: Revert URL change for build script, archive is retrieved broken otherwise? [09dab29b] * Rewrite URLs containing tcl.tk as authority to tcl-lang.org [1711d246] 2019-03-31 Gustaf Neumann * Object.man, nsfInt.h, nx.tcl, properties.test: Improve spelling [a8c1439e] 2019-03-29 Gustaf Neumann * nsf.c (ForwardArg): Move new assertion to the right place [713b8852] * Object.man, tutorial.html: Improve wording [cfb3421c] * nsf.c: Ease human tracing of uninitialized/NULL values [e8349924] 2019-03-29 Stefan Sobernig * .travis.yml: Fix test [a7a09d79] 2019-03-28 Stefan Sobernig * .travis.yml: Add caching support for tclkits. [24caeb31, 14b0a59b, b28a01de] 2019-03-27 Gustaf Neumann * Makefile.in, configure.ac, configure: Improve robustness of configure/ make procedure in the absence of generated DTRACE artifacts so that they are truly conditional on the corresponding configure flags for DTRACE. Thanks to Zoran fore reporting. [e9f818e5, e3968e8c, d13e45f7] 2019-03-22 Stefan Sobernig * nsf.c (NsfOUplevelMethod, NsfOUpvarMethod): Silence compiler warnings on nonnull/NULL compares. [32cc7bc9] * nsf.c (NsfOUplevelMethod, NsfOUpvarMethod) (NsfCallstackFindCallingContext): Reform of uplevel and upvar methods, based on the recent feedback by Zoran. First, uplevel and upvar methods, as well as [current callinglevel] now behave consistently (re frame skipping for mixin and filter transparency). If there is no innermost enclosing proc frame, the innermost non-proc (e.g., namespace) frame is selected (rather than a "#0" as default). Second, argument handling for both uplevel (i.e., level sniffing in multi-arg case) and upvar (e.g., made silent TCL_ERROR for invalid argument arities explicit) have been fixed. * Object.man, methods.test: Added documentation for both methods (Object.man) and tests. [baee0c34] 2019-03-22 Gustaf Neumann * nsf.c (NsfDListAppend): Reduce dead assignments improve indentation of variables [4f234291] * gentclAPI.tcl (ConvertTo*): Avoid variable name "index" in generated code since "index" shadows an outer function [8a19ff2e] 2019-03-21 Gustaf Neumann * nx-mongo.tcl, nx-mongo.test: Add "bson asJSON" convenience method [6cff9d9b] 2019-03-20 Stefan Sobernig * appveyor.yml: Fix YAML syntax [0dac3440] * appveyor.yml: Provide for caching the tclkit running the build script, to improve robustness and availability [0a587021] 2019-03-20 Gustaf Neumann * nsf.c (NextSearchAndInvoke), submethods.test: Fixed explicit "next" call in ensemble leading to unwanted "unknown" handler call [156a37fe] 2019-03-18 Gustaf Neumann * nsf.c (CompiledLocalsLookup, CompiledColonLocalsLookupBuildCache): Since we know length, we can replace strcmp by memcmp [c3085d62] 2019-03-17 Gustaf Neumann * forward.test: Trigger new travis build [61b88669] * forward.test: Error message on stack overflow differs on windows and unix for Tcl 8.5, see CheckCStack. [8b333a99] * forward.test: We see now a different error message in tcl8.5 for a recursive loop (drop test?) [c0221269] * nsf.c (MethodHandleObj): Improve type cleanness [b86d0335] * forward.test: Deactivate under windows for the time being [3abc6a6f] * forward.test (methods.test): Make test more robust ("file lstat" returns less data under windows) [a65f2c7d] * nsf.c, nsfInt.h (ALLOC_ON_STACK): Added an alternative variant of ALLOC_ON_STACK [459516f9] 2019-03-16 Gustaf Neumann * tutorial.html, tutorial2.html, next-migration.html, next-tutorial.html: Improve spelling [93875ccd, 3d145fa5, 38ea9f94] * protected.test, Object.man: Align names (use "subclass" instead of "sub-class") [0697a2e3, f52d344b] * nsf.c (ComputeLevelObj): Align behavior of "current activelevel" with "... callinglevel" in case no NSF frame is found [d5f0e46c] * nsf.c: Fix typos and make spelling more uniform. [c465bb71] * methods.test: Add regression test for testing the behavior of :upvar from top-level tclsh with and without filters [85eec46a] * nsf.c (ComputeLevelObj): Conservative fix for "current callinglevel"; probably more to come [587c2fab] 2019-03-15 Stefan Sobernig * nx.tcl, xotcl2.tcl: Fully qualify uses of Tcl's upvar and uplevel, to avoid confusion when introducing equally named procs/ cmds in the OS namespaces. [bb1a4116] 2019-03-14 Gustaf Neumann * nsf.c: Minor cleanup, factor out common strings (e.g., "::nsf::classes") [3b608d8c] 2019-03-13 Gustaf Neumann * nsf.c, next-migration.txt, , next-tutorial.txt, /metadataAnalyzer.xotcl, speedtest.xotcl, langRef2.xotcl: Improve spelling and formatting [0f30ab62, 67639f37, b9fcdec2] * nsf.c, speedtest.xotcl: Improved handling of object property autonamed [c86c0775] * serializer.tcl: Preserve overriding slot accessor methods defined via XOTcl instprocs during serialization. [542f9ead] 2019-03-12 Stefan Sobernig * win/makefile.vc: COMDAT folding can lead to unusable, pointless function-pointer comparisons (Nsf_ConvertToSwitch vs. Nsf_ConvertToBoolean). Reported for /opt:icf under Visual Studio 2017 under x86. Kudos to Ashok P. Nadkarni. [cb565d85] 2019-03-11 Gustaf Neumann * nsf.c (VolatileMethod): Allow to render an object "volatile" or non-volatile via the object property volatile. [3ebbf610] 2019-03-10 Gustaf Neumann * nx-reference-one.test, tests/*, bagel.tcl, gentclAPI.tcl, serializer.tcl: Improve spelling [9ef8ab28, e5a313d7, 2321487a, 83a7bb90] * makefile.vc: Make sure, the install directory exists before copying data to it [c822857c] * nx-mongo.tcl: MongoDB interface: add option "-asJSON" to "find all" to ease interaction e.g. with single page applications. [9cdb38c7] * nsf.c, nsfObj.c: Improve spelling [38aa0536] * speedtest.xotcl: Added a more complex test for testing "new" + volatile [e5df6994] 2019-03-09 Gustaf Neumann * object-system.test: Add minimal regression test for object property "autonamed" [206792ca] * nsf.c (ArgumentDefaults): make code assumptions clear by adding asserts. [e3d180a2] 2019-03-08 Gustaf Neumann * Adjust regression test to more specific error message [0a73b191] * improved error message "not allowed to have default": make clear, this is stems from a parameter specification * nsfAPI.decls, nsf.c: Added object property "autonamed" (set automatically for objects created via "new") [1279a7ec] * nsf.c: Improved backward compatibility of XOTcl2 volatile method with XOTcl1 [1279a7ec] * speedtest.xotcl: Extended regression test [1279a7ec] 2019-03-07 Gustaf Neumann * xotcl2.tcl: Added new variant of "volatile" trying to mimic the XOTcl1 volatile behavior. [b6046263] * nsf.c: added experimental feature NSF_WITH_TCL_OBJ_TYPES_AS_CONVERTER, which uses registered TclObjTypes as value checkers (currently deactivated) [b6046263] * nx.tcl: whitespace change [6a97bd03] 2019-02-18 Gustaf Neumann * Httpd.xotcl: Protect legacy HTTPd against XSS on error messages [6b093438] 2019-02-06 Gustaf Neumann * nx-zip.tcl: base package nx::zip on Tcl 8.6 builtins instead of relying on the Trf package [c1579421] 2019-01-15 Gustaf Neumann * nsf.c: Use "nonnull_assert" only in combination with "nonnull" declaration [af4c4944] 2019-01-14 Stefan Sobernig * .travis.yml, appveyor.yml: Update build array to 8.6.9 [90c8d70e] * nsf-cmd.test: Make new tests 8.5-savy [167e2369] * nsf.c (NsfProcStub): Re-order logic, so that the availability of a shadow proc cmd is tested first (re-fetch) and the parameter passing comes second, conditional on an available dispatch target. [884a7145] * nsf-cmd.test: Add test rename (target) conflicts for the shadowed procs; improve test formatting [6e91b118] * nsf.c (NsfStubProc): Improve comment formatting [a85b80f5] 2019-01-11 Stefan Sobernig * nsf-cmd.test: Modernize tests to work on error codes. [f93d46e6] * nsf.c, nsf-cmd.test: Fixed nsf::procs for (unintended) deletes of the shadowed proc, plus test cases. [d01fb5ad] * nsf.c, nsfShadow.c (NsfProcStubDeleteProc, Nsf_RenameObjCmd): Provide for coupled renaming of the nsf::proc pairs; and coupled deletion. [2a2f1043] * nsf.c (NsfProcStub, InvokeShadowedProc): Provide for re-fetching (e.g., deleted) ::nsf::procs::* commands, to allow for renamed nsf::procs to run. * nsf-cmd.test: Added test to cover re-fetch [ed5cc784] * nsf.c, nsfInt.h (NsfProcStub, NsfProcClientData): Apply namespace reform to nsf::procs, to prevent proc redefinition after a proc rename to fail. * nsf-cmd.test: Add test case to document/ to cover failing rename + redefine. [47f388cd] 2018-12-22 Gustaf Neumann * nsfUtil.c: Improve code documentation [b3541927] * nsf.c: Remove unneeded assignment [5a153b21] 2018-12-15 Gustaf Neumann * nsf.c: Reduce dead assignments and variable scopes [405ace78] * Httpd.xotcl: Make sure the path ends with a slash [b49c37ce] 2018-12-14 Gustaf Neumann * Httpd.xotcl: Security fix: avoid directory traversal attack in old XOTcl HTTP class [d074fd50] 2018-11-18 Gustaf Neumann * configure: Regenerated configure script [ebae8e0f] * nsfInt.h: Improve handling of HAVE_INTTYPES_H under windows [d7bc5d63] * nsfInt.h: make sure, macros HAVE_INTPTR_T and HAVE_UINTPTR_T are set (should probably upgrade to newer TEA version) [d4cb464a] * Makefile.in: fix typo [e8b9e471] 2018-11-17 Gustaf Neumann * nsfInt.h: Guard definition of PRIxPTR by HAVE_INTTYPES_H and not by HAVE_STDINT_H [dea74ea7] * nsf.c, nsfInt.h: improve type cleanness [6ebbaeee] * README.release: fix typo [af212472] 2018-11-04 Gustaf Neumann * ChangeLog-2.0b5-2.0.0.log, next-tutorial.txt, Announce-1.6.0: Remove comma before "that" [b5c493af] * doc.test, interp.test, tcloo.test, varresolution.test: Use consistently US spelling variation [357028ca] 2018-11-03 Gustaf Neumann * nsf.c, nsfObj.c: Remove comma before that [f92df553] 2018-10-24 Stefan Sobernig * disposition.test, parameters.test: Adjust tests to reflect the changed representational behavior for numerics (int, wide) according to TIP 514 (now in Tcl 8.7a2+). [fca63858] 2018-10-23 Gustaf Neumann * Object.man: Improve spelling [bee99fc8] * nsf.c: Help static analyzer to parse statements [8d65f0a7] 2018-10-12 Gustaf Neumann * Class.man, Object.man: Use consistently US spelling variants [f8df1c79] 2018-10-11 Stefan Sobernig * Makefile.in, win/makefile.vc: Add TCL_PKG_PREFER_LATEST to avoid version hick-ups (stable beating latest) somewhere from TCLLIBPATH etc. [b820ed69] 2018-10-02 Gustaf Neumann * README.release: Update to make sure, all version numbers in configure.ac are updated properly [3754aac2] 2018-09-30 Stefan Sobernig * configure: Make sure configure is stashed with repo, as autotools are not automatically re-generated (e.g., in build array) [a46a3361] * object-system.test: Add a simple test to catch incomplete version bumps earlier [7fa23e7c] 2018-09-29 Gustaf Neumann * configure.ac: bump also NSF_MINOR_VERSION after release [b439657b] 2018-09-28 Gustaf Neumann * follow the Tcl, not the OpenACS numbering scheme [f7b560fc] * prefer US american spelling variants [9aa53ef6] * change version number to first version number after the 2.2.0 release (2.3d0) [dd3cfbfd] * fix usernames at Sourceforge [f92b5538] ./nsf2.4.0/appveyor.yml000644 000766 000024 00000007240 14271014567 015572 0ustar00neumannstaff000000 000000 platform: x64 image: Visual Studio 2019 branches: only: - master - 2.2 - 2.3 environment: my_secret: secure: ngfIQmr9kcRyopeRyHZG8g== MINGW_DIR: mingw64 MINGW_URL: https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/7.3.0/threads-win32/seh/x86_64-7.3.0-release-win32-seh-rt_v5-rev0.7z/download MINGW_ARCHIVE: x86_64-7.3.0-release-win32-seh-rt_v5-rev0.7z TCLKIT_URL: http://kitcreator.rkeene.org/kits/34ac4a331252f9796c31f875e282cb04a01f2743/tclkit.exe TCLKIT: tclkit.exe matrix: - TCLTAG: core-8-6-branch TOOLCHAIN: autoconf-tea - TCLTAG: core-8-6-branch TOOLCHAIN: nmake-tea - TCLTAG: core-8-6-12 TOOLCHAIN: autoconf-tea - TCLTAG: core-8-6-12 TOOLCHAIN: nmake-tea - TCLTAG: core-8-5-branch TOOLCHAIN: autoconf-tea # - TCLTAG: core-8-5-branch # TOOLCHAIN: nmake-tea - TCLTAG: core-8-5-19 TOOLCHAIN: autoconf-tea # - TCLTAG: core-8-5-19 # TOOLCHAIN: nmake-tea - TCLTAG: core-8-7-a5 TOOLCHAIN: autoconf-tea - TCLTAG: core-8-7-a5 TOOLCHAIN: nmake-tea - TCLTAG: core-8-branch TOOLCHAIN: autoconf-tea - TCLTAG: core-8-branch TOOLCHAIN: nmake-tea - TCLTAG: trunk TOOLCHAIN: autoconf-tea - TCLTAG: trunk TOOLCHAIN: nmake-tea matrix: allow_failures: - TCLTAG: core-8-6-branch - TCLTAG: core-8-5-branch - TCLTAG: core-8-branch - TCLTAG: trunk fast_finish: true install: - if "%TOOLCHAIN%" == "nmake-tea" call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" # - appveyor-retry choco install openssh -confirm - ps: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1')) - appveyor-tools\secure-file -decrypt deploy_key.appveyor.enc -out deploy_key -secret %my_secret% - if not exist "%MINGW_ARCHIVE%" appveyor DownloadFile "%MINGW_URL%" -FileName "%MINGW_ARCHIVE%" - 7z x -y "%MINGW_ARCHIVE%" > nul - if not exist "%TCLKIT%" appveyor DownloadFile "%TCLKIT_URL%" -FileName "%TCLKIT%" - dir %MINGW_DIR% build_script: - if "%TOOLCHAIN%" == "autoconf-tea" set CHERE_INVOKING=1 # - if "%TOOLCHAIN%" == "autoconf-tea" set PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH% # - if "%TOOLCHAIN%" == "autoconf-tea" set PATH=%CD%\%MINGW_DIR%\bin;%PATH% - if "%TOOLCHAIN%" == "autoconf-tea" set PATH=C:\msys64\usr\bin;%PATH% # Needed to align MSYS and Windows HOME dirs - if "%TOOLCHAIN%" == "autoconf-tea" set HOME=C:\Users\appveyor # - if "%TOOLCHAIN%" == "autoconf-tea" bash -lc "cd && echo \"export PATH=/c/projects/nsf-2ylk0/mingw64/bin:/c/msys64/usr/bin:\$PATH; \" >> .profile" - if "%TOOLCHAIN%" == "autoconf-tea" bash -lc "cd && echo \"export PATH=/c/projects/nsf-2ylk0/mingw64/bin:\$PATH; export MSYSTEM=MINGW64; export MINGW_PREFIX=/c; alias make='/c/msys64/usr/bin/make'; shopt -s expand_aliases; \" >> .profile" - if "%TOOLCHAIN%" == "autoconf-tea" bash -lc "sh --version" - if "%TOOLCHAIN%" == "autoconf-tea" bash -lc "make --version" - dir %CD% - tclkit.exe apps/build.tcl %CD% %APPVEYOR_BUILD_FOLDER% %TCLTAG% %TOOLCHAIN% on_failure: - if "%TOOLCHAIN%" == "autoconf-tea" cat tcl\win\config.log after_build: - ps: $env:DATESTRING=(get-date -UFormat "%Y%m%d").ToString() - set TARBALL="nsf_%APPVEYOR_REPO_BRANCH%_%TCLTAG%_win_%TOOLCHAIN%_%DATESTRING%_%APPVEYOR_BUILD_NUMBER%.zip" - if exist "%CD%\install" 7z a %TARBALL% %CD%\install\* - if exist "%TARBALL%" C:\msys64\usr\bin\scp.exe -v -oStrictHostKeyChecking=no -i deploy_key %TARBALL% "sobernig@alice.wu.ac.at:/home/sobernig/builds" cache: - tclkit.exe -> appveyor.yml - x86_64-7.3.0-release-win32-seh-rt_v5-rev0.7z -> appveyor.yml ./nsf2.4.0/README.release000644 000766 000024 00000014555 14276140512 015503 0ustar00neumannstaff000000 000000 Steps for a beta release: - docs: * update all docs with asciidoc in doc/ - code: * Tcl 8.5: * configure with --enable-development make test * configure with --enable-memcount=yes make test 2>&1|cat |fgrep Overall * configure with --enable-development and activate valgrind in Makefile make test 2>&1|cat |fgrep "definitely lost" (8.5.11 ok, when every test returns "40 bytes in 2 blocks") (8.5.14 ok, when on test reurns "64 bytes in 1 blocks") * get rid of non-ansi-c make "CFLAGS_DEFAULT=-ansi -pedantic" (warnings are ok, errors not) * compile with clang make "CC=clang" make "CC=clang" test * run static analysis: make cppcheck #/opt/local/bin/scan-build-mp-8.0 -enable-checker alpha make /opt/local/bin/scan-build-mp-8.0 make /opt/local/bin/scan-view-mp-8.0 ... * run Coverity (7.6.0, requires gcc 4.8): (sudo port install gcc48) (download Coverity Build Tool from https://scan.coverity.com/download/) make clean rm -rf cov-int/ /usr/local/cov-analysis-macosx-7.6.0/bin/cov-build --dir cov-int make CC=gcc-mp-4.8 tar czvf /tmp/nsf.tgz cov-int curl --form token=jJ1QoqZ2Ksriz6JXtI3aHg \ --form email= \ --form file=@/tmp/nsf.tgz \ --form version="`git describe --tags`" \ --form description="maintenance checkout" \ https://scan.coverity.com/builds?project=Next+Scripting+Framework * configure without --enable-development make install make install-aol test with NaviServer/AOLserver (xowiki/xowf) * Tcl 8.6: * configure with --enable-development make test * configure with --enable-memcount=yes make test 2>&1|cat |fgrep Overall * configure with --enable-development and activate valgrind in Makefile make test 2>&1|cat |fgrep "definitely lost" (8.6b2 ok, when every test returns "40 bytes in 2 blocks") (8.6.0 or later ok, when every test returns "0 bytes in 0 blocks") * valgrind via vagrant: 1. Install vagrant: https://www.vagrantup.com/downloads 2. Install VirtualBox: https://www.virtualbox.org/wiki/Downloads 3. Check out newest box version: https://app.vagrantup.com/boxes/search?utf8=%E2%9C%93&sort=created&provider=&q=by+chef+bento%2Fubuntu-*+ 4. $ mkdir -p ~/VMs/ubuntu-21.04 5. Add NSF as synced folder: Vagrantfile config.vm.synced_folder "/path/to/nsf", "/home/vagrant/nsf" config.vm.synced_folder "/path/to/tcl", "/home/vagrant/tcl" 5. $ cd VMs/ubuntu-21.04 $ vagrant init bento/ubuntu-21.04 $ vagrant up $ vagrant ssh 6. With box: vagrant@vagrant:~$ bash vagrant@vagrant:~$ apt update; apt upgrade vagrant@vagrant:~$ apt install valgrind 7. Setup `apt install tcl-dev` or a custom tcl build 8. vagrant@vagrant:~$ cd nsf && ./configure CFLAGS=-DPURIFY --enable-development 9. Activate valgrind in Makefile (uncomment line with TCLSH plus valgrind) 10. vagrant@vagrant:~$ cat valgrind.out | fgrep "definitely lost" 11. vagrant@vagrant:~$ cat valgrind.out | fgrep "ERROR SUMMARY" (incl. invalid reads) - test tk apps under windows - Announcement * Summarize changes since the last release in doc/Announce-VERSION As source use e.g. git log --date-order --date=short|less ~/scripts/git-changelog2 -- 2.3.0..HEAD --no-merges > ChangeLog-2.3.0-HEAD Get: https://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=build-aux/gitlog-to-changelog;hb=HEAD curl -Lo ../git-changelog 'https://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=build-aux/gitlog-to-changelog;hb=HEAD' Run: ../git-changelog 2.3.0..HEAD --format=%s%n%b[%h] -- --no-merges > ChangeLog-2.3.0-HEAD Diffstats: git diff --stat 2.3.0..HEAD * Run spell checker over announcement + ChangeLog * git add announcement - rebuild documentation * Prerequisites: o dtplite (tcllib) o asciidoc (port install asciidoc) o Chrome * make doc * make pdfdoc (currently, it is necessary to manually edit next-tutorial.html and next-migration.html and replace setInterval() + next 4 lines by reinstall()) * call "make doc" again to remove editing traces - build test-tar-file * make tar * check content of tar file tar ztvf ../nsf2.4.0.tar.gz |sort -rn -k 5,6|less - create branch entries for CI systems (Travis, AppVeyor) add 2.3 to branches/only sections commit that change (continue with tagging) - tag version in git and commit git tag -a 2.3.0 -m 2.3.0 git push --tags # git push --follow-tags # git push commit In case retagging is necessary: git tag -d 2.3.0 git tag -a 2.3.0 -m 2.3.0 git push origin -f --tags - create branches for CI systems (Travis, AppVeyor) git checkout -b 2.3 2.3.0 git push origin 2.3 register a cron task for the new branch on Travis (website) - build tar * (make sure accurate COMMIT file is present, e.g., run ./configure once?) * make tar * check content of tar file tar ztvf ../nsf2.3.0.tar.gz |sort -rn -k 5,6|less - put NX API and shell onto sourceforge: * cd doc/ * dtplite -o /tmp/doc/ -style man.css -header header.html.inc html . * mv /tmp/doc/toc.html /tmp/doc/index.html * scp -r /tmp/doc/* {gneumann|foxcruiser}@web.sourceforge.net:/home/project-web/next-scripting/htdocs/ * check https://next-scripting.sourceforge.io/ - update archive at sourceforge * create folder with version name * upload tar file to new folder * upload announce to new folder and rename it to README - update web site * Stefan, please add recommended steps here - prepare next release: rename folder containing nsf (e.g. to nsf2.3.0) update version number in * configure.ac (NsfVersion, NSF_MAJOR_VERSION, NSF_MINOR_VERSION) * library/nx/nx.tcl * library/nx/pkgIndex.tcl * library/xotcl/library/xotcl2.tcl * win/pkg.vc * library/serialize/serializer.tcl * library/mongodb/nx-mongo.tcl * library/mongodb/configure.ac in SRCDIR and SRCDIR/library/mongodb/ autoconf ./configure .... ./nsf2.4.0/ChangeLog-2.1.0-2.2.0.log000644 000766 000024 00000133020 14275420257 016622 0ustar00neumannstaff000000 000000 2018-09-23 Gustaf Neumann * nsf.c: Reduce variable scopes [c9a0d623] * nsf.c: Fix access to NULL members (found via clang sanitizer) [83d483b7] 2018-09-19 Stefan Sobernig * Announce2.2.0: Improve spelling [89a7fe07] 2018-09-19 Gustaf Neumann * Announce2.2.0: Update diffstats [bf5e2d24] * next-tutorial.txt: Align release date [061df695] * next-migration.txt: Align release date [c6816ddd] * Announce-1.0.1, Announce-1.1.0, Announce-1.3.3, Announce-1.3.4: Improve spelling [ff459233] * Announce2.2.0: Add paragraph for configure flag "-i-enable-development=test" [b8d2494c] * configure, configure.ac: Align help text with implementation [9f15e921] * ChangeLog-2.1.0-2.2.0.log: Fix indentation [c49479f1] * nsf.c: Fix variable name [8f7cd2c3] 2018-09-16 Stefan Sobernig * ChangeLog-2.1.0-2.2.0.log: Add recent commits [4e4106cd] 2018-09-09 Gustaf Neumann * next-tutorial.txt, next-migration.txt: Improve documentation of "substdefault" in tutorial, add it to migration guide [02934359] * rules.vc: Fix typo [b9a6a8fb] 2018-08-10 Gustaf Neumann * nsf.c (ComputeLevelObj, ObjectSystemFree, ForwardArg, AutonameIncr): Prefer writing blocks in multiple lines [ad4244a2] 2018-08-05 Gustaf Neumann * cget.test, interp.test, substdefault.test: Improve spelling [d4706d18] 2018-08-04 Gustaf Neumann * serializer.tcl, nx.tcl: Bump version numbers consistently to 2.2 [73f1e56a] * Fix typos [2a955681] * nsfEnumerationType.c: Remove unused variable from non-null asserts [5cf5c26d] 2018-07-31 Stefan Sobernig * next-migration.txt, next-tutorial.txt: Minor corrections, adding section on substdefault to tutorial [69a2fff0] 2018-07-24 Gustaf Neumann * rosetta-tree.tcl, next-migration.txt, nsf.c, nsfDebug.c, nx-zip.tcl, nx.tcl, serializer.tcl: Improve spelling [ce99d2e5] * library/mongodb/Makefile.in, library/mongodb/libmongo.c: Remove dead assignment; add cppcheck target [6252b8e8] 2018-07-20 Stefan Sobernig * configure.3, current.3, next.3, nxsh.1, nxwish.1, xotclsh.1, xowish.1: Re-generated to reflect bumped version. [skip ci] [22abf92c] * README.release: Add missing artifacts for version bump [skip ci] [bbe37e8c] 2018-07-19 Gustaf Neumann * nsfmongo.c (mongoc_collection_create_index): Removed last deprecated call of the mongo-c-driver [c5e8bf0a] * doc/Announce2.2.0: Updates to announce file, tested with mongo-c-driver 1.12.0 (released yesterday) [b9bcc40a] 2018-07-19 Stefan Sobernig * apps/utils/source-highlight-with-pp: Generalise executable name in shebang, seems like an unintended change in [ae081c0f1] [69559167] 2018-07-16 Stefan Sobernig * README.md: http -> https [skip ci] [35b21d01] 2018-07-15 Gustaf Neumann * serializer.tcl: Bump version number to 2.2 [f20d7966] * README.md: Change README to markdown syntax, various updates [63cca48b, 18f9c9f5, d25063bf, 7c8895c8, 9ee11c31, 82511c9f, 5e56bff3] * library/mongodb/COPYRIGHT: Update copyright information [4b99da62] * README, dtrace/README, generic/asm/README, library/mongodb/README: Prefer new spelling of macOS [5c2e3f48] * library/mongodb/*: Updating mongodb interface for 2.2: update to mongodb-c-driver 1.11.0, reduce number of calls to deprecated driver functions as far as possible, improve cleanness of compilation (provide prototypes etc.) * library/mongodb/configure.ac, library/mongodb/nx-mongo.tcl: Bump version number to 2.2 [75f11a9a] * nsf.c (Nsf_SafeInit, Nsf_Init, Nsf_ExitProc) (Nsf_ThreadExitProc, ExitHandler): Prefer Tcl defined types over local prototypes [6d66926b] 2018-07-13 Stefan Sobernig * nsfDebug.c, nsfInt.h (STRING_NEW, MEM_COUNT_ALLOC, MEM_COUNT_FREE): Fix compilation with --enable-memcount=yes. [b6f285f7] * configure, configure.ac, nx.tcl, pkgIndex.tcl, xotcl2.tcl, pkg.vc: Bump version to 2.2.0. [9b831c84] 2018-07-10 Gustaf Neumann * serializer.tcl: Fix buggy case when blueprints are used to update interpreters with preexisting objects and classes. There, it was possible that objects are turned into baseclass objects, when the application classes are deleted. [94421e32] 2018-07-04 Gustaf Neumann * Announce2.0.0, Announce2.0b5, Announce2.1.0, rosetta-singleton.html, rosetta-sudoku.html, next-migration.txt, next-tutorial.txt, tutorial2.html, Announce-1.1.1, Announce-1.5.0, tutorial.html: Improve spelling [37fe2bc4] 2018-07-02 Stefan Sobernig * makefile.vc (CFLAGS): Also set -DHAVE_UINTPTR_T. [983e085e] * makefile.vc (CFLAGS): Add -DHAVE_INTPTR_T explicitly. [7db39ce8] 2018-07-02 Gustaf Neumann * nsf.c (NsfDebugGetDict): MSVC seems to be bad on const expressions [fe7198d3] * starmethod.tcl: Add starmethod design study [d6d259af] * xotcl2.tcl: Improve spelling [bada4fa1] * bagel.tcl: Fix typo [7f7d32cd] 2018-07-01 Gustaf Neumann * nsf.c: Improve comments, unify comment formatting and whitespace cleanup [469e0c36] * nsf.c: Properly initialize resultObj in all cases [0f0e846e] * nsf.c: Remove dead assignments, initialize variables also on error paths [1725225a] * nsfmongo.c: Make sure to initialize all variables also in error cases [88e3e5d4] * nsf.c: Reduce number of implicit type conversions; avoid use of macros [8325cbad] * nsf.c: Improve alignment of prototypes and function definitions [0ad07ea5] 2018-06-29 Stefan Sobernig * nsf.c (ObjectCmdMethodDispatch, FindNextMethod): Balance book-keeping in memcounts for Tcl_Objs (technically, an unmatched decrement would suffice). [9131bba5] * nsf.c (NsfProcDeleteProc): Fix freeing of colonLocalVarCache and balance book-kepping on memcounts for colonLocalVarCache. [bbeae255] * nsf.c (ObjectCmdMethodDispatch): Silence static check of GCC 8.1 (-Wmaybe-uninitialized). [skip ci] [4db189db] * nsf.c (NsfCurrentCmd): Avoid (possible, but unlikely) null dereferencing, if CSC was missing [CID 294166]. [27e5aa8b] * nsf.c (NsfDebugGetDict): Compute the remaining size to snprintf for each iteration [CID 294169]. [skip ci] [53a9c013] 2018-06-29 Gustaf Neumann * nsf.c (ForwardArg): Address CID 294171 and change construct for strpbrk [72a0a428] 2018-06-29 Stefan Sobernig * nsf.c (NsfDebugGetDict): Parametrize length computation; remove unneeded nul-termination. [skip ci] [22cdc00a] 2018-06-29 Gustaf Neumann * nsf.c, nsfStubLib.c: Minor cleanup [369069ef] * nsfmongo.c: Reduce variable scope and minor cleanup [c2157faa] 2018-06-28 Stefan Sobernig * nsf.c (NsfDebugGetDict): Make use of strncat more robust by setting the destination length to the remainder of the output buffer. [ea63ea31] * nsf.c (ForwardArg): Provide a const'ed pointer to strpbrk, as required [CID 294162]. [500a581f] * nsf.c (ParamDefsFormat): Fix overrun in memcpy by correcting the destination-length argument [CID 294165]. [b3e820b4] * nsf.c: Fix all "-pedantic -ansi" errors. [bec5f06e] 2018-06-27 Stefan Sobernig * nsf.c (ParamDefsStore, NsfProcDeleteProc): Provide for counting a reference to the execNsPtr from the NsfProcContext structure. While I could not devise a script-level path to pull out the rug (execNsPtr) out from under NsfProcContext clients, I can only also not exclude the latter (from future C-level paths?). Better act defensively. [1a486b9a] * nsfInt.h (STRING_NEW): Silence GCC 8.1 warnings on truncation risk using strncpy; made me wonder whether STRING_NEW would not be more robust against mis-computations of the destination-buffer length by using snprintf (mainly because snprintf does not nul-pad the destination buffer and always nul-terminates the destination buffer)? [d96dedf3] 2018-06-26 Stefan Sobernig * parameters.test: Adding two test cases to cover previously missed code branches leading to leaking NsfMethodNamePath uses. [bf61b8a8] 2018-06-25 Stefan Sobernig * nsf.c (ArgumentParse): Handle NsfMethodNamePath result correctly. [6042ab05] * nsf.c (NsfSetterMethod): Handle NsfMethodNamePath result correctly. [76da4309] * nsf.c (ObjectCmdMethodDispatch): Close another Tcl_Obj leak incurred by not handling the result from NsfMethodNamePath. [424b6e1f] * nsf.c (FindNextMethod): Plumb another memleak (valgrind). The Tcl_Obj computed by NsfMethodNamePath must be refcount corrected. [87bc503b] * nsf.c (AliasGet): Plumbing a memleak found by valgrind. The computed Tcl_Obj from AliasIndex must be refcount-managed explicitly, otherwise the path via AliasGet leaks it. [31c114ee] 2018-06-20 Stefan Sobernig * appveyor.yml: Provide for MSVC builds (pt. 2) [611f73cb, f5ff0c4b, 9eda6984, 900390cf, d78609db] * per-object-mixins.tcl: Fix an example script that got broken a long, long time ago. [skip ci] [49ae7bc3] 2018-06-19 Stefan Sobernig * appveyor.yml: Provide for MSVC builds (pt. 1) [f848dc5f, ae03d540, 457f8a80] 2018-06-18 Stefan Sobernig * .travis.yml: Add allowed failures to Travis setup [9e5f074e] * appveyor.yml: Set allowed failures on Tcl development branches; report failure on first failing build [f718572e] * nsf.c (ParamOptionParse), nsfInt.h: Provide for own MAX and MIN macros, the ones reused implicitly from Tcl's tommath have vanished in 8.7 branches; and are not provided otherwise, at least in MinGW settings. Fixes 8.7 builds for MinGW under Win. [8a1a43a3] * appveyor.yml: Provide for MSYS2/ MinGW builds (pt. 2) [95fa4f4b, 89fc03bf, 2ab16701, a9454bc8, a691997b, 71dd75a1, 25c6fca9, 03d5b57a, 1b07fc0e, bd720946, 59986a2a, f207ce19, 00eb377b, 0c1811dc, 2174fb70, b0457f28, 6c876e33, 65c4d97a, d7e28d2e, 8028ced6, a6a1736d, d41ea5ee, 13e6e4c0] 2018-06-17 Stefan Sobernig * appveyor.yml: Provide for MSYS2/ MinGW builds (pt. 1) [2b4c8032, 96b79f58, 05d909f4, 45f37041] 2018-06-04 Stefan Sobernig * nsf.c (ListSuperClasses): Fix refcounting for 8.5 non-threaded only, otherwise the patternString becomes unavailable once a preemptive decrement has been performed, leading to unexpected info results. [0e8f3a70] * nx-test.tcl (run): Avoid use of [try], to render the test suite independent of the presence of 8.6 or tcllib's try. This may be reverted, once 8.5 support is dropped. [9ba75adb] 2018-06-01 Gustaf Neumann * configure.ac: Add COMPILE_NSF_STUBS to compile flags under windows [554234e8] * nsfStubLib.c: Make stublib initialization more robust and provide meaningful error message in case of misconfigurations [fe5d4828] 2018-05-30 Stefan Sobernig * .travis.yml: Provide first attempt at Travis build array and build script [fffcee32, 2e1926a7, c216c592, f4ca149d, 79e5563d, 63295a8d, 21d83785] 2018-05-29 Stefan Sobernig * .travis.yml: Add an initial Travis CI descriptor; simplify descriptor, for the time being [ea4ef787, e41cd6fd] * Makefile.in: Polishing [b3a3d83c] 2018-05-23 Gustaf Neumann * next-migration.txt, README, Announce-1.1.0: Improve spelling [5c0a0300] * nsfmongo.c: Use mongoc_iovec_t instead of struct iovec iov to improve cross-platform compatibility [8eea27e0] 2018-05-21 Gustaf Neumann * source-highlight-with-pp, bagel.tcl, rosetta-multiple-distinct.tcl, rosetta-tokenizer.tcl, aolstub.c, gentclAPI.tcl, nsf.c, nsfFunPtrHashTable.c, nsfShadow.c, nx-zip.tcl, nsfmongo.c, nx-mongo.tcl, nx.tcl, xotcl2.tcl: Improve comments [ae081c0f] 2018-05-17 Gustaf Neumann * gentclAPI.tcl, langRef.xotcl, xotcl2.tcl: Improve wording [c8cfa996] * make.tcl: Improve Tcl idioms [7a2dc79d] 2018-04-30 Gustaf Neumann * htmllib.xotcl: Remove duplicated word [657e8c12] 2018-04-25 Gustaf Neumann * nx-test.tcl, nx-mongo.tcl, nx.tcl: Fix duplicated words in code documentation [0556efb3] * rosetta-sudoku.tcl: Fix double word in code documentation [f52f9988] * nsf.c: Fix double worlds in code documentation [c78a90d7] 2018-04-15 Gustaf Neumann * nx-mongo.tcl: Add destroy_on_cleanup similar to OpenACS to ease * nx-mongo.tcl: Lifetime management of volatile objects [1debd517] 2018-04-14 Gustaf Neumann * nx-mongo.tcl: Fixing cut&paste error [2ce11132] 2018-04-12 Gustaf Neumann * nx-mongo.tcl: Whitespace changes [4131e4eb] * nx-mongo.test, nx-mongo.tcl: Added class names into serialization syntax (__class). This change allows us to make better use of polymorphism with (e.g. embedded) class structures. Previously, it was necessary, that the called object had to know the class of the serialized object, now it is as well possible to use as well specializations; fix bug, where default value for properties lead to errors, when no property options where given. [3fc67997] * mongodb/README: Update version numbers of mongo's c-driver older versions stopped working on macOS High Sierra. [120d6714] * nsf.c (NextSearchAndInvoke): Fix typo [7831bb96] 2018-04-05 Gustaf Neumann * Access.xotcl, mixinStrategy.xotcl, ScriptCreator.xotcl: Fix typos [50bf7579] * nx.tcl: Fix typo [eb6f33db] 2018-03-28 Gustaf Neumann * next-migration.html, next-tutorial.html: Regenerated documentation [367fd6fc] * next-tutorial.txt, nsf.c, xotcl2.tcl: Fix typos [8f15a5f3] 2018-03-23 Gustaf Neumann * nsf.c (AutonameIncr): Remove unneeded ALLOC_ON_STACK [a8fbf793] 2018-03-11 Stefan Sobernig * nsf.c (ListMethod): Provide a disassemble implementation based on ::tcl::unsupported::disassemble. [::nsf::cmd::info disassemble] is generally available, the info ?object? method variants only in development mode. Implementation covers proc methods and ::nsf::procs. Along the way, prettify some code paths in ListMethod. [1919d17f] 2018-03-08 Gustaf Neumann * nsf.c: Add const declarations, whitespace changes [dcbf5b0c] 2018-03-06 Stefan Sobernig * nsf.c (Nsf_Init): Mark the namespace "::nsf::classes" and its children using "NS_SUPPRESS_COMPILATION". In 8.6+, this guards any commands in these auxiliary namespaces to be picked up by the bytecode compiler (if accessed in an unintended manner). [52340117] * nsf.c (ByteCompiled): Patch the proc command's namespace unconditionally, for 8.5 and 8.6. [4d5e72a9] 2018-03-03 Gustaf Neumann * nsf.c (NsfDebugGetDict): Avoid potentially dangerous call strcat(); remove unneeded assignment [0948fdce] 2018-03-02 Gustaf Neumann * nsf.c: Whitespace changes [869a425b] * nsfStack.c: break overlong lines [b489939c] * nsf.c: Polish and comment the execNs change for Tcl 8.5 [0f58115b] * nsf.c: Quickfix for Tcl 8.5 (needs still more investigation) [a9c0e0c4] 2018-02-25 Gustaf Neumann * nsf.c, nsfInt.h, nsfStack.c: Add const declarations, reduce variable scopes, break longish lines [efe655ee] 2018-02-21 Stefan Sobernig * dtrace/README: Fix call example, updated instructions to cover SIP deactivation, minor corrections. Added one more D script: nsf_call-time.d. [bf3b2a85,ee6699cd] * nsfDTrace.h: Re-generated. [ee6699cd] * nsf.c (NsfConfigureCmd): Fix NSF_DTRACE=1 builds. [8a3defd6] * gentclAPI.tcl, nsfAPI.decls (createconverter): Support for "-global 1" flag that will cause the options array corresponding to an enumeration to become available as a global, properly Nsf_* prefixed symbol. Used for NsfConfigureCmd and the corresponding DTrace probe, for now. [40299a6f] 2018-02-19 Gustaf Neumann * nsf.c, nsfInt.h, nsfStack.c: Add const and pure declarations [56771aad] 2018-02-19 Stefan Sobernig * source-doc-beautifier.tcl: Remove in-block range markers within test bodies to prettify the ADOC output. [d3fd0b4d] 2018-02-19 Gustaf Neumann * nsf.c: Adding const declarations, variable name cleanup [75e891c9] * nsf.c, nsfCmdPtr.c: Reduce number of returns before end of function, ease live for static checker, use more "const" declarations [b655363c] 2018-02-18 Gustaf Neumann * testx.xotcl: Comment and improve linebreak [992c4419] * nsf.c: Prefer bool over int, reduce number of gotos, reduce number of returns before end of function, reduce variable scopes, add "const" declaration, white-space changes [e9cd20a4] 2018-02-17 Gustaf Neumann * nsf.decls: Align prototypes with function definitions [d78fa3ae] * nsfError.c: Whitespace changes [bd06f04b] * nsfError.c: Prefer bool over int, white space changes [25349aef] 2018-02-16 Gustaf Neumann * generic/*.*: More code cleanup [9d1dfb64] * Makefile.in: Update genstub path to recent versions of Tcl releases [976a4004] 2018-02-14 Gustaf Neumann * nsf.c: Prefer boolean over int [d4863566] * nsf.c: Reduce number of return statements beofre end of function [5e2800c9] * nsf.c: Fix regression, prefer boolean over int, reduce number of returns before end of function [61204e9c] * serializer.tcl: Ease life of colon-cmd caching [b35a18bd] * nsf.c (NsfSetterMethod): Don't pass colon-prefixed method names from setter cmd to SetInstVar() to avoid potential shimmering. [e561596f] 2018-02-11 Gustaf Neumann * nsf.c, cget.test (CGetParamLookup): Add Tcl_Obj caching to cget argument; reduced usage of goto statements; reduced size of largish function [343d881f] * nsfInt.h (ObjTypeStr): Introduce macro ObjTypeStr for commonly used idiom [23843225] * nsf.c: Prefer boolean over int [b513759e] * nsf.c (ColonCmdCacheRequiredRefetch): coloncmd reform (part 4) performs validation for per-object cases, provide more detailed statistics (when compiled with COLON_CMD_STATS) [050f0e85] 2018-02-10 Gustaf Neumann * nsf.c (NsfParamDefsNonposLookup, ColonCmdCacheSet): Reduce memory consumption by caching only cmds in non-volatile Tcl_Objs. Add optional statistics, when COLON_CMD_STATS is defined. [fd53af3f] * nsf.c (NsfDListInit, NsfDListAppend, NsfDListFree): Add NsfDList functions similar to Tcl_DString, but operating on void* instead of char and use it for ColonCmdCache data [ac0c6dda] * nsf.c (NsfDList): coloncmd reform (part 3): Leep a per-interp list of colon command cache entries to avoid memory leaks in cases the objects are converted [40317187] * nsf.c (ParamDefsGetReturns): Simplify handling of "returns" object. no need to require paramdefs, when just returnsObj is needed [5d0e4380] * nsf.c (TopoSortSub): Simplify expression [b7c03b14] * nsf.c (NsfMethodPropertyCmd): Remove unneeded variable [e75c61b1] 2018-02-09 Gustaf Neumann * nsf.c (NsfFindClassMethod, ObjectDispatch), nsfInt.h, nsfObj.c: coloncmd reform improves dispatch of [:method ...] by up to 30%; generalized code and apply for object-specific commands as well [68df0e0f, 4be7360a] 2018-02-09 Stefan Sobernig * msgcat.test: Added a small collection of basic tests covering msgcat usage from within NSF/NX objects and classes. Tested successfully with mainline Tcl 8.6 and the TIP-490 branch "tip490-msgcat-oo-2". [071b5e4d] 2018-02-07 Gustaf Neumann * nsfObj.c: Whitespace changes [5f1fe725] 2018-02-06 Gustaf Neumann * nsf.c (MakeProcError, PushProcCallFrame, InvokeShadowedProc): Pass execNsPtr to byte-compiler (which might be different to procPtr->cmd->nsPtr) [fb310a1d] 2018-01-30 Stefan Sobernig * nsf.c (NextSearchAndInvoke): Relax the pre-conditions, objv can actually be NULL (see test cases). Besides, the assertion was not reflected by a corresponding nonnull constraints on the NextSearchAndInvoke prototype. [42350dca] 2018-01-27 Gustaf Neumann * generic/*.*: Use Boolean type where appropriate. [e9949fac, 558d6c0b, de1e5161, de1e5161, 43188404, 90239071, a7f471a9, 4fd1ff60, d9746cd5] 2018-01-26 Gustaf Neumann * nsf.c, nsf.h, nsfEnumerationType.c, nsfPointer.c, nsfProfile.c: Remove unused arguments [625e5b42] * nsf.c: Use Boolean type on more occasions; fix incorrect comments; fix mixture of Tcl result code and 0/1 integers [b2902b78, e2dd2f44, 3f46f0b1] 2018-01-25 Gustaf Neumann * nsf.c: Improve type cleanness for clang 6.0 [c783c671] * nsf.c, gentclAPI.tcl, nsfAPI.h, nsfObj.c: Align prototypes with function definitions and minor code cleanup [6e5500ed] * nsf.c: Write separate commands in different lines (esp. for control structures) [048913c4] * nsf.c, nsfAPI.decls, nsfAPI.h, nsfInt.h, nsfProfile.c, nsfStack.c: Align naming of variables in function prototypes and definitions [ed886327] * nsf.c, nsfStack.c: Mark unused arguments as UNUSED [23bf0a56] 2018-01-24 Gustaf Neumann * gentclAPI.tcl, nsf.c, nsfAPI.decls, nsfAPI.h: Make argument names more regular improve alignment of prototype names with function definitions [9ffb7a5c] * nsf.c: Fix typos [d45807d8] * generic/*.h, generic/*.c: Improve alignment of prototypes with function definitions improve regularity of variable names [8552f707] * generic/*.h, generic/*.c: Prefer meaningful name in function prototypes align names in .decls file with prototypes in the .c and .h files [866971d8] 2018-01-22 Gustaf Neumann * nsf.c (ExitHandler), nsfEnumerationType.c (Nsf_Init), nsfInt.h (Register): Remove unused arguments [88a4a36b] * nsf.c (ExitHandler), nsfCmdDefinitions.c (Nsf_CmdDefinitionInit), nsfInt.h (Nsf_EnumerationTypeGetDomain): Remove unused argument [9c4fabbf, 9cae9f80] 2018-01-20 Gustaf Neumann * nsf.c (MakeProc): Minor cleanup (adjust comments, reduce variable scope) [1dad927c] 2018-01-19 Stefan Sobernig * nx-test.tcl (exit): Fix the return trampoline for [exit] during test runs [bb203de8] 2018-01-19 Gustaf Neumann * nx.tcl: Fix overseen error in regression test [6280104b] 2018-01-19 Stefan Sobernig * contains.test: Fix another 86/85 glitch [2125f114] * nx-test.tcl (try): Make test suite working under 8.5, again. [1d2bdbea] 2018-01-18 Gustaf Neumann * nsf.c (MakeProc, NsfProcContext): Execution namespace reform: Add execution namespace to proc context instead of altering the namespace of the command. This fixes strange behavior of "info commands ::o::p", which might have returned "::p"; provide compatibility with Tcl 8.7a2; extend regression test [3ccbf141] * Makefile.in, alias.test, double-alias.test: Extended regression test [df76a8d9] 2018-01-16 Gustaf Neumann * nsf.c (Nsf_Init): Get the "int" type from the Tcl_Obj directly, which will continue to work in Tcl 9.0. [2d77e6cc] * nsf.c (Nsf_Init): Provide compatibility with TIP #484 on wideInt [382055d5] * nsf.c, alias.test: Deactivate solution to the tcl87a2 problem for now, since we need a different solution with this for recursive aliases [392fda7d] * nsf.c (ObjectDispatch): Improve wording in comment [42f38005] * nsf.c (ParamOptionParse): Remove shadowing variable [d8f6dd4d] * nsf.c (ParamDefsFormat, ParamOptionParse): reduce implicit conversions [fa4eedf5] * nsf.c (NsfMethodAliasCmd): Transitional fix for tcl87a2 problem [63f7ad6c] 2018-01-15 Gustaf Neumann * nx.tcl: Cleaning up substdefault code [32791010] * alias.test: Extend regression test, make assumptions explicit [52af84c2] 2018-01-14 Gustaf Neumann * nx.tcl, parameters.test: Avoid stripping of substdefault from properties [ed365a90] * nx.tcl, parameters.test, substdefault.test: Add handling of extended substdefault options to per-object variables; improve default value checking for slot-less variables; transform associated array into a dict; extended regression tests [babe6447] 2018-01-13 Gustaf Neumann * nsf.c (MakeProc): Delete pre-existing commands explicitly [918dad99] 2018-01-12 Gustaf Neumann * nsf.c (MakeProc): Provide fully qualified names to Tcl_ProcObjCmd() to avoid potential problems in newer Tcl versions [79bca8ba] 2018-01-05 Gustaf Neumann * nsf.c, nx-test.tcl, destroy.test, forward.test: Make it possible to use error code for cmd result comparison; add some NSF specific error code [5ab2ad98] * nsf.c, disposition.test, parameters.test: Provide error hint for "invalid value constraints" errors [dc94a1f1] * nsf.c: Add error message, when present [50d4fe25] * nsf.c (ParamDefsFormat, ParamDefsFormatOption) (ParamDefsRefCountDecr): Reduce number of strlen() operations [11f14cc1] * nsf.c: whitespace changes [01ea26cd] * nsf.c (ParamDefinitionParse, ParamDefsFormat), nx.tcl, xotcl2.tcl: Fold "substdefault" and "substdefaultoptions" into a single parameter option "substdefault" [b6fa8004] 2018-01-04 Stefan Sobernig * nsf.c (ParamOptionParse): Fixed typo in error msg. [5bd8345b] * nsf.c (NSCheckNamespace): Simplify resource management of a DString. [b70b7fe7] * nsf.c (ParamSetFromAny2): Fix inline comment. [b62efa58] * nsf.c (ParamOptionParse, ParamDefinitionParse, ParamDefsParse), parameters.test: Small "type=" converterArg reform. Provided additional parameter in param-parser machinery, to communicate a (namespace) qualifier into ParamOptionParse. This way, the unqualified type=* values are now expanded to qualified names (definition scope): method parameters, nsf::is, nsf::parseargs, setter methods. Type=* in object parameters are currently expanded at the slot level, could also be added. New tests were added, existing ones adjusted to reflect the new behavior. [f0d2956f] 2018-01-03 Gustaf Neumann * nsf.c, nsfAPI.decls, substdefault.test: New command "nsf::definitionnamespace" plus regression tests [7f58a3a3] * nsf.c (ParamOptionParse): Fix typo in comment [3301d272] * nsf.c (ParamParse, ArgumentDefaults): Implement substdefaultoptions (for now, just providing the bitmask); added substdefault.test; rename static function ParamParse() to ParamDefinitionParse(); break overlong lines [25212e40] 2018-01-02 Gustaf Neumann * nsf.c: Silence gcc8 [8591bd17] 2018-01-01 Gustaf Neumann * nsf.c (NsfDebugGetDict): Use snprintf() instead of sprintf() to protect better against potential buffer overflows [37c87756] * nsf.c (CompiledColonLocalsLookup): Remove old-style CompiledColonLocalsLookup and use colonLocalVarCache variant instead. [b916a5a3] 2017-12-31 Gustaf Neumann * parameters.test: Fix leftover from the time, when we could call accessor methods without "get" [6ef0a130] 2017-12-31 Stefan Sobernig * nx.tcl, nx-mongo.tcl (parseParamSpec): Render target parameter non-positional, so that MetaSlot.parseParamSpec() becomes backward compatible. Adjusted callsites of parseParamSpec. [5ac8b093] 2017-12-30 Gustaf Neumann * nx-mongo.tcl (parseParameterSpec): Add missing argument to parseParameterSpec [5d495b6d] * mk_predefined.tcl: Improve portability (restict length of literal strings <= 4095) [1c256d87] * parameters.test: Deactivate two problematic tests for the time being to allow regression test to run [868e7224] 2017-12-29 Gustaf Neumann * generic/*.c, *.log, library/*: Fix typos, updaty copyright years according to commits [0de05aae] * nsf.c: Prefer boolean test, remove commented-out code [b84afe7e] 2017-12-24 Gustaf Neumann * doc/*.*, generic/*.c, library/*.*: Fix typos [c4f449cb] 2017-12-21 Stefan Sobernig * nsf.c (ParamParse): Fix crash when ParamParse is called with an empty-string argument, e.g. nsf::parameter::info type "". Tests provided. [2f921800] 2017-12-20 Stefan Sobernig * nsf.c (NsfParseArgsCmd): Fix another edge case (empty spec and/or empty argv), added more tests. See also TODO. [9bd2c31a] * nsf.c (NsfParseArgsCmd): Fix nsf::parseargs for the case of Tcl-only params, otherwise, it crashes due to an uninitialized params structure. Added some tests. [54277a59] 2017-12-19 Stefan Sobernig * nsf.c (ParamDefsParse): Fix small typo "allowedOptinons" -> "allowedOptions" [5a34df6e] 2017-12-01 Stefan Sobernig * nx.tcl (Class.variable): Clean up a left-over. [03bde7ee] * nx.tcl (Class.variable()): Re-order the substdefault-handling block to render it more meaningful. [7e754788] * nx.tcl (substdefault): Unify and harden substdefault handling. Both, per-class and per-object substdefault should now behave similarly in absence of a pair of evaluation brackets. Also, an attempt is made to capture ill-formed input to subst earlier ([info complete]). An actual substdefault reform, however, must tackle the [subst] calls (-novariables?) and make the calls more robust (at the script and C level; [apply]-like?). Added some tests for documentation. [dc801eac] 2017-11-30 Stefan Sobernig * Parameters.test: Simplify test case slightly. [efd3c005] * nx.tcl (MetaSlot.parseParameterSpec): Refine handling of the type converter to expand unqualified names to the "nearer" namespace, i.e., namespace of the slot-owning object) rather than "". Along the way, intercept invalid type=* values earlier (empty string, "::"). Added some tests. [f177ffa3] * nsfDebug.c: Remove duplicate array entry. [e9dc4cee] * nsfDebug.c (NsfInitPkgConfig): Provide NSF configuration data via the TIP 59 interface (::nsf::pkgconfig). [0ca1bf1c] 2017-11-18 Gustaf Neumann * nsfUtil.c: silence static checker [c9f1c850] 2017-11-16 Gustaf Neumann * nsfInt.h: Improve cleanness of compilation with Tcl 8.5 [f8b5f0a1] * nsf.c: unneeded function [165e176d] * nsfDebug.c, nsfInt.h: Add const declarations [5fb947bc] 2017-11-15 Gustaf Neumann * nsf.c, method-parameter.test: Don't allow bytearrays as name of non-pos args [8ac4f64a] 2017-11-09 Gustaf Neumann * nsf.c: Adjust print format to recent changes [f2ba4d0c] 2017-11-08 Stefan Sobernig * nsf.c, nsfInt.h, nsfObj.c: Make epoch counters unsigned ints, so doubling the number of possible epochs. [1aa07d20] * nsf.c: Unify cmd flags cast (unsigned long -> unsigned int) [a25c4bed] * nsf.c (ObjectCmdMethodDispatch): Simplify and cleanup condition expressions. [20c5ebb6] * nsf.c (ObjectCmdMethodDispatch), submethods.test: Enable private checking on ensembles, added test cases to capture the intended behavior behind -local and/or private for ensemble methods. [96e318fb] 2017-10-24 Gustaf Neumann * nsf.c (NsfColonCmd, NsfSelfCmd): Move GetObj() after tests of non-null asserts [543954d5] 2017-10-20 Gustaf Neumann * nx-mongo.tcl: Fix collateral damage of protection changes by making methods public [9429c5df] * nsfStack.c: Move prototypes to begin of file [b2c4a961] * nsfStack.c: Don't shadow variable names. [09a7e327] * nsfStack.c: Remove commented code, add missing nonnull-assert, shorten overlong lines [6b1b9272] 2017-10-19 Stefan Sobernig * nsf.c (NsfMethodForwardCmd): Provide correct scoping condition when requesting a method handle for a submethod forwarder. Added basic tests. [8b19916c] 2017-10-13 Stefan Sobernig * nsf.c, nsfStack.c: Bump copyright years. [bc16933e] * nsf.c (ObjectCmdMethodDispatch), protected.test: For ensemble or submethod dispatches, since ever, call protection had not been enforced at all. This commit enables call protection (protected) for ensembles and adds basic tests. * nsfStack.c (GetSelfObj): To allow one to resolve the self reference at arbitrary callstack levels, separate GetSelfObj into a GetSelfObj macro for the topmost self and GetSelfObj2. [4e48f104] 2017-10-06 Gustaf Neumann * nsf.c (TclDeletesObject): Fix typo [6a0a8ba7] 2017-10-02 Stefan Sobernig * nsf.c (NsfCCreateMethod): During a shutdown, in a filter setting, objv is not necessarily populated. Prior to this fix, the following crashes on exit for "ObjStr(objv[1])": [86becbe0] 2017-09-19 Gustaf Neumann * nsf.c (RemoveInstance, CallStackDoDestroy) (MixinInvalidateObjOrders, TclDeletesObject, CleanupDestroyClass): Add likely/unlikely for NSF_DURING_DELETE checks [57d67eeb] * nsf.c, nsfError.c, nsfProfile.c: Code cleanup [5df12821] 2017-09-06 Gustaf Neumann * Add Valgrind/callgrind support [81788340] * Improve performance of ObjectSystemsCheckSystemMethod() by over 20% [9612df65] 2017-09-04 Gustaf Neumann * nsf.c (AliasAdd, AliasGet, AliasDelete): Optimization for aliases, avoiding unboxing and re-boxing values as Tcl_Objs [0e77a312] * nsf.c: Minor cleanup and optimizations [5b6d88f8] * nsfUtil.c (strnstr): Avoid call of strncmp() in common cases [3b1402ae] 2017-08-31 Gustaf Neumann * nsf.c (CompiledLocalsLookup): Add cache for compiled locals starting with a colon to avoid repeated linear searches. * nsf.c (ParamOptionParse): Reduce number of string comparisons in ParamOptionParse() * nsf.c (ParamOptionParse, NsfProcDeleteProc): Factor out ProcContextRequire() * varresolution.test: Extend regression test [9c0e4571] 2017-08-21 Gustaf Neumann * nsf.c, nsfStack.c: Minor cleanup [fa5f1303] * nsf.c (MethodDispatch): Remove first argument of MethodDispatch, which is apparently not needed [18c7294b] * nsf.c, nsfInt.h (CompiledLocalsLookup): Avoid mixed declarations and code [a4b53da8]; added experimental definition of NSF_CONSTANT_COMPILED_LOCAL_LOOKUP [d9a45933] 2017-08-20 Stefan Sobernig * nsf.c (FindNextMethod): Provide revised, streamlined implementation of FindSelfNext as FindNextMethod. FindSelfNext is maintained, but unused for the time being. [cc7500b2] 2017-08-20 Gustaf Neumann * nsf.c, nsfStack.c: Cleanup and optimization [fd0a160a] * nsfStack.c: White space changes [f1549882] * nsfStack.c: Reduce number of returns before end of function [b64700f0] * nsf.c, nsf.h, nsfInt.h: Whitespace changes, typos [3f78bdd8] * nsfInt.h: More macro definition after GNU definitions [394c8d71] * nsf.h: Remove redundant definition [263d34ee] * nsf.c: Remove dead assignment [76cc1aa8] * Makefile.in: Add more tidy and checking compiler flags [d81f1d01] 2017-08-20 Stefan Sobernig * nsf.c (NsfCurrentCmd), nsfStack.c (CallStackNextFrameOfType): Render [current isnextcall] aware of ensembles. Extended submethods.test to cover [current isnextcall] within ensembles. [adedd712] 2017-08-18 Stefan Sobernig * nsf.c (FindSelfNext): Render [current nextmethod] aware of ensembles. Added basic tests. [2c338821] 2017-08-15 Gustaf Neumann * nsf.c: White-space changes [35936dfb] 2017-08-09 Stefan Sobernig * submethods.test: Clean up ensembles on top-level objects. [2a10ca19] * nx-test.tcl (nx::test case): As (ensemble) methods are currently not covered by the auto-cleanup feature of "nx::test case", I took care of not cleaning up the per-class ensemble slots while the alias is still available. This led to dangling aliases. [464ec0a0] * nsf.c (GetNextArguments): Ensemble method names via the colon resolver were not cleansed for the colon, leading to a broken method lookup chain. Fix for SF Ticket #1. Added basic tests. [404b5593] 2017-08-07 Gustaf Neumann * nsf.c (MakeProc, NsfMethodCreateCmd): Remove failing assertion, Tcl handles leading colons in proc names [71dcbd9c] 2017-06-18 Stefan Sobernig * nsf.c, forward.test (ForwardArg): Extend to recognize alternative element separators in list string reps (NsfHasTclSpace). [bc7f267a] * nsf.c, nsf-cmd.test (ObjectFindMethod): Extend to recognize all element separator chars (NsfHasTclSpace). [462bf8f1] * nsf.c, parameters.test (NsfMethodSetterCmd): Make list detection aware of all list separator chars (NsfHasTclSpace). [33d063a3] * nsf.c, parameters.test (NsfOResidualargsMethod): Extend XOTcl's list-notation support to recognize all Tcl list separators (NsfHasTclSpace). [5425e020] 2017-06-14 Stefan Sobernig * nsf.c, nsfInt.h: Start housekeeping work on Tcl command/proc names vs. NSF method names to avoid conflicts between ensemle methods and e.g. whitespace-containing command names. Added helper macro NsfHasTclSpace and some first tests. To be continued. [7e090d5c] 2017-06-03 Gustaf Neumann * nsf.c (FilterAdd): Reduce variable scope [9797190b] 2017-05-31 Stefan Sobernig * nsf.c (NsfMethodPropertyCmd,NsfForwardPropertyCmd): Remove extra whitespace from error message. [67401de3] 2017-05-29 Stefan Sobernig * methods.test: Add basic tests on composite names under the default unknown handler. [224bb589] * nsf.c (DispatchUnknownMethod): Sanitize messages emitted by default unknown handler. Unless in the context of an ensemble object (NSF_KEEP_CALLER_SELF, NSF_PER_OBJECT_DISPATCH), make sure that the entire method name, incl. multi-word names, are fully reported. [09b9e7c9] 2017-05-28 Gustaf Neumann * nsf.c (FindCalledClass): Simplify code [c1ac4a3f] * nsf.c (NsfCmdList, RemoveFromObjectMixins, FilterAdd) (FindCalledClass, FindSelfNext, NsfRelationSetCmd), nsfObj.c (NsfFilterregGet, FilterregSetFromAny), nsfStack.c (CallStackGetTopFrame0): Don't assume that CallStackGetTopFrame0() returns != NULL; reduce variable scopes; reduce number of returns before function end [16324e94] 2017-04-29 Gustaf Neumann * nsf.c (NsfOCgetMethod): Make sure, paramPtr is always initialized [be1aa824] 2017-04-22 Gustaf Neumann * xotcl2.tcl, library/*: Use more straightforward Tcl idiom [string index] to access first character of a string; standardize spelling of names of products (Tcl, AOLserver, PostgreSQL) [09b4bca7] * doc/*.man: Use uniform spelling of "Tcl" [bf42a9bc] * nsfAssemble.c: Whitespace change [6450e201] * generic/*.c, library/*/*.tcl: Use uniform spelling of "Tcl", fix more spelling errors [6af35a88, 0fd68504] 2017-04-21 Gustaf Neumann * nsf.c (NsfDebugGetDict): Provide means to debug invalid coding in Tcl_Objs [5561af6a] 2017-03-03 Stefan Sobernig * nx.tcl (VariableSlot): Fix value=delete to actually accept and implement "-nocomplain". Added tests (missing so far entirely) and updated the man pages accordingly. [8f64a468] 2017-03-03 Gustaf Neumann * tutorial-properties.tcl: Extend tutorial description [b6ec6249] 2017-03-02 Stefan Sobernig * nx.tcl, parameters.test (defineIncrementalOperations): Make sure value=add and value=delete actually run value checkers and, in case of "convert", pick up the conversion result. Added basic test. [470bd5f5] 2017-03-01 Stefan Sobernig * nsf.c (ArgumentCheck): Set parentheses correctly. [0c9b20f1] * nx.tcl (makeIncrementalOperations, defineIncrementalOperations): Avoid repeated slot= entries in options. Fix a typo. [d2ca2655] * nsf.c (ArgumentCheck): Avoid double dispatching to value checkers (built-in and type=*) for "slotset" parameters. Previously, configure and then the value=set (value=add) method triggered one dispatch each. Now, the configure pass skips the check and shifts sole responsibility on the value=set/ value=add methods. Added basic test cases to parameters.test to capture the intended call semantics. [daa771f5] 2017-03-01 Gustaf Neumann * tutorial-properties.tcl: Added properties tutorial [f6538271,05569c23] * nx-mongo.test: Extended test case (since people use this as an example; [a6b73475]) 2017-02-28 Gustaf Neumann * nsf.c (ForwardArgFix): Fix for potential bug in forwarder code. It was possible that substituted %proc becomes freed too early [980112e0] 2017-02-20 Stefan Sobernig * Regenerated migration and tutorial, to account for recently fixed typos and fix markup generation [d303212e] * Makefile.in: Unify ASCIIDOC exec configuration. [41946a0c] 2017-02-20 Gustaf Neumann * xotcl2.tcl: Modernize programming style (if-then-else -> if-else) [7fb9a460] * nsf-mongo.test: Add test for regular expression matching in conditions [3b027ad1] * nx-mongo.tcl: Make sure to initialize NSF object fetched from mongo [ac40ee26] 2017-02-14 Gustaf Neumann * nx.tcl, contains.test: Use more modern returnstate handling based on options, added regression tests [f5bba52e] 2017-02-14 Stefan Sobernig * next-migration.txt: Address some typos (thx to Guenter Ernst for reporting). [576c7576] * contains.test: Add two test cases to document the recent fix [6b570a0b] on error and errorcode propagation in contains. [1790b67d] 2017-02-14 Gustaf Neumann * nx.tcl (Object->contains): Propergate errorCode on catch [6b570a0b] 2017-01-18 Gustaf Neumann * nx-mongo.tcl: Add regular expression queries to conditions in NX [788f2f57] 2017-01-18 Stefan Sobernig * makefile.vc: Change another directory location to respect the INSTALLDIR setting [93011b62] 2017-01-18 Gustaf Neumann * nsfmongo.c, mongoAPI.h: Copy changed structure ParseContext [3d447c3c] * gentclAPI.tcl, nsfAPI.h: Prefer NULL over ConvertToNothing in the terminating record, since the former is not available for extensions [96479aa7] 2017-01-18 Stefan Sobernig * makefile.vc: Add missing header files to install target and use STUBDIR to properly locate the generated API headers. [e3446f62] 2017-01-14 Gustaf Neumann * nsf.c (AssertionCheck, ListParamDefs, NsfMethodAliasCmd, NsfMethodPropertyCmd): Include all enum values in case statements [cd3c5e04] * nsf.c: Use preprocessor variables more consistently [95656d26] * nsf.c (VarHashCreateVar, AssertionAddProc, ParamDefsStore. NsfStringIncrFree): Remove old-style function definitions [b49b73b7] * nsf.c (NsfProcStub): Remove implicit conversion to 'unsigned int' from 'int' [d2e248fb] * nsf.c (ObjectCmdMethodDispatch,FreeUnsetTraceVariable, NsfNextCmd, NsfCurrentCmd): ISO C90 forbids mixed declarations and code [4511d320] * nsf.c (Nsf_Init): Don't shadow local variable [54e49b08] * nsf.c, nsfInt.h: Reduce memory consumption via better aligning esp. on 64-bit machines [2076cebc] 2017-01-13 Gustaf Neumann * nsf.c (GetObjectFromObj, ObjectCmdMethodDispatch) (ObjectDispatch, ListCmdParams, ListMethod, NsfMethodSetterCmd) (NsfObjectAllocCmd, NsfCurrentCmd, CscListRemove): Don't shadow variables [22741a63] * nsf.c (NsfMemCounter): Modify STRING_NEW such that it is able to produce "const char *" such that it uses ckalloc [84a4722d] * nsf.c: Provide for clean compile with "-Wwrite-strings", added const declarations [878a74b6] * nsf.c: Removed unneeded arguments; mark unused arguments as UNUSED [b089be70] 2017-01-13 Stefan Sobernig * nx-pp.tcl (State): Add "substdefault" to two property specs to fix markup generation for various token types (variables etc.). [ac12ae10] 2017-01-11 Stefan Sobernig * source-doc-beautifier.tcl: Allow for omitting the built-in title line, to allow for custom doc and title preambles in example scripts ("-notile" flag). [66e3a960] 2017-01-06 Gustaf Neumann * configure.ac, nsf.c: Added a new configure flag "--enable-development=test" (in addition to "--enable-development" or "--disable-development") for activating more expensive runtime tests. "--enable-development" alone activates just assertion checking [fccf09e0] ./nsf2.4.0/autoclean.sh000644 000766 000024 00000000145 11217542614 015502 0ustar00neumannstaff000000 000000 #!/bin/sh make distclean for configscript in `find . -name configure` do rm -f $configscript done./nsf2.4.0/m4/PaxHeader/tcl.m4000644 000766 000024 00000000036 14270755757 016527 xustar00neumannstaff000000 000000 30 mtime=1659100143.318675375 ./nsf2.4.0/m4/tcl.m4000644 000766 000024 00000427317 14270755757 014575 0ustar00neumannstaff000000 000000 # tcl.m4 -- # # This file provides a set of autoconf macros to help TEA-enable # a Tcl extension. # # Copyright (c) 1999-2000 Ajuba Solutions. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. AC_PREREQ(2.57) dnl TEA extensions pass us the version of TEA they think they dnl are compatible with (must be set in TEA_INIT below) dnl TEA_VERSION="3.10" # Possible values for key variables defined: # # TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') # TEA_PLATFORM - windows unix # TEA_TK_EXTENSION - True if this is a Tk extension # TEACUP_OS - windows macosx linux generic # TEACUP_TOOLSET - Toolset in use (gcc,mingw,msvc,llvm) # TEACUP_PROFILE - win32 # #------------------------------------------------------------------------ # TEA_PATH_TCLCONFIG -- # # Locate the tclConfig.sh file and perform a sanity check on # the Tcl compile flags # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tcl=... # # Defines the following vars: # TCL_BIN_DIR Full path to the directory containing # the tclConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TCLCONFIG], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true AC_ARG_WITH(tcl, AC_HELP_STRING([--with-tcl], [directory containing tcl configuration (tclConfig.sh)]), with_tclconfig="${withval}") AC_MSG_CHECKING([for Tcl configuration]) AC_CACHE_VAL(ac_cv_c_tclconfig,[ # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case "${with_tclconfig}" in */tclConfig.sh ) if test -f "${with_tclconfig}"; then AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" else AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/pkg/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ `ls -d /usr/lib/tcl8.6 2>/dev/null` \ `ls -d /usr/lib/tcl8.5 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" AC_MSG_ERROR([Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh]) else no_tcl= TCL_BIN_DIR="${ac_cv_c_tclconfig}" AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_PATH_TKCONFIG -- # # Locate the tkConfig.sh file # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tk=... # # Defines the following vars: # TK_BIN_DIR Full path to the directory containing # the tkConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TKCONFIG], [ # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true TEA_TK_EXTENSION=0 AC_ARG_WITH(tk, AC_HELP_STRING([--with-tk], [directory containing tk configuration (tkConfig.sh)]), with_tkconfig="${withval}") AC_MSG_CHECKING([for Tk configuration]) AC_CACHE_VAL(ac_cv_c_tkconfig,[ # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case "${with_tkconfig}" in */tkConfig.sh ) if test -f "${with_tkconfig}"; then AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" else AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" AC_MSG_ERROR([Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh]) else no_tk= TEA_TK_EXTENSION=1 TK_BIN_DIR="${ac_cv_c_tkconfig}" AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_TCLCONFIG -- # # Load the tclConfig.sh file # # Arguments: # # Requires the following vars to be set: # TCL_BIN_DIR # # Results: # # Substitutes the following vars: # TCL_BIN_DIR # TCL_SRC_DIR # TCL_LIB_FILE #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TCLCONFIG], [ AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TCL_BIN_DIR}/tclConfig.sh" else AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitrary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" break fi done fi if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" AC_SUBST(TCL_VERSION) AC_SUBST(TCL_PATCH_LEVEL) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) AC_MSG_CHECKING([platform]) hold_cc=$CC; CC="$TCL_CC" AC_TRY_COMPILE(,[ #ifdef _WIN32 #error win32 #endif ], [ TEA_PLATFORM="unix" CYGPATH=echo ], [ TEA_PLATFORM="windows" AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) ] ) CC=$hold_cc AC_MSG_RESULT($TEA_PLATFORM) # The BUILD_$pkg is to define the correct extern storage class # handling when making this package AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME}, [], [Building extension source?]) # Do this here as we have fully defined TEA_PLATFORM now if test "${TEA_PLATFORM}" = "windows" ; then EXEEXT=".exe" CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp" fi # TEA specific: AC_SUBST(CLEANFILES) AC_SUBST(TCL_LIBS) AC_SUBST(TCL_DEFS) AC_SUBST(TCL_EXTRA_CFLAGS) AC_SUBST(TCL_LD_FLAGS) AC_SUBST(TCL_SHLIB_LD_LIBS) ]) #------------------------------------------------------------------------ # TEA_LOAD_TKCONFIG -- # # Load the tkConfig.sh file # # Arguments: # # Requires the following vars to be set: # TK_BIN_DIR # # Results: # # Sets the following vars that should be in tkConfig.sh: # TK_BIN_DIR #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TKCONFIG], [ AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TK_BIN_DIR}/tkConfig.sh" else AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TK_BIN_DIR}/Makefile" ; then TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tk.framework installed in an arbitrary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then for i in "`cd "${TK_BIN_DIR}"; pwd`" \ "`cd "${TK_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" break fi done fi if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" # TEA specific: Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) TEA_WINDOWINGSYSTEM="aqua" ;; *) TEA_WINDOWINGSYSTEM="x11" ;; esac elif test "${TEA_PLATFORM}" = "windows" ; then TEA_WINDOWINGSYSTEM="win32" fi AC_SUBST(TK_VERSION) AC_SUBST(TK_BIN_DIR) AC_SUBST(TK_SRC_DIR) AC_SUBST(TK_LIB_FILE) AC_SUBST(TK_LIB_FLAG) AC_SUBST(TK_LIB_SPEC) AC_SUBST(TK_STUB_LIB_FILE) AC_SUBST(TK_STUB_LIB_FLAG) AC_SUBST(TK_STUB_LIB_SPEC) # TEA specific: AC_SUBST(TK_LIBS) AC_SUBST(TK_XINCLUDES) ]) #------------------------------------------------------------------------ # TEA_PROG_TCLSH # Determine the fully qualified path name of the tclsh executable # in the Tcl build directory or the tclsh installed in a bin # directory. This macro will correctly determine the name # of the tclsh executable even if tclsh has not yet been # built in the build directory. The tclsh found is always # associated with a tclConfig.sh file. This tclsh should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments: # none # # Results: # Substitutes the following vars: # TCLSH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_TCLSH], [ AC_MSG_CHECKING([for tclsh]) AC_ARG_WITH(tclsh, [ --with-tclsh Specify a local tcl shell to use for dynamic code], with_tclsh=${withval}) # Use the value from --with-tclsh, if it was given TCLSH_PROG=0 if test x"${with_tclsh}" != x ; then if test -f "${with_tclsh}" ; then TCLSH_PROG=${with_tclsh} else if test -f "${with_tclsh}/tcl8.6" ; then TCLSH_PROG="${with_tclsh}/tcl8.6" else if test -f "${with_tclsh}/tclsh86.exe" ; then TCLSH_PROG="${with_tclsh}/tclsh86.exe" else AC_MSG_ERROR([${with_tclsh} does not point to a valid Tcl executable]) fi fi fi else if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" fi else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" fi fi AC_MSG_RESULT([${TCLSH_PROG}]) AC_SUBST(TCLSH_PROG) ]) #------------------------------------------------------------------------ # TEA_PROG_WISH # Determine the fully qualified path name of the wish executable # in the Tk build directory or the wish installed in a bin # directory. This macro will correctly determine the name # of the wish executable even if wish has not yet been # built in the build directory. The wish found is always # associated with a tkConfig.sh file. This wish should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments: # none # # Results: # Substitutes the following vars: # WISH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_WISH], [ AC_MSG_CHECKING([for wish]) if test -f "${TK_BIN_DIR}/Makefile" ; then # tkConfig.sh is in Tk build directory if test "${TEA_PLATFORM}" = "windows"; then if test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}s${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}$s{EXEEXT}" elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}t${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}t${EXEEXT}" elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}st${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}st${EXEEXT}" fi else WISH_PROG="${TK_BIN_DIR}/wish" fi else # tkConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" fi list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TK_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${WISH_PROG}" ; then REAL_TK_BIN_DIR="`cd "$i"; pwd`/" break fi done WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" fi AC_MSG_RESULT([${WISH_PROG}]) AC_SUBST(WISH_PROG) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SHARED -- # # Allows the building of shared libraries # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-shared=yes|no # --enable-stubs=yes|no # # Defines the following vars: # STATIC_BUILD Used for building import/export libraries # on Windows. # # Sets the following vars: # SHARED_BUILD Value of 1 or 0 # STUBS_BUILD Value if 1 or 0 # USE_TCL_STUBS Value true: if SHARED_BUILD or --enable-stubs # USE_TCLOO_STUBS Value true: if SHARED_BUILD or --enable-stubs # USE_TK_STUBS Value true: if SHARED_BUILD or --enable-stubs # AND TEA_WINDOWING_SYSTEM != "" #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SHARED], [ AC_MSG_CHECKING([how to build libraries]) AC_ARG_ENABLE(shared, AC_HELP_STRING([--enable-shared], [build and link with shared libraries (default: on)]), [shared_ok=$enableval], [shared_ok=yes]) if test "${enable_shared+set}" = set; then enableval="$enable_shared" shared_ok=$enableval else shared_ok=yes fi AC_ARG_ENABLE(stubs, AC_HELP_STRING([--enable-stubs], [build and link with stub libraries. Always true for shared builds (default: on)]), [stubs_ok=$enableval], [stubs_ok=yes]) if test "${enable_stubs+set}" = set; then enableval="$enable_stubs" stubs_ok=$enableval else stubs_ok=yes fi # Stubs are always enabled for shared builds if test "$shared_ok" = "yes" ; then AC_MSG_RESULT([shared]) SHARED_BUILD=1 STUBS_BUILD=1 else AC_MSG_RESULT([static]) SHARED_BUILD=0 AC_DEFINE(STATIC_BUILD, 1, [This a static build]) if test "$stubs_ok" = "yes" ; then STUBS_BUILD=1 else STUBS_BUILD=0 fi fi if test "${STUBS_BUILD}" = "1" ; then AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) AC_DEFINE(USE_TCLOO_STUBS, 1, [Use TclOO stubs]) if test "${TEA_WINDOWINGSYSTEM}" != ""; then AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) fi fi AC_SUBST(SHARED_BUILD) AC_SUBST(STUBS_BUILD) ]) #------------------------------------------------------------------------ # TEA_ENABLE_THREADS -- # # Specify if thread support should be enabled. If "yes" is specified # as an arg (optional), threads are enabled by default, "no" means # threads are disabled. "yes" is the default. # # TCL_THREADS is checked so that if you are compiling an extension # against a threaded core, your extension must be compiled threaded # as well. # # Note that it is legal to have a thread enabled extension run in a # threaded or non-threaded Tcl core, but a non-threaded extension may # only run in a non-threaded Tcl core. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-threads # # Sets the following vars: # THREADS_LIBS Thread library(s) # # Defines the following vars: # TCL_THREADS # _REENTRANT # _THREAD_SAFE #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_THREADS], [ AC_ARG_ENABLE(threads, AC_HELP_STRING([--enable-threads], [build with threads]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention AC_DEFINE(USE_THREAD_ALLOC, 1, [Do we want to use the threaded memory allocator?]) AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) if test "`uname -s`" = "SunOS" ; then AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) fi AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] AC_CHECK_LIB(pthread, __pthread_mutex_init, tcl_ok=yes, tcl_ok=no) fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else AC_CHECK_LIB(pthreads, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else AC_CHECK_LIB(c, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "no"; then AC_CHECK_LIB(c_r, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 AC_MSG_WARN([Do not know how to find pthread lib on your system - thread support disabled]) fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output AC_MSG_CHECKING([for building with threads]) if test "${TCL_THREADS}" = 1; then AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) AC_MSG_RESULT([yes (default)]) else AC_MSG_RESULT([no]) fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then AC_MSG_WARN([ Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads.]) fi ;; *) if test "${TCL_THREADS}" = "1"; then AC_MSG_WARN([ --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core.]) fi ;; esac AC_SUBST(TCL_THREADS) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SYMBOLS -- # # Specify if debugging symbols should be used. # Memory (TCL_MEM_DEBUG) debugging can also be enabled. # # Arguments: # none # # TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives # the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted. # Requires the following vars to be set in the Makefile: # CFLAGS_DEFAULT # LDFLAGS_DEFAULT # # Results: # # Adds the following arguments to configure: # --enable-symbols # # Defines the following vars: # CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true # Sets to "$(CFLAGS_OPTIMIZE) -DNDEBUG" if false # LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true # Sets to $(LDFLAGS_OPTIMIZE) if false # DBGX Formerly used as debug library extension; # always blank now. #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SYMBOLS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_CONFIG_CFLAGS]) AC_MSG_CHECKING([for build with symbols]) AC_ARG_ENABLE(symbols, AC_HELP_STRING([--enable-symbols], [build with debugging symbols (default: off)]), [tcl_ok=$enableval], [tcl_ok=no]) DBGX="" if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" AC_MSG_RESULT([no]) else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then AC_MSG_RESULT([yes (standard debugging)]) fi fi # TEA specific: if test "${TEA_PLATFORM}" != "windows" ; then LDFLAGS_DEFAULT="${LDFLAGS}" fi AC_SUBST(CFLAGS_DEFAULT) AC_SUBST(LDFLAGS_DEFAULT) AC_SUBST(TCL_DBGX) if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then AC_MSG_RESULT([enabled symbols mem debugging]) else AC_MSG_RESULT([enabled $tcl_ok debugging]) fi fi ]) #------------------------------------------------------------------------ # TEA_ENABLE_LANGINFO -- # # Allows use of modern nl_langinfo check for better l10n. # This is only relevant for Unix. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-langinfo=yes|no (default is yes) # # Defines the following vars: # HAVE_LANGINFO Triggers use of nl_langinfo if defined. #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_LANGINFO], [ AC_ARG_ENABLE(langinfo, AC_HELP_STRING([--enable-langinfo], [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), [langinfo_ok=$enableval], [langinfo_ok=yes]) HAVE_LANGINFO=0 if test "$langinfo_ok" = "yes"; then AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) fi AC_MSG_CHECKING([whether to use nl_langinfo]) if test "$langinfo_ok" = "yes"; then AC_CACHE_VAL(tcl_cv_langinfo_h, [ AC_TRY_COMPILE([#include ], [nl_langinfo(CODESET);], [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) AC_MSG_RESULT([$tcl_cv_langinfo_h]) if test $tcl_cv_langinfo_h = yes; then AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) fi else AC_MSG_RESULT([$langinfo_ok]) fi ]) #-------------------------------------------------------------------- # TEA_CONFIG_SYSTEM # # Determine what the system is (some things cannot be easily checked # on a feature-driven basis, alas). This can usually be done via the # "uname" command. # # Arguments: # none # # Results: # Defines the following var: # # system - System/platform/version identification code. #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_SYSTEM], [ AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then AC_MSG_WARN([can't find uname command]) tcl_cv_sys_version=unknown else if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi ]) system=$tcl_cv_sys_version ]) #-------------------------------------------------------------------- # TEA_CONFIG_CFLAGS # # Try to determine the proper flags to pass to the compiler # for building shared libraries and other such nonsense. # # Arguments: # none # # Results: # # Defines and substitutes the following vars: # # DL_OBJS, DL_LIBS - removed for TEA, only needed by core. # LDFLAGS - Flags to pass to the compiler when linking object # files into an executable application binary such # as tclsh. # LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. Could # be the same as CC_SEARCH_FLAGS if ${CC} is used to link. # CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. # SHLIB_CFLAGS - Flags to pass to cc when compiling the components # of a shared library (may request position-independent # code, among other things). # SHLIB_LD - Base command to use for combining object files # into a shared library. # SHLIB_LD_LIBS - Dependent libraries for the linker to scan when # creating shared libraries. This symbol typically # goes at the end of the "ld" commands that build # shared libraries. The value of the symbol defaults to # "${LIBS}" if all of the dependent libraries should # be specified when creating a shared library. If # dependent libraries should not be specified (as on # SunOS 4.x, where they cause the link to fail, or in # general if Tcl and Tk aren't themselves shared # libraries), then this symbol has an empty string # as its value. # SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable # extensions. An empty string means we don't know how # to use shared libraries on this platform. # LIB_SUFFIX - Specifies everything that comes after the "libfoo" # in a static or shared library name, using the $PACKAGE_VERSION variable # to put the version in the right place. This is used # by platforms that need non-standard library names. # Examples: ${PACKAGE_VERSION}.so.1.1 on NetBSD, since it needs # to have a version after the .so, and ${PACKAGE_VERSION}.a # on AIX, since a shared library needs to have # a .a extension whereas shared objects for loadable # extensions have a .so extension. Defaults to # ${PACKAGE_VERSION}${SHLIB_SUFFIX}. # CFLAGS_DEBUG - # Flags used when running the compiler in debug mode # CFLAGS_OPTIMIZE - # Flags used when running the compiler in optimize mode # CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_CFLAGS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # Step 0.a: Enable 64 bit support? AC_MSG_CHECKING([if 64bit support is requested]) AC_ARG_ENABLE(64bit, AC_HELP_STRING([--enable-64bit], [enable 64bit support (default: off)]), [do64bit=$enableval], [do64bit=no]) AC_MSG_RESULT([$do64bit]) # Step 0.b: Enable Solaris 64 bit VIS support? AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) AC_ARG_ENABLE(64bit-vis, AC_HELP_STRING([--enable-64bit-vis], [enable 64bit Sparc VIS support (default: off)]), [do64bitVIS=$enableval], [do64bitVIS=no]) AC_MSG_RESULT([$do64bitVIS]) # Force 64bit on with VIS AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) # Step 0.c: Check if visibility support is available. Do this here so # that platform specific alternatives can be used below if this fails. AC_CACHE_CHECK([if compiler supports visibility "hidden"], tcl_cv_cc_visibility_hidden, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" AC_TRY_LINK([ extern __attribute__((__visibility__("hidden"))) void f(void); void f(void) {}], [f();], tcl_cv_cc_visibility_hidden=yes, tcl_cv_cc_visibility_hidden=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ AC_DEFINE(MODULE_SCOPE, [extern __attribute__((__visibility__("hidden")))], [Compiler support for module scope symbols]) AC_DEFINE(HAVE_HIDDEN, [1], [Compiler support for module scope symbols]) ]) # Step 0.d: Disable -rpath support? AC_MSG_CHECKING([if rpath support is requested]) AC_ARG_ENABLE(rpath, AC_HELP_STRING([--disable-rpath], [disable rpath support (default: on)]), [doRpath=$enableval], [doRpath=yes]) AC_MSG_RESULT([$doRpath]) # TEA specific: Cross-compiling options for Windows/CE builds? AS_IF([test "${TEA_PLATFORM}" = windows], [ AC_MSG_CHECKING([if Windows/CE build is requested]) AC_ARG_ENABLE(wince, AC_HELP_STRING([--enable-wince], [enable Win/CE support (where applicable)]), [doWince=$enableval], [doWince=no]) AC_MSG_RESULT([$doWince]) ]) # Set the variable "system" to hold the name and version number # for the system. TEA_CONFIG_SYSTEM # Require ranlib early so we can override it in special cases below. AC_REQUIRE([AC_PROG_RANLIB]) # Set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case and removed some core-only vars. do64bit_ok=no # default to '{$LIBS}' and set to "" on per-platform necessary basis SHLIB_LD_LIBS='${LIBS}' # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" UNSHARED_LIB_SUFFIX="" # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g AS_IF([test "$GCC" = yes], [ CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall" ], [ CFLAGS_OPTIMIZE=-O CFLAGS_WARNING="" ]) AC_CHECK_TOOL(AR, ar) STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION=""],[SHLIB_VERSION=".$SHLIB_VERSION"]) case $system in # TEA specific: windows) # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test "$GCC" != "yes" -a ! -d "${PATH64}" ; then AC_MSG_WARN([Could not find 64-bit $MACHINE SDK to enable 64bit mode]) AC_MSG_WARN([Ensure latest Platform SDK is installed]) do64bit="no" else AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) do64bit_ok="yes" fi fi if test "$doWince" != "no" ; then if test "$do64bit" != "no" ; then AC_MSG_ERROR([Windows/CE and 64-bit builds incompatible]) fi if test "$GCC" = "yes" ; then AC_MSG_ERROR([Windows/CE and GCC builds incompatible]) fi TEA_PATH_CELIB # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F, '{ \ if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \ if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \ if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \ if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]]) doWince="no" else # We could PATH_NOSPACE these, but that's not important, # as long as we quote them when used. CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi case "x`echo \${VisualStudioVersion}`" in x1[[4-9]]*) lflags="${lflags} -nodefaultlib:libucrt.lib" TEA_ADD_LIBS([ucrt.lib]) ;; *) ;; esac if test "$do64bit" != "no" ; then # All this magic is necessary for the Win64 SDK RC1 - hobbs CC="\"${PATH64}/cl.exe\"" CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" lflags="${lflags} -nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 TEA_ADD_LIBS([bufferoverflowU.lib]) elif test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="\"${CEBINROOT}/cl.exe\"" else CC="\"${CEBINROOT}/cl${ARCH}.exe\"" fi CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower([$]0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" if test "${SHARED_BUILD}" = "1" ; then # Static CE builds require static celib as well defs="${defs} _DLL" fi for i in $defs ; do AC_DEFINE_UNQUOTED($i, 1, [WinCE def ]$i) done AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION, [_WIN32_WCE version]) AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION, [UNDER_CE version]) CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -Ox" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="${lflags} -MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" AC_SUBST(CELIB_DIR) else RC="rc" lflags="${lflags} -nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode AC_CHECK_TOOL(RC, windres) CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD='${CC} -shared' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' PRACTCL_UNSHARED_LIB_SUFFIX='.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" AC_CACHE_CHECK(for cross-compile version of gcc, ac_cv_cross, AC_TRY_COMPILE([ #ifdef _WIN32 #error cross-compiler #endif ], [], ac_cv_cross=yes, ac_cv_cross=no) ) if test "$ac_cv_cross" = "yes"; then case "$do64bit" in amd64|x64|yes) CC="x86_64-w64-mingw32-gcc" LD="x86_64-w64-mingw32-ld" AR="x86_64-w64-mingw32-ar" RANLIB="x86_64-w64-mingw32-ranlib" RC="x86_64-w64-mingw32-windres" ;; *) CC="i686-w64-mingw32-gcc" LD="i686-w64-mingw32-ld" AR="i686-w64-mingw32-ar" RANLIB="i686-w64-mingw32-ranlib" RC="i686-w64-mingw32-windres" ;; esac fi else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" if test "$doWince" != "no" ; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots ;; AIX-*) AS_IF([test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"], [ # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r|*_r\ *) # ok ... ;; *) # Make sure only first arg gets _r CC=`echo "$CC" | sed -e 's/^\([[^ ]]*\)/\1_r/'` ;; esac AC_MSG_RESULT([Using $CC for compiling with threads]) ]) LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_SUFFIX=".so" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported with GCC on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" ]) ]) AS_IF([test "`uname -m`" = ia64], [ # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" AS_IF([test "$GCC" = yes], [ CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' ], [ CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' ]) LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ], [ AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared -Wl,-bexpall' ], [ SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" LDFLAGS="$LDFLAGS -brtl" ]) SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_SUFFIX=".so" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; CYGWIN_*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$[@].a" SHLIB_SUFFIX=".dll" EXEEXT=".exe" do64bit_ok=yes CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"]) ;; HP-UX-*.11.*) # Use updated header definitions where possible AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) # TEA specific: Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library AS_IF([test "`uname -m`" = ia64], [ SHLIB_SUFFIX=".so" # Use newer C++ library for C++ extensions #if test "$GCC" != "yes" ; then # CPPFLAGS="-AA" #fi ], [ SHLIB_SUFFIX=".sl" ]) AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) AS_IF([test "$tcl_ok" = yes], [ LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" ]) AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ CFLAGS="$CFLAGS -z" # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" ]) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = "yes"], [ AS_IF([test "$GCC" = yes], [ case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]) ;; esac ], [ do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" ]) ]) ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [ CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" ], [ case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" ]) ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported by gcc]) ], [ do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" ]) ]) ;; Linux*|GNU*|NetBSD-Debian) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) AS_IF([test $do64bit = yes], [ AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_m64 = yes], [ CFLAGS="$CFLAGS -m64" do64bit_ok=yes ]) ]) # The combo of gcc + glibc has a bug related to inlining of # functions like strtod(). The -fno-builtin flag should address # this problem but it does not work. The -fno-inline flag is kind # of overkill but it works. Disable inlining only when one of the # files in compat/*.c is being linked in. AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"]) ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' LD_FLAGS="-Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) ;; OpenBSD-*) arch=`arch -s` case "$arch" in vax) SHLIB_SUFFIX="" SHARED_LIB_SUFFIX="" LDFLAGS="" ;; *) case "$arch" in alpha|sparc64) SHLIB_CFLAGS="-fPIC" ;; *) SHLIB_CFLAGS="-fpic" ;; esac SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}' LDFLAGS="-Wl,-export-dynamic" ;; esac case "$arch" in vax) CFLAGS_OPTIMIZE="-O1" ;; *) CFLAGS_OPTIMIZE="-O2" ;; esac AS_IF([test "${TCL_THREADS}" = "1"], [ # On OpenBSD: Compile with -pthread # Don't link with -lpthread LIBS=`echo $LIBS | sed s/-lpthread//` CFLAGS="$CFLAGS -pthread" ]) # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*) # NetBSD has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) ;; FreeBSD-*) # This configuration from FreeBSD Ports. SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,-soname,\$[@]" SHLIB_SUFFIX=".so" LDFLAGS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the LDFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LDFLAGS="$LDFLAGS $PTHREAD_LIBS"]) case $system in FreeBSD-3.*) # Version numbers are dot-stripped by system policy. TCL_TRIM_DOTS=`echo ${PACKAGE_VERSION} | tr -d .` UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" AS_IF([test $do64bit = yes], [ case `arch` in ppc) AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], tcl_cv_cc_arch_ppc64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" AC_TRY_LINK(,, tcl_cv_cc_arch_ppc64=yes, tcl_cv_cc_arch_ppc64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes ]);; i386) AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], tcl_cv_cc_arch_x86_64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" AC_TRY_LINK(,, tcl_cv_cc_arch_x86_64=yes, tcl_cv_cc_arch_x86_64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes ]);; *) AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; esac ], [ # Check for combined 32-bit and 64-bit fat build AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ fat_32_64=yes]) ]) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_single_module = yes], [ SHLIB_LD="${SHLIB_LD} -Wl,-single_module" ]) # TEA specific: link shlib with current and compatibility version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" SHLIB_SUFFIX=".dylib" # Don't use -prebind when building for Mac OS X 10.4 or later only: AS_IF([test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \ "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4], [ LDFLAGS="$LDFLAGS -prebind"]) LDFLAGS="$LDFLAGS -headerpad_max_install_names" AC_CACHE_CHECK([if ld accepts -search_paths_first flag], tcl_cv_ld_search_paths_first, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, tcl_cv_ld_search_paths_first=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ LDFLAGS="$LDFLAGS -Wl,-search_paths_first" ]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [__private_extern__], [Compiler support for module scope symbols]) tcl_cv_cc_visibility_hidden=yes ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for combined 32 & 64 bit fat builds of Tk # extensions, verify that 64-bit build is possible. AS_IF([test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"], [ AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" AC_TRY_LINK([#include ], [XrmInitialize();], tcl_cv_lib_x11_64=yes, tcl_cv_lib_x11_64=no) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua], [ AC_CACHE_CHECK([for 64-bit Tk], tcl_cv_lib_tk_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" AC_TRY_LINK([#include ], [Tk_InitStubs(NULL, "", 0);], tcl_cv_lib_tk_64=yes, tcl_cv_lib_tk_64=no) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) # remove 64-bit arch flags from CFLAGS et al. if configuration # does not support 64-bit. AS_IF([test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no], [ AC_MSG_NOTICE([Removing 64-bit architectures from compiler & linker flags]) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done]) ]) ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h [Should OS/390 do the right thing with sockets?]) ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" AS_IF([test "$SHARED_BUILD" = 1], [ SHLIB_LD='ld -shared -expect_unresolved "*"' ], [ SHLIB_LD='ld -non_shared -expect_unresolved "*"' ]) SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) # see pthread_intro(3) for pthread support on osf1, k.furukawa AS_IF([test "${TCL_THREADS}" = 1], [ CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` AS_IF([test "$GCC" = yes], [ LIBS="$LIBS -lpthread -lmach -lexc" ], [ CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) ]) ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) AS_IF([test "$GCC" = yes], [ SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" ], [ SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" ]) SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-5.[[0-6]]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ arch=`isainfo` AS_IF([test "$arch" = "sparcv9 sparc"], [ AS_IF([test "$GCC" = yes], [ AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [ AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" ]) ], [ do64bit_ok=yes AS_IF([test "$do64bitVIS" = yes], [ CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" ], [ CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" ]) # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" ]) ], [AS_IF([test "$arch" = "amd64 i386"], [ AS_IF([test "$GCC" = yes], [ case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]);; esac ], [ do64bit_ok=yes case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac ]) ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) ]) SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "$do64bit_ok" = yes], [ AS_IF([test "$arch" = "sparcv9 sparc"], [ # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" ], [AS_IF([test "$arch" = "amd64 i386"], [ # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" ])]) ]) ], [ case $system in SunOS-5.[[1-9]][[0-9]]*) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ]) ;; UNIX_SV* | UnixWare-5*) SHLIB_CFLAGS="-KPIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers # that don't grok the -Bexport option. Test that it does. AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-Bexport" AC_TRY_LINK(, [int i;], tcl_cv_ld_Bexport=yes, tcl_cv_ld_Bexport=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_Bexport = yes], [ LDFLAGS="$LDFLAGS -Wl,-Bexport" ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; esac AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [ AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) ]) dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so dnl # until the end of configure, as configure's compile and link tests use dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's dnl # preprocessing tests use only CPPFLAGS. AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) # Add in the arch flags late to ensure it wasn't removed. # Not necessary in TEA, but this is aligned with core LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. AS_IF([test "$GCC" = yes], [ case $system in AIX-*) ;; BSD/OS*) ;; CYGWIN_*|MINGW32_*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*|OpenBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; windows) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [extern], [No Compiler support for module scope symbols]) ]) AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}' ]) AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a' ]) if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then AC_CACHE_CHECK(for SEH support in compiler, tcl_cv_seh, AC_TRY_RUN([ #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN int main(int argc, char** argv) { int a, b = 0; __try { a = 666 / b; } __except (EXCEPTION_EXECUTE_HANDLER) { return 0; } return 1; } ], tcl_cv_seh=yes, tcl_cv_seh=no, tcl_cv_seh=no) ) if test "$tcl_cv_seh" = "no" ; then AC_DEFINE(HAVE_NO_SEH, 1, [Defined when mingw does not support SEH]) fi # # Check to see if the excpt.h include file provided contains the # definition for EXCEPTION_DISPOSITION; if not, which is the case # with Cygwin's version as of 2002-04-10, define it to be int, # sufficient for getting the current code to work. # AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files, tcl_cv_eh_disposition, AC_TRY_COMPILE([ # define WIN32_LEAN_AND_MEAN # include # undef WIN32_LEAN_AND_MEAN ],[ EXCEPTION_DISPOSITION x; ], tcl_cv_eh_disposition=yes, tcl_cv_eh_disposition=no) ) if test "$tcl_cv_eh_disposition" = "no" ; then AC_DEFINE(EXCEPTION_DISPOSITION, int, [Defined when cygwin/mingw does not support EXCEPTION DISPOSITION]) fi # Check to see if winnt.h defines CHAR, SHORT, and LONG # even if VOID has already been #defined. The win32api # used by mingw and cygwin is known to do this. AC_CACHE_CHECK(for winnt.h that ignores VOID define, tcl_cv_winnt_ignore_void, AC_TRY_COMPILE([ #define VOID void #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN ], [ CHAR c; SHORT s; LONG l; ], tcl_cv_winnt_ignore_void=yes, tcl_cv_winnt_ignore_void=no) ) if test "$tcl_cv_winnt_ignore_void" = "yes" ; then AC_DEFINE(HAVE_WINNT_IGNORE_VOID, 1, [Defined when cygwin/mingw ignores VOID define in winnt.h]) fi fi # See if the compiler supports casting to a union type. # This is used to stop gcc from printing a compiler # warning when initializing a union member. AC_CACHE_CHECK(for cast to union support, tcl_cv_cast_to_union, AC_TRY_COMPILE([], [ union foo { int i; double d; }; union foo f = (union foo) (int) 0; ], tcl_cv_cast_to_union=yes, tcl_cv_cast_to_union=no) ) if test "$tcl_cv_cast_to_union" = "yes"; then AC_DEFINE(HAVE_CAST_TO_UNION, 1, [Defined when compiler supports casting to union type.]) fi AC_SUBST(CFLAGS_DEBUG) AC_SUBST(CFLAGS_OPTIMIZE) AC_SUBST(CFLAGS_WARNING) AC_SUBST(STLIB_LD) AC_SUBST(SHLIB_LD) AC_SUBST(SHLIB_SUFFIX) AC_SUBST(SHLIB_LD_LIBS) AC_SUBST(SHLIB_CFLAGS) AC_SUBST(LD_LIBRARY_PATH_VAR) # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary TEA_TCL_EARLY_FLAGS TEA_TCL_64BIT_FLAGS ]) #-------------------------------------------------------------------- # TEA_SERIAL_PORT # # Determine which interface to use to talk to the serial port. # Note that #include lines must begin in leftmost column for # some compilers to recognize them as preprocessor directives, # and some build environments have stdin not pointing at a # pseudo-terminal (usually /dev/null instead.) # # Arguments: # none # # Results: # # Defines only one of the following vars: # HAVE_SYS_MODEM_H # USE_TERMIOS # USE_TERMIO # USE_SGTTY #-------------------------------------------------------------------- AC_DEFUN([TEA_SERIAL_PORT], [ AC_CHECK_HEADERS(sys/modem.h) AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ AC_TRY_RUN([ #include int main() { struct termios t; if (tcgetattr(0, &t) == 0) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include #include int main() { struct termios t; if (tcgetattr(0, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) fi]) case $tcl_cv_api_serial in termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; esac ]) #-------------------------------------------------------------------- # TEA_MISSING_POSIX_HEADERS # # Supply substitutes for missing POSIX header files. Special # notes: # - stdlib.h doesn't define strtol, strtoul, or # strtod in some versions of SunOS # - some versions of string.h don't declare procedures such # as strstr # # Arguments: # none # # Results: # # Defines some of the following vars: # NO_DIRENT_H # NO_ERRNO_H # NO_VALUES_H # HAVE_LIMITS_H or NO_LIMITS_H # NO_STDLIB_H # NO_STRING_H # NO_SYS_WAIT_H # NO_DLFCN_H # HAVE_SYS_PARAM_H # # HAVE_STRING_H ? # # tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and # CHECK on limits.h #-------------------------------------------------------------------- AC_DEFUN([TEA_MISSING_POSIX_HEADERS], [ AC_CACHE_CHECK([dirent.h], tcl_cv_dirent_h, [ AC_TRY_LINK([#include #include ], [ #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)]) if test $tcl_cv_dirent_h = no; then AC_DEFINE(NO_DIRENT_H, 1, [Do we have ?]) fi # TEA specific: AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H, 1, [Do we have ?])]) AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have ?])]) AC_CHECK_HEADER(limits.h, [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have ?])], [AC_DEFINE(NO_LIMITS_H, 1, [Do we have ?])]) AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0) if test $tcl_ok = 0; then AC_DEFINE(NO_STDLIB_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0) AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0) # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then AC_DEFINE(NO_STRING_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have ?])]) # OS/390 lacks sys/param.h (and doesn't need it, by chance). AC_HAVE_HEADERS(sys/param.h) ]) #-------------------------------------------------------------------- # TEA_PATH_X # # Locate the X11 header files and the X11 library archive. Try # the ac_path_x macro first, but if it doesn't find the X stuff # (e.g. because there's no xmkmf program) then check through # a list of possible directories. Under some conditions the # autoconf macro will return an include directory that contains # no include files, so double-check its result just to be safe. # # This should be called after TEA_CONFIG_CFLAGS as setting the # LIBS line can confuse some configure macro magic. # # Arguments: # none # # Results: # # Sets the following vars: # XINCLUDES # XLIBSW # PKG_LIBS (appends to) #-------------------------------------------------------------------- AC_DEFUN([TEA_PATH_X], [ if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then TEA_PATH_UNIX_X fi ]) AC_DEFUN([TEA_PATH_UNIX_X], [ AC_PATH_X not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then AC_TRY_CPP([#include ], , not_really_there="yes") else if test ! -r $x_includes/X11/Xlib.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then AC_MSG_CHECKING([for X11 header files]) found_xincludes="no" AC_TRY_CPP([#include ], found_xincludes="yes", found_xincludes="no") if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Xlib.h; then AC_MSG_RESULT([$i]) XINCLUDES=" -I$i" found_xincludes="yes" break fi done fi else if test "$x_includes" != ""; then XINCLUDES="-I$x_includes" found_xincludes="yes" fi fi if test "$found_xincludes" = "no"; then AC_MSG_RESULT([couldn't find any!]) fi if test "$no_x" = yes; then AC_MSG_CHECKING([for X11 libraries]) XLIBSW=nope dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" for i in $dirs ; do if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then AC_MSG_RESULT([$i]) XLIBSW="-L$i -lX11" x_libraries="$i" break fi done else if test "$x_libraries" = ""; then XLIBSW=-lX11 else XLIBSW="-L$x_libraries -lX11" fi fi if test "$XLIBSW" = nope ; then AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) fi if test "$XLIBSW" = nope ; then AC_MSG_RESULT([could not find any! Using -lX11.]) XLIBSW=-lX11 fi # TEA specific: if test x"${XLIBSW}" != x ; then PKG_LIBS="${PKG_LIBS} ${XLIBSW}" fi ]) #-------------------------------------------------------------------- # TEA_BLOCKING_STYLE # # The statements below check for systems where POSIX-style # non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. # On these systems (mostly older ones), use the old BSD-style # FIONBIO approach instead. # # Arguments: # none # # Results: # # Defines some of the following vars: # HAVE_SYS_IOCTL_H # HAVE_SYS_FILIO_H # USE_FIONBIO # O_NONBLOCK #-------------------------------------------------------------------- AC_DEFUN([TEA_BLOCKING_STYLE], [ AC_CHECK_HEADERS(sys/ioctl.h) AC_CHECK_HEADERS(sys/filio.h) TEA_CONFIG_SYSTEM AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) case $system in OSF*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; *) AC_MSG_RESULT([O_NONBLOCK]) ;; esac ]) #-------------------------------------------------------------------- # TEA_TIME_HANDLER # # Checks how the system deals with time.h, what time structures # are used on the system, and what fields the structures have. # # Arguments: # none # # Results: # # Defines some of the following vars: # USE_DELTA_FOR_TZ # HAVE_TM_GMTOFF # HAVE_TM_TZADJ # HAVE_TIMEZONE_VAR #-------------------------------------------------------------------- AC_DEFUN([TEA_TIME_HANDLER], [ AC_CHECK_HEADERS(sys/time.h) AC_HEADER_TIME AC_STRUCT_TIMEZONE AC_CHECK_FUNCS(gmtime_r localtime_r) AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_tzadj;], tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)]) if test $tcl_cv_member_tm_tzadj = yes ; then AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) fi AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_gmtoff;], tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)]) if test $tcl_cv_member_tm_gmtoff = yes ; then AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) fi # # Its important to include time.h in this check, as some systems # (like convex) have timezone functions, etc. # AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ AC_TRY_COMPILE([#include ], [extern long timezone; timezone += 1; exit (0);], tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)]) if test $tcl_cv_timezone_long = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) else # # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. # AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ AC_TRY_COMPILE([#include ], [extern time_t timezone; timezone += 1; exit (0);], tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)]) if test $tcl_cv_timezone_time = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) fi fi ]) #-------------------------------------------------------------------- # TEA_BUGGY_STRTOD # # Under Solaris 2.4, strtod returns the wrong value for the # terminating character under some conditions. Check for this # and if the problem exists use a substitute procedure # "fixstrtod" (provided by Tcl) that corrects the error. # Also, on Compaq's Tru64 Unix 5.0, # strtod(" ") returns 0.0 instead of a failure to convert. # # Arguments: # none # # Results: # # Might defines some of the following vars: # strtod (=fixstrtod) #-------------------------------------------------------------------- AC_DEFUN([TEA_BUGGY_STRTOD], [ AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) if test "$tcl_strtod" = 1; then AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ AC_TRY_RUN([ extern double strtod(); int main() { char *infString="Inf", *nanString="NaN", *spaceString=" "; char *term; double value; value = strtod(infString, &term); if ((term != infString) && (term[-1] == 0)) { exit(1); } value = strtod(nanString, &term); if ((term != nanString) && (term[-1] == 0)) { exit(1); } value = strtod(spaceString, &term); if (term == (spaceString+1)) { exit(1); } exit(0); }], tcl_cv_strtod_buggy=ok, tcl_cv_strtod_buggy=buggy, tcl_cv_strtod_buggy=buggy)]) if test "$tcl_cv_strtod_buggy" = buggy; then AC_LIBOBJ([fixstrtod]) USE_COMPAT=1 AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) fi fi ]) #-------------------------------------------------------------------- # TEA_TCL_LINK_LIBS # # Search for the libraries needed to link the Tcl shell. # Things like the math library (-lm) and socket stuff (-lsocket vs. # -lnsl) are dealt with here. # # Arguments: # Requires the following vars to be set in the Makefile: # DL_LIBS (not in TEA, only needed in core) # LIBS # MATH_LIBS # # Results: # # Substitutes the following vars: # TCL_LIBS # MATH_LIBS # # Might append to the following vars: # LIBS # # Might define the following vars: # HAVE_NET_ERRNO_H #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_LINK_LIBS], [ #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) AC_CHECK_HEADER(net/errno.h, [ AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have ?])]) #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) if test "$tcl_checkSocket" = 1; then AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) fi AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, [LIBS="$LIBS -lnsl"])]) # TEA specific: Don't perform the eval of the libraries here because # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' AC_SUBST(TCL_LIBS) AC_SUBST(MATH_LIBS) ]) #-------------------------------------------------------------------- # TEA_TCL_EARLY_FLAGS # # Check for what flags are needed to be passed so the correct OS # features are available. # # Arguments: # None # # Results: # # Might define the following vars: # _ISOC99_SOURCE # _LARGEFILE64_SOURCE # _LARGEFILE_SOURCE64 #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_EARLY_FLAG],[ AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, AC_TRY_COMPILE([[#define ]$1[ 1 ]$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) tcl_flags="$tcl_flags $1" fi ]) AC_DEFUN([TEA_TCL_EARLY_FLAGS],[ AC_MSG_CHECKING([for required early compiler flags]) tcl_flags="" TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], [char *p = (char *)strtoll; char *q = (char *)strtoull;]) TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include ], [struct stat64 buf; int i = stat64("/", &buf);]) TEA_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include ], [char *p = (char *)open64;]) if test "x${tcl_flags}" = "x" ; then AC_MSG_RESULT([none]) else AC_MSG_RESULT([${tcl_flags}]) fi ]) #-------------------------------------------------------------------- # TEA_TCL_64BIT_FLAGS # # Check for what is defined in the way of 64-bit features. # # Arguments: # None # # Results: # # Might define the following vars: # TCL_WIDE_INT_IS_LONG # TCL_WIDE_INT_TYPE # HAVE_STRUCT_DIRENT64 # HAVE_STRUCT_STAT64 # HAVE_TYPE_OFF64_T #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_64BIT_FLAGS], [ AC_MSG_CHECKING([for 64-bit integer type]) AC_CACHE_VAL(tcl_cv_type_64bit,[ tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], tcl_type_64bit=__int64, tcl_type_64bit="long long") # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... AC_TRY_COMPILE(,[switch (0) { case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ; }],tcl_cv_type_64bit=${tcl_type_64bit})]) if test "${tcl_cv_type_64bit}" = none ; then AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?]) AC_MSG_RESULT([using long]) elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # TEA specific: We actually want to use the default tcl.h checks in # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* AC_MSG_RESULT([using Tcl header defaults]) else AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, [What type should be used to define wide integers?]) AC_MSG_RESULT([${tcl_cv_type_64bit}]) # Now check for auxiliary declarations AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ AC_TRY_COMPILE([#include #include ],[struct dirent64 p;], tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in ?]) fi AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ AC_TRY_COMPILE([#include ],[struct stat64 p; ], tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) if test "x${tcl_cv_struct_stat64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in ?]) fi AC_CHECK_FUNCS(open64 lseek64) AC_MSG_CHECKING([for off64_t]) AC_CACHE_VAL(tcl_cv_type_off64_t,[ AC_TRY_COMPILE([#include ],[off64_t offset; ], tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the dnl functions lseek64 and open64 are defined. if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi ]) ## ## Here ends the standard Tcl configuration bits and starts the ## TEA specific functions ## #------------------------------------------------------------------------ # TEA_INIT -- # # Init various Tcl Extension Architecture (TEA) variables. # This should be the first called TEA_* macro. # # Arguments: # none # # Results: # # Defines and substs the following vars: # CYGPATH # EXEEXT # Defines only: # TEA_VERSION # TEA_INITED # TEA_PLATFORM (windows or unix) # # "cygpath" is used on windows to generate native path names for include # files. These variables should only be used with the compiler and linker # since they generate native path names. # # EXEEXT # Select the executable extension based on the host type. This # is a lightweight replacement for AC_EXEEXT that doesn't require # a compiler. #------------------------------------------------------------------------ AC_DEFUN([TEA_INIT], [ # TEA extensions pass this us the version of TEA they think they # are compatible with. TEA_VERSION="3.10" AC_MSG_CHECKING([for correct TEA configuration]) if test x"${PACKAGE_NAME}" = x ; then AC_MSG_ERROR([ The PACKAGE_NAME variable must be defined by your TEA configure.ac]) fi if test x"$1" = x ; then AC_MSG_ERROR([ TEA version not specified.]) elif test "$1" != "${TEA_VERSION}" ; then AC_MSG_RESULT([warning: requested TEA version "$1", have "${TEA_VERSION}"]) else AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) fi # If the user did not set CFLAGS, set it now to keep macros # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi TEA_TK_EXTENSION=0 AC_SUBST(TEA_TK_EXTENSION) case "`uname -s`" in *win32*|*WIN32*|*MINGW32_*) AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *CYGWIN_*) EXEEXT=".exe" # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG ;; *) CYGPATH=echo # Maybe we are cross-compiling.... case ${host_alias} in *mingw32*) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *) EXEEXT="" TEA_PLATFORM="unix" ;; esac ;; esac # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi AC_MSG_NOTICE([configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}]) AC_SUBST(EXEEXT) AC_SUBST(CYGPATH) # This package name must be replaced statically for AC_SUBST to work AC_SUBST(PKG_LIB_FILE) AC_SUBST(PKG_LIB_FILE8) AC_SUBST(PKG_LIB_FILE9) # Substitute STUB_LIB_FILE in case package creates a stub library too. AC_SUBST(PKG_STUB_LIB_FILE) # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) AC_SUBST(PKG_TCL_SOURCES) AC_SUBST(PKG_HEADERS) AC_SUBST(PKG_INCLUDES) AC_SUBST(PKG_LIBS) AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_SOURCES # PKG_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_SOURCES], [ vars="$@" for i in $vars; do case $i in [\$]*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then AC_MSG_ERROR([could not find source file '$i']) fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done AC_SUBST(PKG_SOURCES) AC_SUBST(PKG_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_STUB_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_STUB_SOURCES # PKG_STUB_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_STUB_SOURCES], [ vars="$@" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then AC_MSG_ERROR([could not find stub source file '$i']) fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_TCL_SOURCES -- # # Specify one or more Tcl source files. These should be platform # independent runtime files. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_TCL_SOURCES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_TCL_SOURCES], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done AC_SUBST(PKG_TCL_SOURCES) ]) #------------------------------------------------------------------------ # TEA_ADD_HEADERS -- # # Specify one or more source headers. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_HEADERS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_HEADERS], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find header file '${srcdir}/$i']) fi PKG_HEADERS="$PKG_HEADERS $i" done AC_SUBST(PKG_HEADERS) ]) #------------------------------------------------------------------------ # TEA_ADD_INCLUDES -- # # Specify one or more include dirs. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_INCLUDES], [ vars="$@" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done AC_SUBST(PKG_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_ADD_LIBS -- # # Specify one or more libraries. Users should check for # the right platform before adding to their list. For Windows, # libraries provided in "foo.lib" format will be converted to # "-lfoo" when using GCC (mingw). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_LIBS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_LIBS], [ vars="$@" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.lib[$]/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done AC_SUBST(PKG_LIBS) ]) #------------------------------------------------------------------------ # TEA_ADD_CFLAGS -- # # Specify one or more CFLAGS. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_CFLAGS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CFLAGS], [ PKG_CFLAGS="$PKG_CFLAGS $@" AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_CLEANFILES -- # # Specify one or more CLEANFILES. # # Arguments: # one or more file names to clean target # # Results: # # Appends to CLEANFILES, already defined for subst in LOAD_TCLCONFIG #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CLEANFILES], [ CLEANFILES="$CLEANFILES $@" ]) #------------------------------------------------------------------------ # TEA_PREFIX -- # # Handle the --prefix=... option by defaulting to what Tcl gave # # Arguments: # none # # Results: # # If --prefix or --exec-prefix was not specified, $prefix and # $exec_prefix will be set to the values given to Tcl when it was # configured. #------------------------------------------------------------------------ AC_DEFUN([TEA_PREFIX], [ if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) prefix=${TCL_PREFIX} else AC_MSG_NOTICE([--prefix defaulting to /usr/local]) prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) exec_prefix=${TCL_EXEC_PREFIX} else AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) exec_prefix=$prefix fi fi ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER_CC -- # # Do compiler checks the way we want. This is just a replacement # for AC_PROG_CC in TEA configure.ac files to make them cleaner. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER_CC], [ # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. AC_PROG_CC AC_PROG_CPP INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c' INSTALL_DATA_DIR='${INSTALL} -d -m 755' INSTALL_DATA='${INSTALL} -m 644' INSTALL_PROGRAM='${INSTALL}' INSTALL_SCRIPT='${INSTALL}' INSTALL_LIBRARY='${INSTALL_DATA}' AC_SUBST(INSTALL) AC_SUBST(INSTALL_DATA_DIR) AC_SUBST(INSTALL_DATA) AC_SUBST(INSTALL_PROGRAM) AC_SUBST(INSTALL_SCRIPT) AC_SUBST(INSTALL_LIBRARY) #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- AC_PROG_MAKE_SET #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- AC_CHECK_TOOL(RANLIB, ranlib) #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- AC_OBJEXT AC_EXEEXT ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER -- # # Do compiler checks that use the compiler. This must go after # TEA_SETUP_COMPILER_CC, which does the actual compiler check. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER], [ # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. AC_REQUIRE([TEA_SETUP_COMPILER_CC]) #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then AC_CACHE_CHECK([if the compiler understands -pipe], tcl_cv_cc_pipe, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" AC_TRY_COMPILE(,, tcl_cv_cc_pipe=yes, tcl_cv_cc_pipe=no) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- AC_C_BIGENDIAN if test "${TEA_PLATFORM}" = "unix" ; then TEA_TCL_LINK_LIBS TEA_MISSING_POSIX_HEADERS # Let the user call this, because if it triggers, they will # need a compat/strtod.c that is correct. Users can also # use Tcl_GetDouble(FromObj) instead. #TEA_BUGGY_STRTOD fi ]) #------------------------------------------------------------------------ # TEA_MAKE_LIB -- # # Generate a line that can be used to build a shared/unshared library # in a platform independent manner. # # Arguments: # none # # Requires: # # Results: # # Defines the following vars: # CFLAGS - Done late here to note disturb other AC macros # MAKE_LIB - Command to execute to build the Tcl library; # differs depending on whether or not Tcl is being # compiled as a shared library. # MAKE_SHARED_LIB Makefile rule for building a shared library # MAKE_STATIC_LIB Makefile rule for building a static library # MAKE_STUB_LIB Makefile rule for building a stub library # VC_MANIFEST_EMBED_DLL Makefile rule for embedded VC manifest in DLL # VC_MANIFEST_EMBED_EXE Makefile rule for embedded VC manifest in EXE # # PRACTCL_TOOLSET What toolset is in use (gcc or msvc) # PRACTCL_SHARED_LIB Template rule for building a shared library # PRACTCL_STATIC_LIB Template rule for building a static library # PRACTCL_STUB_LIB Template rule for building a stub library # PRACTCL_VC_MANIFEST_EMBED_DLL Template rule for embedded VC manifest in DLL # PRACTCL_VC_MANIFEST_EMBED_EXE Template rule for embedded VC manifest in EXE # PRACTCL_NAME_LIBRARY Template rule for naming libraries # #------------------------------------------------------------------------ AC_DEFUN([TEA_MAKE_LIB], [ PRACTCL_TOOLSET="gcc" PRACTCL_VC_MANIFEST_EMBED_DLL=: PRACTCL_VC_MANIFEST_EMBED_EXE=: if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then PRACTCL_TOOLSET="msvc" PRACTCL_STATIC_LIB="%STLIB_LD% -out:%OUTFILE% %LIBRARY_OBJECTS%" PRACTCL_SHARED_LIB="%SHLIB_LD% %SHLIB_LD_LIBS% %LDFLAGS_DEFAULT% -out:%OUTFILE% %LIBRARY_OBJECTS%" MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS)" AC_EGREP_CPP([manifest needed], [ #if defined(_MSC_VER) && _MSC_VER >= 1400 print("manifest needed") #endif ], [ # Could do a CHECK_PROG for mt, but should always be with MSVC8+ PRACTCL_VC_MANIFEST_EMBED_DLL="mt.exe -nologo -manifest %OUTFILE%.manifest -outputresource:%OUTFILE%\;2" PRACTCL_VC_MANIFEST_EMBED_EXE="mt.exe -nologo -manifest %OUTFILE%.manifest -outputresource:%OUTFILE%\;1" VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;2 ; fi" VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;1 ; fi" MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" TEA_ADD_CLEANFILES([*.manifest]) ]) PRACTCL_STUB_LIB="%STLIB_LD% -nodefaultlib -out:%OUTFILE% %LIBRARY_OBJECTS%" MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\[$]@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" PRACTCL_STATIC_LIB="%STLIB_LD% %OUTFILE% %LIBRARY_OBJECTS%" PRACTCL_SHARED_LIB="%SHLIB_LD% -o %OUTFILE% %LIBRARY_OBJECTS% %SHLIB_LD_LIBS%" PRACTCL_STUB_LIB="%STLIB_LD% %OUTFILE% %LIBRARY_OBJECTS%" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}" PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9" if test "${TCL_MAJOR_VERSION}" -gt 8 ; then PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}" else PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}" fi if test "${TEA_PLATFORM}" = "windows" ; then PRACTCL_NAME_LIBRARY="%LIBRARY_PREFIX%%LIBRARY_NAME%%LIBRARY_VERSION_NODOTS%" if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test "$GCC" = "yes"; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc" fi eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_LIB_FILE=lib${PKG_LIB_FILE} fi fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else PRACTCL_NAME_LIBRARY="lib%LIBRARY_PREFIX%%LIBRARY_NAME%%LIBRARY_VERSION%" RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # Store the raw CFLAGS before we add the trimmings PRACTCL_CFLAGS=${CFLAGS} # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi AC_SUBST(MAKE_LIB) AC_SUBST(MAKE_SHARED_LIB) AC_SUBST(MAKE_STATIC_LIB) AC_SUBST(MAKE_STUB_LIB) AC_SUBST(RANLIB_STUB) AC_SUBST(VC_MANIFEST_EMBED_DLL) AC_SUBST(VC_MANIFEST_EMBED_EXE) AC_SUBST(PRACTCL_CFLAGS) AC_SUBST(PRACTCL_TOOLSET) AC_SUBST(PRACTCL_SHARED_LIB) AC_SUBST(PRACTCL_STATIC_LIB) AC_SUBST(PRACTCL_STUB_LIB) AC_SUBST(PRACTCL_VC_MANIFEST_EMBED_DLL) AC_SUBST(PRACTCL_VC_MANIFEST_EMBED_EXE) AC_SUBST(PRACTCL_NAME_LIBRARY) ]) #------------------------------------------------------------------------ # TEA_LIB_SPEC -- # # Compute the name of an existing object library located in libdir # from the given base name and produce the appropriate linker flags. # # Arguments: # basename The base name of the library without version # numbers, extensions, or "lib" prefixes. # extra_dir Extra directory in which to search for the # library. This location is used first, then # $prefix/$exec-prefix, then some defaults. # # Requires: # TEA_INIT and TEA_PREFIX must be called first. # # Results: # # Defines the following vars: # ${basename}_LIB_NAME The computed library name. # ${basename}_LIB_SPEC The computed linker flags. #------------------------------------------------------------------------ AC_DEFUN([TEA_LIB_SPEC], [ AC_MSG_CHECKING([for $1 library]) # Look in exec-prefix for the library (defined by TEA_PREFIX). tea_lib_name_dir="${exec_prefix}/lib" # Or in a user-specified location. if test x"$2" != x ; then tea_extra_lib_dir=$2 else tea_extra_lib_dir=NONE fi for i in \ `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib64/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib64/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do if test -f "$i" ; then tea_lib_name_dir=`dirname $i` $1_LIB_NAME=`basename $i` $1_LIB_PATH_NAME=$i break fi done if test "${TEA_PLATFORM}" = "windows"; then $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" else # Strip off the leading "lib" and trailing ".a" or ".so" tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" fi if test "x${$1_LIB_NAME}" = x ; then AC_MSG_ERROR([not found]) else AC_MSG_RESULT([${$1_LIB_SPEC}]) fi ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TCL_HEADERS -- # # Locate the private Tcl include files # # Arguments: # # Requires: # TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has # already been called. # # Results: # # Substitutes the following vars: # TCL_TOP_DIR_NATIVE # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [ # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} AC_REQUIRE([TEA_PUBLIC_TCL_HEADERS]) AC_MSG_CHECKING([for Tcl private include files]) TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" # Check to see if tclPort.h isn't already with the public headers # Don't look for tclInt.h because that resides with tcl.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tclh}/tclWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tclh}/tclUnixPort.h"; then result="private headers found with public headers" else TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" if test "${TEA_PLATFORM}" = "windows"; then TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" else TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TCL_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -d "${TCL_BIN_DIR}/Headers" -a \ -d "${TCL_BIN_DIR}/PrivateHeaders"; then TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" else TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TCL_INCLUDES}" else if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then AC_MSG_ERROR([Cannot find private header tclInt.h in ${TCL_SRC_DIR}]) fi result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" fi fi AC_SUBST(TCL_TOP_DIR_NATIVE) AC_SUBST(TCL_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TCL_HEADERS -- # # Locate the installed public Tcl header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tclinclude switch to configure. # Result is cached. # # Substitutes the following vars: # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [ AC_MSG_CHECKING([for Tcl public headers]) AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tclh, [ # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) fi else list="" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) else AC_MSG_RESULT([${ac_cv_c_tclh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TCL_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TK_HEADERS -- # # Locate the private Tk include files # # Arguments: # # Requires: # TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has # already been called. # # Results: # # Substitutes the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [ # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} AC_REQUIRE([TEA_PUBLIC_TK_HEADERS]) AC_MSG_CHECKING([for Tk private include files]) TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" # Check to see if tkPort.h isn't already with the public headers # Don't look for tkInt.h because that resides with tk.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tkh}/tkWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tkh}/tkUnixPort.h"; then result="private headers found with public headers" else TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" if test "${TEA_PLATFORM}" = "windows"; then TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" else TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TK_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" # Detect and add ttk subdir if test -d "${TK_SRC_DIR}/generic/ttk"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" fi if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_XLIB_DIR_NATIVE}\"" fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" fi if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TK_DEFS} in *TK_FRAMEWORK*) if test -d "${TK_BIN_DIR}/Headers" -a \ -d "${TK_BIN_DIR}/PrivateHeaders"; then TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" else TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TK_INCLUDES}" else if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then AC_MSG_ERROR([Cannot find private header tkInt.h in ${TK_SRC_DIR}]) fi result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" fi fi AC_SUBST(TK_TOP_DIR_NATIVE) AC_SUBST(TK_XLIB_DIR_NATIVE) AC_SUBST(TK_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TK_HEADERS -- # # Locate the installed public Tk header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tkinclude switch to configure. # Result is cached. # # Substitutes the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TK_HEADERS], [ AC_MSG_CHECKING([for Tk public headers]) AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files], with_tkinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tkh, [ # Use the value from --with-tkinclude, if it was given if test x"${with_tkinclude}" != x ; then if test -f "${with_tkinclude}/tk.h" ; then ac_cv_c_tkh=${with_tkinclude} else AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) fi else list="" if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers directory. case ${TK_DEFS} in *TK_FRAMEWORK*) list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tk is not installed, # and in that situation, look there before installed locations. if test -f "${TK_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tk's --prefix location, # relative to directory of tkConfig.sh, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TK_PREFIX}/include 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TK_INCLUDE_SPEC}" != x ; then d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tk.h" ; then ac_cv_c_tkh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tkh}" = x ; then AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) else AC_MSG_RESULT([${ac_cv_c_tkh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_INCLUDES) if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then # On Windows and Aqua, we need the X compat headers AC_MSG_CHECKING([for X11 header files]) if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_XINCLUDES) fi AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) fi ]) #------------------------------------------------------------------------ # TEA_PATH_CONFIG -- # # Locate the ${1}Config.sh file and perform a sanity check on # the ${1} compile flags. These are used by packages like # [incr Tk] that load *Config.sh files from more than Tcl and Tk. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-$1=... # # Defines the following vars: # $1_BIN_DIR Full path to the directory containing # the $1Config.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CONFIG], [ # # Ok, lets find the $1 configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-$1 # if test x"${no_$1}" = x ; then # we reset no_$1 in case something fails here no_$1=true AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) AC_MSG_CHECKING([for $1 configuration]) AC_CACHE_VAL(ac_cv_c_$1config,[ # First check to see if --with-$1 was specified. if test x"${with_$1config}" != x ; then case ${with_$1config} in */$1Config.sh ) if test -f ${with_$1config}; then AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` fi;; esac if test -f "${with_$1config}/$1Config.sh" ; then ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` else AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) fi fi # then check for a private $1 installation if test x"${ac_cv_c_$1config}" = x ; then for i in \ ../$1 \ `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../$1 \ `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../../$1 \ `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ${srcdir}/../$1 \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi if test -f "$i/unix/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i/unix; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_$1config}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_$1config}" = x ; then $1_BIN_DIR="# no $1 configs found" AC_MSG_WARN([Cannot find $1 configuration definitions]) exit 0 else no_$1= $1_BIN_DIR=${ac_cv_c_$1config} AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG -- # # Load the $1Config.sh file # # Arguments: # # Requires the following vars to be set: # $1_BIN_DIR # # Results: # # Substitutes the following vars: # $1_SRC_DIR # $1_LIB_FILE # $1_LIB_SPEC #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG], [ AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) if test -f "${$1_BIN_DIR}/$1Config.sh" ; then AC_MSG_RESULT([loading]) . "${$1_BIN_DIR}/$1Config.sh" else AC_MSG_RESULT([file not found]) fi # # If the $1_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable $1_LIB_SPEC will be set to the value # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC # instead of $1_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. # if test -f "${$1_BIN_DIR}/Makefile" ; then AC_MSG_WARN([Found Makefile - using build library specs for $1]) $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} $1_INCLUDE_SPEC=${$1_BUILD_INCLUDE_SPEC} $1_LIBRARY_PATH=${$1_LIBRARY_PATH} fi AC_SUBST($1_VERSION) AC_SUBST($1_BIN_DIR) AC_SUBST($1_SRC_DIR) AC_SUBST($1_LIB_FILE) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_STUB_LIB_FILE) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_PATH) # Allow the caller to prevent this auto-check by specifying any 2nd arg AS_IF([test "x$2" = x], [ # Check both upper and lower-case variants # If a dev wanted non-stubs libs, this function could take an option # to not use _STUB in the paths below AS_IF([test "x${$1_STUB_LIB_SPEC}" = x], [TEA_LOAD_CONFIG_LIB(translit($1,[a-z],[A-Z])_STUB)], [TEA_LOAD_CONFIG_LIB($1_STUB)]) ]) ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG_LIB -- # # Helper function to load correct library from another extension's # ${PACKAGE}Config.sh. # # Results: # Adds to LIBS the appropriate extension library #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG_LIB], [ AC_MSG_CHECKING([For $1 library for LIBS]) # This simplifies the use of stub libraries by automatically adding # the stub lib to your path. Normally this would add to SHLIB_LD_LIBS, # but this is called before CONFIG_CFLAGS. More importantly, this adds # to PKG_LIBS, which becomes LIBS, and that is only used by SHLIB_LD. if test "x${$1_LIB_SPEC}" != "x" ; then if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes" ; then TEA_ADD_LIBS([\"`${CYGPATH} ${$1_LIB_PATH}`\"]) AC_MSG_RESULT([using $1_LIB_PATH ${$1_LIB_PATH}]) else TEA_ADD_LIBS([${$1_LIB_SPEC}]) AC_MSG_RESULT([using $1_LIB_SPEC ${$1_LIB_SPEC}]) fi else AC_MSG_RESULT([file not found]) fi ]) #------------------------------------------------------------------------ # TEA_EXPORT_CONFIG -- # # Define the data to insert into the ${PACKAGE}Config.sh file # # Arguments: # # Requires the following vars to be set: # $1 # # Results: # Substitutes the following vars: #------------------------------------------------------------------------ AC_DEFUN([TEA_EXPORT_CONFIG], [ #-------------------------------------------------------------------- # These are for $1Config.sh #-------------------------------------------------------------------- # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib) eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}" if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}${DBGX}" eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}${DBGX}" else eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" fi $1_BUILD_LIB_SPEC="-L`$CYGPATH $(pwd)` ${$1_LIB_FLAG}" $1_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` ${$1_LIB_FLAG}" $1_BUILD_STUB_LIB_SPEC="-L`$CYGPATH $(pwd)` [$]{$1_STUB_LIB_FLAG}" $1_STUB_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` [$]{$1_STUB_LIB_FLAG}" $1_BUILD_STUB_LIB_PATH="`$CYGPATH $(pwd)`/[$]{PKG_STUB_LIB_FILE}" $1_STUB_LIB_PATH="`$CYGPATH ${pkglibdir}`/[$]{PKG_STUB_LIB_FILE}" AC_SUBST($1_BUILD_LIB_SPEC) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_PATH) AC_SUBST($1_STUB_LIB_PATH) AC_SUBST(MAJOR_VERSION) AC_SUBST(MINOR_VERSION) AC_SUBST(PATCHLEVEL) ]) #------------------------------------------------------------------------ # TEA_PATH_CELIB -- # # Locate Keuchel's celib emulation layer for targeting Win/CE # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-celib=... # # Defines the following vars: # CELIB_DIR Full path to the directory containing # the include and platform lib files #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CELIB], [ # First, look for one uninstalled. # the alternative search directory is invoked by --with-celib if test x"${no_celib}" = x ; then # we reset no_celib in case something fails here no_celib=true AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], with_celibconfig=${withval}) AC_MSG_CHECKING([for Windows/CE celib directory]) AC_CACHE_VAL(ac_cv_c_celibconfig,[ # First check to see if --with-celibconfig was specified. if test x"${with_celibconfig}" != x ; then if test -d "${with_celibconfig}/inc" ; then ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` else AC_MSG_ERROR([${with_celibconfig} directory doesn't contain inc directory]) fi fi # then check for a celib library if test x"${ac_cv_c_celibconfig}" = x ; then for i in \ ../celib-palm-3.0 \ ../celib \ ../../celib-palm-3.0 \ ../../celib \ `ls -dr ../celib-*3.[[0-9]]* 2>/dev/null` \ ${srcdir}/../celib-palm-3.0 \ ${srcdir}/../celib \ `ls -dr ${srcdir}/../celib-*3.[[0-9]]* 2>/dev/null` \ ; do if test -d "$i/inc" ; then ac_cv_c_celibconfig=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_celibconfig}" = x ; then AC_MSG_ERROR([Cannot find celib support library directory]) else no_celib= CELIB_DIR=${ac_cv_c_celibconfig} CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` AC_MSG_RESULT([found $CELIB_DIR]) fi fi ]) #-------------------------------------------------------------------- # TEA_CONFIG_TEAPOT # # Try to determine the canonical name for this package's binary # target # # Arguments: # none AC_DEFUN([TEA_CONFIG_TEAPOT], [ TEACUP_OS=$system TEACUP_ARCH="unknown" TEACUP_TOOLSET="gcc" TEACUP_PROFILE="unknown" arch="unknown" if test "${TEA_PLATFORM}" = "windows" ; then if test "$GCC" = "yes" ; then TEACUP_TOOLSET="gcc" else TEACUP_TOOLSET="msvc" fi if test "$do64bit" != "no" ; then case "$do64bit" in amd64|x64|yes) arch="x86_64" TEACUP_PROFILE="win32-x86_64" ;; ia64) arch="ia64" TEACUP_PROFILE="win32-ia64" ;; esac else arch="ix86" TEACUP_PROFILE="win32-ix86" fi else case $system in Linux*) TEACUP_OS="linux" arch=`uname -m` TEACUP_PROFILE="linux-glibc2.3-$arch" ;; GNU*) TEACUP_OS="gnu" arch=`uname -m` ;; NetBSD-Debian) TEACUP_OS="netbsd-debian" arch=`uname -m` ;; OpenBSD-*) TEACUP_OS="openbsd" arch=`arch -s` ;; Darwin*) TEACUP_OS="macosx" TEACUP_PROFILE="macosx-universal" arch=`uname -m` if test $arch = "x86_64"; then TEACUP_PROFILE="macosx10.5-i386-x86_84" fi ;; OpenBSD*) TEACUP_OS="openbsd" arch=`arch -s` ;; esac fi TEACUP_ARCH=$arch if test "$TEACUP_PROFILE" = "unknown"; then if test $arch = "unknown"; then arch=`uname -m` fi case $arch in i*86) arch="ix86" ;; amd64) arch="x86_64" ;; esac TEACUP_PROFILE="$TEACUP_OS-$arch" fi TEA_SYSTEM=$system AC_SUBST(TEA_SYSTEM) AC_SUBST(TEA_PLATFORM) AC_SUBST(TEA_WINDOWINGSYSTEM) AC_SUBST(TEACUP_OS) AC_SUBST(TEACUP_ARCH) AC_SUBST(TEACUP_TOOLSET) AC_SUBST(TEACUP_PROFILE) ]) # Local Variables: # mode: autoconf # End: ./nsf2.4.0/m4/tcl.m4-gn000644 000766 000024 00000427643 14270747021 015162 0ustar00neumannstaff000000 000000 # tcl.m4 -- # # This file provides a set of autoconf macros to help TEA-enable # a Tcl extension. # # Copyright (c) 1999-2000 Ajuba Solutions. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. AC_PREREQ(2.57) dnl TEA extensions pass us the version of TEA they think they dnl are compatible with (must be set in TEA_INIT below) dnl TEA_VERSION="3.10" # Possible values for key variables defined: # # TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') # TEA_PLATFORM - windows unix # TEA_TK_EXTENSION - True if this is a Tk extension # TEACUP_OS - windows macosx linux generic # TEACUP_TOOLSET - Toolset in use (gcc,mingw,msvc,llvm) # TEACUP_PROFILE - win32 # #------------------------------------------------------------------------ # TEA_PATH_TCLCONFIG -- # # Locate the tclConfig.sh file and perform a sanity check on # the Tcl compile flags # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tcl=... # # Defines the following vars: # TCL_BIN_DIR Full path to the directory containing # the tclConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TCLCONFIG], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true AC_ARG_WITH(tcl, AS_HELP_STRING([--with-tcl], [directory containing tcl configuration (tclConfig.sh)]), with_tclconfig="${withval}") AC_MSG_CHECKING([for Tcl configuration]) AC_CACHE_VAL(ac_cv_c_tclconfig,[ # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case "${with_tclconfig}" in */tclConfig.sh ) if test -f "${with_tclconfig}"; then AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" else AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/pkg/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ `ls -d /usr/lib/tcl8.6 2>/dev/null` \ `ls -d /usr/lib/tcl8.5 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" AC_MSG_ERROR([Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh]) else no_tcl= TCL_BIN_DIR="${ac_cv_c_tclconfig}" AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_PATH_TKCONFIG -- # # Locate the tkConfig.sh file # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tk=... # # Defines the following vars: # TK_BIN_DIR Full path to the directory containing # the tkConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TKCONFIG], [ # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true TEA_TK_EXTENSION=0 AC_ARG_WITH(tk, AS_HELP_STRING([--with-tk], [directory containing tk configuration (tkConfig.sh)]), with_tkconfig="${withval}") AC_MSG_CHECKING([for Tk configuration]) AC_CACHE_VAL(ac_cv_c_tkconfig,[ # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case "${with_tkconfig}" in */tkConfig.sh ) if test -f "${with_tkconfig}"; then AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" else AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" AC_MSG_ERROR([Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh]) else no_tk= TEA_TK_EXTENSION=1 TK_BIN_DIR="${ac_cv_c_tkconfig}" AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_TCLCONFIG -- # # Load the tclConfig.sh file # # Arguments: # # Requires the following vars to be set: # TCL_BIN_DIR # # Results: # # Substitutes the following vars: # TCL_BIN_DIR # TCL_SRC_DIR # TCL_LIB_FILE #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TCLCONFIG], [ AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TCL_BIN_DIR}/tclConfig.sh" else AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitrary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" break fi done fi if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" AC_SUBST(TCL_VERSION) AC_SUBST(TCL_PATCH_LEVEL) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) AC_MSG_CHECKING([platform]) hold_cc=$CC; CC="$TCL_CC" AC_TRY_COMPILE(,[ #ifdef _WIN32 #error win32 #endif ], [ TEA_PLATFORM="unix" CYGPATH=echo ], [ TEA_PLATFORM="windows" AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) ] ) CC=$hold_cc AC_MSG_RESULT($TEA_PLATFORM) # The BUILD_$pkg is to define the correct extern storage class # handling when making this package AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME}, [], [Building extension source?]) # Do this here as we have fully defined TEA_PLATFORM now if test "${TEA_PLATFORM}" = "windows" ; then EXEEXT=".exe" CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp" fi # TEA specific: AC_SUBST(CLEANFILES) AC_SUBST(TCL_LIBS) AC_SUBST(TCL_DEFS) AC_SUBST(TCL_EXTRA_CFLAGS) AC_SUBST(TCL_LD_FLAGS) AC_SUBST(TCL_SHLIB_LD_LIBS) ]) #------------------------------------------------------------------------ # TEA_LOAD_TKCONFIG -- # # Load the tkConfig.sh file # # Arguments: # # Requires the following vars to be set: # TK_BIN_DIR # # Results: # # Sets the following vars that should be in tkConfig.sh: # TK_BIN_DIR #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TKCONFIG], [ AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TK_BIN_DIR}/tkConfig.sh" else AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TK_BIN_DIR}/Makefile" ; then TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tk.framework installed in an arbitrary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then for i in "`cd "${TK_BIN_DIR}"; pwd`" \ "`cd "${TK_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" break fi done fi if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" # TEA specific: Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) TEA_WINDOWINGSYSTEM="aqua" ;; *) TEA_WINDOWINGSYSTEM="x11" ;; esac elif test "${TEA_PLATFORM}" = "windows" ; then TEA_WINDOWINGSYSTEM="win32" fi AC_SUBST(TK_VERSION) AC_SUBST(TK_BIN_DIR) AC_SUBST(TK_SRC_DIR) AC_SUBST(TK_LIB_FILE) AC_SUBST(TK_LIB_FLAG) AC_SUBST(TK_LIB_SPEC) AC_SUBST(TK_STUB_LIB_FILE) AC_SUBST(TK_STUB_LIB_FLAG) AC_SUBST(TK_STUB_LIB_SPEC) # TEA specific: AC_SUBST(TK_LIBS) AC_SUBST(TK_XINCLUDES) ]) #------------------------------------------------------------------------ # TEA_PROG_TCLSH # Determine the fully qualified path name of the tclsh executable # in the Tcl build directory or the tclsh installed in a bin # directory. This macro will correctly determine the name # of the tclsh executable even if tclsh has not yet been # built in the build directory. The tclsh found is always # associated with a tclConfig.sh file. This tclsh should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments: # none # # Results: # Substitutes the following vars: # TCLSH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_TCLSH], [ AC_MSG_CHECKING([for tclsh]) AC_ARG_WITH(tclsh, [ --with-tclsh Specify a local tcl shell to use for dynamic code], with_tclsh=${withval}) # Use the value from --with-tclsh, if it was given TCLSH_PROG=0 if test x"${with_tclsh}" != x ; then if test -f "${with_tclsh}" ; then TCLSH_PROG=${with_tclsh} else if test -f "${with_tclsh}/tcl8.6" ; then TCLSH_PROG="${with_tclsh}/tcl8.6" else if test -f "${with_tclsh}/tclsh86.exe" ; then TCLSH_PROG="${with_tclsh}/tclsh86.exe" else AC_MSG_ERROR([${with_tclsh} does not point to a valid Tcl executable]) fi fi fi else if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" fi else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" fi fi AC_MSG_RESULT([${TCLSH_PROG}]) AC_SUBST(TCLSH_PROG) ]) #------------------------------------------------------------------------ # TEA_PROG_WISH # Determine the fully qualified path name of the wish executable # in the Tk build directory or the wish installed in a bin # directory. This macro will correctly determine the name # of the wish executable even if wish has not yet been # built in the build directory. The wish found is always # associated with a tkConfig.sh file. This wish should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments: # none # # Results: # Substitutes the following vars: # WISH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_WISH], [ AC_MSG_CHECKING([for wish]) if test -f "${TK_BIN_DIR}/Makefile" ; then # tkConfig.sh is in Tk build directory if test "${TEA_PLATFORM}" = "windows"; then if test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}s${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}$s{EXEEXT}" elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}t${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}t${EXEEXT}" elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}st${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}st${EXEEXT}" fi else WISH_PROG="${TK_BIN_DIR}/wish" fi else # tkConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" fi list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TK_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${WISH_PROG}" ; then REAL_TK_BIN_DIR="`cd "$i"; pwd`/" break fi done WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" fi AC_MSG_RESULT([${WISH_PROG}]) AC_SUBST(WISH_PROG) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SHARED -- # # Allows the building of shared libraries # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-shared=yes|no # --enable-stubs=yes|no # # Defines the following vars: # STATIC_BUILD Used for building import/export libraries # on Windows. # # Sets the following vars: # SHARED_BUILD Value of 1 or 0 # STUBS_BUILD Value if 1 or 0 # USE_TCL_STUBS Value true: if SHARED_BUILD or --enable-stubs # USE_TCLOO_STUBS Value true: if SHARED_BUILD or --enable-stubs # USE_TK_STUBS Value true: if SHARED_BUILD or --enable-stubs # AND TEA_WINDOWING_SYSTEM != "" #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SHARED], [ AC_MSG_CHECKING([how to build libraries]) AC_ARG_ENABLE(shared, AS_HELP_STRING([--enable-shared], [build and link with shared libraries (default: on)]), [shared_ok=$enableval], [shared_ok=yes]) if test "${enable_shared+set}" = set; then enableval="$enable_shared" shared_ok=$enableval else shared_ok=yes fi AC_ARG_ENABLE(stubs, AS_HELP_STRING([--enable-stubs], [build and link with stub libraries. Always true for shared builds (default: on)]), [stubs_ok=$enableval], [stubs_ok=yes]) if test "${enable_stubs+set}" = set; then enableval="$enable_stubs" stubs_ok=$enableval else stubs_ok=yes fi # Stubs are always enabled for shared builds if test "$shared_ok" = "yes" ; then AC_MSG_RESULT([shared]) SHARED_BUILD=1 STUBS_BUILD=1 else AC_MSG_RESULT([static]) SHARED_BUILD=0 AC_DEFINE(STATIC_BUILD, 1, [This a static build]) if test "$stubs_ok" = "yes" ; then STUBS_BUILD=1 else STUBS_BUILD=0 fi fi if test "${STUBS_BUILD}" = "1" ; then AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) AC_DEFINE(USE_TCLOO_STUBS, 1, [Use TclOO stubs]) if test "${TEA_WINDOWINGSYSTEM}" != ""; then AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) fi fi AC_SUBST(SHARED_BUILD) AC_SUBST(STUBS_BUILD) ]) #------------------------------------------------------------------------ # TEA_ENABLE_THREADS -- # # Specify if thread support should be enabled. If "yes" is specified # as an arg (optional), threads are enabled by default, "no" means # threads are disabled. "yes" is the default. # # TCL_THREADS is checked so that if you are compiling an extension # against a threaded core, your extension must be compiled threaded # as well. # # Note that it is legal to have a thread enabled extension run in a # threaded or non-threaded Tcl core, but a non-threaded extension may # only run in a non-threaded Tcl core. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-threads # # Sets the following vars: # THREADS_LIBS Thread library(s) # # Defines the following vars: # TCL_THREADS # _REENTRANT # _THREAD_SAFE #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_THREADS], [ AC_ARG_ENABLE(threads, AS_HELP_STRING([--enable-threads], [build with threads]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention AC_DEFINE(USE_THREAD_ALLOC, 1, [Do we want to use the threaded memory allocator?]) AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) if test "`uname -s`" = "SunOS" ; then AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) fi AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] AC_CHECK_LIB(pthread, __pthread_mutex_init, tcl_ok=yes, tcl_ok=no) fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else AC_CHECK_LIB(pthreads, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else AC_CHECK_LIB(c, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "no"; then AC_CHECK_LIB(c_r, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 AC_MSG_WARN([Do not know how to find pthread lib on your system - thread support disabled]) fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output AC_MSG_CHECKING([for building with threads]) if test "${TCL_THREADS}" = 1; then AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) AC_MSG_RESULT([yes (default)]) else AC_MSG_RESULT([no]) fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then AC_MSG_WARN([ Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads.]) fi ;; *) if test "${TCL_THREADS}" = "1"; then AC_MSG_WARN([ --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core.]) fi ;; esac AC_SUBST(TCL_THREADS) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SYMBOLS -- # # Specify if debugging symbols should be used. # Memory (TCL_MEM_DEBUG) debugging can also be enabled. # # Arguments: # none # # TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives # the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted. # Requires the following vars to be set in the Makefile: # CFLAGS_DEFAULT # LDFLAGS_DEFAULT # # Results: # # Adds the following arguments to configure: # --enable-symbols # # Defines the following vars: # CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true # Sets to "$(CFLAGS_OPTIMIZE) -DNDEBUG" if false # LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true # Sets to $(LDFLAGS_OPTIMIZE) if false # DBGX Formerly used as debug library extension; # always blank now. #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SYMBOLS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_CONFIG_CFLAGS]) AC_MSG_CHECKING([for build with symbols]) AC_ARG_ENABLE(symbols, AS_HELP_STRING([--enable-symbols], [build with debugging symbols (default: off)]), [tcl_ok=$enableval], [tcl_ok=no]) DBGX="" if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" AC_MSG_RESULT([no]) else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then AC_MSG_RESULT([yes (standard debugging)]) fi fi # TEA specific: if test "${TEA_PLATFORM}" != "windows" ; then LDFLAGS_DEFAULT="${LDFLAGS}" fi AC_SUBST(CFLAGS_DEFAULT) AC_SUBST(LDFLAGS_DEFAULT) AC_SUBST(TCL_DBGX) if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then AC_MSG_RESULT([enabled symbols mem debugging]) else AC_MSG_RESULT([enabled $tcl_ok debugging]) fi fi ]) #------------------------------------------------------------------------ # TEA_ENABLE_LANGINFO -- # # Allows use of modern nl_langinfo check for better l10n. # This is only relevant for Unix. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-langinfo=yes|no (default is yes) # # Defines the following vars: # HAVE_LANGINFO Triggers use of nl_langinfo if defined. #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_LANGINFO], [ AC_ARG_ENABLE(langinfo, AS_HELP_STRING([--enable-langinfo], [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), [langinfo_ok=$enableval], [langinfo_ok=yes]) HAVE_LANGINFO=0 if test "$langinfo_ok" = "yes"; then AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) fi AC_MSG_CHECKING([whether to use nl_langinfo]) if test "$langinfo_ok" = "yes"; then AC_CACHE_VAL(tcl_cv_langinfo_h, [ AC_TRY_COMPILE([#include ], [nl_langinfo(CODESET);], [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) AC_MSG_RESULT([$tcl_cv_langinfo_h]) if test $tcl_cv_langinfo_h = yes; then AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) fi else AC_MSG_RESULT([$langinfo_ok]) fi ]) #-------------------------------------------------------------------- # TEA_CONFIG_SYSTEM # # Determine what the system is (some things cannot be easily checked # on a feature-driven basis, alas). This can usually be done via the # "uname" command. # # Arguments: # none # # Results: # Defines the following var: # # system - System/platform/version identification code. #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_SYSTEM], [ AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then AC_MSG_WARN([can't find uname command]) tcl_cv_sys_version=unknown else if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi ]) system=$tcl_cv_sys_version ]) #-------------------------------------------------------------------- # TEA_CONFIG_CFLAGS # # Try to determine the proper flags to pass to the compiler # for building shared libraries and other such nonsense. # # Arguments: # none # # Results: # # Defines and substitutes the following vars: # # DL_OBJS, DL_LIBS - removed for TEA, only needed by core. # LDFLAGS - Flags to pass to the compiler when linking object # files into an executable application binary such # as tclsh. # LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. Could # be the same as CC_SEARCH_FLAGS if ${CC} is used to link. # CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. # SHLIB_CFLAGS - Flags to pass to cc when compiling the components # of a shared library (may request position-independent # code, among other things). # SHLIB_LD - Base command to use for combining object files # into a shared library. # SHLIB_LD_LIBS - Dependent libraries for the linker to scan when # creating shared libraries. This symbol typically # goes at the end of the "ld" commands that build # shared libraries. The value of the symbol defaults to # "${LIBS}" if all of the dependent libraries should # be specified when creating a shared library. If # dependent libraries should not be specified (as on # SunOS 4.x, where they cause the link to fail, or in # general if Tcl and Tk aren't themselves shared # libraries), then this symbol has an empty string # as its value. # SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable # extensions. An empty string means we don't know how # to use shared libraries on this platform. # LIB_SUFFIX - Specifies everything that comes after the "libfoo" # in a static or shared library name, using the $PACKAGE_VERSION variable # to put the version in the right place. This is used # by platforms that need non-standard library names. # Examples: ${PACKAGE_VERSION}.so.1.1 on NetBSD, since it needs # to have a version after the .so, and ${PACKAGE_VERSION}.a # on AIX, since a shared library needs to have # a .a extension whereas shared objects for loadable # extensions have a .so extension. Defaults to # ${PACKAGE_VERSION}${SHLIB_SUFFIX}. # CFLAGS_DEBUG - # Flags used when running the compiler in debug mode # CFLAGS_OPTIMIZE - # Flags used when running the compiler in optimize mode # CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_CFLAGS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # Step 0.a: Enable 64 bit support? AC_MSG_CHECKING([if 64bit support is requested]) AC_ARG_ENABLE(64bit, AS_HELP_STRING([--enable-64bit], [enable 64bit support (default: off)]), [do64bit=$enableval], [do64bit=no]) AC_MSG_RESULT([$do64bit]) # Step 0.b: Enable Solaris 64 bit VIS support? AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) AC_ARG_ENABLE(64bit-vis, AS_HELP_STRING([--enable-64bit-vis], [enable 64bit Sparc VIS support (default: off)]), [do64bitVIS=$enableval], [do64bitVIS=no]) AC_MSG_RESULT([$do64bitVIS]) # Force 64bit on with VIS AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) # Step 0.c: Check if visibility support is available. Do this here so # that platform specific alternatives can be used below if this fails. AC_CACHE_CHECK([if compiler supports visibility "hidden"], tcl_cv_cc_visibility_hidden, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" AC_TRY_LINK([ extern __attribute__((__visibility__("hidden"))) void f(void); void f(void) {}], [f();], tcl_cv_cc_visibility_hidden=yes, tcl_cv_cc_visibility_hidden=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ AC_DEFINE(MODULE_SCOPE, [extern __attribute__((__visibility__("hidden")))], [Compiler support for module scope symbols]) AC_DEFINE(HAVE_HIDDEN, [1], [Compiler support for module scope symbols]) ]) # Step 0.d: Disable -rpath support? AC_MSG_CHECKING([if rpath support is requested]) AC_ARG_ENABLE(rpath, AS_HELP_STRING([--disable-rpath], [disable rpath support (default: on)]), [doRpath=$enableval], [doRpath=yes]) AC_MSG_RESULT([$doRpath]) # TEA specific: Cross-compiling options for Windows/CE builds? AS_IF([test "${TEA_PLATFORM}" = windows], [ AC_MSG_CHECKING([if Windows/CE build is requested]) AC_ARG_ENABLE(wince, AS_HELP_STRING([--enable-wince], [enable Win/CE support (where applicable)]), [doWince=$enableval], [doWince=no]) AC_MSG_RESULT([$doWince]) ]) # Set the variable "system" to hold the name and version number # for the system. TEA_CONFIG_SYSTEM # Require ranlib early so we can override it in special cases below. AC_REQUIRE([AC_PROG_RANLIB]) # Set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case and removed some core-only vars. do64bit_ok=no # default to '{$LIBS}' and set to "" on per-platform necessary basis SHLIB_LD_LIBS='${LIBS}' # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" UNSHARED_LIB_SUFFIX="" # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g AS_IF([test "$GCC" = yes], [ CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall" ], [ CFLAGS_OPTIMIZE=-O CFLAGS_WARNING="" ]) AC_CHECK_TOOL(AR, ar) STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION=""],[SHLIB_VERSION=".$SHLIB_VERSION"]) case $system in # TEA specific: windows) # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test "$GCC" != "yes" -a ! -d "${PATH64}" ; then AC_MSG_WARN([Could not find 64-bit $MACHINE SDK to enable 64bit mode]) AC_MSG_WARN([Ensure latest Platform SDK is installed]) do64bit="no" else AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) do64bit_ok="yes" fi fi if test "$doWince" != "no" ; then if test "$do64bit" != "no" ; then AC_MSG_ERROR([Windows/CE and 64-bit builds incompatible]) fi if test "$GCC" = "yes" ; then AC_MSG_ERROR([Windows/CE and GCC builds incompatible]) fi TEA_PATH_CELIB # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F, '{ \ if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \ if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \ if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \ if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]]) doWince="no" else # We could PATH_NOSPACE these, but that's not important, # as long as we quote them when used. CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi case "x`echo \${VisualStudioVersion}`" in x1[[4-9]]*) lflags="${lflags} -nodefaultlib:libucrt.lib" TEA_ADD_LIBS([ucrt.lib]) ;; *) ;; esac if test "$do64bit" != "no" ; then # All this magic is necessary for the Win64 SDK RC1 - hobbs CC="\"${PATH64}/cl.exe\"" CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" lflags="${lflags} -nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 TEA_ADD_LIBS([bufferoverflowU.lib]) elif test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="\"${CEBINROOT}/cl.exe\"" else CC="\"${CEBINROOT}/cl${ARCH}.exe\"" fi CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower([$]0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" if test "${SHARED_BUILD}" = "1" ; then # Static CE builds require static celib as well defs="${defs} _DLL" fi for i in $defs ; do AC_DEFINE_UNQUOTED($i, 1, [WinCE def ]$i) done AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION, [_WIN32_WCE version]) AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION, [UNDER_CE version]) CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -Ox" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="${lflags} -MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" AC_SUBST(CELIB_DIR) else RC="rc" lflags="${lflags} -nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode AC_CHECK_TOOL(RC, windres) CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD='${CC} -shared' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' PRACTCL_UNSHARED_LIB_SUFFIX='.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" AC_CACHE_CHECK(for cross-compile version of gcc, ac_cv_cross, AC_TRY_COMPILE([ #ifdef _WIN32 #error cross-compiler #endif ], [], ac_cv_cross=yes, ac_cv_cross=no) ) if test "$ac_cv_cross" = "yes"; then case "$do64bit" in amd64|x64|yes) CC="x86_64-w64-mingw32-gcc" LD="x86_64-w64-mingw32-ld" AR="x86_64-w64-mingw32-ar" RANLIB="x86_64-w64-mingw32-ranlib" RC="x86_64-w64-mingw32-windres" ;; *) CC="i686-w64-mingw32-gcc" LD="i686-w64-mingw32-ld" AR="i686-w64-mingw32-ar" RANLIB="i686-w64-mingw32-ranlib" RC="i686-w64-mingw32-windres" ;; esac fi else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" if test "$doWince" != "no" ; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots ;; AIX-*) AS_IF([test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"], [ # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r|*_r\ *) # ok ... ;; *) # Make sure only first arg gets _r CC=`echo "$CC" | sed -e 's/^\([[^ ]]*\)/\1_r/'` ;; esac AC_MSG_RESULT([Using $CC for compiling with threads]) ]) LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_SUFFIX=".so" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported with GCC on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" ]) ]) AS_IF([test "`uname -m`" = ia64], [ # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" AS_IF([test "$GCC" = yes], [ CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' ], [ CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' ]) LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ], [ AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared -Wl,-bexpall' ], [ SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" LDFLAGS="$LDFLAGS -brtl" ]) SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_SUFFIX=".so" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; CYGWIN_*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$[@].a" SHLIB_SUFFIX=".dll" EXEEXT=".exe" do64bit_ok=yes CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"]) ;; HP-UX-*.11.*) # Use updated header definitions where possible AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) # TEA specific: Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library AS_IF([test "`uname -m`" = ia64], [ SHLIB_SUFFIX=".so" # Use newer C++ library for C++ extensions #if test "$GCC" != "yes" ; then # CPPFLAGS="-AA" #fi ], [ SHLIB_SUFFIX=".sl" ]) AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) AS_IF([test "$tcl_ok" = yes], [ LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" ]) AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ CFLAGS="$CFLAGS -z" # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" ]) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = "yes"], [ AS_IF([test "$GCC" = yes], [ case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]) ;; esac ], [ do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" ]) ]) ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [ CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" ], [ case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" ]) ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported by gcc]) ], [ do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" ]) ]) ;; Linux*|GNU*|NetBSD-Debian) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) AS_IF([test $do64bit = yes], [ AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_m64 = yes], [ CFLAGS="$CFLAGS -m64" do64bit_ok=yes ]) ]) # The combo of gcc + glibc has a bug related to inlining of # functions like strtod(). The -fno-builtin flag should address # this problem but it does not work. The -fno-inline flag is kind # of overkill but it works. Disable inlining only when one of the # files in compat/*.c is being linked in. AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"]) ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' LD_FLAGS="-Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) ;; OpenBSD-*) arch=`arch -s` case "$arch" in vax) SHLIB_SUFFIX="" SHARED_LIB_SUFFIX="" LDFLAGS="" ;; *) case "$arch" in alpha|sparc64) SHLIB_CFLAGS="-fPIC" ;; *) SHLIB_CFLAGS="-fpic" ;; esac SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}' LDFLAGS="-Wl,-export-dynamic" ;; esac case "$arch" in vax) CFLAGS_OPTIMIZE="-O1" ;; *) CFLAGS_OPTIMIZE="-O2" ;; esac AS_IF([test "${TCL_THREADS}" = "1"], [ # On OpenBSD: Compile with -pthread # Don't link with -lpthread LIBS=`echo $LIBS | sed s/-lpthread//` CFLAGS="$CFLAGS -pthread" ]) # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*) # NetBSD has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) ;; FreeBSD-*) # This configuration from FreeBSD Ports. SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,-soname,\$[@]" SHLIB_SUFFIX=".so" LDFLAGS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the LDFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LDFLAGS="$LDFLAGS $PTHREAD_LIBS"]) case $system in FreeBSD-3.*) # Version numbers are dot-stripped by system policy. TCL_TRIM_DOTS=`echo ${PACKAGE_VERSION} | tr -d .` UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" AS_IF([test $do64bit = yes], [ case `arch` in ppc) AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], tcl_cv_cc_arch_ppc64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" AC_TRY_LINK(,, tcl_cv_cc_arch_ppc64=yes, tcl_cv_cc_arch_ppc64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes ]);; i386) AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], tcl_cv_cc_arch_x86_64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" AC_TRY_LINK(,, tcl_cv_cc_arch_x86_64=yes, tcl_cv_cc_arch_x86_64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes ]);; *) AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; esac ], [ # Check for combined 32-bit and 64-bit fat build AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ fat_32_64=yes]) ]) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_single_module = yes], [ SHLIB_LD="${SHLIB_LD} -Wl,-single_module" ]) # TEA specific: link shlib with current and compatibility version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" SHLIB_SUFFIX=".dylib" # Don't use -prebind when building for Mac OS X 10.4 or later only: AS_IF([test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \ "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4], [ LDFLAGS="$LDFLAGS -prebind"]) LDFLAGS="$LDFLAGS -headerpad_max_install_names" AC_CACHE_CHECK([if ld accepts -search_paths_first flag], tcl_cv_ld_search_paths_first, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, tcl_cv_ld_search_paths_first=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ LDFLAGS="$LDFLAGS -Wl,-search_paths_first" ]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [__private_extern__], [Compiler support for module scope symbols]) tcl_cv_cc_visibility_hidden=yes ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for combined 32 & 64 bit fat builds of Tk # extensions, verify that 64-bit build is possible. AS_IF([test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"], [ AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" AC_TRY_LINK([#include ], [XrmInitialize();], tcl_cv_lib_x11_64=yes, tcl_cv_lib_x11_64=no) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua], [ AC_CACHE_CHECK([for 64-bit Tk], tcl_cv_lib_tk_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" AC_TRY_LINK([#include ], [Tk_InitStubs(NULL, "", 0);], tcl_cv_lib_tk_64=yes, tcl_cv_lib_tk_64=no) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) # remove 64-bit arch flags from CFLAGS et al. if configuration # does not support 64-bit. AS_IF([test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no], [ AC_MSG_NOTICE([Removing 64-bit architectures from compiler & linker flags]) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done]) ]) ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h [Should OS/390 do the right thing with sockets?]) ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" AS_IF([test "$SHARED_BUILD" = 1], [ SHLIB_LD='ld -shared -expect_unresolved "*"' ], [ SHLIB_LD='ld -non_shared -expect_unresolved "*"' ]) SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) # see pthread_intro(3) for pthread support on osf1, k.furukawa AS_IF([test "${TCL_THREADS}" = 1], [ CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` AS_IF([test "$GCC" = yes], [ LIBS="$LIBS -lpthread -lmach -lexc" ], [ CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) ]) ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) AS_IF([test "$GCC" = yes], [ SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" ], [ SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" ]) SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-5.[[0-6]]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ arch=`isainfo` AS_IF([test "$arch" = "sparcv9 sparc"], [ AS_IF([test "$GCC" = yes], [ AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [ AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" ]) ], [ do64bit_ok=yes AS_IF([test "$do64bitVIS" = yes], [ CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" ], [ CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" ]) # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" ]) ], [AS_IF([test "$arch" = "amd64 i386"], [ AS_IF([test "$GCC" = yes], [ case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]);; esac ], [ do64bit_ok=yes case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac ]) ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) ]) SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "$do64bit_ok" = yes], [ AS_IF([test "$arch" = "sparcv9 sparc"], [ # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" ], [AS_IF([test "$arch" = "amd64 i386"], [ # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" ])]) ]) ], [ case $system in SunOS-5.[[1-9]][[0-9]]*) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ]) ;; UNIX_SV* | UnixWare-5*) SHLIB_CFLAGS="-KPIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers # that don't grok the -Bexport option. Test that it does. AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-Bexport" AC_TRY_LINK(, [int i;], tcl_cv_ld_Bexport=yes, tcl_cv_ld_Bexport=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_Bexport = yes], [ LDFLAGS="$LDFLAGS -Wl,-Bexport" ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; esac AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [ AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) ]) dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so dnl # until the end of configure, as configure's compile and link tests use dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's dnl # preprocessing tests use only CPPFLAGS. AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) # Add in the arch flags late to ensure it wasn't removed. # Not necessary in TEA, but this is aligned with core LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. AS_IF([test "$GCC" = yes], [ case $system in AIX-*) ;; BSD/OS*) ;; CYGWIN_*|MINGW32_*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*|OpenBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; windows) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [extern], [No Compiler support for module scope symbols]) ]) AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}' ]) AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a' ]) if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then AC_CACHE_CHECK(for SEH support in compiler, tcl_cv_seh, AC_TRY_RUN([ #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN int main(int argc, char** argv) { int a, b = 0; __try { a = 666 / b; } __except (EXCEPTION_EXECUTE_HANDLER) { return 0; } return 1; } ], tcl_cv_seh=yes, tcl_cv_seh=no, tcl_cv_seh=no) ) if test "$tcl_cv_seh" = "no" ; then AC_DEFINE(HAVE_NO_SEH, 1, [Defined when mingw does not support SEH]) fi # # Check to see if the excpt.h include file provided contains the # definition for EXCEPTION_DISPOSITION; if not, which is the case # with Cygwin's version as of 2002-04-10, define it to be int, # sufficient for getting the current code to work. # AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files, tcl_cv_eh_disposition, AC_TRY_COMPILE([ # define WIN32_LEAN_AND_MEAN # include # undef WIN32_LEAN_AND_MEAN ],[ EXCEPTION_DISPOSITION x; ], tcl_cv_eh_disposition=yes, tcl_cv_eh_disposition=no) ) if test "$tcl_cv_eh_disposition" = "no" ; then AC_DEFINE(EXCEPTION_DISPOSITION, int, [Defined when cygwin/mingw does not support EXCEPTION DISPOSITION]) fi # Check to see if winnt.h defines CHAR, SHORT, and LONG # even if VOID has already been #defined. The win32api # used by mingw and cygwin is known to do this. AC_CACHE_CHECK(for winnt.h that ignores VOID define, tcl_cv_winnt_ignore_void, AC_TRY_COMPILE([ #define VOID void #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN ], [ CHAR c; SHORT s; LONG l; ], tcl_cv_winnt_ignore_void=yes, tcl_cv_winnt_ignore_void=no) ) if test "$tcl_cv_winnt_ignore_void" = "yes" ; then AC_DEFINE(HAVE_WINNT_IGNORE_VOID, 1, [Defined when cygwin/mingw ignores VOID define in winnt.h]) fi fi # See if the compiler supports casting to a union type. # This is used to stop gcc from printing a compiler # warning when initializing a union member. AC_CACHE_CHECK(for cast to union support, tcl_cv_cast_to_union, AC_TRY_COMPILE([], [ union foo { int i; double d; }; union foo f = (union foo) (int) 0; ], tcl_cv_cast_to_union=yes, tcl_cv_cast_to_union=no) ) if test "$tcl_cv_cast_to_union" = "yes"; then AC_DEFINE(HAVE_CAST_TO_UNION, 1, [Defined when compiler supports casting to union type.]) fi AC_SUBST(CFLAGS_DEBUG) AC_SUBST(CFLAGS_OPTIMIZE) AC_SUBST(CFLAGS_WARNING) AC_SUBST(STLIB_LD) AC_SUBST(SHLIB_LD) AC_SUBST(SHLIB_SUFFIX) AC_SUBST(SHLIB_LD_LIBS) AC_SUBST(SHLIB_CFLAGS) AC_SUBST(LD_LIBRARY_PATH_VAR) # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary TEA_TCL_EARLY_FLAGS TEA_TCL_64BIT_FLAGS ]) #-------------------------------------------------------------------- # TEA_SERIAL_PORT # # Determine which interface to use to talk to the serial port. # Note that #include lines must begin in leftmost column for # some compilers to recognize them as preprocessor directives, # and some build environments have stdin not pointing at a # pseudo-terminal (usually /dev/null instead.) # # Arguments: # none # # Results: # # Defines only one of the following vars: # HAVE_SYS_MODEM_H # USE_TERMIOS # USE_TERMIO # USE_SGTTY #-------------------------------------------------------------------- AC_DEFUN([TEA_SERIAL_PORT], [ AC_CHECK_HEADERS(sys/modem.h) AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ AC_TRY_RUN([ #include int main() { struct termios t; if (tcgetattr(0, &t) == 0) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include #include int main() { struct termios t; if (tcgetattr(0, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) fi]) case $tcl_cv_api_serial in termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; esac ]) #-------------------------------------------------------------------- # TEA_MISSING_POSIX_HEADERS # # Supply substitutes for missing POSIX header files. Special # notes: # - stdlib.h doesn't define strtol, strtoul, or # strtod in some versions of SunOS # - some versions of string.h don't declare procedures such # as strstr # # Arguments: # none # # Results: # # Defines some of the following vars: # NO_DIRENT_H # NO_ERRNO_H # NO_VALUES_H # HAVE_LIMITS_H or NO_LIMITS_H # NO_STDLIB_H # NO_STRING_H # NO_SYS_WAIT_H # NO_DLFCN_H # HAVE_SYS_PARAM_H # # HAVE_STRING_H ? # # tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and # CHECK on limits.h #-------------------------------------------------------------------- AC_DEFUN([TEA_MISSING_POSIX_HEADERS], [ AC_CACHE_CHECK([dirent.h], tcl_cv_dirent_h, [ AC_TRY_LINK([#include #include ], [ #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)]) if test $tcl_cv_dirent_h = no; then AC_DEFINE(NO_DIRENT_H, 1, [Do we have ?]) fi # TEA specific: AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H, 1, [Do we have ?])]) AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have ?])]) AC_CHECK_HEADER(limits.h, [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have ?])], [AC_DEFINE(NO_LIMITS_H, 1, [Do we have ?])]) AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0) if test $tcl_ok = 0; then AC_DEFINE(NO_STDLIB_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0) AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0) # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then AC_DEFINE(NO_STRING_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have ?])]) # OS/390 lacks sys/param.h (and doesn't need it, by chance). AC_CHECK_HEADERS(sys/param.h) ]) #-------------------------------------------------------------------- # TEA_PATH_X # # Locate the X11 header files and the X11 library archive. Try # the ac_path_x macro first, but if it doesn't find the X stuff # (e.g. because there's no xmkmf program) then check through # a list of possible directories. Under some conditions the # autoconf macro will return an include directory that contains # no include files, so double-check its result just to be safe. # # This should be called after TEA_CONFIG_CFLAGS as setting the # LIBS line can confuse some configure macro magic. # # Arguments: # none # # Results: # # Sets the following vars: # XINCLUDES # XLIBSW # PKG_LIBS (appends to) #-------------------------------------------------------------------- AC_DEFUN([TEA_PATH_X], [ if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then TEA_PATH_UNIX_X fi ]) AC_DEFUN([TEA_PATH_UNIX_X], [ AC_PATH_X not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then AC_TRY_CPP([#include ], , not_really_there="yes") else if test ! -r $x_includes/X11/Xlib.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then AC_MSG_CHECKING([for X11 header files]) found_xincludes="no" AC_TRY_CPP([#include ], found_xincludes="yes", found_xincludes="no") if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Xlib.h; then AC_MSG_RESULT([$i]) XINCLUDES=" -I$i" found_xincludes="yes" break fi done fi else if test "$x_includes" != ""; then XINCLUDES="-I$x_includes" found_xincludes="yes" fi fi if test "$found_xincludes" = "no"; then AC_MSG_RESULT([couldn't find any!]) fi if test "$no_x" = yes; then AC_MSG_CHECKING([for X11 libraries]) XLIBSW=nope dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" for i in $dirs ; do if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then AC_MSG_RESULT([$i]) XLIBSW="-L$i -lX11" x_libraries="$i" break fi done else if test "$x_libraries" = ""; then XLIBSW=-lX11 else XLIBSW="-L$x_libraries -lX11" fi fi if test "$XLIBSW" = nope ; then AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) fi if test "$XLIBSW" = nope ; then AC_MSG_RESULT([could not find any! Using -lX11.]) XLIBSW=-lX11 fi # TEA specific: if test x"${XLIBSW}" != x ; then PKG_LIBS="${PKG_LIBS} ${XLIBSW}" fi ]) #-------------------------------------------------------------------- # TEA_BLOCKING_STYLE # # The statements below check for systems where POSIX-style # non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. # On these systems (mostly older ones), use the old BSD-style # FIONBIO approach instead. # # Arguments: # none # # Results: # # Defines some of the following vars: # HAVE_SYS_IOCTL_H # HAVE_SYS_FILIO_H # USE_FIONBIO # O_NONBLOCK #-------------------------------------------------------------------- AC_DEFUN([TEA_BLOCKING_STYLE], [ AC_CHECK_HEADERS(sys/ioctl.h) AC_CHECK_HEADERS(sys/filio.h) TEA_CONFIG_SYSTEM AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) case $system in OSF*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; *) AC_MSG_RESULT([O_NONBLOCK]) ;; esac ]) #-------------------------------------------------------------------- # TEA_TIME_HANDLER # # Checks how the system deals with time.h, what time structures # are used on the system, and what fields the structures have. # # Arguments: # none # # Results: # # Defines some of the following vars: # USE_DELTA_FOR_TZ # HAVE_TM_GMTOFF # HAVE_TM_TZADJ # HAVE_TIMEZONE_VAR #-------------------------------------------------------------------- AC_DEFUN([TEA_TIME_HANDLER], [ AC_CHECK_HEADERS(sys/time.h) AC_HEADER_TIME AC_STRUCT_TIMEZONE AC_CHECK_FUNCS(gmtime_r localtime_r) AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_tzadj;], tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)]) if test $tcl_cv_member_tm_tzadj = yes ; then AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) fi AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_gmtoff;], tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)]) if test $tcl_cv_member_tm_gmtoff = yes ; then AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) fi # # Its important to include time.h in this check, as some systems # (like convex) have timezone functions, etc. # AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ AC_TRY_COMPILE([#include ], [extern long timezone; timezone += 1; exit (0);], tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)]) if test $tcl_cv_timezone_long = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) else # # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. # AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ AC_TRY_COMPILE([#include ], [extern time_t timezone; timezone += 1; exit (0);], tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)]) if test $tcl_cv_timezone_time = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) fi fi ]) #-------------------------------------------------------------------- # TEA_BUGGY_STRTOD # # Under Solaris 2.4, strtod returns the wrong value for the # terminating character under some conditions. Check for this # and if the problem exists use a substitute procedure # "fixstrtod" (provided by Tcl) that corrects the error. # Also, on Compaq's Tru64 Unix 5.0, # strtod(" ") returns 0.0 instead of a failure to convert. # # Arguments: # none # # Results: # # Might defines some of the following vars: # strtod (=fixstrtod) #-------------------------------------------------------------------- AC_DEFUN([TEA_BUGGY_STRTOD], [ AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) if test "$tcl_strtod" = 1; then AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ AC_TRY_RUN([ extern double strtod(); int main() { char *infString="Inf", *nanString="NaN", *spaceString=" "; char *term; double value; value = strtod(infString, &term); if ((term != infString) && (term[-1] == 0)) { exit(1); } value = strtod(nanString, &term); if ((term != nanString) && (term[-1] == 0)) { exit(1); } value = strtod(spaceString, &term); if (term == (spaceString+1)) { exit(1); } exit(0); }], tcl_cv_strtod_buggy=ok, tcl_cv_strtod_buggy=buggy, tcl_cv_strtod_buggy=buggy)]) if test "$tcl_cv_strtod_buggy" = buggy; then AC_LIBOBJ([fixstrtod]) USE_COMPAT=1 AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) fi fi ]) #-------------------------------------------------------------------- # TEA_TCL_LINK_LIBS # # Search for the libraries needed to link the Tcl shell. # Things like the math library (-lm) and socket stuff (-lsocket vs. # -lnsl) are dealt with here. # # Arguments: # Requires the following vars to be set in the Makefile: # DL_LIBS (not in TEA, only needed in core) # LIBS # MATH_LIBS # # Results: # # Substitutes the following vars: # TCL_LIBS # MATH_LIBS # # Might append to the following vars: # LIBS # # Might define the following vars: # HAVE_NET_ERRNO_H #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_LINK_LIBS], [ #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) AC_CHECK_HEADER(net/errno.h, [ AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have ?])]) #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) if test "$tcl_checkSocket" = 1; then AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) fi AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, [LIBS="$LIBS -lnsl"])]) # TEA specific: Don't perform the eval of the libraries here because # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' AC_SUBST(TCL_LIBS) AC_SUBST(MATH_LIBS) ]) #-------------------------------------------------------------------- # TEA_TCL_EARLY_FLAGS # # Check for what flags are needed to be passed so the correct OS # features are available. # # Arguments: # None # # Results: # # Might define the following vars: # _ISOC99_SOURCE # _LARGEFILE64_SOURCE # _LARGEFILE_SOURCE64 #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_EARLY_FLAG],[ AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, AC_TRY_COMPILE([[#define ]$1[ 1 ]$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) tcl_flags="$tcl_flags $1" fi ]) AC_DEFUN([TEA_TCL_EARLY_FLAGS],[ AC_MSG_CHECKING([for required early compiler flags]) tcl_flags="" TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], [char *p = (char *)strtoll; char *q = (char *)strtoull;]) TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include ], [struct stat64 buf; int i = stat64("/", &buf);]) TEA_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include ], [char *p = (char *)open64;]) if test "x${tcl_flags}" = "x" ; then AC_MSG_RESULT([none]) else AC_MSG_RESULT([${tcl_flags}]) fi ]) #-------------------------------------------------------------------- # TEA_TCL_64BIT_FLAGS # # Check for what is defined in the way of 64-bit features. # # Arguments: # None # # Results: # # Might define the following vars: # TCL_WIDE_INT_IS_LONG # TCL_WIDE_INT_TYPE # HAVE_STRUCT_DIRENT64 # HAVE_STRUCT_STAT64 # HAVE_TYPE_OFF64_T #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_64BIT_FLAGS], [ AC_MSG_CHECKING([for 64-bit integer type]) AC_CACHE_VAL(tcl_cv_type_64bit,[ tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], tcl_type_64bit=__int64, tcl_type_64bit="long long") # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... AC_TRY_COMPILE(,[switch (0) { case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ; }],tcl_cv_type_64bit=${tcl_type_64bit})]) if test "${tcl_cv_type_64bit}" = none ; then AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?]) AC_MSG_RESULT([using long]) elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # TEA specific: We actually want to use the default tcl.h checks in # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* AC_MSG_RESULT([using Tcl header defaults]) else AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, [What type should be used to define wide integers?]) AC_MSG_RESULT([${tcl_cv_type_64bit}]) # Now check for auxiliary declarations AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ AC_TRY_COMPILE([#include #include ],[struct dirent64 p;], tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in ?]) fi AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ AC_TRY_COMPILE([#include ],[struct stat64 p; ], tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) if test "x${tcl_cv_struct_stat64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in ?]) fi AC_CHECK_FUNCS(open64 lseek64) AC_MSG_CHECKING([for off64_t]) AC_CACHE_VAL(tcl_cv_type_off64_t,[ AC_TRY_COMPILE([#include ],[off64_t offset; ], tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the dnl functions lseek64 and open64 are defined. if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi ]) ## ## Here ends the standard Tcl configuration bits and starts the ## TEA specific functions ## #------------------------------------------------------------------------ # TEA_INIT -- # # Init various Tcl Extension Architecture (TEA) variables. # This should be the first called TEA_* macro. # # Arguments: # none # # Results: # # Defines and substs the following vars: # CYGPATH # EXEEXT # Defines only: # TEA_VERSION # TEA_INITED # TEA_PLATFORM (windows or unix) # # "cygpath" is used on windows to generate native path names for include # files. These variables should only be used with the compiler and linker # since they generate native path names. # # EXEEXT # Select the executable extension based on the host type. This # is a lightweight replacement for AC_EXEEXT that doesn't require # a compiler. #------------------------------------------------------------------------ AC_DEFUN([TEA_INIT], [ # TEA extensions pass this us the version of TEA they think they # are compatible with. TEA_VERSION="3.10" AC_MSG_CHECKING([for correct TEA configuration]) if test x"${PACKAGE_NAME}" = x ; then AC_MSG_ERROR([ The PACKAGE_NAME variable must be defined by your TEA configure.ac]) fi if test x"$1" = x ; then AC_MSG_ERROR([ TEA version not specified.]) elif test "$1" != "${TEA_VERSION}" ; then AC_MSG_RESULT([warning: requested TEA version "$1", have "${TEA_VERSION}"]) else AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) fi # If the user did not set CFLAGS, set it now to keep macros # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi TEA_TK_EXTENSION=0 AC_SUBST(TEA_TK_EXTENSION) case "`uname -s`" in *win32*|*WIN32*|*MINGW32_*) AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *CYGWIN_*) EXEEXT=".exe" # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG ;; *) CYGPATH=echo # Maybe we are cross-compiling.... case ${host_alias} in *mingw32*) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *) EXEEXT="" TEA_PLATFORM="unix" ;; esac ;; esac # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi AC_MSG_NOTICE([configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}]) AC_SUBST(EXEEXT) AC_SUBST(CYGPATH) # This package name must be replaced statically for AC_SUBST to work AC_SUBST(PKG_LIB_FILE) AC_SUBST(PKG_LIB_FILE8) AC_SUBST(PKG_LIB_FILE9) # Substitute STUB_LIB_FILE in case package creates a stub library too. AC_SUBST(PKG_STUB_LIB_FILE) # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) AC_SUBST(PKG_TCL_SOURCES) AC_SUBST(PKG_HEADERS) AC_SUBST(PKG_INCLUDES) AC_SUBST(PKG_LIBS) AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_SOURCES # PKG_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_SOURCES], [ vars="$@" for i in $vars; do case $i in [\$]*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then AC_MSG_ERROR([could not find source file '$i']) fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done AC_SUBST(PKG_SOURCES) AC_SUBST(PKG_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_STUB_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_STUB_SOURCES # PKG_STUB_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_STUB_SOURCES], [ vars="$@" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then AC_MSG_ERROR([could not find stub source file '$i']) fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_TCL_SOURCES -- # # Specify one or more Tcl source files. These should be platform # independent runtime files. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_TCL_SOURCES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_TCL_SOURCES], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done AC_SUBST(PKG_TCL_SOURCES) ]) #------------------------------------------------------------------------ # TEA_ADD_HEADERS -- # # Specify one or more source headers. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_HEADERS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_HEADERS], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find header file '${srcdir}/$i']) fi PKG_HEADERS="$PKG_HEADERS $i" done AC_SUBST(PKG_HEADERS) ]) #------------------------------------------------------------------------ # TEA_ADD_INCLUDES -- # # Specify one or more include dirs. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_INCLUDES], [ vars="$@" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done AC_SUBST(PKG_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_ADD_LIBS -- # # Specify one or more libraries. Users should check for # the right platform before adding to their list. For Windows, # libraries provided in "foo.lib" format will be converted to # "-lfoo" when using GCC (mingw). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_LIBS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_LIBS], [ vars="$@" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.lib[$]/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done AC_SUBST(PKG_LIBS) ]) #------------------------------------------------------------------------ # TEA_ADD_CFLAGS -- # # Specify one or more CFLAGS. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_CFLAGS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CFLAGS], [ PKG_CFLAGS="$PKG_CFLAGS $@" AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_CLEANFILES -- # # Specify one or more CLEANFILES. # # Arguments: # one or more file names to clean target # # Results: # # Appends to CLEANFILES, already defined for subst in LOAD_TCLCONFIG #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CLEANFILES], [ CLEANFILES="$CLEANFILES $@" ]) #------------------------------------------------------------------------ # TEA_PREFIX -- # # Handle the --prefix=... option by defaulting to what Tcl gave # # Arguments: # none # # Results: # # If --prefix or --exec-prefix was not specified, $prefix and # $exec_prefix will be set to the values given to Tcl when it was # configured. #------------------------------------------------------------------------ AC_DEFUN([TEA_PREFIX], [ if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) prefix=${TCL_PREFIX} else AC_MSG_NOTICE([--prefix defaulting to /usr/local]) prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) exec_prefix=${TCL_EXEC_PREFIX} else AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) exec_prefix=$prefix fi fi ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER_CC -- # # Do compiler checks the way we want. This is just a replacement # for AC_PROG_CC in TEA configure.ac files to make them cleaner. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER_CC], [ # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. AC_PROG_CC AC_PROG_CPP INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c' INSTALL_DATA_DIR='${INSTALL} -d -m 755' INSTALL_DATA='${INSTALL} -m 644' INSTALL_PROGRAM='${INSTALL}' INSTALL_SCRIPT='${INSTALL}' INSTALL_LIBRARY='${INSTALL_DATA}' AC_SUBST(INSTALL) AC_SUBST(INSTALL_DATA_DIR) AC_SUBST(INSTALL_DATA) AC_SUBST(INSTALL_PROGRAM) AC_SUBST(INSTALL_SCRIPT) AC_SUBST(INSTALL_LIBRARY) #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- AC_PROG_MAKE_SET #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- AC_CHECK_TOOL(RANLIB, ranlib) #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- AC_OBJEXT AC_EXEEXT ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER -- # # Do compiler checks that use the compiler. This must go after # TEA_SETUP_COMPILER_CC, which does the actual compiler check. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER], [ # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. AC_REQUIRE([TEA_SETUP_COMPILER_CC]) #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then AC_CACHE_CHECK([if the compiler understands -pipe], tcl_cv_cc_pipe, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" AC_TRY_COMPILE(,, tcl_cv_cc_pipe=yes, tcl_cv_cc_pipe=no) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- AC_C_BIGENDIAN if test "${TEA_PLATFORM}" = "unix" ; then TEA_TCL_LINK_LIBS TEA_MISSING_POSIX_HEADERS # Let the user call this, because if it triggers, they will # need a compat/strtod.c that is correct. Users can also # use Tcl_GetDouble(FromObj) instead. #TEA_BUGGY_STRTOD fi ]) #------------------------------------------------------------------------ # TEA_MAKE_LIB -- # # Generate a line that can be used to build a shared/unshared library # in a platform independent manner. # # Arguments: # none # # Requires: # # Results: # # Defines the following vars: # CFLAGS - Done late here to note disturb other AC macros # MAKE_LIB - Command to execute to build the Tcl library; # differs depending on whether or not Tcl is being # compiled as a shared library. # MAKE_SHARED_LIB Makefile rule for building a shared library # MAKE_STATIC_LIB Makefile rule for building a static library # MAKE_STUB_LIB Makefile rule for building a stub library # VC_MANIFEST_EMBED_DLL Makefile rule for embedded VC manifest in DLL # VC_MANIFEST_EMBED_EXE Makefile rule for embedded VC manifest in EXE # # PRACTCL_TOOLSET What toolset is in use (gcc or msvc) # PRACTCL_SHARED_LIB Template rule for building a shared library # PRACTCL_STATIC_LIB Template rule for building a static library # PRACTCL_STUB_LIB Template rule for building a stub library # PRACTCL_VC_MANIFEST_EMBED_DLL Template rule for embedded VC manifest in DLL # PRACTCL_VC_MANIFEST_EMBED_EXE Template rule for embedded VC manifest in EXE # PRACTCL_NAME_LIBRARY Template rule for naming libraries # #------------------------------------------------------------------------ AC_DEFUN([TEA_MAKE_LIB], [ PRACTCL_TOOLSET="gcc" PRACTCL_VC_MANIFEST_EMBED_DLL=: PRACTCL_VC_MANIFEST_EMBED_EXE=: if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then PRACTCL_TOOLSET="msvc" PRACTCL_STATIC_LIB="%STLIB_LD% -out:%OUTFILE% %LIBRARY_OBJECTS%" PRACTCL_SHARED_LIB="%SHLIB_LD% %SHLIB_LD_LIBS% %LDFLAGS_DEFAULT% -out:%OUTFILE% %LIBRARY_OBJECTS%" MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS)" AC_EGREP_CPP([manifest needed], [ #if defined(_MSC_VER) && _MSC_VER >= 1400 print("manifest needed") #endif ], [ # Could do a CHECK_PROG for mt, but should always be with MSVC8+ PRACTCL_VC_MANIFEST_EMBED_DLL="mt.exe -nologo -manifest %OUTFILE%.manifest -outputresource:%OUTFILE%\;2" PRACTCL_VC_MANIFEST_EMBED_EXE="mt.exe -nologo -manifest %OUTFILE%.manifest -outputresource:%OUTFILE%\;1" VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;2 ; fi" VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;1 ; fi" MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" TEA_ADD_CLEANFILES([*.manifest]) ]) PRACTCL_STUB_LIB="%STLIB_LD% -nodefaultlib -out:%OUTFILE% %LIBRARY_OBJECTS%" MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\[$]@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" PRACTCL_STATIC_LIB="%STLIB_LD% %OUTFILE% %LIBRARY_OBJECTS%" PRACTCL_SHARED_LIB="%SHLIB_LD% -o %OUTFILE% %LIBRARY_OBJECTS% %SHLIB_LD_LIBS%" PRACTCL_STUB_LIB="%STLIB_LD% %OUTFILE% %LIBRARY_OBJECTS%" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}" PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9" if test "${TCL_MAJOR_VERSION}" -gt 8 ; then PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}" else PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}" fi if test "${TEA_PLATFORM}" = "windows" ; then PRACTCL_NAME_LIBRARY="%LIBRARY_PREFIX%%LIBRARY_NAME%%LIBRARY_VERSION_NODOTS%" if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test "$GCC" = "yes"; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc" fi eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_LIB_FILE=lib${PKG_LIB_FILE} fi fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else PRACTCL_NAME_LIBRARY="lib%LIBRARY_PREFIX%%LIBRARY_NAME%%LIBRARY_VERSION%" RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # Store the raw CFLAGS before we add the trimmings PRACTCL_CFLAGS=${CFLAGS} # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi AC_SUBST(MAKE_LIB) AC_SUBST(MAKE_SHARED_LIB) AC_SUBST(MAKE_STATIC_LIB) AC_SUBST(MAKE_STUB_LIB) AC_SUBST(RANLIB_STUB) AC_SUBST(VC_MANIFEST_EMBED_DLL) AC_SUBST(VC_MANIFEST_EMBED_EXE) AC_SUBST(PRACTCL_CFLAGS) AC_SUBST(PRACTCL_TOOLSET) AC_SUBST(PRACTCL_SHARED_LIB) AC_SUBST(PRACTCL_STATIC_LIB) AC_SUBST(PRACTCL_STUB_LIB) AC_SUBST(PRACTCL_VC_MANIFEST_EMBED_DLL) AC_SUBST(PRACTCL_VC_MANIFEST_EMBED_EXE) AC_SUBST(PRACTCL_NAME_LIBRARY) ]) #------------------------------------------------------------------------ # TEA_LIB_SPEC -- # # Compute the name of an existing object library located in libdir # from the given base name and produce the appropriate linker flags. # # Arguments: # basename The base name of the library without version # numbers, extensions, or "lib" prefixes. # extra_dir Extra directory in which to search for the # library. This location is used first, then # $prefix/$exec-prefix, then some defaults. # # Requires: # TEA_INIT and TEA_PREFIX must be called first. # # Results: # # Defines the following vars: # ${basename}_LIB_NAME The computed library name. # ${basename}_LIB_SPEC The computed linker flags. #------------------------------------------------------------------------ AC_DEFUN([TEA_LIB_SPEC], [ AC_MSG_CHECKING([for $1 library]) # Look in exec-prefix for the library (defined by TEA_PREFIX). tea_lib_name_dir="${exec_prefix}/lib" # Or in a user-specified location. if test x"$2" != x ; then tea_extra_lib_dir=$2 else tea_extra_lib_dir=NONE fi for i in \ `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib64/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib64/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do if test -f "$i" ; then tea_lib_name_dir=`dirname $i` $1_LIB_NAME=`basename $i` $1_LIB_PATH_NAME=$i break fi done if test "${TEA_PLATFORM}" = "windows"; then $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" else # Strip off the leading "lib" and trailing ".a" or ".so" tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" fi if test "x${$1_LIB_NAME}" = x ; then AC_MSG_ERROR([not found]) else AC_MSG_RESULT([${$1_LIB_SPEC}]) fi ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TCL_HEADERS -- # # Locate the private Tcl include files # # Arguments: # # Requires: # TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has # already been called. # # Results: # # Substitutes the following vars: # TCL_TOP_DIR_NATIVE # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [ # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} AC_REQUIRE([TEA_PUBLIC_TCL_HEADERS]) AC_MSG_CHECKING([for Tcl private include files]) TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" # Check to see if tclPort.h isn't already with the public headers # Don't look for tclInt.h because that resides with tcl.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tclh}/tclWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tclh}/tclUnixPort.h"; then result="private headers found with public headers" else TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" if test "${TEA_PLATFORM}" = "windows"; then TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" else TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TCL_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -d "${TCL_BIN_DIR}/Headers" -a \ -d "${TCL_BIN_DIR}/PrivateHeaders"; then TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" else TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TCL_INCLUDES}" else if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then AC_MSG_ERROR([Cannot find private header tclInt.h in ${TCL_SRC_DIR}]) fi result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" fi fi AC_SUBST(TCL_TOP_DIR_NATIVE) AC_SUBST(TCL_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TCL_HEADERS -- # # Locate the installed public Tcl header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tclinclude switch to configure. # Result is cached. # # Substitutes the following vars: # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [ AC_MSG_CHECKING([for Tcl public headers]) AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tclh, [ # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) fi else list="" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) else AC_MSG_RESULT([${ac_cv_c_tclh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TCL_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TK_HEADERS -- # # Locate the private Tk include files # # Arguments: # # Requires: # TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has # already been called. # # Results: # # Substitutes the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [ # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} AC_REQUIRE([TEA_PUBLIC_TK_HEADERS]) AC_MSG_CHECKING([for Tk private include files]) TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" # Check to see if tkPort.h isn't already with the public headers # Don't look for tkInt.h because that resides with tk.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tkh}/tkWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tkh}/tkUnixPort.h"; then result="private headers found with public headers" else TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" if test "${TEA_PLATFORM}" = "windows"; then TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" else TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TK_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" # Detect and add ttk subdir if test -d "${TK_SRC_DIR}/generic/ttk"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" fi if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_XLIB_DIR_NATIVE}\"" fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" fi if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TK_DEFS} in *TK_FRAMEWORK*) if test -d "${TK_BIN_DIR}/Headers" -a \ -d "${TK_BIN_DIR}/PrivateHeaders"; then TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" else TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TK_INCLUDES}" else if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then AC_MSG_ERROR([Cannot find private header tkInt.h in ${TK_SRC_DIR}]) fi result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" fi fi AC_SUBST(TK_TOP_DIR_NATIVE) AC_SUBST(TK_XLIB_DIR_NATIVE) AC_SUBST(TK_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TK_HEADERS -- # # Locate the installed public Tk header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tkinclude switch to configure. # Result is cached. # # Substitutes the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TK_HEADERS], [ AC_MSG_CHECKING([for Tk public headers]) AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files], with_tkinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tkh, [ # Use the value from --with-tkinclude, if it was given if test x"${with_tkinclude}" != x ; then if test -f "${with_tkinclude}/tk.h" ; then ac_cv_c_tkh=${with_tkinclude} else AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) fi else list="" if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers directory. case ${TK_DEFS} in *TK_FRAMEWORK*) list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tk is not installed, # and in that situation, look there before installed locations. if test -f "${TK_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tk's --prefix location, # relative to directory of tkConfig.sh, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TK_PREFIX}/include 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TK_INCLUDE_SPEC}" != x ; then d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tk.h" ; then ac_cv_c_tkh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tkh}" = x ; then AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) else AC_MSG_RESULT([${ac_cv_c_tkh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_INCLUDES) if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then # On Windows and Aqua, we need the X compat headers AC_MSG_CHECKING([for X11 header files]) if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_XINCLUDES) fi AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) fi ]) #------------------------------------------------------------------------ # TEA_PATH_CONFIG -- # # Locate the ${1}Config.sh file and perform a sanity check on # the ${1} compile flags. These are used by packages like # [incr Tk] that load *Config.sh files from more than Tcl and Tk. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-$1=... # # Defines the following vars: # $1_BIN_DIR Full path to the directory containing # the $1Config.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CONFIG], [ # # Ok, lets find the $1 configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-$1 # if test x"${no_$1}" = x ; then # we reset no_$1 in case something fails here no_$1=true AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) AC_MSG_CHECKING([for $1 configuration]) AC_CACHE_VAL(ac_cv_c_$1config,[ # First check to see if --with-$1 was specified. if test x"${with_$1config}" != x ; then case ${with_$1config} in */$1Config.sh ) if test -f ${with_$1config}; then AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` fi;; esac if test -f "${with_$1config}/$1Config.sh" ; then ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` else AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) fi fi # then check for a private $1 installation if test x"${ac_cv_c_$1config}" = x ; then for i in \ ../$1 \ `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../$1 \ `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../../$1 \ `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ${srcdir}/../$1 \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi if test -f "$i/unix/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i/unix; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_$1config}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_$1config}" = x ; then $1_BIN_DIR="# no $1 configs found" AC_MSG_WARN([Cannot find $1 configuration definitions]) exit 0 else no_$1= $1_BIN_DIR=${ac_cv_c_$1config} AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG -- # # Load the $1Config.sh file # # Arguments: # # Requires the following vars to be set: # $1_BIN_DIR # # Results: # # Substitutes the following vars: # $1_SRC_DIR # $1_LIB_FILE # $1_LIB_SPEC #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG], [ AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) if test -f "${$1_BIN_DIR}/$1Config.sh" ; then AC_MSG_RESULT([loading]) . "${$1_BIN_DIR}/$1Config.sh" else AC_MSG_RESULT([file not found]) fi # # If the $1_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable $1_LIB_SPEC will be set to the value # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC # instead of $1_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. # if test -f "${$1_BIN_DIR}/Makefile" ; then AC_MSG_WARN([Found Makefile - using build library specs for $1]) $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} $1_INCLUDE_SPEC=${$1_BUILD_INCLUDE_SPEC} $1_LIBRARY_PATH=${$1_LIBRARY_PATH} fi AC_SUBST($1_VERSION) AC_SUBST($1_BIN_DIR) AC_SUBST($1_SRC_DIR) AC_SUBST($1_LIB_FILE) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_STUB_LIB_FILE) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_PATH) # Allow the caller to prevent this auto-check by specifying any 2nd arg AS_IF([test "x$2" = x], [ # Check both upper and lower-case variants # If a dev wanted non-stubs libs, this function could take an option # to not use _STUB in the paths below AS_IF([test "x${$1_STUB_LIB_SPEC}" = x], [TEA_LOAD_CONFIG_LIB(translit($1,[a-z],[A-Z])_STUB)], [TEA_LOAD_CONFIG_LIB($1_STUB)]) ]) ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG_LIB -- # # Helper function to load correct library from another extension's # ${PACKAGE}Config.sh. # # Results: # Adds to LIBS the appropriate extension library #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG_LIB], [ AC_MSG_CHECKING([For $1 library for LIBS]) # This simplifies the use of stub libraries by automatically adding # the stub lib to your path. Normally this would add to SHLIB_LD_LIBS, # but this is called before CONFIG_CFLAGS. More importantly, this adds # to PKG_LIBS, which becomes LIBS, and that is only used by SHLIB_LD. if test "x${$1_LIB_SPEC}" != "x" ; then if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes" ; then TEA_ADD_LIBS([\"`${CYGPATH} ${$1_LIB_PATH}`\"]) AC_MSG_RESULT([using $1_LIB_PATH ${$1_LIB_PATH}]) else TEA_ADD_LIBS([${$1_LIB_SPEC}]) AC_MSG_RESULT([using $1_LIB_SPEC ${$1_LIB_SPEC}]) fi else AC_MSG_RESULT([file not found]) fi ]) #------------------------------------------------------------------------ # TEA_EXPORT_CONFIG -- # # Define the data to insert into the ${PACKAGE}Config.sh file # # Arguments: # # Requires the following vars to be set: # $1 # # Results: # Substitutes the following vars: #------------------------------------------------------------------------ AC_DEFUN([TEA_EXPORT_CONFIG], [ #-------------------------------------------------------------------- # These are for $1Config.sh #-------------------------------------------------------------------- # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib) eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}" if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}${DBGX}" eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}${DBGX}" else eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" fi $1_BUILD_LIB_SPEC="-L`$CYGPATH $(pwd)` ${$1_LIB_FLAG}" $1_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` ${$1_LIB_FLAG}" $1_BUILD_STUB_LIB_SPEC="-L`$CYGPATH $(pwd)` [$]{$1_STUB_LIB_FLAG}" $1_STUB_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` [$]{$1_STUB_LIB_FLAG}" $1_BUILD_STUB_LIB_PATH="`$CYGPATH $(pwd)`/[$]{PKG_STUB_LIB_FILE}" $1_STUB_LIB_PATH="`$CYGPATH ${pkglibdir}`/[$]{PKG_STUB_LIB_FILE}" AC_SUBST($1_BUILD_LIB_SPEC) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_PATH) AC_SUBST($1_STUB_LIB_PATH) AC_SUBST(MAJOR_VERSION) AC_SUBST(MINOR_VERSION) AC_SUBST(PATCHLEVEL) ]) #------------------------------------------------------------------------ # TEA_PATH_CELIB -- # # Locate Keuchel's celib emulation layer for targeting Win/CE # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-celib=... # # Defines the following vars: # CELIB_DIR Full path to the directory containing # the include and platform lib files #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CELIB], [ # First, look for one uninstalled. # the alternative search directory is invoked by --with-celib if test x"${no_celib}" = x ; then # we reset no_celib in case something fails here no_celib=true AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], with_celibconfig=${withval}) AC_MSG_CHECKING([for Windows/CE celib directory]) AC_CACHE_VAL(ac_cv_c_celibconfig,[ # First check to see if --with-celibconfig was specified. if test x"${with_celibconfig}" != x ; then if test -d "${with_celibconfig}/inc" ; then ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` else AC_MSG_ERROR([${with_celibconfig} directory doesn't contain inc directory]) fi fi # then check for a celib library if test x"${ac_cv_c_celibconfig}" = x ; then for i in \ ../celib-palm-3.0 \ ../celib \ ../../celib-palm-3.0 \ ../../celib \ `ls -dr ../celib-*3.[[0-9]]* 2>/dev/null` \ ${srcdir}/../celib-palm-3.0 \ ${srcdir}/../celib \ `ls -dr ${srcdir}/../celib-*3.[[0-9]]* 2>/dev/null` \ ; do if test -d "$i/inc" ; then ac_cv_c_celibconfig=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_celibconfig}" = x ; then AC_MSG_ERROR([Cannot find celib support library directory]) else no_celib= CELIB_DIR=${ac_cv_c_celibconfig} CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` AC_MSG_RESULT([found $CELIB_DIR]) fi fi ]) #-------------------------------------------------------------------- # TEA_CONFIG_TEAPOT # # Try to determine the canonical name for this package's binary # target # # Arguments: # none AC_DEFUN([TEA_CONFIG_TEAPOT], [ TEACUP_OS=$system TEACUP_ARCH="unknown" TEACUP_TOOLSET="gcc" TEACUP_PROFILE="unknown" arch="unknown" if test "${TEA_PLATFORM}" = "windows" ; then if test "$GCC" = "yes" ; then TEACUP_TOOLSET="gcc" else TEACUP_TOOLSET="msvc" fi if test "$do64bit" != "no" ; then case "$do64bit" in amd64|x64|yes) arch="x86_64" TEACUP_PROFILE="win32-x86_64" ;; ia64) arch="ia64" TEACUP_PROFILE="win32-ia64" ;; esac else arch="ix86" TEACUP_PROFILE="win32-ix86" fi else case $system in Linux*) TEACUP_OS="linux" arch=`uname -m` TEACUP_PROFILE="linux-glibc2.3-$arch" ;; GNU*) TEACUP_OS="gnu" arch=`uname -m` ;; NetBSD-Debian) TEACUP_OS="netbsd-debian" arch=`uname -m` ;; OpenBSD-*) TEACUP_OS="openbsd" arch=`arch -s` ;; Darwin*) TEACUP_OS="macosx" TEACUP_PROFILE="macosx-universal" arch=`uname -m` if test $arch = "x86_64"; then TEACUP_PROFILE="macosx10.5-i386-x86_84" fi ;; OpenBSD*) TEACUP_OS="openbsd" arch=`arch -s` ;; esac fi TEACUP_ARCH=$arch if test "$TEACUP_PROFILE" = "unknown"; then if test $arch = "unknown"; then arch=`uname -m` fi case $arch in i*86) arch="ix86" ;; amd64) arch="x86_64" ;; esac TEACUP_PROFILE="$TEACUP_OS-$arch" fi TEA_SYSTEM=$system AC_SUBST(TEA_SYSTEM) AC_SUBST(TEA_PLATFORM) AC_SUBST(TEA_WINDOWINGSYSTEM) AC_SUBST(TEACUP_OS) AC_SUBST(TEACUP_ARCH) AC_SUBST(TEACUP_TOOLSET) AC_SUBST(TEACUP_PROFILE) ]) # Local Variables: # mode: autoconf # End: ./nsf2.4.0/m4/PaxHeader/tcl.m4-new000644 000766 000024 00000000036 14270755203 017300 xustar00neumannstaff000000 000000 30 mtime=1659099779.441737953 ./nsf2.4.0/m4/tcl.m4-new000644 000766 000024 00000403241 14270755203 015334 0ustar00neumannstaff000000 000000 # tcl.m4 -- # # This file provides a set of autoconf macros to help TEA-enable # a Tcl extension. # # Copyright (c) 1999-2000 Ajuba Solutions. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. AC_PREREQ([2.69]) # Possible values for key variables defined: # # TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') # TEA_PLATFORM - windows unix # TEA_TK_EXTENSION - True if this is a Tk extension # #------------------------------------------------------------------------ # TEA_PATH_TCLCONFIG -- # # Locate the tclConfig.sh file and perform a sanity check on # the Tcl compile flags # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tcl=... # # Defines the following vars: # TCL_BIN_DIR Full path to the directory containing # the tclConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TCLCONFIG], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true AC_ARG_WITH(tcl, AS_HELP_STRING([--with-tcl], [directory containing tcl configuration (tclConfig.sh)]), [with_tclconfig="${withval}"]) AC_ARG_WITH(tcl8, AS_HELP_STRING([--with-tcl8], [Compile for Tcl8 in Tcl9 environment]), [with_tcl8="${withval}"]) AC_MSG_CHECKING([for Tcl configuration]) AC_CACHE_VAL(ac_cv_c_tclconfig,[ # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case "${with_tclconfig}" in */tclConfig.sh ) if test -f "${with_tclconfig}"; then AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" else AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks/Tcl.framework 2>/dev/null` \ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Network/Library/Frameworks/Tcl.framework 2>/dev/null` \ `ls -d /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Tcl.framework 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/pkg/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ `ls -d /usr/lib/tcl8.6 2>/dev/null` \ `ls -d /usr/lib/tcl8.5 2>/dev/null` \ `ls -d /usr/local/lib/tcl8.6 2>/dev/null` \ `ls -d /usr/local/lib/tcl8.5 2>/dev/null` \ `ls -d /usr/local/lib/tcl/tcl8.6 2>/dev/null` \ `ls -d /usr/local/lib/tcl/tcl8.5 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" AC_MSG_ERROR([Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh]) else no_tcl= TCL_BIN_DIR="${ac_cv_c_tclconfig}" AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_PATH_TKCONFIG -- # # Locate the tkConfig.sh file # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tk=... # # Defines the following vars: # TK_BIN_DIR Full path to the directory containing # the tkConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TKCONFIG], [ # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true AC_ARG_WITH(tk, AS_HELP_STRING([--with-tk], [directory containing tk configuration (tkConfig.sh)]), [with_tkconfig="${withval}"]) AC_MSG_CHECKING([for Tk configuration]) AC_CACHE_VAL(ac_cv_c_tkconfig,[ # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case "${with_tkconfig}" in */tkConfig.sh ) if test -f "${with_tkconfig}"; then AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" else AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/pkg/lib 2>/dev/null` \ `ls -d /usr/lib/tk8.6 2>/dev/null` \ `ls -d /usr/lib/tk8.5 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ `ls -d /usr/local/lib/tk8.6 2>/dev/null` \ `ls -d /usr/local/lib/tk8.5 2>/dev/null` \ `ls -d /usr/local/lib/tcl/tk8.6 2>/dev/null` \ `ls -d /usr/local/lib/tcl/tk8.5 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" AC_MSG_ERROR([Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh]) else no_tk= TK_BIN_DIR="${ac_cv_c_tkconfig}" AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_TCLCONFIG -- # # Load the tclConfig.sh file # # Arguments: # # Requires the following vars to be set: # TCL_BIN_DIR # # Results: # # Substitutes the following vars: # TCL_BIN_DIR # TCL_SRC_DIR # TCL_LIB_FILE # TCL_ZIP_FILE # TCL_ZIPFS_SUPPORT #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TCLCONFIG], [ AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TCL_BIN_DIR}/tclConfig.sh" else AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) fi # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitrary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" break fi done fi if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi AC_SUBST(TCL_VERSION) AC_SUBST(TCL_PATCH_LEVEL) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) AC_MSG_CHECKING([platform]) hold_cc=$CC; CC="$TCL_CC" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ #ifdef _WIN32 #error win32 #endif ]])],[ # first test we've already retrieved platform (cross-compile), fallback to unix otherwise: TEA_PLATFORM="${TEA_PLATFORM-unix}" CYGPATH=echo ],[ TEA_PLATFORM="windows" AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) ]) CC=$hold_cc AC_MSG_RESULT($TEA_PLATFORM) # The BUILD_$pkg is to define the correct extern storage class # handling when making this package AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME}, [], [Building extension source?]) # Do this here as we have fully defined TEA_PLATFORM now if test "${TEA_PLATFORM}" = "windows" ; then EXEEXT=".exe" CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp" fi # TEA specific: AC_SUBST(CLEANFILES) AC_SUBST(TCL_LIBS) AC_SUBST(TCL_DEFS) AC_SUBST(TCL_EXTRA_CFLAGS) AC_SUBST(TCL_LD_FLAGS) AC_SUBST(TCL_SHLIB_LD_LIBS) ]) #------------------------------------------------------------------------ # TEA_LOAD_TKCONFIG -- # # Load the tkConfig.sh file # # Arguments: # # Requires the following vars to be set: # TK_BIN_DIR # # Results: # # Sets the following vars that should be in tkConfig.sh: # TK_BIN_DIR #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TKCONFIG], [ AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TK_BIN_DIR}/tkConfig.sh" else AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) fi # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TK_BIN_DIR}/Makefile" ; then TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tk.framework installed in an arbitrary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then for i in "`cd "${TK_BIN_DIR}"; pwd`" \ "`cd "${TK_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" break fi done fi if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # TEA specific: Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) TEA_WINDOWINGSYSTEM="aqua" ;; *) TEA_WINDOWINGSYSTEM="x11" ;; esac elif test "${TEA_PLATFORM}" = "windows" ; then TEA_WINDOWINGSYSTEM="win32" fi AC_SUBST(TK_VERSION) AC_SUBST(TK_BIN_DIR) AC_SUBST(TK_SRC_DIR) AC_SUBST(TK_LIB_FILE) AC_SUBST(TK_LIB_FLAG) AC_SUBST(TK_LIB_SPEC) AC_SUBST(TK_STUB_LIB_FILE) AC_SUBST(TK_STUB_LIB_FLAG) AC_SUBST(TK_STUB_LIB_SPEC) # TEA specific: AC_SUBST(TK_LIBS) AC_SUBST(TK_XINCLUDES) ]) #------------------------------------------------------------------------ # TEA_PROG_TCLSH # Determine the fully qualified path name of the tclsh executable # in the Tcl build directory or the tclsh installed in a bin # directory. This macro will correctly determine the name # of the tclsh executable even if tclsh has not yet been # built in the build directory. The tclsh found is always # associated with a tclConfig.sh file. This tclsh should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments: # none # # Results: # Substitutes the following vars: # TCLSH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_TCLSH], [ AC_MSG_CHECKING([for tclsh]) if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" fi else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" fi AC_MSG_RESULT([${TCLSH_PROG}]) AC_SUBST(TCLSH_PROG) ]) #------------------------------------------------------------------------ # TEA_PROG_WISH # Determine the fully qualified path name of the wish executable # in the Tk build directory or the wish installed in a bin # directory. This macro will correctly determine the name # of the wish executable even if wish has not yet been # built in the build directory. The wish found is always # associated with a tkConfig.sh file. This wish should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments: # none # # Results: # Substitutes the following vars: # WISH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_WISH], [ AC_MSG_CHECKING([for wish]) if test -f "${TK_BIN_DIR}/Makefile" ; then # tkConfig.sh is in Tk build directory if test "${TEA_PLATFORM}" = "windows"; then if test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}s${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}$s{EXEEXT}" elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}" elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}" ; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}" fi else WISH_PROG="${TK_BIN_DIR}/wish" fi else # tkConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" else WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}" fi list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TK_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${WISH_PROG}" ; then REAL_TK_BIN_DIR="`cd "$i"; pwd`/" break fi done WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" fi AC_MSG_RESULT([${WISH_PROG}]) AC_SUBST(WISH_PROG) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SHARED -- # # Allows the building of shared libraries # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-shared=yes|no # --enable-stubs=yes|no # # Defines the following vars: # STATIC_BUILD Used for building import/export libraries # on Windows. # # Sets the following vars: # SHARED_BUILD Value of 1 or 0 # STUBS_BUILD Value if 1 or 0 # USE_TCL_STUBS Value true: if SHARED_BUILD or --enable-stubs # USE_TCLOO_STUBS Value true: if SHARED_BUILD or --enable-stubs # USE_TK_STUBS Value true: if SHARED_BUILD or --enable-stubs # AND TEA_WINDOWING_SYSTEM != "" #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SHARED], [ AC_MSG_CHECKING([how to build libraries]) AC_ARG_ENABLE(shared, AS_HELP_STRING([--enable-shared], [build and link with shared libraries (default: on)]), [shared_ok=$enableval], [shared_ok=yes]) if test "${enable_shared+set}" = set; then enableval="$enable_shared" shared_ok=$enableval else shared_ok=yes fi AC_ARG_ENABLE(stubs, AS_HELP_STRING([--enable-stubs], [build and link with stub libraries. Always true for shared builds (default: on)]), [stubs_ok=$enableval], [stubs_ok=yes]) if test "${enable_stubs+set}" = set; then enableval="$enable_stubs" stubs_ok=$enableval else stubs_ok=yes fi # Stubs are always enabled for shared builds if test "$shared_ok" = "yes" ; then AC_MSG_RESULT([shared]) SHARED_BUILD=1 STUBS_BUILD=1 else AC_MSG_RESULT([static]) SHARED_BUILD=0 AC_DEFINE(STATIC_BUILD, 1, [This a static build]) if test "$stubs_ok" = "yes" ; then STUBS_BUILD=1 else STUBS_BUILD=0 fi fi if test "${STUBS_BUILD}" = "1" ; then AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) AC_DEFINE(USE_TCLOO_STUBS, 1, [Use TclOO stubs]) if test "${TEA_WINDOWINGSYSTEM}" != ""; then AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) fi fi AC_SUBST(SHARED_BUILD) AC_SUBST(STUBS_BUILD) ]) #------------------------------------------------------------------------ # TEA_ENABLE_THREADS -- # # Specify if thread support should be enabled. If "yes" is specified # as an arg (optional), threads are enabled by default, "no" means # threads are disabled. "yes" is the default. # # TCL_THREADS is checked so that if you are compiling an extension # against a threaded core, your extension must be compiled threaded # as well. # # Note that it is legal to have a thread enabled extension run in a # threaded or non-threaded Tcl core, but a non-threaded extension may # only run in a non-threaded Tcl core. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-threads # # Sets the following vars: # THREADS_LIBS Thread library(s) # # Defines the following vars: # TCL_THREADS # _REENTRANT # _THREAD_SAFE #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_THREADS], [ AC_ARG_ENABLE(threads, AS_HELP_STRING([--enable-threads], [build with threads (default: on)]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention AC_DEFINE(USE_THREAD_ALLOC, 1, [Do we want to use the threaded memory allocator?]) AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) if test "`uname -s`" = "SunOS" ; then AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) fi AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] AC_CHECK_LIB(pthread, __pthread_mutex_init, tcl_ok=yes, tcl_ok=no) fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else AC_CHECK_LIB(pthreads, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else AC_CHECK_LIB(c, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "no"; then AC_CHECK_LIB(c_r, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 AC_MSG_WARN([Do not know how to find pthread lib on your system - thread support disabled]) fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output AC_MSG_CHECKING([for building with threads]) if test "${TCL_THREADS}" = 1; then AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) AC_MSG_RESULT([yes (default)]) else AC_MSG_RESULT([no]) fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then AC_MSG_WARN([ Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads.]) fi ;; esac AC_SUBST(TCL_THREADS) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SYMBOLS -- # # Specify if debugging symbols should be used. # Memory (TCL_MEM_DEBUG) debugging can also be enabled. # # Arguments: # none # # TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives # the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted. # Requires the following vars to be set in the Makefile: # CFLAGS_DEFAULT # LDFLAGS_DEFAULT # # Results: # # Adds the following arguments to configure: # --enable-symbols # # Defines the following vars: # CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true # Sets to "$(CFLAGS_OPTIMIZE) -DNDEBUG" if false # LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true # Sets to $(LDFLAGS_OPTIMIZE) if false #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SYMBOLS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_CONFIG_CFLAGS]) AC_MSG_CHECKING([for build with symbols]) AC_ARG_ENABLE(symbols, AS_HELP_STRING([--enable-symbols], [build with debugging symbols (default: off)]), [tcl_ok=$enableval], [tcl_ok=no]) if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" AC_MSG_RESULT([no]) AC_DEFINE(TCL_CFG_OPTIMIZED, 1, [Is this an optimized build?]) else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then AC_MSG_RESULT([yes (standard debugging)]) fi fi AC_SUBST(CFLAGS_DEFAULT) AC_SUBST(LDFLAGS_DEFAULT) if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then AC_MSG_RESULT([enabled symbols mem debugging]) else AC_MSG_RESULT([enabled $tcl_ok debugging]) fi fi ]) #------------------------------------------------------------------------ # TEA_ENABLE_LANGINFO -- # # Allows use of modern nl_langinfo check for better l10n. # This is only relevant for Unix. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-langinfo=yes|no (default is yes) # # Defines the following vars: # HAVE_LANGINFO Triggers use of nl_langinfo if defined. #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_LANGINFO], [ AC_ARG_ENABLE(langinfo, AS_HELP_STRING([--enable-langinfo], [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), [langinfo_ok=$enableval], [langinfo_ok=yes]) HAVE_LANGINFO=0 if test "$langinfo_ok" = "yes"; then AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) fi AC_MSG_CHECKING([whether to use nl_langinfo]) if test "$langinfo_ok" = "yes"; then AC_CACHE_VAL(tcl_cv_langinfo_h, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[nl_langinfo(CODESET);]])], [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) AC_MSG_RESULT([$tcl_cv_langinfo_h]) if test $tcl_cv_langinfo_h = yes; then AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) fi else AC_MSG_RESULT([$langinfo_ok]) fi ]) #-------------------------------------------------------------------- # TEA_CONFIG_SYSTEM # # Determine what the system is (some things cannot be easily checked # on a feature-driven basis, alas). This can usually be done via the # "uname" command. # # Arguments: # none # # Results: # Defines the following var: # # system - System/platform/version identification code. # #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_SYSTEM], [ AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then AC_MSG_WARN([can't find uname command]) tcl_cv_sys_version=unknown else if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi if test "`uname -s`" = "NetBSD" -a -f /etc/debian_version ; then tcl_cv_sys_version=NetBSD-Debian fi fi fi ]) system=$tcl_cv_sys_version ]) #-------------------------------------------------------------------- # TEA_CONFIG_CFLAGS # # Try to determine the proper flags to pass to the compiler # for building shared libraries and other such nonsense. # # Arguments: # none # # Results: # # Defines and substitutes the following vars: # # DL_OBJS, DL_LIBS - removed for TEA, only needed by core. # LDFLAGS - Flags to pass to the compiler when linking object # files into an executable application binary such # as tclsh. # LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. Could # be the same as CC_SEARCH_FLAGS if ${CC} is used to link. # CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. # SHLIB_CFLAGS - Flags to pass to cc when compiling the components # of a shared library (may request position-independent # code, among other things). # SHLIB_LD - Base command to use for combining object files # into a shared library. # SHLIB_LD_LIBS - Dependent libraries for the linker to scan when # creating shared libraries. This symbol typically # goes at the end of the "ld" commands that build # shared libraries. The value of the symbol defaults to # "${LIBS}" if all of the dependent libraries should # be specified when creating a shared library. If # dependent libraries should not be specified (as on # SunOS 4.x, where they cause the link to fail, or in # general if Tcl and Tk aren't themselves shared # libraries), then this symbol has an empty string # as its value. # SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable # extensions. An empty string means we don't know how # to use shared libraries on this platform. # LIB_SUFFIX - Specifies everything that comes after the "libfoo" # in a static or shared library name, using the $PACKAGE_VERSION variable # to put the version in the right place. This is used # by platforms that need non-standard library names. # Examples: ${PACKAGE_VERSION}.so.1.1 on NetBSD, since it needs # to have a version after the .so, and ${PACKAGE_VERSION}.a # on AIX, since a shared library needs to have # a .a extension whereas shared objects for loadable # extensions have a .so extension. Defaults to # ${PACKAGE_VERSION}${SHLIB_SUFFIX}. # CFLAGS_DEBUG - # Flags used when running the compiler in debug mode # CFLAGS_OPTIMIZE - # Flags used when running the compiler in optimize mode # CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_CFLAGS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # Step 0.a: Enable 64 bit support? AC_MSG_CHECKING([if 64bit support is requested]) AC_ARG_ENABLE(64bit, AS_HELP_STRING([--enable-64bit], [enable 64bit support (default: off)]), [do64bit=$enableval], [do64bit=no]) AC_MSG_RESULT([$do64bit]) # Step 0.b: Enable Solaris 64 bit VIS support? AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) AC_ARG_ENABLE(64bit-vis, AS_HELP_STRING([--enable-64bit-vis], [enable 64bit Sparc VIS support (default: off)]), [do64bitVIS=$enableval], [do64bitVIS=no]) AC_MSG_RESULT([$do64bitVIS]) # Force 64bit on with VIS AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) # Step 0.c: Check if visibility support is available. Do this here so # that platform specific alternatives can be used below if this fails. AC_CACHE_CHECK([if compiler supports visibility "hidden"], tcl_cv_cc_visibility_hidden, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" AC_LINK_IFELSE([AC_LANG_PROGRAM([[ extern __attribute__((__visibility__("hidden"))) void f(void); void f(void) {}]], [[f();]])],[tcl_cv_cc_visibility_hidden=yes], [tcl_cv_cc_visibility_hidden=no]) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ AC_DEFINE(MODULE_SCOPE, [extern __attribute__((__visibility__("hidden")))], [Compiler support for module scope symbols]) AC_DEFINE(HAVE_HIDDEN, [1], [Compiler support for module scope symbols]) ]) # Step 0.d: Disable -rpath support? AC_MSG_CHECKING([if rpath support is requested]) AC_ARG_ENABLE(rpath, AS_HELP_STRING([--disable-rpath], [disable rpath support (default: on)]), [doRpath=$enableval], [doRpath=yes]) AC_MSG_RESULT([$doRpath]) # Set the variable "system" to hold the name and version number # for the system. TEA_CONFIG_SYSTEM # Require ranlib early so we can override it in special cases below. AC_REQUIRE([AC_PROG_RANLIB]) # Set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case and removed some core-only vars. do64bit_ok=no # default to '{$LIBS}' and set to "" on per-platform necessary basis SHLIB_LD_LIBS='${LIBS}' # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" UNSHARED_LIB_SUFFIX="" # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g AS_IF([test "$GCC" = yes], [ CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall" ], [ CFLAGS_OPTIMIZE=-O CFLAGS_WARNING="" ]) AC_CHECK_TOOL(AR, ar) STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION=""],[SHLIB_VERSION=".$SHLIB_VERSION"]) case $system in # TEA specific: windows) MACHINE="X86" if test "$do64bit" != "no" ; then case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build ;; arm64|aarch64) MACHINE="ARM64" ;; ia64) MACHINE="IA64" ;; esac fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi case "x`echo \${VisualStudioVersion}`" in x1[[4-9]]*) lflags="${lflags} -nodefaultlib:libucrt.lib" TEA_ADD_LIBS([ucrt.lib]) ;; *) ;; esac if test "$do64bit" != "no" ; then CC="cl.exe" RC="rc.exe" lflags="${lflags} -nologo -MACHINE:${MACHINE} " LINKBIN="link.exe" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 TEA_ADD_LIBS([bufferoverflowU.lib]) else RC="rc" lflags="${lflags} -nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode AC_CHECK_TOOL(RC, windres) CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD='${CC} -shared' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" AC_CACHE_CHECK(for cross-compile version of gcc, ac_cv_cross, AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #ifdef _WIN32 #error cross-compiler #endif ]], [[]])], [ac_cv_cross=yes], [ac_cv_cross=no]) ) if test "$ac_cv_cross" = "yes"; then case "$do64bit" in amd64|x64|yes) CC="x86_64-w64-mingw32-${CC}" LD="x86_64-w64-mingw32-ld" AR="x86_64-w64-mingw32-ar" RANLIB="x86_64-w64-mingw32-ranlib" RC="x86_64-w64-mingw32-windres" ;; arm64|aarch64) CC="aarch64-w64-mingw32-clang" LD="aarch64-w64-mingw32-ld" AR="aarch64-w64-mingw32-ar" RANLIB="aarch64-w64-mingw32-ranlib" RC="aarch64-w64-mingw32-windres" ;; *) CC="i686-w64-mingw32-${CC}" LD="i686-w64-mingw32-ld" AR="i686-w64-mingw32-ar" RANLIB="i686-w64-mingw32-ranlib" RC="i686-w64-mingw32-windres" ;; esac fi else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots ;; AIX-*) AS_IF([test "$GCC" != "yes"], [ # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r|*_r\ *) # ok ... ;; *) # Make sure only first arg gets _r CC=`echo "$CC" | sed -e 's/^\([[^ ]]*\)/\1_r/'` ;; esac AC_MSG_RESULT([Using $CC for compiling with threads]) ]) LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_SUFFIX=".so" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported with GCC on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" ]) ]) AS_IF([test "`uname -m`" = ia64], [ # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" AS_IF([test "$GCC" = yes], [ CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"' ], [ CC_SEARCH_FLAGS='"-R${LIB_RUNTIME_DIR}"' ]) LD_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"' ], [ AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared -Wl,-bexpall' ], [ SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" LDFLAGS="$LDFLAGS -brtl" ]) SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" CC_SEARCH_FLAGS='"-L${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_SUFFIX=".so" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) ;; BSD/OS-2.1*|BSD/OS-3*) SHLIB_CFLAGS="" SHLIB_LD="shlicc -r" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; CYGWIN_*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".dll" SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -Wl,--out-implib,\$[@].a" EXEEXT=".exe" do64bit_ok=yes CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; dgux*) SHLIB_CFLAGS="-K PIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared' AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"]) ;; HP-UX-*.11.*) # Use updated header definitions where possible AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) # TEA specific: Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library AS_IF([test "`uname -m`" = ia64], [ SHLIB_SUFFIX=".so" ], [ SHLIB_SUFFIX=".sl" ]) AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) AS_IF([test "$tcl_ok" = yes], [ SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='"-Wl,+s,+b,${LIB_RUNTIME_DIR}:."' LD_SEARCH_FLAGS='+s +b "${LIB_RUNTIME_DIR}:."' LD_LIBRARY_PATH_VAR="SHLIB_PATH" ]) AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ CFLAGS="$CFLAGS -z" ]) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = "yes"], [ AS_IF([test "$GCC" = yes], [ case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]) ;; esac ], [ do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" ]) ]) ;; HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*) SHLIB_SUFFIX=".sl" AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) AS_IF([test "$tcl_ok" = yes], [ SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" SHLIB_LD_LIBS="" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='"-Wl,+s,+b,${LIB_RUNTIME_DIR}:."' LD_SEARCH_FLAGS='+s +b "${LIB_RUNTIME_DIR}:."' LD_LIBRARY_PATH_VAR="SHLIB_PATH" ]) ;; IRIX-5.*) SHLIB_CFLAGS="" SHLIB_LD="ld -shared -rdata_shared" SHLIB_SUFFIX=".so" AC_LIBOBJ(mkstemp) AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"']) ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"']) AS_IF([test "$GCC" = yes], [ CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" ], [ case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" ]) ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS='-rpath "${LIB_RUNTIME_DIR}"']) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported by gcc]) ], [ do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" ]) ]) ;; Linux*|GNU*|NetBSD-Debian|DragonFly-*|FreeBSD-*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS_DEFAULT} -shared' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" case $system in DragonFly-*|FreeBSD-*) AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the LDFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LDFLAGS="$LDFLAGS $PTHREAD_LIBS"]) ;; esac AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) AS_IF([test $do64bit = yes], [ AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [tcl_cv_cc_m64=yes],[tcl_cv_cc_m64=no]) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_m64 = yes], [ CFLAGS="$CFLAGS -m64" do64bit_ok=yes ]) ]) # The combo of gcc + glibc has a bug related to inlining of # functions like strtod(). The -fno-builtin flag should address # this problem but it does not work. The -fno-inline flag is kind # of overkill but it works. Disable inlining only when one of the # files in compat/*.c is being linked in. AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"]) ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' LD_FLAGS="-Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) ;; OpenBSD-*) arch=`arch -s` case "$arch" in alpha|sparc64) SHLIB_CFLAGS="-fPIC" ;; *) SHLIB_CFLAGS="-fpic" ;; esac SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}' LDFLAGS="$LDFLAGS -Wl,-export-dynamic" CFLAGS_OPTIMIZE="-O2" # On OpenBSD: Compile with -pthread # Don't link with -lpthread LIBS=`echo $LIBS | sed s/-lpthread//` CFLAGS="$CFLAGS -pthread" # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*) # NetBSD has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" AS_IF([test $do64bit = yes], [ case `arch` in ppc) AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], tcl_cv_cc_arch_ppc64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [tcl_cv_cc_arch_ppc64=yes],[tcl_cv_cc_arch_ppc64=no]) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes ]);; i386) AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], tcl_cv_cc_arch_x86_64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [tcl_cv_cc_arch_x86_64=yes],[tcl_cv_cc_arch_x86_64=no]) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes ]);; *) AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; esac ], [ # Check for combined 32-bit and 64-bit fat build AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ fat_32_64=yes]) ]) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])], [tcl_cv_ld_single_module=yes],[tcl_cv_ld_single_module=no]) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_single_module = yes], [ SHLIB_LD="${SHLIB_LD} -Wl,-single_module" ]) # TEA specific: link shlib with current and compatibility version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" SHLIB_SUFFIX=".dylib" LDFLAGS="$LDFLAGS -headerpad_max_install_names" AC_CACHE_CHECK([if ld accepts -search_paths_first flag], tcl_cv_ld_search_paths_first, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])], [tcl_cv_ld_search_paths_first=yes],[tcl_cv_ld_search_paths_first=no]) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ LDFLAGS="$LDFLAGS -Wl,-search_paths_first" ]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [__private_extern__], [Compiler support for module scope symbols]) tcl_cv_cc_visibility_hidden=yes ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for combined 32 & 64 bit fat builds of Tk # extensions, verify that 64-bit build is possible. AS_IF([test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"], [ AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[XrmInitialize();]])], [tcl_cv_lib_x11_64=yes],[tcl_cv_lib_x11_64=no]) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua], [ AC_CACHE_CHECK([for 64-bit Tk], tcl_cv_lib_tk_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[Tk_InitStubs(NULL, "", 0);]])], [tcl_cv_lib_tk_64=yes],[tcl_cv_lib_tk_64=no]) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) # remove 64-bit arch flags from CFLAGS et al. if configuration # does not support 64-bit. AS_IF([test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no], [ AC_MSG_NOTICE([Removing 64-bit architectures from compiler & linker flags]) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done]) ]) ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h [Should OS/390 do the right thing with sockets?]) ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" AS_IF([test "$SHARED_BUILD" = 1], [ SHLIB_LD='ld -shared -expect_unresolved "*"' ], [ SHLIB_LD='ld -non_shared -expect_unresolved "*"' ]) SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) # see pthread_intro(3) for pthread support on osf1, k.furukawa CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` AS_IF([test "$GCC" = yes], [ LIBS="$LIBS -lpthread -lmach -lexc" ], [ CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) AS_IF([test "$GCC" = yes], [ SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" ], [ SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" ]) SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-5.[[0-6]]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ arch=`isainfo` AS_IF([test "$arch" = "sparcv9 sparc"], [ AS_IF([test "$GCC" = yes], [ AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [ AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" ]) ], [ do64bit_ok=yes AS_IF([test "$do64bitVIS" = yes], [ CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" ], [ CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" ]) # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" ]) ], [AS_IF([test "$arch" = "amd64 i386"], [ AS_IF([test "$GCC" = yes], [ case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]);; esac ], [ do64bit_ok=yes case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac ]) ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) ]) SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "$do64bit_ok" = yes], [ AS_IF([test "$arch" = "sparcv9 sparc"], [ # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" ], [AS_IF([test "$arch" = "amd64 i386"], [ # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" ])]) ]) ], [ case $system in SunOS-5.[[1-9]][[0-9]]*) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac CC_SEARCH_FLAGS='"-Wl,-R,${LIB_RUNTIME_DIR}"' LD_SEARCH_FLAGS='-R "${LIB_RUNTIME_DIR}"' ]) ;; UNIX_SV* | UnixWare-5*) SHLIB_CFLAGS="-KPIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers # that don't grok the -Bexport option. Test that it does. AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-Bexport" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])], [tcl_cv_ld_Bexport=yes],[tcl_cv_ld_Bexport=no]) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_Bexport = yes], [ LDFLAGS="$LDFLAGS -Wl,-Bexport" ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; esac AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [ AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) ]) dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so dnl # until the end of configure, as configure's compile and link tests use dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's dnl # preprocessing tests use only CPPFLAGS. AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) # Add in the arch flags late to ensure it wasn't removed. # Not necessary in TEA, but this is aligned with core LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. AS_IF([test "$GCC" = yes], [ case $system in AIX-*) ;; BSD/OS*) ;; CYGWIN_*|MINGW32_*|MINGW64_*|MSYS_*) ;; IRIX*) ;; NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; windows) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [extern], [No Compiler support for module scope symbols]) ]) AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}']) AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a']) if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then AC_CACHE_CHECK(for SEH support in compiler, tcl_cv_seh, AC_RUN_IFELSE([AC_LANG_SOURCE([[ #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN int main(int argc, char** argv) { int a, b = 0; __try { a = 666 / b; } __except (EXCEPTION_EXECUTE_HANDLER) { return 0; } return 1; } ]])], [tcl_cv_seh=yes], [tcl_cv_seh=no], [tcl_cv_seh=no]) ) if test "$tcl_cv_seh" = "no" ; then AC_DEFINE(HAVE_NO_SEH, 1, [Defined when mingw does not support SEH]) fi # # Check to see if the excpt.h include file provided contains the # definition for EXCEPTION_DISPOSITION; if not, which is the case # with Cygwin's version as of 2002-04-10, define it to be int, # sufficient for getting the current code to work. # AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files, tcl_cv_eh_disposition, AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ # define WIN32_LEAN_AND_MEAN # include # undef WIN32_LEAN_AND_MEAN ]], [[ EXCEPTION_DISPOSITION x; ]])], [tcl_cv_eh_disposition=yes], [tcl_cv_eh_disposition=no]) ) if test "$tcl_cv_eh_disposition" = "no" ; then AC_DEFINE(EXCEPTION_DISPOSITION, int, [Defined when cygwin/mingw does not support EXCEPTION DISPOSITION]) fi # Check to see if winnt.h defines CHAR, SHORT, and LONG # even if VOID has already been #defined. The win32api # used by mingw and cygwin is known to do this. AC_CACHE_CHECK(for winnt.h that ignores VOID define, tcl_cv_winnt_ignore_void, AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #define VOID void #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN ]], [[ CHAR c; SHORT s; LONG l; ]])], [tcl_cv_winnt_ignore_void=yes], [tcl_cv_winnt_ignore_void=no]) ) if test "$tcl_cv_winnt_ignore_void" = "yes" ; then AC_DEFINE(HAVE_WINNT_IGNORE_VOID, 1, [Defined when cygwin/mingw ignores VOID define in winnt.h]) fi fi # See if the compiler supports casting to a union type. # This is used to stop gcc from printing a compiler # warning when initializing a union member. AC_CACHE_CHECK(for cast to union support, tcl_cv_cast_to_union, AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ union foo { int i; double d; }; union foo f = (union foo) (int) 0; ]])], [tcl_cv_cast_to_union=yes], [tcl_cv_cast_to_union=no]) ) if test "$tcl_cv_cast_to_union" = "yes"; then AC_DEFINE(HAVE_CAST_TO_UNION, 1, [Defined when compiler supports casting to union type.]) fi AC_CHECK_HEADER(stdbool.h, [AC_DEFINE(HAVE_STDBOOL_H, 1, [Do we have ?])],) AC_SUBST(CFLAGS_DEBUG) AC_SUBST(CFLAGS_OPTIMIZE) AC_SUBST(CFLAGS_WARNING) AC_SUBST(LDFLAGS_DEBUG) AC_SUBST(LDFLAGS_OPTIMIZE) AC_SUBST(STLIB_LD) AC_SUBST(SHLIB_LD) AC_SUBST(SHLIB_LD_LIBS) AC_SUBST(SHLIB_CFLAGS) AC_SUBST(LD_LIBRARY_PATH_VAR) # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary TEA_TCL_EARLY_FLAGS TEA_TCL_64BIT_FLAGS ]) #-------------------------------------------------------------------- # TEA_SERIAL_PORT # # Determine which interface to use to talk to the serial port. # Note that #include lines must begin in leftmost column for # some compilers to recognize them as preprocessor directives, # and some build environments have stdin not pointing at a # pseudo-terminal (usually /dev/null instead.) # # Arguments: # none # # Results: # # Defines only one of the following vars: # HAVE_SYS_MODEM_H # USE_TERMIOS # USE_TERMIO # USE_SGTTY #-------------------------------------------------------------------- AC_DEFUN([TEA_SERIAL_PORT], [ AC_CHECK_HEADERS(sys/modem.h) AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include int main() { struct termios t; if (tcgetattr(0, &t) == 0) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }]])],[tcl_cv_api_serial=termios],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no]) if test $tcl_cv_api_serial = no ; then AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }]])],[tcl_cv_api_serial=termio],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no]) fi if test $tcl_cv_api_serial = no ; then AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }]])],[tcl_cv_api_serial=sgtty],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no]) fi if test $tcl_cv_api_serial = no ; then AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include int main() { struct termios t; if (tcgetattr(0, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }]])],[tcl_cv_api_serial=termios],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no]) fi if test $tcl_cv_api_serial = no; then AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }]])],[tcl_cv_api_serial=termio],[tcl_cv_api_serial=no],[tcl_cv_api_serial=no]) fi if test $tcl_cv_api_serial = no; then AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }]])],[tcl_cv_api_serial=sgtty],[tcl_cv_api_serial=none],[tcl_cv_api_serial=none]) fi]) case $tcl_cv_api_serial in termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; esac ]) #-------------------------------------------------------------------- # TEA_PATH_X # # Locate the X11 header files and the X11 library archive. Try # the ac_path_x macro first, but if it doesn't find the X stuff # (e.g. because there's no xmkmf program) then check through # a list of possible directories. Under some conditions the # autoconf macro will return an include directory that contains # no include files, so double-check its result just to be safe. # # This should be called after TEA_CONFIG_CFLAGS as setting the # LIBS line can confuse some configure macro magic. # # Arguments: # none # # Results: # # Sets the following vars: # XINCLUDES # XLIBSW # PKG_LIBS (appends to) #-------------------------------------------------------------------- AC_DEFUN([TEA_PATH_X], [ if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then TEA_PATH_UNIX_X fi ]) AC_DEFUN([TEA_PATH_UNIX_X], [ AC_PATH_X not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include ]])],[],[not_really_there="yes"]) else if test ! -r $x_includes/X11/Xlib.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then AC_MSG_CHECKING([for X11 header files]) found_xincludes="no" AC_PREPROC_IFELSE([AC_LANG_SOURCE([[#include ]])],[found_xincludes="yes"],[found_xincludes="no"]) if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Xlib.h; then AC_MSG_RESULT([$i]) XINCLUDES=" -I$i" found_xincludes="yes" break fi done fi else if test "$x_includes" != ""; then XINCLUDES="-I$x_includes" found_xincludes="yes" fi fi if test "$found_xincludes" = "no"; then AC_MSG_RESULT([couldn't find any!]) fi if test "$no_x" = yes; then AC_MSG_CHECKING([for X11 libraries]) XLIBSW=nope dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" for i in $dirs ; do if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then AC_MSG_RESULT([$i]) XLIBSW="-L$i -lX11" x_libraries="$i" break fi done else if test "$x_libraries" = ""; then XLIBSW=-lX11 else XLIBSW="-L$x_libraries -lX11" fi fi if test "$XLIBSW" = nope ; then AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) fi if test "$XLIBSW" = nope ; then AC_MSG_RESULT([could not find any! Using -lX11.]) XLIBSW=-lX11 fi # TEA specific: if test x"${XLIBSW}" != x ; then PKG_LIBS="${PKG_LIBS} ${XLIBSW}" fi ]) #-------------------------------------------------------------------- # TEA_BLOCKING_STYLE # # The statements below check for systems where POSIX-style # non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. # On these systems (mostly older ones), use the old BSD-style # FIONBIO approach instead. # # Arguments: # none # # Results: # # Defines some of the following vars: # HAVE_SYS_IOCTL_H # HAVE_SYS_FILIO_H # USE_FIONBIO # O_NONBLOCK #-------------------------------------------------------------------- AC_DEFUN([TEA_BLOCKING_STYLE], [ AC_CHECK_HEADERS(sys/ioctl.h) AC_CHECK_HEADERS(sys/filio.h) TEA_CONFIG_SYSTEM AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) case $system in OSF*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; *) AC_MSG_RESULT([O_NONBLOCK]) ;; esac ]) #-------------------------------------------------------------------- # TEA_TIME_HANDLER # # Checks how the system deals with time.h, what time structures # are used on the system, and what fields the structures have. # # Arguments: # none # # Results: # # Defines some of the following vars: # USE_DELTA_FOR_TZ # HAVE_TM_GMTOFF # HAVE_TM_TZADJ # HAVE_TIMEZONE_VAR # #-------------------------------------------------------------------- AC_DEFUN([TEA_TIME_HANDLER], [ AC_CHECK_HEADERS(sys/time.h) AC_HEADER_TIME AC_STRUCT_TIMEZONE AC_CHECK_FUNCS(gmtime_r localtime_r mktime) AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct tm tm; (void)tm.tm_tzadj;]])], [tcl_cv_member_tm_tzadj=yes], [tcl_cv_member_tm_tzadj=no])]) if test $tcl_cv_member_tm_tzadj = yes ; then AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) fi AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct tm tm; (void)tm.tm_gmtoff;]])], [tcl_cv_member_tm_gmtoff=yes], [tcl_cv_member_tm_gmtoff=no])]) if test $tcl_cv_member_tm_gmtoff = yes ; then AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) fi # # Its important to include time.h in this check, as some systems # (like convex) have timezone functions, etc. # AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #include ]], [[extern long timezone; timezone += 1; exit (0);]])], [tcl_cv_timezone_long=yes], [tcl_cv_timezone_long=no])]) if test $tcl_cv_timezone_long = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) else # # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. # AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #include ]], [[extern time_t timezone; timezone += 1; exit (0);]])], [tcl_cv_timezone_time=yes], [tcl_cv_timezone_time=no])]) if test $tcl_cv_timezone_time = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) fi fi ]) #-------------------------------------------------------------------- # TEA_BUGGY_STRTOD # # Under Solaris 2.4, strtod returns the wrong value for the # terminating character under some conditions. Check for this # and if the problem exists use a substitute procedure # "fixstrtod" (provided by Tcl) that corrects the error. # Also, on Compaq's Tru64 Unix 5.0, # strtod(" ") returns 0.0 instead of a failure to convert. # # Arguments: # none # # Results: # # Might defines some of the following vars: # strtod (=fixstrtod) #-------------------------------------------------------------------- AC_DEFUN([TEA_BUGGY_STRTOD], [ AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) if test "$tcl_strtod" = 1; then AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include extern double strtod(); int main() { char *infString="Inf", *nanString="NaN", *spaceString=" "; char *term; double value; value = strtod(infString, &term); if ((term != infString) && (term[-1] == 0)) { exit(1); } value = strtod(nanString, &term); if ((term != nanString) && (term[-1] == 0)) { exit(1); } value = strtod(spaceString, &term); if (term == (spaceString+1)) { exit(1); } exit(0); }]])], [tcl_cv_strtod_buggy=ok], [tcl_cv_strtod_buggy=buggy], [tcl_cv_strtod_buggy=buggy])]) if test "$tcl_cv_strtod_buggy" = buggy; then AC_LIBOBJ([fixstrtod]) USE_COMPAT=1 AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) fi fi ]) #-------------------------------------------------------------------- # TEA_TCL_LINK_LIBS # # Search for the libraries needed to link the Tcl shell. # Things like the math library (-lm), socket stuff (-lsocket vs. # -lnsl), zlib (-lz) and libtommath (-ltommath) are dealt with here. # # Arguments: # None. # # Results: # # Might append to the following vars: # LIBS # MATH_LIBS # # Might define the following vars: # HAVE_NET_ERRNO_H # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_LINK_LIBS], [ #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. #-------------------------------------------------------------------- AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) AC_CHECK_HEADER(net/errno.h, [ AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have ?])]) #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) if test "$tcl_checkSocket" = 1; then AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) fi AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, [LIBS="$LIBS -lnsl"])]) AC_CHECK_FUNC(mp_log_u32, , [AC_CHECK_LIB(tommath, mp_log_u32, [LIBS="$LIBS -ltommath"])]) AC_CHECK_FUNC(deflateSetHeader, , [AC_CHECK_LIB(z, deflateSetHeader, [LIBS="$LIBS -lz"])]) ]) #-------------------------------------------------------------------- # TEA_TCL_EARLY_FLAGS # # Check for what flags are needed to be passed so the correct OS # features are available. # # Arguments: # None # # Results: # # Might define the following vars: # _ISOC99_SOURCE # _LARGEFILE64_SOURCE # _LARGEFILE_SOURCE64 # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_EARLY_FLAG],[ AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[$2]], [[$3]])], [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no,[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[[#define ]$1[ 1 ]$2]], [[$3]])], [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no)])) if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) tcl_flags="$tcl_flags $1" fi ]) AC_DEFUN([TEA_TCL_EARLY_FLAGS],[ AC_MSG_CHECKING([for required early compiler flags]) tcl_flags="" TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], [char *p = (char *)strtoll; char *q = (char *)strtoull;]) TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include ], [struct stat64 buf; int i = stat64("/", &buf);]) TEA_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include ], [char *p = (char *)open64;]) if test "x${tcl_flags}" = "x" ; then AC_MSG_RESULT([none]) else AC_MSG_RESULT([${tcl_flags}]) fi ]) #-------------------------------------------------------------------- # TEA_TCL_64BIT_FLAGS # # Check for what is defined in the way of 64-bit features. # # Arguments: # None # # Results: # # Might define the following vars: # TCL_WIDE_INT_IS_LONG # TCL_WIDE_INT_TYPE # HAVE_STRUCT_DIRENT64, HAVE_DIR64 # HAVE_STRUCT_STAT64 # HAVE_TYPE_OFF64_T # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_64BIT_FLAGS], [ AC_MSG_CHECKING([for 64-bit integer type]) AC_CACHE_VAL(tcl_cv_type_64bit,[ tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[__int64 value = (__int64) 0;]])], [tcl_type_64bit=__int64],[tcl_type_64bit="long long"]) # See if we could use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[switch (0) { case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ; }]])],[tcl_cv_type_64bit=${tcl_type_64bit}],[])]) if test "${tcl_cv_type_64bit}" = none ; then AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Do 'long' and 'long long' have the same size (64-bit)?]) AC_MSG_RESULT([yes]) elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # TEA specific: We actually want to use the default tcl.h checks in # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* AC_MSG_RESULT([using Tcl header defaults]) else AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, [What type should be used to define wide integers?]) AC_MSG_RESULT([${tcl_cv_type_64bit}]) # Now check for auxiliary declarations AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #include ]], [[struct dirent64 p;]])], [tcl_cv_struct_dirent64=yes],[tcl_cv_struct_dirent64=no])]) if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in ?]) fi AC_CACHE_CHECK([for DIR64], tcl_cv_DIR64,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include #include ]], [[struct dirent64 *p; DIR64 d = opendir64("."); p = readdir64(d); rewinddir64(d); closedir64(d);]])], [tcl_cv_DIR64=yes], [tcl_cv_DIR64=no])]) if test "x${tcl_cv_DIR64}" = "xyes" ; then AC_DEFINE(HAVE_DIR64, 1, [Is 'DIR64' in ?]) fi AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[struct stat64 p; ]])], [tcl_cv_struct_stat64=yes], [tcl_cv_struct_stat64=no])]) if test "x${tcl_cv_struct_stat64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in ?]) fi AC_CHECK_FUNCS(open64 lseek64) AC_MSG_CHECKING([for off64_t]) AC_CACHE_VAL(tcl_cv_type_off64_t,[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[off64_t offset; ]])], [tcl_cv_type_off64_t=yes], [tcl_cv_type_off64_t=no])]) dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the dnl functions lseek64 and open64 are defined. if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi ]) ## ## Here ends the standard Tcl configuration bits and starts the ## TEA specific functions ## #------------------------------------------------------------------------ # TEA_INIT -- # # Init various Tcl Extension Architecture (TEA) variables. # This should be the first called TEA_* macro. # # Arguments: # none # # Results: # # Defines and substs the following vars: # CYGPATH # EXEEXT # Defines only: # TEA_VERSION # TEA_INITED # TEA_PLATFORM (windows or unix) # # "cygpath" is used on windows to generate native path names for include # files. These variables should only be used with the compiler and linker # since they generate native path names. # # EXEEXT # Select the executable extension based on the host type. This # is a lightweight replacement for AC_EXEEXT that doesn't require # a compiler. #------------------------------------------------------------------------ AC_DEFUN([TEA_INIT], [ TEA_VERSION="3.13" AC_MSG_CHECKING([TEA configuration]) if test x"${PACKAGE_NAME}" = x ; then AC_MSG_ERROR([ The PACKAGE_NAME variable must be defined by your TEA configure.ac]) fi AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) # If the user did not set CFLAGS, set it now to keep macros # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi case "`uname -s`" in *win32*|*WIN32*|*MINGW32_*|*MINGW64_*|*MSYS_*) AC_CHECK_PROG(CYGPATH, cygpath, cygpath -m, echo) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *CYGWIN_*) EXEEXT=".exe" # CYGPATH and TEA_PLATFORM are determined later in LOAD_TCLCONFIG ;; *) CYGPATH=echo # Maybe we are cross-compiling.... case ${host_alias} in *mingw32*) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *) EXEEXT="" TEA_PLATFORM="unix" ;; esac ;; esac # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi AC_MSG_NOTICE([configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}]) AC_SUBST(EXEEXT) AC_SUBST(CYGPATH) # This package name must be replaced statically for AC_SUBST to work AC_SUBST(PKG_LIB_FILE) AC_SUBST(PKG_LIB_FILE8) AC_SUBST(PKG_LIB_FILE9) # Substitute STUB_LIB_FILE in case package creates a stub library too. AC_SUBST(PKG_STUB_LIB_FILE) # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) AC_SUBST(PKG_TCL_SOURCES) AC_SUBST(PKG_HEADERS) AC_SUBST(PKG_INCLUDES) AC_SUBST(PKG_LIBS) AC_SUBST(PKG_CFLAGS) # Configure the installer. TEA_INSTALLER ]) #------------------------------------------------------------------------ # TEA_ADD_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_SOURCES # PKG_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_SOURCES], [ vars="$@" for i in $vars; do case $i in [\$]*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then AC_MSG_ERROR([could not find source file '$i']) fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done AC_SUBST(PKG_SOURCES) AC_SUBST(PKG_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_STUB_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_STUB_SOURCES # PKG_STUB_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_STUB_SOURCES], [ vars="$@" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then AC_MSG_ERROR([could not find stub source file '$i']) fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_TCL_SOURCES -- # # Specify one or more Tcl source files. These should be platform # independent runtime files. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_TCL_SOURCES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_TCL_SOURCES], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done AC_SUBST(PKG_TCL_SOURCES) ]) #------------------------------------------------------------------------ # TEA_ADD_HEADERS -- # # Specify one or more source headers. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_HEADERS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_HEADERS], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find header file '${srcdir}/$i']) fi PKG_HEADERS="$PKG_HEADERS $i" done AC_SUBST(PKG_HEADERS) ]) #------------------------------------------------------------------------ # TEA_ADD_INCLUDES -- # # Specify one or more include dirs. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_INCLUDES], [ vars="$@" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done AC_SUBST(PKG_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_ADD_LIBS -- # # Specify one or more libraries. Users should check for # the right platform before adding to their list. For Windows, # libraries provided in "foo.lib" format will be converted to # "-lfoo" when using GCC (mingw). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_LIBS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_LIBS], [ vars="$@" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.[[lL]][[iI]][[bB]][$]/-l\1/'` fi PKG_LIBS="$PKG_LIBS $i" done AC_SUBST(PKG_LIBS) ]) #------------------------------------------------------------------------ # TEA_ADD_CFLAGS -- # # Specify one or more CFLAGS. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_CFLAGS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CFLAGS], [ PKG_CFLAGS="$PKG_CFLAGS $@" AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_CLEANFILES -- # # Specify one or more CLEANFILES. # # Arguments: # one or more file names to clean target # # Results: # # Appends to CLEANFILES, already defined for subst in LOAD_TCLCONFIG #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CLEANFILES], [ CLEANFILES="$CLEANFILES $@" ]) #------------------------------------------------------------------------ # TEA_PREFIX -- # # Handle the --prefix=... option by defaulting to what Tcl gave # # Arguments: # none # # Results: # # If --prefix or --exec-prefix was not specified, $prefix and # $exec_prefix will be set to the values given to Tcl when it was # configured. #------------------------------------------------------------------------ AC_DEFUN([TEA_PREFIX], [ if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) prefix=${TCL_PREFIX} else AC_MSG_NOTICE([--prefix defaulting to /usr/local]) prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) exec_prefix=${TCL_EXEC_PREFIX} else AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) exec_prefix=$prefix fi fi ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER_CC -- # # Do compiler checks the way we want. This is just a replacement # for AC_PROG_CC in TEA configure.ac files to make them cleaner. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER_CC], [ # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. AC_PROG_CC AC_PROG_CPP #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- AC_PROG_MAKE_SET #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- AC_CHECK_TOOL(RANLIB, ranlib) #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- AC_OBJEXT AC_EXEEXT ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER -- # # Do compiler checks that use the compiler. This must go after # TEA_SETUP_COMPILER_CC, which does the actual compiler check. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER], [ # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. AC_REQUIRE([TEA_SETUP_COMPILER_CC]) #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then AC_CACHE_CHECK([if the compiler understands -pipe], tcl_cv_cc_pipe, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[tcl_cv_cc_pipe=yes],[tcl_cv_cc_pipe=no]) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- AC_C_BIGENDIAN ]) #------------------------------------------------------------------------ # TEA_MAKE_LIB -- # # Generate a line that can be used to build a shared/unshared library # in a platform independent manner. # # Arguments: # none # # Requires: # # Results: # # Defines the following vars: # CFLAGS - Done late here to note disturb other AC macros # MAKE_LIB - Command to execute to build the Tcl library; # differs depending on whether or not Tcl is being # compiled as a shared library. # MAKE_SHARED_LIB Makefile rule for building a shared library # MAKE_STATIC_LIB Makefile rule for building a static library # MAKE_STUB_LIB Makefile rule for building a stub library # VC_MANIFEST_EMBED_DLL Makefile rule for embedded VC manifest in DLL # VC_MANIFEST_EMBED_EXE Makefile rule for embedded VC manifest in EXE #------------------------------------------------------------------------ AC_DEFUN([TEA_MAKE_LIB], [ if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" AC_EGREP_CPP([manifest needed], [ #if defined(_MSC_VER) && _MSC_VER >= 1400 print("manifest needed") #endif ], [ # Could do a CHECK_PROG for mt, but should always be with MSVC8+ VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;2 ; fi" VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;1 ; fi" MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" TEA_ADD_CLEANFILES([*.manifest]) ]) MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\[$]@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${LDFLAGS} \${LDFLAGS_DEFAULT} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}" PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9" if test "${TCL_MAJOR_VERSION}" -gt 8" ; then PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}" else PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}" AC_DEFINE(TCL_MAJOR_VERSION, 8, [Compile for Tcl8?]) fi if test "${TEA_PLATFORM}" = "windows" ; then if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test "$GCC" = "yes"; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc" fi eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else if test "$GCC" = "yes"; then PACKAGE_LIB_PREFIX=lib${PACKAGE_LIB_PREFIX} fi eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi AC_SUBST(MAKE_LIB) AC_SUBST(MAKE_SHARED_LIB) AC_SUBST(MAKE_STATIC_LIB) AC_SUBST(MAKE_STUB_LIB) AC_SUBST(RANLIB_STUB) AC_SUBST(VC_MANIFEST_EMBED_DLL) AC_SUBST(VC_MANIFEST_EMBED_EXE) ]) #------------------------------------------------------------------------ # TEA_LIB_SPEC -- # # Compute the name of an existing object library located in libdir # from the given base name and produce the appropriate linker flags. # # Arguments: # basename The base name of the library without version # numbers, extensions, or "lib" prefixes. # extra_dir Extra directory in which to search for the # library. This location is used first, then # $prefix/$exec-prefix, then some defaults. # # Requires: # TEA_INIT and TEA_PREFIX must be called first. # # Results: # # Defines the following vars: # ${basename}_LIB_NAME The computed library name. # ${basename}_LIB_SPEC The computed linker flags. #------------------------------------------------------------------------ AC_DEFUN([TEA_LIB_SPEC], [ AC_MSG_CHECKING([for $1 library]) # Look in exec-prefix for the library (defined by TEA_PREFIX). tea_lib_name_dir="${exec_prefix}/lib" # Or in a user-specified location. if test x"$2" != x ; then tea_extra_lib_dir=$2 else tea_extra_lib_dir=NONE fi for i in \ `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib64/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib64/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do if test -f "$i" ; then tea_lib_name_dir=`dirname $i` $1_LIB_NAME=`basename $i` $1_LIB_PATH_NAME=$i break fi done if test "${TEA_PLATFORM}" = "windows"; then $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" else # Strip off the leading "lib" and trailing ".a" or ".so" tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" fi if test "x${$1_LIB_NAME}" = x ; then AC_MSG_ERROR([not found]) else AC_MSG_RESULT([${$1_LIB_SPEC}]) fi ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TCL_HEADERS -- # # Locate the private Tcl include files # # Arguments: # # Requires: # TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has # already been called. # # Results: # # Substitutes the following vars: # TCL_TOP_DIR_NATIVE # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [ # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} AC_REQUIRE([TEA_PUBLIC_TCL_HEADERS]) AC_MSG_CHECKING([for Tcl private include files]) TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" # Check to see if tclPort.h isn't already with the public headers # Don't look for tclInt.h because that resides with tcl.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tclh}/tclWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tclh}/tclUnixPort.h"; then result="private headers found with public headers" else TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" if test "${TEA_PLATFORM}" = "windows"; then TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" else TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TCL_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -d "${TCL_BIN_DIR}/Headers" -a \ -d "${TCL_BIN_DIR}/PrivateHeaders"; then TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" else TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TCL_INCLUDES}" else if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then AC_MSG_ERROR([Cannot find private header tclInt.h in ${TCL_SRC_DIR}]) fi result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" fi fi AC_SUBST(TCL_TOP_DIR_NATIVE) AC_SUBST(TCL_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TCL_HEADERS -- # # Locate the installed public Tcl header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tclinclude switch to configure. # Result is cached. # # Substitutes the following vars: # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [ AC_MSG_CHECKING([for Tcl public headers]) AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tclh, [ # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) fi else list="" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) else AC_MSG_RESULT([${ac_cv_c_tclh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TCL_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TK_HEADERS -- # # Locate the private Tk include files # # Arguments: # # Requires: # TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has # already been called. # # Results: # # Substitutes the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [ # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} AC_REQUIRE([TEA_PUBLIC_TK_HEADERS]) AC_MSG_CHECKING([for Tk private include files]) TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" # Check to see if tkPort.h isn't already with the public headers # Don't look for tkInt.h because that resides with tk.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tkh}/tkWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tkh}/tkUnixPort.h"; then result="private headers found with public headers" else TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" if test "${TEA_PLATFORM}" = "windows"; then TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" else TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TK_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" # Detect and add ttk subdir if test -d "${TK_SRC_DIR}/generic/ttk"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" fi if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_XLIB_DIR_NATIVE}\"" fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" fi if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TK_DEFS} in *TK_FRAMEWORK*) if test -d "${TK_BIN_DIR}/Headers" -a \ -d "${TK_BIN_DIR}/PrivateHeaders"; then TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" else TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TK_INCLUDES}" else if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then AC_MSG_ERROR([Cannot find private header tkInt.h in ${TK_SRC_DIR}]) fi result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" fi fi AC_SUBST(TK_TOP_DIR_NATIVE) AC_SUBST(TK_XLIB_DIR_NATIVE) AC_SUBST(TK_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TK_HEADERS -- # # Locate the installed public Tk header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tkinclude switch to configure. # Result is cached. # # Substitutes the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TK_HEADERS], [ AC_MSG_CHECKING([for Tk public headers]) AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files], with_tkinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tkh, [ # Use the value from --with-tkinclude, if it was given if test x"${with_tkinclude}" != x ; then if test -f "${with_tkinclude}/tk.h" ; then ac_cv_c_tkh=${with_tkinclude} else AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) fi else list="" if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers directory. case ${TK_DEFS} in *TK_FRAMEWORK*) list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tk is not installed, # and in that situation, look there before installed locations. if test -f "${TK_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tk's --prefix location, # relative to directory of tkConfig.sh, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TK_PREFIX}/include 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TK_INCLUDE_SPEC}" != x ; then d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tk.h" ; then ac_cv_c_tkh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tkh}" = x ; then AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) else AC_MSG_RESULT([${ac_cv_c_tkh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_INCLUDES) if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then # On Windows and Aqua, we need the X compat headers AC_MSG_CHECKING([for X11 header files]) if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_XINCLUDES) fi AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) fi ]) #------------------------------------------------------------------------ # TEA_PATH_CONFIG -- # # Locate the ${1}Config.sh file and perform a sanity check on # the ${1} compile flags. These are used by packages like # [incr Tk] that load *Config.sh files from more than Tcl and Tk. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-$1=... # # Defines the following vars: # $1_BIN_DIR Full path to the directory containing # the $1Config.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CONFIG], [ # # Ok, lets find the $1 configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-$1 # if test x"${no_$1}" = x ; then # we reset no_$1 in case something fails here no_$1=true AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) AC_MSG_CHECKING([for $1 configuration]) AC_CACHE_VAL(ac_cv_c_$1config,[ # First check to see if --with-$1 was specified. if test x"${with_$1config}" != x ; then case ${with_$1config} in */$1Config.sh ) if test -f ${with_$1config}; then AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` fi;; esac if test -f "${with_$1config}/$1Config.sh" ; then ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` else AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) fi fi # then check for a private $1 installation if test x"${ac_cv_c_$1config}" = x ; then for i in \ ../$1 \ `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../$1 \ `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../../$1 \ `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ${srcdir}/../$1 \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi if test -f "$i/unix/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i/unix; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_$1config}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/pkg/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_$1config}" = x ; then $1_BIN_DIR="# no $1 configs found" AC_MSG_WARN([Cannot find $1 configuration definitions]) exit 0 else no_$1= $1_BIN_DIR=${ac_cv_c_$1config} AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG -- # # Load the $1Config.sh file # # Arguments: # # Requires the following vars to be set: # $1_BIN_DIR # # Results: # # Substitutes the following vars: # $1_SRC_DIR # $1_LIB_FILE # $1_LIB_SPEC #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG], [ AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) if test -f "${$1_BIN_DIR}/$1Config.sh" ; then AC_MSG_RESULT([loading]) . "${$1_BIN_DIR}/$1Config.sh" else AC_MSG_RESULT([file not found]) fi # # If the $1_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable $1_LIB_SPEC will be set to the value # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC # instead of $1_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. # if test -f "${$1_BIN_DIR}/Makefile" ; then AC_MSG_WARN([Found Makefile - using build library specs for $1]) $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} $1_INCLUDE_SPEC=${$1_BUILD_INCLUDE_SPEC} $1_LIBRARY_PATH=${$1_LIBRARY_PATH} fi AC_SUBST($1_VERSION) AC_SUBST($1_BIN_DIR) AC_SUBST($1_SRC_DIR) AC_SUBST($1_LIB_FILE) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_STUB_LIB_FILE) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_PATH) # Allow the caller to prevent this auto-check by specifying any 2nd arg AS_IF([test "x$2" = x], [ # Check both upper and lower-case variants # If a dev wanted non-stubs libs, this function could take an option # to not use _STUB in the paths below AS_IF([test "x${$1_STUB_LIB_SPEC}" = x], [TEA_LOAD_CONFIG_LIB(translit($1,[a-z],[A-Z])_STUB)], [TEA_LOAD_CONFIG_LIB($1_STUB)]) ]) ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG_LIB -- # # Helper function to load correct library from another extension's # ${PACKAGE}Config.sh. # # Results: # Adds to LIBS the appropriate extension library #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG_LIB], [ AC_MSG_CHECKING([For $1 library for LIBS]) # This simplifies the use of stub libraries by automatically adding # the stub lib to your path. Normally this would add to SHLIB_LD_LIBS, # but this is called before CONFIG_CFLAGS. More importantly, this adds # to PKG_LIBS, which becomes LIBS, and that is only used by SHLIB_LD. if test "x${$1_LIB_SPEC}" != "x" ; then if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes" ; then TEA_ADD_LIBS([\"`${CYGPATH} ${$1_LIB_PATH}`\"]) AC_MSG_RESULT([using $1_LIB_PATH ${$1_LIB_PATH}]) else TEA_ADD_LIBS([${$1_LIB_SPEC}]) AC_MSG_RESULT([using $1_LIB_SPEC ${$1_LIB_SPEC}]) fi else AC_MSG_RESULT([file not found]) fi ]) #------------------------------------------------------------------------ # TEA_EXPORT_CONFIG -- # # Define the data to insert into the ${PACKAGE}Config.sh file # # Arguments: # # Requires the following vars to be set: # $1 # # Results: # Substitutes the following vars: #------------------------------------------------------------------------ AC_DEFUN([TEA_EXPORT_CONFIG], [ #-------------------------------------------------------------------- # These are for $1Config.sh #-------------------------------------------------------------------- # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib) eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}" if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}" eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}" else eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`" eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`" fi $1_BUILD_LIB_SPEC="-L`$CYGPATH $(pwd)` ${$1_LIB_FLAG}" $1_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` ${$1_LIB_FLAG}" $1_BUILD_STUB_LIB_SPEC="-L`$CYGPATH $(pwd)` [$]{$1_STUB_LIB_FLAG}" $1_STUB_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` [$]{$1_STUB_LIB_FLAG}" $1_BUILD_STUB_LIB_PATH="`$CYGPATH $(pwd)`/[$]{PKG_STUB_LIB_FILE}" $1_STUB_LIB_PATH="`$CYGPATH ${pkglibdir}`/[$]{PKG_STUB_LIB_FILE}" AC_SUBST($1_BUILD_LIB_SPEC) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_PATH) AC_SUBST($1_STUB_LIB_PATH) AC_SUBST(MAJOR_VERSION) AC_SUBST(MINOR_VERSION) AC_SUBST(PATCHLEVEL) ]) #------------------------------------------------------------------------ # TEA_INSTALLER -- # # Configure the installer. # # Arguments: # none # # Results: # Substitutes the following vars: # INSTALL # INSTALL_DATA_DIR # INSTALL_DATA # INSTALL_PROGRAM # INSTALL_SCRIPT # INSTALL_LIBRARY #------------------------------------------------------------------------ AC_DEFUN([TEA_INSTALLER], [ INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c' INSTALL_DATA_DIR='${INSTALL} -d -m 755' INSTALL_DATA='${INSTALL} -m 644' INSTALL_PROGRAM='${INSTALL} -m 755' INSTALL_SCRIPT='${INSTALL} -m 755' TEA_CONFIG_SYSTEM case $system in HP-UX-*) INSTALL_LIBRARY='${INSTALL} -m 755' ;; *) INSTALL_LIBRARY='${INSTALL} -m 644' ;; esac AC_SUBST(INSTALL) AC_SUBST(INSTALL_DATA_DIR) AC_SUBST(INSTALL_DATA) AC_SUBST(INSTALL_PROGRAM) AC_SUBST(INSTALL_SCRIPT) AC_SUBST(INSTALL_LIBRARY) ]) ### # Tip 430 - ZipFS Modifications ### #------------------------------------------------------------------------ # TEA_ZIPFS_SUPPORT # Locate a zip encoder installed on the system path, or none. # # Arguments: # none # # Results: # Substitutes the following vars: # MACHER_PROG # ZIP_PROG # ZIP_PROG_OPTIONS # ZIP_PROG_VFSSEARCH # ZIP_INSTALL_OBJS #------------------------------------------------------------------------ AC_DEFUN([TEA_ZIPFS_SUPPORT], [ MACHER_PROG="" ZIP_PROG="" ZIP_PROG_OPTIONS="" ZIP_PROG_VFSSEARCH="" ZIP_INSTALL_OBJS="" AC_MSG_CHECKING([for macher]) AC_CACHE_VAL(ac_cv_path_macher, [ search_path=`echo ${PATH} | sed -e 's/:/ /g'` for dir in $search_path ; do for j in `ls -r $dir/macher 2> /dev/null` \ `ls -r $dir/macher 2> /dev/null` ; do if test x"$ac_cv_path_macher" = x ; then if test -f "$j" ; then ac_cv_path_macher=$j break fi fi done done ]) if test -f "$ac_cv_path_macher" ; then MACHER_PROG="$ac_cv_path_macher" AC_MSG_RESULT([$MACHER_PROG]) AC_MSG_RESULT([Found macher in environment]) fi AC_MSG_CHECKING([for zip]) AC_CACHE_VAL(ac_cv_path_zip, [ search_path=`echo ${PATH} | sed -e 's/:/ /g'` for dir in $search_path ; do for j in `ls -r $dir/zip 2> /dev/null` \ `ls -r $dir/zip 2> /dev/null` ; do if test x"$ac_cv_path_zip" = x ; then if test -f "$j" ; then ac_cv_path_zip=$j break fi fi done done ]) if test -f "$ac_cv_path_zip" ; then ZIP_PROG="$ac_cv_path_zip" AC_MSG_RESULT([$ZIP_PROG]) ZIP_PROG_OPTIONS="-rq" ZIP_PROG_VFSSEARCH="*" AC_MSG_RESULT([Found INFO Zip in environment]) # Use standard arguments for zip else # It is not an error if an installed version of Zip can't be located. # We can use the locally distributed minizip instead ZIP_PROG="./minizip${EXEEXT_FOR_BUILD}" ZIP_PROG_OPTIONS="-o -r" ZIP_PROG_VFSSEARCH="*" ZIP_INSTALL_OBJS="minizip${EXEEXT_FOR_BUILD}" AC_MSG_RESULT([No zip found on PATH. Building minizip]) fi AC_SUBST(MACHER_PROG) AC_SUBST(ZIP_PROG) AC_SUBST(ZIP_PROG_OPTIONS) AC_SUBST(ZIP_PROG_VFSSEARCH) AC_SUBST(ZIP_INSTALL_OBJS) ]) # Local Variables: # mode: autoconf # End: ./nsf2.4.0/m4/tcl.m4.rej000644 000766 000024 00000011424 14270751635 015327 0ustar00neumannstaff000000 000000 *************** *** 2749,2754 **** # This package name must be replaced statically for AC_SUBST to work AC_SUBST(PKG_LIB_FILE) # Substitute STUB_LIB_FILE in case package creates a stub library too. AC_SUBST(PKG_STUB_LIB_FILE) --- 2749,2756 ---- # This package name must be replaced statically for AC_SUBST to work AC_SUBST(PKG_LIB_FILE) + AC_SUBST(PKG_LIB_FILE8) + AC_SUBST(PKG_LIB_FILE9) # Substitute STUB_LIB_FILE in case package creates a stub library too. AC_SUBST(PKG_STUB_LIB_FILE) *************** *** 3214,3219 **** # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then PRACTCL_NAME_LIBRARY="%LIBRARY_PREFIX%%LIBRARY_NAME%%LIBRARY_VERSION_NODOTS%" if test "${SHARED_BUILD}" = "1" ; then --- 3216,3228 ---- # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- + PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}" + PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9" + if test "${TCL_MAJOR_VERSION}" -gt 8 ; then + PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}" + else + PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}" + fi if test "${TEA_PLATFORM}" = "windows" ; then PRACTCL_NAME_LIBRARY="%LIBRARY_PREFIX%%LIBRARY_NAME%%LIBRARY_VERSION_NODOTS%" if test "${SHARED_BUILD}" = "1" ; then *************** *** 3226,3240 **** if test "$GCC" = "yes"; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc" fi eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_LIB_FILE=lib${PKG_LIB_FILE} fi fi # Some packages build their own stubs libraries - eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi --- 3235,3253 ---- if test "$GCC" = "yes"; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc" fi + eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else + eval eval "PKG_LIB_FILE8=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + eval eval "PKG_LIB_FILE9=${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_LIB_FILE=lib${PKG_LIB_FILE} fi fi # Some packages build their own stubs libraries + eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi *************** *** 3249,3261 **** if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries - eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # Store the raw CFLAGS before we add the trimmings --- 3262,3278 ---- if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi + eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" + eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else + eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" + eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries + eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # Store the raw CFLAGS before we add the trimmings ./nsf2.4.0/doc/next-tutorial/stack2.png000644 000766 000024 00000030052 12501766547 020466 0ustar00neumannstaff000000 000000 PNG  IHDRDHcYiCCPICC ProfilexXgTM 9sNsEҐd0%(J(("J$A@1"H ޳g:zUs>y4FE89P"]x#t֞hop\r:$Y!^ޑF9," OG!t,'?l{~ϱC'yzF@|yb~XPP${z̑ 9,/?~ž^}zzȍ"Â=y FF\I#}S oO{~?7cDijmcGqv_o{@{2,' GAvI(YJGNFVfoM;_,vFcDrcH'O p~ $P@S` 3pdB@8 @"HY (%T:h- x`|X[ Jb!AHT M2l gBh(J\@7;PB/hZ6aL`NXU` ~p8"7] ?ë("P(I JerA"PPBTՆCQh,̓Dh2:} .A_E7{ÁǨaL0N?aLsӄ<|aX&0VkubN(vXq8 %K:pc <ύ]$|!ߎ(h()(,))PPTQQP|" ;B !PD'^VD"QhM 3ğ$:IJ&&U:I/H+Bڔ.Q)k(Pܠ2:NUJL5FZZڍ:" '1R;44!ٴt8:!::oJt(z~z=z2}2}}/,0 C Cua%F:FFXRL(&!&`FL̜:>c,,,>,,7Xlema}͆fcf;vm]̞>sqpsTr qrrqqqs>\b jZȣSók{wwOϞ/k~ />7@@ 9>u!a!Gtyaa8:W""Z"""OE*AEbbbb#ⰸxyQ DDĄ$IRG2FNrFI\*IEꫴY>_222U2/edMeddrrO) ˷WWQ0HhحT,\< bHz\O5%(FoA7qIcZGCV;m~mo+s:::tF6Gg1333\2R474504!Ԙ,*51#ٚ330o-L-,^XXY k.h#k`gKon[kfkc^>ھہաaQ1qIӠ3ss >*>?(|0`[}wjwO[GZmOK U/2%wOϜo?_߂b^@I@ ˠ`!;tA= K W /_0 Elb@h͘ҘoƆ;qd.0r<:ߝ0sTc1cpDBbP$ܤɎm))'RfSRҨ"&OOΐ(9%UM8%{i9J9`τy~V\ܸ<| M )./yV[z,l 9˳7/\dtB[Sʡ+lWTVO_S\SSQSE-\szK7nd5O7=n>o4k쾥r&fHRts;mmMwVWz~N;=}#c3s˯k۽O{{{z=4|Oƣ{jwTZ+>nVnQi}mthX׸ç&O6ߧb^xyu7oEޘV??3Y?|X8=W3/7opɧ>|KWiZrZ=r JݫVoBֶ37X7Tٷ9ux]#׫ݐ0߹ ¾,W@ 俿g 1EN \К!bA*Chyf$3Ͱxahi]P2QU璠DKKKO v5W**&))T1VUTRǪ7ѩYUckgo\`R`ovEV6)v))INǝ]bD pv'{xyEOVox84< T9zllc4'yRxR9XNRg2љ;YkN͟yuf‘sv;zŖK*VUB S-5o85xk qpS|֔;mw=#AUOmoÛ}MZl|55hصe?O |qp+bo8R5ef]R?s]i_iYwE*fuiÍ?6Ӷ¶]v~I2_Q6hA V gEI^B4yt F4S<&/ M"< |95MB-7EgI 򒶗1UVUf֪a%ͦC[f0o8c4ihdlbj?IanV)Ӳ9gΊ  ,(+),c;t"% J*W5ט9^;xݫFhC n_j|uT/Ao`C>GʃC kh>37~j̈́ݤ /]_v{s˴;Y4~xq`qd!gE/_Q_?{abGjZzІOM-m_,JM,qm(NHTilik3b`bead_+\@JhXxD zk2We.ʗ*SUTNVIPPUwgϯåˡǩiccceijdNcAڏ-wl6m:9/|=[='^_{~X\ ?%l-V19| 6HB\v|YB$LOIҘZV~djFlfPlS:speȥ̣ AιEK%K?M0^>rq@@`+#WGjFj=6x}FǍݞjz<2Η~_m_X\xѳѻpoJo_>=8<;2GϺߛhQ=UU7GFN83Uy/#879߳sbׯF3/SV ku'&~ BB{Wݾ s` ?Ns7~` 0"զRijc` <@08ґ 8xV!<ICzHxJ.Bm3h`8?E5Tm G$&Ӊ%a` & (!/FF')FC9AeFEFD#OsV.. =4C(/3LLWXrYX_`e9+/\'#"d /𔔐ܐz$],"/))JbRrJjZ}55okhO,ꡑlhcjeRk:d݂ueU-}}5g nGgךO?s_`[0mHp@DوQcb[⫏ :!x5Y~#?}#aO-3  8oDY:N2p Qk !FHQl@(фnC#"La 8.{?zAcfIc2nEAGE1I$\&Rc$3R+|Q6cWhhh`Lzr 6F3ƷLT̵,, ^pHsLRz]c W)ЎsaF [Ȕtڔ"{BM^SA@F hkiYiVČLBLϘO'Y[XWL1:;>wfq9p;70{^w/˿#;(1}k4#FƴƊ9ϐpxV"UR~ gjmɁLSgsΌF /-yVuA"t2y5249n4Ͷ i{~uծ:zGPCzOv>B묷3?>R }YttyuN[;={GEt\[;H Xʐ8ø{nE%~IDATx xSUWڴ-*>F2>W0:>@||^8 (-" *Kp>0ʳ-QA*-شMiB]k4MNf~;_$;{YVp ` ` 03 0Q}xjਾ}l< D pT>6fZ8oo  >uG6>h1ݴ8wi E N6s>UֳP^pU[OGtCVv.*x>m)*L_BU㵭:-ʧ [J[3Ʈc셑 4 ''~b̹bk˱K8ѩ aoV.{u_'qOm'wxBLJW B?c=}< CI]p+caQ`\+ü'>cg۾%ƛ?kvV:6w=:2-ElF_ #GZ ?-'~v7˰F7&+@/}n#5B' 0[cB ˖jdY^Ҙtx!nx"L8n{b1loϝ,e'H&\6wIbxrpSLu[8|4R$??LCoZE1qB7qD< pc`l-x \ K~Eѻ*etA|FxiM<rXbM.8Tjt@E-qfM&/41Cw^$? `\~&=j֧PQ}3n% (V;Ay**>EK/ft.>̛C'uI~]?%wA]b&.Ʌ ΂oRßȀ'?g;? sWU@-:2OXت0k(Y< c]+a0XV>az^C(/$q0^5D]=u]0`_!Mo(]Q>6+3&ϧt*mjzGCapb!i]U$OopCЂ|Iҿɯڦk?OSM$#qCGSCgi_#ӿ0vljeERFdx}Ѐ +$aj9!-7vN,z# %1܊k0bx ܶ)RR_ܚY#:)2uKX i"P_υV;ՒL`zV[8|py8Cl*Bza{#@84Nb"^8ohlE p"6HHNxEl : 0@#`#u8-`#F 0FpZ+G-b`ᴈW[)i 4R6R"^8ohlE p"6HHNxEl : 0@#`#u8-y"F `^HNb{)uc`Ѱr,0 j_Ąa[umPρmҧFm)߼ёvn]s[@FӨXO:-I`Ҳ% 㗓r{qWh䖡[>ㄏ{ KNhITy3s6Mރ3%/iȯy%pEo~9Y@|:s=-З~C6[5: t6ҍ!.×ϥ!SEazh2ObcDPkom>=8!^8"8U{GyrثĿ^^:&_<|8ZWr?R^|VpJz,Lv|wpk(6"pJz8oYXeG%cahx6QW v1?AvwC"yW?YitP\H"\~smOH6eaMH_4 $$wߏ[q+kރ} ao]_xVsM/pV'?{zaᒳǘTroo8 '}=CcVJk ={@=oBMzaL/d$XW h]itm|HLܒ[x 1zk7Lyj6,7_Bp'a$Xz؋poa[ `}Ӆx9 >m8Xe6 jEZ+. @ln_: V}lv;)+Y?6MƟj81 o{iHnlSHOUZ~<oN_rԸbex+6rb'XςuQߒ(Y04oX(2gQ/뾻|8+#6.k@4mb_~r+2t8Vk?i=Wz]0{9)΃0{-+5(I1)c3@}Ks5ˬ 2é1pUCV7V9Vi+E?H,wO /V~mgso4Yfä뮔ycLV0``7oʽxzHؔ+~};~V +r@a]*4"<8<^{)` `ux2/erWS fpVB-[!(Vkޗu4[lgR]6BZNĸ,v⑻F4$px~ ETȝ+[1i[~VڻSm:,ss!) .Nz]1~u 2M^8[IIMPFQ9-8-op%T(`"v$+5SL+\RL`3ggfmEQ0{ D0)ٜ_BS|N%ghߖygsc\[ 5gޘw 뛸x/);OäAIi y.?I7G7$ր d/p 2 perZ$?.+Xc0ꈽWlҷHLY4,>wN+!kZ2ʪ"&+tvL9R HÆ:s}~ T4"jؽ1zmr>U=.ip.jGr'3ZaoO sx :7ŵj &Z4h[{E|-F pOY-|%av.' ?~*<\\xdRO9j-?υlG%n'`Bo0Bҝ>sp\ t5Zݳo? 6P&M 0ne67Ko\x//gXVfI:\egnʄV 1@')DP`M  phLV6Ypn. 0Փk3Yd*VOd`B@(YZ +`/2?%c.u xsbĔB}.LȁhMŊL?+NlO N3zjQ(f!dEtbbZ}a *bP?AS ROC?Vx[EPG-v-\,g#^ Ze0*V(bHXDQ$ck1Do+&O. 0AL䁧#A)f('y4FE89P"]x#t֞hop\r:$Y!^ޑF9," OG!t,'?l{~ϱC'yzF@|yb~XPP${z̑ 9,/?~ž^}zzȍ"Â=y FF\I#}S oO{~?7cDijmcGqv_o{@{2,' GAvI(YJGNFVfoM;_,vFcDrcH'O p~ $P@S` 3pdB@8 @"HY (%T:h- x`|X[ Jb!AHT M2l gBh(J\@7;PB/hZ6aL`NXU` ~p8"7] ?ë("P(I JerA"PPBTՆCQh,̓Dh2:} .A_E7{ÁǨaL0N?aLsӄ<|aX&0VkubN(vXq8 %K:pc <ύ]$|!ߎ(h()(,))PPTQQP|" ;B !PD'^VD"QhM 3ğ$:IJ&&U:I/H+Bڔ.Q)k(Pܠ2:NUJL5FZZڍ:" '1R;44!ٴt8:!::oJt(z~z=z2}2}}/,0 C Cua%F:FFXRL(&!&`FL̜:>c,,,>,,7Xlema}͆fcf;vm]̞>sqpsTr qrrqqqs>\b jZȣSók{wwOϞ/k~ />7@@ 9>u!a!Gtyaa8:W""Z"""OE*AEbbbb#ⰸxyQ DDĄ$IRG2FNrFI\*IEꫴY>_222U2/edMeddrrO) ˷WWQ0HhحT,\< bHz\O5%(FoA7qIcZGCV;m~mo+s:::tF6Gg1333\2R474504!Ԙ,*51#ٚ330o-L-,^XXY k.h#k`gKon[kfkc^>ھہաaQ1qIӠ3ss >*>?(|0`[}wjwO[GZmOK U/2%wOϜo?_߂b^@I@ ˠ`!;tA= K W /_0 Elb@h͘ҘoƆ;qd.0r<:ߝ0sTc1cpDBbP$ܤɎm))'RfSRҨ"&OOΐ(9%UM8%{i9J9`τy~V\ܸ<| M )./yV[z,l 9˳7/\dtB[Sʡ+lWTVO_S\SSQSE-\szK7nd5O7=n>o4k쾥r&fHRts;mmMwVWz~N;=}#c3s˯k۽O{{{z=4|Oƣ{jwTZ+>nVnQi}mthX׸ç&O6ߧb^xyu7oEޘV??3Y?|X8=W3/7opɧ>|KWiZrZ=r JݫVoBֶ37X7Tٷ9ux]#׫ݐ0߹ ¾,W@ 俿g 1EN \К!bA*Chyf$3Ͱxahi]P2QU璠DKKKO v5W**&))T1VUTRǪ7ѩYUckgo\`R`ovEV6)v))INǝ]bD pv'{xyEOVox84< T9zllc4'yRxR9XNRg2љ;YkN͟yuf‘sv;zŖK*VUB S-5o85xk qpS|֔;mw=#AUOmoÛ}MZl|55hصe?O |qp+bo8R5ef]R?s]i_iYwE*fuiÍ?6Ӷ¶]v~I2_Q6hA V gEI^B4yt F4S<&/ M"< |95MB-7EgI 򒶗1UVUf֪a%ͦC[f0o8c4ihdlbj?IanV)Ӳ9gΊ  ,(+),c;t"% J*W5ט9^;xݫFhC n_j|uT/Ao`C>GʃC kh>37~j̈́ݤ /]_v{s˴;Y4~xq`qd!gE/_Q_?{abGjZzІOM-m_,JM,qm(NHTilik3b`bead_+\@JhXxD zk2We.ʗ*SUTNVIPPUwgϯåˡǩiccceijdNcAڏ-wl6m:9/|=[='^_{~X\ ?%l-V19| 6HB\v|YB$LOIҘZV~djFlfPlS:speȥ̣ AιEK%K?M0^>rq@@`+#WGjFj=6x}FǍݞjz<2Η~_m_X\xѳѻpoJo_>=8<;2GϺߛhQ=UU7GFN83Uy/#879߳sbׯF3/SV ku'&~ BB{Wݾ s` ?Ns7~` 0"զRijc` <@08ґ 8xV!<ICzHxJ.Bm3h`8?E5Tm G$&Ӊ%a` & (!/FF')FC9AeFEFD#OsV.. =4C(/3LLWXrYX_`e9+/\'#"d /𔔐ܐz$],"/))JbRrJjZ}55okhO,ꡑlhcjeRk:d݂ueU-}}5g nGgךO?s_`[0mHp@DوQcb[⫏ :!x5Y~#?}#aO-3  8oDY:N2p Qk !FHQl@(фnC#"La 8.{?zAcfIc2nEAGE1I$\&Rc$3R+|Q6cWhhh`Lzr 6F3ƷLT̵,, ^pHsLRz]c W)ЎsaF [Ȕtڔ"{BM^SA@F hkiYiVČLBLϘO'Y[XWL1:;>wfq9p;70{^w/˿#;(1}k4#FƴƊ9ϐpxV"UR~ gjmɁLSgsΌF /-yVuA"t2y5249n4Ͷ i{~uծ:zGPCzOv>B묷3?>R }YttyuN[;={GEt\[;H Xʐ8ø{nE%~ pHYs   IDATx \\u/)m)Hv!T_\Dzn#թiT7u$XZnQj=o幠B 9H{h/HJq:3h|5guu:㬝`YE@PhD෢ZfE@PE@P%r("[WE@P%2("[WE@P%2("[WE@P%2("[WE@P%2("[WE@HTXG DWE`Yړuuj%{% :"D#FI:2AP%IK9 (/QPFysܵgf(aet'&lʌD0pb-ڴp*0'Q`N#2 NJrbmQbO/"UbzcXSC 3(-sQ^}dmM xH%*-(#FL7&JM)P%7E4#U`d0|G ]Sfr#|đ(3}qiNyЕ@ v*1iJtB^z.[+V`ْT甠]Qؚh0?ε5ԩO"Y|GYN"g-m+#T.DbM ysٖaQ` sG}/³z3xyIOʋU{Z쒼gW\xrp4S"?NMؼ?RL$rTbȴ'J,omJ&酅Tb8t9s>N!aj;|kۤ+GgIEgtsFh'aWޓ8zETdAT 19W'o}ĝt>x"\D{п'K =,HIl e=vчs|)KRbK:K) D$wbʊA,0ihO&W?F@f5GS\&X1S;ò€Ul]赊qZz<*)@>VkԵ]`[*wKnȪ/ [L.SJy]`)ʨr!/'@y{dI@{bNB@y{GQ;'e^j)cT{CH^Z˳yRyt_`#뎣|Tk>Oox~ Wn ;LkV^M{kHHyQ~Ds1l1+A*;]͙V4vEbATJD~֍.F@DnD~,iO "Cn"Hd[ϕmn];ZerpDRcr$bݖǰΑ~h/ƨ á=~tˠ $ݖl/,:ܻ̩.r7b*)*:Ү`\a$ˋ*KATҞX-T0k9e&,<j+ LK82i0|;ܵYxDS;nN=D#rq-_ow?zϢ p'Aǹt?ug׿08D&z'gڊL"`ޜE[ިMj׺x .JǍæ *.߶ ,a{ u{Gv`aV.ka _ J2S4݈=\Xs;yR;Uf%#(׿Rd{/6_Gr%nl޽kʙ._S^`:#?N^:Q+2HqLʯ$Ky+ |Sj v󗭚"l.򰬳VAp!GaY[dz7ƞ3ƙ+,ue[^Y"98. .8Ųyò.XR^ j8;Ȩ*u\Qcw| ?\_xN9y?gZ]Ã"0 ?H7iא7yK4$;I$ oi. 6~o.X'㸌o~)T¥3wF|xNGQw2G&_o<*E*t3(3S[2KDҥA'&`$ NWV 30$b10*m&2㔡|UTX1-GX|TzV.FHvw,XO3,o*9ZI#`i[2bO<#/ΰIkP%6_ugip1 FCg(; (]tcZxD(0<ZckvY c(EמXxy6lZx|~y$DQM [Tx"D#CQQx-~Mc$G!s }]G{콽Wؓ%{y% 4Ӫy/^=KΏ//uYY o;g g!{vʊm(Aʴ{QRߨ.*}Zq0oӦA2QI._BՑQ k}mԣG7{Q;>#ش;yE۰oDA yŎo -(aǂ>F]^O"#+F"Z*PAULC$s rIl]ܨjs}!$t~_o]/6$JhN2teƓ[b(gp?@9.dHF@ȋ۲iO,no}LW\ixl1C ;hH7-_]Yk6o&FI b >Jw¡rNA(0iu81rKؒ D! o3cdi>]')QQ`9ػm%HH(gǫS  /E?/uT˫@KC%ٍiMw|I)ΛpwxK:Q mՓFȊL^coLC$snJ}rxv'~lu7cò݄nׄƘIH];y_̶vnܳf1VxXR|=vyP+.`Sq\ˑSFs10jlI=F, Jl@,߰w~=\$c011(;W?8}X0ЋqیױRV,?xpMpԡ(P% ys_@mg࿈o,Hr< qn0)CgQv#6Wl֮^ɺ{'6JսKtEW~PjG)5h§)tR'jcELK٤vXVuePYvDBE5jŞҪ8(kבeeXmZb 0\k!i/ -e$!19yTܑ[oȂ۟AguobˋkX+f9+^h|Fi"-7pad*=W.t6yQ*i"p:'v$1q8Ё'2B9.^N"'E7K$.Ŗ]1Z9"0hOlvE@PfUbfp @a`<)k (iJ"0CG pyl|VbvtZ0LO$qG]T՚M_W-rhbm^*+ObOXO@^r mY]{yxxOx:/!!'CjB[ iؚfQ1+@ȏ}T?S\">R6yᏑ +뭆"ʎZuer6-՟)[[l~@*pV쭡A, X𼬵 ;!"ED*RrEhJeؖ8hqCKlC^{k֟ZŴATZe*'Q3CUn|ȶ*.9Pskn 0ݙ+* ZYA@2[O㕷ë_݋^yˎO?U%M)02cTZ[@Њ|=9|#yV8WRB!b)&sKn|,oQ~TD$"nhYfiled9OVRȋsZ GT#zYA(/ܸEI\ #+F^ ]-<1$aY1D8d`"QȏȊ(2̌s֘dz:OڳixDI$!|+f|wȗ #aHy!FY ˒Y.{jUdRTTErMQLw6W?L%?!ˤd!^?_&F,%fXG9_ĭE<%TL~:gdQXfdY(+#OȦJ`CVKv@&2JI(ߐMo̹ (2ӋWwYX-*d QX'9,+, K4TB҈I\A6JLu8 #',Cp h"%,r`zb(~$QEF"TE]2M0|,4FH$,4&\J]x,"˷TAh8 dCz^¦WI\[7bD"IX-`#.{c[_?&jӻ2 4ROM/ĥ- ^Br, ""9IaD.D^JŎ)Z#@%&Jr. /&Y^dQV$|CdQbt*@.Ƅ󯑏 IS1&LX0# HE:PAdiL%ҧB>OJ C "#'R#DLoVN<7J(297 `D2代e*P,,$ (Gϐ&Qbt*A@4EI"\ȲFEJ$JMi4np, G,H<(,scoŭ*f IDAT$T^8&f.Y<?3䯓e~{(qO% x@V/IdLgݪE[Xd-Zhb:J2dt42I's1⾏#It ="OA#d2k+[TPpʪo?G&XOc equ8ɇ-1~f{t'a\SRQbe6S%fSymdeL˜VE7HqW=YHY̋]E`vpb%KXU(ڨ"b$q5(GdTǸ?߼#{3y/ . *0Ls 8(,a!6|\Cl@% /YF3ԷJ RG~kOV%F) '֩Dy D{%E` #K#(4ԨF(cv/__'a>yX'x{>aE QbecnmoDzPM6zj1YX ]0g'K,Q)BེE;OJ">r+Oۯo3񀪝E}9Hgg2== ySֽ taLHHzObt18P"|T?5J3BV ~ef^#QR 3K'0H&ueh59|ٍ~o%6=M_nO8 ˶+ nWu΢*-j饏gV;Oq!~8r@|'kܐU_-* a(l`P㺬bKte鸼:E ("'j̧[I^lL&,w}S2M1SFc*$Q7}st6 >ԍ9?5U)Eq_`8uq/~[u< Tar&`bY&dYP>y#u^x~O[$֏O8&nR/sY[xUbsXH4EnfNȑS){?E"0wL͉%FZbU&?FHLfĤ%4|^a{8(&BVcБ`:au0'fYg,+F^eu/n\p!r3 ҫgǞW(ꪭPZFy/7ǹa>_+90I:4 Џza{m:m>q)RuAJGEFl+ބ>yw@"CM~7 et8t81T2ȋao]) *[ppr;'sgC~czK 7U]'.>وMTp. >QL9Ӆ\D]@L"FXFwSCLъaCD:A^cS-sW<ԛ"-B@z8i =@[HIHYx?-tpƤXXL)MLd&LeK1Dke'>޾W&L(1!Ȣj (/Ķ2N,J2YAV⽕n"h;!Fțay6oζ~\C#+Ȓc"@k>.rcVALE9PsjE!nZ)"|1JK^v E)E7?`'#J@(%4hIl&ƍ?BɊ(7*ة$L$ϴ3B!o,k)(F)'F~1E'J`[}))TPi-~Ӣ?P¯>>(uZYkȜ"0VV8ۜH/63p^2؏yfr\TCLc#GiUèc[)AiZ ȫ8moދW_ƹS%Ƌb:Y}|wmچȳyHH؊NY%8ȡȒ(3 Mw SoE`FsBmf._BՑQ kj/6m`ghʩG7Ӈ7t[Xt~}=/sH}t-(=WD ϽmŞ:lhSSWD="-TlFTE]2Og\48r4ni -Ǟ~c|]U>D2Z؏"p[R, y~y}B~{|ׁru]P" "5DZ;3R!`zO(΋pwC՟L29&UuHDo~ɷN+=78eOdhr47ӫL0f\gCr[ixQvr_^MzD™j'vM(ЛL(F;D^2424w+D! SUbcpueӍ$ lD{MqvV?Y27 KWmCKa;nϑg'I3wVw ㎜iIfc&8/&UYC`&(DU.At B&JO*Hb-;Ac9ZJъJx?룵ZG`:=1iLz3d_s-|#JvT~Eg6KMiHF"(G@1*"0eN3Z+N9M\UbW(҂}ܙŋd١ZI\8N,zԒE;qm/GA,,X˖-#/Ik&Y Y8-$ַFyLN8v=QQ:ѵ2q@\*}>_ GmC%Q T6xߏ(˦HB\I!6Xp8^󀽔tTFO)@T fQb, ZO/Cajlͫ1r)SrrԢ@;Avm~Ojhc~ PҒн|#ET.[^t5V`k0m pxr݇(˲Ng.vfZgIMQ3LgEϋ_E~pl:,NIu4C=T/Ͷl!do+~].Yؘ uzŦ5ö'mOe*;mkˆgQ#xu{WgqR:RtiŰ?CXA6ۺ1apz-$,Wӹ4DIp>.yDz=8H ԏJ:ٞzS_P?xQ:v[Cy$= +ozCt # 8aP mwu}`)ʙTPwD ;ZP7!.Op߅%Gy`j=(SE@eYyfp̉Vc]Y}n86&hٽqѻ/R t| 6pM/*CaufKr<w=٧{p3/;/~ߛ(*EM-*A> QL従?b|>*vl]!@7?!8i.v+G`2Y݈Ugqwՠ_N;Q>{]UfƷKt d.E 4k~|LNRdI̛W]1x^2Cζl- 6"X#i #S` 1啬mj (\AZ{PHGxUT ]VK77Ȣt0pK^.pl98. +VCp-cnR NV~^TU=r ƀ?i5d)z.SH2L 𺽗$ˈAy ?-wFZZÎy'ʃ dG䑍MכCJ};o/yALZ'DO[W,K2̡Lep8![`=)ݎ&W9_^2Nt`e%s;:+dh0iiCÖ#lUEşW: ,$T\3d"=11b^^VP}5"01"'6k,E@*XZ~ĢfKIPGG 0{dje|4tXUPe鿐76u5TDOE`VsVvkeyG@VT(,-) TE}R*1Ĝ:/wt+1U%ʮFK l]:8>>: w1EE""Jl.AyvcMsOOG]XMǽZNG™G9 xixկsvHӎ*r5*""3"+Fv1uvz}b\>)o.VŊX{P{p ƊX]NZW&(0Qg)1\M lcW3/ix2q)+"?F ge٨ ag:jpQ gMUFH が~3 Cy2~qq >'Fi9/&,IXyN~(OEP%Cgۤ(MB=><ΆZfGLP^rgy4a-@?c%W :g<#|ٳݔ#!P+(1g 9BJ\lL8_Z23V!߇{+/icի H技vMbG?εbtYo LZW*(uX_e`27" k:@i++F~mJ7KW$wQ^2d eGV!L ىg'XyB0Df =qadq x#}>臯2^<f {ZINJ*c+h6-$KQ'/!k i;`O|}Q((el<&x v?y*ߍ+qN ~0-6[mFQj)6؏.*o5e`^;X x-+EW瑹}?kAk(߄LC@(.q (3l(1vA6uj P3DNE +;%fPJߤfʢ{|Jܹ яxߡfifz҂uAYTٚ}+xA}ыt;> Pgw]A-u[s"HO6{A :s7<ήzhɒ,3TfIEAzFݏگ2}ϞL+:orXR2Ck=i$%a>=l x %tyٗDB#{Ds9*\\(0ij ɣ;_o\Z_;v/ۈ# rggG.^k/v&UuU춑%| [TE?=w2G`=^|Ts{=6/^f6cV޺&xwd֌A|vMmӾ2#H(1O2oSQ\r:K䗦L7pXPW\2W&N+u$NN6 Q ԝ5f ;ZP7MbM ]U~IiDPz9Ssb Vl@:)&[!8]Yo"}=o zj[??s啨ۼﶿP`2t7.͸Mkэ;a!GENhDC%m*!"+c{bĦxh9KCYǗ=2ӷ;_{v7y^Nx)>عxxؼ_P_{Ǖj'b{x$(-}2tk7bsY;:"/FqYWfDswS_y [ n籠g˶?l įځ%|[wx?A$&?(;7 CIJf7bٶ<8*xI#\" Ȋy1/Ϗ1u>c\evƹ.V$-9d)vc7lX]e;1 Sn_˙0!*[+Q){ȪG7;N? of<|zQx S%Ug8?8Ÿgr449Y%y< dܖ4up/>/E9.^Ck 'Bk>7>WWUؽ+Q|T R{oX^a14l^Vy8;dj CH> $'f`yDkCϑDlp~džhn%zgJ OH'SҘH2aO@k bO74DU" 2RV?^jr7JLޤ|Y 3' L[n6w=U^.X.gLQ$奯pQy] uq8Ro߰J4 PJH3%",ϊa:㓦n x [g*024DlIsQ\p'ȈD# R0%>}˩$,\jMƽ,Qz,ώUn~OL>7۸4JǍ"0hszcF9hܸ-ёqLdcFJatf$3DP&qO8F[D9's.ﶗSKgxh0/Gvąb6cO1cQ#sP6n)AY&c 2qu5?W_Bo>2bc9jA@(r.G'=?4Jq?LŹ+oͣn"n +9 sWcm^cP8@ȿͶg٤@8/!a9ڜ ڕ}ztv5`YGJ8FI$oԢЌRch@@GH-rdzw4'@Q7Z#Gf5h{=8He0?)i3(i?\/h=scPm4akoЂ~[L߇W` +Qoמ#d5](z>G!y R#5.^~D^3*\^dl5ʾQ[I>D%mlX xᕟU.;вtIO -z{V]QƼONas;ᯣ!_gCPTU:^cNk0`;ݧF83-~ܮ$쩷 '=0GP{I&s%|dah- fDԻ92+(<9l\w=PԖQߡ$Sܹ],\^` &cx8gbaR*N|ޟt~^/b9-{;xO|Ccj X 0Ff4׍ 0-zUPrݾa>f/Jm/*C߃xᗉe+ΉX㷫@!Ő(+˂˰ޣÅI ^ lQw9* yp]`\޿c2옙R"`(1H:b2s[5xV/ U/p{}Q^Q~ \ 6TP~"7[iAo ?U[P͡ʤԛxu'&x >>'maUk&=^Jk+Xϣt=8/bDi9$3Y?ʅܣ]?zNrOg5t0/Ac*߼\wXn)i48:N5P/)0,h4s8wDT>K!i5=ێ;9KV!%T&aߙYcUo K,(#H"3K>zAIz8`4}er 1/"yn=F!'#"ǵl% 2VN?Kg=HS5/$I^Hbž,4"KHk)'Xw|o؋^DIWնH?G` Gs0ѧ{M|n{FB:ŔgE K-g3YF@]dyU@>Xɇ6<Ҩ ׼1q,Oc,;xıؘF"Y'gʚ"o \O7J'%7%LsR B7UɣMF(M$oˏ N qcXBhGȋp6cHb%,*COҥmR?j1֓ o%δ3ф?4s&T"0IO,>4mv=M{VڲYyh-&m35ck3ܐo4?>yY/P]SX}e}'sXꐻ8zTf9PbT/.oMm-V1PbUM 5@ p߯iEC[DK+n^ZT{N| {5X?w'܏\)+ƅhnmAY6==FGKfs; d[@Bnu4J R%ؗ jΠb۪qA |ɘ 2 s#3jŞ ()@6sY^fC&0oa+Α1)9q@fc,\!01|VYOݎ:c*a|az`Fn~9Np,x,|~\(F09[-gŚ iɈJLݾ PVt1{po0~zmVx$*SNe/4s #R#20G4J{{ C]#;M^ J65J SSCY48MZ,}秙F)Np8X a cBlkyQ]ߖS''Kl% tse~h p佧ўj{N@\^Qs3PW"ZPk3\g$ Q38' E{D~h"G9yx.Zx47`Y^lGCMoDU/h~?ֆ'P 9H\~Ӈ=ؼ[:\n9F ։/وw;0N*_>lpё M2;sTÊ0F^Xeҝd7YVs1-'.?Z9nZjkkyV '{ 2Wu]n mk7!{nũ2{83dz<ǔA󺒻\! ,EnD~n"<\2) g)pE,Ösu :Qɛ'FWYrBvv*$^V'dy] |pdoYݴtc@>,WQ6!򁅒"0G\NQ(%Ej9w7v2Y&v"AcQ ۃzZT,y_I),2X}*9y9<.%", [Aa [O1^n4hool4C@D(3UbC'"OPD7貝(Rk&" L^zDf,#T}Z3HķN9E!6-neNC @nkL*̡\DGM~q_'KERȲFƏ2YYa"<do:$D&dKd߰w"+Td_R%^k| ͱ%T`hI$B4hsJ-g9,oe>J,tofU>LEjA] *\׬I[V*&h-ٰ mCW-@wKҢkCm2(P-$(&zsgf2d2~{9|<93NrQw!.zNps^@ QRyLb{D)R^%pWMmU9C6DlpлI IDAT;z'gp~82$QQY&v(ހ &?A e'N?P>$" bMhL$F҆TA{F bŽH8v(ƊJ?%1cowPI` 觠SnuGp*'ǬN(#hdʠ$`$2LGdJdG1$cCX[6>T icLuQI A:uxzty!m7_ݷ\*APtdq_I+vrߊ{AFDuiGm̽g]=f78 S6xl({]TՅנ G@s./_.q(nA^ 8]i/T=y\K7&pEHP}YQS/gW7|⌌_^pTy{0ٕo, AWA"<#}qlʳN?s73^"o8=I*STN)1r19@yHK ҰEg.R(eayo¨\a0 f،(zhPm܇B4/&""\_E <:rJXИFu>06f\B? | z U큍IDdE{h9"5F4D&AIV]쳈s>k <{}6$x$ ]#usD)"܌;;$BEyIbJdaqiGt !h@oA_A!U0E9Dg{Kp߉E 叐Ӊ:Rrt!Su gH`B:($HvnHT$1"Gde gG&5<_f،(zs 4W"oϱM{pgN#@WGF^FDĆ*]6DJNl Rc^8F@@y z1KIj$Jbti:R"hLh;Y(<* 0k~XX7搐FHD?)6ZI`$2#C8$1 G@@@#eD[(]C?1CQd}f@$ƞ2znNɊ'JZIG`:xJ`v87ZǩKF"$0 BɌdEmD5 Gb#*᰽汑#@sCBB lFH Ei=(YՑsA±0!Y@?9kb uFc: cŵQbC$FR#/6-4҄DeY屖~ ۽WuT'Zʔ^2k偭b}ޜ+p/q>&A r9Id<'Yq?UIFq9H~5(߇t#4R6ARѵ#=&^" >n rD&mUo &UVyF:q+[+A`P :6:\Hu6J)pTFt_S9]at`p[Uh>4;0u ?H FdseYn:q]^m-ZϑmGdeK4GT4D\K#M6CSїOZ9Ev3SH%G~IQ#퐝EZLy A#@ "s}$)F V{v/t[Qd7X.tJj-~:P9ֱpfxl[Ep/h ,¬VtF*ҨA֓V}r)qQƽHMr[EnkF)E^}~a'@Gs#{!B>k_t:Bgqj )݈Kv47*S䮙|~LR7șo=%eHKe2$N&cǿ%y7qUqHB4xr,3Dž+ȁٖXYL镦CŒo OF2\'7$qe#O!oAgQ A&.kkYuߌ]0O()I4w0U岱Za/وA J4AIIW}ݝ^,`G ~Oe"g1iH,9S23KN2ٲce_#^I"Ml+Y#ڋ(JoG 0Kh1#?So=v]&+ ;ٵwwC]މ5w~o5z50ڽd[ p],l-7ZՅnpo-cM.^ZjVLВ;ޱ򥖻9$Ub+o ç}y6zJ30J߉Q'N%ASR$9JH}6!Q/YĤdq&d_:]MJNd>>?2́;e92r} +tAA`RM*&m)m-m&ih)DikiN&M M2<9}.">tI4aaI݇n86C&:5.) 9ߺ9XսE4C@BL)6 1d@`K$: M{Nc$VI,nA x0 W-8 >sA 0$]˔ - A7"<ݖ!"h [+W+?:t뮻wϯNLL۾=RP_@EW^X<1KPp4ܗg,ia9~x3ۂ33خmD.Y, &HEsNC<7B妈@mAqr VT 3 svi@`p<2h pXJ7Ba0崑t#28bqȐ?Yݮ܏1OF ~ x.LX=žen߁O]S>Zq٧`$<-qN`J*px!oy6(1+qCb>1kqW14NBA`F?߆'Tgܐ(F` ?2:.'m 03?$RʻٴVڽˢu{?_|G<-y%k R2C^c9]4YV0}? |Qo?{^~1W-nՍ2g}5jZ QA%N*m6j$|6*d`7yɒ%N2%^{f^d#.D.?ǘA 0* t#d1!$d? 1~ b$0B$y!+1#6ȍȃ;PA)!CHnDĀQp%1?r)f{1X:rjP~PC:x p" } 9t8:$κS7);%lVkDѨTC7Gk_6$2*Qƌ%/Alf: _QٍS ='_P\9@zwϜ BoAq ݷ" <{22ĴdQ(N#g,ds@v8C40%81wQxiCZjP ~oFrC-H|2!uN4?J^e*1fj$|(z/ ć'|=FC?<7ȸYԊ44="5 3n[|iF7~#h"34c<ζegHЂ͞MT<]^ïa>GEp#VFe/Uu>32p8UJiϠC df(eh9gs=6#lGEr(d@P)\UЫ!gO{4y G`J\ti Ѽ9ڏ %$8ȍ(HdJbNֈe7{d=3I6gEe 4{-EaP > (6H]QGK{HtiT0{Kd섔mFb_ȶJ%VDF II5ϡ#cߕ׾=>-z**b}Ty4o  5л u6}'Ȉ̃^G`\zW˰eI2rXl|7˶:ٷ{T;nwϽ}m/٨n} P69Rv'ulhv|t$?yjwyLKle2k/4"nj[dz~N*ˣ*u3]U$!'wyɱ7xߵ,+w\\So5zJƲ`*1*J=5?r:9-=wǾ6?,+Nh:cP m'dbFb@s(Ñj|`ϝ8;^՟O@o 9UGa4(*.rl?wq<$W?EjJXTy%͕R<۰[b1=SVI|;Slv2eU_Z5ި qk=evbURH*PD/Ĺ`aEl/ *ɁϾE~Zuy%HbB$]4|$b =;B9).\eDik 8KVnC\s3;Wg? 2c=2x.LF׭ݖ%K̗W齪lx~呦/z}e/9z?HjY4Oؑ]R&Ih:+xPfM6WEӤ;ASa IDATy_ۏH(>/f$EV8zt7H-P}V#j?i]RQe'Yi,3CO/Җ橲2C%u 3}Gs;/>s47چy_쭭z?F0UqdFw`F1 QJ(Db9!'rqs]]%m-T[J[) [@SwUl\QN={doY\R[_]gO-W%y~$ W}h:BhZvH8MPNG~M "-ܵP`HSH_EZkp^ZR(TD󬗇`c*KJY+GMed/*+>\߹>{T\xIj߁:S# L;>ڒ8該EaZ|;GǮ"&ٸ`9R6.iiv[OUIٷdyvM$Q6Κ-w\"|f&!ce3UȢV6,T{#̙lcH,*}gpA F oȴW9}LyܓR/Υۣ-6gy{fvFnW26;6>}.Ve1,*-)0cXc0ʫ=TnطK,:qKK,L k=] KͲJ+"ߪ+WN5pX]^Չbj 70g@@NҞ g,MAhlIO^uA{X@o`,%]H,˪~|]&T} s";90$VSL{53@t9dXHP#oGc|z1D8/jF ~@XȔ$IsgM u҂u$)l  ]OB \8&y(nC򇋊A1!s: Q" i6^wRnߢ>D32|fg i+|ҵp&(D/{κά6#$%حJo)qn<1n ڊhMzhRK.Ao84E5@KF ԛ=gCD_4Ju;^[= &C0mډ 872p5L . G!yeޑF}R:8jC D*vP#u> P[qٷwWr?hӊ;mi(fC MG !'e'}'RVR2қbZ!s6@j.ٹdek,ݻw}^rj;#V7IڝOY.(_~6[V )};:},k xFn봧()D F?565i }$ܕ~S,u[.el.S^(ϖ2|#pi)9,h[U7d%~Fn/ SWr[?=$ˡu#w2 Euut)UV7RopŠ #[_ǽXToY.7/)vIYRxm6{ǯsrk쪙!aх}@Uy8F[ņ#H TrJ%K6-~XkU"nd,D@G]P=kCJUQNcz>`8HlFmNR7bX(W6VӼhk%ؒ~h F.1ޝP=ٻ}x7v\/wSoo** 0PGrRX!͙zB^Cb!4TA &.LzGder06JK׍)n|o!ڏӆ?jƴǩH+x G Ib!ӖΨKGh˺r%CJ84 JbC=mAw'NΗwbFb0&?`J{'H~]cNHN#dO4/;u$1}*_ svntDF NbHqqƇ6FB ]GI ΑS:$0i=phcȜ.{?RK} 6$7L,A z`#9 #*8 p/# @Ibg2gl T"ҳ1 QG߻;'q3 gJ?Zdgd$Q9Slu} dHb_sBd)wWX)$%E #03%$uuDFR#JbAd{TCbcdb n̷{t٠(AK]3(}Iq%o%C9tyl SlL|4k`mSg(ks4v3}:3-sO{=^)+?-S6>nu|E6晹B9ȶelA;=ٶGu G!w_Qom^;Z8dՒfc&6VsdaÏXmd90G%e}?Sw q-qg3ha8HĽU1ڢe^>v<}dzc*ۗ/-Ed`Mwr"2#/!-ŵBjf*3\bpdn29\+`+#ϓ Ȏq Wy+;2eUaq! IWmOIGhv=娅]immcRvT]/|z>lT3NS= -8YjWˮl>)3CƵcp\CbD;JnY#;M{MFQK5%0W! ydQwqAL>Idݖ`؄SfMRa%Ȓ[.,.i3,/6NVקgMr͆/DGs3k[U:sToy0$\)h'Ts$%&a\A`1+t ?UyLQ{rdO{:r*GyǏ$%]v*I~7xO\sp)v/$WGJ9FHӲcn=;5=eF\M\2ud>SG"q8R󨸧jD u >r$i)ʓE"\zeG Z(p[o ۡD"`v[uGdd]].Mugc'N.A=HKaT,״IC]%d;'uD!A 2zi<i9 cSɴK_: m@QcKr7y}zW$jm/X^'݉9̗C=`$g-nဪ=^R@^f$)NZ&t)/<|7 )tHGrXf()ZYnGy:Q;_`F_1v:A5V9Sހ]6HԨiF^q#x6Q2*lpLGX1j'^ GRMYn3/ Ё!,H!N!J1H8:8jC +#۫>])]PߐX(P4h@jDFgMLÉ6ViK,K#.A ijyN?#}C.qTJfv3b-ch6 0롪E33 ]NЇz?Kfz>ՈA hCu ,7g߅ω֕FzFi!Uw'Jn=M!naoјA@)uiKjO3TqIHNb;T kNֶvd/33$fӵ·U{B]c@Wh/Qi3Q_{P͢:>{O}}2$5 <6b :" nx1qXV)Q5>[9%1>ƐXNÉ֩Q\ !ڏӆ?ҫ#0lH`]JDy]~ِ!(_ iɘLڍ6J`Jb&qUUm#.W*^7H"@rS"ajW%MGb$0N'r3l!Gğ+Cuuv2w1#c1 ՎhjMMBØIU!5Ӊa >߇x/E`NC@u8or&15 f@_:2aTKHȗ#1)ތw"!'5uسf.((PSC#1mj 2( m>XTA486t orUD}n$1mrhOǺ{H8pFgHĶ]Hd 2h$W1aĊX@=4b  4 3$7zF`ph﷡1A#Qy!Q ߆^eҌB߁FiIJbjq#0ՠsg/H!DƆJ+nΜsjt7]mhFGmЙ}h%0H`;oS$eOCRӇ {Tr}H"@6DBqG~"N[Niٜ1iXxݖ&9S_ u7BrAP4~BQȦeάJ gZRIܾZR\%%{K%+$ɾȻWؽIG^dshYT%5[dfEok8"yL-2-%dt?z_GpJՑ9$ƣ~Jb )yU4ENsmʑЫ&v|~i%N3@Stɳ_6e,j9#0-)s'e'[eץ #CR I }P[dK9$АX TbO>6XTyme%/ue$ P>&N15ۖW@hv!pJ2Em ERre-3Sh27Ջ`4#cni/%3p+\9Jf-j_WJcx$oRt<&W/7Y9)y80p/kl 0{NNv}XVIuKKJ)"/!3/zMZ)&ﭒ[Gٱ2OF,Y!Wz_Cbt3Q66PQu!pܐ˃@QT%.Ii\B/p> [.gB,ji&4U E JRUvNnԯ毋x 2;:5, bV$Vg;Kybd\; `['=zi>wVʪ*ĕJV"dS)Y5~H'Z?vEknqKlʯȁrS|(.q/ٓIŚR9|xkrSqY6l<'g&.鋤lΈݹ &ǡ`D!"-lUW>z%/`nxH6 MGs8?k6! < #Uk<6z)$W]}^LɓٛfK|g2'Lv)Y"K(ǎV~*𬗇dK墎8 XȎ(;Hi? #2o/QU܉B崜f o047 ȑͭ޾{,!1`$ï ̜5$D#B_h.&zYl;vle]6y^r%wc>p 2jԨ ?;l἞2IB| ?FV)7(KX%Hbbgڿ!Sfa*riIY7&6& cd<@&dkvm}dX[;-o35TYaRߡ*zjEPWaA 3AMj$6Ts$đX†:,)I0y"utȱ$Փ=H(o$ozli6I¨/ICC`p;?m&bVSL!M(*b·>>>#, H4A fH! `cFKbbg:JJaJD9#Ry_hZ85y A`0&A `* &_A `0 I `0 CbC `0!Ch0D:-Ps!sIN-+SDj9[rew{$jRy -64$w!wC2R)] zrZp oiMn!HACESFKl_+VdsgIlsm|Iv!jAiؿM7md؎h8S2}in܇ն3s4atUyc&G쵕3وσlZ"sd!/@l!*`W$'\m}jeEdFkFZxD>UqɊ{fGF9pL^Z^T_4~<-5HZ#yz}d&eIcٵ2oO{5"~ҵF{l::Q\-0Cj[ vQĢfR8^&s7%όM)JbP^Kˮ9NFH4!m>EY[$e|˳XegJK!M/ ~|n䓙nyD  ¾!1ޓ r؀!bJ I7]=X2I͐Ln,|T(l+6pӸIJ9l䔬Hϕ/Ǿ9dǖv|Y$yW嗠,C#l@ګohSo%2uTe lFˈ$FA#οL.}})Y*\,S/#x%`dM<9φ{i1ΆMCeɜIfȰt6~'^)<> [ȗ{q0.;@6lm+_8I+}3"~bP؈6YIK3ڸsw865(`HCHIvTuxGokj|Kl I /Ad64b=,o&8dBoCǏw\Cm3#@p$%`\/ѧctfw3"I)OSHg _|Au23W1'5߇3+$*~ g<4x [h0 GGblh)m"G sN%&%1Hb$3bLFU2;1aHˈA `|$Q +:Qχ$$bH\#%y\GcNR M#@!pyd#U hk1 >sJxg:LGn )ĂD7bH+tP4"ɋY(Jb:%g*9NdJ l0 D%((F(MFz@)}EWӈJh$1N$Cb\dX8]s0bK!ìհ?e*(Z%/$/!0O* 蒸N~X+ (E/}#,$,$0%.ut(FzA@GbJNtu$4i؇?L`Fbq G xFjL uIˇ 37tBA ZpHTs,PzsǪqPR}W%j! )5 N:J5L1?WvEIba6 4aCbq EAh00: q94$D @T!sQUhSXA `0Cb A j0$ `0 0 EX:SpA `0$fl `0CbQ{L AA `Z E37 Cb A jAFJIENDB`./nsf2.4.0/doc/next-tutorial/per-class-mixin.png000644 000766 000024 00000063360 12501766547 022322 0ustar00neumannstaff000000 000000 PNG  IHDRLp pHYs  iTXtXML:com.adobe.xmp 5 2 1 m @IDATx]EֽsR%+ D ]T0bZT YqMkDY¢b@Y]*3AQT9O1w7o{}w:TuwթuVToyP D AH@ DhD"HJ) &"@HJ"@ $B $% DR` !Dm"@I)0E"@I6@ A`B D! D8ۨ?3aC@+mX&+&'@6F@hx"KPcWʌRr@2B׵u_L-$(C"(Eq>8|(eh!`y@"`cEDL0QAD1B֯ - '`ʜ2-"^REM ݧGr `2@DuU7E #-ݥdR&P=dǶjNTW?hBn;MFbfF]Xi!iT֛Xe{zzK 'J ܚ$G R!Uv>sڵ4iDsOiذq`_]*V(=XܤCt7,ѓ/z뭉Fgv{9Yw/q $ [R!eVZ%s|2p@y'W^yEN?te˖- ܐ!C.g}VD3R#%s">@Py!Jn;xogϞ2rHׯmVGqa 4Hv"&LkV.]ZG~I.ygN7|Sw_{k?,Zο;`W6n(Æ -[Jvd1B:u$;wv_x5J~m 6XtnKFv{~`KpIL DF2*1 K *mUSKU]T>#)^ʕkԨ;V2lvn7oĉy)͙3ǝ}.lعkz{~J}zM6uǏwhןDzv!xq.駟vJJ^޽>/z;=%%?D줽na7 Tkžx^1 (4X/VRKu{ՖU{ ¦O*+[_Jow-[z;ޓO>\ҝؑzK7n;1R̛7ϫPwgc?)5nkݺzj~~ͣ0  J>.;\fM4ܷݵw<@$7) ; !E)g0عU&آAeS`\<7|~aY~}hal2eʔ"ao;p̞=۝p!@ ]tAf͚կ]1&#(?;v Obd%! ݞ%A Zhu։vI:u 3g`C{c]6mdrEɘ1c_ ݺu@x:^弢:(f;:V5L1ch >dÇv7I'$SNuaoJCvpPQNU+ڀ .Aܹs]N vi';ǟDv*;?Іerv-P  :sibR/ۂ0&ԲeK14`6qdhxc<ヒ[b27o%h|ussE g=*cn:1WuP [R@!$g0 ?_gD ++P'bIHx ;fRb@R w2w"`YyYb1E*~INay@ <##%$ k@$DeEax!`v.`ۇۮ0.v'R1Hx"X(ZbL)2Kَlǎ-g0#` +0rf\Zw&)pP!ֱE}v(2 my1#$I)yxE"oZ咿aʳ5bYlڒ2,o8}R "[13%œ-}{wޡ"JԲȊŐ6b*ȽHJà `vnD M& !!ejv Tq]br4UޡFIJiK#&tr`ԕi۹%*&)t7 `V`BJBvb:oK%]) `p)/!yU"ۼu`/,NR"| DIt|J YDE("@(R0"@I)`QD"P:$a( DdR棈 DtHJP"@"$,G"@@JLJD"EHJY"D )C D 6lg$|h(N{P2,o8ldR21nTSFRy!&<+dJ?oO*7qlF% d {")e\:0X(Zx%͛7ڵkVZ_+@k f;O&wZrLwXPeH۶m˼/(첋7̸%; jIJA-<[ vtMNˤIϖ3< w{@S@ oZR$f͒/ܝ뮻dȑrKƍen:5jL * `( @2ʵr9SO>VZIvzr!&LHZ4OΥuc^m8u5>0<_5'Ub:۪n:;`:y:up7%@_¥UWUݠYrFSP.X6v[. XbB+Axl"{Ɉd3,vSi1D#@R y3{D|BOŴ 6|((DHJXsOn5/+7|sDI$dxX?,;D0 )F93I ?{ʿ"W>Ҿ}{w_4wޑ;̭-[&#FzKnFywz' V/iu'1/^,ݻw+VD"Z? *1 苋)USmTf(x%Y;z+~H %Ek͘1ӏz ֹsgO.)xr-7tPOs ͜9SӅ^tUrw\reoҥO<~M(2#b'M3UVQ3SRC7tI^K. y XSNrE/nܸQ.\(X=zE nnUq׽+[.quq6{6r{qE"fHJa.]-i֣Gu{wtr7;\y啎ԫt}"Y Ƥa^zI07pϰ%aFeޒFLtIݺuݘ"@[fhڴiW]u]VⶴS!+×o)D )B)3 #pQG3glڴI{}q$:ynn&˗/[rM_d]ҊKi7ku 6}(>U\˪Uܽ5JiM:O&L{@dp0*p}1'*W W2%2,GEKFk$%.?ݢkpԨQ%]D pL)L;@H@A! 0v Tr 쾋$K4C e#@R*# D,!@R|  DIl"@I)K@1D"P6$1b "@$,"@@ƈ1 D K4?7})?v_}=rŔ@Tfߺ'kr'ȹ瞛ŔQD2CWc.3TP]2C g70TH Fiy"@HRP1" DdR D aHJ CňD"iHJF'D )% #"@@ )eaޟ"@F0TH Fiy"@HRP1" DdR D aHJ CňD"iHJF5^$uzE6dvdM@SNR h0Y厀U"nh?7 ،i2 V"LO02L= BeR " iCn۸^`'Yᘒ!HJ Lb IDnwPNuGե/R2@go2sjvQXZurUV["!)R&彃*ʪ"Vj3UTB Uj{UTP(A޶lT7J@8FJkuu!8K$L{ 1UWE۪Ϫ.SaVj=ZUS2{U S;p<%)!)e Y7(ӄzbUO Z5UAHp*Fx3U)CuF)%'IwÉZov? RjUV< B<&,(U8;&ەle҉}(EM "@R u05UUQ1UE Y*1  ԓUUTLL$L7IwÇ}?XumOJ IکNTWEJ)PHJZaζVrj&I qEÖjMT_'3H(ݾZO4n) Úe` TJnNYy8i|ۡ>PE :5\r|Y_z*g Ú]0yU̦;I+7l)E@k{-aM4\x`]x˶`rX'TW=/r ѪRXS*]n0Qa 2`9%h6l`6ZC%f!AHJ hB@+-ZճTa7%DhcCW-[R  ÔMXQXM)υ-gd?)D 1S*RYP -͚M-ݦ6qDJ )={ZUVP3ybC@|^O LJG8!K@Ҭd?HYM^1]@P"@O)JBCj[/NRB=nfM !U!6_ 14T^[R/fIe. )}>ZbiY<(xD(6n(x0B I)o}R*oGᏴm-%dpL)dىT4otV6\! 2 iVۘtMGzJ9%$̪B7k3`V&&=tW!~,W)kɅ ZM1N?"!LE|l<.7(U VeOӽU (#61H|01=PzjOBVȎj}΍\5gv?J }Qu5ZxI)~cr_Q*E|+ (g~y$\dY\!v0Ƒ(E BF I h}jOP2[,k%(mFTp?IJ?#HM@@P<H%U#)lM"|! qhlkImhDR :kZ4<*)>B2bP Q@<@BuUJI`t*1IC.Wdf5h|U7m(A, $̒dUAG NWPVo]*1 )EDS=M$=VUa5ګ-IPBD$rZUM2|\lJ)Pkјo]{8EJ1dd.6cI*1r^"TZM<[#({EBBeWq9r|ߙ>rWˡvm뮻1DNhBڷo/J"'wNC*uZ>ӈ[ka7 # њrƋ-%G軌DECNв͟2sLi׮rWʕ+w/HzRJү_?7.;tANù(n.ڈn-<ͩ Dc^  9]V`J;qFYbEוvO/L -rO=.%DG9l@N(h\Oo-[8߿q2zh9묳dɒ%\wuzGyDv*~N~`G)KʤOăq=a>Wf̘\mVڴi#;S\qƞ曥Zjr!9r-wX`loirOI2Ok#^ƍ:{GymQ9= K/{X;8oѢEA|xvx=|k[.z;EUNhG+Ԯ_MikK)RUaW_}y^֭ݻg G?)^{cMΫUZĆFg<){ڭ/H}T۩bMK쩢&-wN3r2w?n0\?r.]\s1 V|ro[ՇZj %>Z/_.J^2yd9]ڲ͛7c=&JB1'xBj֬)Bx@!ov˟(.&)S^zq.ޫZ,{ &K.ucG &-[f2~x;vlnݺreny  xlqr*Ly *tݡ j'՞qy[{޽{{JP֏M{s6l7|߽3<ŁGSSM%\¦Oi}-;}Q\<QF'7>TPMuUtNל$5bأA#^+ZvU{ZP>{ѬY3D,9~i#G/wa.@ D'9nukyUtz6mtjC%8>T)k ;r]Ҥͤ/CT` %RAJ@R?Zg:묚h\uGD]tԅ!ܯKJsuq%p  ]}!)CuꮪqT)AknRc^7=)yj\cp^^;8:=5,-AGl=ovr"ƆA4 ҅ z{G]رb}C%!% LTAJT4S)en#֪{Z .A=uãa.97A{#%;]f͚UD1RsO}Fϝ S꾪hcƒ1I))a,<%K5z~׸q]Q1gH_>TSZ.>tѧS=ї|}ɹ+y'VH(7`tG9ƞ00~3\g}/ơ}I.?9G  ¡<.7X~c͛7cD(yJ۶gOSB ,.E 8.,ā;N;]0mt8z'n(۲iJRNp}:]?{a)EezjoUkY5}ASJ}M_}F)<%xT_ٸwIø%fϽT>ۘ)wn ^hF1%̢d`N$h(UVsx 6jҢEbPBpٳqœC` ?Tb*5v`,"{15}XdQD > j*g|yN nҫA@TRE=4#$\܉;+Cċ.G'剰6%0`+%^ԂIcBZ;c@I$5#e)%"%Xge";N&9͵5k/ 3IBd1rJ9iR#Q0@/exay"쾁KTmcer)0#H1f;~JK7u>ʢ .5X6=AdLPhZX7HIeZfB)֏JV-!\k 3XPp LX6)lM4K]r"~åQ,ܗK> ~;J*)R'x qpxf'>lo.≌#˲8ܡyeTFfI]댐,Av["lm?<0W.*.`DJ'>*‹ ?!vQN[׋#uLE)5RW$ O>k}ʘ|A6dkO nPE.(lo+86{*YA="+!~AҲtH GO"P1A ]R [&֒2ac&M@y9 U*~>a/$x(`R%%ON` nB&޶kN@HB F Fm<"@(R0"@I)ۈyD"P"$a DdR DDHJ%B"@6$l#"@@JD]%`fB 㐰퇤LBU V1Wi eq{le͆')%#@I 2LgiddۤoZ)+x aE 3Bm 3_i#oȔJJXaEΰO! `voSny%"xB `dv[7n ڮThuvW6YM WVLJbfĸGJH.omvâTO_~ҶmqI;M4/Rp#FƍK)9\VYZ]j]۪NRkzBP T]Du*5%;]EwgЉ[9K"~z?SҨQ#XTTIV\)j*4ًT>)Y d$aTbblEcs,"idEekKɬY/w.9rҸqc0`[΅ 2D͛'{;od=(!Co3tHʗK.kEyWo)-:3ؤl()-ϧ~26l 8Py裏d.?v$t'xBWG %dvJ;mc%ĞQj"}[x[RG}T8h5FH 7W^͛W_O?',ݻw;OS^<`khYA}40@9X RFʼ/#t) qݺumڴ 4~{]v0؋ٌmC<͈bie] .NrH |NtH_L;উ""R$e?T2K@5D!"]vuiߐ7*!X{J8)CD/B mfOAǾ̲g}0>ÇG>f.[DOr',y*ӆJ˸ZiqJ CO A SG{^2W^1LtR$ozbgi„ x"N5ff8.3 USeI~CI'yȪUܟ5Q@h'hnP2C(V-Xf(vٰ\ed&! DU>P]e=+fʖtŋ'{k HHeb00 a,Y:A ]R   9A+=Į@b`" D%)m޼Y"@{'_|MUWΝrm#<Mԭ*X;a& 6)&oҢE ׿e-@򒔰 7\,#d>LAae[* P?~48^`; .XI|˖-Daq&EBSp;yb؊>"+,ܲeKG4%ჯ.\-)EWDruɾ9s[¹-)-ĊFв}'`9n=SEsϕwQv}w>}Es_vI' I!D ;j* SUZMVnʕ+?-/"GG7 GO(mH>\yvYg H،t1cyr9DKw>,"@2>gwK焮9tAWkMH窫hԢ)hFJ@n={_P?|eK{=zC=4Jd- C믿(d̘1Ү];}xwqOvm7Y|t`lBb*)n:|̲A)V6m=e| ]tLyu~X̐dA׶m[7f _~ =N8qcH_~yv˧Yxn?ݷe>{NN;4@\ĕt!9Aq2uTדIfd]vyw/"}W;xV&qnm"UOiܸqb|` ||y_rzgp J*nh"301!YBp>, <?pرX)$lg!P*#G)Su*|Myꩧ(iAì$r b_G,ax`.5Vh2Y_i; cǎn8)pȍ7(hy~;/C$D 7J8^{E?foD&YJrݱ$ɀܒsq_ |Seذani|(DV С -X %,5Bdx;V׭ր8[UXƎU ^~e"CJZ%#t[Mp„ȩ*|DMZCƢSd%hA`)"!n%w8%O=ԩSl􌔴XYxV rAEW8q܀/8 #P* TҒb8eszJ% 6mHnwX&M][v`QV|B@Hup.52˧'f˲eN9s|Q.OzZ} sW HAa2|sV 'ϡ>x D \d.׽_~ҬYp!"@@dRY%D!DA V"@RA j"@2I)#D" $TP5D"HJ7%DT )!D @R);DݘN'KRJ+$aE*6yfxb6SHJIC @hdo6XfKI!!NʆRD BJ UFPBc s[f ]vOIy 9&؏R%$<]RBA]c{P r] v>,4#U&AT (x=.7eRBph@@FDFF€MuRXMn061Zu h@jK*zct ,H w!&T2FPod-0Rla‚ *ZiøqҸ{'y/2mՖq-%E&%j0_k,r' .I.P"I)刮6  JDib.T}S+0& @O)+0!"t^%)B=I) )"JJ<@ @R|1. )"'$ Zx^F@!@Rʣ*Vb:1`@ "D~T_=;!L# #11#WjQg9xSN妹ɣr>=8 Z%)J kbQ 2ց7 2yiR cJǘO D )%"@@Dc'G@l7}R̀B|X/I)Ux1B 2"݆RlJBDt_٢3c H$TP5D D`k}`x&5 -Ú_| bc؇V0JHJ$e uWE` Q"b/J@R#GIQ@0d.*ۈWiܸLaF2U`' &T%;^2y@ݳw=sx=ztܰ|9uVVϟ/-*+Z5k닝wbݺu2kV0HBWBN@LؑRe$)É@~;.g}zq$ZVV/)?1Jzv={kVR͛7^{%5k֔_vf̘!slҦMy믏F}[os饗Jjdҥ\k"16 ,܄BC=$|򉠅N;w*T.]裏ɓeڴi7ԩS[b\y啂 = C%J*M8;ߗ 7 6mCڵk裏ǎ+o̙3G6l-t΀3ΐON?t~Z^V*h#?4jH.iРAy źJ$3gʠAǏ+W/w/R^G}p?cK;'le:餓guLU`zl>CcII6t)% /HtԩSG^z%WHFBҥ<#駟\ĉYfosʔ)SsdV1cD˓!CQG&M$9xDhw_yW[nq@6 ҃:-}֒%Kdٲe8D~ZhP#-Z PEWL–-[_~ҿG<묳'ʰk׮OS{ƍeذaҲeKi׮ >܅cf_-m۶uנ좋.rQFyvlذ5T<@iҤW?޽{QZPt @ٞ|$(* 혧A/?G=d=p]8*Ur_|!WvѽO]+@"hBkWVZkX 5TUh3Fx .4Ѕ O vHE qƹFٳg;ImN۠ 6X(yH>UNN;4Awg*Tj@FW_}нA… U\7<)*)ta< *{׵~7',FLpx2b!`/O`R /Sہ by].%vw `4 н2Qóp (@X[ۋ/<<͗_~V9ꨣi^x]?РV{9g E8ac~RQ.nݺk0ʪ0~MG܀B`z-*5ϙg麽Py%M .zʵQA危$bݽ^}UYx\x;F3ܾN#wqu;ƳcKyJ:St ҫ[c.?#dP&XjW"XG$|k4zJII"p6kB]ZMD4{4 KSlZ7U~z &&QŠD@>Ɔ0Ȍ>} :GE #=ΣWLQ J껪KOS@@@FBhPqH5O)#!B@IifjU|1q TmVB G@'1%]媰)40 RRp12 /kNS}@U-a jR@"dR!)>({eU[~[dE"{1[~Eql2G!DFJFLDK~HJep"P8XebT89gNA$]wvlۤMRJ .F&GrSTB32RZb"*lL23厀 ɼ4$r/ސ"PPRZ컴D T3m]3WdeʽxC"Xb/Ȅ;?eyf%ё$&eRPV2"X FRM080~R %)%#!UV/*+!^)v\eIJqY"Ph=#?Io5sIݑ\L‡@d\[T( _FL!`^yHi}GRT1D ?@ Zd(D,`/f+okAD`@}`dT`0 #`<퇤0HBU&FN03X.qr7!DV/sKb@cƄk"6FHրuک ׼4˗bg:@A-=O76i^ArPB":PX-*}b. {11;ㄷ$bD"jPX/tIUQZ]uGzJ0ۀMU]JuRU Œ OO%/$1D Xƈ-**G*ʑB@yU`v]hPP)^b} .%-$!D \`;]*XP© 5p^Lbf"t[cPYCAN~RIܾhTRQI[.8">4i!)% / E *󀰵 K<%x;BAUY0-`Qc 5B +y aAZTckx~Â4kEr 9< .PFH؇@1TIOI"@t*XD'$tLcZ ׎P]u [؄PMn"Z  !B]%<#Zw]]P?i1th#¾"[8/8)a]Rp12/o  _m  !TQQ;C-U  !=>RzJ)C @yNȨyFc;m H{Ϫ6H>m22HJD$P^w83@%斧'ށ"PX;RLފBZmWsz.D"P}W2]9#eĈ}h> i1DxO\ϳ6l][*W￿L2EW琲':u/2{׳Cy!"u&L UV5kȴiF]w%+WCڵk裏Mʷ~+]wr-2p@Y~ԩSG|Iy駋ݣRJrWʌ3dw{GO.w̜9SZ9ꨣa/ԭ[Wn6:u̟?_F% *`]qLx,Ϝ9S ?~5㎓e˖W]uHݺuV ΫTWre#~h7H^֭=%#Ǻp]^5;M0%%wnSNqa5<@Uz]Y&l 'R\*i *1A <믿n履~rU´ёzXxgAJ wkҤ`w>?||1  $KJVc(ah_Er5tM.W\Q$,ʻ;W񓒎]y~W^=wv<e˖n?dW~}Obd8HcJZb"@&`L?\|nB9#˗/LFXVd$걈IR 7n^2eС\zrw{%O< 6L.]Ǝ,f @z.]݂ve @R* "=@ ͚5?P.ѱ.6GL;"Yn{,>&IĆjJ>cr- fA[m,Yfzn\=Dǯw?Nb7jn}ԩS]|Ѿ}{793( >$Xm6* ߄':TjOƫYy{υa5n7XI݁zrpwݍٍtʸЀ:[iڴi&/LXpaFL;wMt]G#7cJ(:f  DЙl %|mObvKЍ7o$r|#%b(D"@I)D"@ ) D 0SL DhD"HJ) &"@HJ"@ $B $% DR` !Dəsm#|%)>"Y!0Q$[!FUM'%oB_  A@㦈zX[: qUDZKHJ*Tݨzjm U|{jEU(IW]j*bg*FJV6z*BR F90D 3O [T*Ϊ !%%9 ?]:c GF&'$%C["@p_TQ15ouZ8p<@FJ &` 썘P3@&"D X'%T-yxM %'))Ip47{K (iY$$̧BF *D1^dc#Scp6bh@AJ6q?4PBR Tq01D XgeƑP'ď5@B6g]x]%)4/!D zoKd7" c "?!B\JWLjɈ$,\AO) D0l@D~O C"!))y= [w $(6ނSB@!tlkx)!1Ιƒu, Ϸ㬤%٘.YlIJ) &g^NI(6$XDxL 9C"@ @b`" DhD"HJ) &"@HJ"@ $B $% DR` !Dm"@I)0E"@I6@ Aߊ GIENDB`./nsf2.4.0/doc/next-tutorial/per-object-mixin.png000644 000766 000024 00000060645 12501766547 022466 0ustar00neumannstaff000000 000000 PNG  IHDRws pHYs  iTXtXML:com.adobe.xmp 5 2 1 m @IDATx]AQ E@QAE`[nkbF$** _ƮQcEX;s~~~wyΝ333g. ! $*B@!@dl$B@!Pqdl* 26! 826XB@ɀB@TC! d@! *M!B@F2 G@ƦB@! B1'ilHYJ]LXW i=&0"fX̍D^#ixeJ lJP),FS6L#cl1$ J qM4@WF'R26F L XV/aYH#C '11C 51C7Ĭ>]vS̎#\ A@Ʀ7ШPd/t'Ov={t-͚5GlժU~7(VI:)K ,uf @ EQ@|2Yڥx7Zku]w]ױcG;gs͛7w7|s֬mn5.|+/rByѱiWR26E[b@xTCcCCSUc3sL뮻{>nȑn7w?;蠃<- rM +;Sy]w38#fllTl#S26Eeg. :M6]wunذaO>Ona68Cfm&M;vM7&N=Xww7rmO?u[oݻ;묳/}Y^3<ם~j׿7`)S#F?>vm͛gFrByP~(K0(0H @(`,;/x}0ݐ^}U+%X"tMΝ;hSN{uQ8'x?܇=8s?G׋/x0tР{1c= `öf#$͇q?M0dͼ<jxPRr:\Mpk0ɯNyb JBOB Aڀ7je>W^{-Z+B0}tzk?zt0Iѣ?>4k,8Cڵk*? F8>ԩS>:#a ?OP>PFn <vrR$phx(왒s}X:7{l .k/'|k׎;c!.V\qE7ݣG7FOq)w[fG}}^!8F2DY"D@[#A]aوkƍA_;wnhvBzG=ՙ;a ŵm}Gi~w}\1CLùQF0;%flWm.bʻPـDsqrK/5~ Xq r|g馛 'n6zoDX{yB> փ(fJb ~m%8M ôoO<0-ݧ~ڏ4L24(¤mAbeJۜwo hl._[_#`Vk#@;s7mfw Tߘ5/-[Xcϧ0z0l„ > [.]0~##ɦ` r;7([MޠFE@UU.pqwi0wTjOK^ eے]A> ?8lp\ e%{F1.=tOnCRxEssN"!Pot H؈dqB8G$6M24O9!WW3K g)ׅ#`Jl<8:ዚ\U2:E/cS$p-V*, t1" ɤ b"*XƦtKިtQ5ءWNuDLv /7OhEB XcF"ɵ\G7W&0eVh(tPZS!AH²B y"ͯX*{h$*a)XP'Ő(Е)0E-aCkV2GdlXks!2*aSHz[e_hYb"mBe\ !!7COZuGƦ. mrn*pIPvdhP Wh%h#LȠPBFdlJO38Ʈja626e*c)υ ` ]pʏaY?T(WĭE k2XB:L`)JB! F@Ʀi|*e@@Ʀ * ! hQB@2$BidlGB@!PdlB@i ! @)JB! F@Ʀi|*e@@Ʀ * ! hQB@2$"kn3E ВJƦ@=X@ BBS26zA ;2ތO_,0Mq8ŋO 8!"Mũ kU0aܮ)/Q 26E[bFͰ ˴`7{lצMoG ?j4ZjD)7XHKO>׾}{׶m[ױcG2˸o}Ѯ{nVss;s!S S y=q0`pj̨u~7w„ n׷nVr}].@X~hprubQJBƦ*ͨ!`rn5f_~/H 70_B#CSD.ZHT"Pvm~7pСC#T #S26%[c6x{]޽]߾}]˖-6l;peAXL[4#d $K[eˁǖKyM/~ 4IF\ <<(O9O-Xo4-K7oey&L5 gi- <! M+XB@D(Ԃi͛)sB ġǚ!0qDsxݸq㊽] cTAy嗣5IT­9h k믿ޭꞯtس>n;^S>}O?;>?;-秡|K݌3n磧N16g(i+j;3g-!/t6ZK02d?N~OhƨW^~'ٚk7wa'?߻+O `cܹs:i@OƦOTgE-:9U@VEpGQ6z ?ЩSQ(̙3}ZdRSE9ƎyWԩܙS9T`  %l ELlqZN6@F"溇\h )#FUB Vh&Vե %pH$M%U;3A F+oUkdS^<B@dA@& (B@" cS^<B@dA@& (B@" cS^<B@dA@& (B@" cS^<B@dA@& (B@" cS^:'>_uwGƩ(ʫ :&2UTWS T#MWSzȦx*5! ȂMP%E@Ʀx*5! ȂMP%E@Ʀx*5! ȂMP%E@Ʀx*5! ȂMP%E@Ʀx*5! ȂMP%E@Ʀx*5! ȂMP%E@Ʀx*5! ȂMP(TiMTT"@292dl\{{!X@wa _q eƸ>Q(Celfd]\+FrBZ)_1L#"kRƦHt[|`/45Yٕ`)| ffurGjP"hC?1G<}w?2Y5B#k2Dע"4Zx!24 ׇwTfcIcs!\hL@M/"*7\ܵU ^g M5Mh#Cͷg 7OMۃ[Ɠ¢ v>h>ͯ? n}Gns)c:RDn3obɸ`6"|<\"C1hJ aUs l/dlꤢ뭘h8J h Ξ/x=-`Q~lhS`׃4,;;8W$l$C (ԟkraq s-w"\QVws@0bY`2wl"!pO@Cȑ:{lwR W@O!8G0|^ ~O$ Mrc:n[e룱+*3ճ%0NM>-wf#E[>EB pE.245NvA@$ ipO y|,qX eN5 4FKC8!F|x4n,1Q5gG26 e%?АE͑`.VFMAWX6&cS-cĠ_ ff7]q4߻ 426i(tu`h6CNC|;]=8%zuSIj\hxr06#óDE 5ڜNhFi`d@&D ٧ΰ2gغͫ!Ȧ?ҥዚtm5ʜFOdl#_j$_|3F4: P-O" cSU݂adͭr TOf _! cSuȐ ^ Nlm1MS}DȗF/j ǷEMZ[dv"c)B] M]Ts C9| < 5BB;VBrsuqK09 5k])ez>rzO:Zxh0yu-gW T x%O ī[SSۚf"jq!P}0WPSmGh|8nW24 f>oz_Q1@@&,ዚ닚IECSi(1dl_( S=5Q5ȅM5P3f {`dC`fތ{ݩqP [^LJMFhd [;EC5#XOkWx`N{$szC |?>M6h d#($TP祉CM\,h)bdcš$)NL.ni0$+UqPQaԛn,eB8Z% %R CaoQٳCσ7aJAJ!6`:g?ij>ύsAx]y2PlTccB]1PQr N+ (eh̠Х,+I(ԟ;沿ưȒ `hTcJ´fxlΜ9?wJAٳ]۶m O@JnDؠit#,g(CIK&OXb r:۲\utRryx݁kFHXbCMQR{ݮ]vYꪫVZɝ{7 RK-fƏ.B" , .놬y-[o=׵kWשS'&Gy$ _b.z^K*`W{ZySҎ*G^0\l{ 3pUV?Jlߞ^z0P /(,q4Gu`9fCUvRAVǸݗ*/é?]Y? 5k=|^ZnL6n̓=ܹܳs[n,Oo0{ZLa-SE l4,p+p#s}qGye]{j'p| [nnСnĈ>Ç'S:&uYuAܔ)SG5}_hGsǺs>6rX,֦=ܤ7-\ 6:qM7;3s}nZk9Vw_8]݀駟o暐.#@XL(O AҰPѸWF+x8i_@!A^:vmI'^y啀pGn9v%G}4@_cĔ5@`nؠ? "Nb8jl00v"af ?_ f':<8S02Ҳw=8~!Sgsw Sl\?QZy?ր_駍rc`z~ QDyTʉMQ~뉬̦Cԟ}Qѩr;^|Fq7tk,&3]bnߞa!̸́_U,(2娞txiD?4wsxŧ19r;36Էo_7}tƌF߮];wꩧ0=EOu,TFBUW QGfΜ+ͻąNiXo, _n0ꫯ,X0S膽Ac#@9" U@sO޽ke[#͝uY>keҤIE"m/^Mx;߸w 4h}#뮻o0AC1Q Th]&8lӯw#ą}h 3v6 {y뭷}A.ȇl?)Y\=}'ԁ_,Eߋ5紹$-307η"ܝVOk625\+8ka,NJQqӯXC=on~1_vf^s}o `Pq |2Azñs!7Nk?#Xp{^{|JX9E$@s>f>q֐Nh_~رp;Oggώ~dl>i%z([R": <9vgAvlMJ(IRmJf̘S?ϟsz:8IL "_f3<"l6x>vHRi"sJzdI#G|< QH:;?;cE_me%w6S?\S!g#h0G6C06X.Tc"\H5TJV[9LE z$,;*V GqaRQ1Fd'6E(ؘX¤ ̯ܩyF"Ͱ;,O+$e.eÑ~)&\Pk,<M9GejҰ&OUKd^*je㫄@JlT[iT=N&[Flaa(w5aT~a PbE6BU,3٩Wao U+LvbK̩)%f1yd3,./,aH2$FPL^L߮q#u]YY0*3@ ԐRVH֛аV|b/ɂ@JlT[D317˝*e%Rtͽ;M=餓9}ec:FcuWg&d `B7zTt/ v  xY}zf&Mr;wv-Z@4uTt]ݰa܎;9KXSS3S<;DZۂ?ԡF3w\w9tynw?kӆ)J )L#'p ʖ& MZ?}v|J+Yg[oFƎ{eO?;ߟ~.5ezk)h 닕۰hpG}N;4we뮻瞮k׮nvsac馛Yf5HKetH(cY(SSF}׼OF嫯r<ѣ;}>M8nsGub-%#`rB׮m:˳!+{>5H#7xvg}yW_ucƌacW^y?rHײ%O"@YˑS$[Lɻڵsq)Ç7CunwmrA@(/&3&ꬅƢ >{}ݽ﮻>1V\qE3 O<0QKS&Up!׋,pNaD)Ϟ={(B(H~NfفZ.])ᨗ 0blL1 _fJyldgf9λ1B;,'_ZL^(3fxɥ^KmYp%eSl걕an!#1(qIi:-ek{+UR:t熻DCr+Jj C-#hhfZk9n%G5޳Aω{6K[=n3g4划@j|{6|φ{t{6!{jd{Oso_0M>-2ߧ@JDMfppZ$h,P ie3JdsJFsa <3R&?a(5g0S]! @lm)B@ Kc`G !P8sZ*麣^\pA֙-JB' d:PRY@,MR! U36C prOw&?0ap߻#<ҭ tW^yŢ#y-o?cEB <Ot'|޽?v„ <=nH.r<Ϻu<5n6zݺz\!P1fl[ns=~ s;4Ꮴ VZ6GqD*{ӣot!ďq+3 ;kvR:a3ytI믿;8-O^pkxb4O OuE(=?{^K,wCӗ_~Vc9m?E@vm*AB AÃ40|K/uz$Wo}n6s7t~g6h#Lwn5״`BTmdÜ*p /?l^x8 Zȓou!#7z{~G @K믿]~原8|&qF:9ڐ[Ijl=wy&߈-kO11G,|La~@hg7܍ֵkWwOhJEx4LrHe]Ŀ1x0kL-Zrg8I > x |w>)Xt NN3nw￿q ^<xYpKps`y=('g)0wo ܨ.)# N g} nfK|~bL Gn(TQ=ti@F0Pp@|V )[M#_ Go8M NtN [odӹtd]hT̓[otr'O(NN߬ !Prx_4ݡ_Xǐ[mjlܯ_?_#mhlMi<):It!@X§>gFt j"PUcgL9~'?xV[m>{ϱcǺM6٤YB :Sy8'܃>s6KBT 2:ƅ]{94mڴa, E2 sYU)L.d ˯X񫏮@v̰JJ56VX ;6 59j ä"Tѝr|b lh@I+Lݞ\ָZ.0D/ADblX8c+8}mK<. \,L`cbƍ $+ .3gIs&"I9O(oj? ] Q.恩?ˏi`S^bxEJmYP6(a Ӧb0J@ALPYؠP.(T eyEAMVf!A\L+C YKr#Q bxXZ2A1.QFMpm"SL²,)0ŞG YCi3*KX2Rò!5a6(uό ;Im&Q 64{ǀ?ׂL6flS6ȑ3 k fmHl#bg%IY="r[od%"ܐ0̌ 0e"k$̠P?ؐХPLC%EX>NW\,sKp_]̶lC&ʀu'?r]AE0e J%IYP#b>2ɊdBq(A1eИ~q O%6e!\OcƆDckh׀)f@;dvMo+bXX6,8 LCCE'~ foވAY0e0c4ʋRy,'^XQwى3cXq ، 8|#8 .2 D>;x8Z fd?O)@Yd~i)\67cÝx_uzgaC٠1ae}WX0 bD ufp[9GOTtdŽJU#Q]ʄ1gהrhcC+$. TȃR eވblrAה (N`n0ÊPhXfd?42ǁ eba]sdcFb j]#pʇethc"}`B 30 3%1WMuS5%0=B10GRg5xfB5p}d5TOb*2A cFgr15` ]φ&^լxqPJ>%hXzqfE ԜFm x jiz6@><.:TcF?8e˭ob%Y.\kp.! Qc?%MeC3zpK_Xx|E Cr@m1KF6`a@t`( *l-[hȟ3 !}>DY#hѢUAGl_+d9wٔ?JQ!Pe>9xEM)S_fe"_Qyt[KB@xnl:=T:0Kn()()0)KDg=/ުs9sRK%PMM*_!oyjauQ{衇__ܾ["NG6V5Bk.8q SN!+'--?ټM4=nv^){x㍕J>2D*!PZ"ʒRYqBo=vm7˺>ȝp nذaK/u/k߾ӟ䮺*}\{E7@xe]/xK.ĭ.r<ԩ7"[Ns\s٩\rI[o/??1)| .c-uWkv5 fΜ 80yfk̝;7@cvi>W\,\0ogMC &O>?//[?c_ofmӧ[jw!U'l؃Ph@Ν]ݽ6)͛>mᆮo߾ .p|InM6n֬Y?3 Igu}g~O?A0|ᇮK.>M;o<7mڴtx/dl^*'27@~j;v+ݎ;`x dA端rw}0`tM~|MǴz0 1jr])< O+cG ې3SUQ K/=zn;\Ϟ=uٳg{?OղeZG11C9=# #nm4u]݂ GaAZCS*k6ϵ\ |w./x"0<6pcC~yњM Q/՞ךM`Q`7}C3 Wu]cT3T՚M{>};< Cgޗqg֨#GL `Y .O!Pf_i3El٪U+%v-}yѶmLp"3E0p/wvi'f&Lpth7(9@:~[4|W&lⰃĽێܮHL~Vgqip%_⢠\\{?eOy{[0_~e9bm>+Wzq;si4Ny~X`N6y睽K/.vX llV`Cil`Oi%_{5?}fhf|Uw}sw9t9ыc/~`vaAxmxK4],Jrq & P8kM[Ӭh&3B?b<[PE^_+ %ib!alUW]Տ %-.8EHCewg޽{?j`7v'ts=%y;Oֶn_qa/8*geWm)s=׏~8$V_V۹r\f6?2~㏯j3#U}Vy7F8EG2{xCƍxׯ_??pLjn$N1Q.coܕ,z#is^mE E!w@rM>^'k/ǵEN#s'ըQ*NM{  )Qt7;[W_}ݝw鮿z-!HcC#A!`ʿƜ#*E\O9{sS駟}l|; G4s Gcƌə/9*1-\Wgv׿Yy8 GCg1 pT]'bYlNd?Ų0 v&Fsm1Cak~ u~;_ֹ6eT>-2H6zq*d{!ƣ{y9$>|>3/G6+Upe"CM@l9MfSe)\p ?9L{ffI|;G%r%r7ZB@D/GMG4̖M9TZB@xQp+B@"3[r ܟtaEFl(/~WLų~YC#P2h.Ze|G 7ס-eEIMؠ 玴 U3.#6/ʬMY"F/.:ϋN61>Ry낷ҧBr+_GXƦ A)NL)d`lc ]2E,saekfh Yٲ<7P ?|]tm[+v^Y.ˁޘ eaiE\ 8%ED+g0O+`U0i Kxn(c&o3ݱk)dl 7z)/Ŕ1L @S2E6EgG6fln2p,efiT{D_,A2*F6EVۛg TzGt7x2.llXM!U6ΰ&u̗? 6Y'y٨rg@x"E1E'0nI| ėpo(c&elƆ@Q[Qqߢ DTvָeYYv\A^Drᑴ"n,c؅A;2><9K%*;.F8U34V鐛Hh ӡ)ռl(sa7oRp.Lp Q7D4 [p.Ѡ?W uT Qgi3IIYh~]U‰X6cpEưK*Z,_o@ciѸȗA{ÂގzolJr\ PX.YV+wvr,o&IMhLFY|2xMp`XR6ґ~E Q8r 90{F 3\ffPeC&"Fm)>lX"T=˒츔͗00`'LC7s;2o ZhNgk.o|4, &|Oakvw4_|G;^{mgwy?97 MF&T\>F2+)$2*UB^&{5k7g563g  6J 0  LxwQ  ~)8蠃eYm֏TzlD46L5kT#n _&dQ16$s^֙̕p*eC?'݉'ػ#8͘1}~n <|ns%\o⦄#G3ȡ6xc/Q1=;{ kK~?gsܕ$M\!Vq1^Ԕ0)Ѱe8m݂֭[)( \y~ZbVKOM!]+gȵXȜ/Hdb0_?/8yjLHO۹6Z6D<3*?bB>;mĺ4S{#c!ۨXm<3( *OzZrN 7w!X}1&FV:9O/~a8 k= sHm`U` €?42 ?{N<‹ ÑȘHS37qȸ |ٸ=/ѽ9yxg3_~Y# (MhQ"ZmA5͆2he:BxF4e$M }_7 @r_럈"hATdKS#|e 7mmg_gvZgh^h A)?46:G}"GV('B@yΊ@h}`, pY?A 2@(QPA-8.f 0(o 6 Ad!H R!]!W "8(@%Pt@ hz=EF$Ea9X6-aGxGp\5E^E %AP6(7TJCP5˨NmCj E3hd@Bi yt+!z!cx0RM9I`00-8fŲaŰjXWl6{{ۈ>bWq8'N ybq9㸋^nx7|>_A`C#$g9(F!:Cre93 ]0]:]9]io$&$ɈG*$ՑHOId(YF%7/f,ŜGGR( "eW/3D*:3223*003d8ĸce2acbe4ˌbb6be|yy"bRreeUՉ5u &fV6݀ݟ=27>?G>G#8wN* g(g1g .4$WIenn-n_|fIGǞ'*/oqޛ|l||!|Gzu/QY0j9uEG`@i A1]/BBBGVS'E""A"Dn:m]3Kk{.N$P8!1* KHIVJޗTNH=HkHGHH?!4L˲Zfʶɾs+-S^E>L3& LNOJJڕ>*K)+T~¬br@_凪*MꢚZcuu[w4044ijj6k~В պ-}F{VGP[Δ.UK^ތ9y  i-kFF{Qf#&L&L*L^ 6Q9y^[$K +I+U5lma]j|Έm6ܦ慭mu;]{T::9>%+nWnz5gc)9.î\n87'sn&Gv=GlO!.0nOzOoϫ^/g ^65ޫ>>U>+F|[/ ( X , \ * Z6 #:d-&.t+91q+/21ATTNTf%\ '= ʼneMWƯ'8%\MdLH$4l|6ҟ*:`4('о}sf3dgd~_37+=k6,!Cy|@@u.:78w$O)x|e}=pVa@Hj'ϗ0$̖Z?ѡ2ccqǦʭۏ ?||"bҰ*j߉'/WVT?|iӭ55e7g>~׹s?"۟UV_BQװxqKƗ/\>X⚖x]hl~5kU--PkRJ[PTkNΖ*Yz=Y=[ɽ}Q}7o{?r-[#wMo6{GNאP]mêíTGˈH}xhp&vM'Q樛h3#L8ۏKp*R򜁁ђ)ym7EN47w7/ N!19BR2_)* UbTԧ4~hkKhf3n05}hc˂R}gMm]}Cc뇝\ru_nςs^F)_C^ՇtRޤ鋭ˎH0OJ"&-%KiJ-ߛ/:tVw\ڂCB'GJ~>^|RDg52Ng=Az=UCK5|~~Mۣ]{znDg,U6P6X|;w G}}RTǾ>|cbbc'OE& =xW^S3 3f߼zscBbٷ<ޛ|ZaXY8/٫A_-֙׾=޷Q,BD0DtVa^Q $jzRm8<~PE 3$)A o0-%7r|t;Q/l gnIH$*$C]1P)Z9IejZ.^;iqûF=WMLrw$YZRjb;cϡ\gsW%7^w{vQ%uj1 RN>-S8xăI)pƽivghfjڑq@ټ?j9)>\rtț2Oqʂ'FO~=%xڶfmǙd__kиz4\

    y851x/PY^Te58];ZlMۋK˔w">tٛ?~ $ AkBP )x偺Fb1X[,.ύM8D&q~g(- g˙ sYYs K99ڹyy{z{ZNĉ$ۤ d2K-r l ӊ Jqz*'Ԃԕ5z4,'ujtC6 I4)2u73Ǘwү)9~`AI0@K|BrX]OOҨسq$%'5%PSƙ6=HFRfY9r<4^8WU\*xDf1r>UNX=|CHmҙsbui'.4d]|vY1eՂkZ?T5ӣ[fˀ;2Cá,~ɍ/+9Km?rl:owmiU,NsN Jl;l8jذ@O2Cp[)@d=6Ns } e BFuftH ѯ1L=L4fK`e8.W[:""(ttc$u)2L#XP:+  kHهy%+kMwUb. <<  j ubQS1qČ-NMr }J/U>Y54eu$uzLgF5ƹ&.f;,-QV+K;lfl^ۿuÉ"f;eQ&=·/6p h6G(S@dlLD -=v1+:1+7gҴ+gu;P pr~TqqQc*Nr~{_ܰ|Cr]=}iމvk`}li\޼Tʘ]_6{#wD:?,CQj;d$ׄ\ ~B!9+*u MFNPt%$Vacy;8"Wċi~!0H"f,:IRj2+ Kɤ (\F 1&AFf}qpV,k  { g<w)^4o?~~S*:!P##d*'.2!&vJDdTtL9; /הYU4U} ջ5>hh{T>33l4011-06XYXXyfv(K9ƥۈ=l:^=>]~(  G)F{ c.'%z%$eO3߷79ciP֞슜'y' ^)L,,(,wTr讌|a5}~w\?~(rtl!CgXGj8m2RqAmU &Ӎ`m%0no?CωV>:5ӆ{dW%#c." V2]/μDu= C0 C7dzRvT1R Pg]a!`@".LۻmGĺfW!`!"l7ә$PGa!`@ {i }tGuz,!`!`N'Lc¢0@c@ɲ!`!P(`9C]ҧ|og(>C0 C0 *\ j;;9 P!e1 C0 CPP[CPGdT#i!`! u`:[!`!`dP+hPGd#i!`! u`:[!`!`d C5hl:)4`!`@!`+Թcn5!`!5@C;;::<$C0 C0 l"D;6/:+K+0 C0 |@ Dg*#ai%!`!αPp0 C0 l"DΡF#Ҋ1 C0 C =Թcn5!`!MlG6MPX!`!`@-Rbtn]QV!`@ɪ4^/mVrq#{Si;ñ`UG xo$k3ɐ<u!P$pH}%C"LdזJ|(w5F&a|QH;v*WvӾP2@1 xHD,.^DRE@8QFg5qgTX++Ov6bV+v4tO7B+i@ &HEk<.4OauG Fqȱ&r4i֦h񴻑BdRbyvo'D#e CH@E|28j5|A?ÔPYUVG@AZ:I4iTVRB 3/Yu$K e3 D 0$">.;=\[8=7}Ť'w(C7ގMge6 0@c=KmCjb˵v!`y@`F!Ѣtu?/7I~ ͘wV8ikhq`zޥ+^^=bF#ъ0 C qfX5^^uڵk0Mrʕ+ٳ'|Uw!H" OH51)~ϿI8uƐ!P`\QDH'3 uyy/.kժL;w{]{n=18ٗZ'"FIq#v C0 O|M?Ht>}ܢEH܌L<w`Сn޼y+`MG;ɮԴ+O?~C5m:Lt%ZI!`|~Lp w9s\4G;]wul7mk[c@QF I"XTHQ#I8C0$yr"_' 6JעE;2a7`c]'֚4xx!Plp#i! (!P`&EDEri[&!\[bA @H31 ;6/ Jcb@) BM-EͭX 8UyK.]x4 N?Dewj kR"(4Žm{)1"H+0 9i! !K!`>ۇroM>xL C(6Dh OD`іno5۝ۯ㑮Kf!սk'f[9͕kbhq޷|ʉ Xnz,F-㡇3}4kV>h2[c:~iob#~0Kљ>J2 FHDH:-xq7W,4s݂+%] wӨ^n|e2Fg]=rz/w(e=/_=qI8srD8HE-eP'D\0o jj>RsK±'hdf kC'dzĉG*:,7n"[v)Ɲ43EI-E}{A r E@-̟It C |dZq$Yr"]*Y=wU|JvLwWK/5ex"݅]^v۷cGmٲ-3 ҵNtmAIP6ָ61PcV3=2&!`H u=W-y;n1O m39ǣe+6U9nnܸqk֬|.-W1% xQ&@"g_N OF|!P,O?+jj>.*i&%&DkuPwnkh`*ؐ說f|/?E]x\a{1Q.-p)d:%<%&xfte6 C   Ix%T6y76wڹ_H׷{{W}S{f2yU?tO"N#MiWiښn'\p JH>X ŀs# ]ܴ(`:N+ӂX5&<3rG( "T"ZcztFpUn?"8S]Gp]k0@]66^Yܱe{k#nTmGy#J)U!kƶaCd9?dZʲH'K\n~1]}wPקǡe2wM*סIΣnR횷lT\#꼪^Z?d{<ÊViCFà.p85h iK_k.=?C=D2_g_2]N>Oxd"^eE$d~~ o g,A3NDZֱj '*֠KStֵ$WʫPH"n\yl,/ﱗy#̓kf5+΢׍n ϫ}U_F]V\_Lņ@qn8љutXf\R27k9˦_~[n]v 3$_ޭ\͞=}']Qpop#3E~ڕqұaa9B d\~U#]zkϲg{GyKoH.y  gY5 䮙|ȓ\[o&(wr|ԥ %mSdgц@"lG"T=F[=H; W_}u_\֪U+D44;wt=kA{w9cp/OT, OV{wvfҺT4n\z=ZnǟJ{Vmkc)2iDMdDqypk!!Ƽ-D̨4\L3,bӧ,СCFZ" :}_wW]u/~eÉp_2 4>\-Nj2 չcd@{oL!P8F~N M Mhjjhi!1n#3g32 4T5jwuױS-t}P#)0 Cnspy8$9i߉|Q7<2ZJĚ-&Lp `߅|2-R-3OD#ZKu+5)D m*ĮX Em:*[tYI"@$%R8i0gV3s[n5y4EJꡈkL#$S$"ּjT&ҥK q+tAi bB !"< $'DdKċ61<D!ȮҲO}0' RM-r/Wo^|Eg>MG[/;pqo\E]}SNt]6لopۛRkAh5~uu] 98M͚U#G'rږ+g?!$'O|_?ᡇj| ~yNzïrs7t6(?O3'MЮt}IqՂFxՈN4O2swg+VDw8ٕZ(NXk!3B-R۱y_Nt%ZIIFwPTdt"_9j}2=]~n#]L|_&QZ>覝ZѹR|Gs,e Q>a_aE!^ewiӦ!h|GSN}sud+Ftl,(NajCђ caÆaÆ38N "|IIGq^z_-p}E}0(JS“Q"'v# $L`qYUKގ?yis cx{v`!9# i%,eժU+;w>y}yn5(G˾l1 0fb Bkʵ#rM ""V$Դ͎h{UVGuUCg]}aUoZ{dw(7+ט7v]]د}C ]SN~*Vvu1[prS1qw)+N!gF#{Rͤ7!G⭀i>xh#vOew+l1͏.1(aP In $̉°'k\qSrQ0=-5yn$~ 81wɐn/: *.t;wln߀禽j:?@+ IDATN&+{e\V*MvurqKCڳ`1ß;BMʮX"]aa""~XdK?j'1 sĞSV‘lr(26CRM-Gu!'pQ |~mgUqɰ?9VVpXiOщ(F'+_Z,d11Psn hD+),`M{aN~ްgq!nƼ_9IO|R&F /8+^Iͣ?\ђ%K-7Z#>kѢEC=7dLf+0,|i7}M,- B0ŇVCM4`9&G@?d8E 9gM}{jpW^yսt7iM?Mv;vϻ5 rcvV]m_#)Knȭ3[Qn5k>Z&UKYj_l.3;j?_\M8@lLciuZ6RQheZZvd^%ڡZVt߿gkٲe|^)xN:}WfDE_:5nL3DY?T]7&@ d+љutXfZ?5sB֓a~s猽;'c,q/x4ؖMc~=-[}#lN<KrG`QjnuݝQRM^RhKosYZט &i^MrEI DO"FrF?E*85t,#va_8p`>dʕO.0V С([P{j:POBhw"ۉH5m.RS _CHPFkARݩs9vaq&fNrJ[-[?u'u6J7nvΤ^m腳ցPys~&kPյ;uY4]6 jV"f>HRą(Q;)&"fD3?~vEN) tIA~ ׿> XoNeҥKBiӦM֓/^^NPU9_>I'պ/K6e\q5@լ۶|ģ>:TZj•̥/0Fo_轢9Guu*`}z֝L'.=-C\uqe5ud#]'_1QVYU6.I$@Xlk {s~jeZZ 9VDe*\>|^ƍ[]zꩇH CԵk#AQ#dVKd+$ 2tTnߴ!PD$}}jP(΁;˰&P7/4i_8 ïw]ݢزu SNgJ{=9wLy`Inŷs"Z]"$Gu@OI-Z7&ZwG#5H5WԾC0`kEc:T2?^Ll'JBݮ]p'ZZjO+R,M[S:"*K(.)رI̷Mg] n6˝|齮k[♿Si5./z-637Ͽu-|Z cU>DlqtiNFS/<ɾv6dg}_b۹ F\8c_!9_™ W6mFl*bM-BMm$ ?\[K|IpŤo V{ɝ*scYf>UF7qtO/qDqJL /;}]ثSǹp$XFyeL\&5UOUuJ5εroK~8h-@2GLydGNgn7˲u[bcwh>\].Og{V506i:tšdJycdvפcNmBvl\_ٵhڵm,ۄ ?=GpIHHH&1&Jܮ$DYLx +gX9JB:} 'k7`{8rϜ/ .bճg~-v'`XՐSafy(?X?7p!P\,eQt6C <]>KO'C&ںj6`1=p4uuIPD򶁗dB?>a_~4 $9fuЏX>j%lټy&)_4~֔;v8Y ;H\ǷDy"~~E-3m 5ɻe{ciL!PI5*+bǩ/L 5 4g1t!7?/Oȑwyj-[܍m)oITq˱NcDOu*1M!P{9<'e;!uXQxie -]fࡥ\$E*{S+q"G1Gt,´/Wy'O?6`U8يwC(o0MשLd9&@Q".eĔdh:#"̇DDSft!bDH8D@|DXkW~fȱ~(3r V6m(^٬Y3ÑlF?ـѯ0 ŋ0+MZOk[f(jkR{&m^ː#ԩUjp@۰^=WX6(* S4KWVǃL? S3~:jx㔦8_ <|ɯŦܿf3d3N딏s(0(J+#-D3 UV2IsBXiѢE{׽{.ȆFp/2-G@ZʫxM+60V4'%څiiR׾_իW󥹂7šUW/JK#BtI `[>rofMtk k`G |T&)S^HcW}o?,1,cĉ09wt$ƾS=fZC9;l7ͫqcy„8'/v)ت9I$LJ ҾO=汄p u8Kkp'xl?gE;YH!!4Ip3<[jB7@Ej'FgPgpe64385pU >|/\vG"h|wg+0Nvmu&YB @Ě5 ӣAebgԩS׿uB@AP0)/&H1!P V씏ΠUXH ȗIBʎ;ӦM1VH|GSNq= w\>)U!91V'huO袋L|~^ GL-rcb,膈谬OI  [(Bga|O>q#K/Y<+p%l6#B"G#H]d3cǎhԨdi2}}wJ70':GCê1 #V'[& P#(Ɗ@#ptv$B GMY\4NFjs;w}1ǔuS*H)j*[o~W_7a~o5wot|)d~jpj@c7+p7n40͍sq7 /<}o!`9885k}ꩧޚOS#`{S㓍T!Oj**:;l8k5w}%+Zrt㖈Hce8>>EEy-J;-{-8dNydg/#$3fIdL`liY>7,bm3 jSȃc]?%[\/TϰȘ45UN w0\[pVyS[CBp5G3>j}Bi5pN:mQfқ>*4m;َ6r-Fc 4<_|19y I÷*{-X~mڴَCo^mV!`DPۨw_7& `:P"}DH̸2MkD)+VqZ -Rֱc#XwY޽O+//os 'JZ=h~ڍNط4kV9*KcYL lfp嘰N4|kfy7ϠgpwEZf@o+I8Ad, HəH}26jåf+ҌSu-JϺ>[cow͛7~cWX2wQ֭[8?$Uf뉑puOש˜v jghij$=zt7ЖV Oy~{D[EUFslG#9IR",%Mjv),'r|-HPgMeC?p T$;Q"~7*7A9U)~(N~ioSX@i Pc#$`qg#~m<dl^- OE7b>XD@a#P{ 6Ddg#a1"LҼ\+$X'a> ;IE'ʟU]I`|Y]8yy۶m( 4e/ikߞ>5SI& #Z@&; /L2M0nt:j(P]$7in[(Q@sǍV+IH/tፉg~:SNy2s&]vдiӖ@fҥKgaǐ}/(lCa?mF,'"kT:,ٔq40-[ko8lVzx &-- C  egҢ.I",$jj&ZQq%?3a麬iˈW1׃UY[lYfmO<ľO>G4XnҴ% q="g=p܇#^Ay9G' ¶97UhP#\dBAr_"OЌJ,J51u"d#I:jK;s#xYӲe^,Z"ϟ(>~av2{@Eh?m&R,"yfSEUW #IC!Añ[҂L㴏':o1{FFbwۜ?ɚ :W֭ӧϳ[Qe[E>&mDɵL+&QM N|Ft"98Ahŀ@?inݺ&mfː#)N"IR.Fb%!`W42mIxj!XP3L  iv8{E(?Κ`{/| җt$3Ӻ,X6!qf8i.ǩ CىmO}W]4uY*6R"j~ѳ6Ϥ1|"II! $h"Y"_"czZ'GHE8 'r^S\*8∖&}ne+cS|Daþ.ă{qĄqWCۊ~Z[vfcAVH?pǎ-lwp,j0.cyASEt#4ByP)Yd)HȗH5Z"bMBG'rGt2wA"YQGUn2Ku*'XdX>;ozAȴx+]~jjiiVS@d~d3& ӿ7n|s6)ox~oC$vC@!P&k"2ꈀK1qRfJk i# 9L'ʧ&Դ~vԴlN-Oi#9c~@tA?Y.slxxLz|޽ːۀ}-dVԾcGyiNe"k7" 7`n֤3ꊦi?Fwyt:b@0B]Gࢺ=_$TI'Q_itcyf9YC9 o0c9epFTlWxfI+^ut zL^7 2=-5Ou7 m,^YO @bƌaxN76Dd22"$Y oxAOư)<~/#Y 5 B'wh-] lIPF3+YI⤚7Z Loji0.V>ӉW¾ }?Mk[8b@{ +WsD\g@" a:m'-J3Ur V'"$d"LAf<>aC0&ʓ,x{H 3#{pΉdz(ØDd:vbN*J C8268'YsUt#b>Hx7Q0G@fɌS_iqlj8Ono rT? IDATUc@NhժI-!3PgWV5 Sտ.UbK+*Oxȃ>:t.AV1I`]c:#`_PUsOsPUa@ [ T |kOvOƛ~)><%=zt76|rĈ-X!y,:c@XqxM% 0 iӦP܎A%RPIt#Y|>|^?xz_S%&NK{K+ ;M-C{9*ŽR(v}ݬY5PCh 7ojڞ(ԯhҊL}[nG>kߞX5^pqlF:  //,f! bo!usΝWoZHm/s(~ ggض<54j|4B*5N(>x#UaÆ5͟@7=4jz92?PPZ_"ԸOPGh2#YEt#pS[dB5Hh;vI! [F}H,S*:uYsYo!OCK5U#u`bQ 5t~rs%uG.hB3L ;A{}n{D ٶ1u3Kj#u`bQ&# ÷^><mO3 2=61l <KO%D g~/,w2T C lݺ5 5F#4M˲J .` }+2Iǁޗbl?y?WG}/1Wv_|_з<@ِ}EP7~$Kr\I> ){~ .&d\0C $jlsZA@R)7ģJ/qqr6)8Y{'[=xg?p=ޮcc:ǹO ɣky_*\s}rjOKZ +߈D/C\+J2Iy+@pgO7CL@ 1sAK i/rP 7c>ţg֓|Al0^8|<ޕ/mvGψn3>ӧ."d4~V|8! N@*j/Raap<A,K#lpHF\^Z /o@4*{˗5W]7B#/Ol:@2c5)9UZ!P`,x +._q~^D(t!_%iS4SIe̬3f<]h{,, x޽%<*+1m>wƵ*P)7CU?ZH\%_Ίϥ\]dua"u'v-Z<4Ã7F(քz!^XhOG3L UkS!^Z2f^g:m0(/NՎHҶmVִiY* Y8%Lk|S$>&ZN͟\o3B-$LI1bD+/&b"7{K~M COQYNIV! dBEhQ8tu?/7I~ ͘wU_\%QFx4Wy|]_j&Å9,/pAqPA#ԡ`L%RVű%u0B L8DTS0Vvu͵k׎aF׻+WٳgO>+B N?H) O{:':Kh[D+(D^ %Jbz(3_5B*X2iB|r>3T~@ tdOf> jglW_]Nj Q& {9w׺ppɾ$L\gTرXՂԹBb܁l<" Ip.#迼O cޯ](wb.(P&!]ui"%@m j}e> 4tądGt>}ܢEH܌L<w`Сn޼y+bۄiюt+5JO?vĘ'w47xFh7rO ߋ +xI"re\k(8άȑ#[hkވ?*GNvC׹|(fݻw߀}jIOG?IF2=gסCMVww뮻ͣF=EioiDeXPHO|i--4A9Ëx/S0C EK~wte YWo?mJ [nw&uDE}b%E}G[I^xMnsnnrO[9jX5lL8h5m\Zc#kۇBq;܇ ߸  &Xm= .| C=?o/e B;<׃gIGc\.^TL*/1` lh^=O'٢m!;k5oÝ5n4uwF Z79=ݚ=dkjij|^]ulꮵzO2E rCf˟?溭iӦbl@a^a7_PxuKOKM?mpu֒\#qwԻ/ӟYƹH4N'W"^E4otQQw1U1>qx5;^c2ˍjxHCQ m)RfG51H5B ҋFΠז5<҆cb nȻc9W/(qb*;`_iǠ7*`{x?gmżQ:L+$KN(⇯pgݽ0ޗAyO뮼Rw長lq +oe_-Z,m,Bۛ~'Ԍ e#0BTB1po8#7&}Uճ>YxA)PZ.U`|7BXuS!Gp"6)BTDDE++PW^x;wy]MOrO:% xQ<{5U`:BӰ&$S'_8. +wGV0~ n+U?#XK wmpT} 9>sZ@S|NʑPku(gN6!ĉRnAӖ$?g0zk² FӢ>ohC@XV$Oǽƌs/-| <sͥ{m&p򿀉Iyy\[ y}D`)\$+[gUfP?׹wƇxl8i[㿃?;h)7!C7Wji4ݠ3)lH&pאLR-4+0Huu1 _™xJ-,˾ ʓ529: <qM 4f@]ؼyqVԵ<'4"P>R\w%LӚ$ԔYܻiᖿ{N;U_Z{ew_ gUFB!EPT-A6mXۺ`4 z7vo&dj'_OWd=\pV˶Sl޺ЍUM"n\..t_'+Ԩ5И&@ ܄ 6a/!7R#psxQ9-0%iu'SJ㔯`}U}To8}012 N[tDvm^Sp>8av|0]2xZ8S|u0ni(B=K0#%l` ǛL?‰رcϑН͏$UxJX}}zk!H f[wQUpߺax؁nFx潮O2kC-AdcjX$:1P>(u`zQx9sڵzr~|5q9~Ėa >/wymupAwod*"ŚEDߚЪn˫k?h5eMZ's:dЍ}zUҌ- BX gVUmX'Ր,m۶;jݺ%yȑ-7o>@߄;Wi C %$P6*eE僒UR&Yf^?ĥxm1Ņʶ"Ne9 +*P@ֺhOorXQ P/9y59tuADx`i .m4+&;ž l\}:>ɸ 0rBV݇fvk_͝.̙.}m;nb6OdDqYkːۖ@fy(~^Mݸq6mT76!OD$wuz7?ñ@ys=U7~ihPH'5}Æ kz!<5Y>[ '=LڛV8:"-؞Ry0 1jƌWX)M_Zv֏#ٷH0~ 1(hhXy9+vZ ׿1^W]D )jkvsT&ҥK q+tAii;6/2(3*ddj+ ID~jaA\{8 r}?L6-_A8~K9bp>=E!*Xxͪ}duT^^~*AV+d޵ IDATC} .+-i/ס|'?~Uj]Ȣgg0[iѢE.^a.νj"xhSW^eEp! 1fyRa4'{ 0- O8_q%$?D4_D=D}? yЙv[߇煠=kјX? F W5}P!z$|wx7Sֳ vy.2e[n\De_'I:Pp·&!OJGTT3$HEEk b+֭k׮Ì6![r={={hW{'-N49@\/azЂ6mX2=d:e|Vc,.G;bqJ ;81p~nY"\S]sh}?e$GV v͆iYTMͅ:o[mSpPgQv:v'MYC!bM5|apP󻯾2;U`uxhk͟?Op$ɾ$jױ90+J'9y ̳q<qNgAK'ýqVپz P0s1O-?dzH*_.;H;=x &ɮmic3?DNO i~$F㰷4P͛箸 +Aюt+5JOAyxhFx>쳟?ƽr^y #˱`<5G>a_aEBJ>PvqΣY,>ȝr)Eo. MʶKSԑJ*m1 ,>$tP!$\j-4gzw7\9GQJ8jǽԌ31 m`/pOw۷/& Nt0aB~ G[qN-CL`I##Ղƴ!~|upQC?K5?M\Νws1e]tq{ ~N>$5IJ~GZʽ[_y(:4|O'[#0a#;h!EM=4@DqZ&6 uЁ^@--Ɂg(:l=0h[ z10GAH4hg͚ Σj /WaE'0j6pzw[~Ot$_#)6sk֬q ,<)v½ юcHήlkZ<6eH@ ""|ѵ;|1x⸂;Ў9rq\dbb4<x1M&n/vhZ÷*T Ċq"Xq">!Ě ̈́;-O_C<訣j+pZGPt/| ͏8∮(s3R 6^R^x>jIzx 8&|'Ҧ>P$"P{J&&t5!1DIp/zQs(<|Åytqr01xSB!T)9#-9G$v4GD?e%*8֜Et擃7&]ƳĶm۶v-\p.dquzzpbP>cQyҬ~Im}>_yd[i0fO8( F$"xCE?Tϙ6)L0I|G N<h8PXd1 D7ڵ7Kq"cǎG4ir&o O)ϛ# 3L~6ixi|$h# Qǭp:Pm۶Kӗ,Ya+2O9Bn`|9D+ccfIZa_:E_&˖c|V[PLYW6%<'pd|a] <=㈁?R7s|f{s%-vSNt]uwlvuiO/&^nM^Sy4CYjHË!Ik=p}o}#xD"!7~u{=BC KnGkY^œ$!2zPl$9I)DD.^gI :4,c=v({oڴӧ?S+}!Rwcؗ> .AėcMiڌ~'Ռcr*ۯuԲ$ ѰLjm^P!EMLԱקü[p7WJyןW zq n([׹wak]6SxMNTFehs׺+-jd^t+hO:=|͇'U &=c}9 MӦMBVݰzxFu~d"|7sQ]j۷_iV\DYɕ9sʴe|ZsGN:? ?P~gy?Yg$pd'hxFZYĞj:jZ~mյ,eȦBvGx-7gщJD> _:jAAd!~νCU Sǟn:T_72Ь͸[%652dn鎭Z%u[5!ty!2ҖAB͇5?{W'Eq~ eFՄ5DxAT x%&AĘ!F44*b bT{󍵽s|ڪ񺦺n( ~➁գ-hᅬvUW56 y;R]'N*yjZE HJGKF])1w A ޗkx#V)Ŵ43Ax>xw'}3RAԔy'+iebqmqje<џ< D)7*$~\:eU\'GX]EW`xOF3W ]ljvf*l[kVaN9M͚(~/W,lGw]Ӧ 6|=AZq4V,7_".{u2[63q#N\bv>|l1BZأ\X^yAr\l`0%rW.ו8e,]1{ a/T^l"] ڵǗoO53( A!2p̡˞8>5%ds2o1?ɗn{o_UcsruQӨQf,`ӦM|\-]u@KK]%.u#VZJ^!׈JQ*ePjAJ/]d)aR.#4r2Oq}ii7s`m]ˋF#闞454UbJJJc?mV[btA5ӰNxII"yEbHszZIL >OuxsSsǓ8bW;+&'pMܼvHNZ3t^3+#S].퉇~K{1k ,0'1(q< {"Ig%xmQ! $JI 13>~Вg}2x=4V^nu=5k, *-)A\g_0p['΄\ W5݌h59Fy0O(N.9DH(, # Ol_Y$s~t,nfMnvf؜9qhztXQ=LQGzw+KHӪhnL-ie܋ }pv~h˘ &wr"wc7,\ѵ츞q3k$ӭBf#C̀]LZ+},X!Rg͍;5bn!0Ƿ$nZیں}fYef݆2^K5+.9Y[1.sck{w֘ cj'{e kp}TNꪒi':ڶr ?}08,X}"+?+)'( # ch -c8׼/ƾ_טad vѕ2ԫW- ľm3$5#:~l1\,ɱIDdydY\ɋ5ߍݰgimV<sE {v)#nn 1f$Z\rIpY"PB(:ɖ)dZ\4(QٳZzM8 uW_}eׯM9,83P&~D֥MŏX]&|Y/D*=mDN0eE%O{/hnExm.?s]=b^/.[,GaZ!-f.\ޮ=hZr<.7=.}ԤpП$sc!Լ/$ӆL+1Pׯ_("qmV]Hiےp&Ԏ_L[\GS88q}r̙#MZ#oJ<_/΂LcYČnc)hLmQ5.#댺XЏ(Oee3w=HQ&!Zc{_>lneԊjǜnN?%&w2"[2L`3oJy3쵶a=<^{hF.E(]y蜛eL0\uœtMVM 4&k04G.A|WI%_ҝEFɓl5.|})}9mKӸ&d:zvS~CӸA&0cufofz^$Oc2W^==T/NI˹UrU 8_M O4Z ԟ&7@K.ٯaÆ_a?X8mC>^<}~>N\f͚~ IDAT/2hrLȞǽnL)e#)FS+ibP %ԕ E ` @DžqR*E!,"Zt_᫧Oo0V'qvǓ"M XB'S.Fr>E!jں/~a!0ъMs*U[YLbЛ'<5"pFC(F_9ēxps4*}2lzJ@zba9 CXL %C(H!GcX/"UQ!cI;fx\nqCsɵ%ٰM1kʕ5" RY F=FLR<k]BzX_AkD  dnP_2+1-[&oxD}^ۃ˚`Ls0^0}xHS_U ϰpscc NȥA/w}gׂۥNf%.ts`K__B8R< r)fvŋ͒%K!J|1<ԩ.-_.Yq1ɕ<`@|o֭brݞHH/1MMO)8WK?A3!>X+r4 7 PgAL<Ń&Zk/>:jr &po%%^uDto_G8Np;N crz?.ڻw'NU墾<+b/iήŭP ~B3Arr߶S0wpxAT 0x"9BtEQP5u)~Xʪ%?mgҤIϚ5C!F?g:I}x-{Ut1-{ѣ=qH#?>ļd 'w^=OZ,gVdJga~G&ڵ\~f*.Ln7蕮.uyhsRS?3P`JEQFAw1RvߧV*BVx)둋רQX]·x0H5-2C'5N\-{j/W|49ډ'3p&|W3402>K= iںfU.W65kNAQc\ ǎ<R|dP>#RIq\Fd ~%됋cq{S'B ;v## c8Og˖-պvj."=|4GqͣX<(,J.p$zA |PXDńg|Z.NqʏEO=M(~#-XM|U>n8jJn8U:D#0U,M a!P6&. X5v /B XӺuӟVkӦ'q+7 :RN _l2kACXRǢ_ѷm@2j4hƼKx,왮"lm"Y JFP`GlzI!eM uȴ=T*C"3&9"ٲI K-$. "N?›C5ڵ3پ=oQ2%< ki/GLFgmLBvAQ ; _7n~3;*R +AVF 0N'8zYnݺG~w9? Kr6 yC'P0ry-DZȘ$N0v!a?6\Y)A óbڷo״iS<|=4!F+:r*Xև:ud[ujiѻ+.9X>8 d'a}T_@L&^ΤJZ[&KE >=_Gr|7LOycjժuH[5c𤒼XTRK< |&D@}-d8 iZLsX~QqV !ZaÆ jH GSKh:KH6_0 J>D `s}-d* (_ SX_k!"TB}!fō3@4yxJ  vS{P^|@t{ aMrK|'Ԣ I]/!$e'a"ͼ$ 7Ox$hBgZ8ڨK|!ptp+z#B0SOBX]IǼdb7fĈs帧Q+?ý(o*Q v _L>Hxخ_+= $+@L jNBB W u5 ؋zq%D[6n,zO Ml AKf5OܗJ#J}O7klgup-;36:H<[''uJinB옼\"{løz!VόOE "֋>נab+qLـCQW%$dF uvڂRe+o05!kȝ:j!nW mҤ͛E%в,K%M}Kbm&Թ!r[aƌ57RGyu~LkGDbzq^X!i`)ȱ.석;wv/zEG-@◀x!-^JCە9Kt|!D.W&!+$W$[ 1iX?tbu5ӍX8*8tCCm] IX!6I2~ VäsK a0`+F7>Z" oϠR;9SE۷D>,ǗbUzX Sx!YL󁳌aeA Ij}I $bpDI"&-ꨄq$~{.0~M!YvJ8fYnC-'+֢7qKBEpFor*ȟ1|H|DZ>ߕ7untAc؀>vNi1MnD'OOE)o']&9< yZ64IZVu+x٫ӲB-ҵ-.7xA:>&0|rAv#O k?<.(VZJ^!׈Zu ނ9Շqb@_<נY@ UD[b? }=7G[_29A5VU0αB7xYFΉj|B o u|D1 M,Ɇ&q O.j ?@e]vHBň/DXȴRwBmr-a+n,). ZԞV9*fT1 M ^WBG OpUxXQ~V'Kd͸JzХs`ą@D3'D. q%yK-V4iL . ?Nh"|pG2!tŒLn\ok}IvYcXxt&SX2)AE@CYglh8r?x?  ,+n%CaJC<ܜ&^&90^ @^jx1Ԅ\a㓆%%QGL2mqYPk.؜l۶8sf#؋=udmr,:!qb0v ˒0!%+G`[C4Up6R~YPCk1}ll}OST+ͭ\n'd≮@P[:FCCk| 3V481 R 'LV}4Vڵ[1-[^2 v_KGtk IťF_q~Ld8x?_ZVV(@vmTEKURCTÜ4ě{B'0iME!I3ÈI0rYf ^HEp¾B񦡾l1\MnqqP1lOf ^6O%EtB] +:+J}i 2= ]n6O jE`f|a_|9{*dTdԸ@.q.TyBxHPAW blx$f/Ӷiׁm۶fa{]D4W,KЈږql'$OEZwWW(؅ ieDx @<~YPq } K ScW'L7"vP PDMOb,~6D=ZD?]O NPUzZ3pE7W/tIi$\W%>]I#O VX؏Y>$@2jsxOP_c2Zfdp2%vפCǎ* ?E 0.,xq5\;hzu$0 E_ElbEŕM!bۖ[Xn3-J !p֭[̢/_ *)X r-غ] %uii#Ӄm e /DN gL+z j{@hE p \%~;` gUyAH+ӹaԁ$z/&pBIZh"E Zjzj"^uU+$ӻaCJ.+pYP^ 2&{.SJcc@ 0Z96ap!s6#KtmSX vcbx iv7q43{%K6!W ܭJ^L>}݂v> {7><֪U]x+ޗ_&>0NԄ]TG;!AJ}TXmY5X6cs_q.swtUǸ~P>b/` LOT‡hHEkƻqhum[/M 9qL%ό̑ *^v똍+bH~꧸ʩ{ԦA<9F[:FGM"My<$NT Vr}2hIQ+WdڛJ1*U(bW{/L:.4iPB!ijl7{kQE"CK|"By_MH6l3`2(,4"ZzYNwq3ΘAB+tCC utK&^C@ u 1QR OAm5 /(^h|(S?2Ilu}ž l<@ C"$#wÆ D,#Ӟ Q pL'STg ~ٞ_xT&i4d2d9h E0d%ThEB+8Mb/v>NJ^`[p_I1 ߆O hPacHeo9DHR?w':ju+>Ȱ X>$_UOqŃ9U5jHdؖxAw>e(@k1D<<7@9 CPB<jV :UB#!!ԻwVB2w*Ɵ`gtW **ϗTn ѣA^UP+SF?G?m %D;O>h }y"A RB#̊&H۱UlʒKecT^̵0Ɏ%τ8RM#tȚgV`* +}D { 抙Dlw%zxHQ?|%k5EvZe˖wC{/u=z-M!l/ 5Y+΂t: gHLBuy>-0jUp" 8f-Zxpթ~,ý,t?QOVo>>YeL?d: ^{mkse & ӗ4 ~\"Øw qMQ*i -.0>u޳gRPgA_JztV1*N0w}g': ӻ$["qX eCJctGCT묐T-bདྷ@ƌq(Tb":&2 =ԙ7KKKXIXH9X?Ԃfai V99HwG7rH#2'K? PƻU %YЇPgtl۶ȳ&ϰ!?2/`Tt֭[(VYC#mLL}|cd:y]fc+,Ю=j6 %>08=H%C˭QNo߾I&m a+ 7?\*O"-?ҧkTqU1V^?E"zRڃ]ղ5"5PB2Pf>>Ȣ a/ ΅zꩵa6aNر(ʔ_]&jm@A@|Bڴ'B>G)leIGPQV=ծE#034yt>xyx\sƮX4/R-~ |J{rPԍS(>=jp%>V `f1+PcQBE%{x :l04 l)_.{AxoCpӧ['xsZ 485?E [`@j tӬ|FW^MAx6cYs"P7#/O'V@ꪫ+L<ض>2f-Ї]QIJ}3Ya_+ 5gCV&_ y02`?WǐknZ:=޽{k*KݱcǏ:͓$]J/Z8jѦ=jᯆu2sobL@/\ ,H0X] $ZijLccKǏ=zȐ/(>~#J }^ 'bVp žq\W}ԥ~G0UCLFa+3r98bL߄M|۱z|d9kf І|#{`_s: ٫yxJ GAF&IPOqu' 5"2}+&G řxaVAF<(?Ei֊@FS\ߗтr$s<(wOua-&t JJY5 IDAT, 0~<Lǎ*%jDǎ~X>VQQrOrjЧBT u6hÓᣎPf<zp%J[_btBRfy~1>EEE|A ^hi}ӭ"njVB^5%X ⭄:)WBX5\L_AVSnO#%aK{{0&?|QTBk׮5@ǣ2R ~;JH3OC2x=~rd. OccHRإF~&(@C{Yڻt-[C2͗u8hذ!t ؏u L8tgV1 u:I:0^0A_cC W ? LŹԩswXk< q߃6h/ {h~puG@gOe+QJ}3ꭘ]n6ÑN'|~}m6ѲCbȱ[ M#-@נ=~u6> PW:ԚJ,P_*N eJwPWx"P1a!Z!x@VB 5Jc;9hd 3'0~`Y+ t1~~:kY0HMX~nӦMoČyclzR'TvY<ϕa?kԨчs퇜zSvm~eϪU>#O#;`nDLΩЫ+>H `1\n06 7Iɓ' Z`B0Fқy"jL;*tyܺģ!sIȊOL>}WUҴYG 9еjU[>|3Bk5Ƥv4ܹE q9$ӈ֮]{sLzeee{1μ@?~nvW:,P u@HPOsck`6a7nܸ>(@@$}YՂX_V1%/`ϰpҬ Q_PUB,E|9> tӬ|@{0Aٍeh QQXmB+  m{`UkO9.;>x%ԓV"<{DZ{1"g` WxXඏ@a{Cl"͛76x0*΂&t: Pl>Y(@ H/dZBm.m{!- w]_ODլG0̪`NS-*'X_>kYD-ᇕ̢) R9Z2RH2xʕ+"&DƕPk%>`V޻wP:) w(5@ @}icǎ]兾izP W|G0 |iA"m貓9i낤ΕO&C +Ɩ/jdq~!'\- g^ WB&.Y~-u*V55uQBP*΋71Q=:W~V8Jm5rbPEenCPL yYƋ82:x}Ư0zmF `IޜUnt_MA\(xz^ Yo U޽{== S[yT-N{B/%[%>DVh򡁜?UJnv/&+Aed~H郠#l:F'{"ar4|0~<l۶m|-@Duˇ:WB/ ;?/$b'T?7] EIM~#& SцRjB~1: {q8DBD̊(hΙtGV4'B+i/xȄ4C㈣OB*bB2y"&z 3-#<j9)c\rɾᑮ$*B| [m9ð FF@jժu}kh"/su/Yd[R>&Ť={Hյ.p~Pӽm  eիI:uCQ`b݉~qBE\xsB{z~Ș=D(9 &Ժ_ xjn1*X)G ؟@#bDՠ@`ܸq;1D}}XUa tLJE1# ¸n j!A!MC}FPfULX9hSQgmB6닗{T^}d8}MYy_\) "ۭvR=q;9u4jz+kXH7.x+J4 r7/,&@L?"&`Ky2XfRhݐB t: +P$~/*ث@}EBP:F^^zC7{LDaÆÑt=aU?r&qpuG25ttt OI  ϊ'D0om Fk``ga"\7x]_`U[>0P=j J}lJ}3Y|+?0qȬ`~y`t;张 U5_wB jB=5dd̽85~EVBPf&Q8j>}G]e,?!Z5" x7p7vƍuڵF-J۰ay iZ|\| ~T 0-CPE2Xջ%5jԨO廹Ҳec0a%s1 *W<-O#3_W!j e; Όmm34my|E@P c1_`euG*1ܞVP'1ջJSE, r ^HE@-3H~1Ym3wa<>!\T`A=q;=: z*j܌ jt2{2ykRE@[+ yjժ, 0q-6q:;+XVBjM'O+Ժ:=|RBo8"-X1?_TT@ ܯ_b^uZjƈQ}0Aލ<^-4/~eF'fBbݛ6m ͜J4nR<j{flq뷰E_Hg۴5(#"|n* G;W/ήWr l_:[ݰͥOz <8e˖F}OTڣYԶ={2?>mBjFyNؗx\9>7T6@j_qNe?A.8$৥n]7\G"^%N SBAp#4=0 ynF |gp0D+(yB-|5~X}~{Ǜ4엞AJ6Wg-WӧO_KNmUUno`0ٸkd%G'_ʘ~ R8y@_$Y>x2`|$!]8>BZR6@{ݛjaǺň2F؍02_MK?,h?s>pI aď%A@Ϭ;k ؘ@pV ²1y׉<Z294HajQ[FNI5r!_m ߢEJ oBo9}};'|2Mkhy){j~ 6p2PKn+.;A;CƗ4h0V/P/WFOu $\^%V闐^Js Y~ FR#6=ViXf"ba?HbJ7N|u\_]4SO9<x| \^Z"PDǘkbZ! =n1,r%8weˆȕ駑狜|TB;grPFD+LrljdKsrRB0.?zT}Կ*R!Par<5"7XR}n?'W_34 1OzG`׮]`<L pqП񡤞hExjJ5'F 7Hب;ӊ򋷮xNq[ .HDMV{P x<j! c%oObc 1 םdZ޽{&5RWW'bÆ ?C;;iX]RO$ɻ;zG8z; WM3ŻP"OdD+&xK/-BQ\HOjY<5"|#N+\V,qX3l)9E̋#]%A#EopY͇,p~Z~z$212x*`[ʄ2eNh 1$VnK2Qv lA]apuG]{Emo"H[KcߍQo/=q;OsLMGbp$]'1.ֽLarjÈqnsn5ɱ_!vƁ}ֿ;w>R'0dqC'}xL qnpX%uԙ@0*04VقTeWX{%),)ISe{\q'הYdy:L%\P+00@Ν;?~:jHżCr]~h{4f<7xNLzpy~ǎO0*BD#3V&=[[,_#~JWvdL*S!ԕ @#!^v`"B綎13b,.d!J܏T/"qKv#eO u<}V?_0l[.ym/̕U|Һ~7v^vwcշ->]{ʕo;S.#p; m۶=37̉DL8GZt$t$u tqgPy2$)xIQ!ޠ=UhL:/"2q-0ēi RUӰoSb~"MI2%:#.NTx[@>1`c=P?)Srs%Ֆ|*X+CcǬ _^&MS915ĖH`LV u]5!.bK{^\p\ O"p>ʹTcG:j#lca@ ܚ 1#6q93{l,?Yk˖-"2֫,yM5/!q3:s- C45kAv?= kW|,[Vu7)ҸO ].7cBPƛbp# y]T1ox O IDATp+/QL+\:%Ѣk[2vOM bU) ONX!Bmm9A2<1pǯ?G<&kr鬡ѧy}±)BW}!G9+XWTnP{h܆GLlPojgAI؜\+OLit|gܾ(2ܤNˈ8:ahd/KK%3> tOwծj p˲l# Ѽ;0|A <Ͱ$t_Bm2M]Gf2|v۷o=lY e\-0+@)8jr1i78ΰ%и5^& ;L\ #W_.]YV#q V)^?֎ AýXXδ a_N W}Ikڼn:ŋW#qS2 TBb@.]ͭJpN#oW;d7~Vc)eEfck\F}<=I!J);Zhkҧ\lvð%<^^M6- N2uu.-jժf:"=' f|=ʊLFsv=C.<yБ~C&m}0sڵ 5aC4X4w?_+6`l_3:^<'o*KOXĕ96YuP'C(Xn|K퉟~r'~vqb -׿?? a }7:իWwwׁLb1.l,mm=O]>VWA\}KJu":x"mӦMS2-ܽ{LN(%]V)uL.G +cg#+{SPC?]%m\bmT=ج l($]CʯB',[/\ŮgiqTө(B>7oGR;.Whb+y:k=`hH:21~g=L7o<@ ߜr)$}A'}5>)U:1z9"1~B>kwFOoJ!FQcPʕ[ʰ—N\Մ.sp#~B~^׃=6B|6kDJ2qaӠf!ː~&}.X Kմ+Gu #n>?HarXF>)nj_*>c,>ӧlSʆ/&7))f͚~bkx#z&#_s̊&yɝFȳ2~q<\> Dznc3H]{x^ģ(1 N=T!표P6 ׌1Vty ڵE|5q(իWz+Ɓ%Ӂ0_'5۶mC &yVCohoO QخL4=@dyY?iq5s&|9b+<9RBv@CWɴ?@f7ayሲ䬹(L.;=64i@Vb9r> Va4znRA&_үJ?cm ٹn S̿Xj,aN=MllY}DL|HIT qeV jVqn7o`ˇv3iDޞ_<\:/JƯyg}8py衇8 XN)zM]Vɴs :J5h9|V: ky<ѯ IoO4WW+ Pcnk(P d\5> qƗ5jYt>![Bgōcs㢓 N2Ή]&wNbV<\=uy(!'rKnO.n9퀮*"` [bLԍGju d[?3tp3|[ZfzV[ ֦M2M=yWt,:מ+)X+`"{B:TfŬLNל=Ģ޴qK ӕ .of𸌝Nإ*e;`}-V]/aÆӪ8Yц ~ٿcO4R g7@aJi)XrL$^r~\"}g5%ÍpP+'x05AƝ8 b8u:췬(Dv)f*9mbGڱټ5q6mYy0mNWYw[5n#Gn~jj%BӗxʋCcuR IQ޳K9&q9ˠO[<\&y-uNK^ar 5i# Xҕ/Vf"Ͳ= %at)tҤT@F" ~4_Cki T}=z9W<>HW@;MІI\6Lbzng4+}d1fC6m6ܸ¼5̼*['tiג;'⛽[WY/O3s_Ьgڵ!aN;IMrGMƵXw~k=;nFF̲')3d3 &Oױt,atu͈:2i;PҴ0"+UId&X۫%BF觛p^3nf f΄aټ9ٳL,g,4UsKMDOXIkc.zKn$4pyFsK '`.S2.ق-$rrH:ie{SKqDOMr;s'{;`:0|޽B7)u BMJ]~mz[S#n$Zko8wթ|5zSc['Fv{cKf1:l#kѭ.) å=rOЂܥ?}J!z/4CK8n8"53/ t;׸)-$m NwxjBV{*>.80yÆHw6ܳym}A ޺u{&M"VS}^ί> u,9yF dak@ԪtκJK,$/1.n44KA`Jlx);f zmvW`V@^)J"M]~ n*7铴}L`F 'q79 vh$3n5K>m.ذpz?c->I+6'E)Aj{YIXt<[yk&]0{W67EJiԂwŜ'a9Ǹs٠iwe=l )3_V^jY!ѽoQ(@N#6@~C%6{Ggi<j/` GV<fhJ㢓ލ I(Y\׶eZf-?붼uT>6QssscŎd}oѫ}:;q; 4 Y7z.sY10q˯T\ݼعfGQ!xNB lX^N]x!2PC'U΍(3O ?8\kC,a ˶ 4'2v]~m${uRxgVFO7;=h#]-}{MAeͥǗj(O$kWȽYFֵZv =?E~9;xLI ;jԨ q Evc{xzyKqGzcĈE'ؼy90$N+ Q~֭ },Y989#M]0^n͘afΛcfΜӾo4,ř!KiX^ݺ¼+]~8l"e)'Y!7iY ;34,{VT2_=c!\kY7j_2ꗋgٲ-EJxnrO]Jr<:>E\j9q3ix2YXC8̴ ?ǔ },x;);Q˿VS o_:ip>v3[yQ7u1R~}N@A*Up/'!Tn"%d?ݶxK,1I9e={_]Y u*KK#W?˵@`Ŋ[hqx1c*} G\.ƎS#PTTuq A d2( kcȘXiukSL&Q/nn/қJ"(SE1 0"4[lј%X؍ hĎ(`/D# tD{{yw{wwvvOyvnvgf8[j;_,0p#: ;zUta?1Q]t)%-;f4+5BpS'N4ddv@O&ItnsiӦ飑EJ "=l =` I}5rTbڥ1E`ʕR<jc1(. uj.Gκx<Ͼ6-[k;+yN(P'ֽӹ{8QV^N]7v݊y/sVq}׷ޟ_t*,O/l9맛Zq uFQo߾: Q%\bWmL+y@or̘1<߸i/$GSLc3ePOQ"C!Ýy-mLݼ`kZZZ3)$L)K^; v矯N;k&`7d D*J)]S(L2,[z>BeΨ ||fmVׁS_6l1VY&:H'o˜n: _`r4 Nft/Wx# >Pk}݀}":w衇zӧOg*ԣHtщ0)coH. $)ɻ>"8|!1н_޿B=՗>OmUS=T|YJR%%^̰p]H_*&wM5,Noko?pc?HT7|]uUoc[Fإ%go0`E^I[s[.零ty@be&t;\8boC1]*<毓Xwf̬5S;=S݊W-"N%C`N:m{ku9q4 #[ynG[x7gΜ /"IV3ǝzÑɪ ɐZ(M#ҤAҤ.) IDATL;*p!4*>Xoܸq3ڠȔ.´J/l富su < D[kFL ׌T+XZ \Lim]_S`IInJdDQϯq /O>i gUKkjW5EmfWcؗ`HCL#=n3.Jxd+<]ŏwb-~ަMgQ/s3G}ta."WReL禕_˟H#=LaTd3I6@^$Q5tav.p#Ĥ䔄cq""c$NӰ`[nq犬H"фY%*؀oޱcf $28}VZ 4Ǚ3g~sP壔$W"G}I#JwԩK$UQ&/"X,lҸ-[ajY)-:u'5kq_L_Vx쟁sئhԶ8>Ȱ(NRaEp=풅=B!;;G&x LG?'{_M4 N3qAÍ41qbs"[$_DH̸2M41. Յe^"&2 ?rpRF7lݺ<|zroj.1coޫ]v]u?lϿȃzz)vuLZHӭ4nI壼$&V{tۗ(𚂚mqS@f= 852^"e. dI%x@H@#D.-sgopK7;?wmI,?X `xn#nAgî]ܶmn#ӥKlX~g}340TM b,L>F7L)NEq3v%۝ڞf\}a[q 3;j~`~`iR~3=fR "J \1m@ (5$NjQ4SnYy9\vn5PqN:>QH`_Jx+$x^dZVĂ`UjlDo橧z/~;3ŖW=;@~UkL~DIie43N׹yiu$ RFڱڕtK\`@h&Ř{;,F;U+%ڃm R̿4ZHf (4vrK#iyq<Ge<w^/;7,`k$sc"`_n/SMk^RDZ2D=ܳ-b/؟zVۼ /T/kta>c=65@/%^4.M,M}LZ^|(SJ+|BEv-a=W^;mV3Lඪ zǮc`ς}V( tSL4 . ܌@-İsp YhB/3NjgwyBz;q" K=+V{7)&yl_Xp BMpYgqMk? ݔ"QQhguK@DBEGڕLCwkuJ _ G1`m=x'UN:>G׭[iӦÃuwL0LX%;"ҩH5k#"i,Վ闻%Ws=Ëm<o[ꫯf8<, | S?a{UAl5k~i6$-Gc =BMٰ-pQ*x쳏7=l{J=} XdNig-#LpIaLAPt0aii9n?RҊPH2Y8awHq]gxUXyD_ua6xL7ĚR ~EjFVi5ʇR#*r&UfjÝ x֑<'NΊSaJٕl_($vxhϊbi&D Bbkda꘻UjFjeZ֊u`[yKU-_ίY,MtS:d+:ikuR+f/DMLPزɪ?ROR~>+p棾 M #k@6?餓ƢƙɶF >]0x嗯ũ" x/>Ǿ@+2Jf\+̍g W~{!&nU+]J9]a6lשe+ӂ/ڒ+}`վnD4f;a> vY|p8Ҹg'Qb܉O^ f!bXNt0~#+? +ZMj8kBdtk⥞4QO9/+=Jn奶 3y@@$錟J#%-uK~Q]vUxC=zl_R8iՃ>x1^P ~waGw^#)0^L݇2FmOoB/ ơ"VƍΝ;{ͣ{m~m'q7jf7Bn-nL輯vN‰R%@p& & LOK#Iw,Z  5SwD\XךNbM5QSiq-'xRyCp6SsKb>!ܕ3u&ٷ;aZOIC>&0t}/]++8dl7綥t/TxSm-h+YnI(":lP{Le.iKbfy<% ˗]6+˶ 7p V~S TH {sg@nMؔʴUzIօ׺ o? sU_L;ϗ T KCI)iꎒV[)&xJ锒F C|51I8K_1Lu#8/%cg/ùMb|ɩi2N䧔U?}Kr3MtopVqEö1[&Ι4?QW-WUc4Pm5A 52Bn&j!g6;uJv 8s"`Pet& C׸׹;3gΜg:u><;!ª#C㟘?u&BM)Bj]R\K L$I5sU_n8!ԷfnoT辒U"Y~_q{P?jnݲ, ve:Ii1l+jgr2\>喼mz޻gI M]6Y̷>YkMWs Wh4 'uv1ɕl߉v Yuj ;: Žnfge ZD2UPw}={.$ Nᥗ^zSqy&44iKd[DڕL'Z{ ID蒺u WS8Կ(է' mϑP7o|/o+]PPO,ètq4=Dv^c?%ߥWx;8oLf7eȻǕ/{o;abgOZkWj ƜtemP+yQlA3FPi΄u"c,?I:Y^|)] o|ݻw? _qB|kG)5QtSRW.ndOU^_Ḯ*kM~#7 ݒ+< FnJ+]VrK -2G34 wJpWa"ȿiM<5=n_H\Vޝ^ȅL%)(8ԩS'P?@\mΚ FBC7(Yn4/tQ:]Έ3kgwm^Lln^Q簍;M)]iWRw".V+t{! 3B*IZ7t /M>0ID%Ҹ?Сxk[mo8p ,t&(,Uc ãlv0-Pri~`w2Gä/oEHoӼ[T TnPPJ:e{%JSk(1qjp Q6[he`Gq azJv.䍒LOC?:_/ۉ} ,9 BFAՙtA}rnDvɵ׵~DyO'#"bLoQo4fV vXQLq ;YfCp~+ɒP'ҋAtRV{rۜ|Jjce0:,c7^&%A޼w-xkަc6)9I])w4Clu}5e;iw;;& KrSd:$*Y sʼ4M٥Kf!W@+[aNtX:Gx3ato2d}}zIeﰟHVa{ҘL@eg=wG 6bҤIp]w4q ݴjg)E5#t͊S_8țbS=tׯ?AҭJ)RJ_oQ2J Xm JRJqw}vv 2=Mv2u@JJu4JKH/r͊+f`|HkP0BY ~+vIܒ)QZi!^ X>6@P_1^t+Fi+F{ewV[?n/*3f̘ǍwGeM(NBjmdtu-qN(6;=FVc 壏zm^.wLv)]!)*>@}sUr'BPxɆYPk~2]"KRG`X 0J%p-? c&HuޚMu@yq [7JS=7V `\/P~KIo~=~7ttfcU~8&2ͧzH/žRj7*.R䘒Vs"Uh凳a#++vۏ<=a_&'y7=>2MԧWݶ 7%d1N‚e S^FZp]eNrsp'`i6Z8?sdPit}o1侈NѠw,[aJmG{JLr'@)S4(aLCuKw꧔Nn0FR *~tGB:E}Zqݜd]IP7mDaspN{=Oػyo*uuK}O7 Ǘ (q"WB4~rb`q'eX:7᧤a\I8UPyJWtEZ~(p7򢤑o v p;dr:'Ksm0vb\s/Hi;v2a>ј#RYŗgubO_ZxgL4ć\JH1epN1D n@5VnviTc妤K7,?̧$̿O:R +a-?14+NRJOk$XL0 G:cCWތC"~Y{uvl^)B-z#jșKHw1LOͿH a嗩0eɭt2%(!v& 7j)z`*VS"R@DK+pQOՋJSwѳ7$=v=`VgU"e)CzݤsIn+{i[>Rbj''1&Ӊ 7~܎D& .\B]YKl-':qsԪoZB,L:['M^úUs^;eޣzgVH=kwW^˭y0;^zLfu_:S\ٖ›1Hjfp9Ob~Rӹ( 7>y 6H* y\,},KC`y*Y>fSL?3f@18 NδyȆާs{9mmӶת;moCleT:Nr</V*sx~+"$.WNCou UPyA[* RjW^nbYhu趋.:t֋-A#sVATdA+>1w>(VCE괏C*dBV[(dYRYI @*V^L̆0'Z~aqԨQpt==#膙;F`Riң@`8HՇREuZhp(W,=1yZX "0 G8LQ0|q7T9* "ITbX IDAT_Tr+_DV,YSy8MJdgY(Z}H~5Du ӦM[ 0~({3'O?b NDJ~sƠZVD[3<N_JZW6_2(H³ FD3"yq$v:u􁭈Ίa|,AQؽn7Ɖ8㌳"l=]bE?ƺ\~fbĉo% dv@O&ItnpuѩO`СC+>;Z@y >^FMWv'A>[~zpH֞H~IE{ɓ7< pͬh .]]r%Bp:u~+B]<.ym>n$:WƍכY@! !cU"lЧO:nIdD)vK`K̙(#n:oȐ!gqa&WaWJ隒FaWol `m@ ýV(0Y^{T(z8.L`WaC=B߿.v\DrK|qHZ/ ("_zz7}toԣHtщ0)ؖ5#>wdQ=LmC/ynPF\rHx~iDg=|IO? /ɉcؗ`$8Zd$в&6B \3sLa OPOgaCFdۛPU#%o!P&L_T<g0~7jo5uʿnM˕$^N[onvHGsYƹ\p y#Ta4 ?W'xۮF~—>F`ƏMyG)ID {I#J)gJ$II,OSΆ+hY!@[%fBDu`F5+~2 ^ƍAތ!` 0~8!-NC UBjK+ծ_dHmbK.}r]Py8wy | 'K2 8hm!^?{_}F$kEH#w9fz^K&奶(3.hnu}kL0B (gI(L!?ryl!P\L=xjlxBD\I%RMrpct]hҤI7/^S%|7^#UoIIF2W^kٲe{|g-v'|e J'H5#R>PWԓH5u%[~3Ij$ b XdyXqzAu!PC+X_}Ӑ),,3zx`6m mO@,ZW_}9e7H2'ռ%YW4hQGuxfa|]}.\P_c~bDpY_iꊖHi-.fkEvK |O3!"`:D0Vwm|he3 CA@IQ$W$$t];EC@&GaXVXzni^/Dtzf5>5N YO_p\H/.[][d;(ioMP-@R#520 rFIJ! "JU1%aǂHaxw3<"H.ɲKE9Tޔ/'2`{G#+U&(_vuEBg"Ԕ"ZjsR`f%HnjP eg&_b{W V[N"Qi*5V"_8Tt;E2MDL)eWiZnݢ_~dK /:Ԋr5/B-+B,@<8T阇T*V-vʇEn3 CMXA Cx"{NoZ%9JD@\%H.>[}^Vx뭷oYѺRIK]2<] oUӱcǭ>_W?uԛ-[ƽn5 'ʳ$u#4ZuԌP .vgC("}K:TOgV/Y"Q,'/9|F 'Aˈ$ H;61va{>Zj#x5{@x2D%$Ӳԍ5.J#B"!J 3g 0B]|)>ܰ&0)>3g\+!PL~|e8dPq,O͓2}$wH0?+Ԥ 83-:G|"o&LEHdH D/I,ne"Ғ.)_iH?/<2_3ž:r.9NHi~4QnVu/ ($!-ja@| ؾ_k Q _@WL5¯~u_2C =^L',I p& ɗV HؘiEԪK^<^C݆#?ӖW_'>4rX$ZnI(CkLm čE ̈́SVj kɓ' (!4#92X *шRC)K!^_ Ɗ} ~,>`z:D04~ɸq$$ ||<]7+ 6㫘'43Q~\1\%"ό[M(e\Z&K (吆-i)!V@}_DR(4OqO{? o@¤½UL>}HUhnر&p`W$O$ [Yn~r#a8dS7nY"%b0]@NyR0zsu9q! Ii#`+ԹcV2W`ja5&U?|!o T_Ȳ$xyXqD`ѣz3Fc|e yw# bEË~cS Q$~IH)'0i#isIFT"qfrC.(ҵLC(?N)O$9f$>⁇bi&DPfܲUw=:Xy ! (_LkUТएX>dg~2xt5Y saW '+|0$ . Wn"-8c]?+nmU(3S-?% 1E'p5|&0Sd?gƥڡF ]i\}a|uijQ4&3NRFY„ e{>1V:S$0m1< x<RĴ 65].R"ԌV0%xי3g΃Gdf#@܄_a覡L딎in&>"f pHj'bW DNؓJ(2 RߛK^E.No ?2V} 't^C!_@pG=I&".s.&ye۷2}[:ux*|e6I]2hxDS tx&OJ3Ij>ޑLj2Ռ2B]MJߌſҥfu1 N@b pw;w@8| JҕtL̉7ׯ= p4$}oF~Lҋ+v-FD@wd % R;ˉP1X~ yVW٪g<>E-@rbg=[_ No2͚5dt5 '_ϊ5{8m۶}: >{^o3">0gv3՚*\& -A85i0np'fnx}#)|yX}SJcvx"){> ۆw``?$$ [ Ҭ]vOLϱͣH﮲rUl- )e+Ihp5x$ֆqrHc+9UIVX5n4>R |@6ZĊ{/_IayƏh52qVx.Wлk~HJ5`O5 P*:I瀀})1J=)&̟a|簝w51 2E6vM" >cZػu'N`kr?uC2*T+! |)q4eJc"HgI"`+*d Wlڇ^AVGC a|e$ :3 (o{).v d(Åۺ.$Q7`f%ڷPIF|o{6 _Nf CL5jTz 2}&-Ym ]t)S '" qGa=j7o<Ϝ1iҤa2x B~`[>BV{v ,sYzlX C X!yqEɘo_U@p%l{}*9+կqCtأAWaD @6B씏{v Igol9u㊩x7G^6|ay%,q㖂-QIW<`)A20V vm@? ޯ# T <ڲ*'O-\@|@`GcA:w;v J?-eEdɒP(OCGydS$B<j ;dz0+~f E>`l: PA)At!`AD2n= ΍q~%h 3g{B;ܷo34 C 'GQ~U9]h=`w Pws ojk@f̘qfdH;;+["m4 C 'z.celޛ`Vk [PgS?zd5 @[>Я0F@0 C 5 A-L~(9 y?NDw _#^|e۱8hȑ#vC "ԨUl:d@-;C0-O *,>D A w1:-D|A,DzhgQ׶ urHc:5驧:˵VoCH^{hut@D}#<ܿ@v;'Sqñz NsP] _Zv6ƧC]@>K5YYFCCǻfL\bN@@yy: :C8#Hq<ܶx w؃OxU\?PP@NOg RD}!C?|Cn]@{Eu~̊n5Hznk[:ФI@֯@Xvg-J|<0pf7B.G4c= ԁV1 uȭ>=2> |3>|!cƌ邿_?.zZ VnC LYD#YQ-AvsR kL^PژYU*yC\DjP݈yjtr#f}|mde7@ B uۖ-8qa擘kܸi_JV/C ppnș@h`KFq-,K0҆@0"Hf:ՉV`ZV,0PLaj9#m;l6mFmΙk:csX~kݺud#J}ULU kj\d r59eVɦcB{-^h8l*n5jLb5zp~$d2ӧcÙ[ds12݇tUnxz=T|:9Tpz@[D/PaFk^^jz)W[!]\ _#}Sgr37 yC6[^~ ;d4L`{~,v.-WlޥADK᷅Zpr,yF}gՊ+֌;\Sҩ Oh Hxdҩդ@D`i:b[>BԲ3 C68Ix~߸q>vt@v2pj3Ѡ[>.Ϙ"sBVs@! w=>eb3xVw's?~/H ֭"Xo{Nv!9PԶBP egHA ҏ6tݺ[5+^-@76Q[ԩ㋕+W0P6bmq Bvo: <8ns!Ppe˖b5=97w585f+5&pv!`SN9ekԜ 2}i |}-]^>j 2DѨQ#n){D%O 2#6{(W_D|VC@?3B]$.v[C(</ xo^$/ҫp^T}/[0-=ȑ#狸g+Gs< l_]&6cA u0e%ǯMjtB_> w*HOѰaY!fo)ZqC'^䚍7{y+n+b y` ?ծAapv {W2Mqop`,RS% p4s#qhWjă lGM~^yd^oWX#kz^k@,BCI*ķe@P /&vցx2'C$_6| m3ip k0܅]/eVg Ljw{$4q}E?v>k-,rMkqMGZ?! `~ t)S|>|[yoXm4˰V"K,Y}m@xw|]5Dm'㱂}(Ò5 ^yl`YH XOÃK|DeE:pMg{EPZ@3#ŖN[IGs;#rMG'i$%.uA.-\p2j:MOL<~qAǣ)6$jn¾mQ_H Fς,f ɿXSPiL;RxuX3D}f@@ #P 5;k}A BF/Yz9p?W C R32 O<"`0xlދ6%•a4~I 9(WHgap>CBCA;qGASч&!6ڄ`cΚ!3AN$m)&+/_^sj"iNg$)v 'Hj,y&ʲ Y+YR=Bg 2ˠӵqty>C[ĩVE h[ "/i~2<'pj2(:PGQ+%P&x}#ʷ|FOn AV1(wիۃ~Vd>.=B*: Q*[X~?7:| #1.'VDye@MRD˒H%NHS\vݔoFi:#<Y]0kR#|vcו7Xv +75h`˥@c+tv^p6/Hynۛރg{JSa8&{9] {z,)e}Q:PeagaI^2K%=Ҳy He>PBVeqϲ՛%va+249 Vj/&l5'ʼ^oN>}_VZnAxAAV~'5=_d/`@O2+ݨtT>RRZ_e01 `1O Ά;ֆ@Y_mR aĉ_8o4:@ XvW\VInסykFΥQ;E (8F4)0Ӌ1.q};!uLmh0$RCVهYPX Bv Ʃ^/AGry%u{udc⾄݄lغ906P&HN95?u.R%>pX0qpy2삤5=/{4y-lH<4OW.5 &o'ح[a(N%uؚw'@H1,&8ed Rd>ln2Ϊ&\,(އGYTc+E5L"_x7V T˪!0cJet#P`(F--$Yw@ `_|L.[VunZƻ~׭k "quu(Hmol 7-(*Qne1wo}믿:\.vݼ~dVkBڤ>rv xɌ!x~5?ϬXΌ@@w|V~dO"6'3\Z$v/ݲ[n&dXQOn^\x1ߨ) HN{|w}/87ZMȳ?>?R# ;QawS΋Q?cs5B 96fͣVV (0v Dآ7Yf~J{2[3Y# L&7㔇+ &O!CÊ0_K.qvk| f)#%*Hes'tqPޱX^? OioPz̿cW+pT4~BxId)sFe\eEg E~HrVzlX|Mg2Nzp]`rۂiҥM۷Zhђ~!J&7nn!,O}(/Iw*f\F"xqX~" 3gND!e+?N:C'eKgXY 9]a%eX<_[;aީ8Gh^"p#- tI2-b+""˶t,e&iм};,LSW.:VXŞTU@Qx;*5u| ?FT C{$YT'uuPkjzx1g%A|>p3iBG\~Iߓ;N$V4H4 k~.ýݻoѣGN:yxhcP E\ ^͛?}'mQs`Gg7Ê<$hTƄq:`^Y w%qëqtF!F킒46pO~]w>ZW_}54D{iӦyM6 1rVe]#8N"7~e{qT:t("sx +o.o RB1B]H^ "}7V ~8y_hWu㬃@7o@'/kÉAHLի /x8f@^zV-8sңH5OK*-wb?b-6lXS0L&MLE<-sn  13#h?F3"{$'3@6Oo&'s bPAi`KQ09߃l;t,fLZ㖬 ڴiX) ,;WNN%wJJ+wELR=gF5OƍE?mj_ًdc^e+~]ɒm(H:K#@`ҤIquޠN1cH53p_-렏\| Nz脽sfR$E%Eݼ?V[mURڝj򰍁:ц>[Ii$&TZgUcDE.L9B[~UZXmj@S>881V]n MrFShdx&Ҝ.rkBH]w=ܿ iRuݴ$["ީyLrK]}=PHVJwܸqYDEm2t9~o8U#DdcA)4yG+7c\N*_V̖\I݉gB79dq}v<{<^ SM"Zt ?6xy.6vͣi}.{M3wuOn;W!QdXoV"Pd$nϊN1!HprV mXALhݺJ̣DJϙV7!(Β}8.N4@mfBD 1AeedEJ \<9l2!"ns͚a 'iV/R ߄ILߍ#k׮]{W1d=%X"$_w˕{گys>4.ߡ~=]/QD_ytkϫd1~:dj6]A.Ȓ_+QSu ߵz*ue6K*b@*qV'D֝EQH#J1 !c6_2VF j#ؿ{&: @ckRؘ3j:\.[BOʴMAH(\)p\<4qX]2-2%)b1L.D{ǹgO{  kf+{NքU\R7pr&›2pGtʗOaQ+??N$3O鶍!Ҩ7[s:cL=YLb>fTsi*$8 #Ɍ!P@>}9T[Dir/79h*"~{3Ybd})E%&KwLzmy7MEۍjqN_\?j܋^A=J %6U:9jSjlPK U_d5Ĭ圀CB1\{'L, YBޫ2%Ӻx!ɣFj"K~I%rEHWeMWҮ߰{A&ǛoϴYۢtKiI\zV`]wSY4KA Ãf&c&Ai@GLbۓldU~8 ך\ aE{Nr&Wvߌ 7rKu>+@x־̣v&_+~.ԽkI.b%g fuYޢy%辦^.&i֛ޢe' ۼMgom*;3y^ˮ;bשtʹ7׼ Mٗ$QeI`?%ɭ@ AF+_FUқb1b> y$d\0xc]r d%tA|c HV:f_1e*FE4\MRԊ_iBwcUBY^[>BWc) %ˆ8^%-tqs,hV{kT FzL;V=zx;kZwWmRs5w ۣK[yO[L»G:{ಣ:"=zx(&Y,9g[ _Օ&\Y{~;ZFڲtBy`^{m[{9}V^Zh qI` LOG%YtW.m-e1PFlTfJ  jp,40LtRRR=V军G~;N) IDAT2}4^̺CظGtJIoQmJ?Nx=fŻwzMwTXAcҼs׿/wjyq郼;l\ʒ.}&WFڱ51Th6Ln;bO?DΛ"u;$[yޕ=*/M2\7i9:wha_g/KCHA5V5"SVI;60^6 w} ,D 裏[RPGV }ݷ5e'\]<&?ݮ?]=ҝ0ԻQAǹ,lHfb@F sKni 6TuQ{l\B,wB6p|o*XeRin [,20[e1t~eMtSR;yN/YgiygسjzvxJC|<t7[GODUST]Gu9mkRϩ}r'7ڨ”F%SYfqL Ou]x7.OyQijU-wO%y Wpis,SǶ|ƥ&Fk^ ,ܔny?_G=׭Gw8!YoRemٲee˖߾+RܨQ2 {#%}ݷgEAݕ,9*:v2/iSY:n{;M:tzv㋇訊 CV,a;@)e6 $q_7[RmUm!,mae 5ݸnl a'@ .̘<"#쐋a?}ao gBG"'k@1#a&6BӲ(`λi .~%{}.Ú)0K,_bÉ4xn5S!^ qn;fO\ٟzP4]-}&KRKJү(]#?e3\,+LCa `ۘ WH0_²-iHkLvZH6Y&bi#qVÁFp5K%a z!of V zX_ ;,`W4M2,Jhd=epb}4͗7xO3r̻8z7`v<(%u5TzwۀS琧Pguˢ2LnJ\vcNvi'omeNoѢE/͛7{,t,&RMIRlYiD+*PlbkfWǡ@A\nl5idÅ^X3Ψ}v2SlÛ>}wEyoV{`_J4%KT4.jHߎ{GyN+M8zx+wBGӯtn':UFm{&Av"؂.Z[F( 1׻K~#vwX=huc0ہHje_~C\fbhPԠ|`%lL|P4Pp,'[. aGZMДԫgMYjm㪛&"+xBb0w(E="ApT+&uJNVV+*}/qW}GyknëZkLv{衇Hƍ0 .bw fLS-iLr ujFa&PwĒ.[mG2zm۶gˠ8*лꪫ-\>&%"3,asW}ڕ*Lf̰NggD3c+o׃j5h ~VEȞTmr}EjV)c1d꘧BK??u*_ ᥗ^Ef&d)駟ӗHž +}Rk*m4C&pRTEAA .hdL $3Ją S{QGbbSE#D5qAQ@χ ( 0 oszz9w_So߾%Y#i}IvuN kEA B *sȔ k1rWF('?^I-ķ ASC\Ü.BB{ZV~**W?#]/ ]]-z\ߐs op](*}/Q#OQem+г\XԿ%;dZFiG`N^NY_']ޔ) s ?9IT2#QZ#QP/P̯N йxJ`~{soT",X 4N,&c3|Kd|a.âď`*0S8vn6Vț=zUj@n )ⶈk&aopq=pM|.h4_X<%| ~)yWר83_Wt?]ޜgЯcysQJsY skY3 C=N{.W>KQ#@yR(~XlY# ,{/!GlW.RPyӀsBą[A 3 ir,Ȅ{J]Kp"7hHCTDEJ@0뭎;!Juֱۛ p9 5Eǵ5 dׯ_K[vYlb9+6R ji7d ޺C\iuEaTZpb1ӯ +.vp{i xڨfJSss//rW[`S:tq}AoOtPT-ym5($G,+w}tϝv[bowXs稬QapNAق+F5W]vjnv_Z,c!R&m$icJ1>qL>5\Snq}/KQz𧼁ȩoqڈȗTrʜ=zW%: 1ۡR~y01J.pixgt5K/ݷt;Oó]ڴЍؿu̳G}]ҧUVuZ;V)KzQ… ѽ ?O9kKtE76_TM9}nj׿׿HףsGw9?t/3Mݞ ۩O5v~OCB˜Թ|2L'E9~5vm^H.\\4OӑV\_\j7<\8u4MT/~&vvC3?~ݰF\9]>}I&re t΃P~) )HQk F+9|=8+QFi@?@/~pG2odH2|8(Zϵ nwun}1bV)D,};nԇ]wNE/z^?}/ug*NԲܩsNC|ۡ M0AJ.sil1yR@kscԴ;\F~~[݊p=e׬]wGg0fMK\\D^*0wNZ#_ 6/ϐ!Cܾ𒜃:ޒd'@{q5n9v <9d9@Yq5kPs9u7mw3?7(36/w'B]G=Oqvʹͽv[yqgf++|ϝIE<=2ZʘGuŮ+h0AJ XǂaVMx]cdyXMn/ٛY3\˜k85oS3p gӈz0ex?l)fZTnSq>4' Ѹ"åƿw6l7ԦM׷o_Ĺ2'mg4 Pn' !oc-8a! 74$XZTyP7jߘUnwCŠ- w6A:o\~ԷHsƻ;P͒SG~o/FCZ3aW⼹vsR1KF}[BhPosK`WdcZ׮pJy~4\UnS~~deN"♇ =#;S6WTa]Ft?\u][z++##4cȓ<+7%4֑QPSZUFZs.l.tp?rN̖=3˯v{7\)|Wa]\~޻.:K>㔽7¤qp<4iAx꣑FXaTRhCdgÖ-[>zwV )r]h׎g;PX\&=_8OuZͿ5pwux!a-;2[rLvݪeN~8T^ի5 xY*)F[uן_y;gٳˇg&ԝ)e/$Ds}aW(3ԡ4+ fka.r6v7QPu_N73ϼ~IS3<;z+# +>=ظ'rïParE.Tq!hHȂLc  23<Ԑu!/2 xO>G%1kxX<(D+Ay&ޔgXt4iL!m" p.[@:y0_m⮽o\%:qtnq=Ee\wۇp/S g1Z{)GM/&cDׅv)d[fB=-#e QFCj1CƢ ?5t?"wߛŷ q?C8-sܷ}<#D 07D6As[S_mkrxO?Q8Gr"(}*~mTO F0`È槓3o,K.;w>D?^Q}2hLS~!pmTc@tznHt,E|"itF՛S;;uy.ƴD<¥FLEϼ;ѿ㪫pvnXb+9HLg8)C&'J`*"J"ä&dn<ڝnɚ5+:d|&ߤW3i=U]U,_EZDyn7olmwڵ^_jR(c@<5γ#44N# 8ii4ڴJ< ׯ#~>S``u1Dž0eE9ApfEz͡7>G.b}.~rd7׼8ݍWmu7ٽ nvK;d(@$wwny2 y&]DCZʼnvL7çBfPҬH*fUbcG (7ȹc\c v?z2Y2U*Wɢ\ECԋX0-7Vx0Syfxy{Ruέq'tOux='y re(srk?:DF54hH9;pM03i^/I7xo.B'g|CrA4A?PO\%[po#wEOwc8wHVcq=mo9v*w| w9c*:u噸>y yH7 IDAT\^D4\( EGG˃oT`ei1%9>mz)w콨z{|G{gτ >4xuunuy2zo:wI:_QA__OjBɶ JGn#%Aw-F55i4]c)LovX^ܫm۶Ԭ?:c# C锉?A ӨDF%:,v凅ŋws r?(rڨF69xH^8OOht%mN5kuL&. rǙRא_cad,W]GHU0 b̸3 535$ w4Էzj\ťJZ@ ba0G#euIz|A?}Û9㷦F̮QPHqrs#v3 AlI]jYqH1h8iDkh(é^>ȲyQS<~)见2.&/ecLye 6w}u[lqGO!ӕ Wιl,ɒ,Hr ǒl˨u3KSz1ÏNbqotҥ{-[+x cϲKCNN020F1~ ^F3iX#NJZwޝ+++E2.Y^پyZGB 5? |#G!/9[*ճQF֑h<8. (> 08y](P^(fPb՘k"a+_~3gרT1c۸㫤ϼUuX-[SJ~ qmT#83a #9Fy N;|@ؾ}_o sau1b}i V=qDw;9eG@֧ YB<'3ȑ@!.1=-%^D i5Ri-"/6k֬6\rISO=e>p "aMN+I?'!,h3cal4g.\ K̝;wt1ߑdG!J! f#O}8pƑ8~pRĶg99p="7|o]4*:b GȔ7%tøx$]euau1-vXܡJ~Pc6lׂ ZuQ4J+wVƴ!GS 1\[FaDjbg#sa:f RX\0OO>?T0r!~=_sʀ7֮?tw[y䑭;8mmnfm38eL@?-Qɓ,=DW|G ViUg~r.p(t(ԋ@N8a?.A4"vZwi91н⦊[Z8ˆQ/`ȃ `WES28*.l.t<D܉⎖{R;oiӀ_/Ł@[0|ML#CY)InY?,C$l\#H?VEG@cR:1Ĕpk6855?%&~ARj+҆l({rß4u[hG4+ fkB .nܵ2q qO;P\Wqa>p'N(҂W]}=Zv[/\pi"#To82 Sf=\ymf*61`;؈ҋ'0ȫ^w_k~elfp{Gv݋mSrJR=_/SLbSsy7iNfh8< NQ||PKTX"72 z̠"0ȱ`|u r2  A} _c,)vI%u}umJgZy+ܨfL#6ι Y@F0K(P -=zQRSLeQ6Fmrq=sM^Scq]P|ݎHh݋4śB? GiYiy`|xGY` KHc$վ}H0^XFo׊!9bi:ꕸJoСCǪ=ĠCZJ RnÏV4ЃPNMxf P(#qȑ8ƳUܿ]# }5Z 3QF^Q&1/Fy ԉĘ2AM #jybuG/ cZp 299:6Y`. 9D+iP$ =eHiŪ2 '(o8wKxQ=IQBkGHU_H l3ѿXsЏak:kԻCo҉+i]p^%GyP/zUo^u0h:ٖא _toâ4""kT:pXX@XCÏŏxp(.2e~r*t ~IN5ӠN5{p8򢒦Q YmeYԃ:(Spu!$Ƨ$ k `Ѩ_]nKYN4.8uKQD!3:`iQM}r-Wo$O~o#duiɑJ J/hYҡH-A1:'>DxkY(j*tp*pOr.q%رcҍu򐛝pw!5uڰ5 ?u& X16/˓#?FMCXÁ7ĝ\^`rAYa)Oʴ!̻$y-C4̠Ssa1 T?zwF~ :딢ɓ36 ;Ԕ\@ic ʚ\s䣌Yu RG~# _z"?L<3*/.!kNI^CJck =/Ӊ#ɰP' AS#R/dOm3@3 a<8 , h(WhgX*u G555ȉA(lII5raJ J~e]m0,Y@`ԨQUA;胵Y8ŚD=5 yu// ӈC υqG>+w)pX0z m'ElB%Ǥ)jXF4FER>BP%"'B"?"-ܰ{\ANڠ֊~pO% yAS#^+uPlK%b=#彑d_"G=0G:-vеԽ>I(,i-u &Z_OYkJL0.aɞ{k{w XjNJ .,lT(PTPAN%%B:z i']Nv%mPM8ʀ\+hF+w*v*{k?;jOHh1Ě # q#::aXrԏx[\aI2e@9h./u/47NsAtX,bA4|Ftr(k(8vzj??3۴iQ:=q!kLx?nu8xL\z_ve~jժbj֚)2!W7_FON:z~ԣ3:Y:^r50 a*apC7șNv7Jyy=d.t$t&$t̬EU^պW]YdԥEC@F@G?,xruNȓ|I>`T@̠. qV%G?J~,.ɑFMKr&=G8bEƸiΝ`xvήR~|GzgrcJ lcģe/bDp_Bݰfc@kM><%Ú$.e:Vi k.^đqBȄ4fŒd:0N_=U: FIv,6+u. B:!~8*tf8̓~SCr ڵ;[~t W=0L8 qTa,|(xcڻ*O0KތM3 "2/K ?%t+0hiIk̰F:1#'ތL|HKδ^{5èpL*98(ktƱ<2Ӂni؝bM Y'ܙGL]fLdq^e9?(Xq" :Rg6ƙ_AY b>Po _aFc=S+UtꩧaώF!;v,r; 69< /5\i\ȟ 3o0LE ҌF@n-7|ot‚HyY\ЗAAr-ӱ ӵaquaqS~P?#NPljvLmvѪ^`4aV <#Q3_12J[R6C()E [^RjK=Qúdۤ~>|p V0s̉]rJ؜KpJ/C]r"aX\?Z .67p|@A8{fHk4o]jc50f_eLO(LDJ=7pT=ä $̠nlQH-m\c!E 768]|VƔWִRQj!Cַo\zu0Lpvq!liJ<^n:OJnlfPG.l2Ij '>Y!Pά,toT|U\nh5p},CN̠ QfhDb+_ C dѿ{S RYpH6ς l Ua!`@t)A\]/͠. 1 1c.^tEg(.;u[!`䋀%8A-uFou,K C~:t\:"wQ>@y!vH.͠.VkBWYѴ5cǎ1hFwҥK[o.H!/2Ơ̽)!`O>UΝsV- ( 1)@@ ur^tECIFl .Ҟ\Ogd(C0bG]vQfPA:]hoŠy'j%ٶm۞Za1=J;5kư<g@ndPawZB{fP)Ν[+;Mu]8Wmd4 9ZE OmR%V0 " ՠ͠.fPT2V\9]?53gu^X3 C ZjafPA@fPT2{1먭Am秣e!0 Al,0 $$PݦԻ0_ "usu;r\,Ȇτ IDAT;g\LY!`I PYYɦfPA@/BV!Pp&ZvoU|dt3 0z$_OqoѡekV ;`@$v### In߾}Z䂖0 hӦM_͠Ls͠nzV6m$hOMR%4V!iӦ}PB]@ B ꑏgd BxCmSrD l8E\5vؙǑOxRo:)$!Wm۶yLb C# Gl:Y`u৭fQrQcǎb\,x߾a3<;7Sѿ,o[.Y"DW}U[!` =>y=9Q?)MS0?`Db,kX%vD\ߙZns C0Z&v#Yu'z F6:.[ߣV [l|T'3i;ҍty2I2Fд$C0;`͠NX[F0 4iag0D${_3f2s{ҏsaP2abΰWlug@y" hծ]gș2@Z aG4i1^s *c85|ƍձcoIJeS8qk# zՄи!`區P'+R16E[1iicqr|A? Iw} 4ht" AӠڈF:d)oF5`52 CjPFKq50cXA?UN]\Wq/p~ɒ?~z:'4'WŽ'p3" q2)PA0 2F ω2%@Ak(0~FCZAr#bAMiejѐq mM34r}*++_O4{XC0Gg#^gueu@M4 gkY¿w8'vw 8q[n#(Fzj'wi 6&MOw8~@ B~Us3($$ߡز(-!`i@@^=dϋy-Ct̠U)qх?,cG .WV]vYN:IQܹ=??qwm_%q/8%8dH.sG:rtC0҂@3_ۡ.5*#4p@c8Ϙ߿[ti+nfL *)!|;0dpB-*Ap+8 (G>^-ZqnɆ!`ySp$=/vEEڪLVsg0fy=zH(馛܏~#tyj|j (3B6.c'Oޑ-!6PfEFe@`waY3pcٮC,g<'?q'iQ458n`1xaS[[{c@)!ՠ1A]ڃJȕt1M ?ns83m;@4;?ϽΊ F j4qT૸C~X(qK޽9ȱZ?$јaPӸ.H8Fcd@I!`;Ɋ d/X@)퇱E8WafyLVtI'~\)wڈ~b!`\S 0Je4:kk4%6 ,xnrqY'F7o#8z n58I;a-X:mHg:&wy[41JX0uԥ- !`,QPۑ8ij-SiРQ 9R*6=sKg_Fy[nBƘl?51]~70`Lq0qpyڡG ̠k+쩌ͺ{E-3B4Q F |]:ew C(--C &jP5V$ S8OȢ%QQt_Ȁ_F?ձeCwMu3nv_snѶunLnn˛*7mn۶nǮmn^&`{S[zdLZ~Ȝ4x'1b<o!PȑHz]tE2F84hXi:wrc>Ͻx7} ^p+g)c=7Y~[;n!V_u4׷k q]ʮkr 7W#mT:9k*>{IGOUkґ-_?,_jT,]|_1{wb@"`;JX@4F (iXàt2z6:ˣշ5kosMZKקwLP7ey眝^3773fOtOi yVݡ{o& *X^AS/s>0[z-=ۀ CjP=8cZ"j`TðJz=>N=r 0ύ Xӫט5퍨ql݊7~7/:94C3;n7l}(S~X7k`HGUbQz'1%?F̜$*J+V!`EF v֨<qLExJhn_p#~vWc;ol>bd&֧VE=䞖s g]tey&OVZAuor׶۰ C3Q|D?z-rhC p;>s䅥rWOl=a9!`(C̠NBNyҸ /toؕqa3vlp[ضLX.{/>mx@N {FHK,HSkx72 C(#8gG> w1Q5慬yFre62 C(CڼdjuuN z˓݉tWrhT%!7w ^Pg">iv7Ϣ/|&-WGK=l#C0;vGqnD4mL1M1_|fAqͼ}]ڏoOv39SukTӉ!7 ՝;ڹLM޵nCK~ӟOI'LZ)u0 CD5m;QA]PSR%d ,mX!1w=|݈ ZO|]ҷsvf#GW~!K3M.]uǓ'5SV,/b8t졓gחVUx9ލCK3(5k߿d|YKnpE^gx;bwvww/X쮣Q-7SR:pHĵw"7x{Oc#NLu[lۄ-n=]*@;o"+{5٪/t| n7zJti@TDE(U';D/. _;_$wǚ_%nqÕ^ w+I[n-AoTl'ΣfyG.;DZ=MܶZ4 Cqɠ3A-ս#=>$ߔM^-Uen0ðEӚ7_?ाtql2 C >KEasiӰad@Y!PWD9:n7|}o }mLC 毫"sy|ZMO $PM~%׭8b(;œ 0ҸsÆ k-B0 Ago1Yv~W[/n=}>|KĽ!K&*O^?D~" ; bH =m<ƽI+klۖyLFZݹsg|=]ɓ'/(BC0RtCt!R l}ijBA,q|g>g~[o~%COI{Z_A'4BJK/3k [(_r#L+wQ9j3  jA(|ÎQא2/e tQE!>CI u,fPǏy-b1pAkCaĽ)ӥKe˖רرc{gL)_p8B.[>zepgL]e;P!`xH[$Nnm4 =h9Kqcͳ=lZ ̠.i E/NkIv̚5kל9DJQ裏 7n=*-SaQvWjkkGId9 ur؄;o]}Y-v7: Ҏ1E$D~mlĵvk5J3۷owwݪUؘv8D?(Wʛy/ !pw1uZ!`bRg_qxvܣƍ[6:UqQf!;Ή<̠S)Ϯ' O 6 `P/N8]?҈ڵki|Ito8B4)[-kI|seKrûU8 0Z66W]".V=Eޠ_oW3+ q=X~{3Ȥ"0h`90?]+6mjugo}[nDRB6lp7t;w͟?ߊHeG3dtQ"ʆG< )zu'pv=}|U}UHS7e/I9@0ȑVVԮ]2 Ng1 C 3^!e$}z.AN$y~ð|K'Dqţ+dx?|'fPǍx 4aDGxD&NGqM'磌~Pe˖v 0͝;׽Em+P9 9%qa\OKAlW=7( C# jIt#mЌʴKxmxhq'JK$nu0\ tM_o$mlcԒ'nJ:w^  c<Lck wj>g:8(X/NY#k=#o{a_EقL>a~gŊhL8> \JLCqācpHL>(FΦ0 Csx D?xꩧ~+[>pI{=[z ?PAFNV| TXvIid-m<±zm:Vޘ60uN;4QZv`#2oQ8V\555[ĘW֜?8cEy=!hrCZF0iCftCْŹ E C0cl,q3QF.W)('e~'m`W~=o'iL?fPR)3B,k ll4 b~䃁r "1oF:~p8ژ pȎƳ6K#9>VFu\^GJcgִs#C0Z[Vπ H@)fXU k,PāI4pSJEco7 ͛7o 1I?ߑ&s)/ B>-3iC3a.ݾKҦc-|K{4{C0z7Z e,IA$]J#:8iڠaƝhtD#A^/]r*/jߟy晿K^8Rqӡ cѯyYu u͙4ir0 @3Բ=Z"FD7 cp!4hC~/^8iE#*@1§?PMb-JYPCȇyi,:%kF vV\h0 C 'Cf0&WK C~39hӯèaSpczi]rMo )?0A4r3?8ː{`NS.$?F 秿$G=T.q!D>YD ^ C a@Xxhp酇t? jf8̓~ B/⎐8ԛJ0=&E qYSeE򵥷;-srE!62 C" j~ч9/y!g~ 3ThH,0q0*#McZXƕ,F)8Fwh<8ʂ0(׺2/oFKތ] E$e S!`4ygsu1&A#I65,8X4Ђ]C^4ə_A\0|rTO"^?jD/d̂a-CY d~߿^6!DR}>]AA]K10f@F<`G̓-x>"Z9pЩBsH4M%13˕##TmL!d!wKxF4Ǧ4ȕp9aI@ӆ5΁ի'ԾԻwٵ5{U1* G1^i17n1۷߯A0!`-W(-d%tŌnd1۰SO0ii?We"air` <6M%g oӧσ~:>Sbgi)rx_Q9cڴip}bg1 ϓHt%=/b@ 3c: 5gIA?< 0y8Pի=z$ +9cDKG#GA_ر~f 0!`u6d≷#\lY7-Z^+}5>o޴R_j4|Q0` ^9=ObDm׮η|b/r)V!`&Q|ȳ&oKŦ cg%%~ӋL:j2eʳғap'7Ytza!P G~3 (@ <G/"SČⷘ&My8(_Q=2=^!`ۡNVBfP'@eeJ_Cm3eWq`m`!`D 4h;ԅDݯ "jU6:iͫ4K˭&&Ũn-#0 C .߂gC EFo&, ^.r"7ez`p(ȶnHc!`;C̠Nk!޹a1&n79q+ rbd~|v0 1+d {K!Ѵ\W! { T"{h~Zذamtw7yK_U4 l!`DA@6I%<, y~uZvCIцoBW /ٗT*+:ut̘.+` CD=!ڏ =3ZMF&` 5zjY c@ H|~u j@`IGΔc3S)D5 2NNlgs"QiXㆀ!v̠NVBfP'# ;#ċ3y Cm۶ĽrC0 C ;Q|֎|d)&Cg ,KZz饗vnӦ+i^Regri#w)+.t#i=2Ș0 pl:bm:.QI&/y C0" 6= cg% gHjG-ߚpbΝ̶9.uc=3ɵ}˓PJ[1_~^*q菌v5kHU3 Z3Uw}JSLy^̝+}&H? CDr~Tta U}.rF ;0ݸ!`@vDgFD=alrJ+@ [ACH1#Oғ=d=_&-^gڣNIsّ^/}YIqSl2k̙fC0Z0s̹AsA SO='Yz~D4_0D@'yG$D?yUwо\;]~84e)uXDcKwUUU8k}Z!`-ѕv# `u[ӆ@ĵ.9S_h"K2MCD Iv6 C صyJ d ! F؜(Fg; V.q{K`|Fw/Ϧ!;?bqC0 :Du  " 0[ޘbˋn~6CJaLy?41+d@y#ɠAQh<:3cܚ38]vwz,y˖'x1r ĘN&.LCh99Y0˯:mDCO\p\'q{6 WxC z͛7|bc4C0Zv:YA,-u>cǎϵH k֬k@9 _Gvu <@t\1zHOh9cz`{qusqTپ}9(b=3eH_[WnXՆ!` PYQ.53B F H4 by[dOIJ8caY7ۡ*/oY* C({DGQeXhuG@vTCj, o3j&0:ewNcX*/97ܓmVF\4 C!ɠX"m<7b3ݟ#Nr.2e}QbΒsrFH窷Xҿz;|0T^;Ee3 C u@aFum':fPGr6:A V@;M1H/ھ}Ѣ8gJza+o^tE#s̏( ?8ڗ6P.Y4(`!`ٌdP j =[VTH4But%.eӧOKpu־b60~^bd jEHSB qgRd'ō C(b#J>˓xpq!0 twmPڀA8f2g3[Ϙ1m1T/OQ)V`Q4١μFğdg?ю3Y0r` #4ꃌ!P2)GfP)x8EG@)FyhH Eo0E R]Ʋ6ڴfG|Aspayc7lOnи[~ׯ߹Q(dh_̙W7s`E);ؙX1<#C0bA@t:TN]6rR xEG@>_K;㭢7``Aa~Ʊ|VJ<̛w~u֭-7ns.\QĘ~gFI#Ԁ:L#G_A.!wӽL0 b# mS(,͎LN[,[tb16X_]({ldSNgϞ׿~_WϲXEN+V믿T8I9 0̏tȀa8em@E tSEժQ ;Ĩ[?Bc:tЏpuUשV/YNO=>t0_gɿPK,JŽ* q xF>!`= m'H12 X<{iz)+4JYXaC1ڶm{kOC W;!NR q0o,oJ3MW#4kmh8o:K32 # & oҮ ǥfP7A+(Xƍ;olପ꽿w7T0LS*.o Z)\ѼJ]Oo]3+n*/`/^QI4ӼhRAa`a͞ϙϜo}X_o{kg9 WyfNшȌ[O}~n}Are$;^{aݖ|N} 4cL},$@pt?ʋEaAQ ӣ &WdG=F37K؆;gIrMv"q>_򗃭=f^_X k_LS\KT 9 ^IPETTD N'rߑqhvZa18BL|JL1½unFBw`ܸqnѢE/Fɛo1Ǹbk-" "PrI`2VKG>bcCV2 '"PzOʵ#'3 ((""@ A0g+9{ 7K[vV,uc\Ss}`;21۸z[6~pC2V[[ͥv2yߐO>a_<'v|(<}YЅPRX#E:r" "Prc:#Ӓ|˗.g F1 Qik.Zb-(]w1Xmqs&Zï{-Xv-+q:ޝ1tܗ%f+E+.m"a YmfK$¦4iR_ Al咐ݼ‚SfO!PCu٬+~>umN;r47rέ]~}t޷&\: KwRԱXC˰vyHŵ@oA9GY_P*L$W#j@>}&YG5%x_L3Ԝ-kpgz۾}oj^718H]ov:G|1=:np߹rsmpnn [vWZ:vwcYj8SL󺀕.%GZPˉ@) LFe6C=Vx]I S\QXQTC|sW_#v?w=^{rt_Wyˀv[9SOkRo.AN.Ws3ç6u6 ޸57ᒇܒSUMa;c+E`,9{^󺈿E:@tя<`L2C63Qnjjjzc[/pJ +Xv?w[s_~;S~]#ufA]av:͸Gޮ% ;wvq{{t ^2X:R50y=-8eE@Dp$"*@E?؋4#8_Μ9֞N<1>WBf1#:[r}1H6d 7l#n[~\j:U7醫ڗUoX/Eloy,ۿ-H^F* "PUW$VDFYoR[(`bqx--:wˤF*zӂ~"]ly% H8e0?+kawRԑddpl90,mkLE@DD蔪#td};>n?w!XW u[ [ G F;3}y}p#sB3\ϾyUud9U\ڿxn2]VD@JA ҽE3ԥ@ݾ:Ӽsλѩ;E,?.m06glSàhNZ\?Ntn&]D횷x.$.5kLˉ@lB=}^J^N:D>g@#ѡʪ`|0<4,+{ۻgMk6xkjvOt{t#]ayac7ȉ@{M:"ts/kC`2bv&6"Ѳ׈8VfЎ7훴ttwWYOnn7j/st꺅;7GFuץ#}2+h[c+" 1Hg$Z37mpt<{Gopc~:)gg18]~4c824ʐ/NSl6\)Ppu@u'Aך{O[3gΚxW"F1];nuٍk=_??ē&|g/pWqzɵnxQn#KFѭ~^Pw7VDLRte p)qf>¶|ҙD@j ekrK.ZPqqQFNfތ8 ]TM~+ꇸ,p9j9Нqc~'&:<]JQm;SO7/1 1nU:7fcJQr\y"9-0Ɋ@ Dh[ x΢ZI'H>o:ZFW ;k|녟zn/to-;% 8ܤso<=ػ{߾{a?opnp7߻ O|at;W:U[B͕[T@qu<׆͋kԚz3}8gJg\}ӧ܀OwV/_6c k/An@Nصdu +^r^\n0h\)E+.ub1ΔV>Hgq$M7%4Vҳ`466IO? nhj =gEN)EO" "P3#˘>[ojmPE@D@D2DjG<L;aD*ĭ_]kyꩧ*, 9rxeD@D .|hۼxMpM\SL9fٴiSj.q,COBL>xucx!nȐ![nFvv \Fo8[3ϸ]v!g~y#=Ƙ[V Zɉ@Ih`, ց&'=sΜ9r |0,,D4E,M0Ko+WkނC:ǽK駟fl<0y,t ~E[NN3yU@(lu͆^}B4ŠB*FBb 1轏>vOLRX) y4fq <1ѣǛ{`[1Du/:u63’%KV[e}E.7xbvZ:/f0-a]J&d=gEӡ ᫍMPOz:6z\t/}qF[/j2!RB O4kLD?kbzuP4 PTc|8n'j q~%-Nk6Ոe'@3xE5g%Fq|V$uNX9({$ugRl 'Or%& A]bIW ٳ7'%-ō aa!(w;S 0nr=,K;~fWYBw̰$j5,55zc5" "PZմOoJ,-t&AM@HO:+Ȱv@JSQLS\AlE 龟gk&PHhBzUV?@ޟFpnE7Dc,#L jg iTsǡ^; Xbjr*S xTi{g?ϟ1cFMFE*(!(=}ۻF_\ee4>(LSTN k"P[_: GKAL@CL`9n)a9L!Mgy,b<VTND@JNϚkGN}l唞&T68a!yx{PH# buMП8 Lk!|x?sd$!+"H݇b oUJPõk51=9ĬL͉3g}p[*-kמ4o޼5qPXg֟FBֿa+*"@L&{ j1DŽb:F:x?͊ʉ@x3J˔.[⏲懬6lp_;[GU5!n/,:.0# !Pe))-)L4l:[:K ?0q| Oc<ցԹr" " {q%gv}I$K 4)ٳ sٚ>я)Sg}ndEm鍍?߲$(Pw~D3nrH"i~ؒS`kQ,ߥp|`|1B:=1 4,i_@R]u@@=t? +A\X^~O&?cmvQO[ܼs͜9m SChotB3~_uѶWD@!_Mym^<%Zѵawx\Fs&7! fz뭷*,)_D1 0n|"a?npH7RKP` 8&pLhf-YЦ5I ˄NSII$K*5|_4x^)noA\T]=(Okqsl1fGgźُ5oζ7F!K _SP#ax j Ә4߆È&^di3! )DZR@yf"*uQت.&&^zֶmfyrFp730L5^ۍȖO߆\Bʎ $!(8CM1WƴpFqEq82,X8\ -9c"l*ݛ2PuUxpG{o-ik/eXem,c 71 0[wC jZ -g98\3lq 0DŽW\D@$Yx@:]kk_g-}O3q}W9Ӗ,8[RT,N<,E3ySD:,gc&LMwi Q Zk_(/>Gr~T,h$qR4^gyi[ncٛkF u /wqآf1?5S_Fa(|ΊCWsNyQ WzN;^{%k3fr`(oxf*r y6~/?mkULD@:@gu<#ADjo' K+c6c>^ok!93{_l_*>_H.km[*}pl7pR7k24>A}2޳#g%s):ShtU}`6aSLT(ϔYн{6[u_rI&\^`bv;8y7_29D\Wv|" " K4un,a%c*7ٓLL>6v{#qů-ֶ38_߾}/jhh =c7d;N" " "P"Mf1 u P+H_amg s`},/X-\f33}&`7mǒ'j'ٮW41jJ3LL?T ?~|w{֬Oz7M<_s9g_ϳhViD@D@D "Pk u1[Y"~PY:x2/5h;>VBdaAj*ٟqE<2ͤ"/Sz4|YHo55&//~h ۙ }&؟uYħTz, w^R*," "  `vꜜѣuNBe&zΠ i8ʤgPH~5:vٹs&gZsy ?ĩem!)ڍ?L`d!`HP{krJOHDƋ錇-q t~iUal;FTr){kxM,ay)okް}Ö!ol߾ ^3s̷qՍ" H%$f`Ϟ=<t԰b yW/3 e ,-1?мǯϲיFt-{g/ȣ֬Ym۶mG¿aKQfMZj5~zfa)1>t6r" " FNk"*/ )}KL! {iǙk^ yf;2t G>% fKT@M4P~KPStfbw!agn*ͧXuQnذar{K>g,bYvׯw+VpO>d-%O5WCTSLbaZڀȉH_`{g<ƒվT:D5(ȉk#A$J.xihz|a~c>E?6 zl+=+ԝzh^1AC-Ɣւsjɉ@ ٗi:/ @Tfy!QLba004A;#-*W #3<e~f`u8DPIPStf jN/!'Vk-ͫw_xTÚӧhg$-mV&" " "PmlG$Mg}RI,YuP v׾V7|p#[ஹT+mϷǕb{所@Q"=.ZC]URB«[.b3rD`„ nn #0մU[E@D@:LdY%APqI72 ) i_LM|ǚ}n@h2j"`7 7rH6 `L}1ǵvlu뒜d$롌JPgS|HU:. %Z ' +*@}a媏 gc<քq-J>r" " "xQͳߎIPp5T"B}Mqpx׭p^}'5u`7Lѭ^̽# IL͞ԁÎ!MOq kV7 H0>rvq֭z&$T\&gs;2I?Na x3>`:-9nĈn#^V4giҖnVvlKB%NnV,_V^5gT}%8kB{R9d>g7nYP[_i/K Nb5,c2ӬL\_a˪7C("INu.)Pȧ؂EzŸu7m/,٣L,z@ IDAT_pʤ3w>k*D0c([vm$Am"u-n/@x=eix`au@7w( O;s- ۏ#Lq ,`Vl^4[]!]SƪojA8sL)MD@D@D QCmλɬ`pb~3-30,%> D+sRNKO'f,~dak^k^!JKq_h!\]&^t`hzRt+ܺ-DyskllK57fXѸmGPl۴1NL8C@cpZĦ" " "/xuW\qE X_e~s->;Ɉ pm ̼8xТ?T 3NҲtyΝꮚ:rV?5ݍ >bËjqۧoWqkҺsJO׳g쑶wYk--:wF:ϱmXFNDnUY ˱ŵ|x9xu&Bs jxvTtRwx'i1ud5+9;+eŸx7^/~W͂#|/HB:g2+[_}7)nx{.z]z㧺qmfqg'ĭIp47w8O j]OUhߠH/4)kf+'jT_pYx.Z0‹!t,{ i_|E6ۗǏ_u;ywXtƍOs Wmvx-nz=mdkܕ^ ˛?/ O ;z0w}y}ٛZp#ow-ZTTjƸbb:! Nrp6Zc+" "  !Pd/32KŸk0\Ǚ: o1=lqp~? `⒫YPǩ, 0 `+auƀQݻ/l֧nk]?- Ӄ[?~Θ\zӿn ݌n'3f~cףW Ր9_/4,ƕokzpYI;KA* ģAQ D雿m^St<Ύy5|YH~|&OdAWdB4u= $djsLmZm xBg/!NFEd nN/͸]4}s6w mqɷ?Нq r뱭s/_*6rMEƙ#,'" " #lٲH8S+?,8Qa~[0#]LHyGOF.3r(`8ETz5foٚS/rwmO8qq6r[ւ_ZСQUfϸ$Pיλ5+1!}g2n?ձKC1/w DhelLO:ixb".猱wwozc7v>Q;qvWЯ͏ =qw6o< nEn ~叧?H~" " "PIlbfڠbө𵿕 ;;/\HVx|q?3GOGqڌUZb!gY]]C0ڙpF7߿9w˃ܹ^(3{*6αax&" " x7#=QNѺcu94qܑ1QςBţmA/[v㋑'ąDjc,tU;?w\[Ýun9j&m-9c-uA܄ ǯZb? L66dYOt'$qlqjoRNST޽{ygzd౾[Q4oig` 'K^|X]='pYI 3a뇸˃U k8zoZ gOu{ֹ|;k7[[}!yצsSsoԥ7SG{ų-9՝<+2m63?kyh)" " 7!G96CWP[C`lf&L-TS_p֎a|-8n/Z+yxPWLR/$ZL~ٲ6&~~ǜ^:2]{jc D{Snx=~+q`ojFNVw6p bG^(E2 Gng*eϊBֈ$@nݢ> ` e! 5)ñ,--;2#iv/!cɇ u1qӾhRn1g*u2ew<$aԄ5QV?Խ띯\; ;&5ݱ2o?? (ID@D@DS t޽3ꋉ[,(LJymcYǪ\!|ZNJB@3%JD@D@@^"@VsW+b[aY~)kjJj$`76K8D@D@D lݺ5 -H?DkZ$YPgBZ,odSZhlљn L^" " "P<]Fv=ǜȤjn_( 36+ҥK愢%kq[ǗweYH HWØF=)xxBl!_-oyyl}`l+"c0i&'" " $UP[\ HL%.z`CyJ ?4#WM֮͛]l n|#8SL3N!,'" " %}H3ZC%P͂B֧DAhǔd?Kl~E@D@D|7,}*KȇG:vxӶG݄ Z|MU2,:u{饗L BرcJQq5|:?4YzQuT˜F; ڿ8~_z꺏-/ (m۶/~;@UX3<߃NM񆥷$@sss$=gK>𼔋@ἥҿ0 ((`i~l?Foonʕ$W  !?9sIx84cj'ق54X8ˉ@D֒^mξaa {n滚m^Aٓk>⨣rÆ st}-\5))_{'[LTsMʻj؈zyw8lZr" " "ҥKf̘13աv1̙JX&^2LqE q/bw~<cqx#a^r" " "X;v󅹝vͧ#,!03 8"bB k?`؃̿ lljNHyt#m {f7`L3 c_9š6jr" " "uɇu.&Agwu)} a>B S,C4y ˲Njɟ O!g>2:D@D@D 6|'I;X(e 5}A.дլ6S}~ ?K!LKLA/BԾ P1s1ڀr" " "(Xѭ^ÑiGn>MOKA a!<:E9Pb3ӰpnS10;CD# /}̙i! |KA:x֘@ DQvoVP{! h) ׏<pF"uc FE35-ޒRipoo6惷tX? q[4?AN(@ hG81ڛU 8^ .!F^XP# ;Oc iԆ48~Ey壓:1#je_XP8#9qr @Q 3˴X+Q]<Q9H4K> N4rw.Q>( O5)C<П(BL"y,-Xu0MVD@D@M =# ' MQl_XQ*p14Ɋ@ h7h)kҧL(gij?N&c'*," " D>ԝ<d.LHkdR?2 tydJC>3[" " "PPP2l$%|ӼcuQP[]uuxXv\oN (GD@D@DlW__ҙioU_T;H/yc@Doتf|Ď8 $"R\QgZ0JPVՊ@9ڵ+f N5퐔,Ad(U-l p3F_]&> @D@D@D@&5E+ف%CD@D@D@D jmHPV5@ jkvi4$cjE@D@D@DsC:7劀@E uu珁Z " " " E*hy΋HD@D@D@Dr PLxkꘆ1tnU+" " " "A .A]BD@D@D@:@TAm.1 R}LZ <@oooyϜނ,ȳGF<ϟ7*Zct֏ g-&A]CT5kl>ovi6<3-c>jQίlӲ%)=R9 )KD@D@D@D ~guVeNgt;wΎT IPT[uqGǏBR͐QD@D@D@jرch}^u3; r~ j)SD@D@Df3;kV\lC5[FKm v킠mfO2&`%*D@D@D@DlU6KuX{LX**" " " e$)?N4!1cU* Bu@D@D@D mk:o.uT\D@D@D@A`„ [<\9w+/` t>>3Z甠SE@D@D@MOI]:W#AT_D@D@D@E{֡kD1,Gg$AY" -ײ;_dKk0 {\D@D@D v/c+4+s$z :&" " " w Ǎ"s$n $&" " "uuu*p_{OwJ<*" " "  0z<\[mw_TwMT+A]ìNT;,sN8wOg_3" " " "U~kEG, j=Vԙ(UD@D@D@*)SLb-uɜcdhE5:@(c\ԥZD@D@D@D vydY)Ndӻo~g):$k PE@D@D@@Iޜhӏx≯W[+ԕ8*jd!`>f{Y#'[={:2%sQTkci :RM@z7 D@D@D@DZtt=Jou'" " " !7n|В jBh)+AE@D@D@Dzm}Ek1c^,Xu(JJ'P1bGVLUNYꕅܱc݅ HPg" " " "PqL^wذmyHPlT;wiE).Aʈ@VDQf D)2.J@4K!;ȮJk|#AQTD@D@D@j|c>vr|̗.J `{Jcx(O[9)" HP N@*r=HIPW@6lجIDAT0?:t"K܌e!r1 r~l-n ՖZ<u-," " "89^Eu:Tg PaMRsD@D@D@D@!c`cM;v| u PUtm~hYuu( =vd-MMMmvYQ'AWE@D@D@I~|fޙ}|ueZ#" " " %pgPތQJD@D@D@Dlܸa^ijhoڨ]>0xϟQ$c$ A#\U-" " " "|Z1VE@D@D@D@b$ A#\U-" " " "|cPD@D@D@D F1U" " " " ' A1VE@D@D@D@b$ A#\U-" " " "|cPD@D@D@D F1U" " " " ' A1VE@D@D@D@b$ A#\U-" " " "|cPD@D@D@D F1U" " " " ' A1VE@D@D@D@b$ A#\U-" " " "|cPD@D@D@D F1U" " " " ' A1VE@D@D@D@b$ A#\U-" " " "|cPD@D@D@D F1U" " " " ' A1VE@D@D@D@b$ A#\U-" " " "|cPD@D@D@D F1U" " " " ' A1VE@D@D@D@b$ A#\U-" " " "|cPD@D@D@D F1U" " " " ' A1VE@D@D@D@b$c;pIENDB`./nsf2.4.0/doc/next-tutorial/slots.png000644 000766 000024 00000330230 12501766547 020444 0ustar00neumannstaff000000 000000 PNG  IHDRGw pHYs  iTXtXML:com.adobe.xmp 5 2 1 m @IDATxTU҆Ϫ,Dŀ 3* #bk5b1aV̘3qUDŜּFWŜN=tz=ou:UK$8#8#LC`&pGpG/9#8#M8#8@ 'G)0|pGp'G~8#8#BQ _uGpGɑ#8#prWGpGpr#8#8)UGpGp=8#8@ 'G)0|pGp'G~8#8#B`Ժ:@,R^M3A AI_@ColvߩwLHXFl\cej_@Ҕ?%pq*'G]xK1Af}Qj,]7:I?q'IfU>V=ߕB"F֢ ,P[)D)M8eFQ|@Ro m%-ew ;wJDPV~O/a[R#P&x8@ Er+U^o9СCˆ/7|WV ' +{Yg5r^@W FW8@pr8@ Z G F . \vea- ׯ_C݌n-wq>O7 F Gc%| ކjG eE`\:thXgu­zawum뮳}7O?SN9%\qjǏ [lE,k׮qٵڶmk&_6,L:IHCw}UG(+Lwu h=/0 DmI;JW%}}8&>{"+O2,$ -P$'NLڷo?;蠃2ˇ(Yysn{Vs8DV䧟~ʔ4h?R's5WҺud]vI\pA;vw'FJYf>#LR<=]f2|_xe9Ṛ%+I{K{Frtw1Yz;ֶn!HӤI2ur-n׮]rM7Y49袋G}dnmζK!N x8@`8M;dC,@vLƖ?-e / g_'SǮ6|۲@ϑB' ~x_mhMV9|Zl(vG)F ,F\G89*o6ė ŗWf)Ozλꪫ <|ϰ /0lv> of*4fۑ$o q¾єD_x4嵼nG:@>MET/h'if1~:\sͰ{f>koѬH#F;oXj2簲[۴~\~M6lc"q{ꩧ̼_d(&Xn9*&^#@q8@ĨSO ~8mX r3dȐN;VX!+fO#8D((Eチwg} iF$e\=yfG(-&Gyye*?Hqrq*?բHXO+$ ˱η #P@ox6up*FbD7q1fZA 4mLsO7GyKe~A:@h9iN$FԅfrkTnK.dY0L2%(i+!,Ԑ~D^`Gl:WdZRz;@4FxPG$FgmL 9ꫯ]t ݺu,rJ*e)3죪Yc =O?tm!sOZD&c^NXuUC=dI[+v|駖c,묳e8ӫW@=R4 vifE8Y&iV[meO?dnݻw !c9 2F9 "mr[o喰*X j|pn/߯k&!ԩSP /H+Aw^ -_! [lE,Avjd7L[F\>L(:-!eۅ"Ohy9G@Nj/EsHv.']SKF-رcҪUdEI^{m{h8ʌ5ʶw}DV [ɰcjmYwrnk*ѰX"_ZɾkI6|DLE岲cJ(fz ɞ{,b'IDE ND9H^z뮳.$پ?ȔΉ2ۺ)Kk.۷ڵS(9ímʳee `!Yym}9H4,袶=t:,e+Jx4Yb%%9~î'jh,̒?Yl2w'Q"gCmݺu"Wvw'IQ&]MtQ)iA:JW$-Wt[iO)E[uAf?q{@|RRlH-..%9L@VeȔvmKb>Ke}yQfs;6rH;A se1+ AD,MeI>GFX8FÆ P" _I ok_$ҎGi׮]rM749GGٵ HE3X'6lru$dII{IJ|"!hyGr3ɑuEXZ~G9ddMqȇm|s 0e1gQ{l" _$L^)OfH>9 C^Ia(;!Bۑ>r}bMVs^>|x`h ): Î0ꫯp P qR p)1+ڴ ϺeRlꫯn\uU Q[jlSd|hȧ ]0&K\<Ŗ "k-;wmg}⾎XLsIgȁ?zxipʉ@c?fz{c(\rI\"^od,Ǘp|G1r?ᶌ}فpȤIl9vpWoƶs}jc[o52!%+26Ǔ-̞rynYҳ[F\>u,_Lt<@!R /4$YOi!{·~k.](~7PV?[G ?'Q*?##Pr={Hj~f5l4f8F1cƘ5P\аMp95SkTZ=p-;}8oǦkqyg1+ׁ(-?&#,Bp60aB:smRgg,'.y9kl:Q]ŹO=TXo:|fիtVxMc/WYF YѺbq= tջ6Xt;c2,Q\_j,yErDL$/={{&HV]G\X˃Idv~gq } _4K V7Mz{5_qɇVߘ/{Y1kKQ``F/oŒ/HGGuT裏ڐd@Ła:,X όuG}tsby{mCr# t EWΓv/BZFmu3{2 ^YU[bw}Cz,qLNvpsvd((jHR|02Ή37tժ,hkƼYZL>NWPSX&"_b ip*skHC/27 @a珯RҒK C5g"CJ!Xa׉a9J C[dGþ:CJC,/3x~q"}嚐N:Ƿi0v>a5,L>VmK~'eKl:]$n8~ RwYOi2t)OK/ai1pUt%)c/J!,Ho G?HQ~'t pqʅ@1/80m\}urb8X.\@ 9oEֳ HS!!~A F\Fiv/W$[RHQ\K)'.1RH$ڄ 7,7?  G$L8@X!%! Etq~| !^r Aˏ~_IHP7)I-Ogdh6XaH\#]P 9]Mzi (X7(f)Ғ{HlGy!P rdT慘%!_VٟR+Q8^IrIgN'{byA" G|- [:)֬j{ E +}oi#bf~X/r#PC=_ZH !*1^nJϋ/{Ú.ͲijAd  5N2씖n"=J0/.73d{R~qq @3z^,O?d&=K0$zNyFR1{ѮዤGJ tu)>G?6Kr/ i @x4IDRrZ %GAPI}k8EB{q,F::^vlǗ! 9BfVe|B>B:>(%Ki' Sl 3SPVE* Q=}V^*k@KG1(׏8/1hʃQYYwu-S:O %sFߡCXO,#2!1t va@Hj\Q>%RhZ]+H#R-+h졯r ن(on#$e[ HkW8~qK,y/O<>z0f:'sf_ |)P#P"ގw~7Eh^qo@UKb@ޓ!}YTsdf-ߖN.#W:ﬥ#8M@ ;dwޱK,D ?P.Vv޽ JHk! _|qkbt-"FsKyBucIo#T %#G--`+b@\vipX"DO>c$7tSXgu‰'NGȇz(u]){С!?L6$J'Pmu p F@a)%S襂Oj&ѻ/U?[WA#P%# JJ1cX$lO.] 7`At\sͰF)\pA ,I;<-RCC==4|ps4a„"cZZ+PA9Q$8p`{Ӈ}hV04tNJH<Ԭ:W 1ScO#PzJb9zBs9r-g؆> @s1GomQσL:6lfY\W_}O8!mڴ K4Dڨ/K+O?#ynGp@I>> gE?#"dy_|#AfiMdmĉn֭[J!u#P$R b4P6yR|\Gh43fD-X ),Ƚ~G[r-c=>5jTp ];crt=CLsEKSiѯs8G%9E8?#tꩧ|V[m5k( Cb[ymH{W'9pAaÆٰٞ{N?tWWE^rDTCfVyf|72xk{ژN㎀#@oz=]zw)!%m'űhdz'OlZj,CäI$E S?V*o ,@{AG "w R,28M=#j/i5'€yϩ@rqGA5~#P&8կ)b0mL¡?VU8|QζGz(Q-w*j%dI bߔLK8@CprGB1"&ƝҝE <56p!~xyiGb5XFG=Q1 +sCůjW8glIw""䨈`zU@K H/^Vu S^th8.%@A1K>c"qɍSO^ >{Gȍ@fmnư[ѣG҃Xweˏ'6Z[B!Cg*䲜wI'e]6tݒղ|ɁH|[Rg~^zi@wm0xp0l}@@/HɑsTu<q|_WJzNyZWujEdh᪫ ^xaXi,#9~K1bRB W^y%2\2eJ曍<ácǎXƍzp]w:th8~VĴ}#:7Dh 6lMxy۸B O<17|av}TȘO~ RV!)Q3w8%_p<_;A NQJB^Dd$I#8"9X'3wx7K:!4+ ۴ic۳2Kuۚ5hV}}m%*6$X{LV _ 3O~eYZÚ-BD8v.@ .jK~=RU j;Hm/%P#8u"Pa5Z!M?®j[y&%?3ĉG6D׭F,Myf"D!M B~7|H3O?5X֗@% jEM RHr$#8u"P7[`r-HtM]w mQh۶m4f--(!7poc}O=T!$kov?2!mE*S3muz鐪wp"G8@3k mW_ Z8W '\sͰ{OXpо "Iܹ 뭱C $DwqA~J/G# b/߃҃rėo;ELh>9@ij }1f L4)^PLCeK/Y|=b&"Ά޺tg#(;)>S8MakV;)6^븟L#=+RsG(I&lpfof֤b^j̆{J/m薯W]FaK $GpCզk]vgP=V]uPS.U8F@/n~#0< 0@ ks.#L@Mc^,鰚yI,åU߅1S]%X ;^#0r4u:[ 'PN98 33͉Q}_U|[arNrX2g\M9CՏ\}-fKsN/еko?᭷rϨ>l[%Xf;[z!^'T觖@i{,' [m\ګ7nMRs+][UvSm5#O|ws@ْ|_! aÆ^x!]w]x-nȁ͛iYRr|jWjKZ+V%u/fjiһwHICL]IHjlkU.}Luu#=^ eғJi+`ıݻwK/t;3aֳXD9"),BZtv Δ+D& /CJN’K.nVOڐ2$%zŸ!L2ӭ]vO>K.*{cQ[,K]vE$'xVA &f4~!&, aUuF鶺wkNo8ga*ivf@]N˟՟ k,m%]Zx:NKjo-iFt)&fCA6.0mWLڵ^z )m%}Esqχ6t6)?2?zIs&%l` bG(Zo%'ON19ENdmQ4Yh-pU{پJh%,첉z뮻n8GV%"FVdh["d qEF|8;kuG\k ImIH{gZ2\+XAYgծG[L<䫯J4C&.[Rݷ~;-y2f̘Dw}NLj. {vҞҢ'UKH|ݠߡx܄ҋK&郤2J!FktT7{Zdm[fzV5#I.=UwһKϖ=l拉anzgyFNI{ꫯNz 4Q ǤUVAF'yWLpɵ^'Xr$1EN.ZHs9'S/Ozk#((E((lv"igI@h?B_G;gܸq<2*#Y%59}0Ki;6 9RPzߡx[ijSmO ˿OI!9 !BGKHf{mLϥa8m:_:htaiRFZQZ"-j?VZ,# ]@#HB<.#"Mf߾}3"?ױHEɎ={k4a„iK؈}a A 0,A_Pv bdfR^{0!ʇ ] G%2$q6WWwo&;2TC>>$I#TUj,#,)mC%Q{eòuVRMOKϫ@Kޖ2tU\٥hP].@()9—( ^@X!Hc|vH-_>hHد!)˯ːML;&PL:U(&uve#;:[ۢZI=PϮ^Wi¢0F[d)ҒW8w{B̢k*TstV'-r-kZgɾQ L%ٵ 1XlH뛓3ΐÇ>44g!5Q҄sb4lؾk!mI H }lXA +vYUL8,_OsyrF mE,6*kԊߥUDk,/=W+U'ҩjjZgh U:Aۓ9n{j>(֩ _kpN-!҉5~Yåe#PRO?mlufz衁!7L2ffaa6"0o89zO?=>;ۿdРAab ɇ)\yVqX(P !Gm_poo?`uPZkjfwѬK b)#;lk(&mA@/jͲBrZ-}'wcIҁFQ?ƪhUIsGU P![Lgal8ޥK# `!?m֦g' #k"=\8ͧmÇ~Ȫ+[Pia؍a2Hu צvN4);UNg>G۷uԪ7^l L/Su`m(HTϥҞX8@ DJDꃦ[8LVu+b#ճz{t-pS=o-u - #r(J ;(zp:LR ^k0km}w;6pYopG@/G0hgjE2@@:jmҥݙqu[8@db46]:zhw{? (6zBNnק]e􄦿_p* !G!r140K)C>F';>f=]50c }KVM#P1՞ V{%@S U/MLj:Kt%r]R+UGR(9"7h>K-=: 0 (٪e'=B/t_|Eۯf$c,l?SNAy8D&=E_1OJkM((Jdkq.x("aae BpF,"w,eOYbQ_V1b-tc@'VqW8Jw)?8H"򁇏7ߘ~AN/ꃜpNR@݆H;\nȐ!ACqt BwF)D~mƙ>7]^=eZ;Tgroi}wC)>H.#()9;wD@v}]#$茝. ?+2jԨ曭O<~ #F!LVSO!8{UdP0DVP k7*iGFNӖ .0+|,=픯O޽%nfAxV^y@>5f!{W` lf^fa6WMf;hVYeIL3vڰ_`+ ),RFIsjp&Kx B@TUx].D/8U@E!"|Ւ^N3e!I/?MǟPa?75LZ*\0_.]@@/@.+} DyaPjAnue}@rqf@Efw C0^^ 6YE'1V] G!PQ>G \OCS0c]C! B b1#TN+t6te pHTFs#PLJJ,1(a1ߨh*C=ӲpizzFKEZ5^z@S?r$f+C?p6RFEi;KwX-ƕ Q$GhF1^9>ӌVT2M w~zPNҎ#P]s5AXK"D[m>A Z83 ?ϯꪁs4XX$}S%5U5;8ޯhe{hm|@r%\bPbЯ_?Mm)C,h% 7xcX}-ѣÀ,J>}2-#˒#@ڈAR,.@-d=@;. p %!GYg@ET+kxG,oړO>np 7oF4hl\s53pX\uUvVZUg GL'#aQ 5#ѺUbo#ԍR,%b;iGi7i/)I8U]ms=۩tI2rٶ1Ş lʕ|ɉB"\[9I~Dd%3fSDDm[ѵ3o߾6-y䑉HP@rD֣䦛nJƎ(c"kyƎg}6Qk;@ٺVe- Y"2e~% "㏶}G$vXA()=d^T:31 y7K!3_N[wZˑ?᥸o6nPDf"%ᨣ kae]6`}bzǎ}ݗl׎G}dC}"3d0_m;uDlgni&/vwyvK҂ !6Cua;8@!'A^pV#Aa3VLDy:3Q%;ҐU_mX|I`I"O +`Y]w]sf?y0#ể 4p]@'xŠu9>|pۆ@A mB? F-[,Z@IDATXUsE@uIxv^kwF,h= K.%ae8J~B9JXЍ@phw 1|ٳ9F{շ^{e+ې9lXЃ>88]9ClV0(?p[B)V; q&ATպG›2^#4%eKEQ0Gю\Ffxbtt'#P 7h?=R pAbprbFw\U2\FW8@(˰Z{tG NIkkiWsF #B@#b"=3q8@q})I&TNZpj'4D~駆V5ĘSU`o#‰akYVu0G(9"#)AɱFڑK,^}U#.GC v+&R}'XHC?ӭzt"U21=L4Am"PUZC=#0e#Gӵ$cI{r.va`Őb692lu 6, = FD8o׎sZz?(27?\W8M@ZM"^tLBJ[/tDL'"/S%k^l;DȾcuᬳ$;n;[%A 7l@4W_=6da̖DAH4~YHe/ct#_NiBIP+׊BUW]#mXh,S>+K/duNą"/6qm7/Ҫz!Wl|k_߼N2,@.] ć,5L~,98bWĽ_sLa? G@d߁ҳd<›sJF 8%IW^yŚ"6lc@O 0pE]du|:~lg5e! 7?~|,\x쑠쇬H>裶馛% Q%Jr衇frNk׮N0K]v%sϭE许0ag}%y߈D}t獼t3 \p FvAz]~0׾|! "~Ť""9yH$FD? OJke+2,cC#P wytp58B`CT,%b;iG) zIwʿD/D/Dm^^/D^K(iժU"DD%ɂ354&QTmۖ'U$Od=mY q% ?D/aۯt!^lHYG{챉KՉ^VY>Y,r .`"_D'TK&O9(߉oDBYIv fof,Y*=I"+<@ܙ`++VZs9JdmYk&s,ԅy":|g1,'J.j" a"r7|"SH.:Рߎpoȷ-Xgal׳!!8DFُ?֚`!we5}ݗ>\k==dW@)k۴icDqma-|3cbbBɷ!#"g3cz5X#ZVc(zÔ^zigӆ~Ieu6%uaE'WסݴֱEi߾sa tѢm_:Ղ^Aҡfo#В( 9 0TI g75/ka4 u|Qd!4f(_bQg1Kƶ}A媏ǰ$QHVHL_qm; TP?֩_z4Xg "$s"l><_u2 c8AHmbhsF0'Vď^RR}v;-&S@-C 0QE;fjQYp @^x:7s]FZD d}bC?c)MZ&NhRIN8/^cȌ||pW9~iq d,- c!̖|k_ԋEPZrXN }{Ë R5PS_cT麺6j! 2#0%%G]w4cL4Jae"$dMbbbq Ic̫|効Q1:X;뎀#PlX2ZY|,0 A }G3b( 3*4 I'G pN$if#ЬpQ:3D-GDF@ZǘҲ ]o;@ FZ,F\OufjLriix7ܦוwX84ԯT(]-iY1ٛZ- tl[MR Zeo7bprԀbرaԩ3ӀG!PC"bZqْΞ)LeKxPf8y~JB jv除-$"6Ľ!NN Ho?ӹ[o=+O #23Ev <8XDw}c"Re9/s}<%қmP!~Qc?;1I4 EH3J"OZ^/"ݡP{o{("J xjե#Qn 8n&n&k)9#"ĭ"CI?%FJzDS-il$p4DѝDA.vi N'Qt[nuK͖Jc'Q46]wuv%PDQd1dӓ(A zKs-Q{KJyo<& Z~ʓ`+xYg41(/gз'B'!OAEIH(5O*݈<묳01HW_l,o.%,vDy,G&# 믿IڤuYǞk~ nl;j.a qF+g!_TJB>²[ZtDdMTgH+X\y`0!ÇD aĪ4Gb!FsHK*>Mڐ_]ao* }`kgUcgGo:+r<=H$k7|3fůo}N#}I"ΈARhiG #;[BK#|A@_}U6p@fzH HHKQ?C=2C/#|{G ~BX"#W}Q{'t=hϐ>'0rqHxD/dСf=af, wuMZmٳgT2rJ+2peohSN矷2 ڵHڌl׿e6e87uYG=Y*@{Hbh?xv49|)}MN1x4fK>Ls#!xW'G ZjF  %ku> oDbQ[Ǖ衑T~o'z*_ B%z@iQuJ*SrB\*8dl<#/P[ťݥ}G}ZE';ѰR"D9oBԡ?T+sY#kmү_?+͜Nqkt5{gb%:Kdk/2vMf>s?6V[mh8߶Enm[F ۺ\ 올$-D/qͶȌ+ >H^Duk&XYYr:Lڶmk3Kw9џM[i?"?DfRô,^|;f)KG0qMd/y饗%ke"gJmQLhE( k5h_ve68v:eElW>Ls#QHבvv'ź&#ƭ_nzBoX/Typ:9jAA[ti&H;&ˆ eٵm] I-ܒ(&ZfWz;#BȢhv YHxdݰ[cZf!uq 9mBvriC͟<Ž@@(&G^'d'ñcPi(H,aFV'#H$ Q+DRA Gۺ,dv s6MHMz"1}7YfyY%XA%k`ۗ&G34B5%%9N v.0Gp xΠqx-dcDP ^㐎=H%{J?PƬX C!C 1_M7ԶMO=hؒa5f"LM] ?1L[ٻҺu U}|j8GDV\qE~gxIZ:@ *2ʒdkKg8p&s /3EGH6. 䗡9O ;&!KχMD "6j +3´Vo` !,҂a8@S"K3ϛ:9 lĢ sΉ-!]tE6)gQ"AC6-&˖H q2B\4CRW@d Al@p F A?˵۫!Di_ ᪯;v _(S=cq3Bu嚌UGN=Td0~XE eF2½ɍTZ~U n.#P0_8*d H6/O,1Lg+dox` I ĉ7p!3Lw*LeeZm 5|>RB2xyٿHw3%Ž?^<~>p3)zHq8]k˵? }bԩ=bAZ5>՚aW]_c/l]Ǹ.ÃP+ižkbI5t։F_]RݎJi#.AW){.jb1) 2j#=z4˸9NX9IK"`"(G Gk4b!U"va6((hZI8qF!Y-xGTcqS'I8:_A0 \5 Tytʌt}fcP{@c$DܗmdrhJf=0Lc̚R%F~WS#$aܝ$ QD%$S@cd18byQp۷m(- wMBڰBEƴW,Pq&mNX6,9 ^4 / Rl3E@,w yzmnՅ@I,G,s>I0ǚ1ə$ !FdJQm=RQg>,3'똁Uچňva(HSRd[5`xUvc=qa>mL@!FhX&W4xR.-X ^f1q:L0CX$>=C;=}&(`oo 1GX .ځS ƵV D_b#ЄD2~uS7ᅽjGDcA~m@5~Js@ MXEiXmNL #ځ?抟D D /6ST!F5ERE] AWB06(^–~k'Af 1䇅&H}Ͼo;%D #/~ ~x=vi-3~E8K#8Y-_"Srz*$X\!X3ˈ=!vY܀0E8 3H oia4⛔sh#Ë1]<*q9ms>uG@ '>g˧M9u"ʺK F"!88G883,=ug*t[PC@7|pfVlq:); Yg mQ'X^vys՘ ?N._MsT8dBJJ/ c4rRʅK䎙=[z$Z554G gM(r8EQ}| 9.;`2#P'd I99 -TJ]*ljĬщQ8!)8t}#P&~pq@z_-'͊148/T F85p}Xwroo#P"_@%_!ihpNZtʍ@|~}G HXpհZ .@%")x鰞և-*jymD)Ñ <$ǵZ;bc6 s2"!@ML!?믿I'dw8~r|d"A[oev'C9eNG(5hˇk1#:t?F}ʽi]}M@3 ]w%j=-+SBX#Ͼ/LD:thxo dFM}%"25(KG(xP^4ev U(QvjT!<@Xs53i8N9OE,IQcǎ|oGuE&?o Hf[n}GDR~D }Vb;M%@ %TH#A+죴o~9@@-:-1/hQ!FYftQ_w"8S-T9u#}Y#nђfr$e38FH%uXHѭ[L9VO'8/o8%E"_8_>%m_L߯`Cl |aԨQa 74C4 ӳ>kNٍ%+}&!7pC449.#PfE\Z|N C#AbBegs;7%9%D^:6tƬ6gtP6l%fs=駟n3u9氍ґGitْŦ#^6))~ Q{4@6S*&,`X{ I %b|MX`j}Gx饗ꫯph ~ZHF}GĤ>EJVD@aKR϶vZ(7j)w#B얣;d͖f-C8M"zp\" DuV$\* }z&UTC1C Kw&~F;w馛J^#4^@/T8MȉQ[]W娱-z|G(:9{@D?W@!G|&!iB+Lc_VZr)/T#Voy"?i7Ϟz@E;ΦsիwY?7KfN*հt^p别^`xDkQ\}{I%Cvk)PRi?WZJОxNյ~lkQ|$I,]Z0M{? "ٔ/^:;r AqH#24 ZR"csHP$GS{rG]Z0%feqK3?6ӌ\jo}3ʔ)S,ZH䴽zYm{;f^p'lց$Qnpwf]mn/:\XKH]ua]v\poqx'>Hˬ:08s3O$]uUu]*GMH F DRͻokG.R- c/7brFV]Z2%?>y cƌ vXg}vi0rȰJ+N8!/<<0@ RZtM|`yԎ>pYgY6ђx믿ޢf_xrGqa5$_ۈɹ:M%!~%xW,7,z-Kr׆Gy$|Ga]w5F}p4hP{9T#7/c1 ):A6ըdt&.Ҷ#/H[prq/r ^1=-HG#}/<3L:5q6Bv]d#W׆iw!t0b+Z8DA駟Ē矷("R@?7`#v!pO%/4C"8>M"#+s˥,A~"J{]Z0%%G /pj6Xa#}F* QT6]+$ /rɓטԧz*`ku&nFηZ*SU73϶v0n8B;0,Zk/qļs1GB#PM[WGdxT/Ͽx91Br4 dX-pVm"e|((oQ)Z3!Iܛ#ҥ(Ӡ/k@_?4_$R@8`MjݺuxÐ!C,)K,np뭷ZϨ[n]vmL'IfEW7S.c!@Y8e +ՓO>iCXҰ5ExV_:eD Mh/c1B#QM"#뚪|*܇w AG)҂()9ʅ[niNʟ|Iرc5j%yc༼"ÇC5b bfĈ,͉ԍ5Yd[{mXaI;0!\Hݤ5yg5\pz„ Fێ@3@ Hx؎xA"9L,U&B`]N-u8P)NY)V 1r|ַ#|6pCQƬfUGf +{9ptyUVY{o+Vl![u׵vۅ7|fA 48#om+ZkV[m0ppgE ;^Dfh"/&^@(.Ij"yV!Ŝw񙴗塀 Ae/c;?Z.44Dd?9tc !I&I7oٌ/8|fyb gnǬj֤{Ϧyu\X ۅgRysE )΋^:$DE +®'-qQ^fٱK/1ʉyJ,rw5iעbAE|UBiM%?/41ekzw<ǭ#?z*=ϸ?9mEs?hFgy!|` Vh+%c}<.#\rR±#- 9zgh0,4LF3?!cfSEY$0@W: 9 } ;Sf<\~dgL.!hnKB$ %~arc7aM `EiVSO=u⋍PC08#V C*u::u!G 49@XBlBؐjw}gپBoF:"asP4,Fj ",+p\!k*3 lsAh*qʞR*ĉ->[ҒAİrqGpA|+\w2m_oARd']{7׿첋 1$zf Y[kae! -$`?a/4/3ˆ(.i}0Lqm5bM[ZA4]UJJ'NAl!{޺}*;#d[RtFB!wfr)>ol=,ejE ixo!Cs1tg9<4WlMK`:p;뮍f (Os3צ4<u/P;NP^ #2.@WD@ CX*ٗ>SIv NZF/#nAߎW+:Xо~5Gp:{ƍmZp [}U >\VGӐVs/pou[kw[ktW8cuqdI[P쌒bE7v>GpGBtrhD:p6Ƭr t1GpGtaJ#l6p! 6?S|Kwy1EB gO<9_rWs9p"C8CotPȹ瞛?-\tEbIZ"x &wo0jԨp69w8#8@ Pa5H"=p w5cC)! +P 6lXU!s1G@l 0pTk!.^!J0͚kiCmx&n^G;\pv?6do&vmGpG?uqk /!]ic4^v{1c,6e䣔Yf b@~>AY.#Af[+Auqtz ?lw߶ 1|0h6#3Ԛ%"5@hxص )=PsYˆaҤIf7 [8* .bdz<[#I;3 #8 +.*h+>2~EݩB^#PBЪ`̐R]/6|v' 6b-hc ~kq.̲C`vN.TYr-1DȌ:l^~e3ΞAV[med:`=sQ:CzDXppBS#FX0mfI0LAODzao6L\0ÛniaϗA䭵ZĤv}UWk뭷IMs>o;uEG-IRi:ٕz(-GiK%ټHs_}('M2O0k[!t쌢^v+\W^O?E4U7!ۡȹuW_E9gVE50}c!sҚJPMS5;~7vtw,vP(R(czQ%}Qo'3;#c)ZL$f[~s"XQ*YzH{.S(;+T;3Pj4i6, <̶#L16,u6L5Tona$i;-gm@ Cz }pB4LcvF >묳a nMΗK4QC)EŦ ꫯD%}teX;kũ08@ ɗ]\`gaoXzSv,M G#!ЮJ9($qG܍`V!5sCO8&@Ika{f#SDC`dŮ(IV[m5_p /c̶Q4Jͤ4Gs)\ױ\'sJ7|cjߒ#4<U4aRJWB;\AchRQ[jܐ`"rgLY,!Ef:0WX"Լs"'.G9mXqlbW2dH6Hf ^tGpdGpx% rĈ"FOt$ڍUJd/ 5[l>?8#8#f<'cE5>@K4޳5bɸ5`>} wa@{՗\rsꩧ ><%GpG P7rկ~e~8>D_~6Li,+Ǎ8!Ætrke$lg?4%uqKGpGpuFn2HG 9JGuTPCΌU_XdEćP^ F-EaY|p R:8jՙ+p*D",D(oʹ|ðH{CG4I A k뭷6ǐB"$ ZO=.1ݒ}{63#IGpVG`J\K6@njٺ! SN9e8蠃u`M0Z" [mc+t뭷ڹC?\si[o=%6/<r!|]tQ8q#l N>|8#кܦh"4Gm([ۈs?d]_s5 _~W_YA넶) ׀`_ y;N;Te" $a;GpA@Fc.kҽTGuhrDj"IJKL;?P$#_|'=fĎ<0y-p8#8@AzR'hd5J7pC駟n馐Ruf 6mM75[%!I;suY-߂ .^ziۇѸ#8#to!?vXaB -dZ Ӳ.k,F]tѰ +Xoݲ`=Z*~[Tƈ#& [58#Zh?=5vQk8m@pNW;ܫcFÒ;0OS S;hw +A9A^pNw|>fqݾ8#8m@_<ꫯ8i9Lc=®Zk~; WSO=ua?+MVr7o8eWp0{"–yu=kHKI8j$Gnqv kvnο^{y7g =#رc~g>w3 m-ȒK.Fi.9,ؾc=T i]fig`*MSgڨVE ,.#3Z_^}U#ETG1bCB B~2{޴4  Wp@>p)X9=1{ !ێ@QI-i%ȑ9E1g 6e)?;ru!GhCV[m5zꩧ,,AIo$%AsYllq4hPiLG[C$^m4B"H!GN'lܷ~;,2,|; %IVUx≀ u.ߦ_J,!B8"B?~|g}~9QI bDU] A"G 1olXi FtlWu5BB[~Ä `l֦hJ}Q8CXYy>-?;S )a&?%i`{oPt߾}ۜC 4Dyț3<]"r 1|χL1y: N-]'/a^l/a!ݻt/jhhLhHV3TSN{奣f2+Wi[Z&nƏ;%&C`2;Klkl+w_3kX|MfҤ\4'փv-aI=akJ{`ʳђm"|+P'ꆉƎ;h)GZfߗjy77]♢8 ŰR3ԣp0JoڰGp?CL0>CC5Cj?ld)UB[iӟTx^NVYe3^6 ?2K ό329YZ}b9cCM K^|Í8fڡziҸ@kƴp,f-Rf{18 IRX 34;T` OY@ǽ%P^BB@{7 hn;`HQ`&TKgkMԃcSOn**_ݾ!QYI9\dGȳfٳ l`^Ku2dHxm~<޿jkI=2סߐj"G`pTtANKDPb̩ҖJ*h'Mu԰YQjt/R~|#%’rTYdEQ$ GdSXWv]jEC5/[}Jkt ࠙jQ%;jCX  k*VblJSԪߛpDウhNTZE pFE5Q[[,l m[޶돚xPxˌ`ǤrWXa(qܸqQ(9>>Q#-V9gx1D?54fhC9a[V(7ъEjeq-e͜}w:`qmb~SaӼ}$JSnyiEN:?Q Z([èEixf~ިfF~r^kuk4Qavmg>!"Kih=?3"uSPg53&jm_xQx? D"64N+\$>oDh{y>D ϜQD;J5a{5.X ?[ٻFM29H+e"DL>_<ҶEiX-P πҊJ)ͧD[ GZTVW}B.X59>=#e,J,R&KȨop 1ǘ(>`>{wl |>j#gajBm!ܥ^:r=( pĈQ9>6jȗa !#-q5ְrS)rH䈏1y󱠮)d/5d5בr1iN5TS\I[Ǻ4Q^6b:Rcn|)s6pv@}s}QGiLr\4d./!{,#R/\LٚlKD4 \"/r4lE #Szi"GzH׆AZY0Kb 8$sK)\vW.Td_oyyeZcX{ίf fJZJ;:xN:!J8@ li!_ҔgG҅2ZӠ#5j( 3[cںMM@!IsapN4,ae?rkW>)+ipYrQ7r+FC8QQQ ɀ$Wfv-kE>#@,9=#\m։M;)Es!<~ U6:= D2H9KHixҚ$Çv~CP"G` FkaNDI3vـq d"hj϶eayyȓ#$O L9?8D@hrQ[/?ԏgr$=HFzdcdь!vTpZ.KLJӨA]G"}6%#fi{>DG-j#-MhҦ-3~f; 87)-)la&m Df1bxiH̫=.Q;G!1*v5@gED'ipՁ3W7yO؊H>4nK;ވH3chسm!WɳA=6)Fĥ Ki`rxC_M1MqE+yZ}RoG4A|i]Hp#Ķ8OkH+rbTeMN]G"@#C9J Nɻ/&=X6VIqJÚ䤔K"$q<3jWd#/LࣇUi" B =zS SLIcM&+$4R&&Z?JiSH#39:d0+yLeK?u! g%G5zJ} 5TW(Hk>*v:w%ehNj>8ޮe hOH ovk\ hXHCzV!iLφzhykHOFƲ٥2 0+ YV̚y"Y2R^ Z+ZRm oYzxOD+Wzd-_*/-!L$7Z$܍!Mڥ1J h֣U<-- s & CvX?MlbĹDϏh XNҳQsTjߗro,y=`T drshɷce6y@kI j*=@A[2o酘Q =6+Qt3mh\x顴:J[)5y톆k옜[~[1Rv_VW`|$ i$l[%0غL/}Hm3%hM306!MC~ ٶ>f>6"C of'5`w-r̔c[dS_};NʇOHJN=0 ;lz| v5>/Q.}P.*6+yIaa;3?!0[ #}LͶ*ks1쑒;&3 Els 5\g"vDc`/%^G1~>fGej^zFBbP=3΃ޝQMG?a5t$aR(e녑3q%Q-1f=+lCh i+҇אJӬpNR*r)!4bG<-CsQl>c<7p.VVvQnW}ɯK9e-[@#`}lsUGk^c9ZBE(TN t:Q4mw7Hƭz1HE*ͨ1^Q^Pe+j}x}L8#G6b43F0^$ s= `:dCct80׼`l# =~3zV / ,Tٳg{S_:]L=.rk~#Ѕ6} 0j>Dyew3}. 3hQԬ $ Sk~C3.&ڲ޲e[ oz3;?Ws~2}#ЉHmCvI8@GF6+iFjuXMDHraA#"r4 4eV3 ;oĆea=hZi4=b#<%Li Q>>P\n@V{zJ6G"4F-jjF;L`TgQb/ ^/}pۏA4CgYaL1$%{ d!-l(0lyxp U:s%_> 'p^4]%,1Rg<$MԽn78ŏ8∊{FG#EUsw΃@bfrTab`.Ҁ$fe,G#Aq|Gp:*QDҲMsԧO J0W|%x)xF^{,6 =쳶yGy$1"qV~*&GAlq(yi|}W\~=X =9Hrq)bA':36+SYHn~<\|_{ 5Dh뭷x^~ .袋l{b1}a4o߾GiZ?ek =_|AjIp Lu}[o|&/lr2t9IZ~H8+#D;ᵧVBjVcO>G(m?#d&9v|Xx-]}=uʃ7j4ȰaÌFn$ /EDB>;x`2s=66鬳2tA!CX~_}U ɋ/( wRo+ ÉhJA>"Cꦉֵ\G!@CmIb?)uZԕ-"Z CٕVZ6ƒWj4: r5|B+h_|q#F) ?s;k$ohRl6l3DhYgm-KG z_R#!=5"4@4D#F9.#&mRASmJD:+9Bv[ 7n\hl axav*-Pdw9L1,n d}S1"\ '4N 8FvFRڌD39k#DhAJh輑_k9!CT0rH):쳍#y睁@zAfo?3Ft'6JT'LaMZBxV[m5&K˷z+l6F>||И@RAJ!MO r)-q@pq6E K,ZjAJOx≰KY:= 1mV0oݐ,첁d9眍PVS Cr;8X{ihK˾{osBSuI'1w#ХH M_GpZDtf%D6 <]?E,!"tJ3)s)5=Ӛĉm(0 7IJ@g>0[!(&}]^({{]V>P;-B;4]J_(}4A -c3钢{GD=O;2 %#8m@A~XAb=%gjSwr.@D#%,!,1bpBɦ%bI"-ka%#tticA(@tR4uG M]ʶQq,嫺FuU]3?hg(A/ V($KڗR:͗#5$iצW39樭QGhh\"%".¶#8DZD7襗^!Lo/yw7l3f8mScb8$9#t\!FǑ8#8 #lviT+&_|M_r%IdʳⱭnG ,@8p`G7y~GvM_q--#<2;NnVΚkڰ뮻6?_~]O} ]n'p^mwqGpNH$VqoJ(QR -|#~M7x#^qf"QZ`W<[G "QѢG(gQ>_~("/rW:7TSEi/䒨@r(iK* |s sI`t?1g>u1Ȗ6Ƃ4[3Yfxm-{w-駟n~ Q:BCZ@ro{md+\(BlˆD~QUa]/FzƎ!Wɾ8#8Yf%@`aAOp ACc,c)ʛHɚ=?#63 bԿǷfFɴI̠SXfellwe]C?pa*/K,H<4h_(}4A D=m6]Gp u%GK/Ԇj[H+dN@9N70^Q'⎀#T@] RذXQã:*L?^@ң ipG _2 UOJo(a$ҏJcRzXki8#EAvo{"n)Ai J*mH8s(͢}.#8NC^z%RN; ~RN _yPIÇ>ڊ{B*ⷕ͔;a߬?84C ] ZΡ4DcJEWD8#tB: 9bxlAEl +ƌa2$?Hq۬@ y oȅGm e[%;餓bkS&2V*v9f)tRYOi9%\Gp:!u#Gna>#裏CZH.I;a6SQHf r1bD Fmds-(VZ:Ֆ~rMJˣ`iw^#^{HV(owo ;[6Sgi%L' KCEhj%m.%^\~?8#190I9s#g w}>36kwa?[7iW[n9Zು!76C ci{c:s=VC Qxq:>{B9 l^Pw^W)wU8"FGp:6u#Gp!6vqG {Ǜ'jbAl*@ia׶$xNdXxF7 6 \tE1ܠB(8wiR~_vYS3hQc6^8#С+9Z` 1fqF& C_D' aHzꩴdPN#m痃 2, !K. ߭ъҮ"FՊL8#Щ+9"nY%ec믿BIPZR⋇O>p8sɇhӺ5%bWzVo;#t^*c+u?b0i[5[oՌ;3^c&In]M$!O-e"mZh0X?)[EK oBޛn)|m_3 F)mZ8#tr:9(%zd)/{7î?dCu.h'٥d]v ƍ y*o2l3[t5waRŖ܏ |%p|ZGiq%BBNOi stqG$|j%a<4Fs*5 ij0zf+y.6J'N4 ²l&LP4Ci7KP̬CD)fo&OR`E& AzP_>o;#t|ZqvÙ$Fm%}Y߿j^nFJUBo: Bo A:_jpG!j2İ`s)ݤqkt@VRk JVQ'5fc1=:ڥLrGhoZKs}Hfހts uv:j=7~gsEWi}p%'⻽o]vYwK@ݞJɔ;2J9A .#tpZBmpw\w}ACciȐ!o9[ _I?iEOЧO3fZ?Q?oN*aCq%bjƢPQ(KQ>.Aq9gyf9{GiҼDEkV-˶.Q|E"Dwumţ:*mϤ(QCuv]G(OW^WR){u\rɨ7|o믿/4>|H㫯ju*B/),F ExDqm"Eqvñ~ſvm8=ܸ2}f(jڽmC_B9^ @h8Hql])#+fp@,)%(^s5QV?) GVҞE946lH',ddMY0\veMs*#Rg rD >8cMHҩF2%'HUK3@=֚Z~-CNxƞa}ukRb' v;"iG K/4ވ-Z f^x!HT=\x,+HB#F-԰_ ChȈ %'Ck쁨#TI>xӦ-+ɗ'1HBғ*虑7Yd& =S|A`(3 .U!MB3V{={.ڗl(ɳ:#ERG#}H u&AW!0UeY:o/>iy-lgW 3s1GvcwtiY .:j}ASYIuˮSg4GOޔlT 곸r~ zMi.HCUC&)@&r7?:%༒YrR'H%_ƺ]/ YSbV) iY#/ۨ4dc4JC;o1fFfi(HmDE˔^ŀ[CHF,t75A^BF 8h_yz4+Bl6;~4Z+ -($1c}UχUW]5G==IyMe$R26yӁjzްH7JhZD ,SjAZQ$Nbԓcў|ezf9nxyd=."Zi4LFV?0| +q,6"4> O1# aQwuWif;KlAF݁a*`֛ w fK/` 5tIaРAMہ&k\k@ddB~B0 T|ٴ[fgϞG̚:BCưbfp]vx˅l.åbxIge KClWh}KZrhhFNګz:^U4GMH&RҳۓZ 3dOcNCf:]>DV' rGGa3E$i a DK^D֡Gv ( yA#H>pU>om1hpd<4Q64c "5:I6Ka20lF]Rr>dzB\*C@8*+%ԝh|Hiyl:ө4D:Aj1M DXZ8#&Db!Q9aG2Rr}Mcp_WsЗK$r'b9A9Wbrj$&C>V;f*EDRǎtz+&*%?=W8E3ի^w ^voOJ2].;25t M Ϭ{ mRn}!hbr[kuBg!R u#Gx~碋. Oj*ܝ}N OMо^U<9bj)ZﺉلƜ٩6W#var+ϋڵlNτ&=a5gUS2O95xMLx!$uZ]F 4l\e#VB m HAj%\UL"GyLD]WQ1zh]zuEH*Z9n8SDRfvzaAGE*9:<#̷]x\'diUuF#<5zwtttη5Hxn"̐E3rF X@IDAT_aF3Z&&g^{ůBCf,M="?M->YGl3!!\v0؍#G [d& I#LWf|)L~ns I1( dH~زq--ސ!Cl.>DaAL_sYm2|f G 59R w^ZaPZFҖJ*駟.|X|#"xPZS!N'\=)TxMN|ݨ4eyc1J{*+ou%XџE}m;'"6$5Q3}-#aq ٺQ /V4>vm]krmIRƉ'58E+57jolIQIrH+OQַnڽrM f઴ҲJQhGڼ]i{XMEzCB%IJEoi/Bӄ#<2;#^=3f1ݝZOILOB&;#Pc_csKms#YGD+MQW=c?Y$@OC緳CkK03'7-\eUZ&I hСi-q|qk c?Cq\K./J8Gh7aÆO='XX&G}iUhÄ:gwiu BI;VHw("!TMKj_|JFCT S7Ra\ȋ kH3vmŸi,hXFC<7|憹.uG ~G 2*+6b,9A-"m-!C7lLE M)c~@#:p$$%t1x=C-'!_6bP76lF4yK\Z +`DOMrm1kƍ3g80IJ"eZa7C ˥ |-:]̺#Kb #H rƢ^azi+ D Q>n܌Ch}]wuiAυ1qG##>K 1}kjhhGُG)tpMgJ~h 9hUnqCl^HN`;&ŕlOdCg[5?[@"-$xAgN?tk!G&3ΰK)wҺg#m3sMJ:K* 9 izqx 8)<=2ˠ_ Ah4 = 5 S2E;q1dg=a11:]tmv44K E+v~ҹhdiڜy ]{t؏}mT !hXQw '|20 /i aڀTfD94wyᬳ2"8 RPof3Nfhx cΈe":)1k2E Ҡ0ܖRq?~|0/::*$M S!88s'HWQِs=:`4 5aAt+>XaN@Dh; 3fA >8LZ"ΧpQ)Jeq.*Qg7qJN|GLd) pU?nOh\Zhsè%^QU<[zit5ݕtƌ556cDXD ٺFQLD QT*fZ}ʋ̔Hf!I|EgTfREMՉJL]*0C$!K(aPevcٮ6Km^2/(uYe+k*.WԨ@A̗ۿ 4Him%fc.4R]fת&E۫κ&Z"2bE1lIi_,qB{I'c=s9v-| 7-.@]'ezv:9ׄrs3c#DwƉ#@FmAshFN Q0ϷD{ G#\җ3ƲdͧCˏuWDVY* 1Ce2|4H{%?0|PIG8Bddoф;Zk?ph3?#!-S[@!crmByćdM85 ?˔j({!` ~66OBC9bS#!\G1 i;_I 䗣 k:>jI 2%\aw ;kFVt SZF[e>;h:2YeNCZFb s#5qpK/"C@.# F|,u9tәƈa|+`V~V\qŴFm$)KӒ vaiWaI.@oz@xzefh!B c443i9L3 ~1Jy|86Nb }t~$mQp'vZ{lF4aW4/ш$@K% TfCڤq_w*@aubx'$Yp&"SXI[D1 nQs8@ AvPRw'H2%6zBa<=i$apX1!+fUCyVN @SL/҂; HĨBB5'zU͝G8 iGTnAJm^|᳥Z*暦(/DGDL[.%'Lf=>G$ԝ5|Hk*۵I #Jsˋ5H=lr+zmڛCHπYgeq g^{YF2 R1]# v+=HNu y7îکu aiOG6j#X SO=h.ڔ|>v΅@Aհ2#ϙfQ]i.kvB'㴶ܝpRbj<1@6ڹDErJwu sjfJ)ͩt{K*ncB%G* ՖJ4LU2.䨹@Khhl9AAuIi6!G]0N:ZB9!TKt ]玿E#NZ I/d4$|ktc;＀)A^w!C5&;mo8eprT?H8ut=A&ǥ!?K)/ęK.#ztr_:|)n\*i|0VRGøg}@4=uڛJh=A;6C\pA#&uB}4,A>f:^4[PZ"\uUddkV &L}}묳Nx,Pn-ӧOb-l?KfsZh;X?-q=\sıRINtrTF643)Ksq i/J 1[ qzpgX4Ύ92g}@\.fm_oDkXyÕW^iă.BA_5X` W_}e;4oۇz\qߒ,Fp{[v[L^x 7/&n%dHmG; !."z1L, b-fnӋrZ'|rOȘf\oQ1!FQiĸ֣>j򽺝w޹Ֆ)DNLcƌJrxwAw?馛E]40rI^{@zC~ $.#P  io7%غ%A"ȺkK,aڥk& {94B&_hZk Oc?Bxי_n!@v{|h WZC 71 m;&ڭQFY5묳n]V%\~6duG; !.ԈLMjz34Fc9 ABnFSc꫍.(\zSN SN9e)*һks$-apOǰjl#v{ :*r7n\8#ٳq6GMBܯ_?KNvaDM]Z I H)A'PyKbB<؆K2s5lLfşw z"$($Dۑh cthHB5⋍>mG#0k% "y|{Bhtgk8М#aeRZ뮻zD qeh E샴ƆP$qx3. #EP/ѫB4b;4 1>g#T=3ґnzE 4h4OTv*; u'),3fCKuz$SBہF)eFNfmV[m5k7h𾍽Pj؇$ZNifڷlYoS{sFV>}.EsD)Fś$gf ҁz;opeH%!رc  /B$Lf{ui0A0<*THs&%3ؐi 8@vKLv Ie؆8*EIp:l蜡]f?cG A*'}ch!5W^ֹӄ=|-/c 14iii,uhVSlytUBȐ ŤT+^+z=4"YB3l0#*hRobC?~ii9JCz`\ 1a 3 KiީqasNK½v^>##S6@@}U,+9%DP4!:H, a@8N[@gC4"q>}?DH݂䅶f40EٺBQѳ ҶDޕ'zOQZ4;Gd"ʀP4TQ*F%HԐ]T#(#ǥƶRG EEr!jT([+;[n5\gI^kn[VT#kzJk*VB9HЕjzw:yߑJ5_uF3ҬJWWTV6j}DZ`;4e7e6 2GY^iMS!EgYiZJ|wzJծ۴Wquiw}8^vH$tI?\!,1F\i,_AhF=91 gЛ/̮h]&[Jq>S!J` .=Yz8/t/6E@X1 A2`6/. mKK#4htfU" 1G0 `G^0 RM}#Еtg)bvHv8ϲ a\I#B{3/^5PrKuaJVl T)_(}4A gw+&gPZOp3#z6ygVB#^#hhwRj&khKt:r-yGuhhl.giJX|;6U_'G_ 6 핓VS ={1#D(1Ćƥ #=@gEQgގ@;" t.C"H}v_3:-9-w/(+M` 0|pb/#|̊op]NogBUwng +VX3]D wZBl:KPN%VOL:)]~#ОtZr1k5*_(c8,1gE9;kO׮7?K.!D"<#LpB%JŇd2H&!oG#BF\\t= цҞ2Yzh A,H_9'΂ZU >Tڹ >AUݖ'H5K(f\THp:UHN\S6M7|s|oZg&qOrh _g"(QD"mњ_!i_?>DysUė(l*R?{E֏46xY[GyҶDCifpIQ$(RnVD>v-=WQ3ǛPF :qFf(*FX#y~?;E7r^PT#D&gD^Ěucƌn8rȨvq>IÖ8+nT/2ʟRt'QycFA|D38bOJn'pB1f1R=S&5fx:֘r4l4RG!r;O9&p-<2%պ58Ӥ>IcƜ^]j89!/J*vGIOd$ dJAGlGL.I4bv>R{wDk2?8I{;y6aW6M"Q+;bXM2 +@Bk/F{JAVǼÆnh?|S 瑌5U0Mz衶0$i|=]GAG\pAPCg qFU.aԨQ{Ѳ`{w`hT>@eOyebP!jT9Hf)/\X=HjzNWm 0dXD~Ꙃˍ+ bL:'59ðKF@Bn%*h- CL*3G"mG]Kb6ߑ: >'#fU,VTFZ61+#K/qghZh|G'G`6 襽и9+w lcv 7X gL嘲?~1&[0ɘ -K$al!b& bXc'Ś HX3 FOׯ_w{|>ku֯o瞣%) ȇ_b-9 ٳg6#a^RXmxCfKD[lF;S5G܃>X qڍ@hLG@ Di%Ae mK9%`?Cp>B ]ZCEIbaf'\f̘ښF $'uvG?|JGl'j= RF^fP^-d +b$04{ p}MJj05&vI% V}2h3b<_7dy%HhUHl:AA)7Un\EC}bf Ki](_I'Zێ@U#/'MW `D̢"<3#M: I#"䈙Bx R>z,w`(jL ʓ, qf@Yʣm&ձnc(@H 6 qib6FL׍Pz|b`Lu֌$=i"!Nd[J$ڬYlȰa(ug㈺='ƤR#l &_Ǹ?l5e"|-cKI͸{I%eh#I$5}%T!m2T|iǘa5fҎ"Bb}sm_V7˒|Zڙ+(2L3`U^ ƻZ!Y>K.=ϱ40ĐIhhFdRghxoP܊1uWZ4ca߀]\6;C2O5Mfe~]oyYA-.Q{EfR 26hԩjMOÊeUG1D`ET.]kNŇiǰ ݴm vS+\B g!AF2P;21bzΣf j(v{BҗfI/yvnl!@#)ooI nsNȵ(ֺ$f,&pqL{33i,@Vk.3%cQŇ~XmZ.'H8#`!/C [}g;}H B 1BMi̋ϫ8! #4ر0qUԗM#iϵ̓ GQrsێ#PC s$4Hsw\ͅF䢋.Rm r S=OhxXn@htg~ie͇}<0G(T#BX'qn=0M iPC2OJyݦDžcr58@YAXNxZn?,tDc3ڝ\!~cbל|9f~~ҚGpa6\smGhrD{L*L^ wDŽeG#dA1KU1"@߫WOV#EEr/GyA!%\$$G"&!E>v\hi`a5׌nml/>ƛS؇_~yç#P7.' @蝉UA@WwDE,^P#^fgD2"l- )2c=2eJ$"-HZd/.ؑ vs$n[viN;-"uPًJM!{,abr4lY?i$1KʘGRIa&i#I$IĮ`!2lMR<'ϵݒn %mHI͟t_}UeĐ<+$7+gɝ{{U-9SP0d:荕" ;#6[!)$10u h\Ge$1Q,W}g`йylq3_ZIl,Cd?G`&i VDn'i!I`KHrVcZS|)Y^uA?jw9Bҗ4[$*˳\D@R6YΥ $m=hڪE$Wj[%TD ĥ]; tfЭ[%L{gppEj5l4@% nRipDsWk58rmG"d0WhldMy= )x9 'KLڕ朜r~*QBd+'G@*XbуC{%<Ϛz+}y\eV_pJ#-#FxA;Z$I ~535s.-QҤcNJ~ҤIcǎ3=#PTYϚd1}rc>\8jh $Ͱ-%4c$ %B3֪K5]>}89umuKi>|H0V&H i1rr$ 4SK[Ҍf!>~+j[$K9w^v4B!H̍: \>|xW A'nW]uàAX8jCUG̸%3ͦN'pIF[7ppwqs?G}4A\?PL̲#"ĵ$t>!o%⺭>͎#P4=o>$z$>.V6>:qr$ 4Sƭ!.IJ)ɇy2C=C}Y坎$F9S ri5Bxf6VQģ=(@𘏓Y Axw}W|_u%:W^yu]0G8z})$6h# =ydFx&,Nh.!x6 )L5jT AwRBGbJ>Corh)G0S}p/|\\>6|\"qn$ 4CȹJ" %#|BL{lkuie\AJUP#G lm#5뮻.&B@OD4SO"bۏDG⦡"0v.]+N%^zDJ^xa,Bӟd/%BIj8B3!C˄f H,y$6I[pH󸑏ȔJ$ Zk-%F-q Hp뭷jX/R $%i?v>O$d}GuTXgu4lf|%Ƥj0&,+ aK*'+bؔJڈP0m45ԩS+4Gp\Wsj f#> AY$Ȱ"9APJtJ$DžaNr)iXe|w.)C Cx6io.o[EDž^~b(h_|q{lJpЬtIjɷm  bx!*%A:쌸|`H_k)!'YfFY!mwQgAvP`C(&G(;|H A@%9)VPɎ؄qIh%M#'H$\5 c吶+: IMdXDI՘V@Dڶ][P & /Йmqw\aBcx~b`ٳ5vn}9P\Kfpe^AjxL!G#Y$!mF#$-guc7HZKR~zPV#A2itqJ?aPLT29Jz _pr XkְZGz_3~!*:5b9sjF삪jҰx$Gg9egt IKZ,}Թ/uy5$H94uNT9~e\s+ ;H Dz+Ȏ]8H.#P;|lI7N}~.^P}?rqF5G-_pZrQlnrS z뭧qNcV4bbw7߬N?tko")?zR>6N(CF"8_ + Cwx}5-.A+6L]ɤX_:@ >W_V}Ϭz?{V_`}$$f(c= ~h&E01z"!'HP$޲v!:3# Y$^_=_2$N[od/*"](oH/F6g<$G$vzކn{HE6zgW_=璑xю 1s8LQVWeI;KTҚVAo} 5.#P7`{bI5ic\%/zhݻn 1Q#b۷d@CBq0T綾^:kNVs9m6r饗HֹE]n=ю;!uH$lhFqF89jpGvNw>hhDS]ws=?|?pW6CfeguV;v%& 3 ޲#M>]ɓ%(hEބlf_qQ8|pw _ve>=%ψbϹ l\@?1:&TN 4۟,t?I~G r$cd;~%ue ![3u{?$[ɇW'Of?SFD"laTMWO={pxmbˤYz'h}GÐZ&>|W~;G@ĦeHT!`DV ,-Z)q=sY xO J*+wCY :b{$ΡSNJrX?] zjڵkk{9sf8Ct>o, 6Bof- 1[ ?H$w)ۅ'$?9 <[IIy$>v,Ag$njukn/"GهKYb:K2gL{HZLa%"`;qt\/t)I|a4tno6zŨF~^<2SM3`-;&Oh 0v~&if&͖%*-l&\~A u(!B[4KR=_$OdI'HXy%GWm"䨲ґF12uD}wZ$Sx+!D`Xj! *QfZˈ}yw Hil#8#Phf&qbM -&aae=tISa&{ogn:w_v+x~/ V93[?N8aDxOLP,5U#Ti21>d|ب ʨRRKu nERNRo=N0H 9#_|f͚@O>퇸tM̌3N;0T4dȐ,9&8 |:`4i6aj.48y:thXeUK;>|xlm0k҃@(^Ct`6lp7| B.]C{ ׵oR:C%G.UAս#8AMCZnj?ERwIR͆2|_d[8Jdl$~At?M@EECo Oϸ@2 y2DI_Fԁ8}?HzyFx iш!,#>n4lЁ!Y dfm; l-w@ JkݛƑFt& A))K!{q):)_=1;#Qꁀh\= z5hkȑjH )ʘ1cth裏S =-CfJԑSvYԍ¼>LXG(~< HcWF1 Ps}ugH $ `}=EKvԩ1h4$f8p`뮻 '0}:1"`Mo2SG u5VxOxgﵽK\5| !ć%[nN޲Q&㋺%9FgIhINxCj&vQ8"Cp[MPW&v̗#4Hӹ[&}X#$C z^Sm  ;̷{1v '279u1(AP\u8ѣckfb#UB!"C=D,uhiЙeWb7UPeb@{$6kw*2߯'$ OC:T.hr-ub.꒎e- !։̳lX*iI 7f-&iEIkHLb *E;a$1|y$fRݺDbG'Fg[:;[-y?$M]%-* {yyϽ.-,`x2fhe]6k4 !7ĕG$CXQ޽u;n-H:2_x/ӧGb{z[nQj6>H|E-וNX$Ce(P'L@0x&p>n$7ȮP[_p<S)Z۔ 6uPI4Rr; H?TBR׫R`߃Vhp1^wuN?`Mf 30%?d t|z Dq]M®Xojp[{s<*^#2c Vwwq!fJZ7H;?ҥwl>p:ƕڮ09aYgV!>w [Gl87. 1ԞoE<_u}#Q.@ d3IْhX.E"F1o=z"`4GIQ"w^9*V)`\|I!--rf9H:#Be=9ߙ3gvkes IbOx GpZ*|ܨ_ e8P$7xCx -l*Tה3"c)%Uj8#Ti#Ga^|NV4(;p8Wq`Д|DxO읶w)1pҎ>ORj*]oK?!IcM"<=,fМzj܈!*88kfm]w m!Q:C L3#3Pp"t~/Hb_A&8K._KlRb;iXoRmH4K[[m-斆P%sNkV+`3w⋍-.@k#Vrd#IMŹ"lA!BLħH6iit ?(+"x[9Mj Rg' `8t= :Tq\ $(f۱cGo!G)aM;{[1rڣ{~ǎ#4D/?ď^gmHj%< }oC6AX;- )4oW[_j_dCNY( Ċ\ܹ% $kA\NPB*!\\ʩw:Ywr ~e"@2BN[իj|-Ln.piW|=Z}"k qާSn4xޞ">tJQ7_ 2cs;G44JБwCoB$:B4A ia6o簣z%n^WV@ (1+Gτ4r4:4l᝖=6駟=6OL–"1\lAnAѸA0gہR! Cp陾KpUNKC 5w`[A{D W )!8qbuH>I3loF9mA [hUW2ɇ_wZiIr iEI%m&igIR҄of$ƐNH96/ڟHl"ipsv4z#ДPƊ,57f+TRʩwBjpIZMKb\t^Լ^}!̼ax?P v8LĈĦGd5jT$Fb$CAtt[lj"X.Gb2<{Q# 7Tx=&v?hqt]\DBv"1늶8!Hfj~ ki$Ct u8gڴitОIEqPtiid8-DA"ў>qWl ]$!H:zߔ$JZSP|S ,4sJ\Y =.z6q|m}{9 G4T͕bb6S֫WEU0|@LOh4bVOCː9^4Ŏv2Sp^hpuʸ^hp`36I$s}4L,a؟$^]vf4##jGwx4fR9qa0Fԇ7Zy nW:(d^ȴ 4Gٰg/%iL*qIJK)io%1m6D+.%ˤEei=+@b\`v5-e_|Sܸ@J la1 p w#I}#Sg,3 'LG0BΒ:@? \)z4]C 9Bҿ%}-Iz( "NJA'G}4 X`,-9U+4b61!4a2 Yf'2mN1 A Hڇʹ'?p|&7C}4h"+LR~3ؒ Q*k(&c'|O1u|y0#|ͦ)L奧z饗B;]8@PB$K>%H=9d9~#~ .]A5G1p$CJP64h32_0%M|7/pJFBd#>"u1*"N5!L*HR>N4;KW~uxfUkp2'vG-1?&dxe D?F351lx~;Eb !p8Ip~6?I" qah3_ǒ XJ:;5ih*шk<fZ-ȍhi%my.{:k7Fڴ|Ix#N畯n:KjrČ  ^b@{H.m6y{~H9$aDf$DQ^x~. E 0@An{%61 H+f 8cM֝Z_hiS P_թZ?2Ѱ{db9N5$sPi:.UMǘ$ .uRzUM_ D#t]5;͵AÔX\/"T;' Lwy#3@gH"4a)^=JXBEl$8uay :묣u:1 3/DGr5Ϻ39*Y[ӉB#M5~i{aH 9CWx؞A i 曇g}VCL84e3J1򱙓&s P䈙C3xE5YqH|/N:e෣){$UE؀J\'XWw8|4H{ >Ȑ&kйax;hqօ\ͳf0|@0"SD†_{5%-8H1vays ]hzD9t 3&$608q5B(6Lf HRMCİ#o%:rķDSOCF>D)#,-{ Pbma\c -i8!h< bᐍAhrm)bFsCoκ:5}(Paѭa{طo} "aA4"6CcƌQryfD|RZb lƅul%!h"59-8)؋h|CLs9ô7hlМC B6$cMt k/僄!h$mAQbpǫAmŒoI%?a8Q^zNAGgӥ$I szP5=x I9 d&IK0,Ek׮a24G'! Ņ4hiY+uz3!瞦N@="ǂ^rǣCxQ"]3OhMXYt{4h '% ~UkK1s :3$H;&.M׉hW17xu I,ж{zm > 5b7J Y2!J%M _hN|dWiPUc؍Q>AUXhl JFWH4.#z4&+IKBfzBU#4BEhtE,r=;Ј!)wmOLZ0>`Kq:cdufabqF4 9A0&3 ܁ ,V3f>Xg4]0?G#9[[ir|%5\g1I+JZCf#UmH,xG ?t$=yd^`V&uvcI("!1{X\GnJi~H'$KZTA_c CKZVj6F/E23'CS DaDDy1rDBt]l"5*vQ$X)ڔHbeMB-e$Zݖ!(H#1d͊dE$hv"=f9r\T$Z]x$C_^( 5([:}*ݑˏaE\H4? E9fIV!RID_$$1Gh4d6ཐl|;a|K ,K͑1ނ==yE =$I8}cS۷:֏G.FzL4-lo#`rދ~^uaHK>Yǫ&a"5jb5j܆`ir'c.ҥM֭0ÂFc hB#Bc5쇒^MZj"nlVRfbP+ASQ;~Cp‹&Åh'\P_),ϓ@pɤe { iIIt!d2d Ԉ|1商ϥ<2h>4S^4U`EReȻGYD=%$mW~N2e |!wu`(=Q1]ʰ9D.#0܄A6s Q?JlIļΛ ٢QٗǗVw } vEÉucΥx2m 1 $aOȐ ɦKSOB#^1LX@pɋyI_HR,Ie#^TrAۂ!n1*gDbn K 䨲8uX2W |=:zN f^R)A 4" mK)W#0ä |4L#VYHi%G Ǎa|MeX|nn߮r 몹h#4rKyG[&sj`6GD'z.^;G Lӝs7GH9߶Y5ZU87Cpbna{fp2U4֫q3 -79wNt Vrd#PJ#Ӏֈ{ѣGkܢÇ+9bɀ4Y{}BȑkjG Gg:}t H쳚G1i#GFǟ#'ÌLjZ%B CGaguV8Ca$X A0$W,i :TC̑xi\}\m3 0xa@3aⴽkꂀZ )'=!j+ zkp~A m䈚هbFzN6Oa?23bi3?@.Ah0-Ai7j Q0\ODzOC6JukZ$z GI"V#MD^/fn?KD.ɴPMAAƍon) $b}8@c4>{ EFl٠Vqߏ'[wqG` "zdɓ'@mneQm)2Rݩ,@](Z}n$yD &+a=FfPAc͛HPеkW [ZLCӄ}I<L=BKNsֆ/mx2b2m@J$kσڛuݻnzM>REi„ jabXF=!{mSuK9t2q뭷6 l+ B!ho&m il't˲Š ǎa@:ӦM-0"F m.#O*ư M)%[ӓT,/ }8%Ew}.a3 ^{i4 V_WBvP !;S} À=ѣGK}>!vG#:]tɛw:@'p HD&Tb%K!>^nQx[IDD_dK 9ޮЃ]!bەB!c7AM-nc$,I9sVr+~5jSjP+h.@ E3Iْ0h `T6\F 횣s8#@&3rMRsŐL?SbT 16mw,WD6#1pGh=.￯l?|kG5Gg|QGm!Cj:@U!zGWbe*̘m?N#$W(nkdHCė@ Pj޽{`J+10DX"4~pxVh?#Q]#x#-d,Cr3;r_y=G袋4Z;g ;>GH/UMeBpFc aZ+v)oXp?GCB6|#XGx&\$ D<%PpGpj&G9r:\D{9}:}:Ec#(i=R_ lFwmH;Q3|Ii:d2v)&tp 1ڐ#TUMX`1]-ȣAðn\6ilZs[oZKa z}1&Mѧ1FDF(!BwZG id<bB$)tKGH/UMO Ȭ5X#{饗A]wU#aӀawۤh YA_}pjHO8Q2A3"<~lΈ :^~@-"PjaڡC9D cf|Mȶnw?dQ#ғO>FQ&vKW_}UxC=+#PHGm6|0k֬0ydV+:Q R3\]G:yѳD; gVmR+%dzKu6l3iĬ /{)iӦ?\O˗/_ypCਣ M_:@ P/ {m°aԛ᎟C\:[nú1-_~oH#pkO>Y S| Gpr}9{}pҎ@U)ScU4/<zE;wx3f%!;r m׮:LʇG=~ XsG:ayAiggyo9}ݚ}ոkgqF8;Jr_y=Gujr(it9RKN:)|g P&9NbDԎK#T'8w<^oK.W^&~a8"LA zkxW\^dA O%ϩ#U>O<9J<2$,Ag(g- ƍ"\H\?G:uX,'iˆ I8r D0?m ^o>%e?8@!P՚Ncɖ"=z6 /úaC6=ݻ0IP>?#P3ѪZg :P\6ibAҮ *vX!FaKfGhQZs+k?1,ramɂl3 *[k¨QY!~*#Sosooί|uqA[-i3,*@{ƌK/|zGf):L g}t6hNo`Hcǎ]7pC9s# |Bjre$|vܗ#P.:Ϭ1/!O|d.$74^xa4y晁Y묳jqrqt!g<6e" $$k/kY.umZ y1IƙVHff'Dm۶᫯RjAmڴɞ s=6`FQ&vK;R#\2m.RӲiI%a:,}by}8@s@#o4?pR@UEvwW_}H@<2vСkX|5Ȅ 5^]GhpZ"5~Gz꥾FlZ_z:wAnjp jY|8#ksmGj??wQ"5V#8pt>T|#P_T!4UD.,|g86qz~#P2.2?9mF3xjx `OD`H\󓈃taH&Y~_:#Mi9'I'/Gpj &G;C8B~;uoO9[N8Ajz~7#l\#lGjrĐ~#ٙ"^?'O=j,qoO(.Gp~A5ҿ`k@"P䈡4@_}±d&~k}\h4ޑmpp#0M}OBfzģgm"<.%iL>o [mUr-%K!H*sID%[IDDeRȻ1v]YDiW4.]A#=s@YN2eJ5j.:^g ,wiI2m.r$fK^mdR$U={$#pJ `iXbpglM'h]GaRQn/2<#6.NxԩSp48@]# -y時O'|r<,bAZRP-yI#P2dH袋|.zGQ?JVH/pR?yG49׿n+#l L6, 믿C%F￿|ó>ǘ͂l& I4S>H048p`{tOP'kv_jY^x!nc{f*uij#Fd#khmb4af#&G m۶ 7|:|i@z~~_޻ѓ:蠃z(l/2\r%nЙ)IٱNDϙ2cJ믯dW39o̘1Q裏;vT̤ITd%|Wo?v-!ߊ+ʍ')ogz2uYf@L[oU5?K.dHѠ+_~y8CC޽CΝG_G( &vOSVkgͧìiӦ?\˗ϮKGh={ĦC(OpYxᅳ޳yꫯf#1!FL{=" cO?Բ| N ~)7.)Ā[zUlJ(Ä{O/@;Ѱabb4Ii:S N>ٵ|8@U96Oh9ΈXI, 1Y$ĄL5!&Ypu7$Vj>o?ɓU1l`3O s&|AEf{졇Ѡa8!:*(ifƾfm-nӮ];mk暬;Fks8-@Uk WNmݦaۃ`\裏j|5:6a]z.CZꫯkyWIHʧA{tǫhpv(#qr}3H#bXϤGjk)"ᆰt6d 7Pf4/{q_qCfz:یj)DhG{ÐZ=f?h:=F<]t #lzA$峲#mH|vK &lN - - 6 B Qp vؗ# 5A3{eB>0qD;KL[hwbuGh!J%-[mI$a$VYD0Tň;ktvDʗO셢|:D3"vN e.]^A`OR7IIZ^R{Im%+ҲB?H}$TC/o"D5NnQ&qD2}.)!-CHU$CӧGeh$1#CnB48% ,igIJ7o)(oKm7)HIBњk5ikH|W^ynD뮻6(fıc|B>))_~8 av m6كhfD3ZkAid%6DA^aSisifqVC`dZD>hѳaƤR!^OfIV$^ł]vn9+6 =qI 6}tTr;!wԐc_|E+$ _j&]'tA 2$@lIK p)@k ߾uG ?>Bj/I3=IR>;KGhyj +:#8@#PH*ckXKhG@ H)&G%gQY,F(<#Pqo97t@HdXnz$.!>Kqa8 ̚5KɆz|.X9LfA #+E]2gRf Ք18&hLOh ?o#P>jBh|C)1Tb y5Go0Xݻw[ 4 ia @r-`@2H AEhiB;# 4=qqί õŽk׮z93a(?2UlpfM#P i#G͖͊5c  ds!C`[KRWQpr$`ԳGc#46T{Y]q-͔x.Ia뮻[lݞ䨲>тх@{d ~q7$'NB q =h Ah Dh15Fy9JT*r-rrwWrFQ#SDH¹8ȶjH'SGHUBI+}IJGɸ$}!)»S&;I$+$9!\GpJC m䈏%!~Ad{f xR΍C % ? ~f҅%m»SWH3Ȇ؆4H@p)fK᧧\ c37Q!;qm|2aו̍Kx)D m1~Fl>& FM՚j`%R$l0:bd | 4$-TĻA&A G9( asÌ),2k*Je&:ZWI[ll8JKs6!B Ks*܍6(1Bg͕rnRE v/l?@R9D³e$!N0#sI(?!(șvB2+ \c)AAIJg(a$Y$;^h 0A{$ʅic`Ǎy?ȆTk؂K0hk6P9NQ8pmux&=q!{nlLf%0|v 'h`YAV?\}% /:dXR=Ѷៈ:2?LrvW41éPFpq|AAT ǩCϪo1lc=m GB7{N(C66X̵=O VrdĈɴqćDڲ%=& n[;uIIZDC%BKpKYUw ג DFXBIh Ґ<|h˪#Phv&Lr$)Kj|! | ڵS>]v$cXbvX#Ix 4B: C:À_~3YKVȞuYJ@Оu]ˍiHR='RC.(H2&Mn喰馛SG#!IE6,K?/@#5`͍s̫J-+{|!`>8B~|-q/cyV64G,ђQgHy.5-{' BI$MhuvĿ@I]$=&P^.Yn+IJN`w~Gl >:U*F"!dmհ .z&L٘5-_}U5xmǎՁ$DB`\wuW+[Ľ{-'/"uڈ|"w͘t B^A:dugCӧO<Cj!5 H*8sqɳFS>L3s)߬qRG[^33Xۇ%|ㄈ}m٬YE &;ڒ[$A&KPҙfHZV:MTH擃`0<6Zs$#)-}&HPzfhMD@ &hLn2ٰSzUfA:$Y QY`1M8)~:uĈxƆ=18t d6aICOB$G<, IF~؆ALqJ_4Im$+ r4BƒJ" fcqLEAy_ZK CHJN4 LN _]̺۷j]|ծbA$/x \հAc-DA+Ӕ4Ya:4ZCF2VIԍZ\s%(X#G6^l=Oa̴gI{KOg .i R{$Ic DzXbx:!I,O_It~#i1IbjII:LR/Ibo|nxOx_\[$Υy^ HJs6P`0#Ά 2طMM7ݔRh;n0d4Js1&=tw”`KSH0< Ӽb{6 lx$Ɍ$՛Y6 m aH -]bvmz |B[NROra'a^Zb-H>;fKQϐq%.rM&EYiv*lݚ_ss$=mGN63 hZDX_n`ocNMhv=zCh9"z=.ҡ(0 _NhL|z^Ci&lClݻXnٹg}K/T)7OmșaR*Z_z3Β'w[歈|3d$-"  EU%Ia1Sv jP#Z}A[1 TOA}4MY)Fg~ֳgl|ѐ1Ĉ=B^p'/Ò|;/w #9Onmg깋3ID-,]DQ@r6'GՋ|4 9J*%i( w$ClZBic9F؅^C,H~ios+{fk[vrTYUϹU[-rTU1l;vakJ+U ^ʾVGpZ Drq3ȮP#P`RdSMδ$[jk:prp!@0fጱ[nG ?Xŷh x8GQ1Gƽ8$qkv_xu89nܸZ%G"89^#   +Bp!?:>YVxWgw{_gO裏V$*퉥o !xF{y|,[\0ƏZkiZ-G};tvqG Kv|K1 `ci@\gϞx(D&N*|]jAÇpذy:TBdĉ]vJ>û4>L.!#F2A@XWC6}AK5~ppx≁ x&4i{F۔MW^yE !hȫ3e^ф ԇy&?wq]J!*d+;C KS()<4=\6\@)z^GHb"b!D Eoڅ[\2pƸ*( >p<k׮њs!PL믵(4IVM®O>=<#Jp 4jrmʂLrmoYzLAلV9P‹zj&x@Fh(4&O0lvg#8P{@Zj)M'0XQI;f=rC )n X^㡺@j4oxe|d˦\❙֎J# +ĈxӮ_~('G"|6ÄY5lUEMώ1"D^%=0\G1i$Ui5 YgЀ ?'iCPc'TLݻw?xL84J>8O qp:=6A  Ҍ3Tbɛ2LhG GaCpo[AF < 4U6ugɽ8BQlr1`؊5.P0AT̲_~:OWJ[0B}t6mڄ)Se0 "|sm6tӰk!Cp*ax(NF*qDEֆԊv Z'ӦM*n_n##If`dk.67BCK/0z{챇e 0yU -S!FQ@DG* 8 eV9*cH(S\O>|qֳϯjU+TE 4GUa黝U5GJ#*z 5zrLߥqZp)ɰD)+HƲZ/~[+]e;4GU@]!Qg"WA~BŏSs.D()cݶ(ہ@ @jF8@ q@qwEa@`@sJzzDZ@ 3bX(N 7rJ|9L\ A?@#CU<3Bx{>묳[| 1#xgXC@a5fd!-#53fB xȮ p}T$?`sɖ]v DŽR, |e])Dd=E#vN:$s]7w޹T\i١1#}p Ap_9akƪprxMrYR+s>;,os^{)o27Rux-/K/HR `_rM>0ZH zFq$Ľ^Q "$$/Z8w 1"udn¡ELyFjFEo&8'#="4Fo#@/JD<%8m#f)4Jmc뢏 ȉ[~Ȱ<SeS_a1H [|:$=!Gz<1cÇ׶$=AHLkh,C=$b8/nX4fp/˺r_z_ch#RM'BL}'[zmK,a/1|E-^uUqjI= 49F] [xkT8$o[;)s,(s9X F+ F#tQG#_N?lvV]ul}ݲf.ʹ$s>̟go1;SٕW^R֐AҡuMLDE6GZ)X;$ [RMW\ab4 ;cO~gaۿ{ֿf[ne~Ќ(Υ5<ٮZ٭jz!$[l}9piYo0D/VZ)#DN-c믟L.Ϗ;_]#L Xk_%l뭷 dfٌ3AZ#~k_nw٫jx K͞K>.[mWm~_WvC-P7 I̚5+;w]|s#Hk E@ .]>0tp2YZJ6=:`iM6I^IaSD6'm[ŶH7tKMKĶH" I$|Zfe|% ;>o?}\O֥{t%&[ycm]~vLvI)iX*i.ɿIzWR s?ܓ9^cO$d+sv]󓸇QecXú$I"^"߀Us{^P_Zr%Ӛki4fN"+l g]fl e20рPH z!N|xmxo!(lfMȦLI+SwX)w궄0,'-Jư񍰝Az)[馛aW  G(1`X!4P(b /}4†VO*g4ĀC|(g@V[m5{f/9PD#s>lA!O}Sd ِgÍ(!`ӗLÛ%*Ck> jw?KNR˷ Of{>/:D^a\X!uYgD6tNe &2"G`GBo l\4Tb6<|RMB"=-?tDJh)c&.l\4 UN'p'ʟY_/RDV _ 4L.0 eǎ 6DϯoeI NhžAȞ`ۄU3!h0{ ./~llQO>콘Sly~S̿Kۮ1SlGϰD7DoWif|K%^#.9m?M͏ `{ ԩSUVY3$a8v0M( a Ə!`A0 *|~/0L?.u1\Ii]̸ 1=S$i0 '0Jz Ceil?"$!\/;$Ut [3v?9%(!yl5f,vۤ!#?5|oyYK.4c?ED& > ͥ /N"K[hwSz-c0drmN$ێ ig/%͈M|p 0RG s9ID4ܕԑwIѳc=wqz1wH$cJ( -$¤ #LZmm-Ґ|Z{]љcFnǥiOG(!=_i$2MC/$uI\귚0Վ>az`0Q-N+J+6N~sxZAxC6N򨵟I46G8uԅ@{>ILȋ:6je8aEp %1%aȏ!yfrav|aFe<>VcKY ٰ5\cf],ٹ)Hn({n'~EvzFbLu]_7ytmJ^OD$^ &T$L6Ǝ 7&.Z:O8H4UӱY$p,[?Gf9sNr!]noXYi"&`)skOyvl/7pCG-Gs5{!|P])وފ 衡G?aO.L !h w7$Ȳ; ^'zqk3 mi0뗥kmf 3K0A-$H0}WVQwoidc36Ѫ03R=Øɰ;]m0Õ|+܌lZf d g3c-W1+cB,QF4VlC8Yu8]eV~Ǹ̂ уG剓I!^Om#@^Al>^Wꬓ&m7c{.1$1] MĄ~<띇&lv R~]#aȏd-Sѵq|t(c[)ḏD;!3j#11Q 5?⌱G_E M+Ĉ5#oݭdB Ln7% ] nahr@|]o"#P^NZ ?(̈́9z\ @%EW2!ur+j'κoN@!k_-QM_r>K{b!n?5NoLX '+};<1 8f ')dHR?<&^q Ve,XtA|zR/8ABD5FN|9 E/5;h|GgOF63AbO$>;&8\n;+F9$ "ks\%xVLdm?O:V[-SPo7&fK 8k)mrʔ)vnx>ʃ s=V̖#ɓ3<~#'M#t#Bk7h:oHwD()UND ōpx;@!0tC>*9—>&JUH _P/Ks -8YTzJw$]<zJPaR˕qJ"Dvw$$ZS7ͤXfiwOmqVeI'W̕ ^zIS>UI(1da?CFJzJJ4]oW:SIM#9>4,yT{zHKh af(IC\ΒB 7ܰ| br1cǥIvغ4Ci 6m_'4r 5kT(K#e6d(? 2QV>wH޽[iI/=%I^m7o^B$Ŗ/{e2g})y .l~I.:4C ϴ|x ORwn!-iBz=Goz)F<7i2o^W /+Djvx+~:Bv 2cEB} = CkbU; ҈X 3[dE/>ܜM2$!>\‹Z<|(e ZKKQF\>x}Ӗ7e !Ep*1lE 뮻2\E9n"yxfgg}vFC9$/;ꨣe zI:9zC||pcNX}{a9=eϕKyZ1|x}a@^Z~8I 45fSMYil:ٳm^qB8( ! wO)ccD MY˘ߗ_%!|ίw6Gya# eq,'K|K=aĥC=+aR >؃_ !0v;c)K=u>F| G%%z|YF uϱ~H(ܧ:C]u4HK(si;$$4qhjκ/Ac|1:F3mo `,%\bvjˈ[Mp+* e* !!?y9f u∖all{y*$O eolW_v~:๐5z P^i F$25FRH XS<,{'!jD#3V6կ~5UVYňV|~Ј SBЦmqr\Cy'ɞedм:OY#r`f1'-?iYCEhZB`}m~bfBKIJc!7f1OΟ@UJ/jUv [" uHN` ?8!:#Cgh IvH9M#AxGw"n&)-V^"ӣC65 - !|ac?y|}Df y0(hPUZ2B{(E3 Rjylj|*ea".F1H8 Wlk=`4$Fjhz"IzEyQ#\K4HE$9)b 1LcI>1κ̑#C_!!HZ%v9YBL.|PJ  ,!R2KE;3JnW҉ɉjH ɟ 鬺64ok& 8= %rd5E,]d2Pl!}TN|| 9r:نǐpmѸ# ?樻-'GE|"Ĩ'7̔!#jxf'JYlĸwK2)8eH @{]Ubw 0LmKa0Et;df0N?{,5 i9:3VM}C?Hi,W2*Clc8U'vX&vBrd a̐;H6 ʘI-aJ=BADg#x#ӫ}tM eO+AZK2_7h3o{,];uõGd1K mLl3 !#W Qb݌tirEbfi+K?rܖփgg1C3;ӳzً74Q'HM=u ~_&1%%@\N<2,j[6 ]zs ̜qBiK"X!9o1 ǿ $ 8;+7q[nO+/Xp;dvm7QcKB\{Fm+}w,C皣QD 3OhFcVOZ}w!{%IqmL$ 1hNcnɶ~lM7hC>}zvycFleDž2] }.@RNjq~,,@]w_Kh(}~Y¶~ xC=)`nF8Exȑ  G<$IkڞG$@ 6{x9W!jvpaNqM^AFɅԫ HȀ-Ξ |"L'?0hoCBVo挠/nxv?lo!?oiq<. ?iBx5#U⋍ M<ٜ&'PB`D@`aZ#JaoZc4{^<h'-a+ W#_/VCh:zVM#mo\C!77>YC`:" P&pk&E< bՁA,xnEvk?0}_n*K4]t `]}՛;N #9NLߥԶ0^Gy֪Gͤ: 8鍞~f@MNG1A}NVCˁe&CRzOhN2H"#>eȀ"@'Hx'6s[oͰE"N Ck AX/ DąVt8h#{ ;4,]y*ޛ  mFgqF,=⭅A(oX;^hB~h|j *lbG;Z"xH|f3Jɓf[Fs}z˳0 <&M2 =Os!K<jR>fΝk0-~ /),${ghubwF,a_ZZa V:5 A|Hv.B\P̶FXNܟxCt\c[VXɛl|C;!S P=9Rϑ7b({3/b00Ѵq=^{e?$xFFK/>`;%ƚM梋.N9唊2DRޔGy$llv i|+ $h=a6T̞i~FaI+LCL#(CCKɇ2#kaFW\q#f}b9|zD}y3G=sܠCrwXPU:6Hm]EyRːxv Cs&뭷M3Uxyvygkh ]tb(F1<%\ EgaBKB|c qs9b5ѶAiHiEuh**ڴ뮻ڶۖ/i.II*DNlȈ/ޠ'2aVgşy%i45CI=Q'3;WƐ_IIŶEV.ۡ$MöĶ$JC<5te %:[+[zϩI$3I-oP~&K6_F G:ZRW/͌UqL_)[Ti)*RGJ=+4.!IDATuI$#v>\+hi#{NZҰ?öaRo~vH4S-|q u#2]AJY(-{a$ڪ0XH ,,1* ÈK2. Z ڡ'pQ-"BUU%1*va)6}( `Ɍy!Gf DKH|([dH3~zNl9^b{ϯ}_ɇԼY\f}kP\\=pHcLw+aT 6F+iiS:yb~#D F {L|H]3T{6T+VZy~Ta vC±{l<1Pn Cc4x͈8yyWlʲ'Zω E<'|_ƨBH0u 'T . %Bz׺*a2 -x.a399 rԩ676\`9蠃27 PqH3o3ӊt[oT.w=$;W](Kd1͞ux{Ay{;A;<5 |kƲޫtitjaHKFU vk]cCyU3vQ}~k4q^%Ѽļj2FLRLK(6N 3j9Y&ڂʻ/sKYjk=sJ/R9; 0H<\mk򙌇uΩEA8!08mW mH61*yԧsf#2؇@<692 DPcEܵ;x]՝\#qC^pH8oYgː6\Q꾃  tr9 ApOlQe`jPO+~IK9Ԥ!~҇=I3 i2B ф/ MH"j^S2cs̱D6l$yO,U>TΤI_Qs$gIްWiDwI3H&E Hp]CY5|6p\#T1i"Wgͣ]69L"[I$0z-…r?NWYZV ?GO Xnj">Z(99Bղ*\T0ꑓ#G#_)5M@ {Aq+i8P$$/J4 }=^> H [nIKMjnr$II`@$*0n:s;Z΁I{<̄X IN̞OQgF=G=\ G믿?!:䨋mʠ#BZ| f}zN:ɆE;Of;L\`x .H cGc+L.׃Z#ZfQƎ3#c࿌l|$p*ga+ȗ0D(g|^:B! plĉpZσ@_6Gp||?hñ#ꕯJq66"a{SMPl|1"!1lk|Su]g[OҽK)|9_Zb;^uUVl6V fBLvwfsC1b(nCȧD `.v ox" &/Puꉱsb#7xB"c @ #T4//| q:44d8jfV;1CiCϓ;VA0F{Ž0ƨ& ҆sV92|uVSy'E̺?ԣD |]r#CCDy>HrH)wCeXd - [ ~C@vޏmNY0#CG24ڶg/% 0߱[v k'~稇KX Aq,N q,Rx'zƐ!P8tj/k8k#0"b2 -$frU [9а!Nq=jiuC~Ņ56 f bUϏY+vcO%rq]UZ9p_#P7}+$r.=)AW!=BTnGw;[J]/h G͠9bsDCFUyh7@ A!G& IF,@yFG @"0hEOab#. f1/L P{>d,ktQ\+隤-Em`;wn-?qHa:2r${gP!^yw1$#0( OMJE کԟR=Tv͐@`t5cq!roX3.ixMLtƽ?foh?=J)1Jh#zQ^>un?+1 /|LQzD}$YE3fN?tsHHK/42 Hk>!w44>rH6mڴ ^lv0-o_IO={ꩧF -$ܗ$.g}vv'{)*S*N8$Ldȍ([K| A!Gg| dȟ,m/e XJe? ćzC(*A?#'HH Ld!~^!"w9R$ȵ^)xy6n)áoնrle F :k˦On;p8{lR}F+M< 34d?7F>l`_#0Jn9F~ɑkJ)cT If;!K-T9(lYچ 6H%6 %\RCf]xkl+ w?;!~ #?64d)O NCi6j?N7#Z #Kd;SM/٧>)ACFz٬.fU[v4|/-`q |%dMLoÃz~+c=.fĬj '(FHʅԻ_E& U^*%Xڲ&rR(:qo߷w;!HYiH[o5 I/CRl%;QҊ+hW\q'I|{߳QN"9I [I$ǮU#P<ʧJz<J"Fi޼y wB7$L?я"OI>[V7Zx{1SWˆ _H[qnJJK)}TiM͔Am}ӚkO{챇sM D6ZJCvPL4L%Hp E;_a@Go~6l3;w\}:}K_J[lE'n;Ob]O'6J'9L-]1}ɓ:Id&G'b;.?OrFi?5?9$ua!暴`D~"V ~==SO=e?޲cO?]+O#<>򑏤NUNib%fyEOWL+bj했ZΤ@ĉrqIq:.+mm2J+~,hrћoI֌4m Ǯj/zJ+l/;dJj[k{kش9j}mi6g?ǹ(| wϦW_}ն0"C NrjI﮴=vjcjomE&iN뮻O|"9a~zGL^D^׾ݶ<<:?8H$P|B9@ t6`vr79ϴ { Ȣ M[#HUvY˝'GdL K38*:ȴYo1TB)QmbXMM?z6Gx%r7qpӏ]cFE% e,:a6OId'Sa =V[ R/r~w:+ ;FTĄb\]U7a ;fz3^3P0C &3Uzw!!i len44+DD+]{_W6Aˆcȋ:/mLŵl^Hkb! p/ƹ hA?lClz>irl y",GohHNQ-:/GԮv ,iTaf/l $…7t*/1.SK4`Aob8Hw3̰M wCG oqfnE˥3/<4hF!p|+Ji0H8yue{キ50|R>4TE׏6u M/x(! wƋ@ݮ'\K 5%ntk d*g ctMx"Ժ?. tn½Ap K8Cy&s]9즸/Y+I.fIl|Q9hg'ELZA߬R ̩g,_+@7?؏C!Ri 1,"GN)%pJj !58YD5!º^,[#sRԻqA^hfAMȘ(RO'x* e3aרa7ch )K7I9^2{h aV K{4iJeemcJ>"MIÐI$ɎVQ> ]ݧ`)MWZKcJT,R8b8zٮVkZW6ŀڍ!6)+̞~wMKΫwLĤ ܬ0'_p:FIrdif`\ċ.4]cpjS,߄r1}VZzX<9mGd7hoHC%u%ƍ%e<>TrK3`p݌Cq?j}4F:eM z| i:s0@0^3*z  !0yx1ʦq5~C0ϋgԺO}q}gE`"ŤI n[NC+)v̂k(5Ob9Gs?kJT{Z0wv]FEPPݍwV!1DR۱R/vV3pohb1JWDC"qzn+d>0F GUɽAZ/7ڎ G]džu]le*"f7p|y Ezu+G}>J0q!^h[fUS&]C{DȱuHiE کԡ\H `L^ {5*/W=cBm\@{=ܸ?\| H!@p2Vyn'Ճ2_` 3Ο*=H t d3Gz̓wjz)$NOk3RVfr3fXi8_kTͬ+fAYf묳Y -9eFv@Iz'Ec{8U>IoW"*Boa?ЌF&葘an9v]wզ+`9cd8( ".+$ !oi#qGs-@PH^uW aC5^2j$ AHhjF%yo6,FDx@\[>b)<$/Kú9sXш1܆*$/5 ŒJ'JS"U3QEǫPmѫ?֧NjF Ñ0K؞V_4=_>=rR`*یq.4D.~F@ExlF,;E5FNXzyOzǸԋ^/s bF,+ F eA#:3ZҘm+[""€{C[lEꫛ9Rc8o֬Yv[faGEdy k=m>DҰZ>ڻqqZ3ND4n>|j;bUBV]RxKh+Qx#0hRѨLկ#N HHYet,3l򊖈 8d8-/L7mJ'z3]%jfH#5BpѢ:JWӀ"Pj6+WAB'"\ygA˿u q@xACe r?S[,w:,mW(VBzE}ndۓVC:@_-uxo 0~~{S}1(y@!4o(rClH')K}*}F _gוP%G]l;IFNB:@qd ࿭{&1Dxg4;+B 2!_l;+U[{C,B0Q14b4p#:z䤛K ipwɩLf?xgBH o;#ٟ\E!@ڑ G-&Ψp4$*bSUJ} !Dq2DN1jH8g'Fޙs:3> BvPs}-yZ ix[AsD#-Ĉ(8G/T   [ Q8o&0AHe0!5YShBH @=:ɇQok:353VCAz [Cs^ܐr"`iLrZoxn(Z !G|i|$sMHQA|%7>2`'Fr<$ `! `d34~v4@fP*zfi/.BH!@RohHqc6u+7Ё8,|ѡ]#. ~x!"9i8) ZTD !r;h`FHUh?ސ9!bI}b?K izΥDž}hxg!} ^YRKo[h rh\RJCJ%D uO84Z$4 ۾ !8{|}uRs|;@ uV8!b[>4F# +ި\ˋ7jyC?/@ rHq97~Dȏ탵h;:ςu_^jttBT\ScٟVZPf.ky70#e(q;Gց@ȷ!~t G]1@ AȃD$@ @ t@K@ @`r4xi 5 2 1 m @IDATxD׆콋(" *X+v vE+ذPQw]ĮXQ {CDAEE~>zְ7ɞs]d3)L̜Oř!`TV<0 C@0µ`@0­Ж!`F CFUڲ1 C!`UBJ@[6!`Z0 CJV h0 #\!`T #*m!`k}0 *!0gl Oq` !'/|:YFuը"d> _2YE L/-mur7­ΉEɕ}xSe[5@ L,c_υ5H$A'pԘ _9\E@PVsPUaaY|P5kV:v(X;݌3^cD_~-~ۑYkLMjV^a _uHI^|^xw%e]֝p ]f BN}8 q&Y]$\&\5)p't;묳܈#ܼ "Am2,6tSO &M6 <nI_pnv-[tgqF2rr˹#8q# ڶm+wO`VAMAEV%*'n x%T7Q2i$ъwygSO}nvr@njwz!Gsq:ur묳۷8yCv[c5\M7:()֧~^|E!&McJz[vW )M pF.!DŦYhµjJiB|o;ܵ^뮿z!C*wyu=3Jb>[vWt_}CcС{gK/ڴiTZ~9r;7x#fG &]U#D)X6m*'v[vCD?nvu]ݪ*u7A¤MԘn%-_Ϟ=]׮]SaLP]hRW_}u7n8zw;>A؈^>3Blp#\Բ4ܲYArqB_~n1=:#{$vy9L 3cٚk}QwW~ikL}Mzp롕PGax5,FZj)2+rw]>ɉ fLȘ^4;^㏗+-鳘BDP#_2?h)`m\1yRӧO[t+6&ӦM(vX-H#0:=-Ia1adsi{ϝV U0VXa=ltNza$I(G~-.n\Z*T՛FW-+"otH*Z #܊›!tz.X E 8܏ M/NmBZ+be j=i)kX't})ʳFye"Zm4 H?*hzB0Fe^KP7}mx5\SBr~P&I_!W XJ;x@&4JJEcoйsg^F .2>ȨK/鋙f믿{WSia֒ b>L$gwa?j`qfV[mL<@c͘9%#pY7q6qD[H8%,>Sڅ}Ty睎$^x3[&)~c紟 :7v}\Ípr5.77Fҋs/r-)> HSNsJW\q\װ.H]~2ꫯ pcG߿@D(Nspz~lE]1cT&mPv6'>L@^~ew뭷{GHw"\zkqioaưtArM8}<1 f3+\c~ѶC~XIa 4b<#qW{ȇKCosigNƩ"^Vbn -^yf^ӽm/dN>Նxfn9Ʊy9* ]He}5\ "xGļ4Nf.]c1Ԑ o뮻X阏vo3 XN(lwuvCujN <0W0jj29bLcG5ܼEe"^.laoa0\*Rݏ>HHm" yqUZ [ș0LD:mu-l!l&@0Rk$,,g[5%SW.^ƌ# G6H |00oČaeU#ak)+%?DU2F#J֤5TF a(3\^ǬpJmڴqo$Fz`jxmZ@oOGyсA9R8g5o}!kךdv}6/W3_2cJS$dګa*ߘc,PƐ:>`.DW/ e!.Ly`x |/oz YhxyzְbI~r"` l nfKߣ1Umlj?ShRF?0 RD I"aI%~L^$ ,?nݺh ][,WX&/_iIK!Xp"Nuqy# LM xAC Cㆳp.-0@D/O3ng;䍆-&o$O*"\b"*620Vj@dn Xӽ\ehaɓWo`fPӽfeK?Xoa߹_+,=nISj^xƹjXvp:m;hPKYȅ,>[Jkn.,nP̈́=7 &e|g^$[7ɭ[ E6-n ]ezl޽eY./3'B)sjxyG b%̩$nڳ4jȍMZ.TM e0v1%n1'^(y;p_o?O&+\?nYFB{f+\g.3ޡy֛ c=6P>^CZN9 #xWJ7 17 d٫\-8mG!ޱͳ>+`d;\(c%`=ǹnR[ћ)*Ě U{7,'x#Iy~TpN*e|^p~5qG4 :ee"`TX#;.]@|2ߖz21NC>z7lMp.V*!Jjdwp[23q#\8]jJ[6!=c ;/jw뭷:מEO4ƸR`!:g13t;| юn1#&1c7 F0Yd6rƍKXVkF*T#܊ClD ctZhI,LiچˤFhTVs˱R|{oyzŹ,έgefrpR{ |04>Fr2a|fͪ{$+. }þkR̤P-!(Vtkߍd˿~ؽ;5jڼj@&8^uU|+z{'K,^ K]wF-]ڕ,*8acm p+^#>334Ɏ@˖-ž"`*^X:ur=zA %C)8hJiBҭh'|rnjl);#jD̦Fyp"/=ӽVa^YcM6uv[x 2 `n@$3uAh2@/2^פtL-CK!"0޶I&n)Q2hM7TOFjW #ao9[nEl[F\5?S|ws=پ̤PX5|L;4P\SOu6L(lo[^;b`[ĔpZ+bKfq:v(xdV2B+FQ,n "[neF,LI:t0aBʖ&ݓO>~NKZL>xeȐ!aU FM\rFbwpc[C9D4ᣏ>E$FQHꪫUfγscUP&nZl,b*\rD9/#(o,>vXעEv|wu6l3wֶ0L l+Rf~WS#/q!L,ȄJ ~!g{y$#G&NY#綟~#Iꤡ\)S#< 6ư!7`wGE6 pZbFU:w,l&Nҫ}ݶn+OW1 ^[>&Kz[13!j_~=ә}4_E^{5k,~7@E=Mm%D9so5\cd)S}e#2u$Kt]|$$ybW5f9 #^zIM ,J#ۿ׾}{o;YF"}#H4Bp8i'ZJڙ[l1xX٪dfK^OeQ,*"_}vLC˲ʍ@޽ݘ1cc=frCe1EL 1m^(L5~Ik]"` xovM4Y9,#зo_קOB%0BdGM6u "H~תU+yiO\pפM7ƍgxJ[Xt뭷v4l޼yEUFBuk׮~k"@ vҤIbjJM7vPM Զm[wG]V3kF53ٳ裏_@X VW>nVoF{D,Ą%\2̻l6,,o,b96m; =t\bf&4U2 N;_]tEɨբq( T*nS\y;O`si֬0vӧox휑#hJJYrKo+'ZV*!hrCq#8^L>k,׺ukY &@"`[-_zwMlpC b!=̐6ITF!fb;6,{@?ewQGC^9Ym6l3ǶFmh,rǻ78څVѣcQL4̈́+K/TnPB/bF*WrUO'?W^y.^ N6Jz}.r9s$\NV"O?Z)7#2i~p$~$! KXuw'bW F47n5駟6m Ә@CFCLL0Tgsguo ܢ!O?k7*-r{ns'pBkaE L1ylql oY!IEb+J,H;fÍE3E3fp뮻;BZ?G7Fի^{5k_L-'C I!ƍWˢx?d,m pZ){ڷo/NDXcʊaD6T q04TXabi1h(GO>qw_ee1bpcL(?.Y) x!`nګf6m[ob26⌀pzU,A?p#*bnYZZ&-+BR2פx|3ԤI^x;S+˖^2BLh:'Ntx;vl,g$YjV-֪|͗W9&w1 7|\ɕ-pe5kg}nQ&Ej_?}U=̓2f=CyMh*駟v}Ln휺LOً{LVY{NLJw.4a0o L9,FujP6pތNx`!c9ơttM'!_%eH"~p韻kvh8OEF)DUjX/X^HxM31 EV _3g \pA`;LIUG.!\oN;|:iD`ܸq_wM6dQ(^wY@YL jz. pOnwK[jxE\uOtuo~ֳ$ W =*?[XS[X"pGk_=ޠ˞9,b1 W =_$!W2!7%BlnZ0Z-ɤd bz71495\WE0CP&\xJλKZVoTWEIk |(j܏jjF`dlr뭷ʸN~7i1ގ*\rcvS\RdĈo߾$a&4nxCPE#U*UrAa¥S29K[Jlbƌrəg)3I2]9-Kcr334Z.Jn:mL9MMF 7LS}KvͣU;8R W+kO:eޥLJ|c=Z\{h-Z=I?8(5ǩ4ȫCW^r-? tc.6ϺvI@~K/7o Xb ^X\1s)HgyW{'u= ( ΦOzf#\|q2{{+$sp-[֛h \lwqku_4N/T] λUq|31@  6!P EfDc#B^qFڐ~饗4+ܨQ$.dOp?hĜi 9א! 0jΗ srKs\E {6%LEeimXNOwk pkw^9EX1VEW`E†_\S\ᶍK/0 lפ:`I CWM7(O7*$ AboEnv1 |k:KF5XUVnx\6m|qH6𼒭sU4TؚDr!uFns+|8{Z,R>j!sⱝZgfn\$?hd`MuY'F6p=נX4DrˉzլS A"@F o>CxERb[2Ũ729˨-]tc0_3:@^m2#3.~5ӱGǸq̌ , #9[ 0}t6,14, oBe$`V6A%+Batք, Qmh@l&G\J"\)vDnbUzdeE.Gu_jYΆ@rKR j @6ŦmQAշ0qTʙr0KZ'\:\X%;!g<GW^yj ]Vu 'MpK9 +^s\sM94"~٦ײ< ({ aeKb޸m]wuiфKCk89aĉ@!c &8π*x Á ~X4iL`0~HCuLe.HaD6^pr~̤K8ʃlrJt?N O}įΈw'4oa;[:VF!C;Lߊe3aoB-?$KV[\eKjzʱ^"? ?7co dx\ =Ox׈w0齁%zw nہ)A[r)x [Tu3[o}~xXhI; f iA׮]Rx~223Sa~҉{fv}]H}gВ0x"wR}/[)fO_D.ykp"АHFgͬkٕ b&n'm۶U+ǯgcRc#/r zwr\/?o !?XBcho/7 頙8&rk-hș*YB ^n11N;M=daεZK6la̹~{-"-Kp\O!9 #O_{ nԨQR|E V=zOV[m_%iKo߾2?N[d>#C4{Ƈz5BT^}Uǰ*ՁLN`l:F=?q UtL(0m78<1Rgg,m/

    g<S]15@U!{ϣ2;<Øp;BVbx%#>UU $O4%61 a'|h̨ClL7Vzܰ+|0uaV].a7$BXr/Whū0t^+/-op&ӗ`~/~h4(0ϰaԀsjrѮ&@TJolTaZ+&8yEu7,: {"FT0) *3OfJ* ^`j-†YΙ< 0 LUFluvL#fɂ!uuajc1`' ӄ}վ+,D*ۘL0{ Wa7G*G4%f,F ! J.ےM-`Ă`'ž-8]ry5c9!>\5BÇO]·;lˆ;P*b2~rh+Ķ+$?3P&~jLж {zRoz-txsL1iA6\arD<ޤ*&VZG(u pr1ސ:$,+A1C& <"N;z^jwrjǼ&A__."ȘW|\3̆5p])r1EViCg䈊zg17hB^y;$a.`՜@7 Kp<;(ܯ|@7LަWy-lă봮PXB:,V&\'aF ifƼaa]8,h Ӊ%cfZ! SE5R: SFFnUqxaZ:X}5Oe E.w|aZ ;YUp24FB5|t%[=& ] |\j'Dxc(zv+1JaGe3| 18%K@&C@0}UyHnJi9%W+O ktLD8OgӲ[pbHVށtMU\%]UU҅xM b(pirLUc|Y.s6g7rˢsӳK/mUUZsQԴps7нXUMfGh¥AJghdf/F}=zJ#^pkʃg5/Џv\=tD+.gU!Ev6}jS…lp^#\z}y ).`֬Y3$T=IDATq}WIh6%*/VY㏲cUj(QYՄ[5':֤8K!I&EEڧ!WJ-]r5j{ュgiVմ O%RJ Q0`71H̜VZH[Ud V{ PK'TE+\h,|#<<@׿f4\l&A"URڷ)Jp(qoP:븫mvN8mQH`p#P4+B(K.q/1bDU J"W\:m#4ȘIՠ(e7Ȩra*;vk޼yd{$ndPYANBq3}Qt[b% +0ۇ>@֩$pSP؁!P„Ggy% C=$#t"O-;Qtk2װrpˁbi0L_~n]wuzWXz@@ m$E\YfEx8T!(|%IlU]t7n{eudcٛO3ʦ[Q)Vm nUͲ-&Eqb3 yVM% .s96\ X%v ΍ƬC!!!0[)1­tkb#ڭ:yg3hjN Jim &@ pn!\n!!lQ}@#r#jy"766\5)D+U]4惙~`*U=T*:MgϞO?SڹPEU.[Ba;YڂVY춓&Mr#4ͱBUdK@[ot5+]Z ]@ Rk&(<5wkiA~pS E5lEȖڙ[6[]v\֭+%tٸMxv[I*ewu]eLђJ2Jl&C@ɖXI5­^ZN@ 79h&C@,k[OKb[nD-=C7v$,j0-ccӱEo 6p(Rt15A;ebҳk"` 2yiN.4 D`ƌC7p~m)W^ϗ!nmhp8ayCD M6w}m۶M6T{y3-{GJ\MN:$wYgɰFV'A@>snR:n{ lv{챇8pikZl8ԛ+Tr!r-8?KZ r=l0'9)b[dQe&@ݘ1c\n|^{5qϕVZI1"\M;)-Q e⩧ro#ߝvɽlݻww(L|שS'Yo߾q-Zk!n&wQGI|4i""ݤ|L4U/'/^bJv!{N&7}owK/tΠAhµjJ@,o;]{2:th*UVYŽ;PxgĴb>[Ȗ|+X1<쳲z5w}J29ҝxr $nZqWפ2%gxV[m%{H].]܂ .My 'NKr:;찃\Q=#eQ=z&;`;J8T0RW&sMrX 4X5RK-Yr%gKHLLQ,᥁X%^xTn8AאOZ-{-u(>}8^ l=jh*d̵7p3z{bXfey0-3<2l5t>+et>arHᖩJSX2 F`EIP>JP7hYbK+fF%`H>1;s09`#Z%~g*[-٪eB._pٛ!~}s=SC4^PE<Ȓu^xa ahhɴi$J郑l!ޅi-Ȗ<1uP6L&<00 |+p1nD E[a6hBȎ&FVX"W^籃#2ky*L`I0-SxeJɒ1 "`ڲV/CFk+!`$#2,CeN92f@0-S2T@ H71 C FP)~'n銼.3 #`[qr C AИLOS)'(xz*;t*xnqE\pT-"IW_}n `^z59뮻x狓 FĎs!70 S)CH6\H.΋q?7zY}GSʒ%h*0%1`U"Wp#9ӌF|,8ׯ_?Y? 7of͒5k}]׻wow;>\M OJ,ȁ4Xs q'Nvxg ck1.e&Zk%><_~Y7/P,3mbdC@opK6Dò]k˃x.mQ)$Ჶ. U:c==\Y2cykm689,?pd~!3 N:U]¹2y&Aߞ^(ΓYۉ%Y$]W~"c\s%{gΜ)a6í#LC@WX@\0at_rq"IlMF;w,K|r- {G>UE8= ԣ"Jo8hZa9jߡCw]w9F$dkB+qgoLdˍOac05 WO El8ݱ(vwHj.S C>%AsU ~\XX_S7Xۄc#`hÆ s/BZqs/1  A{.&nڙSfu]|kͭdˍ?k֬deopW5 QML Qm"˵b'|ҵk-k׮7HP- t7F#̬P$145VE]feػ;e..v\!&p}r2 7 P2,"{Z.#x5 j {^),Z!`nAj&CUUҥML#:hg {1T\Fݚf[]ܣnTZXs5݊+pdn %i}؁=bmz7 ^C=u~`!~ȅx+yRfQj W^M6B;os?y}nUW l8ղ7i61lc>! 6]r%E4qD%X­jnWv{n*#F}r0p@U3rYhpN `[ ju~͌3\~\oۢ9CdiAjM4qw:t7|pwgKJlעE qS矧qC-ر!1h mʱ֓⛂Q&@ᖊ`L_p`:묬58ݨQd ;>Jnر(' _ݭbJu\NK/O/LW^yEHZD0a$/8k4[o9~ploǎ%O?u/Ñ;6bD y# -k֬ۏ!P FkZk-I ѣGV>fq[nK wGo]4|c,o)akve!dA%O[&o##Tt3O<95믿h2 ?,6$RA51*J#ۊسgOGc=VjB*Z/2|ZHi …$6XyoUD #;#&4XAdloo:ҁ0H8e9|4&p!P*F"]tQ؅Mt&${TcLZFd,}n=ta!_!cTV[m%-;=d֭ҹsg^{CB0FJe"[ 4fem #$%Qh>0B}0jn @, C>0­vZ@ 0­薥!`'FVkCF5ݲ4 D>jm5@[!Pg[ CZd,,ע_\|dM[f+m~H pT8{Kָj07Iop]0RNvE5*\uύφUaI^1ׇRkpkURՍm /X,G D\6ԛepG;G\$EYPgr= b#ܸ\W k!5-hbUlX`!^p朒.8&njR7+ nq 24uaTZ Bw6m m3E7MW\!nxUIm-Jŕ W"jnR?O[4*%\-sĠ-3)ATsS-nXU5-^aז+ܘ YH=/DiA^xB-&_ڀȶ0l7-X@VM 61)M Ɗ- B1{C<@>Yjɍ֨$Ff#;Xڮ/9fo[:qI7.-Ur*l ÔMGu*řsa5ӤH,6jFHt%: [C> endobj 45 0 obj <> endobj 50 0 obj <> endobj 51 0 obj <> endobj 52 0 obj <> endobj 53 0 obj <> endobj 54 0 obj <> endobj 46 0 obj <> endobj 62 0 obj <> endobj 63 0 obj <> endobj 55 0 obj <> endobj 64 0 obj <> endobj 65 0 obj <> endobj 66 0 obj <> endobj 56 0 obj <> endobj 57 0 obj <> endobj 67 0 obj <> endobj 68 0 obj <> endobj 69 0 obj <> endobj 58 0 obj <> endobj 59 0 obj <> endobj 60 0 obj <> endobj 70 0 obj <> endobj 71 0 obj <> endobj 72 0 obj <> endobj 76 0 obj <> endobj 77 0 obj <> endobj 73 0 obj <> endobj 74 0 obj <> endobj 75 0 obj <> endobj 61 0 obj <> endobj 47 0 obj <> endobj 78 0 obj <> endobj 79 0 obj <> endobj 81 0 obj <> endobj 82 0 obj <> endobj 83 0 obj <> endobj 84 0 obj <> endobj 85 0 obj <> endobj 80 0 obj <> endobj 48 0 obj <> endobj 86 0 obj <> endobj 88 0 obj <> endobj 89 0 obj <> endobj 87 0 obj <> endobj 49 0 obj <> endobj 44 0 obj <> endobj 43 0 obj <> endobj 2 0 obj <> endobj 90 0 obj <> stream xXr8}W䭊/S&d63gvv畒   RL} %~-f<c~P,ßƭvw+9 , G P0Sj%ۮ^ L~[]]DAgݷn|ut]`Ѥvv{w9ƱfL&_+v?UÏ>U{vnWT^'WC #U;OjOQczx:W||JWջe@=/. ZR*pWˁM]r\’ z2ty~k8,=@Y!W[+T Z7c`5v_Bi q ՋQ|q& ] u87.,g1 ]& G+8ڄۣ2bvM7SO#(wa_@˴N|LQL5%b#,PNjT a?*Лh[l |R 7`0 ]95 X"nӡk=kH،\@0\]߸m 6ص ZEFZc0eD$lNiE~s |md.ٴ,m҂&lΦddywuz~ h$Ä IV ~]@9zJ5lLH=#L44d8;a4#0vߛzλQŰ#IHN"8c)`M+rqiM"x|5:'T|']r뺺()ĉpO<ݔ'QxAmpROM2BF KbS%<3Qb 3p\o`M%|dp܀h!49|U=Q06+W6/~ AC!uu`^FQyxi:yK)־ShYқɴ|-$L^m{ "X[`:-l|9`Q*aLelx&*0I"6/yV{}.Td&%lȼ*jƵuٟaV6gV`E<;qSM)H)#69k׭}` F|0Y06U;Sj`,Դxoz߀|QZc5K؂Q\: ,` dЇR [IKBhQvM>{/(;<,Hޗ% \I{ƶnV-HM a&Y [$c5@~,,a endstream endobj 91 0 obj 1880 endobj 92 0 obj <> stream xVy 7(A1iL1>H;%(׋MJT^?xi)bzI:Y"i.Yz:'M(y($Y/ZzX0-d6'a'Kې~9wY0sNH7, Y@*@#8 @ Q`5 - TZA 8Yp\7 !CT@Z>d YB, BPCH @[BFW tA!hz}a ^`WWp:΃wp=| n/7~O"!#J6DX;D#qو H=҂t"==DF>cpab0>0 و)Tab010C w,5c}xl6[==}~pJ8C-KĭZq]>0nǫM@</+w#O2A`I"D\B9pp0J&@"XLl voG$y!ɑJJ$m!UZHWHd2YlG^N7+C ŝ"tQSST 5*6R/QQ?dd|e2dedʼ%˺ʮ]'[.{Rk9[n\~Iy||||u1W!O%aBӥ8G7_ EŊيՊ%JRR J_h,p][sA˂ Ք]yʭ0T>}}5|9~~.SC/5Y*\ \L= |dr_[Bք4| u -3 uˆ o (D.y3J5>=s#+W|pUUW'>Fv {lLDLSWv =[;qp˸!΀2VetHMzѶIn7[y/t0[ZZ / 'Y'[N韪9M;]mhOhtDu;y7ߎ>[}N\y3]Jz}1pK_^~kW^qp`hisӿ[~צ;vw:|={W޿`كa<>{'O垖?SVɹ![C s_בZccgǽ\rUګUͩ]591Vv]{G>,=4c驂O*~f}et:+k7oΤMP[˜%88YĐTL|Jl%P~2{Y@!JBy-$dg5Ps`xBj8ģp"~0kL|YVȏO1|"PvN:BiB_ainn@Fl)zg33 xffnf: d. ? endstream endobj 93 0 obj 2577 endobj 140 0 obj <>>> stream xuRIr1BzƗSP@C3M'aV95D6/FFW<*.ZIסɫZ4ɐ=x8%2NFٮ44lErT*#8gD14xFK`* .RăpgO1(=<6O&ENGXى/sQbҖVnsbp sTض[]ƓQOWz*U'4ײ=f-m]s W}GQS^ϕ=c>Peqc|~ endstream endobj 141 0 obj 299 endobj 3 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [138 0 R 139 0 R 94 0 R 95 0 R 96 0 R 97 0 R 98 0 R 99 0 R 100 0 R 101 0 R 102 0 R 103 0 R 104 0 R 105 0 R 106 0 R 107 0 R 108 0 R 109 0 R 110 0 R 111 0 R 112 0 R 113 0 R 114 0 R 115 0 R 116 0 R 117 0 R 118 0 R 119 0 R 120 0 R 121 0 R 122 0 R 123 0 R 124 0 R 125 0 R 126 0 R 127 0 R 128 0 R 129 0 R 130 0 R 131 0 R 132 0 R 133 0 R 134 0 R 135 0 R 136 0 R 137 0 R]>> endobj 138 0 obj <> /BS <> /Subtype /Text /T (www.princexml.com) /Subj (Prince - Non-commercial License) /Contents (This document was created with Prince, a great way of getting web content onto paper.) /Popup 139 0 R /Name /Note>> endobj 139 0 obj <> /Subtype /Popup /Parent 138 0 R /Open false>> endobj 94 0 obj <> endobj 95 0 obj <> endobj 96 0 obj <> endobj 97 0 obj <> endobj 98 0 obj <> endobj 99 0 obj <> endobj 100 0 obj <> endobj 101 0 obj <> endobj 102 0 obj <> endobj 103 0 obj <> endobj 104 0 obj <> endobj 105 0 obj <> endobj 106 0 obj <> endobj 107 0 obj <> endobj 108 0 obj <> endobj 109 0 obj <> endobj 110 0 obj <> endobj 111 0 obj <> endobj 112 0 obj <> endobj 113 0 obj <> endobj 114 0 obj <> endobj 115 0 obj <> endobj 116 0 obj <> endobj 117 0 obj <> endobj 118 0 obj <> endobj 119 0 obj <> endobj 120 0 obj <> endobj 121 0 obj <> endobj 122 0 obj <> endobj 123 0 obj <> endobj 124 0 obj <> endobj 125 0 obj <> endobj 126 0 obj <> endobj 127 0 obj <> endobj 128 0 obj <> endobj 129 0 obj <> endobj 130 0 obj <> endobj 131 0 obj <> endobj 132 0 obj <> endobj 133 0 obj <> endobj 134 0 obj <> endobj 135 0 obj <> endobj 136 0 obj <> endobj 137 0 obj <> endobj 147 0 obj <> stream x\ےGr}W /Wj-l9drcE*,i R{l`0u HsP̬̓YY/Ub*').t.ʿ?2]I)/^;ë]Wg q篞>uΗO4Ɉ^n1ϮkfG)oaf+a]mV}|vE'E%qf[(xܑ]H.ݾ;ȻWuYrsn;.ү>[|^vŻ_^”|/OܥK)dH[l& ڰPavafdET0qWvoqqiz_/~\~|X|xZ~?uͼ'3f=̉IR!z!2zw\4{L 3>:|Oha>w1ʰaBB!cW-Is +ժoͺ];LK!)m'laesVqnX1/Z\!c/-,w4q4+*mm7-Vպ d}μ|O}?o ;d倇iX,;|fa^>{>8x/lj+\IxS )p٪Ͱ!H!dKF!vOUmGeF5Ȑ޲n<sJ@{5N<Mܴ&ⓑ!/0zFEG:"Cc1Q>qGߗ@oyn;[%O^9e ˫ |11q"kWbQcrذ$ZP|)܎ˀBQk΢xaӷ;.t6j]M,'fb@̂ FiMI\W3 ?p,̘a<6fœͥ&2 6bmɀpr 9rո0Tx_ͅjlq;B3JQw6shamXyӪLN8G/猳KfPd܁=G2hC>]F IG3\'̠9+Vݸ|?m_O""2ZGE7 (HCNYIj}9\ՃiFp0HK'E,8ς'e&g'}{NOqZzNA|,N5l4&wsV3Y]AY*~(K*VIv"!$2]9a%BOz_tZ|Cf$&8t@}Z k3˄HZ스zW N HEio3Kt3b^9$u 9M |کa=G]BiaČx؎Hg5n?ˇZ&Z=bv,5.QR dGԠGĻ~naYy/[%`KdE%*,\+=[Rkdin |$yg;NʅF*EA +dN,xy3(;)sw;[v":-p}]jjqVD J,a8nH@HW,^۬G"&ì R0(B5Fk>?þߐ^ .)j0Ģ<3_\]NZ{ބ g)-¦ǻ%, L@9,kB/d<ҁ^/GRSk?/:<a1\K&E)NH;u2˱_ vMnx ^W2S .F] /g9`rC@.SP]S,HhQI$a,Sl!*G|[Tr:TcU0 ȹ!K|͏aS$F-j^RU](jZQ+x:ꬨ\AT,c͌l&$ EBXTqԙ/E{,) "ڬ6߆1gm.Wz+ӥ$9n^+I±u˜y)74ݬcJwݶNQ*τ{xZG**E=  nSIaANx[15ڦ=8z2쐖,n#Wd_zANT8U:cF;gc^8ULf-]at9dbl5|zbrH`^!8|da6.[ݍ6i& dp91i}RhS=$08RPeZURATQ+mAt &%v'v>8AWECU*Lese% cu81BsrU]fAhd 81w7,XbE #y!raARsnGkZH լ.jЙ=͌YªɆB×5|W'?uf7qae06lCʗ#X O@@ f1%]d!8jeg/ގgq6VABn@ rɛdʼn lQVH*߿;b`8hf$Ib(VR}L*T=gbop5C} F'f)dC֚ȕhQzx )vr6rv*9 0Oe,Z؊c~ɻ:鄱Q3)ME/FMW mvP.݃"!Xv/-rdB!U2xv Źj./NLN%jcofbd/^]H(U,9ak)eEܔ9#D\s:ʽ晴cOˢtqgWUOc#g {wlT-/v7?Mcn4 lW[Z5e\-F#͝fڴ:+<&%X+M!eV/~1B . /IX0&0 B|dĭg%p3m'eĬiNq1_\|kJ#a8Bj.xP+r ԼIKt7U)UȓJw3mUIBZ& > Wsdf:5-\qVÇ<|V)Z3ŠZ +. #n<_+\r74_gLYt4L3æ*NPk+M [r+4m`f׽n/B ihaj}v^zdI2r4D"X{&^d6< L Wp9kajaS pȽrᐗg H-$]Tޯ_Ջ\2Ԛ\(NxI .')U rv. XgH;u\1ǟ rǷBʤWP5 t$6ݫ| pQgP&wEp֢$M0JKQ!ŨC9rP?% ma|?UuY~U֟.SZ{q wy΀.>}E9ime(2ܒy)*^L\); vHhK]ȹ+?%yb$\!hfZhȁg5$G%7zY:ayϚ ՘INYZ| M9΋0LVdͦK6(psI: $YDS8dXJrh9J$Ի8~E ^zlp϶s ~#ӭ A;?Se17OHR?25yI9TLxIZn<|zúF^f#FgbS-r.bDj`0+lC3_`z-P7)ʠ&C"I uv]iqadz/TV'*LM-'vwHQEj,oUj Lv<"{8ʄR{//䇄8۵V:16}r-VrYB8RvgbŻ0E&y < }V>pVw|9axK/.7|5;TBZUF endstream endobj 148 0 obj 5690 endobj 4 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [149 0 R 150 0 R 151 0 R 152 0 R 153 0 R 154 0 R]>> endobj 149 0 obj <> endobj 150 0 obj <> endobj 151 0 obj <> endobj 152 0 obj <> endobj 153 0 obj <> endobj 154 0 obj <> endobj 157 0 obj <> stream xXMs6W80]|営q6L4S_YSJRqﻔN{FbJzk,|F)%"J- @K; i^o+1H o JoZ_˅`u ҇Gm zqy>eX~HT6j8ÃbM}:OMMI,^[g{?Z櫴Ҵ`ْWVCC#Ѿ]?x1p\!K3vCd_r q_c%wX$sHӷ(馡|@G|E՟Ӧ42"# kB D>UDK_wi 1=mWCxu}jJ JH`H ~3T-=?'%h9=MxC΢ЪsR-+:Jf:uE>?ڪԴ ZZvsR푃B# x#8#ǬyggrfĠi8t޽&W=vSO$sdٜjq/Uq?-oyc WmpH8zۏ\jI"ӛT!| :F+rUu=qd5艍@i̐lHI1bѐ/LmV9~vA!7JZzp9 ]@zRs14fNC9X_}Jx#*z/D5&FLIUa 2jvvQhpyklV۾X0tTD"wt б=Hq}R@Ҥ{(oħZ=9i`3͖O^0Z86eW!:`@ (HeFL#Cp.k  sٗ:%Ɋgh(^{ED2m9`MAނfu< @}O(dxms6̊q/G+) YFGcBcU7É3N 2&+DCe~e"۬=.1M69tt0->m_UFnb0D{8E9==}#5B(OSx^Ǎ1ҋ%{ƀu5UW@SgUˉ $w<<);=oGFA7HDbIoWVNy{yŲe?/xI]svA)&֪mO^>|_l endstream endobj 158 0 obj 1393 endobj 5 0 obj <> /XObject <> /ProcSet [/PDF /Text /ImageC] /ColorSpace <>>> /Group <>>> endobj 160 0 obj <> stream x\ێ$q}߯hHzXd1}e`8xSbO/;\LOT䉪)Z/ZNEFF,\;gY;Wj\$vUӕr"Yi&zfB⺪tey)t ߤG``玟0^:g8%s9:إ܅v˖ΦB eP]ܾ{[nz/?mw?~fNv# 5/MRTYjCHe@t5̘c_׻m;DЛO}/3"5CS jx:+mUcm Ulv~ =MMHFL2ka m_6i78)ETY-7}u!c>ROAۃ>%w%*nuijmmgkQ}\@>V~E=T&aQ~q|x2T?)3Ò4 g2>\xFP,yYr>SO_rMX0υ{h~0dD3,wWk=a-+x*0A-~sIBsa62N8x?Kd[}iap/-ޥe(L݄rJ8jn_~ѡ{<}جWYL$Ɲ]T,l.A.~޳:"C}Q#½{]3z{ L7yѮs{цRl-CH$$^rU`sLoyNVNO!ƄrOs|ٶ_:5j~C[(W*)t;bY,|j(m5d#4.U5kFUz6DWȋp/@=lYɅYf1'~{ur+|8b\*/%r?%Bq;Vmsx+aA6G"s9eϗA㬸\fwiFXq!*y1ٜZZ N5kj!! 5'V7Cf{;xv >0C7Jq#t@+(\ ˍL=l6|ZdIߍUqJaj_PZb-gMפjw + +,~Z_)@B=mÂ[,40fU\Ѩr`T֪+ū?ǧ(˸muoZNǠn0qZ)@.<Yf/h~gIէ9_ӆYDϰ2J> ۈƫNY} H8CAU7|jyOQMJ] ;LR[:C]Нnz;j~:cN=4]piNF03801= P}ȄZ~3ƃ(bxˇ!Ar+v%ė?<r^39XRX 3Dp{F꼼^ T#}Z{ RݦD{}3[A`X?J;푮<.JSn_Npn4Eu2;~kXR,wjkÔdl2 )HW-gLēvp^dO&@!Hu\K'A-Z|/uy':ӒH5g"2Y4䎊Q T,/~Kv>'ta"\UmfPuWWKΌUJJ0 rg} EH}a_$ tO0g5֖ Md^ZߦIVs2搂Q ה` LK[ KuYA$fBT=`GJN/pL(ꔊs$5 x($Ɇ$XaœIB꒫U#$ 3 yxN.}PU'!բ:"J̌)"`$JRnwT7xƬ5FT!%i)R_@[Ma$a~6-%CtVjaD!K.;ֹpѳZ ]ҩ鿨8PMUsx/ؖ/޿=z& >I]L4uqsbsBa)d ZQ2[z >Q+깄' ~Qt͔kS9pM !̮i2Հ2E=ݯ)4viCT-J~) 2ʬ0eeoH[CݙHNȇ0`Z;Ր :/N->&WM[&L-8_60DYHpK!Adi;`rxW4k\QR-c>?@@8@ARN˄(yJ~? ;`~sRb5)I]4Qk_شXz[T׳J)}iRX.I$y;,fB퇧Y ORCS(܈5͊EaIub)av&%V I&kr$lIj&xh)=3WaqVOω{-i:C,C(ivq| a9 *FAW`6]1bZwr?ׇ21.>9RbĜW=$*ؒ-9dW<~SфB7œ(A(&ߒ?=ꢕ)S'ϡ.-2E\3**ʰ~wWCjR00;ΨIEAImܯ'SǸ)j:n:6 6#YYu`1'FTT8| !̦u+8kF-y2.-2roZ(SwЧz&pLc G.hABSIAB=PJ (HgTv87G}RT砚Δ+ȣlkRчup"*]Q GR|H!T͸)AMHg81Yzpj<V@If)F+X!,gkNshy9U$o,[yGT_IJDMO\JnxTa>{Űc!!PJzH(<3G (07Ky?cᕏ ,g\ oB䤪 an=s1t_:?M6O_M¿l >yPo'~}T endstream endobj 161 0 obj 5560 endobj 6 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <>>> endobj 163 0 obj <> stream x\]o#DZ}ׯ`ub  p}(jbLrsj$Qsj#m0֠OwWWǩf/rm1fkbeobk˾ͅiJJy0"ـ0b{1o7 3V۱\745X7XI&{Y -o'1-jd_^ٕ&Zl~aMc˛7\RFg+m/:0H@^7t, ,٬p:@bCe`!Gn&KjLHJk=Oq = Z!G uhr2q!D# E %1 '$9!Nr GrrBK~Δkm[vYև[;_|d`wb"bϣT̥FwO \n[Q>r&/|C.f.jT4l f1ؔj<ݭx;,,+!{aސtm6#S$ɼ:Oݑ">h-G%W{d `CJíPW`x{kN"S\5 91!YY-!&yj/o^WJ3PJvAEMonԢL-BuERLN+WҖSf/N lB)91(T6R G~?B{&3SEҷ FJ~(WWv86P yoi<2.YMGPt~ `5 e #WvyK9,;".|/ť.:^G. 6a?E2'v#eGGOrmI,=)QJ~.,S@ax5%h<QR+OkBZhX4CeP_^95-8s,4Sꬥ!)ؾn _OIQΰ J, JȰv 3:Y}'*VVxTSz5jgjɀTddIڧ5"銪7TTSoZ-ѡ_l1',7S,xrTq xX?nФ\3̊if $4+k R  t EZtAӇ7 QXmԖqXwǩu њpVayP>9 xڙg=lVR}{fj",'VLmDȅ!|+r@Qz{UP跲r-?Pr,j(Jkwa y(͌-HYGa[n6_2%&*.IN9|(]#>BV!|9@"f}럾%S@[IarōHnHix&rBn bCtFPWᒕG6eD)g" l7RAM;ERߟB\:'Q0x> n*GQ h֝<ǣj?o{_؅:כ .3%ZUw/PSNs9"03kP%_|H޵_H> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [165 0 R]>> endobj 165 0 obj <> endobj 166 0 obj <> stream xZ[o~ׯ }Hd?v)(1>02es+.%x!h M3s;CIv,$7&g*A"Ͼ-<"z R`5sFH-gg& kgQOˏ"FB=VhKOxzw"Y'[Ei|~ۃceWc &2~t*$)UB;*%\cWRب->BָH 9Bof**d~~BMhMU~k]jn6z^V׿~wcX)>'+f՛n,Q"+1DIo*+fnbi۾^T/QRxx6d&*6S0t="&_&PlP~ raV6w㦔F8#;7SϷzYA@al;ClM1APN*A4b{#p*Eᢄ ! B3m>5٤1fo 9)Iʜs_6XkREfwݶ:/]*ـ V3L3λժ[S(T@EɨT # ZKQW(aRpW?_]1!ʲ̂ZkLn5ujw͆4r_.q'1s0 %i lk2L"i(C(( 5^b44d`*dJ iRk&S; cmgԯ.RPdT|DR9bq$U!*i]"J澙޶$o5I mHJskk7!|Wlgt_4<`]}8NVE6Ngk!Q-Y:[3ؼo-)IH>_M!vT(^K**z1-qQQ5u(@γԲw-j7nVAcfաds RL1k̋הH( &זCMDBI:(RH Z 80"~w"9Ak|.[a!)ѻ@q(ADIVT)`tE\RiKv25s0ٶ}}3xPq0 /,Vgv}۬ K+vI:ckvڞz<*J q߃os/%DomZD&*i6Ʃ6F%bqr6LeշU9̟ghHJll&)Ɏn0Ycc  ;lӭM<:2B(GEAQT[6*FXŢ^ofR3]-&,SN2Vi-7 ծ}w#$YbR_6o焲x0jܳJ;v;: ?g>+(ˍM"X[0 ~d,6.ޑ,\(۶Aguҙ ̤,fnabl" 1Qq//c@`i~]QrLFn.I`Zv2Mg/P 2FX?slH 3O8D#_^2_)4Kt`[]rWK]C} %KGPq8fhٌܩ<PK3jW#.44^]ͲHZ-hlB3_g.yRةێLV-ۍܼ|٫-wNsR6HH3:dDB@S#&k$EKU) u m2_&2`4<Ȭ04B>)kA!% ij|DMȄk1h._mI(/i`-ǮQ|ǡsaidSTYa ԭBB `2=Jܸ0DSS@CIHcCH7Q}WSdHp/w7o:F Ti^z"l޼o-rMlTWPcLm.)Hv~KD.D:X_5nkzÆɱ_mPVrZ.S`~S~ >+/#zd%ґ1#>?Tt\7]@@堙 ҍ s3aȀWDL`)V_Bm__CpYʖM.zmxr 5-W ~r2ss endstream endobj 167 0 obj 2654 endobj 8 0 obj <> /XObject <> /ProcSet [/PDF /Text /ImageC] /ColorSpace <>>> /Group <> /Annots [168 0 R 169 0 R]>> endobj 168 0 obj <> endobj 169 0 obj <> endobj 171 0 obj <> stream x[n#}W̃ց=eě,H, y#il Iß̩(uG\ u9UVuWwW1F)UH8o@P[9WRu !M_Wޚ:oX?~KgbEo4fjws'X8ηǴSɿRZT'ol Nh]]/yoeu*u-rk4ϛͪ[#)Rv/a64},v sV^vB$cOڽXH;RjLBd Ͳ )XsEMaE _3*!$}. IыͨR%*qO\#'fX 殽Dgù 6<)"\)&UY~bzv7C? v}K(Çz?"'`!1%9YƠ`+^}y9NFimU 6o:'?ǸaXnb#:dqO͚Xd9:[54muӳdXpvvW=S#rB%,Pש/>;M_GxV~W5C[-vh7ǫ#Kȿp rDI+Qa~G^XY, FtصXyJ_߾(8M FKoۦd+&"{}^0)}B?J3%.nV}ϼGitn}]` RaH J5_=Ii6GMb@AC0`kX ]H@w8=#>"\UA[USca|T/_uϪ.9BHz{uN%knX?M L1c&ЎP10W7>l%}ECg5td@`hyv?v]`s]!_#ݱTdv#ia;͢C~~Vh<W P@'ةR~X8 ֨ρl}חI'[duN*s`TF/9Vʗ7QR^t"8fDpO7/Ycq c:``z S(B1f@ :DbTkP`nZqsf1`W:ܷls5J1OP|YQϳF?]aUU[x:C[57 1owK!:l@/AL:$y.RD^X,mǾ(EwSM-Q5DR%[;S+ъR:~{gc'âa{u?OumuI`yz[)bMkư endstream endobj 172 0 obj 3514 endobj 9 0 obj <> /XObject <> /ProcSet [/PDF /Text /ImageC] /ColorSpace <>>> /Group <> /Annots [173 0 R 174 0 R]>> endobj 173 0 obj <> endobj 174 0 obj <> endobj 176 0 obj <> stream x[KoFWp]YL^daHs%b"ZRg0*ҢG\Jiahόչ/J<_W"d5&bse M[PydVW1_ZEJ$; X#6c' o*7pJ4\S8I'63:."afoJuߎM>y،:utp4 ,)MkcJ'~'I*&{!{k @d&O=JL&(?Vj_AQy SH~bq J);%%Em^S8F `r]S:Wo<Za2U>2-˭ ݧ r=Wdjཛྷ#!}f¿neOUvBEu.v'F(s]S0WOuԒڶd3p9ёA^D:lesĄ% ~)9Cՠ:C4E:@hݮܶR˪h)hS7_ %0`Eo߾$>j2d~+Y\v/--qPle\4U.3 ozQ KܵپAxv $`s< {faϲg35CPM7 `mhl`J҇=G~mO߯U_'wv=ݦjZ L2"[1GCtZěhnwxXW)"^*@q}o58w:<4Θ @J}[~s:GQi|xuv|Y7/dջ[kE"GNGZk)Ect (eGH,t d_?O73B0~. MwK߈ W, YBBVnvOfk%lҠ6#O:)mv+D 5{c(yigz p%TЀj~I B^5!?tuPF *l%eumDY(f@!RǦe>J9rx${s%x & K)AY=!In8]L`bNXgތq&GR\fC*LJ()8X*`fk Tyt[y_}5_lEm_FN%zqv@n[J>j<1  igȡc .BVo; -j])1GQ s:D^[zlֹ+qSH:p2J&ސ/5X K*/7/FYt.,zfMӠq$XemfP|Rd2U(cذ369P:i)q8QS[`6|9:6#~0q9 Ĥ١EY2ђD(nY5b_7&CC yݜK K_qhͺ._`6U.Ν@,=}d% ?sDl^OfzXDJI%oY؈ZKtrć<-jږRpӖ4?9T/RAF1e)2X \Vź&w5֕h6§h@ Gȑ6ld/f_rx;fq)7s[XQPQxp+̗옔8rWZ?/* ?}2ex8>lzXbl\O*<ƚn**,,<`bi`ӆw\d>EF}X=N.ʟ޽2%1*LBdU懯IrH|tͦzZ'xM 8\E)E&^,d#| ʠ x uczZ򙽲B-J|++F%-z phܬqn,34 TJqX~_ue +WоuqzmEhײB`HIh\tdV|%=2,,_{ \,Beh2kASWvQ &3YFIBKozá{-ey1]e 7i6 (Yw";}5~ )w%qKۏFi  : Bvte[ňԕ@z؁x 3c:]Sd5#I57#u6~:HO:(hq6"I8'}MB8iO0.g6E*cxVydϋr6}Cu72]ȺC xb_w&vCצ,\yʗ)"A]2QN7?w endstream endobj 177 0 obj 3610 endobj 10 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <>>> endobj 178 0 obj <> stream xZKo#WLցINbeELRWC*g'HUuWGV%<,RQVkDkU?|p*e]Bc8JEpVeq-)o{OYͥ\oB7ъZo65q.9ǸczXxڨ5[>wnyzޯ|f4Q㉴IWbI*X(+χv[mi6f&h%FO{X g^o3ނ0eN]]vc򦄛77/77?}[x\y;/:CV|>"ޢ>OXq@rv,BC*dOk-wݦj@.qR>!$ij:XD-jRgN=rUpʗa5ü(bYw}9`,ABsҸx*8#2;L=!2Bfj.cg;cxj4Ǫ17g ԜYKil9X(&m1́ ۧRz,ׄ,ఈ()a3zrFޛ!úߊh^)1 fkjvyxdd焤YXXܤE64CQeB.VU!05Ѫ}z{d2aw/ظ@M42τ9{*^9BR2<$ro|:ZJ;n4#'#o`CE90l^9rY) ΩȠLY9R$> Ͱ(],D5M*`>g |U}ݮy'HRLxcf .=PA: e8^=VؓG [ 'Ś**[PA|>>wc43P(`@18"I2r3vK?~SIRrWg;;)l. $kX s0&:݆q/Bܚfo6PyS2 $sEb['XޣE{Ëg]~]\Xއ5 5ʢB qN|Fhņ{󈪐Нsv[ۡE+Y 8ݮhX螅/DdKQB ܬGCa3WEkGErq)hJJZ"@YVѫDo9JCqCIkn4&eX=b'?oʑ oR$%! JM\’ tұ+6T4RdDt#Qv{GuEbv]k\\:CRשvIu4~G@@wzˋKO.$dR^:W](ƀZ ӥIc=Ʒot?EC-_4xaP㷱eHLЇ_ޢwpjehz<`e u2/-=ejT#s|7]lY< endstream endobj 179 0 obj 3052 endobj 11 0 obj <> /XObject <> /ProcSet [/PDF /Text /ImageC] /ColorSpace <>>> /Group <> /Annots [180 0 R 181 0 R 182 0 R]>> endobj 180 0 obj <> endobj 181 0 obj <> endobj 182 0 obj <> endobj 184 0 obj <> stream xYr9+y†/>N=ᘥg:R"Ru, ZED&KFRŇDf"(%s4^bF)%BҖ/[ʗd,vLBD*_3oLj|,Jg͖GjVp\mR=+N)O5^ &'p5{ћ\i&dqJlҿXaBIG,VokY^>~BٕN۴s\v6AKmމf\rWL^ʨWvҍƘPH~u_$~޶ͮe+a7a6{DYuG' j< 9JQsR0nT_mcHQ棍qǧO?+q>&j>Z#6 fv8ႝ!||{O~x l;&2iD=+:{jqyK\ARh!>HW#F+spLaN(/"y<< Q72k%L@Q.kwԪ$Zfw}!5|wא$8>9/uH+NQykWݼYy^Ȋ!EV0iT`XABB`w"i"fBLus*kXLR'e( m}_JgOO@٦%VLJ%W:vtB9zYZ uk|pΛc"%RO@pZk2ô5&{t11ʴ'eP(m _ t?avJɈ8^ {X#}zWtB"]Hgٷc8XmUXϞlh]Y:qKO! ul%B茘VQS--0"bbhChr<;E!hݮI!WE %5I.hrUmGrާ>3F2?Jff>2\;"Ҹ +=pC,)/؆c*(l\]R$bWœ:rZFc\ԋAq4cQ;ԭV=p08E1j쫍C/Ì$LD+1?_>~s?[Fҙ\/#P!0O<^+ 0͍McA]Stt +_ 'G%YJ b57OB5C1nQх0 ;uh{G!gj9(l2 ,uDHy(o"kL؛ eP Ƴ]ɭ$ ] v;FQ~ Hj(I+daμ곁M {<rG;(BLF~Zxq8ʬ(JePEٵp;I7Q&2/{YQM{ )߬mx&!dLbmtlh3ATbJSNӖz<ój~V1̕ʪU\)0_L(8yb6ME2+㉋yį&>A+״x:XklE޿߿؏_\!v;Y6vصOo^Ku &p7u}evsq:&jR{ endstream endobj 185 0 obj 2375 endobj 12 0 obj <> /XObject <> /ProcSet [/PDF /Text /ImageC] /ColorSpace <>>> /Group <> /Annots [186 0 R 187 0 R 188 0 R]>> endobj 186 0 obj <> endobj 187 0 obj <> endobj 188 0 obj <> endobj 190 0 obj <> stream x[KG(bUC]xa`g tX`4A5"Y&K4ɥx~Tm7_bnR ƴmEkj˶{;զb"*[&m9~S~[o gOOwKΫR|U6.U9Q W^UQ&#\)6h"B)ʷ~F).D( + no.'%_6[U) ^+|U+&5Ts gg]W6 eVoSY|b*9`0\՚O8rׂ K'ՕQ w5c׶ڵVwGFF.?"x[nDw?l3ǻ{qX//͇~1<ik6ePp#>tþ[\ֺ)9#^5.۾T 'ݹ7~d(ex= z9<W3чa5?5] 6o %nwj`u|niO=6?sl~L1-V(u]W_>/Ey#Ӌ?ܲ$U1˓m9m4K]~-M.ճKoYT'cVE[LYVi(AluǧZsYV?o7_݊IYtts1GX5 k&?B@!5y Nis"9}+RPHtZo˻Ah&;aH雈$"}W^ޤF B>p*%t /& Ge$>D=kb )XW'%bAqddM.b3.`ں0{n]5PBT2I2s*"*8S2O stc-=^%8eTI>zN i(/JIS| ƺ$qA7ylaWH%%2dNYsJ+91(qc-q!L,-frЎhhB ʸj҈,H^.EkB A z`v \r@BnňrOqή\0?7TDuD/:3tq2ηD012Xi6 i-BTkiZ"r:"Ƶ)G||kƸ ?:1ЭRe?0ZBL[5XI{J, .$6znJ$a"DbTF*ĂR1fMb!wÖyl%a< -^𚃠"&?($4[~K'fUPG Y. !Z7{RZ%+)2X6rn¼$i_lɶpI:ڬ8s3MH//"IZOT.Yβ0w-tKkF,b%M\ΪeL=FI)mݘ5K˖%W6&C2JŃ_YN,/bav< >#\0hQYeNÂPk^)h8(sdifQ,L!H1'Yo6Tlykf^lfPr*sjIÆQ"" a"R}HjF@msĝW7X3b o^]SmCM^KVKKѣz@ae7  B8NU 3Rj`vXؓgʶ 4J",puA81DgC-@b:,Y"6͟5y`Is3p12=gkl7%AlbbOLxjMbtKLM1K^:4H/Rou.,Eh HsvGD& OI,ʣ`8Q@h9,N:Fje0"^DQ|uT@HE FQÜAY {2楈SRtjb v1 2#e WoO`TXdTЁI+Eф7 x9 x'iښ0>}_m&0j3uyy$ c4; ^2#3B (`'n^Y@0MnV33܄JRܠoDaƈM N\ګEKTN앲{wݩmev; Z 3|*O!p^c,!͉%`Kj(p`7dZ9LE4P|?["OsBH)Y˳ ^ǰv  P.^RX-78e⣗؊k]#yr SfDPyN3fn9/O% s͓+=kf".,{x$_YJhKMn ?_:`DJ\ZW j%U@=wаOJ<SO7F$^S7F1 )`,#X'` v;w$lnF3A5fCZGXb@@4μdOԑX8#.6şk!R-X0CvY>L=oz`z͌-LxԢr#P)p/ Ex+wÒ5z!04(<8ե5#t" h3"kLD4~4Ɨxc1>W7|aP. }36nRJBP0mu׽1-;Lx|GbF։5~`C*8'ۧDYi"fx+ٮ{phzUfdnDLσ?̍in4I ~~bD/ss['FoL0„ \~ /.'N3/g%eLH78z9imٮN,)z 2[ue1cUXMaq_~&=) 'oT/ğH' vp$dv7@(!?`g҇6??[:ٲ_^пݼOϯѿ.֠ӻȲߝv?? endstream endobj 191 0 obj 4274 endobj 13 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [192 0 R 193 0 R 194 0 R]>> endobj 192 0 obj <> endobj 193 0 obj <> endobj 194 0 obj <> endobj 195 0 obj <> stream xZێ} ?ed`ù  ę#J|R't(ɾ9]]]}J:G㫻ku:Lm^J)X6Պ~,5ub3g6~|Y<}Z~PbyjC<ߤxFU6S[?f[;+y9qi LɅƅ{KJPJPksfo!*UddF:EeׯtD׷W/l/57v]5yǡhM׮vq%v?CT'olM 5vX=^/ &KA[ݭqDf͊EqvsϥR84><﫟G~~D3cUȱ{1v#s^%;%_EZ%l57tX^X38/D&Vc`u& .]ɸj_3.&:WqX]びlrI>_Dk;Ok}hHh/#t`@. p $|9p$v8e84Ds*q.Ck/Fs1<#$jWOz_i13mBZ?y#/fa.:(R$* |6(QVCzJ]RBחr12nr ܞj5݂$ա:-FlS5r}_):يE$2jk6Cdb;ᬦzml:[oxF2*'C&eZS/7Pzzzs,Aض_\i^Q:8-!![q J*ͰڡYR07ooU66ʜF_{9l6Wiʉ 9$-kS##?Ϗx`0]]㨲Upg ce5B Q$j<9Vo*su],n5'yeuCշͺU7殭^ jv]=QFhk(uI%tX*Crv͂yn9Ao4tC=+S7bޤS&ziم*ی4Ƅf轄y c]we7«YY,xၶ'M´7MϜf!hĄJ)k7,EYLq [W[+Vp!>An9KX#aA|C-ONefji?4+h"o%Y(1׳0jȥ|ḼtXvnqJiY W:PY9{:jSAk՜_͈h9R\˜Ag@`o-O*af@R?#7-QiZH#wDTۙrr.>=RB&ӑO%ޙA$ #LEfz1H&hPɳv-%IvcS *Ăl<3gEϧFYF %>QCxՕ>RN&cQ| FrEsa!)>_>ZC0{CAAE?k5\Jud+GNԹbV }aˮFU+Q0ݽ+g0GK{d} |%-p͊5P8fd>e< #G9%w v`n^ Ё4;+&( GsrQ%l=X% y0G6v)6pZ}#M0T` 9%d[^,7qALD~@MLzcCC7\~:c״F`vA@qx D6Z`X_j3F1; M!7ghav)c6gO9Ho&lFAG$Jhz??*6ۖM˱T5}O)h()ka Qku5W ŗ?g# Fx%*Oq?V#8 d\jfҾPċ5Gu@I!CTN䄸u=(r+>ѳ>ABY /*mI 9랻bjߙ<ֆw9sq8⨶y]}Δ<2l0Ưɨ;z'&5cP"(>R f|y GkiȎz9dP^(?5CqV kHc`JYHb{%zd.<# :0eO7tQ)"eX9ٚ>U4qW5~A7&XbUg &ή^b3_a(W|<xw`I~|p D!p_MfRW{i0T endstream endobj 196 0 obj 3276 endobj 14 0 obj <> /XObject <> /ProcSet [/PDF /Text /ImageC] /ColorSpace <>>> /Group <> /Annots [197 0 R 198 0 R]>> endobj 197 0 obj <> endobj 198 0 obj <> endobj 200 0 obj <> stream xZMo#W 6nn$ćȡ469p(ɎW$EuG\ɇڳ_ꦪs46J;Sh\弭}ךc^,xB,FiW/`m1oY|X ?>ewEo4fj{S'Xl? [^Oc)ϖل:Ԇ`@\|s #TѤkzqVZG\//fX]tH˔f_(J9xl6]sjK`HmJPJ2.ri(0F:X#lZ͢oKӵJ5VC?Y2۴vS°Z-`0umh"8J#nWM*aii]"/]xWl/) }1o[`U9":6}9o) et4w*p]۳ ̵c-sNވ&2ޓ%ce U7ﶫ_Y¯!z}vr1JW as{vMwVpݬٶcMO,o U7/XXE7k:FsG#l˭gk:YH"80uqsֲH8k}׳qVX&rȫڅ$Ҭ1Y MXRߜҹ%u26Lo,\zv+텋Ta|EDt&z1MvbY%.N;jzLܐuvZꀭ  ̇:w]3ۿ- ge|ojXVǣVq9~EXZ% 8!E_./]5lcbfM r2$B;ƠWP4Pj<D4njoJ5Rd: 4"^jv$afM߳3")n;qwCw5̻^>ӱZyc}fʖ9|6<1e>n7SN~ѵ=$yprekbZz)mH£:~[]plp0;frP<4X,Ë@D@Y/oaVsbP2Y[Nmɹ. d;Tnk{U:{_m UW`Ͷkۡ_vZ&KRѶ;4rޣ n0[$or@w m)^},xàh[9g吖 U30̓Zw HARqzՇ0H7@N832`\j4Grg1!Hb nr@aμEےI7S$\.nj 02f D$OHk !v,=Bd4-6=6٠wVHM[~I,d=ɾ!FDsi4>Fg\fh"4 ݂߬hj{aiv9B:c 5 g U%#D t8~,eV9KZ3G+& }y ;d9ߖ۶g6֍@6=;)J$T.C=fO4NB4rZ^B Ȕ`X3Dᑘc9doX4PV]S1,!7e,ҥ+;㞫}U~Аպl;xvoj~IG[Xt?VH8*Hm6]صrCEf{ٝ7̜g5Yh ٙ@Qtkf?]xW;$[4;ܑ+φ;7RDRYRn83:{!zRR="sk H;&X c#1Y!*|Z+h;֩eUZErtIu+x̓Cك'm]&̆6 u5ͻJJ  '&nǜb}02tJ$Iܞ+TbϳTY켘'Aۚ9F$dT vUgrdI)I7 iᨎLZgV ޚ>51򡟋T-<->y=888;PBe<OZ!J+}.J6ĻmRBq CdN`b(F([K{XbdvNecO~(0kzEY!AMf?;[|C'5)gCfadYtt".-q9nWSJ;C}y4h?-E {NW;B f[TEtM吗}NHfQ9䤣S!;Y jsd%uH(}Pu%[qydYIz#haUVD 4(t5(a4 tDrg]Gz'-[<*!O(%.0orV[F/]"#ۆxuGYHbyҗ|a"I_zMbċJ.vR:ydpgV ae"7 S ^ D>=^t|0c9SlQ5cԮVy8t7v=z U7/j7+W~?$ICsP*op=y!eW*ا Y|\z~" endstream endobj 201 0 obj 3173 endobj 15 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [202 0 R]>> endobj 202 0 obj <> endobj 204 0 obj <> stream xXIoFW Zԓ AhJ$]'j7:Hymd[bd=1pNԄ'8j×:1ꌱ iz=[uϘόwϜ>yOǏJ:LP%ѳ Q3o}^=pnǎ~ \ ) S zE2]^nj8PaT8glV]9AɛU4yC>uS$+gceg}wW_%NNDryt3Б+%45V٢1`Mt7zki(VEkBs*p=#Y, fHu%.e;'Pfl%&菸t2-htHS#mRLv,{m]Xlyd0WqefqHHʽsE"dafOyRJB)b${Q1cwQ.bWY#1ĺIbR$ܖ 'ŐM]m-_CIk:k̪hZlҠL 1F9scl:-POXoV"k (՜ˢ!iiيY"EI(/fB`4۹pwC>݌+%yn]'|qu½b'w*s+G>~EvdKCWx,%9\:&ēM&E.gS/^xjxlwQ9Jws&m2J9йγ6Omw*r!c$7{=0!x7uy[EwBuч8Ix~ gQq]d g*Se;*gYB orxVɈ/3>z"5A" l0}zeCP BZ7fRU<+I[oo}܏PgSωnoÔѐmaB&17o!V}`a^Ђ4`}紉8xPs|(}.Nig MA7\bGnI!Ҟ|ZaFϨeg19q;re9 s:64D6'EF5bY ɤ˓nm2DqAe 7tt΁ /.v紿*]#n ϭ<\˜g`C'yzsIa;wZ[zmPB Q B6i TlgF0ո! cKuN !@֏$Bq9C-? JZ!P9Đ<6Xü}BǾXʕE)dQ!ZVTDN  nP tà ΁,dX.)1O!PTOE | ^Yc냴 F endstream endobj 205 0 obj 1681 endobj 16 0 obj <> /XObject <> /ProcSet [/PDF /Text /ImageC] /ColorSpace <>>> /Group <>>> endobj 207 0 obj <> stream x\Ms#qϯ@.סiL>̥l@~zFvRW]YYY/t5}k1 lb.}_G?ÛzcRnFx,#DBLht똖pJ5>1ٕ.Z, kn޼~.׷->Ϳ|u&@^m~ܬCJp7Jev0la@-53t;WmWBV.-$A.IכRѯ]jfymWs| Q~ض KaE%❚oW \T˟u):R74/fj@,W}0bMh\݄.S]L 'eժ.ѯsԎ y{㔰P^rG'If&4M,۞6FExۥ2EpWo ǎly1Ӝ=K̪io@rR?mZ XvOu@ 1Ed?~ޞs.sgrNAp)6q e 4@S5R|`A_/9)-շTb]KbR,vfA vI;|+y0fO6Xe,D͟x$jӁHXaPt75P1U%G0B32ATq$je PA:ҕ;\CU82 W]+@"A YS-٫b[c̯8d/d%g;wl ٬~Mwo F|ÏT@d#'A9󥀡5nh1AĶI=YnsĹo5 [k@kP2|'Z!h9j9d9LUCmr)k85;Qn`4ٺQ]W DGc:BLY m\/}$шQ"D+̄#]C%>UuTƱqD 1XȼDn2nUr!%mjS0Y$MN!hdo7v(Ac!_>TI ";jqRIH{ѭFY ԺUUÖ]B%#a'!9E~^d1D{`mQU{20b0BIj:jٶ.(p7gՌ'B#S/ ˡ pD{VaL 귛@|k, OjaZP]Ħ[XH L=g; NPa2S!t,ŝUtM p =xصKVR?v;DIi*^^6j~yhS-91'#XJkC +Najtui66+% d;('ce86UYNI> FedD>ijAuw9*P /10˛aՕZ5'65YsWuEdSߖ0$ j[E$SvJdG+ABٚݒ R/pބj)2e*̘Zš?3É88m {8o +3v`jpxΝN9 xT5z 7 2$ԄL쀷  WY=|ĹRyNr .q$RO?zyدN(aN;@0P5jh=HB1RV$Rfa&F59-)*+zi 09ACF͈ЊRRKQBjU!?p!þ25@+{q*~H ZRq '3G%6ץ^췭Z2fC'$ic?ń,]S%U9@axu) Yj<-x)SJb gFl%|9pd _} #BzB}Z+ WHe%ʰI;v8~pݨ꼈L1E';oc)AgT59n0vz_Lb/ÓI;sE[\Q j10nLuȹDZ _I9' QҷDvRƀq"_AjlQ9g`>: p<0ꮄ2AR; $IY:t!-y:ASjҘu\E]k@KFͧWd U ܐMYJhP[Bǻd|Q ;sfKw]e@ Gh0-ʔNU!@t,/\jhPjqk^zyL+spx@¸f3g4dOjG;5Yᱸ7E\տ@ ƌDHZS&jmH@ rZ-̔ '9Hs %Z;2e^vċn8veDHNv.п$.DU"<^mYS-_rڏ9!-wNI]JtpeVCeU?|Ä<+䁒(|~iXd0j|??3 M <Q=-ԅd3C/9Gsi4T1\\ۅPrRo-+uT?TN DռWRI|(v1_+F]HvymlKSëOIxe5R%&{U;&/SU_lMȢ:K܈p<6Gξ7 ժSC棸 z˾3'V>"~K Tec;`>^R =k+EB :W'A|]Qqx|I:o$&Hc1D؅[nK,g8WkKj+lN-5leYDCai1+Ͱ([c+!dG%ȷ"_#s~.wS68taYByȄ+>+ !D\>f,shF:?̻xpPKR(hrXBz/O?ֳ endstream endobj 208 0 obj 5164 endobj 17 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [209 0 R 210 0 R]>> endobj 209 0 obj <> endobj 210 0 obj <> endobj 211 0 obj <> stream xZKsWL9*V~YQ*UypUXkX PR\fn, 0>򛞞_+W!UZJ)ʿXg*QIU)lx%}(V+_9H͆g B,*GW{%zVGMgYUzxcGl#xk#G1ifJUhsU㤫)_hVh\QAHY=awawວ Th"FZ*sHȣln$e^'eSrAHՠ>4_fJ:9 ^SQe0)L `= (Z3yws%XpF"Y8QS 7V C!Z^<I3mE ]LZs㈟~lU,$_}eyրʠ)kiv9ɗ1&;Ո(gըƌ1Z;s^_B S;BiP` U]ŘΪq`{Ϊ#:XǐGSBHX!g]`rcg$HlO| F=WPz:ElbՉZki}ע[ Wxbc?蟚I{N]X?r,spyXb'1tlz2x4xͺ'rӆ(aRa ac^ l\17PXЇvD6xXs68cپl8vP8H |o3L 恜??\Y"T\ IZd>Zsb=ü/L6?ÓnڼmҨ|P"!;F2e+D2D35SR05+%n٭1@FxR!әTo*4GB>"*Z~e5ݤ)}d4+䑖j6̵ ް}ӷdPH̆hksL-y$DfUUU?XAD# lz݁~?mzWQ/ֹ6b^.I.`4Y}9ZN`TyR,E9I`M-ɾd@J-ʓFs;#,:>1T6L1Fw4EAt.$1%Ƙjs]0ܲu2EQ݌{xx}/>^e#•_ t9~66wҕc,NܫpsrIp\[ 3 A}!9.j7K([Fgd?@JmMZ EvwB$8Lh>d=3AFx IGݏsb~M0D:@xȡ|=|tW]I$[krJ"(VMBb#w$h7IoGQuƝ3|GU3F{!i-([/z$}h$3 4q Ŝ8I3$=2!;cCgrAsX]dp=ǭW;]:Fq146 focFo}>hGӏvT%~ޕ>y/Inn3> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [213 0 R]>> endobj 213 0 obj <> endobj 214 0 obj <> stream x[n#}W v_ց=Ey8c0F"m#pHi= 꺜n:GǫkBV_u~uWN!b@V[S'lLX?|LG c"g4flwcGYl3V [c\1;ɜAljf:?hs3.YgiD!B:k}NGv2̏:Mq7tC;sDƏlLyGS M͕n8Ny՗b57tU7\fTT6W8Bo5ݲmVm9kjG>L;lÏuXuu3in6^j6]rXիkZYyuoJ['dr\1D4wڐa0[iuE1 ؀7I3F1f4c85l8*lF rtǧ5%º:DQomio\[Pfd։3`2Qg2]MqV:c/b]H#iޗ@Bv5,ZG#[4s6)8ck?aSF'uS(2}0t>{k1v{ز } %,Ea9^&ӻ sF!הD}{b Yؖal?ƘmD_DgSb- Ȏ ,_lHmfa MF*ki8(++qփ3I_B4H'l/ W +f-qWd1vD֫2#ER"c`)#l01"e@a'z5CfY1@ r_̼5yA u.q}wDH^DxIl0o5P|Niۙ)ʣifӻQ_G"Yu̺UIBO #S(Օv7uC nY ~z3imE*"*HIDx!o29qҁj&R~ +^ `-=(~& _bJz.@o f L`#}߱V񦙱LgvZ? %xM(o>2$I^ܷNc)1h_sf=NΠ͚ydLט*!e!b< :CP}~xBԜؑ/#2=yוl4V,8Bm2/NFm>`pw^K2hdtyhkYS 9X vZgh8Z¬z4YtFuqwpxNCmKe=Hc-bI;ʂ1T&nNDR@DfHIf%Llc_TR=tgI]R6 %:;6/"Gg^%҉s.~D˚d>Ul"{@!9 ! wC;Dye55|y!YRnP H[\HTz"~50BwT^(kKeuc' גڃGW뷢OV ظhr7c%ezu4M`H8n`\AqH4Ñ灪ȡjr}aL[K~$սg^%D٩4Gy'Xrqd[ fпvFœFyKb&^vp}''~ѥ#_taOFLt~l_ژM P)U1Q|Ml;5C=~t&O ^W> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [216 0 R 217 0 R]>> endobj 216 0 obj <> endobj 217 0 obj <> endobj 218 0 obj <> stream x[KsW䋜TRN}HC,\n }BkIv.$NxTaD¿OwRDC6» X9E$V7o^}Z$nq>~܂*٨@9 O7  Þi쫋p'o>\?;]<_ 6b&5k/ ՜FxBGL Rwǃzbu|p([|%K$K1G\k D<d)Hl7rYܢ;G4^d5Tr4ѥp#DӇ>4r:(rs)}l;yA½)ڝMgN$UNNtkNk n'\@|u(9xN#j5ؒ篊;7@NPC* 4̘ÔJ cIxbg@ZBp{l׎ (`Yc(WjYdbT@GE7Ou]4U\w]q'*dV$*? {ڪc0kZ+ԑ%r~zdbxKPaڜ /.^e(Ni`FݿkH?I+`,i E/Xէ}!4お-.N*qPi_FC42&5e4"jaҠv.DIuT"/sK_Ld^A_XA0λIgQj 0& a!'Z2\.'*7ly&2@l3-7 a/ a*Rd[C`c K H†bfgʢEriil6" N@(&/(Cp9c/Ԧ5mjx4W-[ҥ<`,׳EU" XRvJ؃010gzKtXhjT"}q}af(TLPWIk3J۝CbŐώ8NA}DTCV$ktqmJ 5l&!035&ƒal %3")I EzÛWL3(,(+)p/hlph20IOUܛt9Ma }-uّN@ud3ɤU|dSנs-ub02Sx3|E&8Q(]bxѥ5-t~US5"%J+̲`9hTIڸwldRXt|]\s5[XjTv)%ê%T=00r%&&IG!fs /} 7?0,H"  Ec_;x?j$$G׊)`R^k8 2M;$'2ɋx9?(b7k-mz'#sH5!W(k/a9]MFg"5x N\fzM!8]{GV+`&O; glKr͗ӟ~Eu$+15LBb˅%̥\MwH 3exUo<dRn4e?cK`".t9Y^ P{&:@)gv.s3嘡#mrE pUR2un_#'9.~_a;Xջ}Qgxz~-?cxa\qŮ-wnX=0xU]XF?Q& 'nhJBf3ѺDHDlЕ'T3-) ulw"w/_ҐT($%!ՌBj [}b+^TG! PI!),tхƇ$ ߾j)_i)NiԢ(.lEB8aLY۶̔{]|txÁbtJ\P !z;|^>]-! SŁ0b;ekT4BdWä]!uTx-}z-?g0JA,MBeY Ħ~v4'" 6sٷKweT|jeBѓ .B/!&m/V <UZoZ6#yxa! (dސoJlMC&E]6-uÐ$L"bQ}'hdO rx`@؄8҆ѝs&nk/h$\!iu%T8𤠘;pʥ,RԞm$udVqk!( 6 rliu@m0%|(Z sNZN Uo6ED*jfuZ}.`261)ul OkTz_5ݴ| Ύ? Qfy8c --k6KޟffOP endstream endobj 219 0 obj 3848 endobj 20 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [220 0 R]>> endobj 220 0 obj <> endobj 221 0 obj <> stream x[MoFWދm $`C(c1"}_>UuK9_}6J*$U{}{녪Sm[S'm=|S~koY|XO2:I?)ьN_kaq'-̷|e TC?KL2:UfuqE[kOv3FLӷB:Y'fggRʭ+?-m>k!HM -d:z }UګZ*}JWlq {k3dqc05clG%/iȳlv|ӾܖUd%':$ ܗ !Ura]Nf,l8s mW݆kdUc&ҌVAI)YYwM mjKf3DQ`qҷ(3Gf_[gpȜ\;u13.5|✃Ag bw㶛uiR|nXarrlX0E!pT:(ooMkg:a slWnھY<!g/7H(AGB(&s۩{!Ƕ7Q&}la]3<\9+7lvw|m]vcQdYoߵf1ta3$]oY"x.N/R+$&pwdҬH9aϻ}{_@V̶*!Rk u.ei6 K뿮nֆybh2:扈)!ׇn]*P!>2erB W{r09^(aɃpJ^BƔݶ,*8%)mmus c'M• 0 A(CnAC$Bg1ݪo-K B8#۶<F7Vo7̶VSҖ»a?HN``yDC<2FXjK.h\-{l)w8QjÆ!:Gxtx(CDt}Ӂv_녑9<HKF@C P-G(QEddflDID>Fbu|Ԑ"--#?EgdS:;I dr+>L=ı#(1b:nB2!^8n.3M^{X*3Q9&a0Kp,BkH%%񮻹/D8$u9n h(0یCIlamRZ.7޲*d8omm '5Bw ~Za arwxx{ d%,JzMTRYaw%'B0};f?QՓc8#e˵. C܎|ZYG_Ƕ=]k.CIm)˚pnDePɫ_#hBF2BRXEt,?v9NhDdJ Q" =J=޵"ɣKAؘs-KvMGCl]pRA=X ǧm@IZZj(1tM6\H2Ɏ܀i5utIj2~>|4)dtv`"/um4Vp伀\NC\{9x 9ZQGŊc.91_l i5y[ E!epHpIKs8ؐh8M[k~Fmz6xM73mwQ)j1;$RFeXA2X߳ ƪ ѳs.U*D`ӡRrGAldgM6K2u?M Z~8n$̹Ś<$P)s~a,\[%uEkALn >~[jHa%ɮmFD" q<h$ ҽhL}Zhc9 E;%!4y0g8}%:aŊ'|礲Q-9\OB}YD9EZ4t`Ga5Vd EI{u T -+PFǹE?sJsY.J'w7 RaDGN7}T8_j"Z Z;T )dpH%d!$[H -X3E=yxk\P޺2F.0lY1&3δVR"&[; lqXrYⰱ* ,M/85XwSw•'4o"R>XvFVSYb%/hXnF ^9zd@gT LX^,n[~kC呆6K, Tۯ~Ud`= )7QOۈCuF)le1^ QpF3qS9Z ZWԌ< 6y8N8PJZEL T=v͇͇`==JJ DIp4)PQ2Vߕzעm␧IzC^k^2Q;X\ܔT;c3,tu#yudOwC8 4A(>Ho)u"O3b"V!z.L@5ЄH)QMbeNu *Y>zT9b^]0q4eVⰬA7g%@%.r2_YVm$2Ra}{{%DVdclh%f{xW_%9p32OtryZ,d)h,k#dz qf],-T q H$cպ]w'^tP.xLخm_K} jzPpw2`~!)I6)w"bS&G=r܉H-*`5}V->{#yP~ EUSZxxe4Ģ9?Q o*Kv)N O۷v\>.]3ͤQjL /z/'lg#ߎ_ xQq^R39آO6w_bi4ˊ~3 _dС_8vZ"P'M5xWSZY++]bΊUI,Rfktd)R\9yHxc|5UD؏=&U}iUjm{ |8z{xڡhT3R_S$C5@Źt^nz= endstream endobj 222 0 obj 3700 endobj 21 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [223 0 R]>> endobj 223 0 obj <> endobj 224 0 obj <> stream x\nIr}W4]S5yo3c ,nvݒ@OT7QŦ`ȸGdT竘k\uQW:l釡ӕS=xԉ}[ߔo61ߒpu2D㔮.HfTuvmqJ,]3&>raǙ}S8ǚ#\(AɩX?kK# bNߊvLixPU<}ٚ)gc:kA Iӕ1ǀzgc M͕*&AՏlU?Fc#޷ߚǧu 61qm3v[@A>_kGFǧߵ]{Whf:Zv3Xv&rC~jf-[eY]ӺX%lLu[u uUb DZDLBUdf&єuR FP]/˪ٚeOytXPH6RVն۬jVw}_êժY?7U6wV'ugh 561;ga 2٤.#9T_ mNl}iv`0\gNG.D~2{uNY0ikJkЩ9g#joj-'}ausRmaA(uw̰BBX9vklBP5J]ӭsʗ|L}%}Z)Ч<%ô&IbyP.)eg9)Cպ"Bd+ґc:>g;0ky s=#THj͆\]KuJV{'wws <%4]=he8z2Gb ."eLC2y1ajt9tMk('R90YQM^|gҫRG(ǽ_O<ѓl  ׃9A?NpFeNs1T_DqRO~{z&Bcȗ)XR0Z=.HnF.4$#( ^8_Vfhtp 7 Pedy'ojVJܼN*UB?G~>{jA2f[Tm&eA]ЌQ 0Xɭ݁jz灋&ʐ&ʠV{n*M#0H%Π$q69MQK.;8~ǦYrp &Fwp 88Y`ospr-%vg<'ƾhVWlFWN8Ә\<HSl?2P n?lU;9QZ'4~Ml34is(Yv06شC]+k}um[ s*{Hk Z9q<ѵVV@'h#_8aМBXΌKN\9lѡ8x {xJa-/Sszc°66fi7,Zh^5IF%π8]ͬ:p5QĞt3: z2{!iTEݗv傩㼪nAWU$&,UUP;cd#lhƑQJdpby!r؛'_1\ ybÐ+aZI)ꁙM-4obf1ڻ1~ǬT8xmљ28ޥ+!A̱dTt0xb9< !8{coEAT{S( .솎5k Eϣ:yeJEp!n(7}vɭ(p2^vfâ[dYd(5w^H@ Sn`BAʻꇡ]J'ꌲC?LGq/1\{W {%bXi?<¸2^Cd$<6J3'e"Ki,@`h~2&$A5 Rn+A*Ƹ95˕R ɵֻv^W` vOMm*W|um!oݪ:?t _gC Ӣ񟼻9bz{pl$汿;qL~&e?6 .ψ*#CE\ZDRAyBV=8N7bDQ̲YB :)t1#{D1ͺs(r@u`!d2_ӆ'A+ J[L I9LE5SȜnFPhn]/%pFHt3DzD\IeFPyWe9@ײ?IP!qga^@i# Jɛ'=#4Cq"'e̳ڒa v%B!1q{sÝoC#x\$X$I}Go;ިlΡeBr>CY?|C߈VdJ.>#d1 ALaDiD5Eȸ2& <|# tL`31ߚS:$AW**=j )SGTGZY#b.MJTp(n%Pvt e^Է#};  'W,ZS > t}DN_Om@!-z_dC#@*0X.PaJ=.% 㨞ʡW@}J{+rU]\3f P|ySep}7k]\+~LHp #/cĎ)ۻYOݷs͝\ynŇn1pKr+$緽gyǙd\n8 ^ݧw%*arТ#9oj9=|߰[A'^[ftcˋz CM8Ox'18{U4^ ʝiB_8hڒzf x=zD}Z^ {FErjx ./'8׃Ltы{\kkItzpHnLNs[ׁxX pO o;TYeYU7v_BnjOS= Dgi6-K|c0d]q 5鍂9@1;87݇a) endstream endobj 225 0 obj 4535 endobj 22 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <>>> endobj 226 0 obj <> stream xZKoW4O0crڝ 6ًs%j̅,?eA8rf@hsXT:_ȕM9in(:>xAV) zv$ #9oS*2-3nJJK]BS_Ytr_9]IdY &:k wIxzDH+!\Hg{^/S9A`rem2xfe ~FkZf$E7 H{%s hq:)D3YJ晣}bX]Wpe"̯K!U%9x4&YZi`*}Y$*3 +290iBϜ5IH|MIΦD0*[JkҾcOE9"~h5o2N E6m ؅ɝtG&7,=P.}P:HXLƅլwRU{GbQ" lj!cxOKT%;tFRXt`J(Q!-%3玒;R E"5 8!_RڣqRUFf\üA=4 63cTBS_mfoAc +Ri̬zGҘK ݻ#!ʡN-̮s*H%baz[`zNS>瑩aHʚMRWFk˪[v5_ǧT2Uq~N`uD1XO` ,qUlœ/c2GA :oתB &|~iw?+-;Pe$l6!XRr.ee|'" /A"4= L_EiMYcB>oGd6B쯖Ү3Ioi3ʸO0v'Dfʧb)>֩>:-MR}{Gld<E&ԡQ v t~Jl.JA޹b,YYk7|DrǤ`--  b"K!BQf!Б;> ["U*t! ׇ"5\$%ǥ>p(/w5dw 8ĵcʡ&I p)>%ʆ!ee\Q BJ ]/QFa!4H՘SsyeV4Ol^Q9ca,*jxN^ xwm@lÖًa/D.^q m2%v6BvI ٥p0>Fl͛|v>С 4tCn̸>t{eRqЩGgvi)*-6iEZJ=_ R5@aC>" l?ջ32"/M>Aa¸^BJv'_0f-/B—}?,[ endstream endobj 227 0 obj 3110 endobj 23 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <>>> endobj 228 0 obj <> stream xZnF+gtWѻ' l ,eV"%w'ȿ)RuKEYo,Sn~М'Mt8Bb6~V1?to7yk]r)x1J2Og% ٣bsx8ì$"G΂$WᲁA "o rTO`[!hrBvGI<1g,> YOt蟍HM 6Yr ee˕Ԑ.!,f` jh%W8Z{PR |[mǛ` pyaՏ]yX7?sg' 6.Gޟ^^֫EM qINk~m,Zk,%RlP@AHm[gH+vNQ]]2ϫ%,ss J((%{CA)C] JIU YwL$)E)V"zs#G#;xxu V]UoAYE5jBf"NX?IBT~ a>n`]%P,JijjjmZgoXS2!бzK[tMo2= ʖbZ#4ǂ5!+4 ()tqLk(Nc f=7T"֠΄s!mPMUe &`W10&ɴiXuwR @Hô j)?;Õ8DwKÌV>EđV*EPٶ\Y+uZQuJK)xY C"suka1ItM)zŽONː1Zs14+lz6JI+l⚮u^WMի]C *q333ԀvV_Ǵ ) SSWo6Qu}z`{ODaE^R!`-Npk 7)al*GZ?~D*8;8t 0lTk# T5E $:iT*./> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <>>> endobj 230 0 obj <> stream xZn}W4/jYB 7A y#q6$ßI/îpD/uSM GEqev6+\ye;DD&ߺ%X\Xx 7 ,p6c J,:6 ,Q<#Րycl+xcv k8PPbv$&3eϒ3A M>"18ppJ;DZDoƐh7䒭hoUL4m%KR޲$ c(87JŇ w^ξݬm=_wUqv#<īAIqh9lݼdOXєռhXdz9)Wjv;e^,%Ht_\hf˨A^b:{zM$ZN䡗 ^5&󋌖[cevuL& QQE(+D~c$Xd$46}BzJQZTE5HIHY={rge$6d x I/$w!%)ga`ɤWј[Q j9>{cTdM؋RSB{`0) ijyBR Py>PȪnss)@: Bi-> IFǥzBjdDfa|!9*BveW-R4L yA#:p6bgeܵ DcBeY7)̷b&H"b$./rSǪ`Yh[jH/UB~̖ g,Ŋv U iy]t )c+T0=mdB"i 8Ǒ*{kap 1n: )vGILNRJIJCi\M!h kM{`1yi5v(J`2Ӭ칰Ѹ~ݔOe(.֮IIEX80/azq'?xrͻfa?C8\|U@ν4%|-Y8@?oT;%]q^H}DyVW6/S$8Kˇnv]v5+@f/pA|{Zͫ  95rb^9Kv^a;x)[èߞo|LwXNpo<=~}@ONE FE'\Gɋf9fW- }EU A/a6p}|7)i>s B<ٕ,qL^VD퓾‘43c5CH_ۇPsH 6K!R20 2$s!RlHLh/)>&`Jgjm;H&_;TLuroMhi|U#ߞs1Nj~gXϻjlrٟ t.\8ϊ)Ԝ0s5e3rRÐJ}p޿~+{W6$I_Kէx^{e/%УՂniLS3B{uRW:)ٷ鴧~SSv~+{%9ske'gu(sjHub h6x6'vծWe%o 9ʥ  oύx iz>k8R-a8)v*XȤ ;~/:ћQ`zBl m9<űh΃1{F8+>$CoYwtOߍt,Uw6s{Q<8) ]H֍anL/E˜ ?X>7Pf7[9@Y`\ endstream endobj 231 0 obj 2700 endobj 25 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <>>> endobj 232 0 obj <> stream xnV_qྸ=߶fQb-h]I4(IPw3Chs~?G)h'B*R R(Vg8E>dĿΜE$ߖ7oЮuا՘iT%}Cp*=%j$_z;-E^M1jv\Sh i>Dc>bbD-T%> L|N)ۤQ&0gN5Al(SjȘpJ5F 9DIW( '2foa4DejUj*6֌ Ɣ1MQLd ۅJo g %nk%~`.09Rh/śUAI*1ly}] k½9rFA9m֩ |S1}R$"l,džLo9ƥg0뙅AFe@Zyp{k7z[kteK:8*ttfuB)e?; c>X姎GC ո<#;W5t2v: |gSP&=c P(w͖tL-Qh{_"!arr Z bԶêٜ3^6@3D#$&YH4:&Y4oAJtO ^=y:éyîN[瘜X$Xl;.ֹ ,o5_t,ZB;܄(934fуǮu|m}lQůxR(עjۦj)* AKF:N-sc vOOV%ȁsUCIN_-`L8g$^c\M* ]гD [ %(l[r(Vd i0eI9l)s}}sW MnjV,4ԽΛpj!mRY> FC<uwσV+6vgE쳻\`q]jx^;^›+ijP$.n`\rS0YHe) R:Tˇfnϓx0C >x+ݿ7?nίw`y J V3e{#{3KJA b;?pCE#ȎA`!"?^F$Yj;t7ވ=C2^/*jLhv׶bfKyPy]\,:gz"\P[ReP;$Mj]vLnD 2]X`o :*ԃ y`jqH%"j{Iwj9?vɹS6_{$ Ϟq>O4C0hFc;\=G4h~ѣQ/̀-^|/ݮhOL=CSeDGǏbpΘ=HC]u;h`eo^T2E1bX夢 IwAr mma 0zdFA͙~S$ Yww"pe{2 a/| 9"H]u%a!;ĄvYL!HS  EQ1zg-#)|R h(q`!i .0,+h"i(ȡCahMdco=c ,'af:L4>"p6\c}I[ 4- ^2@ /d`w.,420Obtv;I6ęit@frzp2R_ Q`1o5)pc̈́ 6'wm F>zL9ȃ-:gkxdD8i@b'd57d݆4㩹2 @Zkg4wAmR~A')1I5^T*A0]Aa2z%uv P~b#Km*5lmeylrmO8ށ ~l޼a8f~b7ӵ4w r:`w)FH鲺(E{Z>PDWzEwaiSȥT?ߝ~*[, ~MU׉ԯоo@1IcyW|-cN9 9/k_Nד@S^L endstream endobj 233 0 obj 3522 endobj 26 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [234 0 R 235 0 R]>> endobj 234 0 obj <> endobj 235 0 obj <> endobj 236 0 obj <> stream x[ْ#q}ﯨ4r#MQRH#<~ Q@NUփ,z2s4z~6J*DUgm_jMwTBŀhSޚ:o÷X?|Ka>x[Cu|͈1NӭbljORy=qNkl:q88kG\ ;ꨆoN.{X>&W[)MdbbXlZ'Sb(6=)'r&!Tg<|P%'ҩwN)jU=QWqֱuowǿ=qVtk4VN*@ 㴱Jﳾl*FX|0l؇\}6]YnW@:f 5]K|G4I:A(y`HHR)~ڼni v^F2ULפ;.1i(C>MyPD+ $dE%Z8jmT.:AE /;"Kc5U[6pXfʡV #8fU1%ȹ:dj8O˪u8-RXp}UjpagnDEsX(]@ˁ[ZG9D] 9X>1uJТvݵl@Ēvb}^?ML)VV_E\#N,6<*STbfy_~W3+[G&^\siLM[kvm9 %ASf_nߘ=) X*s 7b2K ym_9w -V37IRleýUYfwPIR"Grq %f&Ţ߮n)m@A6AUâo)xIB3D 8 BO$; %td99$9m7 )pK#$>pvTf^ q]A>}[ ][v^ jU߮utW8|Vv8nSu[А"zb"LbC:p0K`a PW 8 ZVXu%QHm) ǐ[&yrH>IKwgc @J% 6++ Zulz* NiF#յۮYfGApK;ya,+VeX6v ^k{=^7vu1QNS j4ḑGɂҊXreqC@PKk8/1e NuHa0& CɁk"ī;H5Il9(CT;B`\lDP2QGFka!5h(q$D[FӚ)XeW3i9qT # di ΕEB11A0!!2:S_ { PqFl{+rOBR&(A؆'ӊ>oPz0DMoIա0.M%`GJKܙ]y:w%`@Ho뉿cnV!f7ǁ0D!CTݾ:GfV@6Mw?j}+c@">*mww~~MjK L/8C{ VH&$_ $:u _Xrrҽ3դ1Ks4^މS E毜P '_YCk&J/$bd";ӨdB@p!}ESn&cu]l)t WJ q0۔FE帞:T+Q? ٲ #H( Q!ٖQ6 {5yqb5AI-0WFlIeT !;,AVM8%*Uí @M&CA{'~gy]Ek>^*тovT:$WC3V`&` MT.9h5 C&+Z]GdEfrzjxFVbO46?חhG jm{MEYѪ h٪բ(R=+/&e "9 ̸1:6LX{\ro&Gd-=VEq'(:Ќpf` ]rGPrqնk$NJYN|MQi#6twD؝#ɨOkehO)^Ltꔢ5Xd4 Qh]be3߾1ϡ9'&;JVw#dΌcGD4p.JE(?q# TEʛ^HX)5,4xXMRxae*nJ̳)dvźbMpdnxpDdN6oX; ވF!*vaA/%wĂO7T8 H)[֦ &b_ D$r^jw8Y:eq=+N t6k;f-f_-2~@hoD W4Dg*tFZ%O~Qjx4n>x]zuKԟ*˪{״5Kg1#^{+QE>͖"Gf1"^DcuG}_AW:ۚN m/+]bNj~au(nU@ҽ@UYwaonA@rfERzx{Fy kX.gT# 3 )s3FrҎe<"?v|%Go:֎^z{CnCS(vxdj[!4ƾ@Q=dK7eCԤyO=ƓUFj\]P3?#mRZŧ!3z^"DN6y9GnсS x8:h _mBɆ`&^?Ki(81b8SH Q"MU[jvχ5,?JC[? At__ p:N\TוC%(Z6{0K~ùM@(y-t/&۲~$kP!:΄Q م*q{wo#~J!%2dˁK,1A63~7 wvY}baី/=q0FaF)s1go6&Z+% BW L_WձT /-oÙ6Nuos7 lI)3D<ˀIpr r!ԥ(JC$^J1=Ƙ(X+cv"<%xU8Dc0`1&7͈Kn|FjRvD?2{ EucCt: S![gݣ`SuҜ'>ߎӬ!{D׈ȻǟSp5Lݏ \'ѿo6χ湽{epπK?J`~CsAS].Y endstream endobj 237 0 obj 4319 endobj 27 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [238 0 R]>> endobj 238 0 obj <> endobj 239 0 obj <> stream x\mO$ί̸_N$Kc%HStռ P]]TS5=VuW1F)UYL8o?˪=8ÁSr}୩{v?SfkgY<<8Szhkr<_xF3:;mƶw=T&~p#p44Ts,^cg_k+:>?8A}lsǝK%U%=j^<X9x?V˪C^Ww?WU͗$4nOh=q (޿kLa?<ͨ+=rNFI]mSaҬ2=bzc0ҹN$.gVdtaTʅPP9DvŊEP0qcfBmFdљjm8N@HvȔeib}rsx܉ oR0:Nu=;DpD4]Yj_G텍Mѐ a&:iˊ\|7>iܦrm퓱s'2݊Yv O6L&aL폚;*!P BZZ̴`AzQ9˶g>xh&`ejxP; Y,Cf Hxf>!0Ҝ'#$?vՖ%J*+7?m\sjWiAUn޲F@=cnbsuLZ@tݞ.T&ťuհbA QHsb&1^ຠ|<xt,((c0BKO-'fv39 ryv3oM@U)e)h̨ ,4WUSX% 2AqeͪY@_3)7bAϨ<ߺӺ<ͤ䅎8y]1T}Cm$J6*i1dۈ&.CqfLb9˴TWu ^jXL ᳜mysAT>jaq$0ݚgr1z_.Z(LM,pE;Ĥ +*NNY4 FLr'{̤ԢC=$(h iR+$D=(dnhDP 2цH1VywDzq=JAz:e.<8k,*cl ?|sQR%sj%!rlhP5YKE ALr5&tٝ{>\VrŻTPXX&;BdmxAE4v0vT'h},E~Ak4ce1F.M.Lbѫn4uOK! 7'KΤ-U;lV6\h¤K6za{)3~j/ j/1{T4[2H& 0r#=&$|ڬ[ނYCD.<ͪkNUP(l'xL(w}W8f&7<5qvnK8YW{xV9h5Bqr $WfM(R]PChdCjf'tB BI&[hPSȤy|մ5mj>穬kTv?AMweMQ$XK8mW[\[_ aHD?)oKA֑`TU'<+KuD 8&WlT>KȠIQ1Cf؝1zÕ0r [ȥ.=K| ėc#\rF+*1TZH6Di /Tz'Ֆ]+:n#e!K/T۾cNe1R|)A U,`LKi7kFB^hE#EGgQ v<*M%^p¯Lu, 칩+C2'I_VnPkD7JT9K\.̻Ȇ>uĠWЩV[^6TY윭Ck H@+l JU0[ؚcoPW^]}2:҉ԱTBn7l ;%*2gDŜ1JQΨ{ \Er`j<y\詡}N*jhK}f{}e58R,#ZeK˘VIVx,c0SCE:}-ReP#ج8vQ[\wk&u4>f WC4ˌ\H3&\hW ^ŻR캻d!EŪË듵 e6jbVJWR{MH7*fUBEB͑3lSRBEœʎ =e*Oowؤ{Y5DGjH@4; x>?9:yw4:*vqvv endstream endobj 240 0 obj 4154 endobj 28 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [241 0 R 242 0 R]>> endobj 241 0 obj <> endobj 242 0 obj <> endobj 243 0 obj <> stream xZ[~_1)N.R$H@݇WwF҈j<#yx!)hWMT֤ ?=JՊ~,?]4u>d#kjK?f:o[Mw÷$>]Bڏ̜-}:YKۛ_f<+,aI5[QmISu,l]n'fcCW*pL̂H+QR^ނt%߿F+_Q[h 8ͻo_Ja&ԡujiUv]OݻvκUX~S/o23+6l*g[d|ݶ*)jkF\#%u rhr5p8fU}Slw4N9y?U܋ v3bEdtj/*! u- ub\u5*rM;1ZN:kgv%$z׫MZ+9\felm]R^NsWqԨMBnHZH6tFҋ)yH#d cZPˆr)s-ek("o2E2hY}@:+)P.&7w Qވf:˒Q.³WeWDVvS Ë|l,W#Y?lk`|ʉV6?C ?^]|{w+]l͢kW)ǫHU*ug"̈́8h ɧ1yj7 s_rx b/v]V|oAײ+Y4Υfgd?q__O'7v h<b٠a5JSOF=^Y;Z`hhJ*fCGMа?WoYVJ:f\*s*Wi狣0J2|FPWb/HK4zX2Ƚt-Qڝ8}9dr!鰚,dI<7b_r:*c4 o:H t8r}lgSiQ d4u/" kmΗ]pAG|!b,:> 8}^6F%+n[Iu2pa1L1?v,.`<&cIk>LV93Ӂ' 9l m<j]nB# ,2)ω1k` 8a.}/wcKrn3AΈ5 Z&ԨxW.i5"qZu øPH =@^aC[Y)Dhc#s:&E1!b<İ1&>!F9ևMe:F_y,zZ9e(7hQj,;ZvԯjPhvϘRvc<wPOǑsX? ؄SC#F!U# Nꦟ;*:`oh 4#dW /Ԯ{-WRM2%]R7nNXvC=GuXX[jy?T_iKdK,h\|jQR-:y%C]Bf=͕sQ6,3ߎD6DCo\#W|Xp4IAY2iRi$5|h|f9t՟eb+j5{[c)?{#;:h.gW{L˩n,Gu{B ^_t&4=Xlx| ;Doah+ 5E^ Y:-Ia A 9$px[a}W:A+_FPvӊԣt+ (( J2凾ԛ8#yF HZH.Hё=l4tmoyLpH IC'|sq'U]z,O[ 4b(TS tfVXC׬PM!ҽ~"H!1H9 429.9\xRÒcG9.'}#] 1w569\yk6Xf.IpMP"r`9BZyQS:XhйjO_puo<ͳpjͧp7NChh'SE%BGHnm% sΡ;V$ª׼%CIGESRwҰ3 Ȉg~wM;VgǢ *q6ӱH0rų : ynk3"+0*8x >e(&&W gzz媛meT:4Rf~&v1}|b:cI2 !,GGw ".-}.5N|؉pz>S VA0ܞdXDh'X=!!bByJ=Uq8D B+goW(N)ѕ[ܩ-=QReSJxTA'[E6INuX *kQL t!O*m^0}+z$wV:0d\r[!ӻɳ~r e{i{>iP1bACaL)(_k2ӠdR%ԍ>t 4nPKA1d ;;.==s"^;1DHXoݘ"fzs$c3N%^M Z?ig6\[P5 GEbm=|iꇍW6dYl2弰 =5W љJ<%r]EAa,Uބ!S52r6v Q ߵQ:#E?\Ӡ`MwB2f`&8 zWi 7]7g}ע)v Yt(Φck;R'e@~MGYQi1ӅԞ3MXt~NL*cv;Q!89JR%n9s!0& dED"jNPdyLn' +܀%Q )b:EO$ҒL5y\VC[)[3LeA*90OW+n7s_ecˏҾ33?dEm-mBa&uUڈa'0mv5?}wb ؞N_yI@#pۭ`WŹKӍ$ endstream endobj 244 0 obj 3493 endobj 29 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [245 0 R 246 0 R 247 0 R 248 0 R]>> endobj 245 0 obj <> endobj 246 0 obj <> endobj 247 0 obj <> endobj 248 0 obj <> endobj 249 0 obj <> stream xZMoGW49 @``7B/#r(MLp9e̿$EuNJ|!=|]]]]Uxq{4J)|qPh._6Jb5"$UD-ϔ?9أsF=zV,*6S[?d(/y5iBS}#* a" Z\/^M8.v:x_~+ zm7RMjFw;1onaҜRUx{wG9Jr<֎,Y=3Ȩva1H0aAwü eT!H7F||IhE|zF}KVֻ̏HlQu_}>*27~xoRBS $_1!%CzJ/ɤ; t:sb74oFɊZar٪ UN[i4޲f>jwd尙UV,Emk4R AaAIcU bwf샍w2H|^qVj1O $l`>Uʀ gg&~\D0 ڸngݢ5*3^f&Evc7$ s)s;âD/elY~Uph1<3Ơ1}O#ejXvk7blgC?vɑⷶ܈f^ Eoz+|[a㣉yO؞P9~ѡp:RzzV% %" 6ODiC mh(舟~nrn;r_gw @f qj uX9Pl]feP$yC1rI D`>t}]qM@RItAD1N0;i E,oj~I1ȁ<5٤|H֡_!ٞōPHI2o?aMX(֑S`ߴH;0 %.m1.!ƱYl۠)JkK5h` G1ahfep."iˑ4b>X=΀Kو,՘mIA.{e&`Υ}"%O9\iA2Q86!}0oTa '(fw=s+ 1 $+,jI#BSc>8R+8Q%")N1{Dyy aٔ8ϕa2Lۥֿmf KaDXl-…"A gHlHcy۶o7M]xօl.3 &&?`ܒPwmYm94ܩaNv[vlRw47ѻ hـ_=[ עRr$}Ti(PVqEH;N1s4ѡ-4<ͳo-<)f藤{_h%Q46jiTׯڜU[ڙ(0hLA:]M-. M,TdN11LC*CX^ݷDyx(( #QD.! ەH~۫v{_=zrQ6UȩD)Њ*]wVZ6(2C 7sπg@0<Ӗ>ʤY/9( (&9c:J@His L 9Emo*侂)D٤OkY:ĵD;DЗ{Vw)"Wc⊝M*ʎٱX '# Z)K]|G: f^w\]0lYJf8Yb ;Ozo SOaܶW$ǒU5􊮼ˡa]4Ep|DOQw-hD3P+okB0-N+6__'Aqt9 9DpwQ:s(H(g!W)|H:'"`FrF0usr cB9e]3X.:f{PLyh_Jc^R6>3{I/zI%mV5g,OW]yuTnT۹XoUWT(xhST$I /$|TD9[]% yI/ 9[Vmw۴t.~>un,+6a?'7#=D޿"PJ;~o ?owe%޶_<ȣ/8 \#&fգ^i endstream endobj 250 0 obj 2723 endobj 30 0 obj <> /XObject <> /ProcSet [/PDF /Text /ImageC] /ColorSpace <>>> /Group <> /Annots [251 0 R]>> endobj 251 0 obj <> endobj 253 0 obj <> stream xZmo_p)Λ}1p(C(\h)$tvzJ"w,,S<3;3+.|J ?hrdS^t!xp'+\Պl>YX`gA=z;%Cզ_ 1tGjxˡzo|ˑsk8f) &>>Fr+eg`m7}vս^l]^W8PMHqp#b^TnVd (Sإ(-#6pX~/7q5f?"l0F1d\7)Fdzzf)n|̄ " CwDBO@V\ϼ$k%VZ>k+,,c ZpvZ0bfj>!8ju)@08ıMbF,P WAȐbU>oSV "n j:[hs>(\)K@4ք2e dI1 xX,\m2am^`O>A@axV)#dJ+ͲjFK8Ŷj6$Y5¨z Ī# د ^g[UKGP(B R7F琊9 B`PVR%Q+3 %@CfM'4^38am3ߗ[$u\ RKjK< Vp+wjL ع=UGs+]/61t?(PtkP9Y%on~[9K4«٦,12!`lBa~FK4ij+! N9 .N*UW }>MU`]t6v"mwabʲ7$Ĭ LNW]{"Av@+Pܹ)t^ |CgHlt3 jLeB  +%pdye7/pzzAg|~3Y5+!V2'ѕ6Ȅĕ_^edGsl^]O>[zV)#s 4 ذϟ{FK$TnꦼEYؼX4. ?/Y|&^/С9s; MAbQ?]T>ճiȀjM0q<+8Új5+-w;1P+%y$|dUV>x73Q%TS^1r}pκ@)<FEWWB#%w[vȩPL.gռ"փ2|7RVB$rҙ2k9 ,E3e!k&֋)ˡWی)f&?{ ٬)H7po;F(;!Q:MA 4tdcʫ.OTl1%}9Ves. j&e V>W'uL:M WoJ@ؔUBsR`ّNA;UG˃ fAFQ;Qosn I"mTѦJR[r$VeܦT#;DiK4ZyfHlY Jfb_.S>T]&d6hK"]4r@mf#`@f4An֋|v\[',N7sCڒЯ̘ćzcHwxrg*:;Bgi7W|gے&wn~CbI |&qP']+&D4i`:FD|;孤m8(~Mpd:*:g5x2UPyGAOE* ^ C%-2H^m>ԯb֌5n؂NdipWԼs^V|U>w.)HpNB?K_xi.Gkq3/M3O _ 8)&-{ZlH?-VΒb XWz}`&f O U JyZ%ZE%U@OϨ Q+:37`7ѽ _5SZ'!r/]ubG`xTo~'&XR\K{9Y?>X8(uv1bA>b `BE(@Ŀ 5zS8\NPqs B#NjlJoL;SfJgxLr4*b5ZbdG-CJCe68;b)d$VD }._v%)~B!t@Wϯp/FS9RS?s |ZLՋ$em:%=;fvLp m^Ұ%H,4TYM9 ?X=슇ax΂z~6/q ` ӱ: endstream endobj 254 0 obj 2747 endobj 31 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [255 0 R 256 0 R 257 0 R 258 0 R]>> endobj 255 0 obj <> endobj 256 0 obj <> endobj 257 0 obj <> endobj 258 0 obj <> endobj 259 0 obj <> stream x[n#}W  {vp#<ȑ46Qjm=UR#SnVe 7g!BU:Szj]Gߜ]*!+;sF}>bgQI|t{vPhURHX*=CGYl3V [Ǹcɿ<2S쳯 f(+y]\pKbl^r·A+afcӯ2vWiX͙VE!Y`uW?4u>+!ӧDJF"j%% eHwͺ0F^'ȁ͔W6u'lU TBsu~ofmhnKcv}OFGv^\#gŤ#7%m$lA:v aͨg pF'q{YXCq1ioV 1[(R!"aD0sgL{e"LD*o춛AXl.haa޾%Ǚpw܈AY؁B,2KI #XHOZ&', ?sV`L1O a3*!I(6]z{>o{ tpȎU 2."OM*Y DslAb\C8GGY!}qr*$t xy&d\vAdMLm,Ї@]$ 9i~ /oGCMᅏ;4 eQ4;0U[=Ay"%R+,D X؂XݎyGrL͋T"-(R%NL6V7-ײqAxHS54r>0cQoCFYJB;̑פ*qAQz,F~' ':qKmQ(ti!o E97}7EbNo.wAe CtEw]L=/=JlݛuCJ&aEm'P˯0m~<~̋Q0/ܧBd.(d7W8_5,R!H50!}3o%k(ȈĊehQ#?m:ʷP,0fRAf9gS ) x4C-vX/Y-21'"Hu7pQV!*ˣjkVXHMH_K~O(9GǑ ҍ fD%#4ZaPY-,<i P82СiTkiMPF8=ѬvֈDA-PO'{S * C {@>.0ywmFTx/.[tyJF$KԀA&\:% K\i+TiO+j%Y=\m{z܂EYW moĊO=I^YR$],XԔA||ȍVhVsEJ ^y!"jA04=%)6RIP{oT;;Gի( *ddM*d9rE95'T֩! BG$FY6"Cf@A MQ(ĒU<#GQ{"=Y/։CI aǥ7Zs:Ulr3vT̺RC9[;PXm}wht57.|w (`qCZ n ] (N7ڙn5NUVر`((d9닿y@SZh .Q|XD-,[*X~^뫑 (= rw Z*B]\&%fl0%+DO8.=AUJw)~Z2E YYkBL0H(R {P:F~,yaXyB>LY nv(TA)s'*M ֢{;԰<p\xjcl Ip`e.c,4_IʵX__Cwܫ. K}]\fsK/4/`:^life[gF]l~Ѯ'H1/jo_NZRMX gn|nlqzB =GQ4VcV\]?i+jmzb7$3H,_P/ٻsa9l7?s} 8{JqJ,UzF Kuzl4GVA3s%\SzvLnOqGݳ*4(hє!j3b s&FpVkzKU=c?Q}3kw=Pu( *>SI}f8h#CM/n:!XdU+k$7gx{Oib8bnGTnDAs Fn-C+rq{&7~HTQuj3z#T1yShMA@Ψ-.p8HBƔ0g_/6Q7桾i&Ӄ)ǿ-  @oFٍMi,2 endstream endobj 260 0 obj 3484 endobj 32 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [261 0 R 262 0 R]>> endobj 261 0 obj <> endobj 262 0 obj <> endobj 263 0 obj <> stream x[[o#I~ϯhM,f64XZ]8|Y|b6ya18_R+?Mc]ujjSc5{lg?M -V`pI۶m Pe),K$ ͂MÀ&Q̖p@8>2FL`!Hb2DhAQft4yT%9U _7BYv}t$/Tyhljmq3}7L٘6aH#d N]XJVBoz! )IyneX亃SQI^z/Jq9 ˕7xYFhs:"OveB]@FFm)F!*apJHF.f9bӲCP Yq4HjRnmM-(a \:u (KOdVeP>D" z ΂ZL3U:HnVv+ (mW3iRo/~(jayqQ!1 sR)O*:cox:G( y۬1a\ˊ0p\}NED1Oƞd:|+k dilBNwZ^ S ~$hx9qȫ gYs"wAlγ)o,D@Lŝ'%ij@xV5oj " ք ؗ0Ӕo4z3(8M#NpI:laQ[0q(; 'Yܦ#x>O/d2T3MB:w-KemZBG%}&䍥F>IX_*MVCjա}閼=᷍:([6۫nt ]^Z۪̅t .v<'-*F]0v 'U\ oErp(1 ޠ9|QsȢYNXx@y32%ҹ`bsNTffN-s̬0o%û G7uE aGC|M#N70PZ.7~Bv*N #sprnyK1N)d 6g;b6 ߬p~9cm9ݤrY 7`C-nm_x30֚bx%ܴ~! b38JH!/7JF B =F 7チ搉9R?["OAm[D5_e.8^( O#:־~zoռ
    Abstract

    This document provides a tutorial for the Next Scripting Language NX.

    The Next Scripting Language (NX) is a highly flexible object oriented scripting language based on Tcl [Ousterhout 1990]. NX is a successor of XOTcl 1 [Neumann and Zdun 2000a] and was developed based on 10 years of experience with XOTcl in projects containing several hundred thousand lines of code. While XOTcl was the first language designed to provide language support for design patterns, the focus of the Next Scripting Framework and NX is on combining this with Language Oriented Programming. In many respects, NX was designed to ease the learning of the language for novices (by using a more mainstream terminology, higher orthogonality of the methods, less predefined methods), to improve maintainability (remove sources of common errors) and to encourage developers to write better structured programs (to provide interfaces) especially for large projects, where many developers are involved.

    The Next Scripting Language is based on the Next Scripting Framework (NSF) which was developed based on the notion of language oriented programming. The Next Scripting Frameworks provides C-level support for defining and hosting multiple object systems in a single Tcl interpreter. The name of the Next Scripting Framework is derived from the universal method combinator "next", which was introduced in XOTcl. The combinator "next" serves as a single instrument for method combination with filters, per-object and transitive per-class mixin classes, object methods and multiple inheritance.

    The definition of NX is fully scripted (e.g. defined in nx.tcl). The Next Scripting Framework is shipped with three language definitions, containing NX and XOTcl 2. Most of the existing XOTcl 1 programs can be used without modification in the Next Scripting Framework by using XOTcl 2. The Next Scripting Framework requires Tcl 8.5 or newer.

    1. NX and its Roots

    Object oriented extensions of Tcl have quite a long history. Two of the most prominent early Tcl based OO languages were incr Tcl (abbreviated as itcl) and Object Tcl (OTcl [Wetherall and Lindblad 1995]). While itcl provides a traditional C++/Java-like object system, OTcl was following the CLOS approach and supports a dynamic object system, allowing incremental class and object extensions and re-classing of objects.

    Extended Object Tcl (abbreviated as XOTcl [Neumann and Zdun 2000a]) is a successor of OTcl and was the first language providing language support for design patterns. XOTcl extends OTcl by providing namespace support, adding assertions, dynamic object aggregations, slots and by introducing per-object and per-class filters and per-object and per-class mixins.

    XOTcl was so far released in more than 30 versions. It is described in its detail in more than 20 papers and serves as a basis for other object systems like TclOO [Donal ???]. The scripting language NX and the Next Scripting Framework [Neumann and Sobernig 2009] extend the basic ideas of XOTcl by providing support for language-oriented programming. The the Next Scripting Framework supports multiple object systems concurrently. Effectively, every object system has different base classes for creating objects and classes. Therefore, these object systems can have different interfaces and can follow different naming conventions for built-in methods. Currently, the Next Scripting Framework is packaged with three object systems: NX, XOTcl 2.0, and TclCool (the language introduced by TIP#279).

    Languages
    Figure 1. Language History of the Next Scripting Language

    The primary purpose of this document is to introduce NX to beginners. We expect some prior knowledge of programming languages, and some knowledge about Tcl. In the following sections we introduce NX by examples. In later sections we introduce the more advanced concepts of the language. Conceptually, most of the addressed concepts are very similar to XOTcl. Concerning the differences between NX and XOTcl, please refer to the Migration Guide for the Next Scripting Language.

    2. Introductory Overview Example: Stack

    A classical programming example is the implementation of a stack, which is most likely familiar to many readers from many introductory programming courses. A stack is a last-in first-out data structure which is manipulated via operations like push (add something to the stack) and pop remove an entry from the stack. These operations are called methods in the context of object oriented programming systems. Primary goals of object orientation are encapsulation and abstraction. Therefore, we define a common unit (a class) that defines and encapsulates the behavior of a stack and provides methods to a user of the data structure that abstract from the actual implementation.

    2.1. Define a Class "Stack"

    In our first example, we define a class named Stack with the methods push and pop. When an instance of the stack is created (e.g. a concrete stack s1) the stack will contain an instance variable named things, initialized with an empty list.

    Listing 2: Class Stack

    nx::Class create Stack {
    
       #
       # Stack of Things
       #
    
       :variable things {}
    
       :public method push {thing} {
          set :things [linsert ${:things} 0 $thing]
          return $thing
       }
    
       :public method pop {} {
          set top [lindex ${:things} 0]
          set :things [lrange ${:things} 1 end]
          return $top
       }
    }

    Typically, classes are defined in NX via nx::Class create, followed by the name of the new class (here: Stack). The definition of the stack placed between curly braces and contains here just the method definitions. Methods of the class are defined via :method followed by the name of the method, an argument list and the body of the method, consisting of Tcl and NX statements.

    When an instance of Stack is created, it will contain an instance variable named things. If several Stack instances are created, each of the instances will have their own (same-named but different) instance variable. The instance variable things is used in our example as a list for the internal representation of the stack. We define in a next step the methods to access and modify this list structure. A user of the stack using the provided methods does not have to have any knowledge about the name or the structure of the internal representation (the instance variable things).

    The method push receives an argument thing which should be placed on the stack. Note that we do not have to specify the type of the element on the stack, so we can push strings as well as numbers or other kind of things. When an element is pushed, we add this element as the first element to the list things. We insert the element using the Tcl command linsert which receives the list as first element, the position where the element should be added as second and the new element as third argument. To access the value of the instance variable we use Tcl’s dollar operator followed by the name. The names of instance variables are preceded with a colon :. Since the name contains a non-plain character, Tcl requires us to put braces around the name. The command linsert and its arguments are placed between square brackets. This means that the function linsert is called and a new list is returned, where the new element is inserted at the first position (index 0) in the list things. The result of the linsert function is assigned again to the instance variable things, which is updated this way. Finally, the method push returns the pushed thing using the return statement.

    The method pop returns the most recently stacked element and removes it from the stack. Therefore, it takes the first element from the list (using the Tcl command lindex), assigns it to the method-scoped variable top, removes the element from the instance variable things (by using the Tcl command lrange) and returns the value popped element top.

    This finishes our first implementation of the stack, more enhanced versions will follow. Note that the methods push and pop are defined as public; this means that these methods can be used from all other objects in the system. Therefore, these methods provide an interface to the stack implementation.

    Listing 3: Using the Stack

    #!/usr/bin/env tclsh
    package require nx
    
    nx::Class create Stack {
    
       #
       # Stack of Things
       #
       ....
    }
    
    Stack create s1
    s1 push a
    s1 push b
    s1 push c
    puts [s1 pop]
    puts [s1 pop]
    s1 destroy

    Now we want to use the stack. The code snippet in Listing 3 shows how to use the class Stack in a script. Since NX is based on Tcl, the script will be called with the Tcl shell tclsh. In the Tcl shell we have to require package nx to use the Next Scripting Framework and NX. The next lines contain the definition of the stack as presented before. Of course, it is as well possible to make the definition of the stack an own package, such we could simple say package require stack, or to save the definition of a stack simply in a file and load it via source.

    In line 12 we create an instance of the stack, namely the stack object s1. The object s1 is an instance of Stack and has therefore access to its methods. The methods like push or pop can be invoked via a command starting with the object name followed by the method name. In lines 13-15 we push on the stack the values a, then b, and c. In line 16 we output the result of the pop method using the Tcl command puts. We will see on standard output the value+c+ (the last stacked item). The output of the line 17 is the value b (the previously stacked item). Finally, in line 18 we destroy the object. This is not necessary here, but shows the life cycle of an object. In some respects, destroy is the counterpart of create from line 12.

    object-class-appclass.png
    Figure 4. Class and Object Diagram

    Figure 4 shows the actual class and object structure of the first Stack example. Note that the common root class is nx::Object that contains methods for all objects. Since classes are as well objects in NX, nx::Class is a specialization of nx::Object. nx::Class provides methods for creating objects, such as the method create which is used to create objects (and classes as well).

    2.2. Define an Object Named "stack"

    The definition of the stack in Listing 2 follows the traditional object oriented approach, found in practically every object oriented programming language: Define a class with some methods, create instances from this class, and use the methods defined in the class in the instances of the class.

    In our next example, we introduce generic objects and object specific methods. With NX, we can define generic objects, which are instances of the most generic class nx::Object (sometimes called common root class). nx::Object is predefined and contains a minimal set of methods applicable to all NX objects. In this example, we define a generic object named stack and provide methods for this object. The methods defined above were methods provided by a class for objects. Now we define object specific methods, which are methods applicable only to the object for which they are defined.

    Listing 5: Object stack

    nx::Object create stack {
    
       :object variable things {}
    
       :public object method push {thing} {
          set :things [linsert ${:things} 0 $thing]
          return $thing
       }
    
       :public object method pop {} {
          set top [lindex ${:things} 0]
          set :things [lrange ${:things} 1 end]
          return $top
       }
    }

    The example in Listing 5 defines the object stack in a very similar way as the class Stack. But the following points are different.

    • First, we use nx::Object instead of nx::Class to denote that we want to create a generic object, not a class.

    • We use :object variable to define the variable things just for this single instance (the object stack).

    • The definition for the methods push and pop are the same as before, but here we defined these with object method. Therefore, these two methods push and pop are object-specific.

    In order to use the stack, we can use directly the object stack in the same way as we have used the object s1 in Listing 3 the class diagram for this the object stack.

    object-stack.png
    Figure 6. Object stack

    A reader might wonder when to use a class Stack or rather an object stack. A big difference is certainly that one can define easily multiple instances of a class, while the object is actually a single, tailored entity. The concept of the object stack is similar to a module, providing a certain functionality via a common interface, without providing the functionality to create multiple instances. The reuse of methods provided by the class to objects is as well a difference. If the methods of the class are updated, all instances of the class will immediately get the modified behavior. However, this does not mean that the reuse for the methods of stack is not possible. NX allows for example to copy objects (similar to prototype-based languages) or to reuse methods via e.g. aliases (more about this later).

    Note that we use capitalized names for classes and lowercase names for instances. This is not required and a pure convention making it easier to understand scripts without much analysis.

    2.3. Implementing Features using Mixin Classes

    So far, the definition of the stack methods was pretty minimal. Suppose, we want to define "safe stacks" that protect e.g. against stack under-runs (a stack under-run happens, when more pop than push operations are issued on a stack). Safety checking can be implemented mostly independent from the implementation details of the stack (usage of internal data structures). There are as well different ways of checking the safety. Therefore, we say that safety checking is orthogonal to the stack core implementation.

    With NX we can define stack-safety as a separate class using methods with the same names as the implementations before, and "mix" this behavior into classes or objects. The implementation of Safety in stack under-runs and to issue error messages, when this happens.

    Listing 7: Class Safety

    nx::Class create Safety {
    
      #
      # Implement stack safety by defining an additional
      # instance variable named "count" that keeps track of
      # the number of stacked elements. The methods of
      # this class have the same names and argument lists
      # as the methods of Stack; these methods "shadow"
      # the methods of class Stack.
      #
    
      :variable count 0
    
      :public method push {thing} {
        incr :count
        next
      }
    
      :public method pop {} {
        if {${:count} == 0} { error "Stack empty!" }
        incr :count -1
        next
      }
    }

    Note that all the methods of the class Safety end with next. This command is a primitive command of NX, which calls the same-named method with the same argument list as the current invocation.

    Assume we save the definition of the class Stack in a file named Stack.tcl and the definition of the class Safety in a file named Safety.tcl in the current directory. When we load the classes Stack and Safety into the same script (see the terminal dialog in e.g. a certain stack s2 as a safe stack, while all other stacks (such as s1) might be still "unsafe". This can be achieved via the option -mixin at the object creation time (see line 9 in option -mixin mixes the class Safety into the new instance s2.

    Listing 8: Using the Class Safety

    % package require nx
    2.0
    % source Stack.tcl
    ::Stack
    % source Safety.tcl
    ::Safety
    % Stack create s1
    ::s1
    % Stack create s2 -object-mixin Safety
    ::s2
    % s2 push a
    % s2 pop
    a
    % s2 pop
    Stack empty!
    
    % s1 info precedence
    ::Stack ::nx::Object
    
    % s2 info precedence
    ::Safety ::Stack ::nx::Object

    When the method push of s2 is called, first the method of the mixin class Safety will be invoked that increments the counter and continues with next to call the shadowed method, here the method push of the Stack implementation that actually pushes the item. The same happens, when s2 pop is invoked, first the method of Safety is called, then the method of the Stack. When the stack is empty (the value of count reaches 0), and pop is invoked, the mixin class Safety generates an error message (raises an exception), and does not invoke the method of the Stack.

    The last two commands in Listing 8 use introspection to query for the objects s1 and s2 in which order the involved classes are processed. This order is called the precedence order and is obtained via info precedence. We see that the mixin class Safety is only in use for s2, and takes precedence over Stack. The common root class nx::Object is for both s1 and s2 the base class.

    per-object-mixin.png
    Figure 9. Per-object Mixin

    Note that in Listing 8, the class Safety is only mixed into a single object (here s2), therefore, we refer to this case as a per-object mixin. Figure 9 shows the class diagram, where the class Safety is used as a per-object mixin for s2.

    The mixin class Safety can be used as well in other ways, such as e.g. for defining classes of safe stacks:

    Listing 10: Class SafeStack

    #
    # Create a safe stack class by using Stack and mixin
    # Safety
    #
    nx::Class create SafeStack -superclasses Stack -mixins Safety
    
    SafeStack create s3

    The difference of a per-class mixin and a per-object mixin is that the per-class mixin is applicable to all instances of the class. Therefore, we call these mixins also sometimes instance mixins. In our example in Listing 10, Safety is mixed into the definition of SafeStack. Therefore, all instances of the class SafeStack (here the instance s3) will be using the safety definitions.

    per-class-mixin.png
    Figure 11. Per-class Mixin

    Figure 11 shows the class diagram for this definition. Note that we could use Safety as well as a per-class mixin on Stack. In this case, all stacks would be safe stacks and we could not provide a selective feature selection (which might be perfectly fine).

    2.4. Define Different Kinds of Stacks

    The definition of Stack is generic and allows all kind of elements to be stacked. Suppose, we want to use the generic stack definition, but a certain stack (say, stack s4) should be a stack for integers only. This behavior can be achieved by the same means as introduced already in Listing 5, namely object-specific methods.

    Listing 12: Object Integer Stack

    Stack create s4 {
    
      #
      # Create a stack with an object-specific method
      # to check the type of entries
      #
    
      :public object method push {thing:integer} {
        next
      }
    }

    The program snippet in Listing 12 defines an instance s4 of the class Stack and provides an object specific method for push to implement an integer stack. The method pull is the same for the integer stack as for all other stacks, so it will be reused as usual from the class Stack. The object-specific method push of s4 has a value constraint in its argument list (thing:integer) that makes sure that only integers can be stacked. In case the argument is not an integer, an exception will be raised. Of course, one could perform the value constraint checking as well in the body of the method proc by accepting a generic argument and by performing the test for the value in the body of the method. In the case, the passed value is an integer, the push method of Listing 12 calls next, and therefore calls the shadowed generic definition of push as provided by Stack.

    Listing 13: Class IntegerStack

    nx::Class create IntegerStack -superclass Stack {
    
      #
      # Create a Stack accepting only integers
      #
    
      :public method push {thing:integer} {
        next
      }
    }

    An alternative approach is shown in Listing 13, where the class IntegerStack is defined, using the same method definition as s4, this time on the class level.

    2.5. Define Object Specific Methods on Classes

    In our previous examples we defined methods provided by classes (applicable for their instances) and object-specific methods (methods defined on objects, which are only applicable for these objects). In this section, we introduce methods that are defined on the class objects. Such methods are sometimes called class methods or static methods.

    In NX classes are objects, they are specialized objects with additional methods. Methods for classes are often used for managing the life-cycles of the instances of the classes (we will come to this point in later sections in more detail). Since classes are objects, we can use exactly the same notation as above to define class methods by using object method. The methods defined on the class object are in all respects identical with object specific methods shown in the examples above.

    Listing 14: Class Stack2

    nx::Class create Stack2 {
    
       :public object method available_stacks {} {
          return [llength [:info instances]]
       }
    
       :variable things {}
    
       :public method push {thing} {
          set :things [linsert ${:things} 0 $thing]
          return $thing
       }
    
       :public method pop {} {
          set top [lindex ${:things} 0]
          set :things [lrange ${:things} 1 end]
          return $top
       }
    }
    
    Stack2 create s1
    Stack2 create s2
    
    puts [Stack2 available_stacks]

    The class Stack2 in Listing 14 consists of the earlier definition of the class Stack and is extended by the class-specific method available_stacks, which returns the current number of instances of the stack. The final command puts (line 26) prints 2 to the console.

    stack2.png
    Figure 15. Stack2

    The class diagram in Figure 15 shows the diagrammatic representation of the class object-specific method available_stacks. Since every class is a specialization of the common root class nx::Object, the common root class is often omitted from the class diagrams, so it was omitted here as well in the diagram.

    3. Basic Language Features of NX

    3.1. Variables and Properties

    In general, NX does not need variable declarations. It allows one to create or modify variables on the fly by using for example the Tcl commands set and unset. Depending on the variable name (or more precisely, depending on the variable name’s prefix consisting of colons ":") a variable is either local to a method, or it is an instance variable, or a global variable. The rules are:

    • A variable without any colon prefix refers typically to a method scoped variable. Such a variable is created during the invocation of the method, and it is deleted, when the method ends. In the example below, the variable a is method scoped.

    • A variable with a single colon prefix refers to an instance variable. An instance variable is part of the object; when the object is destroyed, its instance variables are deleted as well. In the example below, the variable b is an instance variable.

    • A variable with two leading colons refers to a global variable. The lifespan of a globale variable ends when the variable is explicitly unset or the script terminates. Variables, which are placed in Tcl namespaces, are also global variables. In the example below, the variable c is a global variable.

    Listing 16: Scopes of Variables

    nx::Class create Foo {
    
      :public method foo args {...}
        # "a" is a method scoped variable
        set a 1
        # "b" is an Instance variable
        set :b 2
        # "c" is a global variable/namespaced variable
        set ::c 3
      }
    }

    Listing 16 shows a method foo of some class Foo referring to differently scoped variables.

    3.1.1. Properties: Configurable Instance Variables

    As described above, there is no need to declare instance variables in NX. In many cases, a developer might want to define some value constraints for variables, or to provide defaults, or to make variables configurable upon object creation. Often, variables are "inherited", meaning that the variables declared in a general class are also available in a more specialized class. For these purposes NX provides variable handlers responsible for the management of instance variables. We distinguish in NX between configurable variables (called property) and variables that are not configurable (called variable).

    A property is a definition of a configurable instance variable.

    The term configurable means that (a) one can provide at creation time of an instance a value for this variable, and (b), one can query the value via the accessor function cget and (c), one can change the value of the variable via configure at run time. Since the general accessor function cget and configure are available, an application developer does not have to program own accessor methods. When value checkers are provided, each time, the value of the variable is to be changed, the constrained are checked as well.

    person-student.png
    Figure 17. Classes Person and Student

    The class diagram above defines the classes Person and Student. For both classes, configurable instance variable are specified by defining these as properties. The listing below shows an implementation of this conceptual model in NX.

    Listing 18: Properties

    #
    # Define a class Person with properties "name"
    # and "birthday"
    #
    nx::Class create Person {
      :property name:required
      :property birthday
    }
    
    #
    # Define a class Student as specialization of Person
    # with additional properties
    #
    nx::Class create Student -superclass Person {
      :property matnr:required
      :property {oncampus:boolean true}
    }
    
    #
    # Create instances using configure parameters
    # for the initialization
    #
    Person create p1 -name Bob
    Student create s1 -name Susan -matnr 4711
    
    # Access property value via accessor method
    puts "The name of s1 is [s1 cget -name]"

    By defining name and birthday as properties of Person, NX makes these configurable. When we create an instance of Person named p1, we can provide a value for e.g. the name by specifying -name during creation. The properties result in non-positional configure parameters which can be provided in any order. In our listing, we create an instance of Person using the configure parameter name and provide the value of Bob to the instance variable name.

    The class Student is defined as a specialization of Person with two additional properties: matnr and oncampus. The property matnr is required (it has to be provided, when an instance of this class is created), and the property oncampus is boolean, and is per default set to true. Note that the class Student inherits the properties of Person. So, Student has four properties in total.

    The property definitions provide the configure parameters for instance creation. Many other languages require such parameters to be passed via arguments of a constructor, which is often error prone, when values are to be passed to superclasses. Also in dynamic languages, the relationships between classes can be easily changed, and different superclasses might have different requirements in their constructors. The declarative approach in NX reduces the need for tailored constructor methods significantly.

    Note that the property matnr of class Student is required. This means, that if we try to create an instance of Student, a run time exception will be triggered. The property oncamups is boolean and contains a default value. Providing a default value means that whenever we create an instance of this class the object will contain such an instance variable, even when we provide no value via the configure parameters.

    In our listing, we create an instance of Student using the two configure parameters name and matnr. Finally, we use method cget to obtain the value of the instance variable name of object s1.

    3.1.2. Non-configurable Instance Variables

    In practice, not all instance variables should be configurable. But still, we want to be able to provide defaults similar to properties. To define non-configurable instance variables the predefined method variable can be used. Such instance variables are often used for e.g. keeping the internal state of an object. The usage of variable is in many respects similar to property. One difference is, that property uses the same syntax as for method parameters, whereas variable receives the default value as a separate argument (similar to the variable command in plain Tcl). The introductory Stack example in Listing 2 uses already the method variable.

    Listing 19: Declaring Variables

    nx::Class create Base {
      :variable x 1
      # ...
    }
    
    nx::Class create Derived -superclass Base {
      :variable y 2
      # ...
    }
    
    # Create instance of the class Derived
    Derived create d1
    
    # Object d1 has instance variables
    # x == 1 and y == 2

    Note that the variable definitions are inherited in the same way as properties. The example in Listing 19 shows a class Derived that inherits from Base. When an instance d1 is created, it will contain the two instance variables x and y. Note that the variable declarations from property and variable are used to initialize (and to configure) the instances variables of an object.

    Listing 20: Setting Variables in the Constructor

    nx::Class create Base2 {
     # ...
     :method init {} {
       set :x 1
       # ....
     }
    }
    
    nx::Class create Derived2 -superclass Base2 {
     # ...
     :method init {} {
       set :y 2
       next
       # ....
     }
    }
    
    # Create instance of the class Derived2
    Derived2 create d2

    In many other object oriented languages, the instance variables are initialized solely by the constructor (similar to class Derived2 in Listing 20). This approach is certainly also possible in NX. Note that the approach using constructors requires an explicit method chaining between the constructors and is less declarative than the approach in NX using property and variable.

    Both, property and variable provide much more functionalities. One can for example declare public, protected or private accessor methods, or one can define variables to be incremental (for e.g. adding values to a list of values), or one can define variables specific behavior.

    3.2. Method Definitions

    The basic building blocks of an object oriented program are object and classes, which contain named pieces of code, the methods.

    Methods are subroutines (pieces of code) associated with objects and/or classes. A method has a name, receives optionally arguments during invocation and returns a value.

    Plain Tcl provides subroutines, which are not associated with objects or classes. Tcl distinguishes between +proc+s (scripted subroutines) and commands (system-languages implemented subroutines).

    Methods might have different scopes, defining, on which kind of objects these methods are applicable to. These are described in more detail later on. For the time being, we deal here with methods defined on classes, which are applicable for the instance of these classes.

    3.2.1. Scripted Methods

    Since NX is a scripting language, most methods are most likely scripted methods, in which the method body contains Tcl code.

    Listing 21: Scripted method

    # Define a class
    nx::Class create Dog {
    
      # Define a scripted method for the class
      :public method bark {} {
        puts "[self] Bark, bark, bark."
      }
    }
    
    # Create an instance of the class
    Dog create fido
    
    # The following line prints "::fido Bark, bark, bark."
    fido bark

    In the example above we create a class Dog with a scripted method named bark. The method body defines the code, which is executed when the method is invoked. In this example, the method bar prints out a line on the terminal starting with the object name (this is determined by the built-in command self) followed by "Bark, bark, bark.". This method is defined on a class and applicable to instances of the class (here the instance fido).

    3.2.2. C-implemented Methods

    Not all of the methods usable in NX are scripted methods; many predefined methods are defined in the underlying system language, which is typically C. For example, in Listing 21 we used the method create to create the class Dog and to create the dog instance fido. These methods are implemented in C in the next scripting framework.

    C-implemented methods are not only provided by the underlying framework but might be as well defined by application developers. This is an advanced topic, not covered here. However, application developer might reuse some generic C code to define their own C-implemented methods. Such methods are for example accessors, forwarders and aliases.

    An accessor method is a method that accesses instance variables of an object. A call to an accessor without arguments uses the accessor as a getter, obtaining the actual value of the associated variable. A call to an accessor with an argument uses it as a setter, setting the value of the associated variable.

    NX provides support for C-implemented accessor methods. Accessors have already been mentioned in the section about properties. When the option -accessor public|protected|private is provided to a variable or property definition, NX creates automatically a same-named accessors method.

    Listing 22: Accessor Methods

    nx::Class create Dog {
     :public method bark {} { puts "[self] Bark, bark, bark." }
     :method init {} { Tail create [self]::tail}
    }
    
    nx::Class create Tail {
      :property -accessor public {length:double 5}
      :public method wag {} {return Joy}
    }
    
    # Create an instance of the class
    Dog create fido
    
    # Use the accessor "length" as a getter, to obtain the value
    # of a property. The following call returns the length of the
    # tail of fido
    fido::tail length get
    
    # Use the accessor "length" as a setter, to alter the value
    # of a property. The following call changes the length of
    # the tail of fido
    fido::tail length set 10
    
    # Show that an invalid value raises an error
    fido::tail length set "Hello"

    Listing 22 shows an extended example, where every dog has a tail. The object tail is created as a subobject of the dog in the constructor init. The subobject can be accessed by providing the full name of the subobject fido::tail. The method length is an C-implemented accessor, that enforces the value constraint (here a floating point number, since length uses the value constraint double). Line 25 will therefore raise an exception, since the provided values cannot be converted to a double number.

    Listing 23: Forwarder Methods

    nx::Class create Dog {
      :public method bark {} { puts "[self] Bark, bark, bark." }
      :method init {} {
        Tail create [self]::tail
        :public object forward wag [self]::tail wag
      }
    }
    
    nx::Class create Tail {
      :property {length 5}
      :public method wag {} {return Joy}
    }
    
    # Create an instance of the class
    Dog create fido
    
    # The invocation of "fido wag" is delegated to "fido::tail wag".
    # Therefore, the following method returns "Joy".
    fido wag

    Listing 23 again extends the example by adding a forwarder named wag to the object (e.g. fido). The forwarder redirects all calls of the form fido wag with arbitrary arguments to the subobject fido::tail.

    A forwarder method is a C-implemented method that redirects an invocation for a certain method to either a method of another object or to some other method of the same object. Forwarding an invocation of a method to some other object is a means of delegation.

    The functionality of the forwarder can just as well be implemented as a scripted method, but for the most common cases, the forward implementation is more efficient, and the forward method expresses the intention of the developer.

    The method forwarder has several options to change e.g. the order of the arguments, or to substitute certain patterns in the argument list etc. This will be described in later sections.

    3.2.3. Method-Aliases

    An alias method is a means to register either an existing method, or a Tcl proc, or a Tcl command as a method with the provided name on a class or object.

    In some way, the method alias is a restricted form of a forwarder, though it does not support delegation to different objects or argument reordering. The advantage of the method alias compared to a forwarder is that it has close to zero overhead, especially for aliasing c-implemented methods.

    Listing 24: Method-Alias

    nx::Class create Dog {
      :public method bark {} { puts "[self] Bark, bark, bark." }
    
      # Define a public alias for the method "bark"
      :public alias warn [:info method handle bark]
      # ...
    }
    
    # Create an instance of the class
    Dog create fido
    
    # The following line prints "::fido Bark, bark, bark."
    fido warn

    Listing 24 extends the last example by defining an alias for the method bark. The example only shows the bare mechanism. In general, method aliases are very powerful means for reusing pre-existing functionality. The full object system of NX and XOTcl2 is built from aliases, reusing functionality provided by the next scripting framework under different names. Method aliases are as well a means for implementing traits in NX.

    3.3. Method Protection

    All kinds of methods might have different kind of protections in NX. The call-protection defines from which calling context methods might be called. The Next Scripting Framework supports as well redefinition protection for methods.

    NX distinguishes between public, protected and private methods, where the default call-protection is protected.

    A public method can be called from every context. A protected method can only be invoked from the same object. A private method can only be invoked from methods defined on the same entity (defined on the same class or on the same object) via the invocation with the local flag (i.e. ": -local foo").

    All kind of method protections are applicable for all kind of methods, either scripted or C-implemented.

    The distinction between public and protected leads to interfaces for classes and objects. Public methods are intended for consumers of these entities. Public methods define the intended ways of providing methods for external usages (usages, from other objects or classes). Protected methods are intended for the implementor of the class or subclasses and not for public usage. The distinction between protected and public reduces the coupling between consumers and the implementation, and offers more flexibility to the developer.

    Listing 25: Protected Methods

    nx::Class create Foo {
    
      # Define a public method
      :public method foo {} {
        # ....
        return [:helper]
      }
    
      # Define a protected method
      :method helper {} {
         return 1
      }
    }
    
    # Create an instance of the class:
    Foo create f1
    
    # The invocation of the public method "foo" returns 1
    f1 foo
    
    # The invocation of the protected method "helper" raises an error:
    f1 helper

    The example above uses :protected method helper …. We could have used here as well :method helper …, since the default method call-protection is already protected.

    The method call-protection of private goes one step further and helps to hide implementation details also for implementors of subclasses. Private methods are a means for avoiding unanticipated name clashes. Consider the following example:

    Listing 26: Private Methods

    nx::Class create Base {
      :private method helper {a b} {expr {$a + $b}}
      :public method foo     {a b} {: -local helper $a $b}
    }
    
    nx::Class create Sub -superclass Base {
      :public method bar     {a b} {: -local helper $a $b}
      :private method helper {a b} {expr {$a * $b}}
      :create s1
    }
    
    s1 foo 3 4     ;# returns 7
    s1 bar 3 4     ;# returns 12
    s1 helper 3 4  ;# raises error: unable to dispatch method helper

    The base class implements a public method foo using the helper method named helper. The derived class implements as well a public method bar, which is also using a helper method named helper. When an instance s1 is created from the derived class, the method foo is invoked which uses in turn the private method of the base class. Therefore, the invocation s1 foo 3 4 returns its sum. If the local flag had not been used in helper, s1 would have tried to call the helper of Sub, which would be incorrect. For all other purposes, the private methods are "invisible" in all situations, e.g., when mixins are used, or within the next-path, etc.

    By using the -local flag at the call site it is possible to invoke only the local definition of the method. If we would call the method without this flag, the resolution order would be the standard resolution order, starting with filters, mixins, object methods and the full intrinsic class hierarchy.

    NX supports the modifier private for methods and properties. In all cases private is an instrument to avoid unanticipated interactions and means actually "accessible for methods defined on the same entity (object or class)". The main usage for private is to improve locality of the code e.g. for compositional operations.

    In order to improve locality for properties, a private property defines therefore internally a variable with a different name to avoid unintended interactions. The variable should be accessed via the private accessor, which can be invoked with the -local flag. In the following example class D introduces a private property with the same name as a property in the superclass.

    Listing 27: Private Properties

    #
    # Define a class C with a property "x" and a public accessor
    #
    nx::Class create C {
      :property -accessor public {x c}
    }
    
    #
    # Define a subclass D with a private property "x"
    # and a method bar, which is capable of accessing
    # the private property.
    #
    nx::Class create D -superclass C {
      :property -accessor private {x d}
      :public method bar {p} {return [: -local $p get]}
    }
    
    #
    # The private and public (or protected) properties
    # define internally separate variable that do not
    # conflict.
    #
    D create d1
    puts [d1 x get]   ;# prints "c"
    puts [d1 bar x]   ;# prints "d"

    Without the private definition of the property, the definition of property x in class D would shadow the definition of the property in the superclass C for its instances (d1 x or set :x would return d instead of c).

    3.4. Applicability of Methods

    As defined above, a method is a subroutine defined on an object or class. This object (or class) contains the method. If the object (or class) is deleted, the contained methods will be deleted as well.

    3.4.1. Instance Methods

    Typically, methods are defined on a class, and the methods defined on the class are applicable to the instances (direct or indirect) of this class. These methods are called instance methods.

    In the following example method, foo is an instance method defined on class C.

    Listing 28: Methods applicable for instances

    nx::Class create C {
      :public method foo {} {return 1}
      :create c1
    }
    
    # Method "foo" is defined on class "C"
    # and applicable to the instances of "C"
    c1 foo

    There are many programming languages that only allow these types of methods. However, NX also allows methods to be defined on objects.

    3.4.2. Object Methods

    Methods defined on objects are object methods. Object methods are only applicable on the object, on which they are defined. Object methods cannot be inherited from other objects.

    The following example defines an object method bar on the instance c1 of class C, and as well as the object specific method baz defined on the object o1. An object method is defined via object method.

    Note that we can define an object method that shadows (redefines) for this object methods provided from classes.

    Listing 29: Object Method

    nx::Class create C {
      :public method foo {} {return 1}
      :create c1 {
         :public object method foo {} {return 2}
         :public object method bar {} {return 3}
      }
    }
    
    # Method "bar" is an object specific method of "c1"
    c1 bar
    
    # object-specific method "foo" returns 2
    c1 foo
    
    # Method "baz" is an object specific method of "o1"
    nx::Object create o1 {
      :public object method baz {} {return 4}
    }
    o1 baz

    3.4.3. Class Methods

    A class method is a method defined on a class, which is only applicable to the class object itself. The class method is actually an object method of the class object.

    In NX, all classes are objects. Classes are in NX special kind of objects that have e.g. the ability to create instances and to provide methods for the instances. Classes manage their instances. The general method set for classes is defined on the meta-classes (more about this later).

    The following example defines a public class method bar on class C. The class method is specified by using the modifier object in front of method in the method definition command.

    Listing 30: Class Methods

    nx::Class create C {
      #
      # Define a class method "bar" and an instance
      # method "foo"
      #
      :public object method bar {} {return 2}
      :public method foo {} {return 1}
    
      #
      # Create an instance of the current class
      #
      :create c1
    }
    
    # Method "bar" is a class method of class "C"
    # therefore, applicable on the class object "C"
    C bar
    
    # Method "foo" is an instance method of "C"
    # therefore, applicable on instance "c1"
    c1 foo
    
    # When trying to invoke the class method on the
    # instance, an error will be raised.
    c1 bar

    In some other object-oriented programming languages, class methods are called "static methods".

    3.5. Ensemble Methods

    NX provides ensemble methods as a means to structure the method name space and to group related methods. Ensemble methods are similar in concept to Tcl’s ensemble commands.

    An ensemble method is a form of a hierarchical method consisting of a container method and sub-methods. The first argument of the container method is interpreted as a selector (the sub-method). Every sub-method can be a container method as well.

    Ensemble methods provide a means to group related commands together, and they are extensible in various ways. It is possible to add sub-methods at any time to existing ensembles. Furthermore, it is possible to extend ensemble methods via mixin classes.

    The following example defines an ensemble method for string. An ensemble method is defined when the provide method name contains a space.

    Listing 31: Ensemble Method

    nx::Class create C {
    
        # Define an ensemble method "string" with sub-methods
        # "length", "tolower" and "info"
    
        :public method "string length"  {x} {....}
        :public method "string tolower" {x} {...}
        :public method "string info" {x} {...}
        #...
        :create c1
    }
    
    # Invoke the ensemble method
    c1 string length "hello world"

    3.6. Method Resolution

    When a method is invoked, the applicable method is searched in the following order:

    Per-object Mixins -> Per-class Mixins -> Object -> Intrinsic Class Hierarchy

    In the case, no mixins are involved, first the object is searched for an object method with the given name, and then the class hierarchy of the object. The method can be defined multiple times on the search path, so some of these method definitions might be shadowed by the more specific definitions.

    Listing 32: Method Resolution with Intrinsic Classes

    nx::Class create C {
      :public method foo {} {
        return "C foo: [next]"
      }
    }
    
    nx::Class create D -superclass C {
    
      :public method foo {} {
        return "D foo: [next]"
      }
    
       :create d1 {
         :public object method foo {} {
           return "d1 foo: [next]"
         }
       }
    }
    
    # Invoke the method foo
    d1 foo
    # result: "d1 foo: D foo: C foo: "
    
    # Query the precedence order from NX via introspection
    d1 info precedence
    # result: "::D ::C ::nx::Object"

    Consider the example in Listing 32. When the method foo is invoked on object d1, the object method has the highest precedence and is therefore invoked. The object methods shadows the same-named methods in the class hierarchy, namely the method foo of class D and the method foo of class C. The shadowed methods can be still invoked, either via the primitive next or via method handles (we used already method handles in the section about method aliases). In the example above, next calls the shadowed method and add their results to the results of every method. So, the final result contains parts from d1, D and C. Note that the topmost next in method foo of class C shadows no method foo and simply returns empty (and not an error message).

    The introspection method info precedence provides information about the order, in which classes processed during method resolution.

    Listing 33: Method Resolution with Mixin Classes

    nx::Class create M1 {
      :public method foo {} { return "M1 foo: [next]"}
    }
    nx::Class create M2 {
      :public method foo {} { return "M2 foo: [next]"}
    }
    
    #
    # "d1" is created based on the definitions of the last example
    #
    # Add the methods from "M1" as per-object mixin to "d1"
    d1 object mixins add M1
    
    #
    # Add the methods from "M2" as per-class mixin to class "C"
    C mixins add M2
    
    # Invoke the method foo
    d1 foo
    # result: "M1 foo: M2 foo: d1 foo: D foo: C foo: "
    
    # Query the precedence order from NX via introspection
    d1 info precedence
    # result: "::M1 ::M2 ::D ::C ::nx::Object"

    The example in Listing 33 is an extension of the previous example. We define here two additional classes M1 and M2 which are used as per-object and per-class mixins. Both classes define the method foo, these methods shadow the definitions of the intrinsic class hierarchy. Therefore, an invocation of foo on object d1 causes first an invocation of method in the per-object mixin.

    Listing 34: Method Invocation Flags

    #
    # "d1" is created based on the definitions of the last two examples,
    # the mixins "M1" and "M2" are registered.
    #
    # Define a public object method "bar", which calls the method
    # "foo" which various invocation options:
    #
    d1 public object method bar {} {
       puts [:foo]
       puts [: -local foo]
       puts [: -intrinsic foo]
       puts [: -system foo]
    }
    
    # Invoke the method "bar"
    d1 bar

    In the first line of the body of method bar, the method foo is called as usual with an implicit receiver, which defaults to the current object (therefore, the call is equivalent to d1 foo). The next three calls show how to provide flags that influence the method resolution. The flags can be provided between the colon and the method name. These flags are used rather seldom but can be helpful in some situations.

    The invocation flag -local means that the method has to be resolved from the same place, where the current method is defined. Since the current method is defined as an object method, foo is resolved as an object method. The effect is that the mixin definitions are ignored. The invocation flag -local was already introduced in the section about method protection, where it was used to call private methods.

    The invocation flag -intrinsic means that the method has to be resolved from the intrinsic definitions, meaning simply without mixins. The effect is here the same as with the invocation flag -local.

    The invocation flag -system means that the method has to be resolved from basic - typically predefined - classes of the object system. This can be useful, when script overloads system methods, but still want to call the shadowed methods from the base classes. In our case, we have no definitions of foo on the base sclasses, therefore, an error message is returned.

    The output of Listing 34 is:

       M1 foo: M2 foo: d1 foo: D foo: C foo:
       d1 foo: D foo: C foo:
       d1 foo: D foo: C foo:
       ::d1: unable to dispatch method 'foo'

    3.7. Parameters

    NX provides a generalized mechanism for passing values to either methods (we refer to these as method parameters) or to objects (these are called configure parameters). Both kind of parameters might have different features, such as:

    • Positional and non-positional parameters

    • Required and non-required parameters

    • Default values for parameters

    • Value-checking for parameters

    • Multiplicity of parameters

    TODO: complete list above and provide a short summary of the section

    Before we discuss method and configure parameters in more detail, we describe the parameter features in the subsequent sections based on method parameters.

    3.7.1. Positional and Non-Positional Parameters

    If the position of a parameter in the list of formal arguments (e.g. passed to a function) is significant for its meaning, this is a positional parameter. If the meaning of the parameter is independent of its position, this is a non-positional parameter. When we call a method with positional parameters, the meaning of the parameters (the association with the argument in the argument list of the method) is determined by its position. When we call a method with non-positional parameters, their meaning is determined via a name passed with the argument during invocation.

    Listing 35: Positional and Non-Positional Method Parameters

    nx::Object create o1 {
    
      #
      # Method foo has positional parameters:
      #
      :public object method foo {x y} {
        puts "x=$x y=$y"
      }
    
      #
      # Method bar has non-positional parameters:
      #
      :public object method bar {-x -y} {
        puts "x=$x y=$y"
      }
    
      #
      # Method baz has non-positional and
      # positional parameters:
      #
      :public object method baz {-x -y a} {
        puts "x? [info exists x] y? [info exists y] a=$a"
      }
    }
    
    # invoke foo (positional parameters)
    o1 foo 1 2
    
    # invoke bar (non-positional parameters)
    o1 bar -y 3 -x 1
    o1 bar -x 1 -y 3
    
    # invoke baz (positional and non-positional parameters)
    o1 baz -x 1 100
    o1 baz 200
    o1 baz -- -y

    Consider the example in Listing 35. The method foo has the argument list x y. This means that the first argument is passed in an invocation like o1 foo 1 2 to x (here, the value 1), and the second argument is passed to y (here the value 2). Method bar has in contrary just with non-positional arguments. Here we pass the names of the parameter together with the values. In the invocation o1 bar -y 3 -x 1 the names of the parameters are prefixed with a dash ("-"). No matter whether in which order we write the non-positional parameters in the invocation (see line 30 and 31 in Listing 35) in both cases the variables x and y in the body of the method bar get the same values assigned (x becomes 1, y becomes 3).

    It is certainly possible to combine positional and non-positional arguments. Method baz provides two non-positional parameter (-y and -y) and one positional parameter (namely a). The invocation in line 34 passes the value of 1 to x and the value of 100 to a. There is no value passed to y, therefore, value of y will be undefined in the body of baz, info exists y checks for the existence of the variable y and returns 0.

    The invocation in line 35 passes only a value to the positional parameter. A more tricky case is in line 36, where we want to pass -y as a value to the positional parameter a. The case is more tricky since syntactically the argument parser might consider -y as the name of one of the non-positional parameters. Therefore, we use -- (double dash) to indicate the end of the block of the non-positional parameters and therefore the value of -y is passed to a.

    3.7.2. Optional and Required Parameters

    Per default positional parameters are required, and non-positional parameters are optional (they can be left out). By using parameter options, we can as well define positional parameters, which are optional, and non-positional parameters, which are required.

    Listing 36: Optional and Required Method Parameters

    nx::Object create o2 {
    
      #
      # Method foo has one required and one optional
      # positional parameter:
      #
      :public object method foo {x:required y:optional} {
        puts "x=$x y? [info exists y]"
      }
    
      #
      # Method bar has one required and one optional
      # non-positional parameter:
      #
      :public object method bar {-x:required -y:optional} {
        puts "x=$x y? [info exists y]"
      }
    }
    
    # invoke foo (one optional positional parameter is missing)
    o2 foo 1

    The example in Listing 36 defined method foo with one required and one optional positional parameter. For this purpose we use the parameter options required and optional. The parameter options are separated from the parameter name by a colon. If there are multiple parameter options, these are separated by commas (we show this in later examples).

    The parameter definition x:required for method foo is equivalent to x without any parameter options (see e.g. previous example), since positional parameters are per default required. The invocation in line 21 of Listing 36 will lead to an undefined variable y in method foo, because no value us passed to the optional parameter. Note that only trailing positional parameters might be optional. If we would call method foo of Listing 35 with only one argument, the system would raise an exception.

    Similarly, we define method bar in Listing 36 with one required and one optional non-positional parameter. The parameter definition -y:optional is equivalent to -y, since non-positional parameter are per default optional. However, the non-positional parameter -x:required is required. If we invoke bar without it, the system will raise an exception.

    3.7.3. Default Values for Parameters

    Optional parameters might have a default value. This default value is used, when no argument is provided for the corresponding parameter. Default values can be specified for positional and non-positional parameters.

    Listing 37: Method Parameters with Default Values

    nx::Object create o3 {
    
      #
      # Positional parameter with default value:
      #
      :public object method foo {{x 1} {y 2}} {
        puts "x=$x y=$y"
      }
    
      #
      # Non-positional parameter with default value:
      #
      :public object method bar {{-x 10} {-y 20}} {
        puts "x=$x y=$y"
      }
    }
    
    # use default values
    o3 foo
    o3 bar

    In order to define a default value for a parameter, the parameter specification must be of the form of a 2-element list, where the second argument is the default value. See for an example in Listing 37.

    3.7.4. Value Constraints

    NX provides value constraints for all kind of parameters. By specifying value constraints, a developer can restrict the permissible values for a parameter and document the expected values in the source code. Value checking in NX is conditional, it can be turned on or off in general, or on a per-usage level (more about this later). The same mechanisms can be used not only for input value checking, but as well for return value checking (we will address this point as well later).

    Built-in Value Constraints

    NX comes with a set of built-in value constraints, which can be extended on the scripting level. The built-in checkers are either the native checkers provided directly by the Next Scripting Framework (the most efficient checkers) or the value checkers provided by Tcl through string is …. The built-in checkers have as well the advantage that they can be used also at any time during bootstrap of an object system, at a time, when e.g. no objects or methods are defined. The same checkers are used as well for all C-implemented primitives of NX and the Next Scripting Framework.

    value-checkers.png
    Figure 38. General Applicable Value Checkers in NX

    Figure 38 shows the built-in general applicable value checkers available in NX, which can be used for all method and configure parameters. In the next step, we show how to use these value-checkers for checking permissible values for method parameters. Then we will show, how to provide more detailed value constraints.

    Listing 39: Method Parameters with Value Constraints

    nx::Object create o4 {
    
      #
      # Positional parameter with value constraints:
      #
      :public object method foo {x:integer o:object,optional} {
        puts "x=$x o? [info exists o]"
      }
    
      #
      # Non-positional parameter with value constraints:
      #
      :public object method bar {{-x:integer 10} {-verbose:boolean false}} {
        puts "x=$x verbose=$verbose"
      }
    }
    
    # The following invocation raises an exception, since the
    # value "a" for parameter "x" is not an integer
    o4 foo a

    Value constraints are specified as parameter options in the parameter specifications. The parameter specification x:integer defines x as a required positional parameter which value is constraint to an integer. The parameter specification o:object,optional shows how to combine multiple parameter options. The parameter o is an optional positional parameter, its value must be an object (see Listing 39). Value constraints are specified exactly the same way for non-positional parameters (see method bar in Listing 39).

    Listing 40: Parameterized Value Constraints

    #
    # Create classes for Person and Project
    #
    nx::Class create Person
    nx::Class create Project
    
    nx::Object create o5 {
      #
      # Parameterized value constraints
      #
      :public object method work {
         -person:object,type=Person
         -project:object,type=Project
       } {
        # ...
      }
    }
    
    #
    # Create a Person and a Project instance
    #
    Person create gustaf
    Project create nx
    
    #
    # Use method with value constraints
    #
    o5 work -person gustaf -project nx

    The native checkers object, class, metaclass and baseclass can be further specialized with the parameter option type to restrict the permissible values to instances of certain classes. We can use for example the native value constraint object either for testing whether an argument is some object (without further constraints, as in Listing 37, method foo), or we can constrain the value further to some type (direct or indirect instance of a class). This is shown by method work in Listing 40 which requires the parameter -person to be an instance of class Person and the parameter -project to be an instance of class Project.

    Scripted Value Constraints

    The set of predefined value checkers can be extended by application programs via defining methods following certain conventions. The user defined value checkers are defined as methods of the class nx::Slot or of one of its subclasses or instances. We will address such cases in the next sections. In the following example we define two new value checkers on class nx::Slot. The first value checker is called groupsize, the second one is called choice.

    Listing 41: Scripted Value Checker for Method Parameters

    #
    # Value checker named "groupsize"
    #
    ::nx::Slot method type=groupsize {name value} {
      if {$value < 1 || $value > 6} {
        error "Value '$value' of parameter $name is not between 1 and 6"
      }
    }
    
    #
    # Value checker named "choice" with extra argument
    #
    ::nx::Slot method type=choice {name value arg} {
      if {$value ni [split $arg |]} {
        error "Value '$value' of parameter $name not in permissible values $arg"
      }
    }
    
    #
    # Create an application class D
    # using the new value checkers
    #
    nx::Class create D {
      :public method foo {a:groupsize} {
        # ...
      }
      :public method bar {a:choice,arg=red|yellow|green b:choice,arg=good|bad} {
        # ...
      }
    }
    
    D create d1
    
    # testing "groupsize";
    # the second call (with value 10) will raise an exception:
    d1 foo 2
    d1 foo 10
    
    # testing "choice"
    # the second call (with value pink for parameter a)
    # will raise an exception:
    d1 bar green good
    d1 bar pink bad

    In order to define a checker groupsize a method of the name type=groupsize is defined. This method receives two arguments, name and value. The first argument is the name of the parameter (mostly used for the error message) and the second parameter is provided value. The value checker simply tests whether the provided value is between 1 and 3 and raises an exception if this is not the case (invocation in line 36 in Listing 41).

    The checker groupsize has the permissible values defined in its method’s body. It is as well possible to define more generic checkers that can be parameterized. For this parameterization, one can pass an argument to the checker method (last argument). The checker choice can be used for restricting the values to a set of predefined constants. This set is defined in the parameter specification. The parameter a of method bar in Listing 41 is restricted to the values red, yellow or green, and the parameter b is restricted to good or bad. Note that the syntax of the permissible values is solely defined by the definition of the value checker in lines 13 to 17. The invocation in line 39 will be ok, the invocation in line 40 will raise an exception, since pink is not allowed.

    If the same checks are used in many places in the program, defining names for the value checker will be the better choice since it improves maintainability. For seldom used kind of checks, the parameterized value checkers might be more convenient.

    3.7.5. Multiplicity

    Multiplicity is used to define whether a parameter should receive single or multiple values.

    A multiplicity specification has a lower and an upper bound. A lower bound of 0 means that the value might be empty. A lower bound of 1 means that the parameter needs at least one value. The upper bound might be 1 or n (or synonymously *). While the upper bound of 1 states that at most one value has to be passed, the upper bound of n says that multiple values are permitted. Other kinds of multiplicity are currently not allowed.

    The multiplicity is written as parameter option in the parameter specification in the form lower-bound..upper-bound. If no multiplicity is defined the default multiplicity is 1..1, which means: provide exactly one (atomic) value (this was the case in the previous examples).

    Listing 42: Method Parameters with Explicit Multiplicity

    nx::Object create o6 {
    
      #
      # Positional parameter with a possibly empty
      # single value
      #
      :public object method foo {x:integer,0..1} {
        puts "x=$x"
      }
    
      #
      # Positional parameter with a possibly empty
      # list of values value
      #
      :public object method bar {x:integer,0..n} {
        puts "x=$x"
      }
    
      #
      # Positional parameter with a nonempty
      # list of values
      #
      :public object method baz {x:integer,1..n} {
        puts "x=$x"
      }
    }

    Listing 42 contains three examples for positional parameters with different multiplicities. Multiplicity is often combined with value constraints. A parameter specification of the form x:integer,0..n means that the parameter x receives a list of integers, which might be empty. Note that the value constraints are applied to every single element of the list.

    The parameter specification x:integer,0..1 means that x might be an integer or it might be empty. This is one style of specifying that no explicit value is passed for a certain parameter. Another style is to use required or optional parameters. NX does not enforce any particular style for handling unspecified values.

    All the examples in Listing 42 are for single positional parameters. Certainly, multiplicity is fully orthogonal with the other parameter features and can be used as well for multiple parameters, non-positional parameter, default values, etc.

    3.7.6. Defaults substitution

    Optional object and method parameters can set a default value. Recall that default values can be specified for positional and non-positional parameters, alike. This default value is used to define a corresponding method-local and object variable, respectively, and to set it to the default value. By default, the default value is taken literally (without any substitutions). Default values can also be preprocessed into a final value using Tcl substitution as provided by the Tcl [subst] command. To control the kind of substitutions to be performed, the parameter option substdefault can be provided.

    Listing 43: Default-value substitution using substdefault

    nx::Class create ::D
    nx::Class create ::C {
      #
      # By default, all substitutions (command, variable, control
      # characters) are active, when "substdefault" is used:
      #
      :property {d:object,type=::D,substdefault {[::D new]}}
    
      #
      # The actual property values are computed and
      # set at instantiation time.
      #
      :create ::c
    }
    
    ::c cget -d

    Listing 43 uses substdefault to provide a default value for the property d. In this example, the default value is a fresh instance of class ::D. When the parameter option substdefault is used default, all substitution kinds of Tcl are active: command, variable, and backslash substitution. substdefault can be parameterized to include or to exclude any combination of substitution kinds by providing a bit mask:

    • substdefault=0b111: all substitutions active (default)

    • substdefault=0b100: substitute backslashes only (like subst -novariables -nocommands)

    • substdefault=0b010: substitute variables only (like subst -nobackslashes -nocommands)

    • substdefault=0b001: substitute commands only (like subst -nobackslashes -novariables)

    • substdefault=0b000: substitute nothing (like subst -nobackslashes -nocommands -novariables, noop)

    4. Advanced Language Features

    4.1. Objects, Classes and Meta-Classes

    4.2. Resolution Order and Next-Path

    4.3. Details on Method and Configure Parameters

    The parameter specifications are used in NX for the following purposes. They are used for

    • the specification of input arguments of methods and commands, for

    • the specification of return values of methods and commands, and for

    • the specification for the initialization of objects.

    We refer to the first two as method parameters and the last one as configure parameters. The examples in the previous sections all parameter specification were specifications of method parameters.

    Method parameters specify properties about permissible values passed to methods.

    The method parameter specify how methods are invoked, how the actual arguments are passed to local variables of the invoked method and what kind of checks should be performed on these.

    Configure parameters are parameters that specify, how objects can be parameterized upon creation.

    Syntactically, configure parameters and method parameters are the same, although there are certain differences (e.g. some parameter options are only applicable for objects parameters, the list of object parameters is computed dynamically from the class structures, object parameters are often used in combination with special setter methods, etc.). Consider the following example, where we define the two application classes Person and Student with a few properties.

    Listing 44: Configure Parameters

    #
    # Define a class Person with properties "name"
    # and "birthday"
    #
    nx::Class create Person {
      :property name:required
      :property birthday
    }
    
    #
    # Define a class Student as specialization of Person
    # with and additional property
    #
    nx::Class create Student -superclass Person {
      :property matnr:required
      :property {oncampus:boolean true}
    }
    
    #
    # Create instances using configure parameters
    # for the initialization
    #
    Person create p1 -name Bob
    Student create s1 -name Susan -matnr 4711
    
    # Access property value via "cget" method
    puts "The name of s1 is [s1 cget -name]"

    The class Person has two properties name and birthday, where the property name is required, the property birthday is not. The class Student is a subclass of Person with the additional required property matnr and an optional property oncampus with the default value true (see Listing 44). The class diagram below visualizes these definitions.

    configure-parameter.png
    Figure 45. System and Application Classes

    In NX, these definitions imply that instances of the class of Person have the properties name and birthday as non-positional object parameters. Furthermore, it implies that instances of Student will have the configure parameters of Person augmented with the object parameters from Student (namely matnr and oncampus). Based on these configure parameters, we can create a Person named Bob and a Student named Susan with the matriculation number 4711 (see line 23 and 24 in <<xmp-object-parameters, instance variables name, matnr and oncampus (the latter is initialized with the default value).

    4.3.1. Configure Parameters available for all NX Objects

    The configure parameters are not limited to the application defined properties, also NX provides some predefined definitions. Since Person is a subclass of nx::Object also the configure parameters of nx::Object are inherited. In the introductory stack example, we used -mixins applied to an object to denote per-object mixins (see Listing 8). Since mixins is defined as a parameter on nx::Object it can be used as an object parameter -mixins for all objects in NX. To put it in other words, every object can be configured to have per-object mixins. If we would remove this definition, this feature would be removed as well.

    As shown in the introductory examples, every object can be configured via a scripted initialization block (the optional scripted block specified at object creation as last argument; see Listing 5 or Listing 12). The scripted block and its meaning are as well defined by the means of configure parameters. However, this configure parameter is positional (last argument) and optional (it can be omitted). The following listing shows the configure parameters of Person p1 and Student s1.

    Listing 46: Computed Actual Configure Parameter

    Configure parameters for Person p1:
       Command:
          p1 info lookup syntax configure
       Result:
          -name /value/ ?-birthday /value/? ?-object-mixins /mixinreg .../?
          ?-class /class/? ?-object-filters /filterreg .../? ?/__initblock/?
    
    Configure parameter for Student s1:
       Command:
          s1 info lookup syntax configure
       Result:
          ?-oncampus /boolean/? -matnr /value/ -name /value/
          ?-birthday /value/? ?-object-mixins /mixinreg .../? ?-class /class/?
          ?-object-filters /filterreg .../? ?/__initblock/?

    The given parameter show, how (a) objects can be configured at run time or (b) how new instances can be configured at creation time via the new or create methods. Introspection can be used to obtain the configuration parameters from an object via p1 info lookup parameters configure (returning the configure parameters currently applicable for configure or cget) or from a class Person info lookup parameters create on a class (returning the configure parameters applicable when an object of this class is created)

    The listed configure parameter types mixinreg and filterreg are for converting definitions of filters and mixins. The last value __initblock says that the content of this variable will be executed in the context of the object being created (before the constructor init is called). More about the configure parameter types later.

    4.3.2. Configure Parameters available for all NX Classes

    Since classes are certain kind of objects, classes are parameterized in the same way as objects. A typical parameter for a class definition is the relation of the class to its superclass.In our example, we have specified, that Student has Person as superclass via the non-positional configure parameter -superclass. If no superclass is specified for a class, the default superclass is nx::Object. Therefore, nx::Object is the default value for the parameter superclass.

    Another frequently used parameter for classes is -mixins to denote per-class mixins (see e.g. the introductory Stack example in Listing 10), which is defined in the same way.

    Since Student is an instance of the meta-class nx::Class it inherits the configure parameters from nx::Class (see class diagram Figure 45). Therefore, one can use e.g. -superclass in the definition of classes.

    Since nx::Class is a subclass of nx::Object, the meta-class nx::Class inherits the parameter definitions from the most general class nx::Object. Therefore, every class might as well be configured with a scripted initialization block the same way as objects can be configured. We used actually this scripted initialization block in most examples for defining the methods of the class. The following listing shows (simplified) the parameters applicable for Class Student.

    Listing 47: Parameters for Classes

    Configure parameter for class nx::Class
       Command:
          nx::Class info lookup syntax configure
       Result:
          ?-superclass /class .../? ?-mixins /mixinreg .../?
          ?-filters /filterreg .../? ?-object-mixins /mixinreg .../?
          ?-class /class/? ?-object-filters /filterreg .../? ?/__initblock/?

    4.3.3. User defined Parameter Types

    More detailed definition of the configure parameter types comes here.

    4.3.4. Slot Classes and Slot Objects

    In one of the previous sections, we defined scripted (application defined) checker methods on a class named nx::Slot. In general, NX offers the possibility to define value checkers not only for all usages of parameters but as well differently for method parameters or configure parameters

    slots.png
    Figure 48. Slot Classes and Objects

    4.3.5. Attribute Slots

    Still Missing

    • return value checking

    • switch

    • initcmd …

    • subst rules

    • converter

    • incremental slots

    5. Miscellaneous

    5.1. Profiling

    5.2. Unknown Handlers

    NX provides two kinds of unknown handlers:

    • Unknown handlers for methods

    • Unknown handlers for objects and classes

    5.2.1. Unknown Handlers for Methods

    Object and classes might be equipped with a method unknown which is called in cases, where an unknown method is called. The method unknown receives as first argument the called method followed by the provided arguments

    Listing 49: Unknown Method Handler

    ::nx::Object create o {
      :object method unknown {called_method args} {
        puts "Unknown method '$called_method' called"
      }
    }
    
    # Invoke an unknown method for object o:
    o foo 1 2 3
    
    # Output will be: "Unknown method 'foo' called"

    Without any provision of an unknown method handler, an error will be raised, when an unknown method is called.

    5.2.2. Unknown Handlers for Objects and Classes

    The next scripting framework provides in addition to unknown method handlers also a means to dynamically create objects and classes, when these are referenced. This happens e.g. when superclasses, mixins, or parent objects are referenced. This mechanism can be used to implement e.g. lazy loading of these classes. Nsf allows one to register multiple unknown handlers, each identified by a key (a unique name, different from the keys of other unknown handlers).

    Listing 50: Unknown Class Handler

    ::nx::Class public object method __unknown {name} {
      # A very simple unknown handler, showing just how
      # the mechanism works.
      puts "***** __unknown called with <$name>"
      ::nx::Class create $name
    }
    
    # Register an unknown handler as a method of ::nx::Class
    ::nsf::object::unknown::add nx {::nx::Class __unknown}
    
    ::nx::Object create o {
      # The class M is unknown at this point
    
      :object mixins add M
      # The line above has triggered the unknown class handler,
      # class M is now defined
    
      puts [:info object mixins]
      # The output will be:
      #     ***** __unknown called with <::M>
      #     ::M
    }

    The Next Scripting Framework allows one to add, query, delete and list unknown handlers.

    Listing 51: Unknown Handler registration

    # Interface for unknown handlers:
    # nsf::object::unknown::add /key/ /handler/
    # nsf::object::unknown::get /key/
    # nsf::object::unknown::delete /key/
    # nsf::object::unknown::keys
    References
    • U. Zdun, M. Strembeck, G. Neumann: Object-Based and Class-Based Composition of Transitive Mixins, Information and Software Technology, 49(8) 2007 .

    • G. Neumann and U. Zdun: Filters as a language support for design patterns in object-oriented scripting languages. In Proceedings of COOTS’99, 5th Conference on Object-Oriented Technologies and Systems, San Diego, May 1999.

    • G. Neumann and U. Zdun: Implementing object-specific design patterns using per-object mixins. In Proc. of NOSA`99, Second Nordic Workshop on Software Architecture, Ronneby, Sweden, August 1999.

    • G. Neumann and U. Zdun: Enhancing object-based system composition through per-object mixins. In Proceedings of Asia-Pacific Software Engineering Conference (APSEC), Takamatsu, Japan, December 1999.

    • G. Neumann and U. Zdun: XOTCL, an object-oriented scripting language. In Proceedings of Tcl2k: The 7th USENIX Tcl/Tk Conference, Austin, Texas, February 2000.

    • G. Neumann and U. Zdun: Towards the Usage of Dynamic Object Aggregations as a Form of Composition In: Proceedings of Symposium of Applied Computing (SAC’00), Como, Italy, Mar 19-21, 2000.

    • G. Neumann, S. Sobernig: XOTcl 2.0 - A Ten-Year Retrospective and Outlook, in: Proceedings of the Sixteenth Annual Tcl/Tk Conference, Portland, Oregon, October, 2009.

    • J. K. Ousterhout: Tcl: An embeddable command language. In Proc. of the 1990 Winter USENIX Conference, January 1990.

    • J. K. Ousterhout: Scripting: Higher Level Programming for the 21st Century, IEEE Computer 31(3), March 1998.

    • D. Wetherall and C. J. Lindblad: Extending Tcl for Dynamic Object-Oriented Programming. Proc. of the Tcl/Tk Workshop '95, July 1995.


    ./nsf2.4.0/doc/next-tutorial/configure-parameter.png000644 000766 000024 00000110746 12501766547 023247 0ustar00neumannstaff000000 000000 PNG  IHDRt< pHYs  iTXtXML:com.adobe.xmp 5 2 1 m @IDATx USf2d  B!ERDe&(iz;sb„ .f*~TO~RcNJX; %hQNMs,n]vq7t;蠃o?|![oUtG6mڸ H2&Mr]t?rH'O>ٍ?M>ݵnڡ=|Gn=tnӧOd֬Yn̙rqF- 80~=Cu[ofm$~5j{弎;J\" xS~(K,uFbx |"T$sϹO?}7tW\qL.]|;5\SyիV]uU9r6/;"ϯXRi)ECHhPۍ$I )9- >$vk_-&A_:رc,石K#ʱ+p< 7n,uYG4-Nز.+Z׌3\޽݊+:u5k&icԔh$(5(C̨ T}ݺu4Zȡ $}[gu[md??8^DDФTs9sX Ț>@_}B!EiWd?kXc 7ϱĔh)iaYM+v!@ţS*K0Ч[nEL o yjz'&K<cGb?̛7G{yld %1D#Y-PMִM$>{j8T/ղeK80fm&hv;\Νk&$͛7g s$h۵k' !u]%\"i>/]w;07m49Q'03Ze,XP `0sb_ePPi+i:{ 0@+AD'N]M绗^z)_~y"dv 7oÇ93M $%a6lc3]:_,\!QcmSOw]ҧ$9jBˋrp 2]9 o|C駟ws<>h#8qЧ{[D<^{±>VX(QU&V7`/T>,MONN_nj3 }q8iSTm#0"妔e&qlo"b*u.'Ab3h&C/7Żݩ6=6h+ZIL3ZndvI'im](/|-na$V h"DD}̹媔PNh>;y~[Gsλ,ރ,=+2@@It_d*hXU~h5 ֖tmMBXʌHׯlp+ /-+ӽ %ҏgX_e6VF8 u">۶m+~dzW; .,"#Oe0G)cphѢ)'OFf'4gh!`$a>~g _J d1 oF|BV!n舣H`3<1E ByBG&ذG}TȰo߾yz2K0|̜aOj$.!CČDd Ȋz'Q;k[:a&1>l׫W)?e}vf4}Z~r"و UYfe$jg }^C?f **H9?h"Y2M>OP=93w]5O.J\u_"lK3"1ѤSR e,H,rZ(DK56rz C\0+7gNem-p!<0sby'ePIL/72S$l :SN&3λ %*%2H^VL!@9ѲH$91rV |E2Y_:uT[oe}] |mLE#0FbaD#&!ڒ.Ihȑ^({  /-+܍Ȣ["Ģn,gDx2J?6|sSO=r#<7ove7fףGrr-edСC݌3܀?6mh}B}'a>>׵kW7~x馛:AJ١nVk3<3Nn7[o=w!5\u=Cnvs{Ē1 T& ;V1?۷o:ub 6&F`.]qHM'tk[oN;4G誺u뺕W^իWթSǿm~YWFRY5M*^su=V:~oh̟?_Klұqqƺ>͝;]y啲?sd({ Y?X>Xj$uVbؠ}[h׿,X_ķW[m5w饗_mr^9OUYObz4Z(esO>oK;}駲ذad8qvGkFC~6:TʤVPMi7>jIof";quul;E{7]vܟ:v0#"}>Fۺ#Fȱ:?կ_uYO e%j_>OP}9Gbĕ}ThCK,q/v~4w qa*D_~'qBTseF_+(m;'M^{mH,û\n}F&c٪6u,2Dׯ[k%\"C&/=*覭 ʋ]#T]vO^=p&`ZUN_̙3w{CE}Xn"G(KC!`XkL@0+sG,F"x'˸^zI_|~,8pK=_!PU[g#Q쯺*ALD^{c9]xᅮ[n~Μ9BXtLҫW/@M*b3" nР뮻G}$$O?Iߙ?&}i\pBwE?y r>|7nk?@"`j}܂ŞDxN;X1_p0xaqq[}<~K,3&VZC|fbT+Fb ӯn:H" #BTTԘ CnҤ^^c ҢE_6 8Fbq(lH~r͋Cixe?!AޏG#cL)¢U-'VEgO( f?Cfs; N!DOe]6-05&B;{W.V]uUG0gb`}b%nQ5_ Kme?ֶm86#H\o+D0H\M C&V{ -C -LC/OKr#}u| @$7sgϖ` \ z!`Ċ-ht6m8NO^nht#G޽{K Y~2˞!PU{pt_usH BEit{gkC(FbR&d}Y}]a!P4ĊݨR =7~7qx衇gV3s傀X)gd`^zI"}{Wdg1 b_Mo 5(B}p'ҹߏm:v~t(y\A53a@a0sba C0 X C0 Xa?ek˲!PU{N'|6d$G:u{뭷ҟhg@^0 !z C(FbEn]ܲeKתU+w}-rKYn3g;JY{uQ[ۻŋن!`$FH,1.Jܡu殾j7f̘CDv^{8q>|7n'g̙ oAV 'v}wpBwEZuO.iq?0yB$NVXAƠ3c!#jA2Aڶm8CLD'[oN;4ww?}WLrmɴ-uu+WD'!Ҿ]ƍ]nkѢ{G"}a!#ؑ*@;w1A )AL\pײ.03A\ĖH 'Tt|AgO<:w0R `$;T0 aJJeV>-./BL}M֭%s=瘮O>zYuh^hbZ3F@zcdgT0:urO>ݟ)}_kFz#<]s5pѬY3?mF[CGh2~F /the&!;13 E`6sڵsD'>R+HQF⼱ۺ#Fž+7߸뮻NС;]sO~*ڏ~ya02CgU&Ş*TYgujh\O4{}mbi04GN:nȐ!Lt<8Q;,2mHDs+R=i5,K"L Z_- @Lib0sbz G Qx#'h>K2OLXlj}!BH,5!,=碭Zݗ,= 2iaFiL C =Fb13 qkmfo~}_"=xA4žo߾cGHH0#`Qcdg_\_=>_(\˼cH8(0dLR Q|!xI6nxؤX❯cGt*T]vYǒNE:XL C s̜9Vv!`@0M,b/IJa/  >L}'.v!`D #OJ}Y7uTh"YCbS\zZk֭+G}⋔AC(OUew뮻mV֯__e>c٭ꮻ:7eʔd*VسMmɄ $ꫯT;ne@AHLݘu]X bM[ocLa{1. &.!`T&y!1*SO)յ-]<鶮s%5/6`׿w}(31 CV$>MǍ*{"JJ'>SNsҥ;v瞎Y {>Cr&1 ,%UVYB(K,3 FA%2?Aԩ ~'%;(; ,!`IlCd؟)k tl؏!B /CM:SI(۷oN 4v*K/]v#иqtC; DkF,!٦M/\f੧0e|2?cm]55rF$&2m཯)6qD\RKh|&@:(',>Ǝ̉T6jNd&d$A1g!~Xb]{[nnukN8~R9e"ӈ#{C(Gk?r!B<dd8|2b:u2B@ L=[47 "p~gDschbh##> HD5w-+7.9>VFHYfr)CjРA' AYFO/E  ZI'䔀v5m4?y 6СCW^)3In$eHS>}ѣACgC|FD*XOŬaW ~:r{ksU$?k*tA2O?z-A( (`}ܣx 餃9wiqGAhj<i? 8$GR}GĹr$IߋIh_* ~x̘12Ke I+W\1Gfle:hx4neAdC~ @J+$q'{E g㑴Me %0ZЪ*3x`q b<~1!Z\Wz=h8Z뭷kԨꪫjF;W!Zm 54LH OʊDOO(VVTJ>Qn!0 Z!J>o9hL|mvlĴw6 Y8N!dDV˝jEb rD%3H]uTG>.:YhUp ic39#dHl:>oD<iM>!B΁PfmvȀp?3 q@C" mKMc|o+jl9~ Ñ#G7HCE I8eAI2AX*쬛TB`Ѣnc315xdy`p3dxb;F;_{:ퟂoT"C%2jKb=ʧ:i9 Zi`tS. 8NyEZAc16Bd6ecF-'@41Y&\5}\,e*ID^z&l͓ʎ;oѠ!Ҧֶj~Zq)yAvZvu|TC?cW+.Lhةˆ2C Kjbzng[+궮+8{NPa<(ZIK}TNAn,wrG|ě@m9g_,x)&-#ءlyAlpIșĨi`1369Vh ˎJ0RV 告mXV,&#@_&cja* @xfwg|(qQNF|ΖRșx~-fAx{}tT=cL%,*ݮm #{@ZjRo=f͒ "|8 u<EMC$2Kg0L W#_;l, f=D -_eVMUm̜9u!-)}d63eEQ̣)1[^>X -@fb@$ڶm4hP#/Q_y1S`@@("`ӓ&8SFT-ZHrD2v3̽ے;&ZCfz)yn-t)=ꨣ$AײQrhINDUel22 L  3ތD`1ńLт!>Iyϐ!&GCa#+C``ذan8|pqtibZJH,Q&}}݅j :iaKܹhmqx"MEg}իWa(;&!v'{L3\B=wuW9V~Of9.Gr&1}XmU͋z\ TMVAzUtg/{(:ĽpѨl#Ff2GLx&bM!X-cN$tgb͉dN L)Ue591̈cǎtJ8ۙ7|~IF-Kec 17_Q7"1?30Lz}LdJ@@κf ~)ވ&@1f Z5h"=]DTaRhA6"+~+31@NQ׃@5=&@b*ƫ+{ء@#zxi|2˵"IJ.(4 9K0v}2,;&ԩS8C  p!Ʃ!PH h&ŋoCII(?LuJc#Gt/Bs!FLaD!(>iӦQFꫯgy饗D%m0`f3!K@QӁ\ T y f_0-Br)C`d2Ӷma̤Fa/q?pp`2Up^hМLhD,21g/1к]'ԧO;)~?MNe?kZ`酅h{G|7|y f_w؁bͤ&@m0 zvm&0aBQ   3̄`NCm|ҤIn]vmG Lȧ~*APaf1q*g)\':t M lb:D< 63kzE} ̈A,BVRdܛc0y䑢nF-&Hd̘1qFQ-Rڏ!!L77nbzxf@Y ?*U4&%A19^͊L{N93V,$408K8I+:#쉹 rH7n4Q؞;B bX" Zi_>yTJ`Sc'$۟|C; !Lru׍Q/D&/&0%rklmBM k ]X8L |"Psb.fKv_ >D(6WE})6q6 1#@qW,C"Y&@>&χ C(6vJDHߪ=!1[Cް&@>0'!`$Dcr? NC WrEή3 0bVp"`$!Pv!`f{f!O򉦥eI`>c>M4;`$@H,(0  k5j$Voߞ(2FbE nW+#|^'I0/( .twlO I4I M`&yh{҂"$DTf=zl32iMz޽d<C vJ+QK=kΫ-q MۺPV娲ڞNP"s EVkݮmAJfFhޕĪI @N!m]ٶ!h`n2ϯk)_ҙ)N4]j^LbZВcY_5|=~-?Jm]ӳ{N:tVqNxxx3a(ku{}?Mwh~C(Y~)n³e9]Hi=#[neBf5߇\7ߍ^S|E=I {wyAzÆ s'p#`hX6`)!.sR0y-Lu+0gʊʥ8KI?pjZk(g/Ry^z׈דco2OZb!!qꩧ:ߓѿv֬YI&GifXN_Q.p9,L<#!zk_XP>('xJ$`%]vґ{K.X>}t)o۶{eW\nV͖ݘ1cСC݌3܀/on5QXLۅctRyQߒfp}a^l~ᇤ؁D_̴ UfT9&~8~9縳>;wn;w:!Ί+͛'$׳gO1CGCH"|IYCȂ _|!ѢE{nS%Q kM8Qqů!@١LT&e* КȨ ǥ^5jhTȴ.4~ڜIL+!wm>&ϭnM7usu-[guJ+]wݸ-ۙgN>dWNɮjnРAw]oΜ9J&u֕ՓrI'9ƬlNs2)wI*" -Lfrwg}JkVpцŢ~n]vqӧOd^{5N;9 `w8p@V[I .7@'׫W/Igss%nI?~4ɓSe׎ rCCHMUY%3SRaDV曻 |0i h"~>PN[\^t"!5>h|ۗ_̐߻D+5EyDiN1S iӦIc SpQHoB袋A6m*v5C`hw| QF;N5|s ={{Y 1-C@Yf)%3#*<@~a1d Ov%U / 0RM$hrxBB\, ɟIqN'啊J%` dM\T2an.ofG/w]wœ[o޽{K0X_~ѨYgSOIu˖-݄ j4 ǎ+ O?]yW#&Z5$n|A LZn||AimAW^uB:x2@iA4qbX5? ]iܸ?cݚk:,Ѹ:1c@Zn-k~tMi)bG2ND %1M~?a0s'FB ?.]A`Ύ LxݞvEpPoPR͚5sK%Kd?;w,}d lJij";u$HvĈz ,!%0]QxL SLDWbTwe=#U =Y\$)j`ֲTA9kKFd/}]J ;Q$>4 !8bhc\Ƀj_vaVŤ8!eHˑ݅gτۡ!eZXpdb ,_ᶿ[H̊4&17D ,-;UsmFŏP@t?B'cX$JUz#/EF@,)>U#Ip $7 Ɯq!/wG)DM*"k$h Z&yp(8W|K@IDAT!䐤*AJ{Ahа R~Yn{q, 6 LheX= ) x#0n.Р满wC_(ߍo(mNjbBDitKn2FO\hz %**%L lPز/ }'k׮r? O}+8CQ"a@'5i7~9poƖ `ɢ3L}a ~+yge1=W8۬bt2 C jYŜH/P|AK"S 0a&s}ېLiNTŋr"€i^4K0 /-`imK 4pf, n %FK!Dϥb~4~21@@͈AÉ`4EP_9[<a1d)o)ח\r /2!̨$hYMJfuasVM ¢WL|a M6%Sb1&~>hgLF\ @HhGeCVxO/R8shՍV@FK2d˼wGk񙤕h>9 |S hzfQ!=bs eewK/($FEOTI\DG1. CF`RQїFdk`̝ĽKy!ɢM - 2Xu' 1{.MֆPd[a'lѧ(c2֭DaHy!LՂ؜zVy:'}rYé1A.&d|!=zј !q ѿ1~?M5IT*؝,(I4tz !dECݷ(ߊQ2ӵ^!Ԉ9T@!" @9˪X"C9Fӕ>L3V>1Rc#vA4''ڟ981|bNFEt pDǤ a:$sA`31* -kYR ),:G=l0*cp饗ݻ.DoM9\?GE!1 >>^>(hESQ#E0e$Z~TCBT|40E+ S$z.nGbI@392' WPA`| TJ~YYSїi: Eq||&C@ˍ̴(q;H_BxD c9T$hC>FaUaOBb  Nk _AR!'O$؀Dnɇk=ޡ j'1e)n>h$ SuqK,Y*4. Ctw eDH(+C(9Q3NdF:80v7x,]Q05};BJF9jk1&P( 33A9 4mڴY&/ibT:E(O=Wc/,U,7H Xqf chJ_=_vD>_ {d{ذa!5k,ˆ0)4M_'u <Ѩx衇wF!Dlg$b:B($ƏGBBRr>Q0pk 08 1IH {u,{(cc/&Cdz wq2 ^DA4.>$~ ^MR$D a &M8*l'3k96 @QH $;FҐdQJ#|7OCJ; BN~gyo[Vd>{7sј]\c&FL* s9HmE˔!*m@1yeE 4}< 2ϲ.+\LhT>5S#c`(G}쁦;!uOr;%140D F-3p^?)H᧟~A&CrBN; .Ϟ=;)vJn۶mޟޯQ_f絒GAШse'fO7n2eJW:THj{,k . e$!E^uF4P"LK/'$@O6LQ)0xN 80~SN3=L 0-v[HC9RbNE!1BI  )iF"0Y!nĂE:ch3(SO31үcƌ8=;Rԯ_?{z.PhD%dX.(V5R(KHxủDǫALϢMhMD #wswKtn?5N0A&>aݺus3gΔyp&h?@b1оj{EF em%xh$.#/#P nx xi篼J9ľdŃvaMZ8B09 !*&@ HT3JX}(yFbNVM#UA&} Gzh9Li??XO! &x l姫;OZ?y',_GSE&B̽&TQ tRA31~R+t!ʉ6tmeǹHXƃ#=xAE$K^̛D:*,41@3B ZlhZk?`0_Ťxx9p!8\̵H80xp l?Ep$SX+G8`,MwDfLѓL\܍=ZHB e2`b aXj*ϖn4c̄Z}ե_x|7JnmqsQ4ǎL&/07"LB[61޶lXYQh#T]ʌhOJ̉ *] 0{)~|ki W߯f0BhĚV5 ]b A@ 兲cFbV+v?x׾}-k4`Fel񚥿ٙOY2/#P&l'B<왒7tlw޽lD!@0d:mMm2DXZrtXc ⸚Fb)qvmY#0l0!bi%Q)Ab8@8%AXc_" HQ=Bb%L3*>}WɠjDqWl4L> BB_=Վ=E Gܳ>[EIJʉ ‚,؇'n2cv~X*f͚𢄨>+Re( ^&=zp#F;RD "`x;㵒D|(Ar,!h*Khdo^$)~ Z[TJ`TLpg'zƌB&мpalwq54>ɓPn}ẄACƆ/?\ߟɶObeìȚ \mevcXY{h'ࠒD%ZI(ր6O,Y# wLW6VB_ |yzkذaN@L>AX5-T 33M,fAJJ"C|0T3S팁IZe] ӖNn@OzҝZǯ waCɓ' ' %%ʆҥ\DȒU-M7m TȨZMDꪫ_|nւڴiAxJ^|)+`M]#,x ^~3 &2ǹƎ( @fP>fuX*z~iݺ8)] ҁhe#VHXϙ3K$m:LDv8.5*i0d L.￿|ʔS8HPNtQ2y,."10N*[kNL?|t1ɓ><ȤIׯw٤G%D?نXd4b p~o?!]wu,2MٳR0?.3jhz\1oUv^H,.K~ δP 1Z+ 65;T?Z])?fPAْ%KĬy;esJ!gu}e?ACC[ۘkzi $wk)qYr"Dr .ʝwީU1;&ՃeIU^Q}Q vmYy׻wor1)3XB'2pFۤI1Nʆcѹs倓^Xj=[ rB푳@rN!?R'(脏VWr8nߒ~OUאTOnʔ)b-D"T!b%'xvz&tr䤉 ./ 6~=&c$@r5eRۉxKӘ1cr,)3'I˷~+l;3rNiL $Y!Fx^n2eϨ~9mfE;KK5辨!'Zm߄ Ƥ~hEHhKx(2)-]twC?bXķL,w5=D>4hx>J!gM thEPut9p $7ƌȇrHݚUK蓂(jc&7t|!Ad1% =w\k/ԝ m`}ݗ]SIR"41|I8L,%Q߾}]xnomF gs"qAPT CƄ%0j', RbQm ".Wm 2LCIVyhHM+.>M Ťvl65H.=JeAdZfsLE!/]w{L rD 'кV51*Zuv@bx.aA {TD Iɉ5 k%;&*P|`|uy%vi97xZJ@$J XgF-\Aא>9rҢE <Qwuo&.LhlDY}H/5csmy3Lb$DCe6EE Y=ֹ!@%c2y'O<,UpᶺOיd!SY`9sfI D3w1ΣϚs}݋qK!P0rrHհDھ`:tfE4&W_uL'e k[ِ>"pg~Nstc2YfI$%wMBcI |DiL: 2D_ ezꩧ:#ǭ 20oCzn$ 7ܠEn+e@@:&e bW_}u?AYo޼bab͚5}@;s^&bAX08/ A,-!ֶmۄi]v`,I{`>X@br~wke[-&hƱ` zl}{W,Dnn,( D.o yk̉ekT004<N;9f%݇~xhk#$NmKg*ӧhm Q0 Z0/i)J(s='A}_xᅲeN Ԙ_~e-Yi@B0qD# ZQa%- 8f7F#7jSh^YLc@lИbL$FL,Fb, n\aÆ{n 9"WFO98ꨣyoGK:N8H0C[%H{Ub>#7j()?\r pWJ_ ' s1'A 1cLɰٳg>W_8 X&o^Cx`ر袋j@K?--EK$V& 1yG8,iɔ`:X0 NsQӃĂAL`?93_wtwv&=z}sjQUJ r$ ; r,h\ 'O~~"ץ McA9?T=3b8^SNW^yEXРcpsu4jr$?ً8G ނ*z,ݠD Kd(˭*Ӫ̙3'٬1$XL2TށShjw1҇ƅ3vt؃Lq85s>:ЖwyUTCPRpM Eԅ^(&'OLJ !0Sb~G⇧O. ~uhJ8 yGu7 ah]w%&J&0$) 1M$-6> Zx& ܹ]ƍ !@&E˂PS4@r&'Ef\bЍ <зEN";Һuk '%.R=T v.{$p,xe|4l;'!3.pƅ)8o^BdUY9 s0+>v`< 2BL1*/ӠT0pWz(>O[5`\cGu|j+,Zj%q?|fzܸqpPڦmWA8R5M,I VP>\qYPBeOC @߾}]0םcsJ8v0O=2~/GmСžmfÔJÇ]-|L{cdMʔ쉜`"0ɢoJt^7w^!K0c` z2{|!@LRi:U&> 1Eh@sc>(\ 4q}C,3߿IN`ߧM6m`9餓 wXs̓It~P.|hԨ̃W&^sdo'[("SұYJUTwbxn'Q[E f&9nԭ[7jٳŒ(m՘}A}|tl;5pfbѫW/w1Ǹ#GV- U߶FG l7>C=4JY<;쭷r+r sR[Wwb&0>d>}YfiӦU|T>?"#oƭZ%sTfI0+Yi^~VXs3utsw-Vv!kBjiy@ߖ,G<},˂_?i|{=v۹g}V:??9yMtH6ٵ@Xx8r 25o޼@wdX+ [>}D W-믑ʦFQc/S"3sbeKKaÆ,NtSN)e"@CleEL,۴RoX*t!P;LrG"o5NM d5Ú؇֛o"3+컴 `N0E{饗v  1*Tbi;B`,1ȍX>P4 < @G~a:!MB0ĨPYL/"7Tu>sQ;| L+(%K,߾Y{Cb|-L+Պx2x@Jcא6x|ii9!pGmJj aJ4QEcDz.w[P {!쵚 d0ʢEddPCSse_Τ`OG!H͉HO_[EAGuÆ s'O*ʍ&TIQ#)$o"3f\3qݫB`lŌx:P%0]7f$?|3I Y E`Hoc}uafgBDǘ֭[VU6IQ͊U Fw%Be[={/yR.LJ:Χ0.0Nr%0{(Db$F>AI&II'Ν6lg.-P~}_^O?vċK(Y-@?*ys]w'_45\wq` W<ᄏkҤ0 m&ZS L[NZXisZYwyߨsUt*ۅ !Zxx- `$`/\s9s#d}~0n\{J)k Z7[fyO?$kU,-vwi'a:}=#7n: _}m#{IJl+5kX0,Q`!-Z8H,]*%3_C'mQNQf8V?n1 ^:tc^xnWt<++5QQTX)3Rݗ2 .ܚDUMm%~ℰKL]v1Iqʔ)75H%H?cmw 0)<:6 ]f T_,e˖2ĉ3AE]$3$g( 7n`V_y$owy; 7 uV[m%eRoto[uU% u 5itMrrb`RBX`X+vW_} ܱk͟W,boc .}&.t@\kժU,=ztlVʱ"uek垁gSS֭[¼frByE)G'UT}ǀbA% R~[Ot9֦M&Ƶ*͓sZjͷK~R:v(Ǿk9+0cAC2ѣGl6q@cV[mXr-@d rX̵};Vb)7?Fm Z|hlAFH3I>!̚Pb$f_ Sao1cƈI$YSb8]Mgm>$"va#xzb^xg}&&[o=G DH^{>S?gzK%8_/ۘM#78zM9Pnͻ!Z1hgw,JK07 f !N"ϗ1kV"ӷЧNΒ2+ &Hi@~~G֭+d߾,#2xIaOSN5rL!壡#Fqѯd>*!1*d;-6H-4bO5M'VIk :QԩS(ڥ9>Rb;>euvoGXJ?0V4(Z_`LqcAg>$1+ɠk:TƤ\uU.vڹ> HJI n}N28a8$͚5KOIV>^)G?:J&QUݑ1$#^I~ ja_ r"&LxH&ASHEH Zf&dhHr N w| /do S$MbrCZo6sĢ̟2L K3E{7C2,/|5.LɋTIx0]ij?>d7JN$s*a04 Z N}q DTɝ.|_4X~axHcS1L)Bԣ*ܗ\ps;> l Fû10&>hǘ7< 4SO=U<kڴ}6䈣m; LCCiSb >N` ys})*mA!Lݼ'QMʞB.xBaQ/G"]4"CZ~`\FkL񇁩ڂMq',4T ?/(%}2|.h) RnPpaEVLUYB@t`n5`*+\1iȒHGŢ5znxMk41쯡h]&bR9<[sM%D˹*Zb d-mȌ5!P*L+%/ĥPĬB*)[Sf2T&ٶlV(FbbS=AZ>۩ҰcՇ@N}Շ=q)0sb)/} Y{|0t% ]EDEcHE5"]E{h IR2jD%%R$t1&ť"C01s~99>yfٷ^yYg1s#@9aFY~⏚ + _ǹN6@cCA0qzUr F_ӧ7nLd2k: R=Nx'pdΝ-Ux&>\c7RxE >dڴi1L] BӴOhI%l0+O<( ݒ` =p_9Hb%#_12 穸>9ATLppRJ|,W, oɲ3&C@ˊW ▢U!TbI"/8e&,O8Qb;YpL|_!9\04#6kLVfN:_fDŽG*V5?iYd3:իET_[}ޓz_v6l>|S×VcD?k,9gnΜ9rN:Zj={pD}?uTצM;%޲eׯ_"3g&M6eʔu;((UD( ﳡ߆~163ܶ076r#jSoda$kDK,{GI&]v =<-XmڴIXsɒ%9E۷oO<#y7d0b2-k͟??Z 68~rAD QO,PBƌj׮-E9Ǫ:Cu& 6իWr=z Ν;g{jnXwP [>x?˷p:\^=!&%:xOG={v"ņcbj,dU245jpk֬ѠG!A͡CE%wD`PPPڴBE *)wpb˖-@C@x@XEX04A,nF%tCv?|³܋Ax'JI"?>=5h{ŪbaO-J֭+,Po݄͛ j-hzB Z]ٷo_uA4!ZM8@c(Y}J3"$b 18B\:C)TBs"d֭[}jhȑ,}0n+UI Vӎ@xcWOvŭZJ$k.a %SXbC\l2[wAGMad۶m !ƍ޻qFi\~O/>X":ւBI*o@b -\08K >C9M C Xsb1h@Ѽys(t*㏋ՅŃլYT3¨E#<Ww*rò4t}s }&!GgV܁ɓxm''A_veBFc׮]}sf=c q;6 g YbbgrF 8Z~ss$;87e^ P> T !$g*wpͿAE `4z'L89r!뱞ˍ?Fb!+kRGTI͹]˺dǺq_L󛻷OL>Yi9a42˞ ɦ OJS nIECC@ˊ*,c9  eII.L  gӪ"Y󌀒_^<9tC`Ll󔓗Y$G @YsD7Ǝ#4*`ȏlRMKː^s; ,Xc.3)x.kEMID@KHOa}AbX? $Q₼)GFbQxB%1Kل}i9֪1U)I!2_|[e*4%<٣PM xi$] a-1#}ȼI-0 ,՗Y??|B[BD@+6(s=hꡌ7NЦ m޼5mڴʸ@-1*ҨST>L gV 먣rG}Pȍ{~u̳nɯߝaУFrf͒F SOe* ke}6b$ z1|V PTԶMC`((!65=;DC1=UCԔÇۅQv#!%0[ Xb JQV(# *(+q=ۂs*j)Qr~kѢE02M>L kBKaRa$?m-Pd E'0==S>R*9 L{<(VڠA\:u\n\VŋACUe~լY3t~La$)b%%Em?2h3}eFS 철rQV-|r׶m[w!iJDznƌr++VZNdw9d_|=3n˖-үxzuQz']Æ i^z۹s駟2}4믿5\5j#(}(ANԴ8琗6#D-~3e3twaq{[1ʵSNKx'Λo) I0 A 8]pW_X]w۷o;ȑ#ݵ^j5ll۶mtgu؅"PLҢ y)qPԌ3F@I=e61j{ | #! :T ~믻3g:y6mѣ\b\T1cƸO}\M7N* q@$U0ytA;sbk׺J^zItXȱ+}۸qKr?smzuH˖-s}x?ˆcN@.U?[1Q>Gur|Q"Siq=);ޫ j8} K.ĵnZQ8Itci_3N / M8 7o<@_#b%͝;W<4W^"qڵs+W&_%A1ׯ~˒4>BbgQ/R B poX||(XJ҄bBt\k"X$bү_?Q|gbh+nX"A矋G _A + /]Կ5ks# PqҾ}{y/MllĢThy)V^Q%  h?HS"{WV-%>8N9z/{#OɌWLL ڡFa@@@˗oYJRKɿ֮][;BgUYFH Ckroyns]v͉E~Z >[ۘ;AbA$SO|ф& kX*mE h +?8>Jlڿ~z>"pc={H]:ͨ~|  A#}!]tyH4h S&L @ՃtH VPa7HQ x饗~+ᵏ-Ub\O+[; C Da~MIUlݺ11(͛7wsqs ѣX&Mr;w7xcFz2!_}TKVe!# D}l=N*iٲ4?^ƪ _SabgEb d4 EKf9RB+M}fMF|G>;ŋK,Uĉ7!no:T8ݱcxt`<=0ٖE .ef^3}xX#`A:xرcPv":g|w)-hX:(YC(I Bd ^ȘA.;[eZJd +[jՄ!.*4uSASZg$3A@I!e 'U +T % +]7 ܱX^sC(hB%ʗqؿ+[ـ!$W 1%2)e/f$fQ@<菁*W 3 HLY0VkL2B!p(WذTB^8"?I$%XVAZSYdM)#Ybc C@"(Q%1Kl`Gf!X 9GS>.B!%0_Ȋ=a>e<#lгg C v@JlXY\Q>pR"=֗63r_Ib"g@lP KJIߓ9M#yAR>&["g@*ȜXvX-, Q" ͐?Fb! C4U4rY\(8۔e=o!P4-bC0 CYI0 C-FbtpC0 #1+!`EH,n!`$fe0 C Y C0Ĭ !`#~:K!`C0 "`$Og 7 C?:kIENDB`./nsf2.4.0/doc/alias.man.inc000644 000766 000024 00000005512 13030507000 016262 0ustar00neumannstaff000000 000000 [comment {-*- tcl -*- manpage fragment for alias method, shared by nx::Object and nx::Class}] [keywords "alias method"] [keywords "value checker"] [keywords "method handle"] [call [arg [vset CMD]] [opt "[method public] | [method private] | [method protected]"] [method "[vset MODIFIER] alias"] [opt [option -debug]] [opt [option -deprecated]] [arg methodName] [opt "[option -returns] [arg valueChecker]"] [opt "[option -frame] [const object] | [const method]"] [arg cmdName]] Define an [term "alias method"] for the given [vset SCOPE]. The resulting method registers a pre-existing Tcl command [arg cmdName] under the (alias) name [arg methodName] with the [vset SCOPE]. If [arg cmdName] refers to another [method method], the corresponding argument should be a valid [term "method handle"]. If a Tcl command (e.g., a [cmd proc]), the argument should be a fully qualified Tcl command name. If aliasing a subcommand (e.g., [cmd "array exists"]) of a Tcl namespace ensemble (e.g., [cmd array]), [arg cmdName] must hold the fully qualified subcommand name (and not the ensemble name of the subcommand). [para] As for a regular [method "[vset SCOPE] method"], [option "-returns"] allows for setting a [term "value checker"] on the values returned by the aliased command [arg cmdName]. [para] When creating an [term "alias method"] for a [emph C-implemented] Tcl command (i.e., command defined using the Tcl/NX C-API), [option -frame] sets the scope for variable references used in the aliased command. If the provided value is [const object], then variable references will be resolved in the context of the called object, i.e., the object upon which the [term "alias method"] is invoked, as if they were object variables. There is no need for using the colon-prefix notation for identifying object variables. If the value is [const method], then the aliased command will be executed as a regular method call. The command is aware of its called-object context; i.e., it can resolve [cmd ::nx::self]. In addition, the [term "alias method"] has access to the method-call context (e.g., [cmd nx::next]). If [option "-frame"] is omitted, and by default, the variable references will resolve in the context of the caller of the [term "alias method"]. [para] To express deprecation of the [term "alias method"] [arg methodName], set the [option "-deprecated"] flag. Deprecated methods remain usable from client code, but their usage will be signaled to the developer and/or can be tracked using [cmd ::nsf::deprecated]. To register [arg methodName] with the debugger, set the [option "-debug"] flag. Entering and exiting a method, which was flagged for debugging, is recorded by calling the redefinable callback procs [cmd ::nsf::debug::call] and [cmd ::nsf::debug::exit], respectively. By default, these callbacks forward to [cmd ::nsf::log], which can also be customized at the script level. ./nsf2.4.0/doc/trace-xotcl.html000644 000766 000024 00000026465 13464231231 017064 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/lib/trace.xotcl

    ./library/lib/trace.xotcl ./library/lib/trace.xotcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./library/lib/trace.xotcl

    Description: Various tracing tools for the XOTcl language.


    Class: Object

    Procs/Instprocs: lintFilter, showCall, showClass, showMsg, showStack, showTimeEnd, showTimeStart, showVars, statFilter, traceFilter.

    Instprocs

    • traceFilter args
      Arguments: args: arbitrary args
      Description: Filter to trace every method call on an object or class hierarchy. Outputs a message befora and after each call of the traced object.
      Return: empty string
    • lintFilter
      Description: Experimental lint filter
    • statFilter
      Description: Experimental statistics filter
    • showVars args
      Arguments: args: is of variables
      Description: Show the values of the specified variables (or of all variables) of an object on stderr.
    • showMsg msg
      Arguments: msg: optional output
      Description: Show a message msg with the form "[self] $cls->$method $msg" on stderr.
    • showClass
      Description: Show classes and mixins of the object
    • showStack maxDepth
      Arguments: maxDepth: max stack depth, default=100
      Description: Show callstack up to the specified calldepth.
    • showCall
      Description: Show the current call with the form "[self] $cls->$method $args" on stderr.
    • showTimeStart ?handle?
      Arguments: ?handle?: Handle object name, optional
      Description: start a timer
    • showTimeEnd ?handle?
      Arguments: ?handle?: Handle object name, optional
      Description: end a timer and show result


    Object: Trace

    Class: Object
    Procs closeTraceFile, openTraceFile, puts.
    Description: Write trace outputs and produce statistics. Variable traceStream defines where to write trace output (default: stderr).

    Procs

    • puts line
      Arguments: line: output line
      Description: Define how traceFilter writes to the output stream. Default: write to trace stream.
    • openTraceFile name
      Arguments: name: file name
      Description: Redirect trace output to file.
    • closeTraceFile name
      Arguments: name: file name
      Description: Close trace file and redirect output to stderr.



    Back to index page.

    ./nsf2.4.0/doc/Class.pdf000644 000766 000024 00000516221 12422512322 015477 0ustar00neumannstaff000000 000000 %PDF-1.4 % 1 0 obj <> endobj 22 0 obj <> endobj 23 0 obj <> endobj 24 0 obj <> endobj 25 0 obj <> endobj 26 0 obj <> endobj 27 0 obj <> endobj 28 0 obj <> endobj 29 0 obj <> endobj 21 0 obj <> endobj 20 0 obj <> endobj 2 0 obj <> endobj 36 0 obj <> stream x[KoGW rRPߏ\$ ] JL(R;l ȏOՐ)5{ܬztuW=R8L%wJ?2YU5FLUR8beK4IY5Ū^ 㩜7C%E.P@+E&I W6%a4p?vC+QB2i7X^nlcZcNZ!eKuNcJz2\ݘ?U2UC7xU\ M//.V'*T{ ؤQsw#S1n Shqpy*WOtCwS4~HMP . `>JVfuq6KHV}}u'X8ڙ.?(}Bybu RO@YM]nUvbRF?Q/~$29傛v Yq履}_]]y3RIyI2'L'ە):yM]]wyZu^~~iBze~:w)ZXОi_vMvXѭ!VvwgO{^^^^ջ妞pjhK8#|+cx/E1`a3nMАa@.M8 *2>pbm&dCЃ4gnYe; =1ڵ;ɹg55 RW i^qVL/B7.ܬ}VˑRT"PimF 8reh@1NJ†-8RN]  P:ȴ_gbB1XOkDLЬnW*X~}ibw|UTd^Oht[㽆\r]jYF1w+;U[Ly-Xq`MhTJhC! &(PGB4i8+d9UƦXIk޽]*iËpKbl,f=t5VsB"cf% w9׬m@J[28)+Ft"[O,6n![%K.PcҬrWM}xnhi hmzP/ SaӀ{1dP CCu iV A4pn:#DCc.n<4zGBF3\:d-G”ec餝Fa2VrlmD| ϱ袗j4K|kW偎8U#pź7ht~n:!Jv\4S`br5Taw2 qݎ˔K.X[i4+ڌu6#wiM k4#dFsBT:Wn>:N V Bu55_asksTg2!7iq$V^"19N#S< ! w%zHQ\ɴ-#iF[ &k;E-Z"H:3/#Om0 emR7=ŏ< RE0BՌ"оdz؝F(Uj MìVcʨAs*W3j8 ˴ޮvCݬ{z0G{](o=-P| zrxV>=ogp} "ɦަ9땐J]-7}I)P aA?켟ƫaIPCKW@QA8ƫўV$ -D=8P͵px[*;i.l(gXEIu\;n &*eԼS]8<S$T#1#@Fň̸m 0:I hԚb1PugI(HQ~w@<,C(UQ1q|5 l/|<1 h)?y6؈TE0E^ɹjbA/KD'(2Q)T^HIیoC&@f\-mX#H(yclhh)y :8QWg҈bBUV.-,0Z[/Y+UrLa(5>Dq4ݳxȋR9xkH3=űRh3V; x󢮖tٝ0ɧ8kS7ٝj#J9lj9/uaQ1bpAp2 ]JͲ㑟7j.,\]>Ew24D<Ǡ|Ic DI蚠ŠEJ#ʷ`x1K8FI >ʷ WO;|%ia-$ ՜|nЫYd2T[S!,,h20)գ_>նg@i1^/f-iQ' @V@sMAXJOJ8޾#Nw?R(aޏa6.1 UwHsT/*Ȑ7De5OHͳa0mWŘ  Ṝ؆EwښSe|Z v_m)xO|~cO|M, Ȟ&3*&ȋST `> Q,'j\" CqIncQ,R G%/]_&OroK2̱Թ@"s#$v_n&O; i*bϋ-PAO, ?g TfV˦~<ؐ8i*xuhؔNܼ(>` TcL DUqVh2 1"`yq1Kâ ?{)3YAV&g*i(h?bU2S:נB&:ZɇHns|rFyJ᫢;9"@XrRƭ]Q_VgeOi4FrT?ʼn3Ylۥ<?%S'_mCԙ~7b9D|y9$",sZe$ 3uZ xÏ!1Z7B[eDzl.Mq!$(gloHEHrFYΊ)$a$MJ0 LD<4gsyau񛧘B k1 t=F'$K}j4"A($ȉW-m&lv? v7*Kѱ.F-~Z}*Uu'% endstream endobj 37 0 obj 3581 endobj 80 0 obj <>>> stream xuRIr0BzT%9x.!ؓT*'-hht`ACXCd3<Ȉ`Hjܽn1U\h-CWk!4ɔE{R9/p:KKm\pO+]ih؜ 5(*PY 9#3]0TDΦh?tq*$;{A?cSbrYМTaejdEI[4Z#d_ )>JKmEmҩW]ںЦ90kiր dZ;/ZzVv}&X˜qc|T]~ endstream endobj 81 0 obj 303 endobj 3 0 obj <> /ProcSet [/PDF /Text]>> /Annots [78 0 R 79 0 R 38 0 R 39 0 R 40 0 R 41 0 R 42 0 R 43 0 R 44 0 R 45 0 R 46 0 R 47 0 R 48 0 R 49 0 R 50 0 R 51 0 R 52 0 R 53 0 R 54 0 R 55 0 R 56 0 R 57 0 R 58 0 R 59 0 R 60 0 R 61 0 R 62 0 R 63 0 R 64 0 R 65 0 R 66 0 R 67 0 R 68 0 R 69 0 R 70 0 R 71 0 R 72 0 R 73 0 R 74 0 R 75 0 R 76 0 R 77 0 R]>> endobj 78 0 obj <> /BS <> /Subtype /Text /T (www.princexml.com) /Subj (Prince - Non-commercial License) /Contents (This document was created with Prince, a great way of getting web content onto paper.) /Popup 79 0 R /Name /Note>> endobj 79 0 obj <> /Subtype /Popup /Parent 78 0 R /Open false>> endobj 38 0 obj <> endobj 39 0 obj <> endobj 40 0 obj <> endobj 41 0 obj <> endobj 42 0 obj <> endobj 43 0 obj <> endobj 44 0 obj <> endobj 45 0 obj <> endobj 46 0 obj <> endobj 47 0 obj <> endobj 48 0 obj <> endobj 49 0 obj <> endobj 50 0 obj <> endobj 51 0 obj <> endobj 52 0 obj <> endobj 53 0 obj <> endobj 54 0 obj <> endobj 55 0 obj <> endobj 56 0 obj <> endobj 57 0 obj <> endobj 58 0 obj <> endobj 59 0 obj <> endobj 60 0 obj <> endobj 61 0 obj <> endobj 62 0 obj <> endobj 63 0 obj <> endobj 64 0 obj <> endobj 65 0 obj <> endobj 66 0 obj <> endobj 67 0 obj <> endobj 68 0 obj <> endobj 69 0 obj <> endobj 70 0 obj <> endobj 71 0 obj <> endobj 72 0 obj <> endobj 73 0 obj <> endobj 74 0 obj <> endobj 75 0 obj <> endobj 76 0 obj <> endobj 77 0 obj <> endobj 82 0 obj <> stream x[Yo~ׯka lgR ȑ4 l?>U=WpVU4J¨ќ'3 OWK()4Ռ}vvwƨwNdr{NՆ8D CP)c_P@2^S&*NmIe[Kq~׭;t%׫8 a/^}ן\"׿z1ku`TlU0hE1pN=nj)^ FRhUPI4' Vb HE|kw׋-~:"_^CFnEF6aDdw^Fvg)~lC 7zJ(tdrkW޼"}=GKNv mI 8, M=w*rՉONQ+"/h6ܙJpdeB=e=w)~n]CqJ;*$tPr(9nUŷE^ܮ3rؑE[9PFƱ: %L֎P*#%Y yX|)%tNh VS?1IHx 2T{$ ;L )?-  tR3C5>xzeτN uP3,Cst/u\8A\?*?*[<!V =Ym|$>#n319t<4pbq ~jL簕 `H41!*I);8Rf&0_f5݀N2KR@u@4Qf@τjξc`k ƪGm==x|9^H$02s?u~sm~Rד d3| ZyZ|;>#u܌s^Sy;R(1w0,nɋhvn;n&/b)!ΝKL"gH4bJ R^hY, |ňaVzR}xF"t7u{ @('y5"ei$M5 `.~gHG 0=%zm%ZD_#3VpVKlׁs# غ'r)ё7ݱr(`8t䢕:v|-' ?*ہe&?5Ds$ܠ&?5x'r5QVRk9[9?aaͫRaAH j- kmvwbL+f(_l6bnڽk7ǘՠL.`7e҈[×;މ{3sgCHc9/aؾzֺz{Ʊyx:yI%2k<$O^lIpe숷C#Ox9f2y eׂ[+pF`<اT6WU)C@TY!I[ ceXjzl9#@X7IJبP>:@Y doZNiQA_'ďD4اl s6X & #7*sƮN=g|z 1/{ְ15.U@4qj㙰ɿÖpdTHaWޛ><j*_!Mz.A@=Wٲ e go4eFu" l@yZ3qQh ~OBةC"nd-86|}ǡ|jk :6+:z F(vJ5츸vsqeʷ jOgag-kMjk6JFg]}֕8d+rH[C:.O7iso§$~.5ZK797ۣ]q] og@{j6G Bd+4mGdxe,r^ ]~V$D@- (|/qfM¤DQ̬JZpdޙ`X ~݈Pʷow]~/0x)t i 7|o ))RcnWD󤻡 :#/O2FXP =!ܽ[jp^W Bc^ٮ:6L7奒5.=nɶHֹ3 i/7>~>sЋTqt/WӗUُxhPˏ^/o {u5Fc:;t`U ]kClz( *ܖn-pz^޾y9>X!>!6x 5!&pX!n8&OZȩ5hs/27E6fg'4!NQ)0Q!I= ܱ0X)j3(y?te 2x '6넅U~Gn+xT(gS~*J}f(ݭ`@_En4Yv*^ E$"4?Fˊ> o<%!+x!4+Y endstream endobj 83 0 obj 3349 endobj 4 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 84 0 obj <> stream x[[o~S̹_҇bݠڤ>XmsWT]oŋH񨛗$7˵2cќ/϶OWH2U.02XX-x'{<V>\)&2so b  wG.[nSDzXvEl> ͳf~-ԸQ#_P׸e0$R\h<1I~cb*wL!u&3$tn$,P{,bo \ cop72t<5ʐ DQ p"# Z>#ĺI7"I2N娙CsߖkeSV^zX߳|_z~&+(RSs(G?Cb nVX8l `,y ~-wMq *mxЮk3W1ͶEL"Ù K0bRzO+F\y:BVsuZ1Q!ɴb@-rH+/7hD̥qMf;u#Ěϕ 'Z+2 BupG+$7HCG|y7TF2("s! IDD$DfP0]-poF@\:;RPBKMt\tT{.UTq' 2h)P󲲜/%"h,K?-qi"#]X<+ꣲd8|*_U=m.v[}z):0D3[>T9f$7@W@J6>/,V H(Y\ -OD^"KCDRǃ[NZHX|ձa(*c| 7٪uLr7]XWS@uPW xu3\W=Qrz8~U¤m/@WTDž:~O@dPψhVǃ S]ֶ#~_lqp72^Vs&QQBFUޝSQHyjA)k}:}{^sT~l8rQgdeޑb$8.3E4IhT t_p8F8=Jң D^ >L$F- T˖ ^K@_T&J6#TDP4W h Jer?E̤BaF򰙒PP'4@Vdi3n$N V};1E tP7\wwfY$)i)Bx;]u(,g嶀%jaFTS~% [Q5 ~U@d(^%>5"'fzLs NF|)7ζexaM`ESp} >?TdJ4hړdRGFNQAAr$j|m䛯 d=Z*ץ/Of8}.ύ,wxwZnƧex+X_KVͿWlU H[QY|\n7@0D@4j_>~'FX^φ18Z\oSFP=!xjŷb~@z"KWYנt0ⱴ4v=`!SY6j#_K|<g%ѩrK}}HÕO33+9Kzߤn4L^ŮXB8cm8} FS8-%yih<]0%/n2Myme㆏Ӵ0"g-b'ԧM.> /ProcSet [/PDF /Text]>>>> endobj 86 0 obj <> stream x[KoW ,lra$G_FPM:J^'W=o3\uY^fh:;> etf(tЙIu&`s\dU*# Bse$ӌ"s3/]B=QvN0Ý>=" γOۻc٧N0)b.8I$<gZ)Bhfd$t>qgJBVfVqUdS;<^lNٻ`W@S``Ow'C UN90 e;cA<*bGRpCXObPP^.O`82n6S^lsocBuIr/"=$~%!JHI ;SR _,FoywE''>ZwϪ˵PF CU4=~Ͼ_㩌鲱@ݙ(ZOWh1AKxn-xlVܠJcUQ,y?I͵ɖOD^ 1A$y#x;>Qxu-:Kv@Z8J@YRGwGDH $jΘFU7nWPq*{|}{)'^& GU$y#&k Kpl5*FPJpfq ,ّfLR5e/15'h_|b< ։9L{hnlt{4TKW1}| ;i$㖈\P{]Wnm4>L 2h dU 7NF3R]`bjL, ܠE2S(&#tIL.jK:(KlT}]xE\8Po_Pgc- $&[+ׯrSWn(@ 4PQze/-"t ZsPB}׈ڝ~iHk뷶MW:HRFHyTPp R_,L>C__5;M(X4Fj%um:|lͺn_j) 3 h&*鞬D)ODpH4s+vWL9y(Ȟ#5q^Q=EX]w+ ʈP{&*xrWRZHdA8Ma-W%-;xٝYN/)0䬬7ʮ"MDKOB!Gs^6AA'm)1v?bn J{p#7.A%( q>f JAmwt[vX9ԝKLZс/%tҒH-"R)d 1_"ƶ{!JkΫe5;jUq|#_ſ^˷|WO9>E(9'2wˉLIf}@K(hC8e,3"G+Ŕi!؟ #JcF-uu:n`_ДV79}KU?dy,^AYc*P1?DU|. UJ"ZU 3ڞG U[(!U x ]I᧨(Ю( Vasi[Z;=IRNLO:(윷mK7D7gF+ quClCϴ!v;C[acFj`hFvfC V"J~/YohĮed3!9 b>@8!GT3A$x#x k Ԙp'q?(X$=n\+JV##M\KVPD9@s?FHȋH BZȊopog>ԛZ{Q.s$n[A5evddR@rux jTyP '{(_nG]/FG6[-V<ޚZ{A-kydѠ#KMkصFu$,5=w Ap$kC]yC\n'iGAlkVi^y'A `]z+x\X:`?3֧?o6Tn-I:Q&#WcٷrqGeIX y}dOD^E"[@"JxdZClfhR%h|x,E*dUq8}.-ߴX*=J/MLCTR]tTz`s0= qD/3O ~ж_u$0A!ةf1ǖ= endstream endobj 87 0 obj 3215 endobj 6 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 88 0 obj <> stream x\KQNIȼbrUJ9ĊLĚJ|=xx (_u7?s|q }^g(<#OĽowz|"X;|}l]zPۘoQ|7Q81]E|Vls_oc~UD1dyv ',|s6tD(tbF ⧨<QuDjVZ.xsrKd=u}9._: ViNx`ƚ_YA9PHpxTpCMGF4!2KbK""|@4I) {j'ҷBAPssҌZbt#=@um+h)t&Yl">pOةwϊ3jQ=:E=fMO7Yy45Md2e?ȄsZ~QpZM׈shʑ"Ygϸygi߬ib}~$hUtφ2ٓ9?ŦNT;$H}Խ' 7ߝ,w6D!Ͽo׷Fw@ߺ2~>/kuU#2x;]u@とb"oDrW>=/t;c6 d DD.[TVg:&POSF= ,$.%u :mK"]TJp.wT%YaB~[Ouw/(S)Vʒbcܩet{J?R D?ZF $1 +OW8`HǬHP;dBC[Z0AB~ދx a @A`^]k"Gs"8*d(d)\xNւ{:" qHl:oȐc{Qp[8%QHBx[ s6v, sjzv(LYQ`^`%2_ V/sOŗS_n}$sl`mvO DQN㸌sɺJw&Km yگuMIߖsD&~FtC&aUn (/ܿN4TNBx<2_Ϡ>O6ffVvD+.iJX9ODvnXJ$V`^oa(׌7Qo( [k/oC_{FylR\oiԄrź~멆mjѼ˧J%x=C{4 pBjTl/83MS(~ɑ2թD[ !ܟXH @i*mS_nkR2XVRf#dQD*dF-dS.&Tq!߿ocak%$Y"RMTQFx Zp,TO)/Av˰kNkod u65UHH Ѻ7↉9z|F G%~9N~dא̠$^B]Q4Jm(!ƣ^@]Oy~J^˥:h}ީ&Yq'Dz]ыITMPރtGC](~jO"U+Peэdmq,SsbMYp.Ƹu\f6c ?2iۂWr)H*? NPh4D( kKkDgc\Ք^*T5l 1RS{$BYQA) i_V:z l1ݧ.D5L,t988tc^~TNIZީʢQ(@neJF,tVYx}x<ʹSkT:ogFSV%Y Ñ@߶ڨ )cjJv}[D7ږV[W Zo >-30=^;AzԄ3΍22zO;N[7`Shᴨj~۱-Ÿ1 Oh;55[ Ti(.P!A.#P@XtfX՝ENNpޗp'g6TWz)qï@ D5x jjf(G[.M~/P# uZ@稲$f /۸Cc}MdIl#dPb[CNn5BNCK-;p%TGyNMŒugynZ /'^+F cȺ@D&Bb۰>+9UbێDSx<=P ksDJ,1sGOn"zwEKm^$ew`ۼZJj^ԮYm[k]^mO {U,OsvMʸtJ˷4t ; -s7 ;&Bѭ#;&Ya01O@(ϐpzɋ$? 9a";Ԡvr}+'ƺhЄƚ~JuD[1jms#΃'m&Gmb(~4*4d*BGՂ*p5.Y7">G"t^OEQGI#k7 )K* JЏNj LPBv%xxro}u稽uldMJΰww&%M=_UoqᎬ̊KIy˥7W /Rߢs4[5T 嚝ќ|O>O9 `+UuC W endstream endobj 89 0 obj 4347 endobj 7 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 90 0 obj <> stream x\Ks丑ű `ൽ9Co/T%f=\d[aK,,VJZTf/XUOBe5 uXea;|?d__>?r.sx j3!rQ*<,CikJ-3!aUvH\pD"b"b^@'QKT IUۍ Kki#2oFzh` Er6kC} ̦#*J:g=کS۬B"L&AxBI%"eIR9gțpDMb(I^s`LnUxE$SďPUȕ#hQQ4oU_6&Xy$+sShQ$KQM$6l8\LR)AatD*QEO&JcP]*%rn2g%;WbSv?'m80>&OO%n;wJ00V/8wi\aFRKlD~n 431scs)Y`Ĉ2ݿ>VR䬘Ya䊐 qS* ,-c s%ҩa/Ynh4&J.'+<ΑRaӪP2u*RK D4jUZ."/o=ֿW!V2]fuj(Jފm%c$~" _뢜RH ;'6ʊK䰧В~vDOd݆ T_^O8_(gL7Enⓖwvq)YJ8|J0Ru5yY {Q?!"Un| uҼlV]g_mo%ڑҔP4]_:"O;ictk}Z|/>dqSo.;nw,neÉ6HuSơV; $~AkiX^ ]*t@*VPby{8pUm}q>fVY:KOީuVS@U/QXoPjTgϚ1kD>.T&R|(Cþ$~9Mnb*/8-Sf3_MDc;S6[*lfu *v_%Dk¶sx<|K`IDd G$BF"/xRjj-1GdZ s tcyZǪ]44e)>MRRvjLc5}Wkg~_ñϞw;[y%y/s'pD/_r2qD6B >'8PѰJfL3^F33 Lk;l]΅z>՝}>J-% ;pJ!˪Dd$%̹(s3Ȃ&[|gE!ϕV=o;7'c[]>e|%)Hb()SDt;#zz=J@'38P`I;G) aO'kP#~Wr:'2׬P+(j0YZR7:.}{:c"(ZU@hvDpv `J#bΓzBwpGeHZ9NG`gm E ϰ xO^?qIe?; 2/i=$3JZ/9" 4&Ep|PI2Ҋ4lzPgc{zFZM6 lgjUY,siϭE6?Y 8Q-V FNY{%4nmo۾ޏaBn>>G+өq2gtLzZg(W&/KQ饖C[t}/'g׾ em|kddʄ,OTL|oQZ˳?pg>Ά ̺Ӯ;>j.[13DKw|?v ]V4Z>p.E(m]8m4M:1!ڸŒklݾFaTWt5 pBYyT\WLÆShn48{}̚RIJŲpDwAp'IQ0Z܈3Awb]JY +C+i239rjt3+ >v(J>澠|@1WGg*3$kn##q7kS" g0PcR(J~hT tE~YFGuElƍ,l9vB**34.Qڃ~w0N0.+mPPd%Ƙ ) r!nVzOɞ=|viDUI+@&KQ AD7Y R/84Bz]!N @!M N9 M7` s"2ntkq 'Z4h3pZPY3ݩͳwg7N@}3 狁TL~ 8йX3L DylwbQ_I߰|{mVOFyaP״NCCMH4ۮ>~TJ/W'[մS[̚qzִ^$L{?NkU~%6jɫkPb<.6Cr y==^c~x*g_#p6Fso^mf/s&UD]k/8'BYs {񏪔/KxD C'4FOGsHqȮUݾ^]8?Q#}8A$+IG(4'熢KTZDR 4u-PAwKgwQ ?!TKFDIk[ƇxL?O# G qG͔OWvqDfŘͤG曅Y禕 %Z/߾ F_-2Vٶ~h 1~斝 ؎EKe:Q/ v,wGT4N:~O*xKҡSODЌR=۳a3ϳP> /ProcSet [/PDF /Text]>>>> endobj 92 0 obj <> stream x\͎8S@{Qֈ/Ї]ؓ/LKe63bgsHRI'tD FOEΤb'en5g1:/ˍ*}ӿ~7JGoHaYn,s3 KykӾcd~}lRb&Fst7!ϥ d5y"$ CtXS_-8mY_Kk%\ZC{ήU K<ڨ,:E&/7UMuN׬=v.RH^~;}6FH r3ظm)1"zm '=l\hg,鞳5ksn\h&ٵsuykO5ERiÎg8LﴇS8 ^]4y(b 8E$28 A( o笩չl#y|i˯|B!Xb/g$幖eR D/O'"'=ȅ#"}Ot˙uPw_s+q=roe^a!1vW猪'XqEîYTβeI{<0N)m9繒+"zA *7`qEqDO'bB#i)~bIDd'J0 x$:'Ş5zm}u^t7_+ɐ#g>!J鑜rcAr pƕ6N,QtSRJdv/8_!WR>ǎ%2,<<H .FoMDy[S(ڬ\3_o J7l{M`v5~/^[ooi+߯;=jrbӴߗ,|*K, 2I'"=yOtqz<>s+Q%1Sd/yyP6Tk֞>F !>]H:UO}l7Uk0xߪX\U[XՃ:6.(-v{r&7ZM曶&9s&s""_O҅ԃI\/e@gl&{-UջB|זwƘx47u (ۙ{`|$(cܫy$|cODVz"sNYq^Ub5mdlgJbYxUͧ xbZdJwZY?do8t㱸p]ǀ;֑K!:C hhh_<ۑ/QW:>n<uwwjAW ]<ĺ =2i߈ uz 5/VɩۥƒP78/D0hY\׊ͭ\*Hpvk@(kyU~ѣnk$3< &`>eD:+QtqpnZ`O/Qz^?C 'Y/8/ "tH\_˯QDgyzG#Y)N6 `S޺|+Ot A4#ALbJp^~?)s$jSEmIg'_ "z|[jzgc &'Pow9sqΗ?Xa8r}}cQ$@BjVFH%' p h~"'%3^pc3+ =3{BszäK)riMFe'>q lT7&x.^:C<Әy\X!qQ*>`d<t!ms0K4eZ^4`L8B~45ËyX: KkHBI,;qƉ?@+QU(Z th% lVajV~=V~j,D¤ !BŦt3Ltʙ'm3NpN35!LHB|CDC')ڒ9[6 ODβN1Ӄgb!""0]9KXpMRf rm~~?bPN@U&=1hO*]BMװ&h9PœXt@; ({*dX^5ў A:A.ƿc9nhT:c\ ?7"HqF C8s5,c?#6v4}`}k-I;ݹ*ݥZd1 Lb2ӑlM'$LEnl H4L&L“JQ]~ἪnIBW^}TD_]Un~I[RmG*akxj>R(gp"}[;=+&b BYefH˔gO%񽯈q{Jb5\c_F6Iᗜ'mp;wmp[pXN_ѿLЉ1(vk'*="I=Ϥҋ6f\?߉~؉}O`q#i u7Fq;H;鸰ΐ~c]wk\XDi1g:QMh' Z斂~ǂn1֍X5t\Xg;nlge.3( VjRmD1 c_(B':(:Q [g/aȠ[;Qkc'jO;z•ԉD6zUYEHld۵~O["CuK+=y*_\Im *-LzNAG oˮ}nT? :%hZ-: wOy*4cҤ<} hqポxR+_ '$SF7kAUH5ӘhA @o@2Y:ï`$ԛ^v Wn<,cL^P&gJo}kO_kB5:(55(4cG"e7&w[K]8G?J~V>0oP޶i^4Au7kBO'* s xAc1Gd9rͦR^iPlwc$,DR>攃Z$ /[rRd M HX^n0_pC5W)w<) ԂI7AmQ͍MYj.TXѷ}-!<8#:C<Әy\XiWp~ r0?aAg.XHυfs`,jXk:.p裧3X,simqB&H`ԝ38಩O,?@봛۠a ?=7Q4b*{A f2- :F|+qϚ\  SFʵAFϗus+ (68BDW⒙\sLWy j-GTs\Wjx>͋I+;K) Dd'rvGe ^{򧐆Y_CjƐ^.0X[AVn}E+[HxYmc5?'9j@_ Pby; yW!.uы u^s9GO) _ňI[Y2}KAfÕ82xo(G HP7/=vZOyiP.3DBԣ endstream endobj 93 0 obj 4834 endobj 9 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 94 0 obj <> stream x\ˮ+f)Ҥo8pIZj3" $AϜy 3=^XUU:Uui^2S|{ǹ,զƕFjVQ Uy1ť~wʂUq\Z!_JGBAj_?{<,̴-/5}7KfP|o0k']i-lϥ/ BNc$?[#Tt*/_7z{_aF,K6խ:ym4G^e]&YBRIm BҶGOrc*-4^QKKu*}NA!N N\y.aIDF&RRy/VD*K_ZU %J#eMkq8W[}9Fn+n2/ ϥA2$\)eC+U*&t JԲDu2%$GcP)vxs=G|rU]o驸=VC}>., ;rgF9$J(cdZ[ȒIBOBBrB?+%b1»,~o6)؝ G_8VÑQ -)kgZ>csZTS YjbK9v`)J,v EG!9$URZ!T[Ã[95Dx]2Dq Fxw]NۗM-1 6B7!tþNǐ\H̕R 2ʳAȗr5#D*'#S/<.7DFJXcѺ@җ_@K ^rP4ӑTLuJ>c wOlCb~n=g!RC6]ÿ[[3v_|6ޔ#M @&<}v`=CAV3~&dY~F^uǟY|}Ofj̈́~jShP,JSJbv$K߿^Sa"{;8蓐׭P@%3\`ϡCla`#0jϏӵN/LQ44PPם,vmOT A"\Y  wF:~Ѐ/u!ct@30U&Z3FLa LFs?óI)dʐ'Tg8vx4.asX}p_aaݜ~?3(1‘P΀*?9ׇú?ducRús}Iڠu5Qޝ=Z@*&pdhD(ñ;:JGE? v-юϕ)C_!Mrq30,IK0S==lC(CB`B4AC9~ehL@YejOj@fPI1k!Ԑ *34Az6ف#1o G,en=X794Yrga p#P ߠ$1LH&Q TG_"BD B3|tc ܈` s5Z~| 8OL> y:LBcgxBZWs|,Nʥ3(U)=  t{tFZ i8u)BQ-knJʐ+v}}>*.aK-: /)V~@xzf$wLj)\ם/M}*UrN&l$Aj7T~}Bd2#ؿ*ۃ=:<_X7V]*>xP {BI؝q|{.`Rkɇ}cl$xaRWoWDO;"1W`0GSZ)C]:V$ ONfP74yZ&^nn^l1<'4w~%ѧ zZ^;c&$BPn P'?G>%F!LEËrNCqքR_ϧ(U0T?APO̩:6G{ܪF*E3Ly \Nu{=_S/tk Ӯ}OB>l$]|:|7AvG(-]߽g-r/w@KIXo8nw)}7(ګʏGN9(4<%j~Jҍb4 ;Wlc3CǷlPO^^Q.ORz@1>/Ls AD؎pPQΤj:ex<AR/rIȹ Iì٩54v6z\+B2 wE 6k~}FI+?±]a3JLC`$ `3,}r,Q B~q3='N@ݧBl dOOAv[ÃOpl--W籟wsl*0-Ηݖ^ohT*nnV%KGC{Ue+㡂ZM#,FGaDpu&@lqJY.=4 kZ>D7B֒rV3;6wgfO}i:{I%3* ^KYϊV(2CT)# miAK| ;J)7%k+U$1˷QNMTF똼rٜfCh 0JH8*ԌV[9k"!W@*?=mN(=o.[ >jӀha~RBiYu,}MJ,rIn.-6. WsI df ]V㸀%KR$1٥0MGɳb nѦ8F{PM$S# t>}Rwezm綝CCTjn}g|37TR+Co[? }VG !زN*"ccQ2Ɯ]_N&{ o 'Ph3rYR{)R988Y",8=k1 CRX[υ2=1)22nt? SJK?d.n|s h`=RšSeupN 5d2lZ TuԮ;zԠ((nz 5>.y(EEMS*ߏ[u4?9嗿ӯF7AxaK3Z^) endstream endobj 95 0 obj 4087 endobj 10 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 96 0 obj <> stream x\IoʑW=Pӹ/a>/%ѨESUeHn,=Xd}vJ4/^Q3֚R:oOwCݧ}./~֕Zh3נg?U/r\usxUxɸes/Mq~lׇbΔSO-mu8WGr:t~GUm7]u l)k5IJ{'o)B&f^rUa`c\y1ũ{K+  =e- Ү4jxJN`?ab5Jf_MR2&?_pِ#mW]z+m.e,6EQ\W8/nĕ,Nn"*s AZoJ['7+)Ci8OM1X$gduYï/ DxQF#8yo(L%#?u_3!hC ,ъ6NZž*1&(S,0:}9V^DxtƜ;mig^mIoKGgvL10N P~7늓[M*QPzVvYTaDtS;PhЁ*GߵAd،#qEOD&)z~q#Ł&.u*ٸӿyYGDxfF)kp~~xN6 V>WsVQ582̊OJ" nעu#ju=d LD֩z,}'v:u8qC)%)lO֮a+pɼ6gE,~"E[A.aIg=DF &3nv7 NНtB8 ؜" Sv<ёfwīx{y=U՗jWEbW/3ANͣlD"r("DA.k95D ih,~!t)} ʶ|A  1l1%qÌ4Y9w`]6 V>0cRA~"r.ɘ 80krg%658Zoюh"0gS~GԯoF9}GQ]wD6DP[RC6J;/=VhrC>Ȗ(!c@CXEz_ʽ$_s5]KfZ3{ ORj9SMd^s%}Q*LXNMCMtyh-#䙩?9*@Fo4=Y8x#CkEr!J#٢ _nt2 f68nwI'H>՛tO]µ }It޼n%DJې"9y!:RPah._oaQ`2NvmRیcOI:+Z=).vYƞX,쉾p8m䑷LA߶jl3=eX#!Knj3Ɔ25P!'3 1f?W;I7jtTQKb~a$NI2,DRq̭LY)DD(!tiWF~_b~JJ&諃^[tRf5rC 8Q/Iï 6&>3bk;M{X4]ОjnN?ygoh:+X%;. uK++V]tLi7v7]s%Zi4p!آR;Z- endstream endobj 97 0 obj 4128 endobj 11 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 98 0 obj <> stream x[KܸWDM@>l^O>X\Unz$[RG , OLL3S4˴I2cS#5KH*x85K_Y+haVY֭O4΍jX\3L;[$o.*I2WD[[-?6i~-ÅNCT(~"rٔ["zhNTuv1q}ODNx6h[?k:snr'YuQ|1Dd' zIdlOuz^k19Kcx!*Z!l7 9\LKanTԝFs)/@Zᩂ DZVҪN˗wm{̢R&U"&Qag\rT\Q)LFvSe9cW2Ed=I!7$GqA0m+y,5(c'_bH%"rz"6-a<IBe{t.ꈚ\-RiÏY+仗Z~~&=}5L=aOdDQ:9z;0n"Śc?5+JM6+AT9^ߞNaP r-A򯇐lTIú1CS{6B%Jis78: ކZ8KqhSĿ¨V;g1p$؅1 Y/*(Ib %] eou(~I d(y$sML60Iۗbegz '{[2*丢}xPpOJ xM -PZ`E1Eq Sgh;)7?(xh&,Ϙꞑ~xK:,s9}˼?}}Mk!f)b@!FeG}[* i-9 4 {6HXye3d%=3y6Ω/џEkq5?}g%ޑބ%\#q}qٔ* !QT7d`) d/x4Dv ̴UeGQDd' Z;4#Oo3YAQO[*">SMv&~)d' HD$={Hiө:&?_@_6 0i[aŻ}Gu"a4?` t6V) 8I=Ovi%EէehgIPš(+Mp7$|," __~?WQpP}%ך/%Ca v&o,@/h&.< ea'h&O\2:: e S[CN~%'_Evr~ACp" jn8IwP9tFI֡"ODgDrQou O]>:# ף#Sg>߮]8u!EHf6zZ$dG#9E dr"z<@*>S@FZh=g.SGMѶ>3W4u}zX;^;jDF>˷+Cq@`bJTr#Ax").y]>aS |sE60VS{nu ;@!=!"]1W d;wXt c[Jˆ؇7D(K8 #F(~:QDDOtg(zkQ> /ProcSet [/PDF /Text]>>>> endobj 100 0 obj <> stream x\˒ƭWp)9f~hC7,T.᏿wɒHl8>2͜*3)4FgB.Ż?,(2C?d%Q_(ǸB)OB(ęxF a'dW?>p}^^ҋyaN0RK2PLEe`1wFY@ٙVN^tk`*19Hҗk-PLGE, ~뺸G (Ayax(Ԏ7r,jK 5Ôz'jI:fMLHDM؟ ԤPhlkVY̕ZMOV=ҁWV+}(XZ!Ih;XEe )͍cyQMa&7EIJ?}Ϯš|^? $}%!o"\ہ /5 a 1䚐,7wϳ'ք";m(U1Kn%V+0E:E*("QIhie:ÃH;dfgō~ŨrHqQ/n Kq_\M5S-I(₼g".o᱇z/U $NUp~dɫ#B6Hf5H,"~0F$R-ZTZDj<*\XtS?,^/ to.= ^o.I$, 9l&MBahE_Wj“b |0Sy\"jmESr"ʲ?Ѯ)V~OŹT /IOn4Rz<X$2q5"Q1IHbkxf"^B7J6*~;YêMZ3+,km"k!5QhewO;$"FqZo}8WZ8& %({su~@;'ͭ8u1^jVw]zT  E4)-5B+= 1c(>Cz'9Tћh{P0Q I( 3 N)ZXBZ^4(1Ȅv&$}) GBCKCRz`VxΈESW ~@%TV@R+CkTL襼A$K4lGm5 2Q8WZϫ/j\.%+R+ VPrDޣr>{;}~VٛR%RP$][Ã{io4o' +܀pjxdk=3'!/Ԯ(GﷷKy_J2sG5ϒ AǽMҌC^aŚ~$x{B;4m͸ښ~;kSf-Hhg%:K͉N3tW2 -W7WVI(ޭV%PBj"^FV /P|{LxX^:CUc1 K^5JS Y:g 2"kPMl ~̱Z8|$}"JFdlk8 " ]R|F;f_y8 7f1vn%e$}gp($0$<ӖLi9b:"yPxC_q1xً[0TZ!aCu P n5T ;KY]O߉fo<Ųy.Ltm>W_uITa/(˝evPWyehxyf/ܷ:4))}82"3)RtH"Sp)hǣDy̡xLM]i{LTt'դo" &{Jjt*oi H1iXJ7j_+Κ:OU$}3Z$]l ,C,E>P^KyÙ$Zoχbtt1kGmCsSf5B^`;c4&tOϭ(8 ݖQd68]X q,?O2 e屒Y.)?oR`ID$#NɽfK_B 4˔I~@4> /ProcSet [/PDF /Text]>>>> endobj 102 0 obj <> stream x\]ȱ}h Iv}ؽ؇!k⋀#Q3HD5Sͯ&EJهͩjVUWW.Oqkvz~'T̤,ibSe"Rkqةx;s*nBKO% ,M2O%zxOqUNTb2٧ s ?og9y]m]y,,gO]SQY~d\M_٧_'d"f 1`aر#,1?[V=Zl!!>>ϻw|V "WwUcY!+]R'B_HmTf$v-3}z).;Ke_/`zcedsʩl#gAʼQ$ʬpMI|90/3vʯ,c]Gd ڙ'x7k)NűfF`4VmDpVNůA k"N\-Ó $*]b%NH ~3[xnd#M??B)dwu 7h.%3&6юF*'x"$EDYb=Ѣڅ &@KVPqY&l#S!ˇk`rJ~f؛Wh "VG[1_wɖIꉖHIYvxv^sB1F*13֕$oC2IeKiu:;T'Y&[v?jQ_'* sM~0{X4mfKd)d /=}7E~ޱcuc{6tDS% mq yTb+w1_YP Y`]ԧ2&c؜} SJk#RrLrm #5K!+eE ZoĘ3 _4(!@B.Iۏ|/YSM)V~zV$CFzk>vr.5f.#f>IvZ B 5>vVh u 3q٠ޮNz )$i_nB28R8ؔ؆|Pʣ߃%n2jÞQ{Okxݥ:)B y;՜'Z&څGOtӇ'^1}xӨ qTtwM(V.|fM}@d(<9D "U E%Ib O*u-ʦ¡c(Ȝ  p#m%S wwm%H/|ue/4(ave[.ԗzA',DE /)׎Omq'QB7x:82S ~ȇ!n-Bjίf.,I6s55Z5^@y,柡| "sݴ Rh] FM-a[i1dK4CoyԦx7LvE|w)Ț{)zQ+7M&Ч5p{3xՀ%Ʈ)"/UVNh~d|"r oWdlQ_ յ0LXFv}[پ5jǂ{ YBb܅;俕_F(W"D4A]7W*Ѧ`P(4X"2~ f'NUj(~)5`'nE^_ǜ~OYÈR/#D&^Ӷ}|Cb꜋R)Vm~!u@~X ^ʺn'RԃSSO{먆٤ACd4 ~z๨hA]*h@G_I +TKfT&zܲ4g!gIkё^NÌ!?9< yg~+Ì2ͽa9u6-Tnd":G*JzyP+h%,5n g4Bi5w2f M<3<9'g SP>mbL-x@x}7C{ۮ5EF58_kA>ˀ&-rfBϙJnrB[&U}Ճ8b_JXbL39 0W$_(K'[Wg֐?P0x>4tgi0ʨveQw~Bŏz0p{q[@g(ue6'"Pc)@=ehL??n ܨ&gZyK@Ddݿ%j 'dszBm/ʢ._xLy"Tw  ͂*_"e%+$npF 8uyd>vQjw2Z~I۶D^!;㉖zl^t/(m=ՠg/(DI4$Xʊ1_ҼD4z_{P I)ѩia/Lf:WSxHۅM1Jeɠ>B%8];aGgL3aGgIWTLν@oη+": -:qb<ޫQt~.P&~vYRԗ<o:bx3E%JHϴD2" 1tprTx)%)uhkɷZ; I\};zoGShzD[SbݩS=ګѾ 㸞5Kq7Z͡>թp@@)p-~"r%Q-n-ug}7L=}@êTҨ:kqc8:[ QSӘ(͠GLߍ\o9.յN)Lbݭ)< EӒQn;`/{JAk'r7UAMA6|v2aFLݦ{Գ8F!=ݖj^27G3"62hW_YaOjɚ]ej0zS\e7qnxSkbjLey)|n94˱~$L6DN(qcW^NXgr&B=fr.xMГ1_^׿>hJ?a@-gi! |"~"B&"8S [x?rgԬ;=9ЍpT[w׳Sk&Wy6I0nl?~MX5Wym'aF̐3xY0#LsﹺKUF.zAYzGZi^ς0%ͳ6ve: ds<3<9'g WyqEWyOXSP8ĉLn'nF[BXI_%֖nzni/p G qm`]u<#N ҏms/h +a?+Qѧ4͞W]Dq>a>*u?cpv4f?*T DEv% &ƨC)eULEq\ކDS=k7崌h^ _s>}C:jC@wN֛ټ|-ۻ .r垊ssm**eN*dy"3 ~e߇2"`Nc *2S1 endstream endobj 103 0 obj 4188 endobj 14 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 104 0 obj <> stream x\K6rϯ#Lj“l+BĞR]Xbw?%>ե52o$ %ϟR,3fRDThSgYr->='Z˄~HCX\#S&M! _䗯X+Ƭ'T\'_~5KlO>W|ӿ;2 im!3Xb Oʔ'<`Z]kS#hOF&<(|!u }VJ jw8ܝ{Ty!%i2|433D][Y9y.ߊs~';EZyߦsQ!y٭EKxVvcu˲LMHP<^C¾Sɘ> H khC$d&Hn裑p-C["အFvk R#~ [PD$ *]Vbd࠴=(|9 K)-Y/.)Q+b{T'չHkrcxZf\_ܿա6fL&' 8\ЪLlpxF>+NB!J7/̴`E>F@zzI9WzW=!]ۿ쮻=ݒoo0m[YjzCU9yS݈/?fU (ƛDW]έρ" H G9B #g*ɜ sݿ''4( 0@PA*@ 442 R['sӯz(5Oux,rƸ\m0kP.3D|smMHd[q/[ykzsk!  ]^>8#Aab_Z[N-9 ? ߬n8L{qNu_A5YDf} G&%r4AAy:fq2Iʯ*AR%pf]d4Pp4 +ΣNvLAҧ3ڨB(]5/8~!:~Og(&CٙB1ⅅ=2K@6w䫣ay111.s}\Ou-"gI!i#뵸 $|xWt#n͠edPw \rL*?7M~/ulQfZ') }a6e*Rw9 H s/YrkVXΞ͍s=10TŴ03-&HΐP\mМĂb0)T $\4W弩[DY:֤ͪkOwc YŖH!;4GYnGxKR>%]LrY"lGM5DZOI_K1ڡz}L~ ( y=Gel{KἾKI3%.Sz^8$gmh+o'ž=*1fI!ږxJbrx!Do%9u$]TX,lg]Ûjˢh*Hswl>fQ2Ɔ&4HĠZ= ic]C v~ 5M ~f˱%(wf61|+T$4<~*=m1 s@3< pX/JfH;F7+fTļ-MD6bϱLTi 9ޢlpun&VdSDYw] CXܦp@֋zf*Uw}|$:(|9hǦj *@shZ~gkiRrDp~ CDp Ca .0!HI@"P`8] >y DA{14΂|blLfM#QҬ#yMT85Lޤ;on~mwtRn>u'Go|v&4S3~efZ)kLd@h?60."(i}r3-r'ÛO'<;ihK4}~nOKvܘF{{8#X_CvR^A[9ϲOOn=AnnOݽ''Z*)Š4';> /ProcSet [/PDF /Text]>> /Annots [106 0 R 107 0 R 108 0 R 109 0 R]>> endobj 106 0 obj <> endobj 107 0 obj <> endobj 108 0 obj <> endobj 109 0 obj <> endobj 110 0 obj <> stream x[r6+xTԤ* -63H;9|$E"v.KT,ycBڍ>uW+;^@1h2ґf2Ga67* ECƾ+DW\Y iS2jZ]fHn^o{ʤYIy|&VOS5` 1hcai.[ aFt11aTK86U4ceM#@N16aD1 ZŐ^8٭ay p2\ 3rOЍay =C+²maF]Eay*CXvՉa3vܟKlގrFGe2f96tig(|(l* l"i68 lB0(%vG/-X*h$Q^AzCk;Ӻg.ǔs lsx=W};_ө&E}?OՐS@O]5Gh d25\vEt͂#h%Fx`MwS48QS Ya0eYIaW*0>u#:xXcڒosc鐆rKTZ|NXN|T^}JiNm4l˧>'C;UO#jc >$q!τAWԅ\U[jDH >6!*Ah7xPvW1 jH5~ej?29l'5yGwžx.-Rdx=L s0G H diLx`3R9Vfj8۽,|+O([5x;3*R2:Y0]BVk qG_{{`;v3d]s{Nw34w+RRiua*zͼ3⊡!pavkY֬q5w4fr7osp9:=ghKߣEZ欉F9ͷO>R-!\Y:Kcsrz-7S6L&~{B^g#%]΍< 6iQJI3M$;W5|x>$ >8u$?gi!mT8s K@V9% <;Sç,vAjJxjZEst@hSF}x`o]AeG#U2)jM=TG2CkQ0.Ȟ~9#cUDKI?}Ne2rȆ?"=)  #QP|&Fٵ'LgžgLؓQ,.[cLسFs@3a nϛ0(hOX >YZ x0ag.9@Aϴ>a]U&x]}j?̍%4 )xH*SrfcHswe%*!'Gy)*(|2'P [Yl=7vBy)z!'S Ma*yU5ӈ'4PEd0wڙbzBt>ρ x1B8_?.ΜYz$Tj I@Ϫ"YH@ sKϪdxT yߎ|Rq/r2DΖ;ySYͲ3Bvn hȵ&öWŵ:(7#E#n?T@6#à7g4ZQH( "1Bm>t >3n"x,mLe[rP,lK)^Jɯ(QN$80>x)9ݲ,x[9\=d}ms.chBn%޶ (! ۦl=K7~o۽HVHfm%ff͒\]]3G0}3]lonX/Oi̜3R ]5)soƺ:\CԬAxm^ۑ!Rs}s&ww{Z347ΐ4ҿ׼{7C6Yp~i7CO osp9:=ghxgstRʫw>ʪA7W~) =癰4ivUU ?dͥ}DhlSd߷}eE^}O.f D _:;{q,muDm;*2}NWb_ 49$U]ڮtQ[,'{v=x!,rB;DUd]As ݣNHΩm+?g9 .LTvcDUW!,oT*pl{5_@dSBu\[jpƍ>tPׇ_Gэ5þ* 0hFmGCi}Lgy[@RV*m@($ 9 tX͏^\26AZjf/IgN[}I)Zob(|ŵgR<be2(Gx,~Ek7l>O-%ץCjK9Tk*-5y:K/D f }^+oRb3 _ofq')GdB~:45r_Krc_ eFF1 :MTn>l[ >BK@ܽ?f: -ۚ];w}ЧJR=ik^nW뛷K6uqF\Pzȷ.NF_#fs=JS>{r>a ZwaTE ڟ\6ewgnwdB]\T{K|Y$#B\WAvzȝN#y7%y#&>]_nF慂oº469[B@3Z*x<,>CM) Ѷ(a)o>o) {zmq"6 @aCp颌eehz6X&R%('P+qJʣfcyϿa:xq+rEyn.^ NMY+kWPRC}:H7E?%L&pY endstream endobj 111 0 obj 3966 endobj 16 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 112 0 obj <> stream xZmoF_s7\C$@A|^KKŖJ쒴Eɧ@3dTK+ Fs/'ݙPATf@c5cg_J/+Zv'$~,@t^Np_mӷW5+MݳY [`ی̳E2-`*I*$<gΔh 5EgmO6zͷeFnΫ,BRa)G(!O6 IyK'Bx NN7TjA׾\ 9x2OoUEb]٬Y6z E~mhbJh"B{ϵF"GD6e%õk4mYST".Q UR؝/Spț5D̏I4D^XfiwaJPS6JW6JgT|tNc*m jm$o5Ç}|߳?Ӯ36P i9{:3 `NiEFOָ1c?\]+PF) >_diO%>KWA}AuAͺUM:E,ۻe[P~w;_zgG&yf,[u 6+s@) +Y`GugW$-/`DDsuR#LfVTo.6|s&_A,{soE HI2PBHWuw"?/P)_kH(="O3:!FT`{Oԯ:-n^?{;LnϴO?CȮQpKnzݞs~m/%wd(I7d 0,?s`;O~ O؅\A"՘Drn/~:p~asQ]1 Orv}֗*S%%2_\s;S0ϏCE&v>CX?F nud,$#8bgf&HZB*ky]$D $"[JR N#WԮU&H'HJo6˩yctVGzw<[`2C*Զ.H[kaTI4R-8a!>5DC~B)VwJ#<8_Ծ*`T4MtDGf0`YQ SpAGe<Ԍ駽[J1|b]xRI7ڈE$OIdj cFw)Yt[T1ԊʫJߌVu+ N I7H~XD$ &@E 8z2۔Y„x(לEc:+ThXٷG,R QʧK1S4x APx?4 t? q 扎 Bʏ#˭oQod|u#!`o;0źDx,W~$"h!> @+˦"^ $N3xšp}n!i(8>Ɂ$#xD.az5Xdǎ!F,{x/Ϙravs 2So¼҇ɏ+RNїz7؎tf uNr"lRyW#[GSKkU'3д5_@Dr |Pp@Oq.spP8D[\C\8y^mzx޳:@dcidͭ!|?Unha7T|~O~K37TBNp_=iԴiL\m+{>=j33ި9oh< r9Fǀj?!K8 gz[ղiU ]]QUVf@S&MW]Ta֎ʬ CյO#vcζ*ęn|Jm6%׷GϭDCY4 ,UM^ , 2I$zp^0Yi ~J[Oxn񁴣8n5d; c%zQMt`M<8 'd?䈁2- ? @Zy^ L2d$"}$-&2d|ƌ/Pm|iC98\zÿ!%ezM\l~$_@G5oOR!ȗ z$?g|˗[¿2.583v7[Y'6-2@qI0&WN$-8|q@;Ф[@k5NBQAmOY e"FE_#"A0O={S]6T`XdRb2QS+9(yEw+:wo Sv2lt6 x l@2+K8Z%z:?xÓ@H{"رSզp0/t0mU"KcF`2\#˴Q:o {4A~t^>8X'fcɅ^?Ot-z)rT 4L4#w8?3ټD+,C,*Pym?-WlDp ɹ}Gjlu<7ͦhu ?E@Qr4I{"A<~5s|:ͬ΍ן3m:ؔ ᩵EV8zH8ˉO// jhL2Mx+сM=QSoKy~٤Ï"#gEFptl \sLjE.;8 LN endstream endobj 113 0 obj 3219 endobj 17 0 obj <> /ProcSet [/PDF /Text]>> /Annots [114 0 R 115 0 R 116 0 R 117 0 R]>> endobj 114 0 obj <> endobj 115 0 obj <> endobj 116 0 obj <> endobj 117 0 obj <> endobj 118 0 obj <> stream xY]oܸ} Pl6OQ lv@ ?C@plm4ҬQeɉ}6ad/TmTDB)sۿ_@D )e!w\LSrNqj)IyfN3Pɵ RjJ3oNisʲpjS᮳ĕŽ7!BXj4cv{qφ lۺn*wx#w컶tCzr}}M -j+(-;7h6d;q[oɢL"&E۾.mn&'94'~*pOO(|2f*h$՚`SfvOH Q̮i CT rWar 5YjNૺ mQۉg%j˺JVY (,$uPOVn3-3""*3b&I9sf_K|xZMU튮ȡw$bp]4-^!Q Ij̈́=6#b> qyN(C YdvmD{%4(*3LAyMŞ}#v(T*]ה>VC1 \Q#4t{$e%Y"v'f3LS H΢/.+iQͶʡ'wnxtY0bGo^U<8d5dΑX $@}&w Ic3THT0ڌZvPcv`؅7b"'ȕ1sT m %r*9_#'⾡d. QoX1qG-sC>]hY|yC)?ī?]H[ܧx~ztNENLL6o V(0j8ԑg%pMzlHz͐m94bSr@>]VѫJnP1e(3ֆ#_1يLOHd^Xh5f $z.3P')}prK+`) hj.{k;LEYTЉZ@`uHho@[&Ln>Φ~y|Y7?!Z T[D? $\4K_ᛛWfyz+Q`%2˟'LbB+'DzG"08ܧKOE@ */L-ڐi=erbb&Y2ѕ_'/ SQl[VJ;}y|j6YgdA1=$[u2-Vrk\\sUdEm `U=0)e߸hkjXD;)=sXz0(i˒U zpâe<ŶšB<Л]soϸJ& GTk;xV7.4|THаFVUW~:2Óӫr8%g[.]l6UصBτ_l]|MeXYkYZCB)UDrMjUBe#LU|顜v sNIBvL:ֽxAb%Sf*#ߥN߳@|2 ;r2g<9jLQIX><󴙋u-KՖ*#S+.- inUq|ElC ޡPP1K$Gn_ݑ'.~/`Ҭ}/LNzd7#&$@26\E' 3gIX~\OڬX?=?E7V]b2m_D2I{q>Xg0_Ytʌמ]QM3o77%!yS3{%@4l_OℂcH_xL}O endstream endobj 119 0 obj 2625 endobj 18 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 120 0 obj <> stream xXnF+fd7h MM[4PHb!I%qeH!ݕ;qΝ;&XrJR L/ H+%!(w~9? IvFF1V&r={!{2Xnf^_ސrGl |/x*\D$nDZ2`}J{CbIRQ-| ׳d ŔLyO"X4 $HTEJ-|ʭbq)1܎m쀾x2 $oaIL[tK Tfh6T L#IZQZ&Qָ5X*ZE y$;$KQPuG;Vd_&iPLc)}c9ﳸmĚU 'NPsyw!Dtݶ3*6֮0xԤayݕ X/fN]WXL%5 A!0"a1L${j4fYA%5v$EVJƸĆZ3Gg_5TYv7!\?Ad4)(H@W{N۩<X a> /ProcSet [/PDF /Text]>>>> endobj 30 0 obj <> endobj 122 0 obj <> endobj 123 0 obj <> stream x xTE0\Uw޷$};!B""A# $@B؜l*8*6HH1:;3:fu%ߩ3ݩS=ԩSܪ!#jGL5osP_aۂUmꏣ~'.l^t,2-[pF!dq 4ڱ';BS  l$O[|}K fYӂ:1im?{}ݚf1]ŐW]طG! !iE[,}P탴'~1oCFJ<~0"zʰq<(kdd(VD.C(RCiY9ܼ!C "J@h?|(IP)ZGSp#9Ngau^<M@,1G"v`JC.4 M, U/W|sl?oC/_XJdh? 5/Pu~$h:v:>|F_Sf Fc.t;;!=Bb> ֈRP*B±c T~¸݊va/@GQI 3{4FjGaʝ~;xdGYS#I1]z+@/װk屇b/ ':e| ?rw{84Hd  ϙnAϣWoz4̀''cg'^cACv%ڍ:`Fgq͟Iv`?H!]OC(xԆCa=9OKpމ'I|ϊ-l?=169  ݀o!=-:</|M$JfFRG:x ߃_HDZO7=7&|LFc8&ƴ03L7&9v(;`f +ܓ / %.]$į# `^7`|Y Kq%“Z܀o.~?  Dd4AH@6;!% f25rYlg`aN3_0}0kn6]coqWq9{] |~ 8 Äf]b3N9:X[/8 1,@yar& bxY;kloϢb' hb$&'ߓ+{{}r5DO6NgtA35@O><߈Kz.q13T{Xztւ}5kb } }@?`.5h7QhAoET:[ d:DwހΠ/ Q{NG_`*Cú[Hqܵe%ZXG-&:XУ mCvh=E_aNDžUvn?wG~(p{z$Sf(XB_sE(e9bj5z|L0a=qĵw& -0Ny 3x z9o@'m< FZp3PgXߣQ=Tu j;T(MZ7S/oA˅?i[j[bE-Cey긐NJڍNjO'v6 BugqځkqoW[4cCc\tP6hj>ݣ MT/T1t0;N3 Vv B;PhL%7Actc;1j#mUn[AkP}ݵs:j k[Rqp2Ө-Վisi\] c@_^Y};0j O#V#UJ *N_Ch-]vH1[tk>;|-3焂Pu]EA2}mWSTq4[4hXCzs UMYL1 MPɜ4F іá|1ꨇinQFrڿKWBH@K%| pG8ܑCED s 8yɰPBCSu# isyw"-?\AjiM@siؽ6|Hwb?ⲏ[<CuCjFj9- Vͼ,~.ua$?ׂP^{11vB]PXPjj9}qPKO.uK`1"|y~e˰3na_6T͜e|Y]%(-[*Cj-uݱ!U m!Ⱦ-j&;vtj b1JИ!iA o1wNݦs: &ckTL9=`hz)XJs*͡* IDߣ!Ԯײz_Ѝ^&a >y` V"8 ݤ\#2H(F^碄93ưyʹٲIe`DC ֠5" 齠qG,dZE6r sxC`Xŭ2c0oE1YQd*r\.3r7&3j@MvtKT>[m4 --v8db\8,z|xL]id1RPfβc(a$)&ǩHBbDdT%,g>T^) \CX+)"鰹],w+Ci_IMNF`!d,`L<$S^D;A7 )'3tHbc[G1lN@q3*F$-}cNOV??x#i${@> `)iQ)`XS >|^jAF,pt!z {y$ÑL2,(VL7MNڛٱӬ{FEwkUkM>_/3^jWov`ukoQ@,%0ii*MɫҋɟwwMVţz;֫\^[Ee/OL/ӗ8ayAoRd\$`n_^TS ."TdUJSy*.WQᰒaV%#f⢩Ȕx:=ׇw|9zQ<2`;y~4p| # k_c_yO46y^~voTŗƳc=cc}b'͛c\lvAI&Oڟ,P&M^!y{b2$hIMLi0}PB.n<[ Fb3s L| e5 οIT>-@kZ`bkQT|JvZK)=J)+*hZ?y2v ~c@WSMjڜ&HÇW-kpf8JVT+L B߅G4TY,Fb_9(zJ?ރ?,zu K~k_=kS3OI,eWI[^ n0s;Wt9;$(vW0`R4LLd®nL4Ko'v^^?(Ju0ٽc/́ѥX8x.N '4_u½@ޜ|6!gk5 ͶQUj-Mr C5t]u %lE  BԴIX1NzuaU5s&_h7n\κ~95x%t~4^=qN}mٰl+n}>z3s?VC4?3pV0X 8TvViy_\[_{M/c@,uu*xIt+f{S[dgWf9xeG7J)Ó,N~мmZ'I8`DT\|AKPQUF7rm}T;?{J&oY&82'3@&Ҵt?5`Ƨ0o(1r+#Fkn87j_sN, AB&F,*NRVq mj0 F9l%ܸ-! BnHL12YXA m,rxQ|ɣd/9"Y̼@8H4>,u!]4) ]"QXh!漆 ls5-gkZ<5T|lRHn>hpFnHx/n⡉m|Ÿ9$E$Sި0̨H#1hGcQԅ<;|xBuP0 =]{їH\KxR;za QOR+kp~>p4W59XV :%>+7SyING(5fUG:Fğ̷<`F%Cv؟hC<}!{ꐂ!d#UEG7ڕ7tFYvԴ ǗnѠ/|] ;cɥN}4i?hzQ@E^YWeBC0PiJ傠 KQy'2dOn45,jY/6窫&澵־My g[_$o9++fI\Otd<bɷI].e]]w.eLَlJnt' v$I,>n*W;]Cg`P[==A^\cEfEU,x[4'bj˓7+HI=@`侽˿.1/-T?Pqgak<)jztx62kT2[c:&|`?[_ٳj?_sK 񽻯lUW_:Ptz( K]ծ.=̿T,t"z3XH$J,R(DR^AJe bv+O"Tn@!Gjo+Y8>eyeefz;B?s˞U9 f?xLe^gRڮ]!r pæ%K$ |CȀ >T`LTL " 8"}&-;[3ˊ\ze]4n:p/[~Kr_e~m o%Ԫ<.bE"(NS@kLg#>P` >EF9v2}#I}E9;VqX}*h)U)U* ~w~ϲfy|Y)x5Lia O%bfx6-+IؕK6lUSNWWOM΃LlPUHN-H%=2:v_(پ}>X|4*o O_8hfd&֠SQ)'j<ޞ;V\(d }qٱ}E|M쵒e76c @'+rt.INgm08JAA:9Qߠ+lR5TSi6=^k"dR]ו/s5 o^2!s++hy8Tc*M끦A<M jAWa$QJS NrI p\3wc91H$̇t1TSބC&5AJqwJ#;𰡹ZZDfJ FShA٬xMq{ ӵ F &C0#aZ5)iDDVGHݱ]T{4iBKWk,Y$Vr䲪//"iaHGsk7]-$*@NKʧgWiF".o'CY.˫ZV UlT%_-^-͑olD)Y^d'nIH`,qFA(BUF:f)"j̈FPP 20"Hˠ;g`H-$2aXbBH`bĀ%u&.3#\ E,_pܠ l5H Pa{0[lK_8])y2G S-5݄mkZya"}ج&jY[H.H%+Z>rs0.Y0a$PKu/6O_K^}^7xwFh.6`j(k7Z&X=̋]0s"du2,RBHJ2U -15֚nHlڒWgz<.ɒOC^kr !blU#M!A ,cA1UK|jLŵx;ރ;p/YWˑ<حwܣtoX'ЛvBf9[9Hí5n SUn?ɣo&ҿvKS=@NͽYl&V*B˾F(3WSqj1qiljehDkzi. t].YԏUHk7 n!z~7M;Xy{ =*>8MkE&mCF^t~eAqji$=ǷR|Nj|-JR]x̑t!2ci2/V<4v+?isK/h\CũN*O8?NbNf_8Qv4ʋhQtx$\-Vv(;)G\8?n5tg?_g~ {~֏+P^/㥊o>]Nu>eÊaS w:ow,}/׵pVM'~ud??>|v<̈́/D?Q]uPf.7znxع2$WxRz'j؅av KǏ2;,!T­n$EHxe͗+ثk ]ny.Tf_f_dHA`D2"J o0s+;kvgobD9!}JI*^CbYV/e.>!u'hUayDfvZZZPP0Bwx.*::rD%x4?ߌRE~2ʘeXXe8 L /!(BE[,$.4!O'Vi{uB2~۷&2lgw5_E>THrZPk)M iYy#MiHZ~W`DH̱#lrr..BƏVf$kyP+y|`7i{&9ZLPP"hC 1[2U8N1DpV OEynOqs7q疾>(ϝu(u!n=rݙ[4pɑii&\M `W-5T3a;ptO}J(VoKX7uW1WE`?ZWMmUZɜ)|$}W%xMsJJW}V,90$XzMB [6PZOlllOu_̎4DZU*8=}l4c&t.kN)J6a2,8SE\wK٤'UiVERk BBOcW>&XgZq'F콹h皃-2am-5?sOt3я~<6y~Y@{9/mKڵhktYIv_R^|Rtx}sF_P3/|/L_^֜ O kVi5C Dy/Љ27{3uጙw?5M{0jll|\mK.ԜҞBF0g;0NtVx$..*5 -0;lTR,Fe'(z]iqNAVL|hK _S ' ~`Qa?>8H 7co-↺Mo|j 6{!ʅW-#zG +ӃX'M;ǹ}ҳn(:xr%_)OIyt?{Y~|x^dJ$95NlX9p2N]R솔ܡdj5Fm^çd5~Oyԓj(< l48y)M)SKPL0< ×Fi9U:m dTy .j )6g?ґ /Hmע-K1}Qpc>Ow97~1KDCbr%vӺosh¨gE-ܴΔkhzf{؀}•ǎ.)Lny⡇؞Yϱ uja R:<O, K#s쌃` ej2#Hp. r(ijZ䀄c|m;WjZdg4{x7A SW[vqb]g>//Ƈ09bd%YeN5p,OG 3l`KLĐ>q/W9Mg1Ի.1) jS=>{<7z/5V[U__?}jF.3T-(7#\˽}?D]Hbd20FE򗸀83] }&كw < vWw#LDx" 2NU&?{Tݞ;Q~ #f=*$|Irȷ땜d_2;e!XLEɰYŵV Tj?#9 ʚpmNCԒD(S7rjLhP!-3"F'%3ٞɠL5 3fzZ6&^s`V{&*I?~a-0nqtRϭ{n2/Kjf.QPȵ+9m!)F/΋f3zbY3][[wD |`nn/O{j3ڭy>W\,,R* ˗ **M` U61zߨlِa4SLƋۈPr9/;0eZg(p:z:mZ鄶0(@n;5O O x/v@ /i{NeGl^+je}ڳw;{Oܟ&e:/KFn 2V] n"+8J_O ;qgd`W4zXLt\c؀,>hő_*X{/ARoob<ޭeNW~mpx;ERS=`&&+Kw ~.AtklP3SW_]sC}A 褒:u.QEO/$zgζ)0Ů;ο6N%=rVLOדu{`v+JFi%21EeII11IldTsզjwov^yoy{ъ~, G3Ŗ wժF Ϳs?- 4rB{ѻ0n=lj%PgVnL0=sk~]F\Wش+w[i*P2s~a?O:֪QrέCG B)Τn/]C+QV8rey"xøm;FH,=p3w7f;n]I'ئ)_G-A_Ody mܱq:o:88P:5{̩#X/=P?OT.BSxwQ!C穛OYCEVrC!3)sg/ t'3o'?)6n<  6,5E#^YH4t\Hv:N' `'IEIgD,{6>ȠGK {Ƿ`YۿzN6c#;4`|FՈ8y (A# 5MF},䎰IG2=i W.̀d K!X*5ORV` YSry~ @3SX=J Dm,bUP! _ܓ8 {&NU u ]ob@A_0[\#љ8nެQ^όs呔8O%Ocm(pVF<N#IaOpH)h022xf<+X F?.!yeBYl&'eəơ%U+ɕxaaWsk5jFm6_S)+9pN|Θ#ѯA Ư90h4gA 5$nCƧ ScxY*AFz1FD0kd8 H"/ DZ,`F$fbYGK'# 1|H^Ӌ=76|I>OۍJ#D߫1=VMl߈CT d4AY4#-9ʚ'<b[ԚRa80:ځ/cgGd'4yȆ[vi[WXK gL(Xŗx\W r Ov)r;BNϊW3j^^oawG?d $X͑rW!O#9V.]`!ӳxiF0+ ,9HD΋'5+-d\I>cPmtO. wE}{bvNCI)?n~[轂>$Fa ᖁ;qh edJ`5~miiW Z>Ϊޅ>݅7G3NJo #tś0v9dⰝ1Z"d4iĹ0"|# hxG~E!G|3d0V0zFfrHн,0_'f*NtP`VF O dA(Bfhcy)8orT"@}B$O" d6BW 82B!1"9 ,9>4C(z &-SBC*F(8|P)B#s*/@H{oH}з!V,83 2L?KGs&HDm As/0߀w&`yУ ,,.0'` m{짆Sb~ُ.0Y0A,H Ȑ'H CF.7W$`pSr? XB&`} #cg+0|,ܒ"V)Wya[fMW7a_^ tXr"K 8pq88?q8puO'`Jw:l?;- E)bP7<>bof*i5 EIRVq6&`:}:l<$`vP|70#~N(w'`SEK RҌL/a?Sic9d}N%`: %`9^N0;:C#-pG0#[),8 At7jo4/Ɓyy,B4h1jtjB!Y/ Vi\z!P32HC"߆VH* - ~ڨ[@qV$b ( hD B+{(y5u, 3-2:snQ#͂\#(*P?y9#؋u*U 6[z`0"TZ"O\y\4 &5uعP6UǫUiy2:qΫh(* )D:vΫg9Ns u\&fyk/RBIS[:o:}f<|}/Kй"xj۬KI=`@Fu)G~x]O[s^rXCY>R*Qx?~isߪ\Q0XV/k9iiӟ7 t8PZI_EI.T)W۠J'vEiC[.I< Wg.nP'5-oj[ܠmjmnjkklZ>Dl:q ꇌnm[6iY@zJFnh]=!ԬI ZV4-l֛fƛ7PԶֺZM -jr f-olkWgյ5@MjԴ V.okmlX13iTZq"u… 7z/?eX7 p bGaaTh5Z0# `̮.E}]{6ZaES!LB {tꉩK6*~+  1~kEb OTf9 H@ |t<.R+3qu`*dle9Y9@Xƣ70&Td€,%(~:gqVFG6C+wrafe]ph#3Ȝ l \hy' 4ʌc 2 i%A22w~EǏ֨.wПv0wܩ?|{WB4:Bx=@u-0S[`R[@j6C|̬F!ڣiY=cgJ}]bf.8|1m]nOaӳLNJnO;4wg񩁎.:%Ǚ$`eL2 t@ ray2CޣMHH;zɛEAަI3z|vDȳGbA>$="Hv_ t.H:M.J,}g8?۟l4 I/J9H=6 ϐbnP"}"NHW)@'O;Q<75?ph >ޕ< aiLFa<F{ "y!vSky^ `/WUG+NP _ds'[1htY3:TNnES c!܄Xo p^a%ՠMG3hzf =GޣYJG-mnӦqJ!&fƭ%UlP ܢHpm*R%*R !Qs* x#AqD17ʉk޳ b7xg&^y-(3QQQQf[QfDDDD""". epAL \.IIII& L$A$A$A l66 fa1b"Sf DDD8ie~bH H Hҫ<<<5k`1˫#V 4̈́Ah BLAAAԙ3Q[CY8yqu^l~ EwE=֪PU?3]qk`a[0sa6wUwn ^gzLJFW5wj@[YVji }C4n *;W r_V$=**_=4Ϩw갽J+JN'11IkTS1Oy̚G̰9n>n~+dZeeXϜi`?f ( p>dlK[x^z Fa6+ zuQ8cfMzW8+(ㅦyBmOy )PRr.н%R\2"|ҕRI N?6pI>;fGgYO=ZS-tV}$%o%pϟ\ nw yDnVVI0GpOD/~I~ ;k68Blφ#kD"G^ ܱ nH)$SqCJr0}辋uvX= <q4Y_y9XYn׺wϼ9] |8g7&w^p!'ƺ;'|t>ev,> endobj 125 0 obj <> endobj 126 0 obj <> stream x |E7^U}NwL}f2I& $D%B r4(T$@.®ºˢ+d}f&d{ysS0BHCKn2wԼOY(=ߡ| !q3澽n Br94eϨB$B OϜ6yǓ6ơp3^fj8Ν9w8'{qޔZUp\5wN$BwMN ~RNϟpQ ڌ=az~iޯy @F?G.&$U3[pPvEʉP~Aa7()ޣgޕ}V]qeq8?ѱ/!|3ǐW=CY3<ݓohvWЫ,j7:ZGhƾd *Acpxt+:؛݆p 3AWhM.FI &47&k$K>B?$ۑh |%>Lu_܏B'}Ȁ4•h qrF'hA mad#> }xD9y 8C"ab&y K|Zc gO&"*F?-h_ T*<::d =CX|9Qw4Z K>qW# ˽t_x)$c$g* 3\/YSI P$Fb34oD&sw&CGs9x$+:|/~'rC﹙\25|F ;]DmhO=kHUcг8>'X*'#x,>xމ[)'k/|H'Jɯ#8|Noɿ9q\W̓V೟+IfaCxNxU8+j2߾D{(>97ђ+r 0 ٨ Z?>ޛvwc]x($<70k 0{hY r54@}O~$N嬜 4n5sosrs繋I 1O__ /DE+[zJWJ#R\$ޕ;;<>ŭp=???OBSJvd%n!R/鋇| 5'}<FID',ߡ60p祢o%ߋڋg+勸I,'=<Í.xRE׀Wd y#0,%G@sȇ x=zOg{P^BOT 7]D~7nA Ĺh5s[Gh1:+3yhqWßF +ZԐ\ q(?趂G`D ݇j 3b, <8(G"!h`:o%F ɧC}+ ڄv5[| dW|DF͗F;{7y^BhTܘ|!t^~O;Ȟ@n>$|&43y#$M[42* FZ so옫+ۧwKKu-.RXˍD١`z.nӭ*&Y#7Xkdܩ9 U/9\. _~WNٕFJJPUhXhOY Gm\Mlr$?n0?nt-F{*={J 3d34?O[ VY~{nnWawVnذ.ܼmdm{oI aȚf=JoZtn6E0HЌF-S? aLm4\MDF-3¾t-ޣRbM4s´s.!:FEC4%QSom.: j lWAC<=/m1OE'3梢.](H+qE%$aÇFNSPj࠹qdm8nEFIQ]3gdθ33?'0,:1`ff8=-u~萑j6ԧvȘˎR{wKjIHcg)'v\Ljf>ES[%fԶND&_ݥܧ㾗_r@~£+x ~w/\垅?-M'袇7.'`&pp>x.$pXUa܄ -6<IB6hK\E[X)%H$@m]a(Vt$z+.ۇZd6iz\mnd7n?OI4KqLjW^eX3eWDa#廏/۰ىeϟfh@'&En-Pr-h+wEX(b5BZ-byޞn#"[y~ >entҾ HsEU'Oħ_ܼaŸ/] Zl3|x _zNl# B >Sv66uВss6`a cd=Kˀ$NQٳׁc#;pW7:xU&sAj |2#5E/̇ |EqKTRֽ5@'+"H!nݿhfCyV6|qKQ;;ɯH%ЇC".^g%iM~fpp[ 섫f8pg9t -;W )řb JΦDO''$M~ۄ#YxB!P!^pf5yў %Ɇ4Zܚ[֡ 19H%p+|gTUi 5ni]-/ݳE %0ך/Yr9 xYi^2tǚ)+lau(B^ ѳ΄4P+yЈu!l@w1TF[ZMG{P%vh6y)C;ؐ{[SQQU2Cёzg<40g_FPic,s;_k/:H@YzH<$`~&?(;AZ g}m֊i+&6uYHǽ ͶL"m`+"`Slړbvj'Qxpik!~f:K" @M iQFz8/sEb=0NpP`K{O[-?:~;y'vjʑ[~1}ί87j=݁S%)E.M85{SV-FU  Ph5_XbX Ec%ՠDڀ~m+E=ү@0kxے7}>9սؼּ̹yg)"974^K)YX3h4=DD>2ȇV L}0 {)'1M1bz@ϽHĚz[qセw!CVŭ=bTu(­Ӕ9AORz i u^}ի!%Dq-Ϲm+ˆ:ֵgmtDyasO)q&އ5߾b1tW}ީz#} `q)081VmvjohPn+ޢNP+rZж \f+sEm ɣzDwO%P>4`츔DgArv CA# YbGDGA2`ZvYֆ͎g> &ϙJRҡ;xbuZN "b8hC 604-VÅӍzwa<$}~Iu//F^K!6qzO’}\8(AFXG6,^'w+<eb∸" r9%귌}Ѝ8~c{G/_},/qᮣo;MĒz޽Vse.xx8O  36AUӬ0өc蔂yfyֱwP2ަSJv%?<>&<*Mgۧɋkw6)L8?%(>mGN"l-3s[}1Y4۟ݑe)O_H[gpjN^Pzm6ؼ" D#-D#0ffYSMCh:*G=`ԦSDF\ҝFn#z{|t:w{FtehNa7/Î+܏w>SEOn p$d)Hn>+ l\6Sn0m%a#;[: xץ5啤<-0\f,^1y=qϗ6ݲcSݹbvy'%?_% Wl9Z>ⴽ(XsUXRv "c.cK ?`tHEh;;vc,mAk'ԳcSz)q4e"EϔDQs xE*5cB(UJoPW$c~5Ӥs.jazHY3k'LȄ`\0\9\'~bR:\EkO:vaϽu1j޲/q4}hA#ă'Bsa_ XH8<6? XI-*1yU)L F HTd6B&NzZ[H'K o%FJ Ah<G;ɫ0YX{GN T כPObG< t3 ??i\RYUG?2g_S0b܂5%v&E|Cg;?3u9-6~w-u^pͺFl!pV\7ZWM>I_v6:|q˟[q7vovw>o[ov:%d3`Ug?Z҅%"c3-KLSk^guU82B6ikpbx^3[dQ4(ˢ&a1E$ÒShqa^s¯L!AC"' * ahčO\@f+Ɔ:B;"Ը& kXJ%r(W?HAt^*?p 6W3by>5Q~uBjR;Y=94rBm odP,?RW4Sq(.Q.9"\,_8R'RsoCse¡Éd|VfR6 :"h2y~`t\tztiI_,7P|w L&=ԥKa! f`ܲC!1Qؚ(h(ґezwZtR>Ŵ 4.z/ 6c 8O-ȩ<+,/;I2ԴKQHHfVUl%Nh(H cK(7؎NfnL _CX]|[-ڕ~>aE:~ 6X6tHUBnCMW0+}'vj~NK>inAgWth\ ya΀es(b<"L8ô ݄q,?/lXW~= /f=a7gQi=YИba+̅U|)ur?4:#U8ﯤ0t> 'j1=ˎy|,5gENGX!/*p)AlP::!|"`YU.CGF>h5mP2wSĶ[[l yHu{+IԂhuƚz4c^xXipO}`ӘS}AajKBןbB[* mC͈/ANH qBj7͖f [7qNobF0du 㙁 lJ#ܔ υ$S:}[@KgB&ՂdQTWiUhz#:Qɏ\l,O8B"P&1![b#.-Ƕ< l+QZ" 0@Y.Y JcXͦ{mCp+ҎӻKdX3id3nh0\ Ju& KeNN%Z0`m+ŖZ:~yeYV W{Z!\ɐkW[Cfi{Fj )DRA2]wmNF;";w+VP46TNZ gH+&+0uV2ŰP/4 ,d>[_~މWyϘ e8X0 z_2Ғ}fsi\m?(6=H8&ŊBmzvq+`# GA+u*$,;Q+{0w[*S0>N6nx3r٫Y%ܞ$$s&$\X ])I3vU^6*d fx2WEqPtpRӝtXyB)M^lr6uKJ+eGأR<>(Him4F+%z|Yb]WILte` h9lB#IFTxYPi[Sw:@uީzsx2l=V5&9&x&yVNGSz-<āW'XL|@s&Ķ~!q>*Eʎہȋlsd>y~W xSv=&3Q؛ld؏5wN}XڛlLaFy\ؠajnÏŇv_S8dO;0D{x;\f9Ae1]`{lpŘ`[msY-h)[av_N~g5ˊzzOg6xmx:187Բ̺FYo}j=cʪ ۬Njj&{DnEӬ(k2=~_C%y<(Z9<"f D:w " ùssKcţh0;[*Ѻ+KXR*yIȓҖȆҪP LcX}J#X8 _`(c-6#N6}{<؛w +޾fH a#g[hWoJ틹^dـ_)~!+`?n44k@v܁:ib;(u+xf yB,SSL!)Sv -c$i-P2!<.:6FuyeswܼܺR_0o-AӼz&̛]5b~S*chsp(vP1+&ru.΂%mO蚗k1B$ ȒsDy9PNgߠl p͍2ǍiY\&,Vl8GGC5P!.nifB٩&w=c,9pBiKocK.:G{lL4UG 0+Dz# l–%o7.{b_4Oyώ1oƑf_?!뮝+{j>?o{ L.Ĵy:UYu9}/Y||᢯)n8wf`[fgj% SQ0&%t8zP= @R^< &;;pKLP.ĖK1&EpYʟ(?얝o|\ 4_/Bj[OX! 1o%iFl탼h>ޫ?(?hMQcU.kavk0UZ$,nqY\2atfT0xE _N4-Vt.u& {n{c $>cd9:].]3B.;6j 6&MM& WZM&Y&&n!Lx$ # .H#ikwIqv;l_vw5O);uQT͔:oV ]i()ȃ.8 ZffFS,C8R QN& -V?~M/%ʗ< \v½M|cxڠ O%v0p7 A[%BGo܋-66T{9#lޔnOf|Jb|Tv=>ry ',c34~c^,U nUnA~G i>W5r^&Ra%]D DsO)A=X:N_bt7aX6á˜iEŢN&##fsX㜚"q!3z$ 3ZJrDVܺR|Z El1q"C #jOѰsg/|m8/ue,JPj\Y%Kq:fئ|P3hUN*15fJ;K T:R;*@% 10|9-nO\!PPRWZV "UBK4%lKS7e0^ +vio'Eg#]&r&~qxM{kňPS$KóȦ>:>2W 6ݘ_e< |lr3řg"OH%(DΤht*NEQEN4qTvZ.L0(.,jj+&Eii%^äFJBsfUˆ5lb0:32HKD$=`|*FCS/%Tec\׭H&)nZZG'u iX锶4PXBW]*zL&0 _`3TAƈmo[ȈW_Hr5+V,l»/kM"]bgw)4wRiep9eyV 浅[w]|=[pRQ?>-qZ6jD*(lOKy%_Y*w{?.͵ָzlFLMG?>|[߲Ne'}aZ,0:B.|/']]^$(T\A=b]5zQS*Q՛|9BeeI(2gr: 5"_dLX5,@ (x>KGќ|K]iY F/C޻/y^8M70}GWu2"yk ir[UL #*y-.IX%,cヨ{/u4w{&s[OO5SfYla6h~Zo:4V,9Y9+1zhVچN` Z* 4="3| @rբl:&TQ:0M]%-UKD8B/JG~9P%%*H+j[UϢ@:I-He"r\՞_8Âݾ&ճk~(@ș h6d l7UqsyiJ ic-ej%GO~{*{HDߨd\Rq<9Ց[7pIߦ]AEBȳc3hv]1P ݘ3 T!e6)Ky4 /VNUTflw+]3 wTQ*%`AF#R3&ƋjOkѴtJ~U{CU:=:,i֠]9)[ؙt'G)}{΢`vy>0f(PAisigzvX[ߚ@COx}!A籂26uF u YOtt-fmIet=l5j.9YPfV.U<2󬪏Wm YT-d,Ov36Xre:) LԱ4Kfۙ:7[<$&`آOɎ`i3XS޳}M滷I7&μTJm8K߁9x6vj23WS!R䟏ނ*x+(/h(bk`Tַ?~]#x<1a}'˄Ay *oTPTIj:\hы(jy&*3ɶs8wEuj&4rNi , uȺ5&J,R8̅SC&tږ̜ٽz]`?߷OP(<:IH[0 <(fށJiiHC$|Ep`O;}FqJd ;k|A;Ӛ͝6gsE2~SȦSLGx`b(BieTp@Pw? )_P?4בgJ=lh0tp^`/SAWtv?y?[~Dݷf^,Io!l~ބK#@A; {4~>Da.ԢY=\=Κn }<}z i=9,}gNHON;ONaw/ҋ\|} >AB{VBWms=`]1zQÌa#ej.Nfv2]JT]e <L\(/ yMdD@y^^|Y<(ym ]Nj|׉zs'f/>y˄MlO/Y3I^0rO$.5OcGz7?RxMbw h iܣ"ۗ !4Uk m @u`ct`cJ>zW|W/$9ZTh@mE>>EbżEty Rh|Պua6Z D,aDXY VHY(MǚÆE =~_ebAHᛊe.>j_5`[:3n,Z偱/'έox=҅O^,"ai[⎧ر߽S HPņ08(_GEh&dvLfXe"SA地;H;l ['E#2 ̢H9b'#}_8t ֐: [_@Z7Q@QyY]WcLQN(r>Ǚti9+LV>xUl!{K+މDDe:Qh-6VfXK&a̝ԩScS E6JyDKTvjO?Y/ cd L!7S(Hykh!)f Y4 i \-OCw9b6 MV_o羅m@uNzN8zXl]><1Js;3wޙ$dn,BH@@$H LL&(bhkkՂ>h}2$,a[q*}b.ڪ%y9&O;|gw]љA3D oLnlw$-b{ F|,x ߯&k-TLYTpLݩA1W*$,pLp"~SaO*+|MR:t}\]^tCص3e@7RL*U=U7{":71s1emss H5D=WUN7aavyU7[0_OrHE9䢐[hI`v zhrCv!($?OVlaK: 62or+m#jP^1(Z-bcg)Au5[_;kgV^oI~,ؿ_mm_ηtF[Ve]?iiu'= ;b#5H  BjrXUp쪖 :Ȩ(͕ǢpD?c9kZc=f扝x`s26sjf*t=ԽX+ΰzxwYW{3wII67La'h 9BR4IXa%RXtWɸ,ABLL 93N9;X^4Ndk~q9hȗCJT(a,MrӨn/+7鏄MC<<Žʯ9xS#|| g",z(5[mlBځL̍OgT+Zv^eJ0+W*$e%Y( VE) W',8#[D"La?bR+RYmïYm$-ܪs|Ye^6论H*ӊ3 }oޛTF#8 <4e ~]q:vx,c=lf{C f1[i Fuq|x)C+nWΆMEi8Pbq+ѹمhoX:tC:dRh)P݂[75/nȁr͟a[Gr-6dKS=V Xlv<$ ɢ_Jg 6(JaW9TtW0Ju9<RUZlZKlؾ|w\6%MBtjKqE%i^Q7\=sv0 b['a=l4x=zzH-:L3 8ੂ"Z!.͚?:ޟ$B@F~bC*.>gdߑ' 3܎^_CkӨ8 {&nPFmN*%a^)@UQS[Ԫ={{KFUiB<əUj6r]*\ni]?#;teMߝj)y}~[91}~F\_Q6`hdӯSWU6ϯ)6<O=ϑpt=IMIQO4):ims'}֤;?(9QX&V^NаęCjrRRУ$Eu`g+ Vʸ"%c~(H0mgy"sC=ddtyqiEtdGCXEf(:k_;F9v#V"vO;{&}m4 c5JJU)H]…{#}M**A&6_`I3\*$s >䐓}]S!}d/ gɝeYȺ' j%ξm[6 _gvSc+qz$!AW#2df&$ h\U*Rr DTVF(kHkH\F m$g%!R *Hoڤrݫ.4*)JP(afk4;&.uVzlۊog;tpE\k\]V˼\qPH=`TUgn1LkA3pW4Y󚛫V>$$MCz%~yIҸ&~beL&`z,y/f*RU4!{c) vS˲&G{ -y=w sW^#Ǟs:5TQ*zyI O{Akjuz0$T[.̫=]X pwq, ߉{v!(~nv(tL꩜I+Z:4 d 8WL)6*O?-lZ|UWEY(ҘJ慴LU4_)`䫹?`uSV#KHS!ֈ"Q:m'`bClo)SR29 WGY"o[1d6vʧC(Âa $%2 ( ĩܮ3)K]Χ=i`^r'h˫XmOb2>Ztm6%z[uItRv -'o 0e߼P;dRK{!PY[J8Qx`emk~՜ oͩ_v<0c;z#9E;&͆K̴)9.*[ ݄om#zюѻ"DZ?FijR/DŽC}77ޚasK\L5IڈVKXuZrJ;£a!|>(5@(auoPMgZȣ?Xfv#u:V ~EOwΎ_`^οω`4U I B4򆔠-,+@e ")2R"R254-IN-dhL ˚֛۶mYE&(nxK(4_2~ _'_#;_|Ůן|=)z쉑_7^yoZߐ3{ᆳ{MO܉/@:N^X p]kJ.h? >30. 4bUZ 3~ԠdZA5)x}V\7ie|0i6iç&-a2in&MI6eMh% LూZn6I` s vˬEN3 i2N۸{;$NKeSmР !CL1dhІ ڐA24hCmȐʄycsZcyt('OiT}Ns?r:cO`BFK /ⴏ҄KrLpw С%2!Іx!Ξ ftrbNa)q6mȽ VA:a;:CݾVNXf:T`̓a*RSZ71h &ĵK71(g3BcSـn,^,.2E$CRf܅%<˦cbX.(.4S<CC:L*#ssYmFǟQfC!tW@~K LhB؅p 5l4}A=|V#B8HCS|MFB7hj],ֻhޡ`^*=ĉpI&no0XBFa& ك)a78#5@a B7 z ~ BkNO"LF ,FALf6W y_q+ęO3PcG0b q [ z5nz e@aB=j;ll x0#pRe6s<,Ad} PgFbإ H螝heF;bF[bFmH1#Թ )fZ#ŌЊH1#T߈􁃹y DQi?JԏR gBؽpAa`08J@JdJ2&~2I"d }X">2p +%!2$d@'a5xiGs9a3QiJ4 | | a"Ȥg̩ g2ե<|`t F9 a5qF)43~7U4Kf!F3gbfg6z/fE24 wI3G3i%x#{ܒ{8:Ac1eF`  L"?L :R!D< z?G\:_PQ0qP_~H~?x[7*hh :sCi=Yǽ \mǕh_m ҋq_apU01 a,y9<*IGHG\.֋SRHb.&KI\CR$IIJ %#al㛒l@KJ$ $Ѻ٤.q/rdEš3$> endobj 128 0 obj <> endobj 129 0 obj <> stream x| |T9Y2KIB$$$! D2%$@v\ADZ-Tq!X֥{mҾUZU{ιX~py9=͟HM]P<< }G4 }JC!Kv>|G[AϒN$ɍ:OP.DOȎ^AZohv #rԍ }p;*t#FSmCqBs2#0qP>.Z=oAJ6hIF z  ?'^W Yuj5tƜl֠Ũ]@C?@8fèd5l^x!n"r-9H \| ܻf81T=zhSCL}(] m.C&&t-պatEP?@B?/?)kf|O7/Ii"׸>#ǯECޡ>4}y P+|#ڇ~=>0|џr |Unl <</pނ÷~}0#9X,M&9dA' |$&'$9o fs˸n3{|{a|??m½"UqZKoI4_Z)]-]#]'@;LG}2c+zq<<΃p?Ŀͤq qqF=ϣ$q@NM֐ͼ_?ԀK8ؒX~(IcD~L*R9,$q*O!NUC9OWHLx:= (FZsz&n1>\3xc8r?rTƮPݪW/ T_RUja[hLN/QaGy@bIX-Hf34'2InH2"+ZUXm ~)\|,6113`|:^d.Ø*;vU]"CW45x,~p0)UKw(FfwH !5~*Ğ}ޯ~ f.ލm}/FKAzAHCf5d"!u[5`c'$I3jL 8Gϰ"9>SFSJPsnUMLFΖA6P \rCC( (Br1a)m~v͓^bOw=/]ze㌻€۷;E~d${ { zOܰZ 00{=*a s\8D. +p f* ~+xH"xC*b/^ @<<*zc (k D dgUm8خm"ViP$p5? YɎ͎E:T x5:6oX7ɣ >OR2s2Nq(my{06}'~P3wnDbZL\L<-6si:OZ_=g{܏˟ _Qr_t00XgN$_?0siڍRgkT&i&[eF S3vIu'x\E9\nwlvbtj,>ݭJhaq(pq[3i/Ss](OmOnPÖ,ѰCeL ӳ L`g$.Z:*KhW*-=0mLW|f__VǶYy7(>SqۜɗwESKo$0]Oε9L8KCSrvE~Z&k L ׍'|\BS([ZNaFj6ffM]JQ NJra<)I 8o<%dsj{+#CCjKI4dh$'eX K0ρv2z#GtQ8`\:O*(,g(KR $"qN7|)| %ui2y>Y|U~\tų ~y_G_/ʒi?XuqK8%g--\<>*c=^i?r~C kH %)&+*^EE(4dJL.A( !Iyg{1AZLzt\1殲]ά luh 7#ߜ3,rT /"< %Y"C h ;AF'I Y&' HV!Of2 " O<|9Hyzy=p{Il^EmMg*E~c9eSgIOo;Mh%CT4MBχ/i4c5b\"__ 2|NF@Fs y` J{/|]guaW$V-թ %l&w$sϐͰ-<Æ`W Ҩg(*e1[5 b6A)L S>8 ā,WRȩi.gM(ҽT_\_睒zzIe+t%o_MRZsqgWͻ`UKKW,z1( N7?7mC.ۣ~8ޖV6#6neՏ93.ss _KDɑ ըhDs&~($&RKhB {\*n4-8զS_ Eeu}(P 5HF7ԋ8sfء*K~rP$NX(XWһ^.i;_״|k8X4s[yNG+xnn6\X@ksJGYƋ[ldYBzE,NsRH,ZS- 85^Yx(y}i@ťI:dQ-RT\ME+Οp|Øp,S) zK=N0)bL9 .~^un1r;~SkyHZ+[( LNgJD LI8K,ӍsߐWkXi&O(*u1#-^O$tK粌wxٱ͚RUjx<^'g=$A2Jpjrz IZN뻀xuaAυ2; .j@V,S򋺤` G?{v㋫~]/GS\s ٯdݛ739 |޻؊&v;G~\9xC. g]ǻNvq84LFgT,6+\ h v,mqr=*8{O\r!8Pɡ.g8Ww]e¾I SU,ê^" jiNyu|pA$I|)5<`҃>O˦N*rz~v2-GIݻ]I%hR2Q&F4P )Qo$s'4{Z\*Re7Üz7XF7NEH."P9<n1g6$ǣxu--}97r7F`S#$Tt%m(/e í܆CXHņ./Y|SoACŒaN}MfhahE=#*-Ȏ"F|Btu8ݮZB&?ER&983'~'W+oݯ޸quLrMQmTkqɩ=Y? C>z5 dẢWaq?g5=4;Cf8]>L&UeuJ*o;M䍼8!t"C}Ofi6ʚAc.3_c~̫3q?*Vx@:1^# 쮝J- G[\~ݏl{Q,53-;&ihF ],195Z,v;fVm\o.{VrԂ^^$p搄sBGrr_rBKs *ە7Χ()eH(2$x%[Q IR; 5#A4'|h-7P-$9j&ǔ2>45R4?:3fUIz⤬IX/ OH(Evs2x<x;^/HakGfܬeFLf3x o15 E(i6+h6kAd B)!d-YjB5 s V1820Cm(Θik{G?&SRFUgt!d3/O0SࠪM͝\7͠x|}}|oTήqK?2 }oT 4!$,o$V.KЦ#yU(CQ!6(edH29;#Qu"Za5X:,^+*J貖l0!4vq21cz N)9 p?E 4]+*%#oiLML/Z vQ۩~,{;X8|% r\ZO{hvCUl4bhJ.ջ ILfō+l8apT8% F,fm qJҎN7َ2BL##q׬p3 ̤HbM-w MJN4F 4iV=p:gOL&fL_2 "!Ӫ*rqᚐٗ&ׁS}GK|ucd1 >ꠊXW Ky>%GSg<: ;vރHĄs,yю! {/13^c6.DZ5x{ωKn=q:+R]m4_=kpy6tk|GbE }*MHʅJ%V-fcST\~f\nPqZԒNV1Bn .!!X0f娃^S I\ |x\ :Lcx.:b $`tiyճ5~8 ;bG"cᝃ 4]{GͪU|z\3xI_{ihs?|z1N))D\sI\mr#' G58'$x qUCjHRN֧5z+5p{afHaAU {<5'vL^Q׾xw$|.TW4nѼtA6~&φPJܺ$nU7WXg ik0/ j| }zfs3/z=b<RW{Dُ6%SjI}RmȢh(~y<((6;fUiuR2:E)W5ƺTR\̿wl_.!%o81dŸ[XX g$Vc_'|VYu(dQ ;(6K| NkD`>]/ժ&ڏKG/3O S?B`L]v79f]cT{a/ B<Ȗ-x { )^r>mNu\98+ }q˜i"C9z|n#{.o`R?FA!3_m14rTJk&# RS] (>$XEG\P?fSe i$sE̖:Tyυ]O}^] g>klGHLq%w +j78"e\nޜsFy_߾WYXҎȵ59Ur23yw̼x=ڼ% 7ͽwҥSrpţ֕֍{-?p<O'~9"1f=ESLk1>C@X S@XUe)/ب!xy oe6vHB'MbTPDHE=O.YʍvOҞ7&N,Nۤդm7^{DKKmȧ6xerta ^M s8CgcpZbe0.XnGAvʹ`eLߗ^" ʂsQgԕy]^`Shren-9t֜;Ok[7ԃ>TWq@ JCΖ_f4N2YL{P"={R>kƥT[]k|[bk⻉dww&n&u=Q~PÒr{Z1jXlfhsN7>MC)@0 &&Ynf3tƋ -IZOtu܏4G0̖><)V0ބ[wSs櫮ޯ<9xjԯ>'t104XdGݱo~71\0Ѕ(H*.Lal8 |r2:{bg2x28! D'/]d>1+?4T[%䴫6FYCy-{6F=@T\ &:"$!^p9&b5,VlQD[eI8" ]*U,bk3DbTa<pHܱ>N,Ab1o쥦[GR3R=JGQ?#dK~$}՛: @6xRۢX 8> oǥ~=e༷ӱ+R3$ p￯\PUZr!Sȵ (&٥ b(ˊbC,sVU͗,NI-I2Hy ,:Q§9^cZXʟK6NcIRf,TU0X< +m.|L~?wمpgpu_Yn-RO6~M_ o2+]TFTnx,0пc9"H 8ˏBZT/Zj mt/ Aף%pUt-\W@; N%t ~iH* P9_ZCC9 }~;By44__O dnQ~' mDH^[2%)BYo B" #]yTNJ !lB7!-!?BJ72-( T W] ԀWJR>W;r&fƱk-yAhgb1%زZ/hfiIeD&z &vb+(Ǘ u ^Caя|9|h1vM\֌S>u& ۿ35qkCeh5Vǎlt9݆5?:9(i1 ý%9ܧѴWGLk!tSp}r>pq=Pr͙|hzL|wr3˛3'4^%a9pu \! 6E1TTf -s/.f#z!pCn7,&";̃;HK}< B=Ok,F]Ȏ^7{}_"{o}u_/u 3BY}65VIkd.i2͜UBeEf㓾f_~6{4>z7ceݍǖAqY ҷج^-&"-NJ{sAio7IrvY-I6Ȳ,ʼLd$?~ S DgJ_FaWMNͨzja 󗄅tWE=`uDZ. VyKa|[=F"KnL7E?[h:tȵSfj+[c>+?eVO]"Av!d^$^X~,>G eu~?I~. \@˹jXb ɿEeɿe|<Nsi(.m _2~edƗ~o߱@eű@`3.e,>}0a,UYc,FX&8|ǧa3)N+̫ۨ;&ԥvNenN}8aaC`z<1DSX" .=:aG06A9V=-{UߨĪ\C@GYA%OQ endstream endobj 130 0 obj 13388 endobj 33 0 obj <> endobj 131 0 obj <> endobj 132 0 obj <> stream x9{\Uek}O9DGQԣe>BE9(/E2GHM39e䨙)Ʊnm(g3G'{Ț׽l׷ַ׷^Z߷Fhz;LW}d&Gjwi{뫟 _]۶N{a򳶕7D$iNp[kt@,~6kV4۩755QS/՗U}b[i?664\TzcSU#۩Ot~p }ORQ yj5lp"Q1q |l %$ j('Hp/o!z*nS)nU8!o8 YKeA#i,*UXBkrac3 pAxCp3'q$f p3;ݟ*q%>n5L6f e8/:hmpH+; ^SMBaO"76+RXihfl.?_hDG2Hd*K<ӯJV6ib>F(bѫ罉C841}~azNA뜲--&Ps T2iॿye꠴˺+q.kԉMO1d]1qOpD֥KҜ~VF}:!&x2KsIKK]ҮyRVDU#н(V(>gW qXV@ Fh)}ԏɅŋ b%14taqOI 2_[ja-$y2Q Jv =v"=8}@1*G`*= =)CzJ&pr/S@t?sL+Tp<ϞggF<6 0܌1{5$*zO* Lσz6? | F+{-4>ERyQW#: F]=6EGx F[]>2f( +ҖqN}r.72 쁂 9riIIl/ޤ$y`,Ȱ|u\Pmd@ b-&cG1Mb Ű^dDESڬɌ #\ o Gb:g:KyX?$&_ṯS$wwɛX'٣dXN2@c`E:R EIvAA^iwLb}t$Yu\ VWo$iyk;[d^&j~d`9IF):Ϝ3.9HӜ&Vj`ٺ۷<..j6.ທ:Ǿ 7]^8cqV췏~~N6*Z䆪8QOVqtg (V" .Fpkk/^Q4U󑤛?ƪ 7%R*`Vgzx^K<, +i$R;׮ΦPfJj` iYӓÿ_x|UD^^DJ4ETGնsՉ]FHDtt.CFKPTaX/B RglruB'w8;\}t}>g/*eOәɡ%2.9'{g<ə&I.wXrV _=\f'trsoWCuhoT@\Dqd0/0>:KNA]0.bʂĮ˾du.T2`ȗsB5мB*~S1~`bSW61g_V,]mwnLۻ k E`Hbz+k,*\!z>t{s$;ܳed9\uM;@&pnn}3@1+NSy?w4We@=sNb +× w qu\Kh 7` ݨ6>k]DoEgW#j -4dzb'GYZj?ȃT,0oC۱he\ o.ހ]-m^k.Hau&-m[jJbpQ6Oמbc׿^?!-!hRv@\qvDY5`ĺFOh-SmֳTnhS"?o#)r%^$QHZI'%s"}n_/%44δʹό)Usq1T Ϛ5\L:OFT}AA#^Eyp;h,E[F **(l k9%XUVh?ʗS5)/6м.eg˘}s4PҳB8lTvӦ%tS##O+M>,l|tV[yaO Z1TSsc˅:dR:3zU#Xy sK٥kBc$4."o U.KS̾8ڏcؘu]UuTSJcKY&U27ˮ(?/5Bgx෪u,50;PB NZ9;h IFf6&@" Kw'#u~59gH/ Q43ِq}|BW9w;Ao|ΐ1.s劤cv4 $jSuTC1ՔjN9|tWjlj\j|jB4ޓ,eۘN‹c>u?L/~ E}~xl]KWg]o7ЏG{~DS䏳'y(pܨULɝ`[yˆ>!⅃F.̟5?fМ}^\Ѥg=F%ORPsp( Lk>-$[{k-xm_-]s,$=;hNj^/0]x:x& <BǓ"c N"oW2\ƗZ:蔓J ;X_.e_Q1ŵOk$~$:Pos3F!1Z h#WOjQh봡E ^Q'-g$:EC %p ,YLѦdqn6i6hی;Ssx5mR Sc`;>myeΝ'Q.ge\u7w;>@zlA!]ǐ#uh^'-:2W# eiE尢ZVFޮy=CAtW#*Et|w젼-_6# wOEjF{ZHrQX&Lf^ɠ6=̆dDd|VeKje]p fƔLF~3ƿ(Js`춃ޟސϢ&>ms,CV(|ұ᷄Jjac85ur H.A`s?:p;^jǨVA1jЖqwøj} |sM Qn$rO o@Hx>Ya%aҌhh`FIԞ0üiro6+P"M*>`APxZW^怇;0BaP@aaXC00H?7ȫv< 4aXnbQaS0lN7445T[G%ff4JW:CKS6|cچjivyCh$e욖斦YeLicUeªچ * )4iJFfeVU4埘7?r"&~fMT.5WVՕ7֌Q`AMuyˆk} 5ԚȡP7$XmPKfXHz[C} *hd3a+ D'TD@W5; j"XVrH<*h#ƗS[< hZ4>Ҥ\GTE@C:aьitUB5PM=*nX1iVPT4"&VP߬tu4f.TZ*gj3# ۠o&BHGSpö I^Gz ^r?\{9OgNWW'o:Oވ'^<ǟUb/>x:|<&|ԄG8&#GKGGG%x4I2ďpߍ2>> endobj 134 0 obj <> endobj 135 0 obj <> stream x{yxTEw=,4 dO!HH l" $@% YeM08`BqQF}"b7p4"*${v'<<<_UnSNWuB !zRENͬs FaۄP%W^W!Brq첇&"}ex!%E3 \2u2! ѷ/ :{-zxUxW>k6f<\!&;(+zO YEz߯XPT'BTvlχψP?,(*F&HPpHhX8! oHݫwLl\|BbRrJԾiHzezg DN+>eҲNXIO9_=M7f!H&MZ >':Tbx'E}M牓~6: qȣvZF/ J!wsY-iRu.jrTdpLz390bAM_(cm;NW6P$T=?ڄzg@LSjq}`&];MʅzC_Ir$`*<%.+V 0!g6ٟԪ\V.ʧOX*N9~k'JS1!qi ιv*ߵoLށ[F9w*QdٍOFf)TTJ?q&C6h0i5J{YCI.]%kAVR!XM*YA$anܹ'qtUF2Ѱt<1TonݮbGs4Q[PCq|V6c{PQr鍎Y%据E㚈:v$~Jow4ᇉ&.H6z;u$9\9(R⍢ 8y=!٘8Q8 Ndhckt:k<:4ԙݒb4' e6ƊU m$7z\ƪC7<|Mo(mDnUc[U.g(op9]N3(mK:1 Չ%_!"ASZZ-$B{1_hОgqZND$ !KV2OsxQ:LB1VRƠp̄f%:i&".fg&BúWa2dž ,e,}ap_IRR %υLu*D]"<7Ɣ]Sgb*Yh&MLo̼)fOҙҝlR>_ -8N&@ =D+Ht'm~]1{tmc0ruDtr0#l&P%/2mWHɭWo^5_}U5ݒnڐeM3b8xAmxlbËlD`Y%HJ](ŧfuvOxੱ~xa( f+M,}I[Cu:b;)"o?}>gQ F] ڛSe՛qcCJ* %/RDb%Hk Bz}$C`|HBA3B7@M[b-$`pJ>R)2 H H#BI[0XE ) /)dd'svC2ed-#kYZF2e.'eIqRv'eIqRv PvԆaGmQv"ygkQt40C ROD4J9@V)MI)6Io McFϝ7jL麦bK=os5,Kj^f3wys[w81>aQ)}d_mNN|sȞQѿ)'w2Cu繤G*}Y3m^2z3Zfd3n óWr Zї`jeL|\hҚ;a#W!룀V hV h h΀ h΀ h΀ h壀V h8GǑe!jsRX`Қիߺ^^r KgvE(WrJPSrL:SCԡc1u:tL:SCԡ(K@krTE](e|9heudTqxX,\ӼȀGR 1m)tT5mw]3j(ܸfRTM,) ilZ} ɡkn}oxVyosy!$nig+K\nYH(/` vljq8Q̞,z/Eβlzd=65 ?Rɯ6(r;-ʹNΧ'v?\b!F(\M j2$?Xqpat /ֻm]gp']C]t+%!* dH#j\oM) t\}Mj {x5JxS> J8 ` SԃUɛiCO'm6I }҆>iCO'm]>iC)y3Ǘ*+o%[1"">Q4mPÍ?pU#k6UP7l9{?ZӾϬ=#dﱷ6U _AE#EwyLmpS+y̋"L)՝­i.y8O,y؁[Sqta> #{z0$K[[,YCHb Ta4CpsGkGѣۯRW%GqԾ$MZ<])"FJ /t,>BR sTM9Y1._OA[X֐:_qy7=dW1jǞzWWkP^B; v~n7+ O"o=㻅ߟ]=l۾zk[J16='gS}6=ڰgyfKO{}1}HxS!NU/QXz-PIh踐ў˼fW*O-).%^oysӑ4I _㺫Ed'RTԫ, B=YohP폀pFIȭ&>}VG '(p5fR7̾i1Sg<ґgߞ#gMNrR]n"y<TO wG$4f4h#+>OY=[¶*:߅9f|÷O4= x'ugqx}zon#eRdX%Q/ϫ@(=vDI!RqY 0^gG=t%$@WBH8n^~3?q!6m2fF@|[i5j!  Q6ڴI_Wg_;h0ط^nVS?%\ɮ_5 P zqu!ˤ@*piZN<(au٘3Vɐiy=O>M>søyI󳇾SVO5a`)~^K 1!!>7Y <y85'?\KG앨w.J`mo-|_}gpV#3//y2ETrȂ0Jβk[,*GPgQv?i2UFi(bwmqit9J7Ta&u׾(c'&IhZGmU8 m&E̘wdfF)yqOv>'T~%V*=*  RXՎkzX 4H 6jeP( P!~2ben wp{UI']d%e+xWv'д4˯9tMU|2,zDnvtJ{:**7չjOჯ>r,|}ƍK͋\d'J5Pc4ZBw`d rHN8-9;aB8Ļ>yw=EB5k7n\f};†&!/]5S)ŨsFUlek1^=#ՎizklhpOT>"4Jj@MMD` C#Lǣ &~l:V ^4mDo_u[9Pk1m)0yݪuծ_ףkc~m뼺&!9z(>vwzŴ?95?qޜ/1nsK~ 2aȺ{e 0+,VRpzxC.>PPc/sYs]d@F޻]u$z:BTI[oQwCwEQ4~@:2975S;Rjka &l@.QC`n5cVZ&Q68?]Y_R_uP,,Hn`'AR RGC0s# W/BX*2y* h O`*~Fg"wTslrgeܯ'!(5d[vݳg*״pfJWy}D?O<^$HOTդU$pXz0O_Vq΋#m<%kkOboo6Do}jBCMt@,PolSie1*ܴ=n31SAaI$4ŜhbXƒtyZ@p׵,}K²y^~q^hõQ(1fPka "bGEꀣA5bi*r_lUu*o,G>;FAv~4Az ܷkʩ/ذ~e7oM#.c{\-}ʧ۩u5^-=v 2Jj"zL}Hi4x/ h=?PLwi~'ٱ]ܲ0aPqo|AK鹟@S|ͻ5?L^i=7ͭxtIzn/˝3 ?g!αL c6nm}"F$~ZJ%1dQe5<%PR1BP$xh6y-qx.)s(Z<:LYZsVE4(L%j˧Ǯ6bRSLz~Uzo{S.K+{%X??`rktQg'v.@,iB!:'I{ =^r/KOJr*EVjrt#yI|}P b4GS[",V?Y3i;ؑ]k1 aJm+#ڕ ԛ%%ԥCwiCVQKp{PܹݻPkP:3J/x}M@ 4hm-NPYZHE5 j֎VJlݵ[P)@*%tJVQE/N'j8G̯_iSkbh+Qo:,S. \K0n¹Z.Of4p =G<d& Ff4~bԨ[,f*ښk^;-ӭvaYPѼ,-jk>ϒkɵ4TV *#4>SfEo}(:8-Y1ۧc:<\OLĺy0 "FLKsշiGʊSsQB?u6POP)ߴ|JLs]m ]HM xtme'?ٺY8T1+=hʸA슔Ģ^{ooRT:~X87Z|eH 3ԂDJ x M yX%oIxyi_[-i|t)ɍ ){ )>XEmq^G:TwWڑ!7xD`ن^(O#5(/ T>XBԊ3=\U4҇HԈtM!Z̝Z->~ 1xvb"m#TE% j~Ct@ Q8N >xĆA}P`3C!!Ѓ!, KH#aB(:!yHyD>%t$|֍cgp(1剞ob=٘Zc\pFV"MRq7Hs-%G|u@Z{W_U o4_$@nTԠc5Xյt8u:_(de Jg,rs$'&;WT+rΟ1scŒ%esvd( H=J-\hFYyxqE ,)*]4^ًX~IEI_Rr\bz\r{z+mq(]ᘰ`FaQٌswMfT/(Z8|dR,DZ@ 2@XFaB2c[KAfbυZŤ"Rmr)-bfx"T$?KO$QqxooV3ə"]d˃ʽ qX/Ƕ x z-+y]n?gB 8@F/J>ú -Jݬ|v6*uÁI@V4PIoORcJRGRJPO>Ơst0V2r~^?ݬ~bQ|f ܬo\)ȇzO ?o  W:hG79#~7 R(}[W _*}P? >çu70t1@b|\} }M:`?\`p=t{Z8,3-ҙ0x ޮn4Z' 'Vc:?WH- ^}@zZ%r-Rx#nhfpjK/38š[:B8PcF+7gZa?}{ҾdkgXgay:Nzf<aS v9XU~,94ßdh/508~}=qDcG*qfz- q~lvC-*v0<}6j V톍`=u ֮Hk1XQKxXŠaXJX+"FX`)% /KM"=,:*.BC */hix(y &Pr fbE ̚!b00t26Y'M3BA!L= Sb?LZt?Lb00xܿ20M F0"7HCRn 3W !r@v ņi0$" &шYMRW=Fi 7ѣxK#xh^e5R2S(b0Ex 2 Q/)D72H }C>#!1AN HZBk#'C\5[X?։1R سz ^ D1iw`Ά&p14HNG\89A80mP\`a 9r 0 N ̂f~~` ,8sKq^ݙzdWwFV2՝ugЂuwPk@m+M1L 46e?hKp l"1mk6јkZ endstream endobj 136 0 obj 10683 endobj 35 0 obj <> endobj 137 0 obj <> endobj 138 0 obj <> stream xz{|Ź5{ly7MABYV wE.1$Hn $$f6Ā1RH)ZM- Q*UPp-9փ Tœ`ةXOkh][++qؙcuMbf?ú!;b/9?kjliZC%hr豃XB%z* DĈD4huD]a2[6銊!q Dv+W|z0 w0$Frv#HO">KD7!lrPm#6O!$4yrl#;IGț8'&"e!|cn#mB-β3E$ cOtOH;v*|b~}IxvFrh<u5+4WX D>'=*2;Cz4#bmSGCX+VЃ|ⳍC65b'.zy!vBn!D(ɐ-wVM~RwfuU٢A+^ +cYi?_z>O23+O+ :i KԐiAɘ$y% Y! iVtHō%}<gS*oΪ*O*k/5džlpaI=>JؑbԇqDu8²pAd̘#Cʼ% cn<ㅱR1)QaMs-X0FAcI֭ݿiحp=H_Gz?LuDN MԦMwB=nTE4]$:+ֱ9"Zv cV붺Drb~{5ojM- ddlF=Vj)4_4miD*uZ0lgQm9}Q*p Ƒ쁁Kcy} +J*M3!o|@;'4 i6,6=m%ec;Gy?IۃۻV哷ohwzzbU Y|E"&n mq``nW+! 'Z9:,ɖ'ȴeo.'Io˟da]HC/#˩os[gF;y$/-[Ƽ7em|k oS0CDHAÈA Oj2_[-ޯ:jZ%(Qb&[p%=XT,t˃u1յA>`/!?:Пe:C~tȏNG7̏xVERxGOYЍ\\,ȃ?̃*s=Daf>ub2I 4ŁB*SU\8`gҡ+8:$JA 8^Q֫kkzO_TlU94SVr!Fa^J $'$VNԎRHZm!պ6ݪ h:jwb oeC4Ck3d@ G8^~G_}Fd&$&huFoMLL "unp dX$ Jbm&-iɎGQ_gf}Sq5CQOQOJ%4UH9Ҝi$ z=SMi0c:DZl/v;#夜M=ȝvS4'(-usޯڼ!I5iUo7CIG Φy/='ow㌒19OoOEfiS;};֟cB2Ce}?AdLB$T QDrXC3x5ӇȻThlWΰtup.$ OL%mBbh>$j4']|7vDKA.B8cuEF㙨SsE,-'&ij8f6XIifz32d +,l6:5Xu+FHY}83m#޸XKh1) %j2$+2dx=KV|=QRŚ<;6%/>>c_ľ辘X~_oq zS Ja0P"'_/)yݹbhKjmM/\Ghj3OK4j1 jx{F!lmiwn_'6vϽRSnB_xJQV@,٣33a) S,$' N,9sۈI:-ے<^ؒ%CTr'%]lFBEEւhz1HAE!hTA"bW,[&{x;mHyfVlڴƶXPTޑ-, 0ǙYdQbY\';[``/Y#,#͇gg=]_[~tީܳउSԴO4*=oBi>y Zk Ĝ E`!:JqaɜN ^ccHGlosfpIxdOQLᢢM'+;3?joh\F8, Ṓ-Y&;nb ?}_S/Λ6 ? }ڲiSYɢ6b{WYH*C؎:,'8ROgD#Rg䖈@j<9.EhYcIU  oEu.FHFh5F7465i9Q9:z! u%ֶw2[zupx$QrY뱬rh M3>}5)0WÂQ-v_ 11ŠgA.cjvIl3IzSè7-:-".A O(Cu*ʹ;c,#;U汻/p81~&YR^;*9~0Ps5N}m3Lq=ڊ }~ 2gQ9+1A1ї2vK:Pr|8EFN9ӦC-Δ3bѐV'BrUu*7=F_u&=庍v qM5>hys~6{QV:^??sbgdYۨ}Yӆ{W|LLCF ܤhsخ3Z3DڐdE0"l@;[,Ld1(kf(~a0 J{ݭeDh 'O>Bao+N*m|9Wme^3R/:r`Sr |[X^F:>*F50>czm閄.}(*P""j &eYO( k` gԡb"mw\c!x$ fŊ==0UsO93loR *''*a-ZGM=6 bx&@`mY4Tcn'Q-^8f |F믎77~"O|J:v=xkJ\ѧ2 |Hߧu#6ԸcZ1"zz"nM/ !!1|r|w6ik4~unY+-iB@ 4WRQW ޿~KW'*9ülp0OQ1-œCWWxRnWU%KGZmb6ڵ0J:bT<Ѯ.ҪUvh9 %M$gxzL͚{CqSx e }\:9D(tXdð)ٌL^Kf$%%y}(Qԓd>֙["IQ.oN2ɝuF#%꽎$P|鋖KYV թ+ =͙o&] l׍}rD0XT1t&t$ُDʹPHmx͹@͞;(@ݚ=ng3såY '<|py)7_(l\ͷbEŤ)s y`Mf~M xS?8,๠|s7(V{AFRk5x[%/8 : Q *L cKci`U:>%MBp﹦&LKN\0?8sAʹj7o?lհf͹w:iU:q^,!vđ=d8=$$fxȣX`!/A6|Nk|v5@Q1 Dg) [F}%hFc?6if0gkp9_-&.UeSےgAG{+_4]qcYIgE{`U"#4iMF0g:'J+T5hh:֦8L[XfRC{ 5*tN\b_;-eylpg:g5xN8 U!i#ldnYCk`[[$hH aؙE6qJ4f&\Xʹ6d$ʅ>_p)"J'4ՙY@ ,2: #KI)-JI=֓tl\nKؕ&9T"T*lgvdɣ3 eV+|r .VQ.[<όyfV~ =bUEض ϱNj`soZzm7 ԁ&M~?eQQEGGTW$rx N".mpEDG9&``X0°{97k}dr}2߷V־iuk8>=_KȍqMtaPC':> VZG(7$:Ff696pܕܬVŕ:m0bЕZa͋9׹kx"490sߘrF[~~wtz:zP¨ya?TUx \YaܳcNn [ʵD݄H>HrEL$wC6}wS\;vo~;Bx}|o?)܈X :=U2^Z%$Ah$^#RQN)Gk$"wC^cuģy&P"b:|ɟ܉tX1x~ /#_M!g׿ۑ&7zP0u'nu[Dz49SGO4:a"xUT|r3(IvIBA7&/ߏ+~bIg_z$["b֝w*^?1viҧ=K̓&Z7[)=}-Xe{x~ }tOI)RɅSŘ抧`)S0t+ݘbOQmV6L"2_髱1? L#a~ 1N !FK\^B%# N$DDŽ4f\AH3$L 1F3T% ZDuhi?FJA+V391!k;<Be.qeS2#|,!p!IP:r1\/=wFeQs3 e#yXxƦKZg䜱c ۛVY+k۔ rzrMòƕK婕u`\֖@eCFhW(}Z@@M]+gVVr|<1kl͸[qq9c 2s&\!ܬ2}E+k krǵ;W#u2ԓV҂H%i ҀQN@Z +܈zˤ { F14aJ,j0)[V*V׊gI1,cZ<<^Q824bJ5f!]_,T(lQm&ˑֈ#l q EBd)BB7bMGVfo*+ `YmUUb77ϰ\m+U>U)7ai[)5aY8ouvKr0b# ѤM8;6Ç p8}h;xrT/=0Irx9&ȁ׏kpGqǏ+e>n&+c~7)l8 G8A 9sYpH<4~B u/P|,|,{T/ypxtB_;O` n?.?ᰳvǽ#;z[#vq詍`=۰eUr;sul бIC^r_| r 6@[ ovXa-5Vshm1h1A V5Y٪1dF+94pX<,ly4,@8,Ek#/#c5YPUBJ GY%%(TleKa_C9X_|BQRKnE(E^(=8,\`e 9,|8au*p:30f`f/PSsvTvtOd0e¦dd a[9 2_/L 1a+0(r0Xmd`%CpH3Yj/p𚢙79x8$qĤ=DHL0H0A|@blAEBˢ8HN ر˷q֩`3Nh` 3EC#5􂞃GqFF'g2 2 `!O-zFiMG7M?D b;= endstream endobj 139 0 obj 7323 endobj 140 0 obj <> endobj xref 0 141 0000000000 65535 f 0000000016 00000 n 0000001197 00000 n 0000005554 00000 n 0000015449 00000 n 0000019469 00000 n 0000022981 00000 n 0000027614 00000 n 0000032145 00000 n 0000037276 00000 n 0000041660 00000 n 0000046075 00000 n 0000050519 00000 n 0000054966 00000 n 0000059445 00000 n 0000064477 00000 n 0000069335 00000 n 0000072856 00000 n 0000076373 00000 n 0000077947 00000 n 0000001133 00000 n 0000000997 00000 n 0000000081 00000 n 0000000171 00000 n 0000000287 00000 n 0000000394 00000 n 0000000504 00000 n 0000000651 00000 n 0000000784 00000 n 0000000901 00000 n 0000078138 00000 n 0000099098 00000 n 0000126717 00000 n 0000141112 00000 n 0000148021 00000 n 0000159759 00000 n 0000001360 00000 n 0000005016 00000 n 0000006542 00000 n 0000006678 00000 n 0000006814 00000 n 0000006950 00000 n 0000007086 00000 n 0000007222 00000 n 0000007359 00000 n 0000007496 00000 n 0000007632 00000 n 0000007768 00000 n 0000007904 00000 n 0000008040 00000 n 0000008176 00000 n 0000008312 00000 n 0000008448 00000 n 0000008584 00000 n 0000008720 00000 n 0000008856 00000 n 0000008992 00000 n 0000009128 00000 n 0000009264 00000 n 0000009400 00000 n 0000009537 00000 n 0000009674 00000 n 0000009811 00000 n 0000009948 00000 n 0000010085 00000 n 0000010222 00000 n 0000010359 00000 n 0000010496 00000 n 0000010633 00000 n 0000010770 00000 n 0000010907 00000 n 0000011044 00000 n 0000011181 00000 n 0000011318 00000 n 0000011455 00000 n 0000011592 00000 n 0000011729 00000 n 0000011866 00000 n 0000006025 00000 n 0000006372 00000 n 0000005038 00000 n 0000005533 00000 n 0000012003 00000 n 0000015427 00000 n 0000015649 00000 n 0000019447 00000 n 0000019669 00000 n 0000022959 00000 n 0000023170 00000 n 0000027592 00000 n 0000027803 00000 n 0000032123 00000 n 0000032345 00000 n 0000037254 00000 n 0000037476 00000 n 0000041638 00000 n 0000041850 00000 n 0000046053 00000 n 0000046276 00000 n 0000050497 00000 n 0000050720 00000 n 0000054943 00000 n 0000055157 00000 n 0000059422 00000 n 0000059647 00000 n 0000064454 00000 n 0000064721 00000 n 0000064858 00000 n 0000064995 00000 n 0000065132 00000 n 0000065269 00000 n 0000069312 00000 n 0000069537 00000 n 0000072833 00000 n 0000073100 00000 n 0000073237 00000 n 0000073374 00000 n 0000073511 00000 n 0000073648 00000 n 0000076350 00000 n 0000076564 00000 n 0000077924 00000 n 0000078875 00000 n 0000079068 00000 n 0000099074 00000 n 0000099867 00000 n 0000100055 00000 n 0000126693 00000 n 0000127412 00000 n 0000127608 00000 n 0000141088 00000 n 0000141793 00000 n 0000141985 00000 n 0000147998 00000 n 0000148773 00000 n 0000148960 00000 n 0000159735 00000 n 0000160446 00000 n 0000160642 00000 n 0000168057 00000 n 0000168080 00000 n trailer < <48180BF191D93DF5235DE0AEAEFED2C1>]>> startxref 168174 %%EOF ./nsf2.4.0/doc/Persistence-xotcl.html000644 000766 000024 00000021575 13076351162 020254 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/store/Persistence.xotcl

    ./library/store/Persistence.xotcl ./library/store/Persistence.xotcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./library/store/Persistence.xotcl

    Description: Persistent store for XOTcl objects with Eager and Lazy persistence. Take a look at "persistenceExample.xotcl" for example of usage.


    Class: PersistenceMgr

    Class: Class
    Description: A persistent store requires a persistent manager. The persistent manager implements the Storage interface via storage mixin. With the parameter "dbPackage" we can specify which storage will be used. The persistent manager than tries to load the package "xotcl::${dbPackage}Storage". Default is Sdbm. Example:
    	    PersistenceMgr pmgr -persistenceDir . -persistenceFile example-db
    	    


    Class: Persistent

    Class: Class
    Procs/Instprocs: makeVarScript, persistenceMgr, persistent, persistent+init, persistentVars, unPersistent.
    Description: Superclass or mixin class for all persistent objects. Normally subclasses are used as mixins or instmixins on object, like:
    	    o mixin Persistent=Eager
    	    p mixin Persistent=Lazy
    	    

    Instprocs

    • persistenceMgr args
      Arguments: args: persistent manager name
      Description: Specify which persistence manager to use for [self] object, like:
      	    o persistenceMgr pmgr
      	    
      Each persistent object must have a persistence manager specified, before vars can be made persistent.
    • persistentVars
      Description: Returns list of persistent vars.
    • persistent list
      Arguments: list: persistent variables
      Description: Make a list of object variables persistent. If a persistent DB exists, the values are read from this DB, overwriting the current value. E.g.:
      	    o persistent {x y}
      	    
    • persistent+init list
      Arguments: list: persistent variables
      Description: Initialize all data in the list as empty strings, if they do not exist yet, and then make them persistent using the 'persistent' method
    • unPersistent list
      Arguments: list: persistent variables
      Description: Make a list of object variables not persistent.
    • makeVarScript
      Description: Build a Tcl script of "set ..." statements reflecting the current situation in the database.


    Class: Persistent=Eager

    Class: Class
    Description: Eager persistence strategy. Store everything at the same moment to the database


    Class: Persistent=Lazy

    Class: Class
    Description: Lazy persistence strategy. Store everything on object destroy (or program termination).



    Back to index page.

    ./nsf2.4.0/doc/composite-xotcl.html000644 000766 000024 00000002222 12161565464 017764 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/scripts/composite.xotcl

    ./apps/scripts/composite.xotcl ./apps/scripts/composite.xotcl


    Package/File Information

    No package provided/required

    Filename: ./apps/scripts/composite.xotcl

    Description: Simple composite pattern meta-class taken from the paper 'Filters as a Language Support for Design Patterns in Object-Oriented Scripting Languages'.



    Back to index page.

    ./nsf2.4.0/doc/JufGdbmStorage-xotcl.html000644 000766 000024 00000001560 12161565463 020630 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/store/JufGdbmStorage.xotcl

    ./library/store/JufGdbmStorage.xotcl ./library/store/JufGdbmStorage.xotcl


    Package/File Information

    No package provided/required

    Filename: ./library/store/JufGdbmStorage.xotcl




    Back to index page.

    ./nsf2.4.0/doc/xotclsh.man000644 000766 000024 00000002436 13723231517 016127 0ustar00neumannstaff000000 000000 [comment {-*- Tcl -*- xotclsh manpage}] [include version.inc] [manpage_begin xotclsh 1 [vset VERSION]] [copyright {2014 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3.0 Austria license (CC BY 3.0 AT).}] [titledesc {Simple shell containing NSF/XOTcl2 interpreter}] [moddesc {Command-line interface}] [description] [list_begin definitions] [call [syscmd "xotclsh"] [opt [arg fileName]]] [syscmd "xotclsh"] is a shell-like application that reads XOTcl2 and Tcl commands from its standard input or from [arg fileName] and evaluates them. If invoked without [arg fileName], then it runs in REPL mode, reading commands from standard input and printing command results and error messages to standard output. It runs until the exit command is invoked or until it reaches end-of-file on its standard input. [para] [syscmd "xotclsh"] can be used like [syscmd "tclsh"] to make XOTcl2 scripts directly invocable from the shell, by providing the following first line ("shebang") in the respective script: [example { #! /usr/bin/env xotclsh }] A (more portable) alternative is: [example_begin] #! /bin/sh # the next line restarts using xotclsh \ exec xotclsh "$0" "$@" [example_end] [list_end] [manpage_end] ./nsf2.4.0/doc/method.man.inc000644 000766 000024 00000005540 13030507001 016453 0ustar00neumannstaff000000 000000 [comment {-*- tcl -*- manpage fragment for method method, shared by nx::Object and nx::Class}] [call [arg [vset CMD]] [opt "[method public] | [method protected] | [method private]"] [method "[vset MODIFIER] method"] [opt [option -debug]] [opt [option -deprecated]] [arg name] [arg parameters] [opt [option "-checkalways"]] [opt "[option -returns] [arg valueChecker]"] [arg body]] [keywords "value checker"] [keywords "colon-prefix notation"] [keywords "self call"] [keywords "alias method"] Defines a scripted method [arg methodName] for the scope of the [vset SCOPE]. The method becomes part of the [vset SCOPE]'s signature interface. Besides a [arg methodName], the method definition specifies the method [arg parameters] and a method [arg body]. [para] [arg parameters] accepts a Tcl [cmd list] containing an arbitrary number of non-positional and positional parameter definitions. Each parameter definition comprises a parameter name, a parameter-specific [term "value checker"], and parameter options. [para] The [arg body] contains the method implementation as a script block. In this body script, the colon-prefix notation is available to denote an object variable and a [term "self call"]. In addition, the context of the object receiving the method call (i.e., the message) can be accessed (e.g., using [cmd nx::self]) and the call stack can be introspected (e.g., using [cmd nx::current]). [para] Optionally, [option "-returns"] allows for setting a [term "value checker"] on values returned by the method implementation. By setting the [term "switch"] [option "-checkalways"], value checking on arguments and return value is guaranteed to be performed, even if value checking is temporarily disabled; see [cmd nx::configure]). [para] To express deprecation of the method [arg name], set the [option "-deprecated"] flag. Deprecated methods remain usable from client code, but their usage will be signaled to the developer and/or can be tracked using [cmd ::nsf::deprecated]. To register [arg name] with the debugger, set the [option "-debug"] flag. Entering and exiting a method, which was flagged for debugging, is recorded by calling the redefinable callback procs [cmd ::nsf::debug::call] and [cmd ::nsf::debug::exit], respectively. By default, these callbacks forward to [cmd ::nsf::log], which can also be customized at the script level. [para] A method closely resembles a Tcl [cmd proc], but it differs in some important aspects: First, a method can define non-positional parameters and value checkers on arguments. Second, the script implementing the method body can contain object-specific notation and commands (see above). Third, method calls [emph cannot] be intercepted using Tcl [cmd trace]. Note that an existing Tcl [cmd proc] can be registered as an [term "alias method"] with the [vset SCOPE] (see [method "[vset MODIFIER] alias"]). [comment {TODO: refer to nsf::proc?}] ./nsf2.4.0/doc/Announce2.3.0000644 000766 000024 00000015001 13464761731 016020 0ustar00neumannstaff000000 000000 Dear Community, We are pleased to announce the availability of the Next Scripting Framework (NSF) 2.3.0. The changes are mostly perfective improvements in terms of bug fixes, API consistency, and backwards compatibility. See below for the details. Diff stats since 2.2.0: 189 files changed, 17743 insertions(+), 16889 deletions(-) (222 commits) Major changes relative to 2.2.0 are: New Features - NSF: * Reform of "uplevel" and "upvar" methods: - The methods "uplevel" and "upvar" (well as the underlying commands [current callinglevel] and [self callinglevel]) behave now more consistently and more similar to the XOTcl 1 semantics. This eases the migration of XOTcl 1 code. These methods are needed for "frame skipping", i.e. when methods using ":upvar" or ":uplevel" are overlaid with filters/mixin classes but should keep the uplevel semantics without these interceptors. Otherwise, adding a filter/mixin can easily break existing code. - The behavior of uplevel/upvar should be stable now with respect to Tcl's "namespace eval" and similar commands. - Error handling for providing potentially invalid level arguments was fixed. * Rename reform for "nsf::procs": NSF procs can now be safely renamed (or deleted) using the Tcl [rename] command. This was only partially supported before, and could also lead to crashes (when redefining a renamed NSF proc). * New object property "autonamed": NSF objects having been created using "new", rather than using "create", can now be tested for this condition using the object property "autonamed": % package req nx 2.3 % nsf::object::property [nx::Object new] autonamed 1 % nsf::object::property [nx::Object create o] autonamed 0 The property "autonamed" can be used to avoid having to rely on pattern matching of the command names. This is e.g. useful in the NaviServer/AOLserver blueprint management, where temporary objects should be omitted. * Extended object property "volatile": By setting or unsetting the object property "volatile", the volatility of a given NSF object changed dynamically. In previous releases, it was not possible to remove the volatility property of an object. % package req nx 2.3 % ::nx::Object create ::o -volatile ::o # query volatile property % nsf::object::property ::o volatile 1 # modify volatile property % nsf::object::property ::o volatile false 0 - NX: * Properties and variables now provide "exists" as an additional accessor method, in addition to "get": % package req nx 2.3 % nx::Class create C { :property -accessor public {a 1} } ::C % ::C create ::c1 ::c1 % if {[::c1 a exists]} { ::c1 a get } else { ::c1 a set "1" } ^^^^^^ This is mainly to provide for symmetry in the property and variable API, which otherwise requires one to resort to low-level tests for existence, e.g.: if {[::c1 eval {info exists :a}]} ... This breaks the property/ variable abstraction, because one cannot move to a different value store other than object variables w/o rewriting client code. * Fixed method combination for ensemble methods: In previous releases, calling [next] at the end of a next chain in ensemble methods could fire unintentionally the unknown handler. * nx::zip rewrite: nx::zip now uses the built-in Tcl 8.6 encode and decode facilities, if available, rather than requiring the Trf package to be present. - XOTcl: * Improved compatibility of XOTcl2 with XOTcl1 behavior for volatile objects (see "volatile reform" above). * Improved compatibility of XOTcl2 with XOTcl1 behavior for uplevel/upvar from within methods (see "uplevel/ upvar reform" above). - nx::serializer: * Improved backward compatibility: Preserve overriding accessor/ mutators methods (instprocs) for slots. - MongoDB: * Added JSON serializer: The "find all" and "bson" methods now provide for JSON-formatted results, on request. ::nx::mongo::Class "find all" -asJSON ::nx::mongo::Object bson asJSON This is to facilitate implementing single-page JavaScript applications, among others. * Fixed test suite; tested the NSF MongoDB binding against latest stable releases of MongoDB (4.0.9) and MongoDB-C driver (1.14.0). - Documentation: * Added documentation of uplevel and upvar methods. - Maintenance & bug fixes: * VLA reform: Avoid the use of variable-length arrays (VLA) when building argument vectors of Tcl_Objs internally to NSF. Use fixed-sized ones (stack-allocated for a size known at compile time or dynamically allocated above) to prevent from potential overflows and to produce more time-efficient instructions. * Tcl 8.7: Support for Tcl 8.7a1 and the upcoming, unreleased Tcl 8.7a2 (core.tcl-lang.org/tcl branch "core-8-branch"). NSF compiles and its regression tests execute successfully (including TCL_NO_DEPRECATE). * Misc (esp. NSF/C): Ran valgrind checks, plugged one source of potential leaks (NsfProcStubDeleteProc) and one invalid read on a dangling pointer (NsfCCreateMethod). * Test suite: Fix recursion tests on 8.5 (Windows-only, forward.test) for platform-specific error messages (CheckCStack), obsolete for 8.6 with NRE. Guarded test case on recursive forwards, to avoid preemptive crashes on stack-size limited systems. - Build environments: * Microsoft C compilers: Turned off COMDAT folding (/opt:icf) under "nmake" builds which can lead to unusable, pointless function-pointer comparisons (Nsf_ConvertToSwitch vs. Nsf_ConvertToBoolean). * Improve robustness of configure/ make procedure in the absence of generated DTRACE artifacts so that they are truly conditional on the corresponding configure flags for DTRACE. * Improved robustness of Windows (nmake) installation routines by testing for the existence of the install directory. * Rendered inference of GIT commit in autotools setup more robust, in light of partial GIT checkouts (e.g., w/o tags). The detailed changelog is available at https://next-scripting.org/xowiki/download/file/ChangeLog-2.2.0-2.3.0.log The Next Scripting Framework 2.3.0 (containing NX 2.3.0 and XOTcl 2.3.0) can be obtained from https://next-scripting.org/. Please report issues and wishes by opening a ticket at https://sourceforge.net/p/next-scripting/tickets/. Best regards - Gustaf Neumann - Stefan Sobernig./nsf2.4.0/doc/tutorial2.html000644 000766 000024 00000605464 13523544312 016571 0ustar00neumannstaff000000 000000 XOTcl - Tutorial

    XOTcl - Tutorial - Index

    Version: 2.0.0

    Introduction

     
    Language Overview

    XOTcl [Neumann and Zdun 2000a] is a successor of the object-oriented scripting language OTcl [Wetherall and Lindblad 1995] which itself was an early highly flexible object oriented exitension of Tcl [Ousterhout 1990] (Tool Command Language). XOTcl was so far released in more than 30 versions, is described in its detail in more than 20 papers and serves as a basis for TclOO [Donal ???]. XOTcl 2.0 [Neumann and Sobernig 2009] extends the basic ideas of XOTcl 1.0 by providing support for language-oriented programming and makes it easy to host several object oriented languages by a common environment...

    XOTcl runs in the tclsh and provides a few extension commands. These are offered via the Tcl namespaces ::xotcl and ::xotcl2, and can be imported into the current namespace to reduce typing and improve readability. All Tcl commands remain available (and are also applicable on the extension constructs).

    A central property of Tcl is, that it uses strings solely for the representation of data. Internally it uses an dynamic type system with automatic conversion (which enables efficient type handling). For that reason all components (e.g. written in C) once integrated in Tcl automatically fit together and the components can be reused in unpredicted situations without change. The evolving component frameworks provide a high degree of code reuse, rapid application development, and ease of use. The application developer may concentrate on the application task solely, rather than investing efforts in fitting components together. Therefore, in certain applications scripting languages like Tcl are very useful for a fast and high-quality development of software (see [Ousterhout 1998] for more details).

    Tcl is equipped with appropriate functionalities for the easy gluing of components, like dynamic typing, dynamic extensibility, and read/write introspection. OTcl is an object-oriented extension to Tcl, which encourages a Tcl-like programming style and is composed of language constructs with properties similar to Tcl. It offers an object-orientation with encapsulation of data and operation without protection mechanisms and single and multiple inheritance. Furthermore it enables to change the relationships dynamically, offers read/write introspection, has a three level class system based on meta-classes and offers method chaining. These abilities are integrated in XOTcl with only slight changes to OTcl visible to the programmer.

    Extended Object Tcl aims at complexity and adaptability issues that may occur in context of large (object-oriented) software structures and in the context of component glueing. In particular we added the following support:

    • Filters as a means of abstractions over method invocations to implement large program structures, like design patterns.

    • Mixin Classes, as a means to give an object or a classes' instances access to several different supplemental classes, which may be changed dynamically.

    • Dynamic Object Aggregations, to provide dynamic aggregations through nested namespaces.

    • Nested Classes, to reduce the interference of independently developed program structures.

    • Assertions, to reduce the interface and the reliability problems caused by dynamic typing and, therefore, to ease the combination of components.

    • Forwarders, to delegate calls efficiently to other objects or classes.

    • Slots, to manage values of instance variables with a common interface.

    • Meta-data and Automatic Documentation, to enhance self-documentation of objects and classes.


      

    Figure 1: Language Extensions of XOTcl
    new graphic, extension of the features above, history with OTcl, XOTcl1, tcloo and XOTcl2

     
    Introductory Overview Example: Stack

    To give you an impression of the language before we go into the details of the extended language constructs, we present in this section a simple, classical example, familiar to many from introductory programming courses: the Stack example. In the later section, we will present the soccer club example, which focuses more on the dynamic features of the Extended Object Tcl.

    In a first step, we define a class Stack. A new class is defined in XOTcl via the command Class create yourclass. The stack will have a constructor (in XOTcl, the method init) and the methods push and pop. In the following example, all predefined commands (some from Tcl, some from XOTcl) are emphasized.

    #
    # Create a stack class 
    #
    Class create Stack {
            
      :method init {} { # Constructor
        set :things ""
      } 
    
      :method push {thing} {
        set :things [linsert ${:things} 0 $thing] 
        return $thing
      }
      
      :method pop {} {
        set top [lindex ${:things} 0]
        set :things [lrange ${:things} 1 end]
        return $top
      }
    }
    

    The three methods are defined via :method (which means: define a method for the current class). Variables are set with the Tcl command set. Variable names starting with a dot "." are treated as instance variables (variables of an instance of the Stack, i.e. an Stack object). The other variables are scoped to the methods.

    The definition of the class Stack is typically saved in a file (say stack.xotcl) and can be used e.g. in an interactive Tcl shell (tclsh) as follows. The percent sign indicates the prompt of the Tcl shell, the reminder of the line is typed in, the result of the command is shown in the line below. Comments are lines starting with a hash symbol #.

    % package require XOTcl
    % ::xotcl::use xotcl2
    % source stack.xotcl
      
    # Create Object s1 of class Stack
    % Stack create s1
    ::s1
    % s1 push a
    % s1 push b
    b
    % s1 push c
    c
    % s1 pop
    c
    % s1 pop
    b
    # Delete object s1
    s1 destroy
    

    In the session above, we load XOTcl into the current shell, import the names from the xotcl namespace and we load the file stack.xotcl. At this time, the class Stack is available in the scripting session. In the next step, we create an stack object named s1 and push into the stack the values a, b and c via separate push calls. Then we pop values from the stack and we destroy finally the stack s1.

     
    Object specific methods

    The definition of Stack provided above is pretty similar to stack definitions in many other object oriented languages. The next example shows how to define purely object specific behavior. We can define an object stack without the need of a class Stack. Notice that the methods of the object stack are defined exactly the same way as in the previous example with the class Stack. Instead of defining a constructor, we can set the instance variable things directly in the definition block of the object.

    #
    # Create an object named stack
    #
    Object create stack {
    
      set :things ""
    
      :method push {thing} {
        set :things [linsert ${:things} 0 $thing] 
        return $thing
      }
      
      :method pop {} {
        set top [lindex ${:things} 0]
        set :things [lrange ${:things} 1 end]
        return $top
      }
    }
    

    The object stack can be used in exactly the same way as s1 (the instance of class Stack) before.

     
    Refining the behavior of objects and classes

    So far, the definition of stacks were pretty minimal. Suppose, we want to define "safe stacks", that check e.g. for stack underruns (more pop than push operations are issued). Checking safety can be done mostly independent from the implementation details of the stack (usage of internal data structures). With XOTcl, one can define stack-safety as a separate class using methods with the same names as the implementations before, and "mix" this behavior later into classes or objects. The implementation of Safety uses a counter to check for stack underruns.

    #
    # Create a safety class 
    #
    Class create Safety {
            
      :method init {} { # Constructor
        set :count 0
        next
      } 
    
      :method push {thing} {
        incr :count
        next
      }
      
      :method pop {} {
        if {${:count} == 0} then { error "Stack empty!" }
        incr :count -1
        next
      }
    }
    

    When we load the classes Stack and Safety into the same script, we can define e.g. a certain stack s2 as a safe stack, while all other stacks might be still "unsafe". This can be achieved via the option -mixin during object creation.

    % Stack create s2 -mixin Safety
    ::s2
    % s2 push a
    % s2 pop
    a
    % s2 pop
    Stack empty!
    
    Note that the definition of Safety can be used not only for instances of the class Stack, but for arbitrary objects supporting the same interface. We can as well use Safety to create a new class SafeStack. In this case, all instances of SafeStack have the safety property defined above.
    #
    # Create a safe stack class by using Stack and mixin 
    # Safety 
    #
    Class create SafeStack -superclass Stack -mixin Safety
    
    SafeStack create s3
    

     
    Stack of integers

    The definition of Stack is generic and allows all kind of elements to be stacked. Suppose, we want to use the generic stack definition, but a certain stack (say, s4) should allow only stacking of integers. This behavior can be achieved by defining an object specific method for the stack s4 that checks the values to be pushed. In case the pushed value is ok, the push definition of Stack is called via next.

    # 
    # Create a stack with a object-specific method 
    # to check the type of entries 
    #
    # s4 is a stack of integer 
     
    Stack create s4 {
    
      :method  push {value} {
        if  {![string is integer $value]} {
          error "value $value is not an integer"
        }
        next
      }
    
    }
    

     
    Class specific methods

    In extended object Tcl, classes are objects as well (objects with certain properties; we will come to this later in more detail). However, we can define as well methods of classes, which are not inherited to the instances, but which are to be applied on the class object itself. This can be achieved by the modifier object which is placed in front of method. Such methods defined on the class object are actually exactly same as the object specific methods in the example with the object named stack above.

    In the following example, we will define the method available_stacks on the class object, that returns the number of the currently existing stack instances.

    Class create Stack {
    
       # ...
        :class-object method available_stacks {} {
          return [llength [:info instances]]
       }
    }
    
    Stack create s1
    Stack create s2
    
    puts [Stack available_stacks]
    

    The final command puts prints 2 to the console.

     
    Introductory Overview Example: Soccer Club

    In our second example, we will focus on an application example where one can benefit substantially from the dynamic language constructs of XOTcl, the soccer club example (the full code can be found in the xotcl/src/scripts/soccerClub.xotcl file. All the persons and characters in this example are fictitious, and any resemblance to actual persons, living or deceased, is coincidental.

    Before we start, we introduce an instrument for making the documentation of programs more easy. In order to document source code files, we can use the @ object, which is used generally to provide any kind of information, meta-data, and documentation on a running program. Here, we just give a file description. Then the makeDoc.xotcl tool can automatically document the program file later for us.

      @ @File {
        description {
          This is a simple introductory example for the language XOTcl. 
          It demonstrates the basic language constructs on the example of
          a soccer club.
        }
      }
    

    All things and entities in XOTcl are objects. A special kind of objects are classes. Classes define common properties for other objects. For a soccer club, we firstly require a common class for all kinds of members.

    Common to all members is that they have a name. Common properties defined across all instances of a class are called 'parameter' in XOTcl. In this example the instance variable name will be initialized by default with an empty string.

      Class create ClubMember -parameter {{name ""}}
    

    A special club member is a Player. Derived classes can be build with inheritance (specified through superclass). Players may have a playerRole (defaults to NONE).

      Class create Player -superclass ClubMember -parameter {{playerRole NONE}}
    

    Other club member types are trainers, player-trainers, and presidents:

      Class create Trainer -superclass ClubMember
      Class create President -superclass ClubMember
    

    The PlayerTrainer uses multiple inheritances by being both a player and a trainer:

      Class create PlayerTrainer -superclass {Player Trainer}
    

    Now we define the SoccerTeam class:

      Class create SoccerTeam -parameter {name location type}
    

    We may add a player by using method. Methods can be defined in XOTcl2 either by :method in the class creation block, or via "ClassName method ...". The added players (as well as other club members) are aggregated in the object of the soccer team (denoted by :: namespace syntax).

      SoccerTeam method newPlayer args {
        # we create a new player who is part of the soccer team
        # "eval" is needed to pass the provided arguments separately to the call of new
        eval Player new -childof [self] $args
      }
    

    A player can be transferred to another team. The player object does not change internally (e.g. the playerRole stays the same). Therefore we move it to the destination team.

      SoccerTeam method transferPlayer {playername destinationTeam} {
        # We use the aggregation introspection option children in order
        # to get all club members
        foreach player [:info children] {
          # But we only remove matching playernames of type "Player". We do
          # not want to remove another club member type who has the same
          # name.
          if{[$player info has type Player] && [$player name] eq $playername} {
            # We simply 'move' the player object to the destination team.
            # Again we use a unique autoname in the new scope
            $player move ${destinationTeam}::[$destinationTeam autoname player%02d]
          }
        }
      }
    

    Finally we define two convenience to print the members/players to the console with puts.

      SoccerTeam method printMembers {} {
        puts "Members of ${:name}:"
        foreach m [:info children] {puts "  [$m name]"}
      }
      SoccerTeam method printPlayers {} {
        puts "Players of ${:name}:"
        foreach m [:info children] {
          if {[$m info has type Player]} {puts "  [$m name]"}
        }
      }
    

    Now let us build to example soccer team objects.

      SoccerTeam create chelsea -name "Chelsea FC" -location "Chelsea"
      SoccerTeam create bayernMunich -name "F.C. Bayern München" -location "Munich"
    

    With addPlayer we can create new aggregated player objects

    Let us start some years in the past, when "Franz Beckenbauer" was still a player.

      set fb [bayernMunich newPlayer -name "Franz Beckenbauer" -playerRole PLAYER]
    

    playerRole may not take any value. It may either be NONE, PLAYER, or GOALY ... such rules may be given as assertions (here: an instinvar gives an invariant covering all instances of a class). In XOTcl the rules are syntactically identical to if statements:

      Player instinvar {
        {${:playerRole} in [list "NONE" "PLAYER" "GOALY"]}
      }
    

    If we break the invariant and turn assertions checking on, we should get an error message:

      $fb check all
      if {[catch {$fb playerRole SINGER} errMsg]} {
        puts "CAUGHT EXCEPTION: playerRole has either to be NONE, PLAYER, or TRAINER"
        # turn assertion checking off again and reset to PLAYER
        $fb check {}
        $fb playerRole PLAYER
      }
    

    But soccer players may play quite different, orthogonal roles. E.g. Franz Beckenbauer was also a singer (a remarkably bad one). However, we can not simply add such orthogonal, extrinsic extensions with multiple inheritance or delegation. Otherwise we would have either to build a lot of unnecessary helper classes, like PlayerSinger, PlayerTrainerSinger, etc., or we would have to build such helper objects. This either leads to an unwanted combinatorial explosion of class or object number

    Here we can use a per-object mixin, which is a language construct that expresses that a class is used as a role or as an extrinsic extension to an object.

    First we just define the Singer class.

      Class create Singer {
    
        :method sing text {
          puts "${:name} sings: $text, lala."
        }
      }
    

    Now we register this class as a per-object mixin on the player object:

      $fb mixin Singer
    

    And now Franz Beckenbauer is able to sing:

      $fb sing "lali"
    

    But Franz Beckenbauer has already retired. When a player retires, we have an intrinsic change of the classification. He *is* not a player anymore. But still he has the same name, is club member, and is a singer (brrrrrr).

    Before we perform the class change, we extend the Player class to support it. I.e. the playerRole is not valid after class change anymore (we unset the instance variable).

      Player method class args {
        unset :playerRole
        next
      }
    

    Now we can re-class the player object to its new class (now Franz Beckenbauer is President of Bayern Munich.

      $fb class President
      # Check that the playerRole isn't there anymore.
      if {[catch {$fb playerRole} errMsg]} {
        puts "CAUGHT EXCEPTION: The player role doesn't exist anymore \
             (as it should be after the class change)"
      }
    

    But still Franz Beckenbauer can entertain us with what he believes is singing:

      $fb sing "lali"
    

    Now we define some new players for Bayern Munich:

      bayernMunich newPlayer -name "Oliver Kahn" -playerRole GOALY
      bayernMunich newPlayer -name "Giovanne Elber" -playerRole PLAYER
    

    If we enlist the players of Munich Franz Beckenbauer is not enlisted anymore:

      bayernMunich printPlayers
    

    But as a president he still appears in the list of members:

      bayernMunich printMembers
    

    Now consider an orthonogal extension of a transfer list. Every transfer in the system should be notified. But since the transfer list is orthogonal to SoccerTeams we do not want to interfere with the existing implementation at all. Moreover, the targeted kind of extension has also to work on all subclasses of SoccerTeam. Firstly, we just create the extension as an ordinary class:

      Class TransferObserver {
        :method transferPlayer {pname destinationTeam} {
          puts "Player '$pname' is transferred to Team '[$destinationTeam name]'"
          next
        }
      }
    

    Now we can apply the class as a per-class mixin, which functions exactly like a per-object mixin, but on all instances of a class and its subclasses. The next primitive ensures that the original method on SoccerTeam is called after notifying the transfer (with puts to stdout):

      SoccerTeam mixin TransferObserver
    

    If we perform a transfer of one of the players, he is moved to the new club and the transfer is reported to the stdout:

      bayernMunich transferPlayer "Giovanne Elber" chelsea
    

    Finally we verify the transfer by printing the players:

      chelsea printPlayers
      bayernMunich printPlayers
    



    Object and Class System

    In XOTcl every object is associated with its managing class by a relationship called class. Classes are special objects with the purpose of managing other objects. "Managing" means that a class controls the creation and destruction of its instances and that it contains a repository of methods accessible for the instances.

    Since a class is a special (managing) kind of object it is managed itself by a special class called a "meta-class" (which manages itself). Meta-Classes are used to define classes and to provides methods for these. Most classes are defined by the predefined meta-class Class. One interesting aspect of meta-classes is that by providing a constructor pre-configured classes can be derived. Meta-classes can be used to instantiate large program structures, like some design patterns (see [Neumann and Zdun 1999a] for more details), where the meta-class may holds the generic parts of the structures. Since a meta-class is an entity of the program, it is possible to collect these entities in pattern libraries for later reuse easily (more details about meta-classes are given in a later section).

    The methods common to all objects in the XOTcl 2 object system are defined in the root class Object (fully qualified name ::xotcl2::Object). All methods can be predefined (defined by XOTcl) or user-defined. All objects of XOTcl 2 are either direct instances of Object or instances of subclasses of Object.

    The most basic meta-class is Class (fully qualified name ::xotcl2::Class). All classes of XOTcl 2 are either direct instances of Class or instances of subclasses of Class. Since - as noted before - a class is a special kind of object, Class is a subclass of Object. Therefore, all methods available in all classes are the union of the methods of Object and Class (see Figure 2a).

    Figure 2a: Basic Classes of the XOTcl2 object system

    When we create an application class such as the class Stack in the examples above, we create it as instance of the basic meta-class ::xotcl2::Class. The application class will have ::xotcl2::Object as it superclass, unless we spefify this differently. When we create an instance of the class Stack (such as e.g. the stack s1) we create it by using the method create provided by ::xotcl2::Class (an instance can use the methods provided by its class).

    Figure 2b: Application class Stack and instance of Stack together with the Basic Classes of the XOTcl2 object system

    XOTcl supports single and multiple inheritance. Classes are ordered by the relationship superclass in a directed acyclic graph. The root of the class hierarchy is the class Object. Note that it is possible to create as well objects from this most general class; we have done this already above by creating an object named stack.

    A classical problem of multiple inheritance is the problem of name resolution, when for example two super-classes contain an instance method with the same name. XOTcl provides an intuitive and unambiguous approach for name resolution by defining the precedence order along a linear "next-path" incorporating the class and mixin hierarchies. A method can invoke explicitly the shadowed methods by the predefined command next. When next is executed a shadowed method is invoked. The execution of the shadowed methods is called "method chaining". Method chaining without explicit naming of the targeted method is very important for languages supporting a dynamic class system, because one cannot always predict which classes are currently participating in the inheritance hierarchy at design time (often necessary in inheritance models, like C++).

    An important feature of all XOTcl objects is the read/write introspection. The reading introspection abilities of XOTcl are packed compactly into the info instance method which is available for objects and classes. All obtained information can be changed at run-time dynamically with immediate effect. Unlike languages with a static class concept, XOTcl supports dynamic class/superclass relationships. At any time the class graph may be changed entirely using the superclass method, or an object may change its class through the class method. This feature can be used for an implementation of a life-cycle or other intrinsic changes of object properties (in contrast to extrinsic properties e.g. modeled through roles and implemented through per-object and per-class mixins [Neumann and Zdun 1999c] ) . These changes can be achieved without losing the object's identity, its inner state, and its per-object behavior (methods and mixins).

    xotcl2 changes until here, reminder is missing;

      

    Figure 2b: Object and Class System

    Basic Functionalities

     
    Objects

    at least the first paragraph has to be rewritten; "2 commands" don't really hold

    Initially XOTcl offers two new commands: Object and Class. They represent hooks to the features of the language. This section discusses both of them in detail and shows how they function in the context of XOTcl. Note that even if most of this is compatible to OTcl, a few changes occur. For this reason, this section is no introduction to plain OTcl. The Object command provides access to the Object class, which holds the common features of all objects, and allows us to define new objects. Objects are always instances of classes, therefore, objects defined with the Object command are (initially) instances of the Object class. But since they have no user-defined type, they may be referred to as singular objects. As all other objects they may be specialized by object-operations and -data.

    The object command has the following syntax:

      Object objName ?args?
    

    A command of this form is a short-cut for a message to the create instance method (forwarded automatically by the unknown mechanism, which is invoked every time the message dispatch system discovers an unknown message):

      Object create objName ?args?
    

    It creates a new object of type Object with the name objName (in fact it invokes a create call on the Object class). objName becomes a new command, which allows us to access the created object. Similar to the Object command it may be used like a normal Tcl-command (using sub-commands to access the object's methods). Therefore, this form of access is called object-command approach. A simple example is an object which holds the information of a kitchen. It is created by:

      Object kitchen
    

    An object creation calls the constructor init of the object's class. The destruction of an object is handled by the destroy instance method. The general syntax of destroy is:

      objName destroy
    

    E.g. the kitchen object is destroyed by:

      kitchen destroy
    

    To invoke a user-defined destruction process, it is possible to overload this instance method in every class derived from object.

    Note that the destruction of an object is performed by the method destroy of Object (since every object is an instance of Object, every object can call destroy). When an application class overloads destroy, this method should contain a next in order to reach the base class and to actually destroy the object.

    Data on Objects

    The Object class provides a range of operations to manage objects, including those to manipulate data-structures on the objects. They are similar to the same-named Tcl-commands:

      objName set varname ?value?
      objName unset v1 ?v2 ... vn?
    

    The set instance method with given value option allows us to manipulate an object-variable's value or to create a new one, if the variable varname does not exist on the object so far. Without value option the set operation queries the variable and returns it's value, if the variable exists, otherwise it produces an error message. The unset operation deletes one or optionally a set of variables from an object. For example the kitchen object can store information on the color of the wall-paper by:

      kitchen set wallPaperColor white
    

    Similar to Tcl-variables the object variables are dynamical; they may be set at run-time when they are needed and unset when they become obsolete. E.g. the persons in the kitchen may be stored in an array. If there are no persons in the kitchen the array is deleted:

      # Peter enters the kitchen to cook
      kitchen set persons(cook) Peter
      ...
      # Marion enters the kitchen to take one of the seats
      kitchen set persons(seat1) Marion 
      ...
      # Both Peter and Marion leave the kitchen
      # the array is deleted by unset
      kitchen unset persons
    

    Since XOTcl variables are internally realized through Tcl-variables they may be treated like all Tcl-variables. For that reason they have all Tcl-variable abilities, including the possibility to handle them as lists or arrays (as seen in the last example). The array command of Tcl is mapped to an XOTcl-command directly. An object-oriented call to an object of the form

      objName array option arrayName args
    

    forwards its arguments to an array Tcl-command for the object´s instance variable arrayName. It could be used like the same-named Tcl-command, e.g. the command

      kitchen array names persons
    

    returns all indexes currently stored in the persons array.

    Similarly Tcl´s incr command is mapped to the object system. A call with the syntax:

      objName incr varName ?value?
    

    increments varName with the given value (or without given value with 1).

    Methods for Objects

    Methods in XOTcl resemble Tcl-procedures. On objects one can define object-specific methods, called procs. Instance methods which are defined on classes are called instprocs. A new proc is defined using the proc instance method of the class Object:

      objName proc name args body
    

    The arguments of the proc instance method specify the name, the arguments as a Tcl-list, and the body of the new proc. All of them must be given, only one of args and body may be empty. An example proc would be a method to let persons enter the kitchen:

      kitchen proc enter {name} {
        [self] set persons($name) [clock seconds]
      }
    

    Here the predefined self command is used in one of three possible ways, which allow us to access useful information when working with XOTcl-methods, these are in particular:

    • self: returns the name of the object, which is currently in execution. This command is similar to this in C++. It is automatically generated on each object. If it is called from outside of an XOTcl method, it produces the error message "Can't find self".

    • self class: the self command with the argument class returns the name of the class, which holds the currently executing instproc. Note that this may be different to the class of the current object. If it is called from a proc it returns an empty string.

    • self proc: the self command with the argument proc returns the name of the currently executing method (proc or instproc).

    The method enter can be written in XOTcl as well with less syntactic overhead by using the predefined primitive my instead of [self]:

      kitchen proc enter {name} {
        my set persons($name) [clock seconds]
      }
    

    Note that there is a difference to the realization of these object information to OTcl. XOTcl uses commands in order to make XOTcl-methods compatible to Tcl-procedures and accessible via namespace-paths. OTcl uses the three variables self, class and proc, which are filled automatically with proper values by the interpreter each time a method is called. To gain backwards compatibility XOTcl can be compiled with -DAUTOVARS to provide these variables additionally. By default this option is turned off.

    Each XOTcl-method has its own scope for definition of local variables for the executing method. In most cases when a method uses object-variables, it is likely that the programmer wants to make one or more of these variables part of the method's scope. Then the Tcl-command for variable handling, like set, lindex, array, ... work also on these variables. The instvar instance method links a variable to the scope of an executing method. It has the syntax:

      objName instvar v1 ?v2 ... vn?
    

    It makes the variables v1 ... vn, which must be variables of the object, part of the current method's scope. A special syntax is:

      objName instvar {varName aliasName} ...
    

    for one of the variables. This gives the variable with the name varName the alias aliasName. This way the variables can be linked to the methods scope, even if a variable with that name already exists in the scope. Now the enter method can be adapted slightly and a leave method can be added, which uses Tcl's info command to check whether the named person is in the object's persons array. To demonstrate the alias-syntax this is done with the persons array and the alias p.

      kitchen proc enter {name} {
        my instvar persons
        set persons($name) [clock seconds]
      }
    
      kitchen proc leave {name} {
        my instvar {persons p}
        if {[info exists p($name)]} {
          puts "$name leaves after [expr {[clock seconds]-$p($name)}] seconds" 
          unset p($name) 
        } else {
          puts "$name is not in the room"
        }
      }
    
    A method defined via proc can be deleted by proc using an empty argument list and an empty body. The following example deletes the method enter:
      Room proc enter {} {}
    

    Information about Objects

    XOTcl offers reading and writing introspection. The reading introspection abilities are packed compactly into the info instance method which is available for objects and classes (there are special info options for object aggregations, nested classes, mixins, filters, meta-data and assertions, which are explained separately in the following sections).

    Options for the info method on objects

    objName info args methodName

    Returns the arguments of the specified proc (object specific method).

    objName info body methodName

    Returns the body of the specified proc.

    objName info class ?className?

    Returns the name of the class of the current object, if className was not specified. Otherwise it returns 1 if className matches the object's class and 0 if not.

    objName info commands ?pattern?

    Returns all commands defined on the object if pattern was not specified. Otherwise it returns all commands that match the pattern.

    objName info default methodName arg var

    Returns 1 if the argument arg of the specified proc has a default value, otherwise 0. If the default value exists it is stored in var.

    objName info precedence ?pattern?

    Returns all classes in the precedence order from which the specified object inherits methods. The returned list of classes contains the mixin and instmixin classes as well as the classes of the superclass chain in linearized order (i.e., duplicate classes are removed). If the pattern is specified, only matching classes are returned.

    objName info vars ?pattern?

    Returns all variables defined on the object if pattern was not specified, otherwise it returns all variables that match the pattern.


    For example on the kitchen object

      kitchen info procs
    

    returns enter and leave as a Tcl-list since these are the procs defined on the object.

    Classes

    Creating Classes and deriving Instances

    There are different ways to create a class in XOTcl. They have in common that they derive the new class from a meta-class. Initially the Class command provides access to the meta-class Class, which holds the features common to all classes. It also allows one to derive new meta-classes. The common way to create a new class is:

      Class className ?args?
    

    Similar to the object short form, this is a short form of a call to the create instance method of the meta-class Class, which is also executed by the standard unknown mechanism. This mechanism is always triggered when XOTcl does not know a method called on an object. Supposed that there is no method with the name className, defined on the class-object of Class, XOTcl looks up the method unknown (which is found on the Class Object) and executes it. The standard unknown-mechanism of XOTcl calls create with all arguments stepping one step to the right; in the general case:

      Class create className ?args?
    

    This may also be called directly. Besides the indirection when using unknown, in most cases there is no difference in the action performed: Firstly the memory is allocated, using the alloc instance method; as the next step the constructor init is called on the creating object, which is in this case the class-object of the meta-class Class. In seldom cases the programmer may want to suppress the init call. To do so the alloc instance method may also be called directly:

      Class alloc className ?args?
    

    As seen in the preceding section objects are created in the same way. The difference was, that the command Object, which accesses a class, instead of the command Class, which accesses a meta-class, was used. The user-defined classes may also be used in the same way to create new objects:

      className objName ?args?
    

    Resembling the creation of classes this creates an object objName of type className using the unknown mechanism. That means the create instance method of the class is called. If there is no other instance method defined on the class-path so far (which would mean, an user defined creation process is invoked), the create instance method of the class Object is invoked. This method is similar to the create method of the meta-class Class. It firstly calls the alloc instance method on its (of the Class class) which allocates memory for the object, and makes it an instance of it's class. Afterwards a call to the constructor init is invoked.

    Now we can specify the object for the kitchen by the class to which it belongs. In this case a kitchen is an instance of a room.

      Class Room
      Room kitchen
    

    A set call on a class creates an instance variable on the class-object. This variable is unique for all instances, therefore, it may be referred to as a class variable.

    Methods Defined in Classes

    Methods which are defined in classes and which are provided to the instances of these classes are called "instprocs". The syntax for defining an instproc is:

      className instproc procname args body
    

    It is similar to the definition of procs on objects, but uses the keyword instproc to distinguish between the methods defined on the class-object and those defined on the class. Since all rooms (in the modeled world) have ceilings, we may want to define a simple convenience instproc, which is able to set the color:

      Room instproc setCeilingColor color {
        my set ceilingColor $color
      }
    

    A special instproc, the constructor init, was mentioned already. Now we are able to define such an instproc. Defined on a class it is responsible for all initialization tasks, which needed to be performed, when constructing a new instance object of the class. The constructor of the Room can initialize a variable for the color, in which the ceiling is painted, to white as default, since this is the color of ceilings without painting.

      Room instproc init args {
        my setCeilingColor white
        next
      }
    

    After this definition, all instances derived from the Room class have an instance variable ceilingColor with the value white. The args argument used here is a special argument in Tcl which allows us to use a list of arguments which may change its length from call to call.

    An instproc can be deleted by the method instproc as well. If instproc is called with an empty argument list and an empty body, the specified method is deleted, as the following example shows:

      Room instproc setCeilingColor {} {}
    

    Information about Classes

    Resembling to objects, information on classes may be gained through the info instance method of the meta-class Class. Note that this instance method does not only support the class info options, but also the class-object info options, since the accessing command refers to the class-object, which itself is an object and, therefore, offers its information. The following table summarizes the additional info options available on classes.

    Options for the info method on classes

    className info heritage ?pattern?

    Returns a list of all classes in the precedence order of the class hierarchy matching pattern or a list of all classes, if pattern was not specified.

    className info instances ?pattern?

    Returns a list of the instances of the class matching pattern or of all instances, if pattern was not specified.

    className info instargs methodName

    Returns the arguments of the specified instproc (method provided to objects).

    className info instbody methodName

    Returns the body of the specified instproc.

    className info instcommands ?pattern?

    Returns all commands defined on the class, if pattern was not specified, otherwise it returns all commands provided to objects that match the pattern.

    className info instdefault methodName arg var

    Returns 1 if the argument arg of the specified instproc has a default value, otherwise 0. If the default value exists it is stored in var.

    className info subclass ?className2?

    Returns a list of all subclasses of the class, if className2 was not specified, otherwise it returns 1 if className2 is a subclass and 0 if not.

    className info superclass ?className2?

    Returns a list of all super-classes of the class, if className2 was not specified, otherwise it returns 1 if className2 is a superclass and 0 if not.

    The full list of info options is provided in the language reference.

    Inheritance

    Besides encapsulation of operations and state in objects, a second central ability of object-orientation is inheritance. XOTcl supports single and multiple inheritance with a directed acyclic class graph. Automatically each new class created by the instance methods create and alloc of Class inherits from Object. Therefore, it is ensured that all instances of the new class have access to the common features of objects stored in the class Object.

    To specify further inheritance relationships the instance methods superclass of Class is used:

      className -superclass classList
    

    E.g. in the example a kitchen may be seen as a special room:

      Class Room
      Class Kitchen -superclass Room
    

    Now all instances of Kitchen are able to access the methods provided by the Room and the Kitchen classes. Note the transition the kitchen was going through: firstly it was a singular object, then it was an object with a user-defined class, and now it is a class. This is possible because we can provide a per-object behavior, and because classes are a special kind of objects. Both properties of XOTcl's object system lead to a seamless connection of the run-time behavior of objects and the descriptive properties of the classes. It is possible to avoid the strict distinction between objects and classes, known from static typed languages, like C++, Java, etc.

    Moreover, since the syntaxes of constructs expressing the same concern are nearly identical, we can re-factor a solution with very few changes to the alternative. We will see similar "ease of refactoring" throughout the XOTcl language. E.g., we can also easily re-factor the class hierarchies or exchange class hierarchies against mixin solutions with only slight changes in the code.

    Besides single inheritance, as seen, XOTcl provides also multiple inheritance. This is syntactically solved by giving the superclass instance method a list of classes instead of a single class as argument.

      Class Room
      Class 4WallsRoom -superclass Room
      Class CookingPlace
      Class Kitchen -superclass {4WallsRoom CookingPlace}
    

    Now the kitchen class is specialized a bit more. It is a special room which has four walls and it is a cooking place. Multiple inheritance, as seen here, is as simple to apply as single inheritance.

    Most often when the disadvantages of multiple inheritance are discussed, the name resolution along the class graph is considered as the biggest problem. The question is, which method is to be chosen and which path through class graph is to be taken, if more then one method of the specified name exist on the class graph.

    In the example such questions would arise for an object of the Kitchen class, if two same-named methods are defined on CookingPlace and 4WallsRoom or if a method of the class Object is called, which is reachable through two paths (along CookingPlace or Room).

    Often - e.g. in the inheritance model of C++ - the path through the graph is not clearly determined and/or the rules are too complicated to be understood on the first glance. The programmer often can only determine by trial which method is found firstly. Than an explicit naming of the class is necessary, which means storage of non-local information in subclasses. Often different compilers of one language behave differently. All these issues make code reuse difficult. Moreover understandability and portability are reduced.


    Figure 3: The example classes and the following next-path


    XOTcl goes an intuitive and unambiguous way to solve this problem. It resolutes the precedence order along a ``next-path''. Firstly the class of the object is searched, which is Kitchen in example. Then the super-classes are searched in definition order, which means at first 4WallsRoom, then CookingPlace. Each branch is searched completely, before changing to the next branch. That means, Room is searched, before the CookingPlace branch is visited. At last the top of the hierarchy, the class Object, is searched.

    The usage of next in XOTcl is different to OTcl: In OTcl, next is defined as a method, in XOTcl it is a primitive command. Furthermore, in OTcl, it is always necessary to provide the full argument list for every invocation explicitly. In XOTcl, a call of next without arguments can be used to call the shadowed methods with the same arguments (which is the most common case). When arguments should be changed for the shadowed methods, they must be provided explicitly in XOTcl as well. In the rare case that the shadowed method should receive no argument, the flag --noArgs must be used.

    Destruction of Classes

    Classes are destroyed by the destruction of the class-object using the destroy method of the Object class. The destruction of super-classes does not destroy the subclasses. The super-class is simply removed from the subclasses' super-class lists. All classes have the super-class Object, if no super-class is specified. Therefore, if all super-classes are destroyed or removed, the new super-class is Object, not: no super-class. The destruction of the class of an object does neither delete the object nor leave it without class. In XOTcl a deleted class leaves it's instances with the class Object.

    So all empty class- and superclass-relationships are automatically reset to Object. Note that this are differences to OTcl, where the destruction of a class destroys all instances and an empty super-class list remains empty.

    Method Chaining

    A special feature of XOTcl is the method chaining without explicit naming of the ``mix-in''-method. It allows one to mix the same-named superclass methods into the current method (modeled after CLOS). The previously described next-path is the basis for this functionality. At the point marked by a call to the next primitive of XOTcl the next shadowed method on the next path is searched and, when it is found, it is mixed into the execution of the current method. When no method is found, the call of next returns an empty string, otherwise it returns the result of the called method. The syntax is:

      next ?arguments|--noArgs?
    

    As stated earlier the usage of next in XOTcl differs from OTcl, since the next call without arguments in OTcl means per default that no arguments are passed. But most often all arguments are passed through to the shadowed methods (since these will most likely have the same signatures). When all variables should be passed through, in OTcl it is necessary for correct variable substitution to use:

      eval $self next $args
    

    To avoid such difficulties, we made the passing of all arguments the default case; a simple

      next
    

    performs the task of passing all arguments to the shadowed methods. These arguments are called the standard arguments. If the standard argument feature should not be used, optionally arguments can be given or the flag --noArgs could be set as sole argument, which means that the shadowed method is called with no arguments.

    E.g. the following next call ignores the standard arguments and sends the arguments 1 and 2 instead:

      next 1 2
    

    As an example all classes involved in the previous example should get a constructor instance method, which simply sets an instance variable on the object:

      Room instproc init args {
        my set roomNumber 0
        next
      }    
      4WallsRoom instproc init args {
        my set doorPosition 0
        next
      }
      CookingPlace instproc init args {
        my set stoveType electric
        next
      }
      Kitchen instproc init args {
        my set cookName -
        next
      }
    

    After creation an object of class Kitchen gets automatically four instance variables cookName, roomNumber, doorPosition and stoveType set up with default values in this order (since this is the order of the classes in the next-path). Note that the order is important, because one missing next call, in one of the init methods, means that succeeding init methods will not be executed. This mechanism functions equally on all kinds of instprocs, not only on constructors.

    The constructors use the args argument, which allows us to give a list of variable length as arguments. To ensure reusability of our classes the constructors should use args in most cases, since they may pass through arguments for constructors further up the class hierarchy.

    If a proc with the searched name exists on the object it shadows all instprocs. A next call in a proc leads to the normal next-paths search, starting with the object's class.

    By the way, an observant reader might notice that the example above can be rewritten without explicit constructors, just by using parameters with default values.

      Class Room -parameter {{roomNumber 0}}
      Class 4WallsRoom -superclass Room -parameter {{doorPosition 0}}
      Class CookingPlace -parameter {{stoveType electric}}
      Class Kitchen -superclass {4WallsRoom CookingPlace} -parameter {{cookName -}}
    

    If an instance of a Kitchen is created it will contain instance variables for doorPosition, cookName, roomNumber, and stoveType, as the following statements will show.

      Kitchen k
      puts [k info vars]
    

    Dynamic Class and Superclass Relationships

    Another property of XOTcl that distinguishes it from statically typed languages are dynamics of class relationships. The realization of the definition of super-classes as seen above with the superclass method suggests already, that it is not only available at the class definition time. In the above example its appended to the class definition with "-superclass" as a short syntax for method invocation at definition time (all other available methods can also be called with a preceding dash ("-") appended to definitions).

    At any time the class graph may be changed entirely using the superclass method. Suppose the rooms and kitchens created in modeling of a house should be displayed to a screen, but it is not determined, whether the user of the system has the possibilities for graphical outputs. Two classes TextOutput and GraphicalOutput may be defined, which handle the output. Both have an instproc paint which does the painting of the virtual world on the chosen display type. The common output requirements are handled by a derived class VirtualWorldOutput which calls the paint method of the superclass using next. In statically typed languages it would need more sophisticated constructs to change the output class at run-time. E.g. a delegation to another object handling the intrinsic task of the output object would be introduced solely for the purpose of configuring the output form. With a dynamic class system we can use the superclass method to do so easily:

      Class TextOutput
      TextOutput instproc paint args {
        # do the painting ...
      }
      Class GraphicalOutput
      GraphicalOutput instproc paint args {
        # do the painting ...
      }
    
      # initially we use textual output
      Class VirtualWorldOutput -superclass TextOutput
      VirtualWorldOutput instproc paint args {
        # do the common computations for painting ...
        next; # and call the actual output
      }
    
      # user decides to change to graphical output
      VirtualWorldOutput superclass GraphicalOutput
    

    Sometimes, such a change to new intrinsic properties should not happen for all instances of a class (or the class hierarchy), but only for one specific object. Then the usage of a dynamic super-class relationship is a too coarse-grained means. A second form of such dynamics is the changing of the relationship between object and class. This means, objects can also change their class dynamically at run-time. This feature may be used to model a life-cycle of an object, without losing the object's identity, inner state or per-object-specializations through procs. The class instance method enables this functionality.

    An example would be an agent for the virtual world. Agents may be placeholders for persons, who interactively travel the world, or programs, which act automatically. When a person decides at run-time to give a task it has performed formerly by hand to an automatic agent, the agents nature changes from interactive agent to automatic agent, but the identity and the local state (that means the parts of the task, that are already fulfilled by the person) stay the same. This is a scenario for changing class relationships, e.g.:

      Class Agent
      Class AutomaticAgent -superclass Agent
      Class InteractiveAgent -superclass Agent
    
      # create a new agent for a person
      InteractiveAgent agent1
    
      # the person does something ...
      # and decides the change to an automatic agent
      agent1 class AutomaticAgent
    

    Meta-Classes

    Meta-classes are a special kind of classes. Similar as classes are managing objects (where managing means: control the creation and destruction of instances, know what instances exist, provide methods), meta-classes are managing classes. So, meta-classes are used to define classes. In other words, every Class in XOTcl is created by a meta-class, in most cases by the meta-class named Class. New user-defined meta-classes can be defined as subclasses of the predefined meta-class Class, or by adding an instmixin class (see below) containing Class to the precedence chain of the class. By defining Object instmixin Class one can even change the object system of XOTclin a way such that every created Object is a meta-class.

    Since the concept of a meta-class are sometimes confusing to people of a background of some other programming languages, we explain meta-classes slowly with the analogy of classes and objects.

    When a class Foo is created via the command

       Class Foo
    
    it has no private variables and no special methods. This is somewhat similar as creating an object via Object:
       Object foo
    
    This plain object foo can be configured directly, or one can create a class that configures the object. Instead of writing
       Object foo 
       foo set x 1
       foo proc hi {} {puts "hello"}
    
    one can use
       Class C -superclass Object
       C instproc init {} {my set x 1}
       C instproc hi {} {puts "hello"}
    
    and create an instance and call the method.
       C c1
       c1 hi
    
    The same holds for meta-classes and classes as well: Instead of writing
       Class Foo
       Foo set x 1
       Foo proc hi {} {puts "hello"}
    
    the following can be used:
       Class MC -superclass Class
       MC instproc init {} {my set x 1}
       MC instproc hi {} {puts "hello"}
    
    The instances of meta-classes are classes which can be defined the usual way:
       MC Bar
       Bar hi
       Bar b1
    
    Now we have a class names Bar which has a class-scoped variable named x with the value of 1 (set via the constructor); the class Bar has as well a class-method named hi which prints, when called, the string "hello". The class Bar can be used to create instances of the class like b1, b2 and so on.

    Note that the command Class is a predefined definition of the most general meta-class in XOTcl. Each time we are creating a class, we use this meta-class. In order to define a specialized meta-class, we can do this the traditional object-oriented way: we subclass. Therefore, in to define a specialized meta-class, we can use:

      Class myMetaClass -superclass Class
    

    This defines a new meta-class myMetaClass, which has all the abilities of meta-classes. That means that the programmer is able to specify new class features or override old ones. Later she/he may instantiate these into new classes.

    This is a very powerful language feature, since it allows one to give some classes further abilities than the others (or to restrict classes). This way large program structures, like certain design pattern parts, may be instantiated. Meta-classes hold the common abstract parts of the structures. They allow one to form libraries of such structures very easily.

    Example 1: Overloading the info method of classes

    As a simple example we can derive a new meta-class NoClassInfo from Class. Later we override the info method of Class. Thus the classes created with NoClassInfo, have an info option that only produces an error message. All classes created with NoClassInfo, like Agent in the example below, are not capable of accessing the class info method anymore:

      Class NoClassInfo -superclass Class
      # redefine info ability
      NoClassInfo instproc info args {
        error "No class info lookup"
      }
      # derive agent class from meta-class, which
      # can not access class info
      NoClassInfo Agent
    
    Now a call like:
      Agent info superclass
    

    triggers the error message.

    Example 2: Defining Classes that Count Their Instances

    Meta-classes are frequently used to define some bookkeeping about the number of instances on the class level. In the following example we define a meta-class named CountedClass which defines classes that count their instances:

      Class CountedClass -superclass Class -parameter {{counter 0}}
      CountedClass instproc create args {
        my incr counter
        next
      }
      CountedClass instproc dealloc args {
        my incr counter -1
        next
      }
      CountedClass Dog
    
      Dog piffie
      Dog idefix
      puts "nr of dogs: [Dog counter]"
    
      piffie destroy
      puts "nr of dogs: [Dog counter]"
    
    Note that the behavior introduced by meta-classes can be orthogonal to the behavior of the classes. One can define Dog as a specialization of Animal or defines a special kind of dog such as Poodle using the method superclass as usual.

    Example 3: The Singleton Meta-Class

    Finally, a small example, which is more practical. Some applications have the requirement that only one instance of a class might be defined at a certain time. Such a behavior is frequently called a "Singleton". In XOTcl we can define a class singleton by overloading the create method of Class: when create is called and there exists already an instance of the singleton it is returned instead of a new instance.

      Class Singleton -superclass Class
      Singleton instproc create args {
        expr {[my exists instance] ? [my set instance] : [my set instance [next]]}
      }
    
    If someone wants to have a class e.g. Manager to be a singleton, you can create it by e.g.
      Singleton Manager -superclass FOO
    

    Create, Destroy, and Recreate Methods

    XOTcl allows since version 0.84 for a flexible destroy and recreate scheme. create and alloc are both Class instprocs handling creation for their instances. I.e.:

     className alloc [self]
    
    and
     className create [self]
    

    are used for creating an instance. A similar method dealloc exists on Class that handles physical destruction of an object. The method destroy on Object which lets an object destroy itself in fact has the following behavior:

      Object instproc destroy args {
       [my info class] dealloc [self]
      }
    

    However, this behavior is not implemented in XOTcl, but in C. create distinguishes between the following situations:

    • Create a new object: By default create calls alloc and then doInitializations.
    • Recreate an existing object: When the specified object exists, it is recreated through the recreate method:
        givenClass recreate [self]
      

      The method recreate can be customized like all other XOTcl methods (e.g. by overloading or interception). By default recreate calls cleanup followed by doInitializations.

      Note that recreate is not called, when a someone tries to recreate a class as an object or an object as a class. In these cases, destroy + create are used.

          Class c
          Object c ;# here, "c" is downgraded to an object, no "recreate" is called
      

    For create and recreate, the method doInitializations is called automatically from C and has the following default behavior:

    • Search for parameter default values,
    • Call parameter initialization methods,
    • Call the constructor init.

    Each step has a method call that can be changed, intercepted, etc. Of course, cleanup, recreate, dealloc, etc. can also be overloaded or intercepted.

    Consider a typical case for overloading recreate: a structure preserving recreate that cleans up the class but preserves the existing class hierarchy (subclass and instance relationships):

      Class StructurePreservingRecreate
      StructurePreservingRecreate instproc recreate {cl args} {
        if {[my isclass $cl]} {
          set subclass [$cl info subclass]
          set instances [$cl info instances]
        }
        next
        if {[my isclass $cl]} {
          foreach sc $subclass {
            $sc superclass $cl
          }
          foreach i $instances {
            $i class $cl
          }
        }
      }
      Object instmixin add StructurePreservingRecreate
    

    Now the following code does not change the superclass or instance relationships of C:

      Class A
      Class B
      Class C -superclass {A B}
      Class D
      Class E -superclass {C D}
      C c1
      C c2
    
      # recreate -> is structure preserving
      Class C -superclass {A B}
      C c2
    
      # test
      puts superclass=[C info superclass]
      puts subclass=[C info subclass]
      puts instances=[C info instances]
      puts class=[c1 info class]
      puts class=[c2 info class]
    
    Starting with XOTcl 1.4.0, xotcl provides also a user-friendly way for a structure-prevering recreate implemented in C. Since this version, one can configure "softrecreate" as follow.
    ::xotcl::configure softrecreate true
    
    This command causes that recreates are structure-conservative.

    Methods with Non-Positional Arguments

    So far we have introduced methods only with positional arguments: that is, the position of an argument in the argument list determines to which local variable the argument is bound, when the method is invoked. Sometimes non-positional arguments -- arguments that carry both a name and a value when the method is invoked -- are useful. Before a non-positional argument can be used, it must be defined in the method definition using the following syntax:

     className instproc methodName ?non-pos-args? args body ?assertions
     objName proc methodName ?non-pos-args? args body ?assertions
    

    The non-positional arguments are defined with the following syntax:

     {-name?:checkoption1, checkoption2, ...? default value} \
         {-name?:checkoption1, checkoption2, ...? ?default value?} ...
    

    Only the name of the non-positional argument is really required, all other parts of this syntax are optional.

    Let's consider a simple example, where a method with two non-positional args is defined; one has only a name ("a"), and one has a name and a default value (b):

     Object o
     o proc someproc {-a {-b {1 2 3}} x y} {
         puts "$a $b $x $y"
     }
    

    We can invoke this method as follows:

     o someproc -b {4 5} -a 1 3 4
    

    Here, the order of a and b can be changed; hence the name non-positional arguments. As b has a default value, we do not need to provide a value for it. In the following invocation b has the value "1 2 3":

     o someproc -a 1 3 4
    

    The ordinary arguments start after the last non-positional argument (here: "3 4"). We can explicitly end the non-positional arguments by using "--". This is useful if we want to provide arguments that contain dashes ("-"), e.g.:

     o someproc -a 1 -- -b -c
    

    Sometimes we want to check or control the non-positional arguments. For instance, in the above invocation, we might want to check that a is not forgotten, because otherwise the method cannot execute properly. This is the role of the checkoptions. There are three predefined checkoptions: required, boolean and switch. required checks whether a non-positional argument is given, boolean checks that a non-positional argument is of boolean type. For instance:

     Class P
     P instproc someproc {-a:required {-b:boolean true}} {
         puts "$a $b"
     }
     P p
    

    This method requires a, and b needs to be of type boolean (is has the default value true). This invocation is valid:

     p someproc -a 1 -b 0
    

    This invocation is invalid, because a is missing, and b is not a Tcl boolean type:

     p someproc -b " a b v"
    

    The checkoption switch is similar to boolean except it does not require an additional argument. If the default value is false, the switch can be turned on, if the default is true it can be switched off.

    The checkoptions are extensible. In fact, they are defined in an object ::xotcl::nonposArgs. We can extend this object with new methods. A check option method has the following syntax:

     someobject|someclass proc|instproc methodName {?optional nonpositional arguments? argName arg} {
      ...
     }
    

    argName is here used to denote the name of the argument, and arg is the provided value.

    Of course, the non-positional arguments can also be introspected. The following info options return the non-positional arguments of a method:

     objName info nonposargs methodName
     className info instnonposargs methodName
    

    Message Interception Techniques

    Even though object-orientation orders program structures around data, objects are characterized primarily by their behavior. Object-oriented programming style encourages the access of encapsulated data only through the methods of an object, since this enables data abstractions. A method invocation can be interpreted as a message exchange between the calling and the called object. Therefore, objects are at runtime only traceable through their message exchanges. At this point the message interceptors can be applied to catch and manipulate all incoming and outgoing messages of an object.

    Generally interceptors can be applied to attach additional or extrinsic concerns to an object or a class or a class hierarchy. For instance roles or aspects can be implemented this way on various levels of scale.

    We have already discussed some interception techniques implicitly. E.g., the unknown mechanism intercepts messages that have not be found on the object. It can be used as a very useful programming technique, e.g., the define a default behavior for an object. The interceptors presented in this section have a different character: They are applied before/after the original method even if the method is defined for the target object. Thus these interception techniques may be applied

    We will discuss the message interceptors in this section in detail. The table below gives an impression, when which interceptor may be applied.

    Message Interceptors Overview

    Applied When

    Primary Target Structure

    Coverage

    Per-Object Filter

    before/after a call

    object hierarchies

    all methods

    Per-Class Filter

    before/after a call

    class and class hierarchies

    all methods

    Per-Object Mixin

    before/after a call

    object

    specific methods

    Per-Class Mixin

    before/after a call

    class and class hierarchies

    specific methods

    Unknown Mechanism

    after method was not found

    object

    all unknown calls


    Filter

    The filter (see [Neumann and Zdun 1999a] for more details) is a language construct to implement broader extensional concerns either for a single object or for several classes or class hierarchies. This way large program structures at the scale of several classes or class hierarchies can be managed. It is a very general interception mechanism which can be used in various application areas. E.g. a very powerful programming language support for certain design patterns is easily achievable, but there are also several other domains which are covered, like tracing of program structures, self-documentation at run-time, re-interpretation of the running program, etc.

    A per-class filter is a special instance method that is registered for a class C. A per-object filter is a special instance method that is registered for a object o. Every time an object of class, C or the object o respectively, receives a message, the filter method is invoked automatically.

    Usage of Filters

    All messages to a filtered object must go through the filter before they reach their destination object. A simple example would be a sole filter on the class of the object. To define such a filter two steps are necessary. Firstly a filter method has to be defined, then the filter has to be registered. The filter method consists of three parts which are all optional. A filter method has the following form:

      className instproc FilterName args {
        pre-part
        next
        post-part
      }
    

    When a filter comes to execution at first the actions in the pre-part are processed. The filter is free in what it does with the message. Especially it can (a) pass the message, which was perhaps modified in the pre-part, to other filters and finally to the object. It can (b) redirect it to another destination. Or it can (c) decide to handle the message on its own. The forward passing of messages is implemented through the next primitive of XOTcl. After the filter has passed its pre-part, the actual called method is invoked through next.

    After the call of next is processed, the execution returns to the point in the filter, where the next call is located and resumes execution with the actions of the post-part. These may contain arbitrary statements, but especially may take the result of the actual called method (which is returned by the next-call) and modify it. The caller then receives the result of the filter, instead of the result of the actual called method.

    The pre- and post-part may be filled with any ordinary XOTcl-statements. The distinction between the three parts is just a naming convention for explanation purposes.

    The filter uses the args argument which lets us use a list of variable length as arguments, since it must filter a lot of different calls, which may have different argument lists. Furthermore, it may pass through arguments to other filters and the preceding filters may change the argument list.

    Since any proc/instproc may be a filter, a registration of the filter is necessary, in order to tell XOTcl, which instprocs are filters on which classes. The filter and instfilter instance methods are able to handle this task for per-object filters and per-class filters respectively. Similar to the XOTcl language introduced so far, the filter registration is dynamic at run-time. By supplying a new list of filters to filter/instfilter, the programmer can change the filters registered on a class at arbitrary times. The filter instance method has the syntax:

      className instfilter filterList
    
    for per-class filters and:
      objName filter filterList
    
    for per-object filters.

    Now a simple example should show the filter's usage. In the preceding examples we have defined several rooms. Every time a room action occurs it is likely that the graphical sub-system has to change something on the output of that particular room. Therefore, at first we need a facility to be informed every time an action on a room happens. This is quite easily done using filters:

      Class Room
      Room r1; Room r2;       # just two test objects
    
      Room instproc roomObservationFilter args {
        puts "now a room action begins"
        set result [next]
        puts "now a room action ends - Result: $result"
        return $result
      }
    
      Room instfilter roomObservationFilter
    

    Now every action performed on room objects is notified with a pre- and a post-message to the standard output stream. We return the result of the actual called method, since we don't want to change the program behavior at all. E.g. we can set an instance variable on both of the two room objects:

      r1 set name "room 1"
      r2 set name "room 2"
    

    The output would be:

      now a room action begins
      now a room action ends - Result: room 1
      now a room action begins
      now a room action ends - Result: room 2
    


      

    Figure 4: Cascaded Message Filtering



    All classes may have more than one filter. In fact they may have a whole filter chain, where the filters are cascaded through next. The next method is responsible for the forwarding of messages to the remaining filters in the chain one by one till all pre-parts are executed. Then the actual method is executed and then the post-parts come to turn. If one next-call is omitted the chain ends in this filter method. As an example for an additional filter we may register a filter that just counts the calls to rooms.

      Room set callCounter 0;  # set class variable
      Room instproc counterFilter args {
        [self class] instvar callCounter
        incr callCounter
        puts "the call number callCounter to a room object"
        next
      }
      Room instfilter {roomObservationFilter counterFilter}
    

    Filters are invoked in registration order. The order may be changed by removing them and adding them in new order. Filters are inherited by subclasses. E.g. in the preceding example for the next path, an OvalOffice was derived from the Room class. Without a change to the program each OvalOffice object automatically produces the same filter output as rooms.


      

    Figure 5: Filter Inheritance


    Filter chains can also be combined through (multiple) inheritance using the next method. When the filter chain of the object's class is passed, the filter chains of the superclasses are invoked using the same precedence order as for inheritance. Since on the subclass there may also be a another filter chain, without sophisticated computing in the pre- and post-parts one can produce easily a powerful tracing facility. E.g. if we want to distinguish an OvalOffice from other rooms we may want to add a filter solely for rooms of the type OvalOffice:

      Class OvalOffice -superclass Room
      OvalOffice o1;  # test object
      OvalOffice instproc ovalOfficeObservationFilter args {
        puts "actions in an oval office"
        next
      }
      OvalOffice instfilter ovalOfficeObservationFilter
    

    A simple call to the o1 object, like:

      o1 set location "Washington"
    

    produces the following output:

      actions in an oval office
      now a room action begins
      the call number 3 to a room object
      now a room action ends - Result: Washington
    

    As seen already, filter registrations can be added dynamically at runtime. But they may also be removed. Perhaps the counting on rooms should stop after a while, then a simple call of the instfilter method is sufficient:

      Room instfilter roomObservationFilter
    

    Filters can be removed completely by giving an empty list to the registration method:

      Room instfilter {}
    

    Per-object filters operate on a single object. E.g. if we only want to observe a single Room object room1, we can use the filter method to register the roomObservationFilter only for this particular instance:

      room1 filter roomObservationFilter
    

    As a filter we can register any method in the precedence order of the class or object. Thus we can also register procs as per-object filters. Additionally, meta-class methods may be registered as per-class filters. Filters are linearized so that each filter is only executed once, even if it is registered multiple times.



    Introspection on Filters

    In order to gain information about the currently registered filters on a certain object/class, the class-object info option filters and the class info option instfilters may be queried. It returns a list of the currently registered filters:

      className info instfilter
      objName info filter
    

    A special call-stack info option for filters is self filterreg. It returns the name of the object or class on which the filter is registered. Since the filter may be registered on other objects/classes than the one on which it is defined, this may vary from self class in the filter. The command returns a list of the form:

      objName filter filterName
    
    or:
      className instfilter filterName
    
    respectively.



    Example: A Simple Trace Filter

    The trace example primarily demonstrates the inheritance of filter chains. Since all classes inherit from Object, a filter on this class is applied on all messages to objects. The Trace object encapsulates methods for managing the tracing:

      Object Trace
      Trace set traceStream stdout
    
      Trace proc openTraceFile name {
        my set traceStream [open $name w]
      }
    
      Trace proc closeTraceFile {} {
        close $Trace::traceStream
        my set traceStream stdout
      }
    
      Trace proc puts line {
        puts $Trace::traceStream $line
      }
    
      Trace proc add className {
        $className instfilter [concat [$className info filter] traceFilter]
      }
    

    First we define the object and set a variable for the stream to which we send the trace outputs (here: stdout). With a method for opening and a method for closing a file we can redirect the trace stream to a file. puts is helper method for the filter to print an output to the selected output stream. In add the traceFilter is appended to the existing filters of a specified class. The actual filter method (see below) displays the calls and exits of methods with an according message. The calls are supplied with the arguments, the exit traces contain the result values. We have to avoid the tracing of the trace methods explicitly.

      Object instproc traceFilter args {
        # don't trace the Trace object
        if {[string equal [self] ::Trace]} {return [next]}
        set context "[self class]->[self callingproc]"
        set method [self calledproc]
        switch -- $method {
          proc -
          instproc {::set dargs [list [lindex $args 0] [lindex $args 1] ...] }
          default  {::set dargs $args }
        }
        Trace::puts "CALL $context>  [self]->$method $dargs"
        set result [next]
        Trace::puts "EXIT $context>  [self]->$method ($result)"
        return $result
      }
    

    As trace message we write the callee´s context (class and proc), the invoked method (using calledproc), and the given arguments. In the switch statement we avoid to print whole method bodies.

    With

      Trace add Room
    

    messages to all rooms, including all instances of Room´s subclasses, are surrounded with a CALL and an EXIT output. With

      Trace add Object
    

    messages to all objects in an XOTcl environment are surrounded with a CALL and an EXIT output. In general, it is possible to restrict the trace to instances of certain classes, or to produce trace output for only certain methods. This requires registration methods and a more sophisticated implementation of the filter method.



    Mixin Classes

    Per-object and per-class mixins (see [Neumann and Zdun 1999c] for more details) are another interception technique of XOTcl to handle complex data-structures dynamically. Here, we use mixin as a short form for mixin class. All methods which are mixed into the execution of the current method, by method chaining or through a mixin class, are called mixin methods. Mixin classes resembles the filter presented in the preceding section. While the filters work on all calls to all methods of an object/class hierarchy, the mixin classes are applied on specific methods. The filter is defined in a single method, while the mixin is composes several method in a class.

    Supplemental Classes

    Mixin classes cover a problem which is not solvable elegantly just by the method chaining, introduced so far. To bring in an addition to a class, the normal XOTcl way is to define a mixin method and chain the methods through next, e.g.:

      Class Basic
      Basic instproc someProc  {
        # do the basic computations
      }
      Class Addition
      Addition instproc someProc {
        # do the additional computations
        next
      }
    

    In order to mix-in the additional functionality of the supplemental class Addition a new helper class (sometimes called intersection class) has to be defined, like:

      Basic+Addition -superclass {Addition Basic}
    

    This is even applicable in a dynamical manner, every object of the class Basic may be changed to class Basic+Addition at arbitrary times, e.g.:

      Basic basicObj
      ...
      basicObj class Basic+Addition
    

    Now consider a situation with two addition classes. Then following set of classes has to be defined to cover all possible combinations:

      Class Basic
      Class Addition1
      Class Addition2
      Class Basic+Addition1 -superclass {Addition1 Basic}
      Class Basic+Addition2 -superclass {Addition2 Basic}
      Class Basic+Addition1+Addition2 -superclass {Addition2 Addition1 Basic}
    

    The number of necessary helper classes rises exponential. For n additions, 2n-1 (or their permutations if order matters) artificially constructed helper-classes are needed to provide all combinations of additional mix-in functionality. Furthermore it is possible that the number of additions is unlimited, since the additions may produce other additions as side-effects. This demonstrates clearly that the subclass mechanism provides only a poor mechanism for mix-in of orthogonal functionality. Therefore we provide an extension in the form of class-object mixin classes, which are added in front of the search precedence of classes.

    Per-Object Mixins

    The mix-ins methods extend the next-path of shadowed methods. Therefore, per-object mix-in methods use the next primitive to access the next shadowed method. Consider the following example:

      Class Agent
      Agent instproc move {x y} { 
        # do the movement
      }
      Class InteractiveAgent -superclass Agent
      # Addition-Classes
      Class MovementLog
      MovementLog instproc move {x y} { 
        # movement logging
        next
      }
      Class MovementTest
      MovementTest instproc move {x y} {
        # movement testing
        next
      }
    

    An agent class is defined, which allows agents to move around. Some of the agents may need logging of the movements, some need a testing of the movements, and some both (perhaps only for a while). These functionalities are achieved through the additional classes, which we will apply through per-object mixins.

    Before we can use the per-object mix-ins on a particular object, we must register the mixins on it with the mixin instance method. It has the syntax:

      objName mixin mixinList
    

    For example we may create two interactive agents, where one is logged and one is tested:

      InteractiveAgent i1; InteractiveAgent i2
      i1 mixin MovementLog
      i2 mixin MovementTest
    

    At arbitrary times the mixins can be changed dynamically. For example i2's movements can also be logged:

      i2 mixin MovementTest MovementLog
    


      

    Figure 6: Per-Object Mix-ins: Next-Path for the Example



    The mixin option of the info instance method allows us to introspect the per-object mixins. It has the syntax:

      objName info mixin ?pattern?
    

    It returns the list of all mix-ins of the object, if pattern is not specified, otherwise it returns the matching per class-object mixin classes.

    The inverse operation of info mixin is mixinof finds out, into which objects a per-object mixin class is mixed into.
      clsName info mixinof ?pattern?
    

    Note that the constructors (init methods) of per-object mixins (and per-class mixins) are only called, if the mixin is registered already during object initialization (when init is called). For per-object mixins, one can achieve the initialization of a mixin via an idiom like

      Object o -mixin M -init
    
    that registers the mixin before init is called. When a mixin is registered after object creation and it needs initializations, it is necessary to define special methods for this. Note that the behavior described here is introduced in version 0.84 to ensure consistent behavior of intrinsic classes, per-object and per-class mixins, and to achieve predictable behavior for dynamic registration for all kind of mixins, and as well during recreations of objects having mixins registered. Older versions used heuristics for the initialization of per-object mixins.

    Per-Class Mixins

    Per-class mixins are exactly identical in their behavior to per-object mixins, but they operate on classes. Thus they are the class-specific variant of the per-object mixins, like instprocs are a class-specific variant of procs. Therefore, in the language the per-class mixins are called instmixins.

    In general a per-class mixin is a class which is mixed into the precedence order of all instances of the class and all its subclasses it is registered for. It is also searched before the object's class itself is searched, but after per-object mixins.

    Per-class mixins are linearized according to the precedence order like classes on the superclass hierarchy. I.e. from the full list of per-object mixins, per-class mixins, and intrinsic classes (and all the superclasses of all these classes) always the last occurrence is used.

    From the point of view of language expressibility instmixins are not required, because they cannot express anything that per-object mixins cannot express already (like procs can express any instproc feature). As alternative to instmixins, we could simply register the per-object mixins in the constructor of the class.

    But there at least the following reasons for instmixins as an additional language construct:

    1. we can at runtime determine with info mixin and info instmixin whether it is a class- or object-specific mixin. Thus we get a better structuring at runtime.
    2. We have not to 'pollute' the constructors with per-class mixin registrations. Therefore, the constructors get more understandable.
    3. If it is required to add (and remove) dynamically interceptors to a set of objects, which are instances of a certain type, per-class mixins are much easier to handle (e.g. add an instmixin to Object to intercept e.g. all calls to certain predefined methods).
    4. The language is more 'symmetrical', since any object-specific feature in XOTcl has a class-specific variant.

    The mix-ins methods of per-class mixins extend the next-path of shadowed methods in the same way as per-object mixin methods. Before we can use a per-class mix-in on a particular class, we must register the mixin on it with the instmixin instance method. It has the syntax:

      className instmixin mixinList
    
    The inverse operation of info inmixin is instmixinof finds out, into which objects a per-object mixin class is mixed into.
      className info instmixinof ?-closure? ?pattern?
    

    Now consider that in the given per-object mixin example all interactive agents should be tested. We could either build a subclass TestedInteractiveAgent or register the per-object mixin in the constructor of the interactive agent class. The subclass solution leads to the same combinatorial explosion of intersection classes as discussed in the previous section, if more supplemental classes are added. The per-object mixin solution pollutes the constructor and does not prevail the structural semantics that the 'tested' property belongs to the interactive agent class at runtime

    Here, we can use a per-class mixin:

      Class Agent
      Agent instproc move {x y} {# do the movement}
      Class InteractiveAgent -superclass Agent
      Class MovementTest
      MovementTest instproc move {x y} {
        # movement testing
        next
      }
    
      # now register the instmixin
      InteractiveAgent instmixin MovementTest
    
    

    The per-class mixin now operates on all interactive agent including the instances of subclasses. E.g. for interactive agents i1 and i2 we automatically have movement testing. i2 is also logged, since it has the logging class as object-specific mixin:

      InteractiveAgent i1
      InteractiveAgent i2 -mixin MovementLog
    
      i1 move 3 4
      i2 move 1 2 
    

    At arbitrary times the instmixins can be changed dynamically.

    The instmixin option of the class info instance method allows us to introspect the per-class mixins. It has the syntax:

      className info instmixin ?className2?
    

    It returns the list of all instmixins of the class, if className2 is not specified, otherwise it returns 1, if className2 is a mixin of the object, or 0 if not.

    Per-class mixins are applied transitively. That means the per-class mixin A of a per-class mixin B is also applied for an objectin B's scope. This is exactly the same as how superclasses are applied for instances. Consider the following example

      Class X11 \
         -instproc test args {
    	puts [self class]
    	next
         }
      Class X12 \
        -instproc test args {
    	puts [self class]
    	next
        }
      Class X \
        -instmixin {X11 X12} \
        -instproc test args {
    	puts [self class]
    	next
        }
    
      Class Y \
        -instmixin X
    
      Y create y -test
      X create x -test
    

    Here the application as a superclass (for x) yields the same result as the application as an instmixin (for y):

      ::X11 
      ::X12 
      ::X
    

    Precedence Order

    The precedence order is composed by the precedence order of the superclass hierarchy (as explained earlier) and the message interceptors. In general, filters precede mixins and the superclass hierarchy. They are applied in the order of the next path of the object. Thus per-object filters are ordered before per-class filters.

    Mixins are processed after the filters. Again, they are applied in the order of the next path of the object. Thus per-object mixins are ordered before per-class mixins.

    Finally, the object's own heritage order comes in the order: object, class, superclasses.

    The three precedence order lists (filters, mixins, and classes) are pre-calculated and cached.

    Filters as well as classes (mixins and ordinary classes) are linearized. That means, each filter and each class can be only once on a precedence order list. If a filter or class can be reached more than once, than the last occurrence is used.

    For instance, consider a class A is superclass, per-class mixin, and per-object mixin. On the precedence order lists only the last occurrence as a superclass is used after linearization.

    Guards for Filters and Mixins

    Message interceptors, such as filters and mixins, are applied for potentially huge number of messages. In many cases it is possible to reduce the effective number of cases in which interceptors are applied. Interceptor guards offer this functionality: they are boolean conditions with which you can specify in which cases a registered interceptor should be applied.

    Filter Guards

    A filter guard is a set of conditions that determine whether a filter is to be executed upon a certain invocation or not. Syntactically we can append a filter guard to the filter registration, or it can be registered using the methods filterguard for filters and instfilterguard for instfilters.

    Each filter guard is an ordinary condition. A filter guard is executed in the call frame of the filter to be executed, if the filter guard returns 1. Thus, the call-stack information are already set to the values of the targeted filter - and these values can be used in the filter guard.

    Let us consider a simple program:

    Class Room
    Room instproc enter {name} {puts [self proc]}
    Room instproc leave {name} {puts [self proc]}
    Room instproc loggingFilter args {
        puts [self calledproc]
        next
    }
    Room instfilter loggingFilter
    

    Now consider we only want to apply the logging filter for enter and leave, not for any other message sent to Room instances. In the following example, for instance, we do not want to log the set message:

    Room r 
    r enter Uwe
    r leave Uwe
    r set roomName "Office"
    

    In this example a filterguard can be applied to restrict the application of the filter to those two methods:

    Room instfilterguard loggingFilter {
      [self calledproc] == "enter" || 
      [self calledproc] == "leave"}
    

    Here we limit the filter application of the logging filter on rooms to calls to enter and leave. All other calls are not filtered at all. Note that the same syntax can also be applied for filterguard. Also, there is a short form to register filter guards directly during filter registration. The following code has the same semantics as the filter and filter guard definitions above:

    Room instfilter {{loggingFilter -guard {
        [self calledproc] == "enter" || 
        [self calledproc] == "leave"}}}
    

    The filter guard language construct is registration centric. It only applies for the class or object on which a filter is registered, not for all applications of the filter method. That is, if we use loggingFilter on another class we may give no or completely different filter guards.

    If no filter guard is given for a filter, we assume that it is to be applied on all methods (equivalent to the filter guard '1' which is always true).

    There are introspection options for filter guards. In particular, we can use info filterguard and info instfilterguard for getting the filter guards for a particular filter or instfilter respectively. For instance:

    puts [Room info instfilterguard loggingFilter]
    

    This prints out the content of the above guard definition. We can also append -guard to info filter or info instfilter to obtain a filter definition with guards:

    puts [Room info instfilter -guards]
    

    If we call a method from within a filter guard, as for instance callsMethod, we might require some parameters from the guard's context, such as calledproc. These parameters can be passed as references, as in the following example:

      Room instfilter loggingFilter
      Room instfilterguard loggingFilter {[my callsMethod openURL [self calledproc]]}
    

    This example works because the filterguard is already set to the scope of the guard. Now we can use this dynamic calledproc context in the called method:

      Room instproc callsMethod {method calledproc} {
        return[string match $calledproc $method]
      }
    

    We simply check whether the called method matches the given method name or not.

    Mixin Guards

    Similar to filters, there are mixin guards, defined with mixinguard and instmixinguard, or with -guard during mixin registration. Consider a simple example: there are a number of birds who have two mixins: Fly and Sing. For Fly there are limitations: a bird can only fly if it is at least two years old and is not a Penguin. Such problems are be solved with mixin guards:

      Class Fly
      Fly instproc fly {} {puts "[my signature]: yippee, fly like an eagle!"}
    
      Class Sing
      Sing instproc sing {} {puts "[my signature]: what a difference a day makes"}
    
      Class Animal -parameter age
      Animal instproc unknown args { puts "[my signature]: how should I $args?"}
      Animal instproc signature {} {
        return "[self] [my info class] ([my age] years)"
      }
    
      Class Bird -superclass Animal
      Class Penguine -superclass Bird
      Class Parrot -superclass Bird
      Class Duck -superclass Bird
    
      Parrot tweedy -age 1
      Penguine pingo -age 5
      Duck donald -age 4
      Parrot lora -age 6
    
      Bird instmixin {{Fly -guard {[my age] > 2 && ![my istype Penguine]}} Sing}
    

    An invocation like:

    foreach bird {tweedy pingo donald lora} { $bird fly }
    

    yields the following result:

    ::tweedy ::Parrot (1 years): how should I fly?
    ::pingo ::Penguine (5 years): how should I fly?
    ::donald ::Duck (4 years): yippee, fly like an eagle!
    ::lora ::Parrot (6 years): yippee, fly like an eagle!
    

    There are similar introspection options for mixin guards as those for filter guards. In particular, we can use info mixinguard and info instmixinguard for getting the mixin guards for a particular mixin or instmixin respectively.

    Querying, Setting, Altering Filter and Mixin Lists

    The methods mixin, instmixin, filter and instfilter are system slots having the same query and update interface.
    • If one of those methods is called without argument, it returns the current setting.
    • If it is called with one argument, the argument is used to set the specified list as indicated in the above examples.
    • If these methods are called with more than one argument, the first argument is used to specify the action. Possible values for the action are set, get, add and delete. See below for commonly used examples.

    obj mixin same as: obj info mixin
    obj mixin {C1 C2} same as: obj mixin assign {C1 C2}
    obj mixin assign {C1 C2}sets the mixins for obj
    obj mixin add C3 adds the mixin C3 on front of the mixin list
    obj mixin add C3 end adds the mixin C3 at the end the mixin list
    obj mixin add C3 3 adds the mixin C3 at the 3rd position
    obj mixin delete ::C3removes the mixin C3 from the mixin list. Use absolute class names. delete supports an optional flag -nocomplain that does not produce an error, when the specified class is not in the list.

    Note that the list of possible actions can be extended by extending the class ::xotcl::Relations.

    Querying Call-stack Information

    Since the presented interceptors are normal XOTcl instprocs they can access all XOTcl introspection abilities introduced so far. In instprocs all recent information is accessible within their scope. But the interceptors are mechanisms, which cover more then their sole scope. The meaningful usage of the meta-programming abilities often requires to go further and to get information from the caller's and the callee's scope (e.g. for delegation decisions). Therefore, we introduced rich call-stack information for the interceptors. Note that these are also available for ordinary methods, but the "called..." info options return empty strings.

    All call-stack information are packed compactly into the self primitive as additional options. Note, before XOTcl version 0.84 these were implemented as a part of the info method. They are part of the self command for conceptual integrity: introspection options in info can be expected to produce the same result, when they are not explicitly changed. In contrast, all information provided by self are call-stack dependent.

    Querying Call-stack Information via self

    self activelevel

    Returns the stack level from where the current command was invoked from, or where the last next was called (whatever is closer to the invocation). If the current command was invoked from an XOTcl method the absolute level is returned (e.g. #4) which can be used in the uplevel or upvar Tcl command or XOTcl method. If the current command was not invoked from an XOTcl method, the value 1 is returned.

    self calledproc

    Returns the name of the method which was invoked in the original call.

    self calledclass

    Returns the name of the class which presumably (if no dynamic class change occurs afterwards) is invoked in the original call.

    self callingclass

    Returns the name of the class from which the call was invoked (if one exists, otherwise an empty string).

    self callinglevel

    Returns the stack level from where the current command was invoked from. In contrary to activelevel next-calls are ignored in the computation. If the current command was invoked from an XOTcl method the absolute level is returned (e.g. #4) which can be used in the uplevel or upvar Tcl command or XOTcl method. If the current command was not invoked from an XOTcl method, the value 1 is returned.

    self callingproc

    Returns the name of the method from which the call was invoked (if one exists, otherwise an empty string).

    self callingobject

    Returns the name of the object from which the call was invoked (if one exists, otherwise an empty string).

    self filterreg

    In a filter: returns the name of the object/class on which the filter is registered. Returns either 'objName filter filterName' or 'className instfilter filterName'.

    self isnextcall

    Return 1 if this method was invoked via next, otherwise 0

    self next

    Return the "next" method on the path as a string, i.e. the method which will be called by [next].


    Note that three options with the prefix calling represent the values of self, self proc, and self class in the scope where the original call was invoked. In the following section we will show a simple program in which all of the info options have different values.


    Filter Call-stack Information Example

    Now we discuss a simple example that shows that all filter introspection options may have different values:

      Class InfoTrace
      InfoTrace instproc infoTraceFilter args { 
        puts "SELF:                [self]"
        puts "SELF PROC:           [self proc]"
        puts "SELF CLASS:          [self class]"
        puts "INFO CLASS:          [my info class]"
        puts "CALLED PROC:         [self calledproc]"
        puts "CALLING PROC:        [self callingproc]"
        puts "CALLING OBJECT:      [self callingobject]"
        puts "CALLING CLASS:       [self callingclass]"
        puts "REGISTRATION CLASS:  [self filterreg]"
        puts "CALLING LEVEL:       [self callinglevel]"
        puts "ACTIVE LEVEL:        [self activelevel]"
        next
      }
    
      Class CallingObjectsClass
      CallingObjectsClass callingObject
    
      Class FilterRegClass -superclass InfoTrace
      Class FilteredObjectsClass -superclass FilterRegClass 
      FilteredObjectsClass  filteredObject 
    
      CallingObjectsClass instproc callingProc args {
         filteredObject set someVar 0
      }    
      FilterRegClass instfilter infoTraceFilter

    The invocation of callingObject callingProc produces the following output:

      SELF:                ::filteredObject
      SELF PROC:           infoTraceFilter
      SELF CLASS:          ::InfoTrace
      INFO CLASS:          ::FilteredObjectsClass
      CALLED PROC:         set
      CALLING PROC:        callingProc
      CALLING OBJECT:      ::callingObject
      CALLING CLASS:       ::CallingObjectsClass
      REGISTRATION CLASS:  ::FilterRegClass instfilter infoTraceFilter
      CALLING LEVEL:       #1
      ACTIVE LEVEL:        #1

    The filter reports for self the value filteredObject, since this is the object on which the set call is invoked; infoTraceFilter is the method of the filter, and therefore, the actual proc, while the actual class is InfoTrace, the filter's class. The class of the actual object is FilteredObjectsClass.

    The called procedure is set. While the program stays in a XOTcl-instproc all calling-info-options are set, the calling procedure is callingProc, the calling class is the class, where the method is defined (namely CallingObjectsClass), and the object from which the call invoked is callingObject.

    In this example, the calling level is equal to the active level, both are #1.

    Slots

    A slot is a meta-object that manages property-changes of objects. A property is either an attribute or a role in an relation. In a nutshell, a slot has among other attributes:

    • a name (which it used to access it),
    • a domain (object or class on which it can be used) , and
    • can be multivalued or not.

    We distinguish between system slots (predefined slots like class, superclass, mixin, instmixin, filter, instfilter) and attribute slots (e.g. attributes of classes).

    System Slots

    System slots are predefined slots defining e.g. some relations between classes, or between objects and classes. The predefined system slots are:

    • superclass: every class in XOTcl has one or more superclasses. The name of this slot is superclass, the domain is ::xotcl::Class, the slot is multivalued, since one object might have multiple superclasses.

    • class: every object has a class; therefore, the domain of the slot is ::xotcl::Class, the property is not multivalued.

    • mixin: every object in XOTcl can have one or more mixin classes. The name of this slot is mixin, the domain is ::xotcl::Object , the slot is multivalued.

    • instmixin: same as above, but the domain is ::xotcl::Class.

    • filter, instfilter: similar to mixin and instmixin.

    The system slots were introduced earlier with their semantics. Here we just point out, that they have all the same interfaces for querying, setting, adding and removing of slot values.

    Every slot can be used set and query the property from its domain. The syntax for setting values is

      object property newValue
    
    and for getting its values is
       set x [object property]
    
    where property denotes the slot name. Every multivalued slot provides the methods add and delete. Here are a few examples for using the system slot mixin which we have introduced already in the section of the mixins
      Object o; Class M; Class N
      o mixin ::M      ;# replacing the per-object mixins of o with M
      o mixin reset ::M  ;# same as before
      o mixin add ::N   ;# add N to the front of the mixin list
      o mixin delete ::M ;# delete M from the mixin list
      puts [o mixin]   ;# query the current mixin list
    
    Every system slot (e.g. superclass) has the exact same interface.

    Attribute Slots

    Attribute slots are used to manage the setting and querying of instance variables. We define now a person with three attributes name, salary and projects.

      Class Person -slots {
        Attribute name
        Attribute salary -default 0
        Attribute projects -default {} -multivalued true
      }
    

    These attributes might have a default value or they might be multivalued. When an instance of class Person is created, the slot names can be used for specifying values for the slots.

      Person p1 -name "Joe"	
    

    Object p1 has three instance variables, namely name, salary and projects. Since slot projects is multivalued, we can add a value to the list of values the add subcommand.

      Project project1 -name XOTcl \
         -description "A highly flexible OO scripting language"
    
      p1 projects add ::project1
      p1 projects add some-other-value
    

    The value of the instance variable project of Person p1 is now the list {some-other-value ::project1}.

    Attribute slots are implemented via dynamic object aggregations (see below), where the Class objects contain the slot objects with the information like default etc. In order to prevent name clashes between the slot objects and the methods of a class (like e.g. create), an intermediary object named slot is used as a container of the slot objects. In the example above we create an object structure of the following form:

      Person
      Person slot name
      Person slot salary
      Person slot projects
    

    This object structure can be used to query and modify the slot properties or to add additional methods to the slot objects. One application is for example to used slot-specific methods for checking slot values, as shown in the next section.

      Person info vars  ;# results in the list of variables of ::Person
      Person slot name info vars ;# list of variables of the slot object ::Person::slot::name
    
    Since slot objects are ordinary XOTcl objects, they can have their own slots as well (such as default, name etc.). The following example sets and queries the default of the slot name of Person:

      Person slot name default "gustaf"
      ? {Person slot name default} gustaf
    

    However, due to the current implementation, it is necessary to re-init the slot object when the slot properties (such as e.g. default) are changed. This can be achieved by calling the method init of the slot object.

    Note that a statement for creating a slot object like

      ... {
        Attribute name
        ...
      }
    

    is a short hand notation for

      ... {
        Attribute create name
        ...
      }
    

    This is exactly the same situation like every where else in XOTcl, when an object/class is created. One has to use create explicitly, when a name of a slot object conflicts with a method of the class (e.g. one has to use "Attribute create class" if a slot named class is created).

    One cannot define on a meta-class an attribute named slot or slots and use then "... MetaClass Foo -slots { ::xotcl::Attribute x}... to create the slot objects. To handle this naming conflict, one has to create the slot objects outside of the aggregation and to provide the values for the properties of Attribute (domain, manager, .... ) by hand.

    Setter and Getter Methods for Slots

    When a slot is called via its name, the call is delegated to the slot object. Per default, the slot value is read via the get method of the slot and it is set the assign method. By redefining these methods, it is possible to provide custom setter and getter methods. The following example redefines the setter methods assign to check, whether an attribute value is within the range between 1 and 99.

      Class create A -slots {
        Attribute foo -default 1 -proc assign {domain var value} {
          if {$value < 0 || $value > 99} {
            error "$value is not in the range of 0 .. 99"
          }  
          $domain set $var $value
        }
      }
    
      A create a1
      ? {a1 foo 10} 10
      ? {a1 foo} 10
      ? {catch {a1 foo -1}} 1
    

    For the most common simple cases with single valued attributes, where neither setter or getter are redefined, XOTcl optimizes the slot access function and replaces the delegation to the slot object by the C-level implementation of instparametercmd.

    Note that it is possible to subclass Attribute (e.g. in order to store more properties for attributes, like when attributes are stored in a relational database) or to register mixin-classes or filters.

    Backward-compatible Short-Hand Notation for Attribute Slots

    XOTcl provides a short-hand notation for creating attribute slots, which is backward compatible for the most important options of XOTcl version prior to 1.5.0. Instead of writing

      Class Car -slots {
        Attribute owner
        Attribute doors -default 4
      }
    

    one can use as well

      Class Car -parameter {
        owner
        {doors 4}
      }
    

    The various features of the prior implementation of parameter are deprecated and will be removed in future versions.

    Experimental Slot Features

    Value Checking

    Attribute slots can have types assigned which are tested whenever the instance variable is altered. The slot salary is defined as integer whereas projects is defined to be a list of instances of the class ::Project (a list of instances, since projects is defined as multivalued).

      Class Person -slots {
        Attribute name
        Attribute salary -default 0 -type integer
        Attribute projects -default {} -multivalued true -type ::Project
        ...
      }
    
      Person p2 -name "Sue"	-salary 1000
    

    It is as well possible to define custom value checkers and to normalize the input values. We extend the previous example and define "my sex" as value for type. If the value checker consists of multiple words, the type check compiler assumes that the value is a Tcl command, to which the actual value is appended as additional argument before invocation. my refers to the slot object. In the example below, we define for the slot object an object specific method that returns 1 or 0 depending on the success of the check. This method (a) checks the values via switch and (b) normalizes and resets the value via uplevel.

      Class Person -slots {
        ...
        Attribute sex -type "my sex" -proc sex {value} {
          switch -glob $value {
            m* {my uplevel {$obj set $var m}; return 1}
            f* {my uplevel {$obj set $var f}; return 1}
            default {return 0}
          }
        }
      }
    

    The slot values are actually checked via Tcl variable traces whenever the associated variable gets a new value assigned. This means that the values are enforced now matter how the variables are set. Therefore, the checks are performed in the following two commands as well, although the slot values are not accessed via the slot names. The checks will throw an error in the second command, since 1100x is not an integer.

      p2 incr salary 100
      p2 append salary x
    

    Similarly the second command below will throw an error, since some-other-value is not an instance of ::Project.

      p2 projects add ::project1
      p2 projects add some-other-value     
    

    When a check throws an error, the instance variables are reset to the previous value. To restore the original value, an associative array __oldvalue() is kept as instance variable in the object.

    **** NOCHECK is removed ****

    In general, checking of variables can be turned off globally by

      ::xotcl::Slot instmixin add ::xotcl::Slot::Nocheck
    

    This mixin replaces the methods check and checkall as well as mk_type_checker by no-ops. When the mixin is active and the Attribute definitions are loaded, the specified type has no effect.

    Value checking can be turned off also selectively for each slot via using ::xotcl::Slot::Nocheck as per-object-mixin; if attributes are subclassed, it is possible to register the Nocheck mixin on a subclass of Attribute.

    Init Commands and Value Commands for Slot Values

    An init command (initcmd) of a slot is similar to a default and is a command to be executed when the value of the associated variable is read the first time. That means that when an object is created the associated variable has no value. On the contrary, when a default is used, the variable is set to the default value, when the object is created.

    The primary advantage of slot init commands is Lacy initialization: When an object has many slots and the initialization of all slots is costly (e.g. the value of each slot is fetched from a relational database), and not all of the values are needed for each instance, only the relevant variables of the object are initialized on demand.
      Class C -slots {
        Attribute x -initcmd {puts {init}; set _ 101}
      }
    
      C c1
      c1 info vars  ;# ==> returns ""
      c1 set  x     ;# ==> puts init, returns 101
      c1 info vars  ;# ==> returns "x"
    

    The initcmd is executed only once, when the variable is read the first time. For later reads of the variable contents, the values are returned.

    A value command (valuecmd) of a slot is similar to a init command, except that it is executed whenever the value of the variable is read. A value command can be used e.g. to implement live updates for variables or for abstracting from sql sequences or the like.

    Finally the value changed command (valuechangedcmd) can be used to specify the behavior, whenever the value of the variable is altered. This option is used to implement the value checking described in the last section.

    The slot parameters default, initcmd and valuecmd have to be used mutually exclusively.

    Nested Classes and Dynamic Object Aggregations

    Most object-oriented analysis and design methods are based on the concepts of generalization and aggregation. Generalization is achieved through class hierarchies and inheritance, while static aggregation is provided through embedding. Since version 8.0 Tcl offers a namespace concept which can be used as a mechanism to provide dynamic aggregations.

    A namespace provides an encapsulation of variable and procedure names in order to prevent unwanted name collisions with other system components. Each namespace has a unique identifier which becomes part of the fully qualified variable and procedure names. Namespaces are therefore already object-based in the terminology of Wegner. OTcl is object-oriented since it offers classes and class inheritance. Its objects are also namespaces, but an object is more than only a namespace. Therefore, two incompatible namespace concepts have existed in OTcl in parallel.

    In XOTcl every object and every class is logically implemented as a separate Tcl namespace. The biggest benefit of this design decision aside from performance advantages is the ability to aggregate objects and nest classes. Contrary in OTcl every object has a global identifier. Through the introspection abilities of namespaces nested classes are also traceable at runtime and can be changed dynamically. In XOTcl objects are allowed to contain nested objects, which are dynamically changeable aggregates of the containing object.

    Nested Classes

    The notation for nested classes follows the syntax of Tcl namespaces by using ``::'' as a delimiter. For example the description of a oval carpet and a desk can nest inside of the OvalOffice class:

      Class OvalOffice
      # general carpet
      Class Carpet
      Class OvalOffice::Desk
      # special oval carpet - no name collision
      Class OvalOffice::Carpet -superclass ::Carpet
    

    Nested classes can be used exactly like ordinary classes, a user can subclass it, derive instances, etc. The information about the nesting structure of classes is available through the info instance method:

      className info classchildren ?pattern?
      className info classparent
    

    The classchildren option returns a list of children, if one or more exist, otherwise it returns an empty string. classparent results in the name of the parent class, if the class is nested. Since nested classes are realized through namespaces, all functionality offered by Tcl's namespace command is usable from XOTcl as well.

    Dynamic Object Aggregations

    The nested classes only provide an aggregation of the descriptive not of the runtime properties of an object. We have pointed out the difference of object and class in XOTcl. Because of the splitting of a class into class and class-object it is possible to give each object its own namespace. The internal implementation of objects enable them to contain nested objects, which are aggregates of the containing object. In XOTcl these can be changed dynamically and introspected through the language support of dynamic object aggregations [Neumann and Zdun 2000b]. Suppose an object of the class Agent should aggregate some property objects of an agent, such as head and body:

      ClassAgent
      Agent myAgent
    
      Class Agent::Head
      Class Agent::Body
    
      Agent::Head ::myAgent::myHead
      Agent::Body ::myAgent::myBody
    

    Now the objects myHead and myBody are part of the myAgent object and they are accessible through a qualification using ``::'' (or through Tcl's namespace command). But in the common case they will be accessed, as introduced so far: the explicit full qualification is not necessary when such variables are being accessed from within XOTcl methods, since the object changes to its namespace.

    The information about the part-of relationship of objects can be obtained exactly the same way as for classes through the info interface:

      objName info children ?pattern?
      objName info parent
    

    Relationship between Class Nesting and Object Aggregation

    The classes Head and Body are children of the Agent class. It is likely that all agents, interactive or not, have properties for head and body. This implies a static or predetermined relationship between class nesting and object aggregation. Such predetermination do not exist in XOTcl, but are simply build, when specifying the relationship in the constructor, e.g.:

      Agent instproc init args {
        ::Agent::Head [self]::myHead
        ::Agent::Body [self]::myBody
      }
    

    Now all agents derived from the class have the two property objects aggregated after creation. But still they are changeable in a dynamical manner, e.g. with:

      Agent myAgent
      myAgent::myHead destroy
    

    The agent turns into a headless agent. In companion of the introspection mechanisms such constructions could be very useful. Suppose, that in the virtual world the agents heads may be slashed from their bodies. The graphical system simply needs to ask with info children on the agent's object, whether it has a head or not and can choose the appropriate graphical representation.

    Simplified Syntax for Creating Nested Object Structures

    To ease the generation of nested structures, one can use the predefined method contains. In essence, contains changes the namespace, where objects are created to the object, on which it is executed. In the example below, we create three nested rectangles, where two of these contain two more points. The outer rectangle is r0 containing rectangle r1 and r2.
      Class Point -parameter {{x 100} {y 300}}
      Class Rectangle -parameter {color}
    
      Rectangle r0 -color pink -contains {
        Rectangle r1 -color red -contains {
          Point x1 -x 1 -y 2
          Point x2 -x 1 -y 2
        }
        Rectangle r2 -color green -contains {
          Point x1
          Point x2
        }
      }
    
      ? {r0 color} pink
      ? {r0 r1 color} red
      ? {r0 r1 x1 x} 1
      ? {r0 r1 x2 y} 2
      ? {r0 r2 color} green
    

    Every object in XOTcl is realized as a Tcl command. If nested objects are created, these commands are available as object specific methods. So, instead of calling the contained rectangle r1 via the fully qualified name ::r0::r1, one can use r0 r1. This is exactly the same situation as it arises, when e.g. a global Tcl proc proc o1 {} {...} and an XOTcl object o1 (created via Object o1) is created. Both commands cannot coexist in the same namespace.

    Copy/Move

    Often an object has to be copied/moved. This is a very useful functionality when XOTcl should be used as a prototyping language. The XOTcl method move provides this functionality. Another common behavior is implemented by the copy method which clones the actual object to a destination object via a deep copy operation. The two methods have the syntax:
      objName move destination
      objName copy destination
    

    Copy and move operations work with all object/class information, i.e., information on filters, mixins, parameters, etc. are automatically copied. Copy and move are integrated with class nesting and object aggregations. All copy/move operations are deep copy operations: all nested objects/classes are automatically copied/moved, too. E.g. if we want to reuse an imperial march object of star wars for star wars 2, we can just copy the object:

      starWars::imperialMarch copy starWars2::imperialMarch
    
    Note that move is implemented in current versions of xotcl as a copy plus subsequent destroy operation.

    Method Forwarding

    As you have seen from many previous examples, XOTcl's primary command for method forwarding is the next primitive. next calls the same-named method of the current object, usually with the same argument list. However, frequently method forwarding is required between different objects as well, commonly referred to as delegation.

    In general, delegation can be achieved in XOTcl without any special construct using simple methods containing a few lines. However, In several situations, forwarding is as well needed to plain Tcl commands, for example, if object oriented stubs are implemented on base of non-oo function calls. These functions might access instance variables of the objects. XOTcl uses this functionality in various situations, such as for instance in the implementation of the set, unset, append, array methods among others.

    The forwarding functionality is supported by XOTcl be the methods forward and instforward that address these requirements and provide an efficient implementation for these tasks.

    The forwarding command specifies that whenever methodName is called, this invocation is delegated to callee, where the actual argument list (from the invocation) is appended to the argument list specified in the forwarding command. Like for procs and instprocs, we can distinguish between forward and instforward, depending on we want to the method available for a single object of for the instances of a class.

    The general form of the forwarding commands is:

      obj  forward methodName ?options? callee ?arglist? 
      cls  instforward methodName ?options? callee ?arglist? 
    
    where valid options are -objscope, -methodprefix, -earlybinding and -default. The option -objscope is used to specify that the command should be executed in the scope of the calling object (i.e. instance variables apprear as local variables), -methodprefix means that the called method should be prefixed with the specified string (to avoid name clashes), -earlybinding means that the function pointer of the specified command (callee) is take at invocation time (should only be done for (built-in) commands implemented in C), and -default provides a means for providing default methods when none are specified.

    Each of the arguments after the method name (including callee) can be be substituted an invocation time, or they are taken literally. The arguments to be substituted are starting always with a percent sign. These arguments can be %self, %proc, %1, %argclindex, or % followed by a Tcl command, and it can be prefixed with a positional prefix %@. We will introduce the usage of these options and argument substitutions based on examples.

    In our first example we define an object dog and an object tail. If the dog receives the call wag it delegates this call to the tail and returns its result. In this introductory example, the method tail simply returns its arguments.

    In this example, forwarding is achieved through the method forward that creates a forwarder command. This method receives as first argument the name, under which the forwarder is registered, followed by the object that receives the delegation (the "callee"), followed my the (optional) method name and optional arguments. More about this later. Here we register the forwarder under the name wag, the callee is tail, and the method is defined to have the name of the forwarder. We could have written here dog forward wag tail wag as well, be we use %proc which refers to the name of the forwarder. Using %proc is slightly more general in cases the forwarder is renamed.

      ###########################################
      # trivial object delegation
      ###########################################
      Object dog
      Object tail
      tail proc wag args { return $args }
      dog forward wag tail %proc
    

    With these definitions a call to "dog wag 100" calls actually "tail wag 100" which returns the result of 100.

    The following command shows the delegation to a Tcl command (instead of delegation to an object). We define a simple forwarder that forwards a call to the Tcl command expr with some arguments.

      ###########################################
      # adding 
      ###########################################
      Object obj
      obj forward addOne expr 1 +
    
    The invocation obj addOne 5 returns 6 as value.

    In our next example we want additionally that the Tcl command should to be evaluated in the context of the current object. This means that the method can easily access instance variables of the delegating object. We define a forwarder for the class X with the name Incr (to avoid confusion with the already defined method incr), we use the -objscope option and specify incr as the callee. Since the forwarder is defined via instforward the forwarder is available to all instances of the class.

      ###########################################
      # evaluating in scope 
      ###########################################
      Class X -parameter {{x 1}}
      X instforward Incr -objscope incr
      
      X x1 -x 100
      x1 Incr x
      x1 Incr x
      x1 Incr x
    
    After the three calls to Incr the call x1 x returns the value 103.

    In our next example, we show the usage of the %-substitution more advanced argument handling. This example sketches the implementation of the mixin add, mixin set methods as shown above. In order to obtain extensible subcommands (such as mixin add, mixin delete, etc.), we define an object for which the subcommands are defined as methods. We will use this object as callee for the appropriate methods. So, we define an object named mixin and define a forwarder with the name Mixin (again we capitalize Mixin to avoid name clashes with the already defined methodmixin ).

      ###########################################
      # mixin example
      ###########################################
      Object create mixin
      mixin proc unknown {m args} {return [concat [self] $m $args]}
      obj forward Mixin mixin %1 %self
    
    We define here the method unknown to see what arguments are passed. The following invocation will lead to the call in noted in the comment.
      obj Mixin add M1       ;# calls ::mixin add ::obj M1
    
    You see that %1 was substituted by the first argument of the invocation (here add) and %self was substituted by the name of the current object (here ::obj). The second argument of the invocation (here M1) was appended as usual. However, in calls like
      obj Mixin
    
    we have to deal with cases, where the used argument (%1) is not given at the invocation. In this case we get either an error message, or we can specify a default argument via the option -default:
      obj forward Mixin -default {getter setter} mixin %1 %self
    
    This definition means that if no argument is specified in the invocation we call the method getter, if one argument is given the method setter, in other cases we use the specified arguments. Therefore the following three invocations are delegated as indicated in the comments.
      obj Mixin              ;# calls ::mixin getter ::obj
      obj Mixin M1           ;# calls ::mixin setter ::obj M1
      obj Mixin add M1       ;# calls ::mixin add ::obj M1
    

    When we implement subcommands by delegating to other commands (as shown in the last example), there can be situations where naming conflicts might arise. For example, if we want to implement a subcommand method class we might not want to implement a new method class on the callee, since this would overwrite the standard definition of class. To overcome such difficulties, we provide the option -methodprefix. The following example shows how to prefix every called method with the prefix @.

      ###########################################
      # sketching extensible info
      ###########################################
      Object Info
      Info proc @mixin {o} {
        $o info mixin
      }
      Info proc @class {o} { ;# without prefix, doing here a [Info class] would be wrong
        $o info class
      }
      Info proc @help {o} { ;# define a new subcommand for info
        foreach c [my info procs] {lappend result [string range $c 1 end]}
        return $result
      }
      Object instforward Info -methodprefix @ Info %1 %self 
    
    With this definitions, the following call is rewritten as indicated in the comment.
      x1 Info class          ;# ::Info @class ::x1
    

    When a forwarder is defined, the callee (the target command) can be omitted. When the callee is not specified, the method-name is used instead. When the method-name has a namespace prefix, the method name is the tail and the callee is the fully qualified name.

      ###########################################
      # optional callee
      ###########################################
      obj set x 2
      obj forward append -objscope
      Object n; Object n::x
      obj forward ::n::x
    
    With this definitions of the forwarder append and x, the following calls are rewritten as indicated in the comment.
      obj append x y z        ;# ::append x y z ... returning  2yz
      obj x self              ;# ::n::x self    ... returning  ::n::x
    

    The forwarder append forwards the call to the Tcl command append, which accesses the instance variable x and appends the specified values.

    The list of tokens executed by the forwarder might contain Tcl commands executed during every invocations. This makes it for instance possible to pass instances variables to the callee. In the next example the object has the instvar named x which is multiplied by a factor of 10 when the method x* is invoked.

      ###########################################
      # command substitution
      ###########################################
      obj set x 10
      obj forward x* expr {%my set x} *
    
    With this definitions, the following call is rewritten as indicated in the comment.
      obj x* 10               ;# expr 10 * 10 ... returning  100
    

    In certain situations it is necessary to insert arguments always at the same position (e.g. at the second to last position). The positional addressing can be achieved by prefixing the arguments of the forward specification by %@POS , where POS is either a positive (argument positing from the beginning) or negative integer (argument counting from the end) or the constant end (denoting the last position). After POS a single space is used as a delimiter for the rest of the argument, which might be some other %-substitution or a constant. The positional arguments are evaluated from left to right and should be used in ascending order.

    The following examples show a few usages of the positional arguments in the forwarder. The forwarders f1 to f5 are created, followed by one or more usages. The first argument of the usage is the call to forewarder, the second argument is the result.

      ###########################################
      # forwarding with positional arguments
      ###########################################
      Object obj
      obj forward f1 list {%@end 13}
      ? {obj f1 1 2 3 } [list 1 2 3 13]
    
      obj forward f2 list {%@-1 13}
      ? {obj f2 1 2 3 } [list 1 2 13 3]
    
      obj forward f3 list {%@1 13}
      ? {obj f3 1 2 3 } [list 13 1 2 3]
      ? {obj f3} [list 13]
    
      obj forward f4 list {%@2 13}
      ? {obj f4 1 2 3 } [list 1 13 2 3]
    
      obj forward f5 {%@end 99} {%@0 list} 10
      ? {obj f5} [list 10 99]
      ? {obj f5 a b c} [list 10 a b c 99]
    

    The construct %argclindex LIST can be used to substitute an argument depending on the number of arguments when the forwarder is invoked. For example, it is possible to call forward to a different method depending on how many arguments are specified. The number of arguments is used as an index in the specified list. When the number of arguments is larger than the number of elements in the specified list, an error is generated.

      ###############################################
      # substitution depending on number of arguments
      ###############################################
      obj forward f %self [list %argclindex [list a b c]]
      obj proc a args {return [list [self proc] $args]}
      obj proc b args {return [list [self proc] $args]}
      obj proc c args {return [list [self proc] $args]}
      ? {obj f} [list a {}]
      ? {obj f 1 } [list b 1]
      ? {obj f 1 2} [list c {1 2}]
      ? {catch {obj f 1 2 3}} 1
    

    Finally, the concluding example defines a class chan to use the I/O-commands in an OO-manner. The proc open is used to create a chan instance. For the channel object we provide the method close (to close a channel and to destroy the channel object), puts (to write on a stream), blocked (to check whether last command exhausted all input), and fconfigure (to configure the stream). Note that for puts we specified that the actual stream should be inserted as the second to last argument.

      Class chan -parameter stream
      # create stream and object
      chan proc open args { 
        set stream [eval open $args]
        my create $stream -stream $stream  ;# make an object
      }
      # close stream and destroy object
      chan instproc close {} {
        close [my stream]
        [self] destroy
      }
      # handle other subcommands (methods) via unknown
      chan instproc unknown {m args} {
        set valid [lsort [chan info instcommands]]
        stderr puts "unknown chan method '$m' $args called; 
          	defined methods: $valid"
      }
      chan create stdout -stream stdout   ;# define standard stream
      chan create stderr -stream stderr   ;# define standard stream
    
      chan instforward puts puts {%@-1 %my stream}
      chan instforward blocked fblocked {%my stream}
      chan instforward fconfigure fconfigure {%my stream} 
    
      set c [chan open /tmp/junk w]
      $c puts -nonewline "hello"
      $c puts -nonewline " world"
      $c puts ""
      $c xxx                                       ;# trigger unknown
      # The stream instances denote the currently open streams
      stderr puts "currently open streams: [chan info instances]" 
      $c close
      stderr puts "currently open streams: [chan info instances]"
    

    Assertions

    In order to improve reliability and self documentation we added assertions to XOTcl. The implemented assertions are modeled after the ``design by contract'' concept of Bertrand Meyer. In XOTcl assertions can be specified in form of formal and informal pre- and post-conditions for each method. The conditions are defined as a list of and-combined constraints. The formal conditions have the form of normal Tcl conditions, while the informal conditions are defined as comments (specified with a starting ``#''). The lists containing the pre- and post-conditions are appended to the method definition (see example below).

    Since XOTcl offers per-object specialization it is desirable to specify conditions within objects as well (this is different to the concept of Meyer). Furthermore there may be conditions which must be valid for the whole class or object at any visible state (that means in every pre- and post-condition). These are called invariants and may be defined with following syntax for class invariants:

      className instinvar invariantList
    

    or for objects invariants:

      objName invar invariantList
    

    Logically all invariants are appended to the pre- and post-conditions with a logical ``and''. All assertions can be introspected.

    Since assertions are contracts they need not to be tested if one can be sure that the contracts are fulfilled by the partners. But for example when a component has changed or a new one is developed the assertions could be checked on demand. For this purpose the check method can be used either to test the pre- or the post-conditions. The syntax is:

      objName check ?all? ?instinvar? ?invar? ?pre? ?post?
    

    Per default all options are turned off. check all turns all assertion options for an object on, an arbitrary list (maybe empty) can be used for the selection of certain options. Assertion options are introspected by the info check option. The following class is equipped with assertions:

      Class Sensor -parameter {{value 1}}
      Sensor instinvar {
        {[regexp {^[0-9]$} [my value]] == 1}
      }
      Sensor instproc incrValue {} {
        my incr value
      } {
        {# pre-condition:} 
        {[my value] > 0}
      } {
        {# post-condition:} 
        {[my value] > 1}
      }
    

    The parameter instance method defines an instance variable value with value 1. The invariant expresses the condition (using the Tcl command regexp), that the value must be a single decimal digit. The method definition expresses the formal contract between the class and its clients that the method incrValue only gets input-states in which the value of the variable value is positive. If this contract is fulfilled by the client, the class commits itself to supply a post-condition where the variable's value is larger than 1. The formal conditions are ordinary Tcl conditions. If checking is turned on for sensor s:

      s check all
    

    the pre-conditions and invariants are tested at the beginning and the post-condition and invariants are tested at the end of the method execution automatically. A broken assertion, like calling incrValue 9 times (would break the invariant of being a single digit) results in an error message.

    In assertions we do not check methods that modify or introspect assertions. These are check,info,proc,instproc,invar, and instinvar. The reason for this is that we want to be able to recover a malicious action in a catch error handler, like:

      ...
      if {[catch {my assertionBreakingAction} errMsg]} {
        puts "CAUGHT ERROR: $errMsg"
        # remember checking options, for turning them on later again
        set check [my info check]
        my check {}
        # recover from broken assertion
        ...
        # turning checking on again 
        $fb check $check
      }
    

    Meta-Data and Automatic Documentation

    To enhance the understandability and the consistency between documentation and program it is useful to have a facility to make the documentation a part of the program. There are several kinds of meta-data which are interesting for a class, e.g. the author, a description, the version, etc.

    Older versions of XOTcl have contained a special meta-data command metadata. This command is now (from version 0.83) deprecated and replaced by an integrated solution with XOTcl's API documentation functionality. The object @ is used for documentation and metadata issues. Per default it is not evaluated at all. Everything that is send to @ is simply ignored. That way we do not waste memory/performance at runtime, if we do not require to parse the metadata/documentation.

    If we have to know the meta-data/documentation, as for instance in the xoDoc component and the makeDoc tool, that handle XOTcl's internal documentation, we have to re-define the documentation object. Alternatively, we can partially parse the source code for @ commands.

    With @ the meta-data/documentation is handled by first class XOTcl objects. By defining alternate @ implementations - as in xoDoc/makeDoc - we can evaluate the meta-data/documentation arbitrarily. xoDoc/makeDoc are only an HTML back-end, but the basic idea is to provide support for several other usages as well (e.g. XML, RDF, on-line help, documentation of dynamic structures, etc).

    The object@ handles comments via its unknown method. xoDoc adds the appropriate instprocs to t@ to produce HTML output. The appropriate command is:

      tclsh src/lib/makeDoc.xotcl DOCDIR DOCFILES
    

    The source of a documentation is structurally very similar to the XOTcl constructs being commented. E.g. one can copy an instproc and add comments at the right places, like:

        Class C
        C instproc m {a1 a2} {
           return [expr {$a1+$a2}]
        }
    

    can be commented as follows

        @ Class C { description { "my sample class"} }
        @ C instproc m {a1 "first number" a2 "second number"} {
           description "add two numbers"
           return "sum of a1 and a2"
        }
    

    One can do essentially a copy+paste of the source and add the comments via attribute value pairs. Every basic language construct can have a "description". If you want to include other properties to the description, you can add them like:

        @ C instproc m {a1 "first number" a2 "second number"} {
           author "GN+UZ"
           date "Feb 31"
           description "add two numbers"
           return "sum of a1 and a2"
        }
    

    This way, author and date are added automatically to the generated HTML file. In addition, there is a @File hook for a per file description, like:

    @ @File {
      description {
        This is a file which provides a regression test
        for the features of the XOTcl - Language. 
      }
    }
    

    Additional Functionalities

    Abstract Classes

    In XOTcl a class is defined abstract if at least one method of this class is abstract. The instance method abstract defines an abstract method and specifies its interface. Direct calls to abstract methods produce an error message. E.g. a Storage class provides an abstract interface for access to different storage forms:

      Class Storage
      Storage abstract instproc open  {name}       
      Storage abstract instproc store {key value}
      Storage abstract instproc list  {}         
      Storage abstract instproc fetch key        
      Storage abstract instproc close {}         
      Storage abstract instproc delete {k} 
    

    All kinds of storage have to implement every method from the interface. E.g. a GNU Database Access, a relational database access, and several other storage forms may be derived by subclassing (therefore, all conform to the same storage access interface).

    Checking Commands for being Objects, Classes, or Meta-Classes

    Since XOTcl is a hybrid language containing several Tcl commands, sometimes its necessary for applications to distinguish between Tcl commands and object commands for XOTcl. method of the Object class looks up an objName and returns 1 if it is an object and 0 if not:

      objName1 isobject objName2
    

    If one can be sure that a command represents an object, it might be unsure if the command is only an object or also class or even meta-class. The two instance methods isclass and ismetaclass check in the same manner, whether a class or meta-class is given (since ever XOTcl class is an object, they also return 0, when objName is not an XOTcl object).

      objName1 isclass objName2
      objName1 ismetaclass objName2
    

    Exit Handler

    A task for a programming language, sometimes of similar importance as object creation, is the object destruction. XOTcl ensures that all objects are destroyed and their destructors are invoked when XOTcl applications terminate. For that reason objects and classes are destroyed in the order objects, classes, meta-classes. Sometimes further destruction order is of importance. For these cases, the XOTcl language provides an exit handler, which is a user-defined proc, which invokes user-defined exit handling just before the destruction of objects, classes, meta-classes is invoked. For instance, the exit handler lets the user specify objects which have to be destroyed before all other objects.

    The exit handler is defined as a proc of Object, which is per default empty:

      ::xotcl::Object proc __exitHandler {} {
        # clients should append exit handlers to this proc body
        ;
      }
    

    There are some procs of the Object class pre-defined, which let us specify an exit handler conveniently:

       Object setExitHandler body
       Object getExitHandler
       Object unsetExitHandler
    

    setExitHandler lets us specify a proc body that actually contains the user-defined exit handling:

       Object setExitHandler {
         aObj destroy
         puts "exiting"
       }
    

    destroys the object aObj before all other objects and prints the message existing to the screen. With getExitHandler the exit handler can be introspected. E.g. if we just want to append the destruction of object bObj to an existing exit handler, we use getExitHandler:

       Object setExitHandler "[Object getExitHandler]; bObj destroy"
    

    unsetExitHandler deletes the exit handler.

    
    

    Automatic Name Creation

    The XOTcl autoname instance method provides a simple way to take the task of automatically creating names out of the responsibility of the programmer. The example below shows how to create on each invocation of method new an agent with a fresh name (prefixed with agent):

      Agent proc new args {
        eval my [my autoname agent] $args
      }
    

    Autonames may have format strings as in the Tcl 'format' command. E.g.:

      objName autoname a%06d
    

    produces

      a000000, a000001, a000002, ...
    

    Integrating XOTcl Programs with C Extensions (such as TK)

    Because all XOTcl commands are in the ::xotcl namespace, it is usually no problem to integrate XOTcl with other Tcl extensions. Most often it works to import the XOTcl commands (like Object, Class) into the current namespace because there are no name-clashes with the commands defined by other extensions.

    Consider you want to perform a deeper integration of another extension and XOTcl because you want to benefit from XOTcl's object system. For instance, you might want to introduce composite TK widgets (sometimes called mega-widgets) as classes and inherit from these classes. Here, you have two options: you can change or extend the C code of that other extension to provide XOTcl classes or objects, or you can write an XOTcl wrapper in Tcl. For the first alternative, there are some examples provided in the XOTcl distribution. XOTclGdbm provides an OO Tcl interface to the GDBM database, for instance. XOTclSdbm does the same for SDBM, and the TclExpat wrapper provides a class-based interface to the TclExpat XML parser.

    Consider you do not want to change the C code of a Tcl extension. Then you can write an OO wrapper in XOTcl for the commands of the other extension. For stateless commands, you can simply write forwarder methods. If the extension maintains some state, you typically associate the state handle with an XOTcl parameter, acquire the state in the XOTcl constructor, and align the XOTcl destructor with the stateful instance.

    Consider you want to wrap the Tk button widget. You can acquire the widget in the constructor, and maintain the widget ID in a parameter. You now can forward invocations to this widget ID (e.g. when using "pack"), or register command callbacks (like buttonPressed). Note that we let the "self" command be replaced in the scope of the current method so that TK receives the correct object ID for the callback. In the destructor we destroy the widget as well (we use "catch" because sometimes widgets can destroyed by other means as well (e.g. by their parent widget, when a widget/object hierarchy is destroyed at once).

      Class MyButton -parameter {button}
      MyButton instproc buttonPressed args {
        puts "pressed [my button]"
      }
      MyButton instproc init args {
        set ID [namespace tail [self]]
        my instvar button
        set button [button .$ID \
          -text "My Button $ID" \
          -command [list [self] buttonPressed]] 
        pack $button
        next
      }
      MyButton instproc destroy args {
         catch {destroy [my button]}
         next
      }
    
      # a test -> 3 buttons, destroy one of them
      foreach b {a b c} {
        MyButton $b
      }
      b destroy
    

    The "trick" to substitute "self" within the current method scope works for all kinds of command callbacks. Extensions such as TK, however, often work with bindings to (global) variables as well. Using global variables is frowned upon in the OO community. Instead you should use instance variables of objects. As Tcl can only bind to existing namespace variables (and XOTcl acquires the namespace of an object on demand), you have to make sure that the namespace of an object exists before binding a variable. That can be done with "requireNamespace":

      GUIClass instproc buildEntry win {
        my requireNamespace
        entry $win -textvariable [self]::entryValue
        my set entryValue {Init Value}
      }
    

    Note that in the above example we have used to tail of the object ID as ID for the widget. Usually, it is a good idea to the object name, if possible, for TK (and other extensions) IDs as well. Another option is to use a autoname to get a unique name for the ID.

    Sometimes you want to simply send all invocations, not implemented by XOTcl, to the wrapped command. Here, it is tedious to write a wrapper for each of these methods. Instead you can use "unknown" to handle automatic forwarding. Consider you want to wrap TK commands like pack and replace XOTcl object names with their TK widget ID, so that you can use both IDs synonymously. You can rename the respective TK commands in the following way:

      foreach tkCommand {bell bind bindtags clipboard event 
        focus font grid image lower option pack place raise 
        selection send tk tkwait winfo wm} { 
        rename ::$tkCommand __tk_$tkCommand
        TkCommand ::$tkCommand
        ::$tkCommand set wrapped __tk_$tkCommand
      }
    

    The XOTcl class handling the ID substitution for the TK command might look as follows:

      Class TkCommand -parameter wrapped
      TkCommand instproc unknown args {
          my instvar wrapped
          set args [Widget replaceWithWidgetIDs $args]
          # now call the command
          eval $wrapped $args
      }
    

    References

    [Zdun, Strembeck, Neumann 2007] U. Zdun, M. Strembeck, G. Neumann: Object-Based and Class-Based Composition of Transitive Mixins, Information and Software Technology, 49(8) 2007 .

    [Neumann and Zdun 1999a] G. Neumann and U. Zdun. Filters as a language support for design patterns in object-oriented scripting languages. In Proceedings of COOTS'99, 5th Conference on Object-Oriented Technologies and Systems, San Diego, May 1999.

    [Neumann and Zdun 1999b] G. Neumann and U. Zdun. Implementing object-specific design patterns using per-object mixins. In Proc. of NOSA`99, Second Nordic Workshop on Software Architecture, Ronneby, Sweden, August 1999.

    [Neumann and Zdun 1999c] G. Neumann and U. Zdun. Enhancing object-based system composition through per-object mixins. In Proceedings of Asia-Pacific Software Engineering Conference (APSEC), Takamatsu, Japan, December 1999.

    [Neumann and Zdun 2000a] G. Neumann and U. Zdun. XOTCL, an object-oriented scripting language. In Proceedings of Tcl2k: The 7th USENIX Tcl/Tk Conference, Austin, Texas, February 2000.

    [Neumann and Zdun 2000b] G. Neumann and U. Zdun. Towards the Usage of Dynamic Object Aggregations as a Form of Composition In: Proceedings of Symposium of Applied Computing (SAC'00), Como, Italy, Mar 19-21, 2000.

    [Neumann and Sobernig 2009] G. Neumann, S. Sobernig: XOTcl 2.0 - A Ten-Year Retrospective and Outlook, in: Proceedings of the Sixteenth Annual Tcl/Tk Conference, Portland, Oregon, October, 2009.

    [Ousterhout 1990] J. K. Ousterhout. Tcl: An embeddable command language. In Proc. of the 1990 Winter USENIX Conference, January 1990.

    [Ousterhout 1998] J. K. Ousterhout. Scripting: Higher Level Programming for the 21st Century, IEEE Computer 31(3), March 1998.

    [Wetherall and Lindblad 1995] D. Wetherall and C. J. Lindblad. Extending Tcl for Dynamic Object-Oriented Programming. Proc. of the Tcl/Tk Workshop '95, July 1995. ./nsf2.4.0/doc/UNIVERSAL-xotcl.html000644 000766 000024 00000003402 12161565464 017333 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/actiweb/univ/UNIVERSAL.xotcl

    ./apps/actiweb/univ/UNIVERSAL.xotcl ./apps/actiweb/univ/UNIVERSAL.xotcl


    Package/File Information

    No package provided/required

    Filename: ./apps/actiweb/univ/UNIVERSAL.xotcl

    Description: This is a demo of a Webserver that presents the contents of an RDF source file in a friendly and easy readable manner.

    The RDF file is parsed first into triples which are added to the resource database RDFdb. This RDFdb used in this example replaces the standard triple database of xoRDF by an application specific version, which is easier to process. The triple database is the source of the Catalog, which displays a short, easy to read summary of the entries. The database is used as well for the "detailed view", which presents all the data of the triples through nested HTML tables.

    The demo program uses either HTTP or HTTPS (in which case you will require the SSL/TLS extension of Tcl).




    Back to index page.

    ./nsf2.4.0/doc/mixinoftest-xotcl.html000644 000766 000024 00000001471 12161565464 020340 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./tests/mixinoftest.xotcl

    ./tests/mixinoftest.xotcl ./tests/mixinoftest.xotcl


    Package/File Information

    No package provided/required

    Filename: ./tests/mixinoftest.xotcl




    Back to index page.

    ./nsf2.4.0/doc/Class.3000644 000766 000024 00000165274 14274463622 015117 0ustar00neumannstaff000000 000000 '\" '\" Generated from file 'Class\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2014-2019 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. '\" .TH "nx::Class" 3 2\&.4\&.0 Class "NX API" .\" The -*- nroff -*- definitions below are for supplemental macros used .\" in Tcl/Tk manual entries. .\" .\" .AP type name in/out ?indent? .\" Start paragraph describing an argument to a library procedure. .\" type is type of argument (int, etc.), in/out is either "in", "out", .\" or "in/out" to describe whether procedure reads or modifies arg, .\" and indent is equivalent to second arg of .IP (shouldn't ever be .\" needed; use .AS below instead) .\" .\" .AS ?type? ?name? .\" Give maximum sizes of arguments for setting tab stops. Type and .\" name are examples of largest possible arguments that will be passed .\" to .AP later. If args are omitted, default tab stops are used. .\" .\" .BS .\" Start box enclosure. From here until next .BE, everything will be .\" enclosed in one large box. .\" .\" .BE .\" End of box enclosure. .\" .\" .CS .\" Begin code excerpt. .\" .\" .CE .\" End code excerpt. .\" .\" .VS ?version? ?br? .\" Begin vertical sidebar, for use in marking newly-changed parts .\" of man pages. The first argument is ignored and used for recording .\" the version when the .VS was added, so that the sidebars can be .\" found and removed when they reach a certain age. If another argument .\" is present, then a line break is forced before starting the sidebar. .\" .\" .VE .\" End of vertical sidebar. .\" .\" .DS .\" Begin an indented unfilled display. .\" .\" .DE .\" End of indented unfilled display. .\" .\" .SO ?manpage? .\" Start of list of standard options for a Tk widget. The manpage .\" argument defines where to look up the standard options; if .\" omitted, defaults to "options". The options follow on successive .\" lines, in three columns separated by tabs. .\" .\" .SE .\" End of list of standard options for a Tk widget. .\" .\" .OP cmdName dbName dbClass .\" Start of description of a specific option. cmdName gives the .\" option's name as specified in the class command, dbName gives .\" the option's name in the option database, and dbClass gives .\" the option's class in the option database. .\" .\" .UL arg1 arg2 .\" Print arg1 underlined, then print arg2 normally. .\" .\" .QW arg1 ?arg2? .\" Print arg1 in quotes, then arg2 normally (for trailing punctuation). .\" .\" .PQ arg1 ?arg2? .\" Print an open parenthesis, arg1 in quotes, then arg2 normally .\" (for trailing punctuation) and then a closing parenthesis. .\" .\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b .\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out .\" # BS - start boxed text .\" # ^y = starting y location .\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. .\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. .\" # VS - start vertical sidebar .\" # ^Y = starting y location .\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. .\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. .\" # Special macro to handle page bottom: finish off current .\" # box/sidebar if in box/sidebar mode, then invoked standard .\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. .\" # DS - begin display .de DS .RS .nf .sp .. .\" # DE - end display .de DE .fi .RE .sp .. .\" # SO - start of list of standard options .de SO 'ie '\\$1'' .ds So \\fBoptions\\fR 'el .ds So \\fB\\$1\\fR .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. .\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\*(So manual entry for details on the standard options. .. .\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. .\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. .\" # CE - end code excerpt .de CE .fi .RE .. .\" # UL - underline word .de UL \\$1\l'|0\(ul'\\$2 .. .\" # QW - apply quotation marks to word .de QW .ie '\\*(lq'"' ``\\$1''\\$2 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\$2 .. .\" # PQ - apply parens and quotation marks to word .de PQ .ie '\\*(lq'"' (``\\$1''\\$2)\\$3 .\"" fix emacs highlighting .el (\\*(lq\\$1\\*(rq\\$2)\\$3 .. .\" # QR - quoted range .de QR .ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3 .. .\" # MT - "empty" string .de MT .QW "" .. .BS .SH NAME nx::Class \- API reference of the base-metaclass of the NX objectsystem .SH SYNOPSIS \fBnx::Class\fR \fBcreate\fR \fIcls\fR ?\fB-superclasses\fR \fIsuperClassNames\fR? ?\fB-mixins\fR \fImixinSpec\fR? ?\fB-filters\fR \fIfilterSpec\fR? ?\fIoption\fR \fIvalue\fR \&.\&.\&.? ?\fIinitBlock\fR? .sp \fBnx::Class\fR \fBnew\fR ?\fB-superclasses\fR \fIsuperClassNames\fR? ?\fB-mixins\fR \fImixinSpec\fR? ?\fB-filters\fR \fIfilterSpec\fR? ?\fIinitBlock\fR? .sp \fIcls\fR ?\fBpublic\fR | \fBprivate\fR | \fBprotected\fR? \fB alias\fR ?\fB-debug\fR? ?\fB-deprecated\fR? \fImethodName\fR ?\fB-returns\fR \fIvalueChecker\fR? ?\fB-frame\fR \fBobject\fR | \fBmethod\fR? \fIcmdName\fR .sp \fIcls\fR \fBcreate\fR \fIinstanceName\fR ?\fIoption\fR \fIvalue\fR \fIoption\fR \fIvalue\fR \&.\&.\&.? .sp \fIcls\fR \fBdelete\fR \fIfeature\fR \fIarg\fR .sp \fIcls\fR \fB\fR \fBfilters\fR \fIsubmethod\fR ?\fIarg\fR \&.\&.\&.? .sp \fIcls\fR ?\fBpublic\fR | \fBprotected\fR | \fBprivate\fR? \fB forward\fR ?\fB-debug\fR? ?\fB-deprecated\fR? \fImethodName\fR ?\fB-prefix\fR \fIprefixName\fR? ?\fB-frame\fR \fBobject\fR? ?\fB-returns\fR \fIvalueChecker\fR? ?\fB-verbose\fR? ?\fItarget\fR? ?\fIarg\fR \&.\&.\&.? .sp \fIcls\fR \fBinfo heritage\fR ?\fIpattern\fR? .sp \fIcls\fR \fBinfo instances\fR ?\fB-closure\fR? ?\fIpattern\fR? .sp \fIcls\fR \fBinfo mixinof\fR ?\fB-closure\fR? ?\fB-scope\fR \fIoption\fR? ?\fIpattern\fR? .sp \fIcls\fR \fBinfo subclasses\fR ?\fB-closure\fR? ?\fB-dependent\fR? ?\fIpattern\fR? .sp \fIcls\fR \fBinfo superclasses\fR ?\fB-closure\fR? ?\fIpattern\fR? .sp \fIcls\fR \fBinfo info\fR ?\fB-asList\fR? .sp \fIcls\fR \fBinfo filters\fR ?\fB-guards\fR? ?\fIpattern\fR? .sp \fIcls\fR \fBinfo method\fR \fIoption\fR \fImethodName\fR .sp \fIcls\fR \fBinfo methods\fR ?\fB-callprotection\fR \fIlevel\fR? ?\fB-type\fR \fImethodType\fR? ?\fB-path\fR? ?\fInamePattern\fR? .sp \fIcls\fR \fBinfo mixins\fR ?\fB-guards\fR? ?\fIpattern\fR? .sp \fIcls\fR \fBinfo slots\fR ?\fB-type\fR \fIclassName\fR? ?\fIpattern\fR? .sp \fIcls\fR \fBinfo variables\fR ?\fIpattern\fR? .sp \fIcls\fR ?\fBpublic\fR | \fBprotected\fR | \fBprivate\fR? \fB method\fR ?\fB-debug\fR? ?\fB-deprecated\fR? \fIname\fR \fIparameters\fR ?\fB-checkalways\fR? ?\fB-returns\fR \fIvalueChecker\fR? \fIbody\fR .sp \fIcls\fR \fB mixins\fR \fIsubmethod\fR ?\fIarg\fR \&.\&.\&.? .sp \fIcls\fR \fBnew\fR ?\fB-childof\fR \fIparentName\fR? ?\fIoption\fR \fIvalue\fR \fIoption\fR \fIvalue\fR \&.\&.\&.? .sp \fIcls\fR \fBproperty\fR ?\fB-accessor\fR \fBpublic\fR | \fBprotected\fR | \fBprivate\fR? ?\fB-class\fR \fIclassName\fR? ?\fB-configurable\fR \fItrueFalse\fR? ?\fB-incremental\fR? ?\fB-trace\fR \fBset\fR | \fBget\fR | \fBdefault\fR? \fIspec\fR ?\fIinitBlock\fR? .sp \fIcls\fR \fBrequire\fR ?\fBpublic\fR | \fBprotected\fR | \fBprivate\fR? \fB method\fR \fImethodName\fR .sp \fIcls\fR \fBvariable\fR ?\fB-accessor\fR \fBpublic\fR | \fBprotected\fR | \fBprivate\fR? ?\fB-incremental\fR? ?\fB-class\fR \fIclassName\fR? ?\fB-configurable\fR \fItrueFalse\fR? ?\fB-initblock\fR ?\fB-trace\fR \fBset\fR | \fBget\fR | \fBdefault\fR? \fIscript\fR? \fIspec\fR ?\fIdefaultValue\fR? .sp .BE .SH DESCRIPTION .PP \fBnx::Class\fR is the base metaclass of the NX object system\&. All classes (e\&.g\&. \fIcls\fR) are (direct or indirect) instances of \fBnx::Class\fR\&. Therefore, the methods provided by \fBnx::Class\fR are available to all classes\&. A class \fIcls\fR which does not have \fBnx::Class\fR as its direct or indirect superclass is referred to as an \fIapplication class\fR\&. By default, when instantiating a new class from \fBnx::Class\fR, it becomes an application class with \fBnx::Object\fR being set as its superclass\&. A class \fIcls\fR which is explicitly declared as a (direct or indirect) subclass of \fBnx::Class\fR is referred to as a \fImetaclass\fR, that is, its instances will become classes as well\&. In other words, a metaclass instantiates and subclasses \fBnx::Class\fR at the same time\&. .CS +---------+ | ::nx::* | +---------+--------------------------------------Y | | | instance of | | \&.-------\&. | | +--------'+ instance of +----------+ | | | |<\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.| | | | | Class | | Object | | | | |\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.>| | | | +---------+ subclass of +-----+----+ | | ^ ^ ^ | \\\&.\&.\&.|\&.\&.\&.|\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.|\&.\&.\&.\&.\&.\&.\&./ | | | | |subclass\&.\&.\&.\&.\&.(xor)\&.\&.\&.\&.\&.\&.subclass| | |of +-----------+ of| | |\&.\&.\&.\&.\&.\&.\&.\&.\&.| |\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.| | (metaclass) | /cls/ | (application class) |\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.| | instance of +-----------+ .CE Classes can be created in the following ways: .TP \fBnx::Class\fR \fBcreate\fR \fIcls\fR ?\fB-superclasses\fR \fIsuperClassNames\fR? ?\fB-mixins\fR \fImixinSpec\fR? ?\fB-filters\fR \fIfilterSpec\fR? ?\fIoption\fR \fIvalue\fR \&.\&.\&.? ?\fIinitBlock\fR? To create a class having the explicit name \fIcls\fR, use \fBcreate\fR\&. .TP \fBnx::Class\fR \fBnew\fR ?\fB-superclasses\fR \fIsuperClassNames\fR? ?\fB-mixins\fR \fImixinSpec\fR? ?\fB-filters\fR \fIfilterSpec\fR? ?\fIinitBlock\fR? To create a class having an automatically assigned, implicit name, use \fBnew\fR\&. .PP The configuration options for direct and indirect instances of \fBnx::Class\fR, which can be passed when calling \fBcreate\fR and \fBnew\fR, are documented in the subsequent section\&. .SH "CONFIGURATION OPTIONS FOR INSTANCES OF NX::CLASS" .PP Configuration options can be used for configuring objects during their creation by passing the options as non-positional arguments into calls of \fBnew\fR and \fBcreate\fR (see \fBnx::Class\fR)\&. An existing object can be queried for its current configuration using \fBcget\fR and it can be re-configured using \fBconfigure\fR\&. .TP \fB-superclasses\fR ?\fIsuperClassNames\fR? If \fIsuperClassNames\fR is not specified, returns the superclasses of the class\&. If provided, the class becomes the subclass of \fIsuperClassNames\fR\&. .TP \fB-filters\fR ?\fIfilterSpecs\fR? Retrieves the list of filter methods currently active on instances of the class, if \fIfilterSpecs\fR is not set\&. Otherwise, activates a list of filter methods for the instances of the class\&. Filters are returned or set in terms of a list of filter specifications\&. .TP \fB-mixins\fR ?\fImixinSpecs\fR? Returns the list of mixin classes currently active on instances of the class, if \fImixinSpecs\fR is not specified\&. Otherwise, the class is extended by the list of mixin classes provided by \fImixinSpecs\fR\&. mixin classes are returned or set in terms of a list of mixin specifications\&. .PP The configuration options provided by \fBnx::Object\fR are equally available because an application class \fIcls\fR is an indirect instance of \fBnx::Object\fR\&. .SH "METHODS FOR INSTANCES OF NX::CLASS" .TP \fBalias\fR .RS .TP \fIcls\fR ?\fBpublic\fR | \fBprivate\fR | \fBprotected\fR? \fB alias\fR ?\fB-debug\fR? ?\fB-deprecated\fR? \fImethodName\fR ?\fB-returns\fR \fIvalueChecker\fR? ?\fB-frame\fR \fBobject\fR | \fBmethod\fR? \fIcmdName\fR Define an alias method for the given class\&. The resulting method registers a pre-existing Tcl command \fIcmdName\fR under the (alias) name \fImethodName\fR with the class\&. If \fIcmdName\fR refers to another \fBmethod\fR, the corresponding argument should be a valid method handle\&. If a Tcl command (e\&.g\&., a \fBproc\fR), the argument should be a fully qualified Tcl command name\&. If aliasing a subcommand (e\&.g\&., \fBarray exists\fR) of a Tcl namespace ensemble (e\&.g\&., \fBarray\fR), \fIcmdName\fR must hold the fully qualified subcommand name (and not the ensemble name of the subcommand)\&. .sp As for a regular \fBclass method\fR, \fB-returns\fR allows for setting a value checker on the values returned by the aliased command \fIcmdName\fR\&. .sp When creating an alias method for a \fIC-implemented\fR Tcl command (i\&.e\&., command defined using the Tcl/NX C-API), \fB-frame\fR sets the scope for variable references used in the aliased command\&. If the provided value is \fBobject\fR, then variable references will be resolved in the context of the called object, i\&.e\&., the object upon which the alias method is invoked, as if they were object variables\&. There is no need for using the colon-prefix notation for identifying object variables\&. If the value is \fBmethod\fR, then the aliased command will be executed as a regular method call\&. The command is aware of its called-object context; i\&.e\&., it can resolve \fB::nx::self\fR\&. In addition, the alias method has access to the method-call context (e\&.g\&., \fBnx::next\fR)\&. If \fB-frame\fR is omitted, and by default, the variable references will resolve in the context of the caller of the alias method\&. .sp To express deprecation of the alias method \fImethodName\fR, set the \fB-deprecated\fR flag\&. Deprecated methods remain usable from client code, but their usage will be signaled to the developer and/or can be tracked using \fB::nsf::deprecated\fR\&. To register \fImethodName\fR with the debugger, set the \fB-debug\fR flag\&. Entering and exiting a method, which was flagged for debugging, is recorded by calling the redefinable callback procs \fB::nsf::debug::call\fR and \fB::nsf::debug::exit\fR, respectively\&. By default, these callbacks forward to \fB::nsf::log\fR, which can also be customized at the script level\&. .RE .TP \fB__class_configureparameter\fR .RS .TP \fIcls\fR \fB__class_configureparameter\fR Computes and returns the configuration options available for \fIcls\fR instances, to be consumed as method-parameter specification by \fBconfigure\fR\&. .RE .TP \fBcreate\fR .RS .TP \fIcls\fR \fBcreate\fR \fIinstanceName\fR ?\fIoption\fR \fIvalue\fR \fIoption\fR \fIvalue\fR \&.\&.\&.? This factory method creates an instance \fIinstanceName\fR of \fIcls\fR and returns \fIinstanceName\fR\&. .CS % nx::Class create AClass { :method init args { next }; # initialization method for instances of 'AClass' }; # defines a class 'AClass' being an instance of 'nx::Class' ::AClass % ::AClass create anInstance; # defines an object 'anInstance' being an instance of 'AClass' ::anInstance % ::anInstance info class ::AClass % ::AClass info class ::nx::Class .CE .IP \fBcreate\fR accepts the configuration options \fIoption\fR available for this instance, such as those defined by properties of \fIcls\fR (see \fBproperty\fR)\&. .sp Note that \fBcreate\fR is called internally when defining an instance of \fIcls\fR using \fBnew\fR\&. .sp By calling \fBcreate\fR on \fBnx::Class\fR itself, the created instance will become a new application class \fIinstanceName\fR on which \fBcreate\fR can also be applied (i\&.e\&., it can be instantiated)\&. If the so-created class has \fB::nx::Class\fR its direct or indirect superclass, \fIinstanceName\fR is referred to as a metaclass; that is, a class whose instances are again classes\&. .RE .TP \fBdelete\fR .RS .TP \fIcls\fR \fBdelete\fR \fIfeature\fR \fIarg\fR This method serves as the equivalent to Tcl's \fBrename\fR for removing structural (properties, variables) and behavioral features (methods) of the class: .TP \fIcls\fR \fBdelete property\fR \fIpropertyName\fR .TP \fIcls\fR \fBdelete variable\fR \fIvariableName\fR .TP \fIcls\fR \fBdelete method\fR \fImethodName\fR Removes a property \fIpropertyName\fR, variable \fIvariableName\fR, and method \fImethodName\fR, respectively, previously defined for the scope of the class\&. .sp \fBdelete method\fR can be equally used for removing regular methods (see \fB method\fR), an alias method (see \fB alias\fR), and a forwarder method (see \fB forward\fR)\&. .RE .TP \fBfilters\fR .RS .TP \fIcls\fR \fB\fR \fBfilters\fR \fIsubmethod\fR ?\fIarg\fR \&.\&.\&.? Accesses and modifies the list of methods which are registered as filters with \fIcls\fR using a specific setter or getter \fIsubmethod\fR: .RS .TP \fIcls\fR \fB\fR \fBfilters add\fR \fIspec\fR ?\fIindex\fR? Inserts a single filter into the current list of filters of \fIcls\fR\&. Using \fIindex\fR, a position in the existing list of filters for inserting the new filter can be set\&. If omitted, \fIindex\fR defaults to the list head (0)\&. .TP \fIcls\fR \fB\fR \fBfilters clear\fR Removes all filters from \fIcls\fR and returns the list of removed filters\&. Clearing is equivalent to passing an empty list for \fIfilterSpecList\fR to \fBclass\fR \fBfilter set\fR\&. .TP \fIcls\fR \fB\fR \fBfilters delete\fR ?\fB-nocomplain\fR? \fIspecPattern\fR Removes a single filter from the current list of filters of \fIcls\fR whose spec matches \fIspecPattern\fR\&. \fIspecPattern\fR can contain special matching chars (see \fBstring match\fR)\&. \fBclass\fR \fBfilters delete\fR will throw an error if there is no matching filter, unless \fB-nocomplain\fR is set\&. .TP \fIcls\fR \fB\fR \fBfilters get\fR Returns the list of current filter specifications registered for \fIcls\fR\&. .TP \fIcls\fR \fB\fR \fBfilters guard\fR \fImethodName\fR ?\fIexpr\fR? If \fIexpr\fR is specified, registers a guard expression \fIexpr\fR with a filter \fImethodName\fR\&. This requires that the filter \fImethodName\fR has been previously set using \fB\fR \fBfilters set\fR or added using \fB\fR \fBfilters add\fR\&. \fIexpr\fR must be a valid Tcl expression (see \fBexpr\fR)\&. An empty string for \fIexpr\fR will clear the currently registered guard expression for filter \fImethodName\fR\&. .sp If \fIexpr\fR is omitted, returns the guard expression set on the filter \fImethodName\fR defined for \fIcls\fR\&. If none is available, an empty string will be returned\&. .TP \fIcls\fR \fB\fR \fBfilters methods\fR ?\fIpattern\fR? If \fIpattern\fR is omitted, returns all filter names which are defined by \fIcls\fR\&. By specifying \fIpattern\fR, the returned filters can be limited to those whose names match \fIpatterns\fR (see \fBstring match\fR)\&. .TP \fIcls\fR \fB\fR \fBfilters set\fR \fIfilterSpecList\fR \fIfilterSpecList\fR takes a list of filter specs, with each spec being itself either a one-element or a two-element list: \fImethodName\fR ?-guard \fIguardExpr\fR?\&. \fImethodName\fR identifies an existing method of \fIcls\fR which becomes registered as a filter\&. If having three elements, the third element \fIguardExpr\fR will be stored as a guard expression of the filter\&. This guard expression must be a valid Tcl expression (see \fBexpr\fR)\&. \fIexpr\fR is evaluated when \fIcls\fR receives a message to determine whether the filter should intercept the message\&. Guard expressions allow for realizing context-dependent or conditional filter composition\&. .RE .IP Every \fImethodName\fR in a \fIspec\fR must resolve to an existing method in the scope of the class\&. To access and to manipulate the list of filters of \fIcls\fR, \fBcget\fR|\fBconfigure\fR \fB-filters\fR can also be used\&. .RE .TP \fBforward\fR .RS .TP \fIcls\fR ?\fBpublic\fR | \fBprotected\fR | \fBprivate\fR? \fB forward\fR ?\fB-debug\fR? ?\fB-deprecated\fR? \fImethodName\fR ?\fB-prefix\fR \fIprefixName\fR? ?\fB-frame\fR \fBobject\fR? ?\fB-returns\fR \fIvalueChecker\fR? ?\fB-verbose\fR? ?\fItarget\fR? ?\fIarg\fR \&.\&.\&.? Define a forward method for the given class\&. The definition of a forward method registers a predefined, but changeable list of forwarder arguments under the (forwarder) name \fImethodName\fR\&. Upon calling the forward method, the forwarder arguments are evaluated as a Tcl command call\&. That is, if present, \fItarget\fR is interpreted as a Tcl command (e\&.g\&., a Tcl \fBproc\fR or an object) and the remainder of the forwarder arguments \fIarg\fR as arguments passed into this command\&. The actual method arguments to the invocation of the forward method itself are appended to the list of forwarder arguments\&. If \fItarget\fR is omitted, the value of \fImethodName\fR is implicitly set and used as \fItarget\fR\&. This way, when providing a fully-qualified Tcl command name as \fImethodName\fR without \fItarget\fR, the unqualified \fImethodName\fR (\fBnamespace tail\fR) is used as the forwarder name; while the fully-qualified one serves as the \fItarget\fR\&. .sp As for a regular \fB method\fR, \fB-returns\fR allows for setting a value checker on the values returned by the resulting Tcl command call\&. When passing \fBobject\fR to \fB-frame\fR, the resulting Tcl command is evaluated in the context of the object receiving the forward method call\&. This way, variable names used in the resulting execution of a command become resolved as object variables\&. .sp To express deprecation of the forward method \fImethodName\fR, set the \fB-deprecated\fR flag\&. Deprecated methods remain usable from client code, but their usage will be signaled to the developer and/or can be tracked using \fB::nsf::deprecated\fR\&. To register \fImethodName\fR with the debugger, set the \fB-debug\fR flag\&. Entering and exiting a method, which was flagged for debugging, is recorded by calling the redefinable callback procs \fB::nsf::debug::call\fR and \fB::nsf::debug::exit\fR, respectively\&. By default, these callbacks forward to \fB::nsf::log\fR, which can also be customized at the script level\&. .sp The list of forwarder arguments \fIarg\fR can contain as its elements a mix of literal values and placeholders\&. Placeholders are prefixed with a percent symbol (%) and substituted for concrete values upon calling the forward method\&. These placeholders allow for constructing and for manipulating the arguments to be passed into the resulting command call on the fly: .RS .IP \(bu \fB%method\fR becomes substituted for the name of the forward method, i\&.e\&. \fImethodName\fR\&. .IP \(bu \fB%self\fR becomes substituted for the name of the object receiving the call of the forward method\&. .IP \(bu \fB%1\fR becomes substituted for the first method argument passed to the call of forward method\&. This requires, in turn, that \fIat least\fR one argument is passed along with the method call\&. .sp Alternatively, \fB%1\fR accepts an optional argument \fIdefaults\fR: {\fB%1\fR \fIdefaults\fR}\&. \fIdefaults\fR must be a valid Tcl list of two elements\&. For the first element, \fB%1\fR is substituted when there is no first method argument which can be consumed by \fB%1\fR\&. The second element is inserted upon availability of a first method argument with the consumed argument being appended right after the second list element\&. This placeholder is typically used to define a pair of getter/setter methods\&. .IP \(bu {\fB%@\fR\fIindex\fR \fIvalue\fR} becomes substituted for the specified \fIvalue\fR at position \fIindex\fR in the forwarder-arguments list, with \fIindex\fR being either a positive integer, a negative integer, or the literal value \fBend\fR (such as in Tcl's \fBlindex\fR)\&. Positive integers specify a list position relative to the list head, negative integers give a position relative to the list tail\&. Indexes for positioning placeholders in the definition of a forward method are evaluated from left to right and should be used in ascending order\&. .sp Note that \fIvalue\fR can be a literal or any of the placeholders (e\&.g\&., \fB%method\fR, \fB%self\fR)\&. Position prefixes are exempted, they are evaluated as \fB%\fR\fIcmdName\fR-placeholders in this context\&. .IP \(bu {\fB%argclindex\fR \fIlist\fR} becomes substituted for the \fIn\fRth element of the provided \fIlist\fR , with \fIn\fR corresponding to the number of method arguments passed to the forward method call\&. .IP \(bu \fB%%\fR is substituted for a single, literal percent symbol (%)\&. .IP \(bu \fB%\fR\fIcmdName\fR is substituted for the value returned from executing the Tcl command \fIcmdName\fR\&. To pass arguments to \fIcmdName\fR, the placeholder should be wrapped into a Tcl \fBlist\fR: {\fB%\fR\fIcmdName\fR ?\fIarg\fR \&.\&.\&.?}\&. .sp Consider using fully-qualified Tcl command names for \fIcmdName\fR to avoid possible name conflicts with the predefined placeholders, e\&.g\&., \fB%self\fR vs\&. %\fB::nx::self\fR\&. .RE .sp To disambiguate the names of subcommands or methods, which potentially become called by a forward method, a prefix \fIprefixName\fR can be set using \fB-prefix\fR\&. This prefix is prepended automatically to the argument following \fItarget\fR (i\&.e\&., a second argument), if present\&. If missing, \fB-prefix\fR has no effect on the forward method call\&. .sp To inspect and to debug the conversions performed by the above placeholders, setting the switch \fB-verbose\fR will have the command list to be executed (i\&.e\&., after substitution) printed using \fB::nsf::log\fR (debugging level: \fBnotice\fR) upon calling the forward method\&. .RE .TP \fBinfo\fR A collection of introspection submethods on the structural features (e\&.g\&. configuration options, superclasses) and the behavioral features (e\&.g\&. methods, filters) provided by \fIcls\fR to its instances\&. .RS .TP \fIcls\fR \fBinfo heritage\fR ?\fIpattern\fR? If \fIpattern\fR is omitted, returns the list of object names of all the direct and indirect superclasses and \fIper-class\fR mixin classes of \fIcls\fR, in their order of precedence, which are active for instances of \fIcls\fR\&. If \fIpattern\fR is specified, only superclasses and mixin classes whose names match \fIpattern\fR will be listed (see \fBstring match\fR)\&. .TP \fIcls\fR \fBinfo instances\fR ?\fB-closure\fR? ?\fIpattern\fR? If \fIpattern\fR is not specified, returns a list of the object names of all the direct instances of \fIcls\fR\&. If the switch \fB-closure\fR is set, indirect instances are also returned\&. A direct instance is created by using \fBcreate\fR or \fBnew\fR on \fIcls\fR, an indirect instance was created from a direct or indirect subclass of \fIcls\fR\&. If \fIpattern\fR is specified, only instances whose names match \fIpattern\fR will be listed (see \fBstring match\fR)\&. .TP \fIcls\fR \fBinfo mixinof\fR ?\fB-closure\fR? ?\fB-scope\fR \fIoption\fR? ?\fIpattern\fR? If \fIpattern\fR is not specified, returns a list of the object names of all the objects for which \fIcls\fR is active as a direct mixin class\&. If the switch \fB-closure\fR is set, objects which have \fIcls\fR as an indirect mixin class are also returned\&. If \fIpattern\fR is specified, only objects whose names match \fIpattern\fR will be listed (see \fBstring match\fR)\&. Valid values of \fIoption\fR are \fBall\fR, \fBobject\fR, and \fBclass\fR\&. Passing \fBobject\fR will have only objects returned which have \fIcls\fR as \fIper-object\fR mixin class\&. Passing \fBclass\fR will have only classes returned which have \fIcls\fR as \fIper-class\fR mixin class\&. \fBall\fR (the default) will have contained both in the returned list\&. .TP \fIcls\fR \fBinfo subclasses\fR ?\fB-closure\fR? ?\fB-dependent\fR? ?\fIpattern\fR? If \fIpattern\fR is not specified, returns a list of the object names of the direct subclasses of \fIcls\fR\&. If the switch \fB-closure\fR is set, indirect subclasses are also returned\&. If the switch \fB-dependent\fR is on, indirect subclasses introduced by mixin class relations of subclasses of \fIcls\fR are also reported\&. \fB-closure\fR and \fB-dependent\fR are mutually exclusive\&. If \fIpattern\fR is specified, only subclasses whose names match \fIpattern\fR will be listed (see \fBstring match\fR)\&. .TP \fIcls\fR \fBinfo superclasses\fR ?\fB-closure\fR? ?\fIpattern\fR? If \fIpattern\fR is not specified, returns a list of the object names of all direct superclasses of \fIcls\fR\&. If the switch \fB-closure\fR is set, indirect superclasses will also be returned\&. If \fIpattern\fR is specified, only superclasses whose names match \fIpattern\fR will be listed (see \fBstring match\fR)\&. .TP \fIcls\fR \fBinfo info\fR ?\fB-asList\fR? Returns the available submethods of the \fBinfo\fR method ensemble for \fIcls\fR, either as a pretty-printed string or as a Tcl list (if the switch \fB-asList\fR is set) for further processing\&. .TP \fIcls\fR \fBinfo filters\fR ?\fB-guards\fR? ?\fIpattern\fR? If \fIpattern\fR is omitted, returns all filter names which are defined by \fIcls\fR\&. By turning on the switch \fB-guards\fR, the corresponding guard expressions, if any, are also reported along with each filter as a three-element list: \fIfilterName\fR -guard \fIguardExpr\fR\&. By specifying \fIpattern\fR, the returned filters can be limited to those whose names match \fIpatterns\fR (see \fBstring match\fR)\&. .TP \fIcls\fR \fBinfo method\fR \fIoption\fR \fImethodName\fR This introspection submethod provides access to the details of \fImethodName\fR provided by \fIcls\fR\&. If \fImethodName\fR is not the name of an existing method, an empty string is returned\&. To disambiguate between a non-existing method and an empty string as valid return value (e\&.g\&., for \fBinfo method args|parameters|args|\&.\&.\&.\fR), use \fBinfo method exists\fR\&. .sp Permitted values for \fIoption\fR are: .RS .IP \(bu \fBargs\fR returns a list containing the parameter names of \fImethodName\fR, in order of the method-parameter specification\&. .IP \(bu \fBbody\fR returns the body script of \fImethodName\fR\&. .IP \(bu \fBcallprotection\fR returns the call-protection level set for \fImethodName\fR; possible values: \fBpublic\fR, \fBprotected\fR, \fBprivate\fR\&. .IP \(bu \fBdebug\fR returns 1 if \fImethodName\fR is in debug mode, 0 otherwise\&. .IP \(bu \fBdefinition\fR returns a canonical command list which allows for (re-)define \fImethodName\fR\&. .IP \(bu \fBdefinitionhandle\fR returns the method handle for a submethod in a method ensemble from the perspective of \fIcls\fR as method provider\&. \fImethodName\fR must contain a complete method path\&. .IP \(bu \fBdeprecated\fR returns 1 if \fImethodName\fR is deprecated, 0 otherwise\&. .IP \(bu \fBexists\fR returns 1 if there is a \fImethodName\fR provided by \fIcls\fR, returns 0 otherwise\&. .IP \(bu \fBhandle\fR returns the method handle for \fImethodName\fR\&. .IP \(bu \fBorigin\fR returns the aliased command if \fImethodName\fR is an alias method, or an empty string otherwise\&. .IP \(bu \fBparameters\fR returns the parameter specification of \fImethodName\fR as a list of parameter names and type specifications\&. .IP \(bu \fBregistrationhandle\fR returns the method handle for a submethod in a method ensemble from the perspective of the method caller\&. \fImethodName\fR must contain a complete method path\&. .IP \(bu \fBreturns\fR gives the type specification defined for the return value of \fImethodName\fR\&. .IP \(bu \fBsubmethods\fR returns the names of all submethods of \fImethodName\fR, if \fImethodName\fR is a method ensemble\&. Otherwise, an empty string is returned\&. .IP \(bu \fBsyntax\fR returns the method parameters of \fImethodName\fR as a concrete-syntax description to be used in human-understandable messages (e\&.g\&., errors or warnings, documentation strings)\&. .IP \(bu \fBtype\fR returns whether \fImethodName\fR is a \fIscripted\fR method, an \fIalias\fR method, a \fIforwarder\fR method, or a \fIsetter\fR method\&. .RE .TP \fIcls\fR \fBinfo methods\fR ?\fB-callprotection\fR \fIlevel\fR? ?\fB-type\fR \fImethodType\fR? ?\fB-path\fR? ?\fInamePattern\fR? Returns the names of all methods defined by \fIcls\fR\&. Methods covered include those defined using \fB alias\fR and \fB forward\fR\&. The returned methods can be limited to those whose names match \fInamePattern\fR (see \fBstring match\fR)\&. .sp By setting \fB-callprotection\fR, only methods of a certain call protection \fIlevel\fR (\fBpublic\fR, \fBprotected\fR, or \fBprivate\fR) will be returned\&. Methods of a specific type can be requested using \fB-type\fR\&. The recognized values for \fImethodType\fR are: .RS .IP \(bu \fBscripted\fR denotes methods defined using \fBclass\fR \fBmethod\fR; .IP \(bu \fBalias\fR denotes alias methods defined using \fBclass\fR \fBalias\fR; .IP \(bu \fBforwarder\fR denotes forwarder methods defined using \fBclass\fR \fBforward\fR; .IP \(bu \fBsetter\fR denotes methods defined using \fB::nsf::setter\fR; .IP \(bu \fBall\fR returns methods of any type, without restrictions (also the default value); .RE .TP \fIcls\fR \fBinfo mixins\fR ?\fB-guards\fR? ?\fIpattern\fR? If \fIpattern\fR is omitted, returns the object names of the mixin classes which extend \fIcls\fR directly\&. By turning on the switch \fB-guards\fR, the corresponding guard expressions, if any, are also reported along with each mixin as a three-element list: \fIclassName\fR -guard \fIguardExpr\fR\&. The returned mixin classes can be limited to those whose names match \fIpatterns\fR (see \fBstring match\fR)\&. .TP \fIcls\fR \fBinfo slots\fR ?\fB-type\fR \fIclassName\fR? ?\fIpattern\fR? If \fIpattern\fR is not specified, returns the object names of all slot objects defined by \fIcls\fR\&. The returned slot objects can be limited according to any or a combination of the following criteria: First, slot objects can be filtered based on their command names matching \fIpattern\fR (see \fBstring match\fR)\&. Second, \fB-type\fR allows one to select slot objects which are instantiated from a subclass \fIclassName\fR of \fBnx::Slot\fR (default: \fBnx::Slot\fR)\&. .TP \fIcls\fR \fBinfo variables\fR ?\fIpattern\fR? If \fIpattern\fR is omitted, returns the object names of all slot objects provided by \fIcls\fR which are responsible for managing properties and variables of \fIcls\fR\&. Otherwise, only slot objects whose names match \fIpattern\fR are returned\&. .sp This is equivalent to calling: \fIcls\fR \fBinfo slots\fR \fB-type\fR \fB::nx::VariableSlot\fR \fIpattern\fR\&. .sp To extract details of each slot object, use the \fBinfo\fR submethods available for each slot object\&. .RE .TP \fBmethod\fR .RS .TP \fIcls\fR ?\fBpublic\fR | \fBprotected\fR | \fBprivate\fR? \fB method\fR ?\fB-debug\fR? ?\fB-deprecated\fR? \fIname\fR \fIparameters\fR ?\fB-checkalways\fR? ?\fB-returns\fR \fIvalueChecker\fR? \fIbody\fR Defines a scripted method \fImethodName\fR for the scope of the class\&. The method becomes part of the class's signature interface\&. Besides a \fImethodName\fR, the method definition specifies the method \fIparameters\fR and a method \fIbody\fR\&. .sp \fIparameters\fR accepts a Tcl \fBlist\fR containing an arbitrary number of non-positional and positional parameter definitions\&. Each parameter definition comprises a parameter name, a parameter-specific value checker, and parameter options\&. .sp The \fIbody\fR contains the method implementation as a script block\&. In this body script, the colon-prefix notation is available to denote an object variable and a self call\&. In addition, the context of the object receiving the method call (i\&.e\&., the message) can be accessed (e\&.g\&., using \fBnx::self\fR) and the call stack can be introspected (e\&.g\&., using \fBnx::current\fR)\&. .sp Optionally, \fB-returns\fR allows for setting a value checker on values returned by the method implementation\&. By setting the switch \fB-checkalways\fR, value checking on arguments and return value is guaranteed to be performed, even if value checking is temporarily disabled; see \fBnx::configure\fR)\&. .sp To express deprecation of the method \fIname\fR, set the \fB-deprecated\fR flag\&. Deprecated methods remain usable from client code, but their usage will be signaled to the developer and/or can be tracked using \fB::nsf::deprecated\fR\&. To register \fIname\fR with the debugger, set the \fB-debug\fR flag\&. Entering and exiting a method, which was flagged for debugging, is recorded by calling the redefinable callback procs \fB::nsf::debug::call\fR and \fB::nsf::debug::exit\fR, respectively\&. By default, these callbacks forward to \fB::nsf::log\fR, which can also be customized at the script level\&. .sp A method closely resembles a Tcl \fBproc\fR, but it differs in some important aspects: First, a method can define non-positional parameters and value checkers on arguments\&. Second, the script implementing the method body can contain object-specific notation and commands (see above)\&. Third, method calls \fIcannot\fR be intercepted using Tcl \fBtrace\fR\&. Note that an existing Tcl \fBproc\fR can be registered as an alias method with the class (see \fB alias\fR)\&. .RE .TP \fBmixins\fR .RS .TP \fIcls\fR \fB mixins\fR \fIsubmethod\fR ?\fIarg\fR \&.\&.\&.? Accesses and modifies the list of mixin classes of \fIcls\fR using a specific setter or getter \fIsubmethod\fR: .RS .TP \fIcls\fR \fB\fR \fBmixins add\fR \fIspec\fR ?\fIindex\fR? Inserts a single mixin class into the current list of mixin classes of \fIcls\fR\&. Using \fIindex\fR, a position in the existing list of mixin classes for inserting the new mixin class can be set\&. If omitted, \fIindex\fR defaults to the list head (0)\&. .TP \fIcls\fR \fB\fR \fBmixins classes\fR ?\fIpattern\fR? If \fIpattern\fR is omitted, returns the object names of the mixin classes which extend \fIcls\fR directly\&. By specifying \fIpattern\fR, the returned mixin classes can be limited to those whose names match \fIpattern\fR (see \fBstring match\fR)\&. .TP \fIcls\fR \fB\fR \fBmixins clear\fR Removes all mixin classes from \fIcls\fR and returns the list of removed mixin classes\&. Clearing is equivalent to passing an empty list for \fImixinSpecList\fR to \fB\fR \fBmixins set\fR\&. .TP \fIcls\fR \fB\fR \fBmixins delete\fR ?\fB-nocomplain\fR? \fIspecPattern\fR Removes a mixin class from a current list of mixin classes of \fIcls\fR whose spec matches \fIspecPattern\fR\&. \fIspecPattern\fR can contain special matching chars (see \fBstring match\fR)\&. \fBclass\fR \fBmixins delete\fR will throw an error if there is no matching mixin class, unless \fB-nocomplain\fR is set\&. .TP \fIcls\fR \fB\fR \fBmixins get\fR Returns the list of current mixin specifications\&. .TP \fIcls\fR \fB\fR \fBmixins guard\fR \fIclassName\fR ?\fIexpr\fR? If \fIexpr\fR is specified, a guard expression \fIexpr\fR is registered with the mixin class \fIclassName\fR\&. This requires that the corresponding mixin class \fIclassName\fR has been previously set using \fBclass\fR \fBmixins set\fR or added using \fB\fR \fBmixins add\fR\&. \fIexpr\fR must be a valid Tcl expression (see \fBexpr\fR)\&. An empty string for \fIexpr\fR will clear the currently registered guard expression for the mixin class \fIclassName\fR\&. .sp If \fIexpr\fR is not specified, returns the active guard expression\&. If none is available, an empty string will be returned\&. .TP \fIcls\fR \fB\fR \fBmixins set\fR \fImixinSpecList\fR \fImixinSpecList\fR represents a list of mixin class specs, with each spec being itself either a one-element or a three-element list: \fIclassName\fR ?-guard \fIguardExpr\fR?\&. If having one element, the element will be considered the \fIclassName\fR of the mixin class\&. If having three elements, the third element \fIguardExpr\fR will be stored as a guard expression of the mixin class\&. This guard expression will be evaluated using \fBexpr\fR when \fIcls\fR receives a message to determine if the mixin is to be considered during method dispatch or not\&. Guard expressions allow for realizing context-dependent or conditional mixin composition\&. .RE .IP At the time of setting the mixin relation, that is, calling \fB\fR \fBmixins\fR, every \fIclassName\fR as part of a spec must be an existing instance of \fBnx::Class\fR\&. To access and to manipulate the list of mixin classes of \fIcls\fR, \fBcget\fR|\fBconfigure\fR \fB-mixins\fR can also be used\&. .RE .TP \fBnew\fR .RS .TP \fIcls\fR \fBnew\fR ?\fB-childof\fR \fIparentName\fR? ?\fIoption\fR \fIvalue\fR \fIoption\fR \fIvalue\fR \&.\&.\&.? A factory method to create autonamed instances of \fIcls\fR\&. It returns the name of the newly created instance\&. For example: .CS % nx::Class create AClass; # defines a class 'AClass' being an instance of 'nx::Class' ::AClass % set inst [::AClass new]; # defines an autonamed object being an instance of 'AClass' ::nsf::__#0 % $inst info class ::AClass .CE .IP The factory method will provide computed object names of the form, e\&.g\&. \fB::nsf::__#0\fR\&. The uniqueness of generated object names is guaranteed for the scope of the current Tcl interpreter only\&. .sp It is a frontend to \fBcreate\fR which will be called by \fBnew\fR once the name of the instance has been computed, passing along the arguments \fIoption\fR to \fBnew\fR as the configuration options (see \fBcreate\fR)\&. .sp If \fB-childof\fR is provided, the new object will be created as a nested object of \fIparentName\fR\&. \fIparentName\fR can be the name of either an existing NX object or an existing Tcl namespace\&. If non-existing, a Tcl namespace \fIparentName\fR will be created on the fly\&. .RE .TP \fBproperty\fR .RS .TP \fIcls\fR \fBproperty\fR ?\fB-accessor\fR \fBpublic\fR | \fBprotected\fR | \fBprivate\fR? ?\fB-class\fR \fIclassName\fR? ?\fB-configurable\fR \fItrueFalse\fR? ?\fB-incremental\fR? ?\fB-trace\fR \fBset\fR | \fBget\fR | \fBdefault\fR? \fIspec\fR ?\fIinitBlock\fR? Defines a property for the scope of the class\&. The \fIspec\fR provides the property specification as a \fBlist\fR holding at least one element or, maximum, two elements: \fIpropertyName\fR?\fB:\fR\fItypeSpec\fR? ?\fIdefaultValue\fR?\&. The \fIpropertyName\fR is also used as to form the names of the getter/setter methods, if requested (see \fB-accessor\fR)\&. It is, optionally, equipped with a \fItypeSpec\fR following a colon delimiter which specifies a value checker for the values which become assigned to the property\&. The second, optional element sets a \fIdefaultValue\fR for this property\&. .sp If \fB-accessor\fR is set, a property will provide for different getter and setter methods: .RS .TP \fIobj\fR \fIpropertyName\fR \fBexists\fR Returns 1 if the value store of \fIpropertyName\fR (e\&.g\&., an object variable) exists and has been given a value, returns 0 otherwise\&. .TP \fIobj\fR \fIpropertyName\fR \fBset\fR \fIvalue\fR Sets the property \fIpropertyName\fR to \fIvalue\fR\&. .TP \fIobj\fR \fIpropertyName\fR \fBget\fR Returns the current value of property \fIpropertyName\fR\&. .TP \fIobj\fR \fIpropertyName\fR \fBunset\fR Removes the value store of \fIpropertyName\fR (e\&.g\&., an object variable), if existing\&. .RE .IP The option value passed along \fB-accessor\fR sets the level of call protection for the generated getter and setter methods: \fBpublic\fR, \fBprotected\fR, or \fBprivate\fR\&. By default, no getter and setter methods are created\&. .sp Turning on the switch \fB-incremental\fR provides a refined setter interface to the value managed by the property\&. First, setting \fB-incremental\fR implies requesting \fB-accessor\fR (set to \fBpublic\fR by default, if not specified explicitly)\&. Second, the managed value will be considered a valid Tcl list\&. A multiplicity of \fB1\&.\&.*\fR is set by default, if not specified explicitly as part of \fIspec\fR\&. Third, to manage this list value element-wise (\fIincrementally\fR), two additional setter methods become available: .RS .TP \fIobj\fR \fIpropertyName\fR \fBadd\fR \fIelement\fR ?\fIindex\fR? Adding \fIelement\fR to the managed list value, at the list position given by \fIindex\fR (by default: 0)\&. .TP \fIobj\fR \fIpropertyName\fR \fBdelete\fR ?\fB-nocomplain\fR? \fIelementPattern\fR Removing the first occurrence of an element from the managed list value which matches \fIelementPattern\fR\&. \fIelementPattern\fR can contain matching characters (see \fBstring match\fR)\&. An error will be thrown if there is no match, unless \fB-nocomplain\fR is set\&. .RE .sp By setting \fB-configurable\fR to \fBtrue\fR (the default), the property can be accessed and modified through \fBcget\fR and \fBconfigure\fR, respectively\&. If \fBfalse\fR, no configuration option will become available via \fBcget\fR and \fBconfigure\fR\&. .sp If neither \fB-accessor\fR nor \fB-configurable\fR are requested, the value managed by the property will have to be accessed and modified directly\&. If the property manages an object variable, its value will be readable and writable using \fBset\fR and \fBeval\fR\&. .sp The \fB-trace\fR option causes certain slot methods to be executed whenever \fBget\fR, \fBset\fR, or \fBdefault\fR operations are invoked on the property: .RS .IP \(bu \fBset\fR: \fIslot\fR \fBvalue=set\fR \fIobj\fR \fIpropertyName\fR \fIvalue\fR .IP \(bu \fBget\fR: \fIslot\fR \fBvalue=get\fR \fIobj\fR \fIpropertyName\fR .IP \(bu \fBdefault\fR: \fIslot\fR \fBvalue=default\fR \fIobj\fR \fIpropertyName\fR .RE .sp A property becomes implemented by a slot object under any of the following conditions: .RS .IP \(bu \fB-configurable\fR equals \fBtrue\fR (by default)\&. .IP \(bu \fB-accessor\fR is one of \fBpublic\fR, \fBprotected\fR, or \fBprivate\fR\&. .IP \(bu \fB-incremental\fR is turned on\&. .IP \(bu \fIinitBlock\fR is a non-empty string\&. .RE .IP Assuming default settings, every property is realized by a slot object\&. .sp Provided a slot object managing the property is to be created, a custom class \fIclassName\fR from which this slot object is to be instantiated can be set using \fB-class\fR\&. The default value is \fB::nx::VariableSlot\fR\&. .sp The last argument \fIinitBlock\fR accepts an optional Tcl script which is passed into the initialization procedure (see \fBconfigure\fR) of the property's slot object\&. See also \fB\fIinitBlock\fR for \fBcreate\fR and \fBnew\fR\fR\&. .RE .TP \fBrequire\fR .RS .TP \fIcls\fR \fBrequire\fR ?\fBpublic\fR | \fBprotected\fR | \fBprivate\fR? \fB method\fR \fImethodName\fR Attempts to register a method definition made available using \fB::nsf::method::provide\fR under the name \fImethodName\fR with \fIcls\fR \&. The registered method is subjected to default call protection (\fBprotected\fR), if not set explicitly\&. .RE .TP \fBvariable\fR .RS .TP \fIcls\fR \fBvariable\fR ?\fB-accessor\fR \fBpublic\fR | \fBprotected\fR | \fBprivate\fR? ?\fB-incremental\fR? ?\fB-class\fR \fIclassName\fR? ?\fB-configurable\fR \fItrueFalse\fR? ?\fB-initblock\fR ?\fB-trace\fR \fBset\fR | \fBget\fR | \fBdefault\fR? \fIscript\fR? \fIspec\fR ?\fIdefaultValue\fR? Defines a variable for the scope of the class\&. The \fIspec\fR provides the variable specification: \fIvariableName\fR?\fB:\fR\fItypeSpec\fR?\&. The \fIvariableName\fR will be used to name the underlying Tcl variable and the getter/setter methods, if requested (see \fB-accessor\fR)\&. \fIspec\fR is optionally equipped with a \fItypeSpec\fR following a colon delimiter which specifies a value checker for the values managed by the variable\&. Optionally, a \fIdefaultValue\fR can be defined\&. .sp If \fB-accessor\fR is set explicitly, a variable will provide for getter and setter methods: .RS .TP \fIobj\fR \fIvariableName\fR \fBexists\fR Returns 1 if the value store of \fIvariableName\fR (e\&.g\&., an object variable) exists and has been given a value, returns 0 otherwise\&. .TP \fIobj\fR \fIvariableName\fR \fBset\fR \fIvarValue\fR Sets \fIvariableName\fR to \fIvarValue\fR\&. .TP \fIobj\fR \fIvariableName\fR \fBget\fR Returns the current value of \fIvariableName\fR\&. .TP \fIobj\fR \fIvariableName\fR \fBunset\fR Removes \fIvariableName\fR, if existing, underlying the property\&. .RE .IP The option value passed along \fB-accessor\fR sets the level of call protection for the getter and setter methods: \fBpublic\fR, \fBprotected\fR, or \fBprivate\fR\&. By default, no getter and setter methods are created\&. .sp Turning on the switch \fB-incremental\fR provides a refined setter interface to the value managed by the variable\&. First, setting \fB-incremental\fR implies requesting \fB-accessor\fR (\fBpublic\fR by default, if not specified explicitly)\&. Second, the managed value will be considered a valid Tcl list\&. A multiplicity of \fB1\&.\&.*\fR is set by default, if not specified explicitly as part of \fIspec\fR (see above)\&. Third, to manage this list value element-wise (\fIincrementally\fR), two additional setter operations become available: .RS .TP \fIobj\fR \fIvariableName\fR \fBadd\fR \fIelement\fR ?\fIindex\fR? Adding \fIelement\fR to the managed list value, at the list position given by \fIindex\fR (by default: 0)\&. .TP \fIobj\fR \fIvariableName\fR \fBdelete\fR ?\fB-nocomplain\fR? \fIelementPattern\fR Removing the first occurrence of an element from the managed list value which matches \fIelementPattern\fR\&. \fIelementPattern\fR can contain matching characters (see \fBstring match\fR)\&. An error will be thrown if there is no match, unless \fB-nocomplain\fR is set\&. .RE .sp By setting \fB-configurable\fR to \fBtrue\fR, the variable can be accessed and modified via \fBcget\fR and \fBconfigure\fR, respectively\&. If \fBfalse\fR (the default), the interface based on \fBcget\fR and \fBconfigure\fR will not become available\&. In this case, and provided that \fB-accessor\fR is set, the variable can be accessed and modified via the getter/setter methods\&. Alternatively, the underlying Tcl variable, which is represented by the variable, can always be accessed and modified directly, e\&.g\&., using \fBeval\fR\&. By default, \fB-configurable\fR is \fBfalse\fR\&. .sp The \fB-trace\fR option causes certain slot methods to be executed whenever \fBget\fR, \fBset\fR, or \fBdefault\fR operations are invoked on the variable: .RS .IP \(bu \fBset\fR: \fIslot\fR \fBvalue=set\fR \fIobj\fR \fIvariableName\fR \fIvalue\fR .IP \(bu \fBget\fR: \fIslot\fR \fBvalue=get\fR \fIobj\fR \fIvariableName\fR .IP \(bu \fBdefault\fR: \fIslot\fR \fBvalue=default\fR \fIobj\fR \fIvariableName\fR .RE .sp A variable becomes implemented by a slot object under any of the following conditions: .RS .IP \(bu \fB-configurable\fR equals \fBtrue\fR\&. .IP \(bu \fB-accessor\fR is one of \fBpublic\fR, \fBprotected\fR, or \fBprivate\fR\&. .IP \(bu \fB-incremental\fR is turned on\&. .IP \(bu \fB-initblock\fR is a non-empty string\&. .RE .IP Provided a slot object managing the variable is to be created, a custom class \fIclassName\fR from which this slot object is to be instantiated can be set using \fB-class\fR\&. The default value is \fB::nx::VariableSlot\fR\&. .sp Using \fB-initblock\fR, an optional Tcl \fIscript\fR can be defined which becomes passed into the initialization procedure (see \fBconfigure\fR) of the variable's slot object\&. See also \fB\fIinitBlock\fR for \fBcreate\fR and \fBnew\fR\fR\&. .RE .PP .SH "OBJECT LIFE CYCLE" \fBnx::Class\fR provides means to control important stages through which an NX object passes between and including its creation and its destruction: allocation, recreation, deallocation\&. .CS /cls/->create(/instance/) \&.---------------\&. exists? [false] \&.----------------\&. \&.-------------------\&. ---->|Class::create()|----><>---------------->|Class::__alloc()|-----------><>---->|Object::configure()| `---------------' | (1) `----------------' ^ (3) `---------+---------' [true] | | | (4) | \&.-------------------\&. | \&.------------------\&. `->|Class::__recreate()|-------------------------' |/instance/->init()| (2) `-------------------' `------------------' /instance/->destroy() \&.-----------------\&. \&.------------------\&. ---->|Object::destroy()|---->|Class::__dealloc()| `-----------------' (5) `------------------' .CE Object creation is controlled by the factory method \fBcreate\fR, provided by \fBnx::Class\fR to its instance \fIcls\fR\&. \fBcreate\fR produces a new object \fIinstance\fR as an instance of \fIcls\fR in a number of steps\&. .IP [1] If \fIinstance\fR does not represent an existing object, an internal call to \fB__alloc\fR, provided by \fBnx::Class\fR, runs the \fIallocation\fR procedure for a fresh \fIinstance\fR of \fIcls\fR\&. .IP [2] If \fIinstance\fR corresponds to an existing object, the \fIrecreation\fR procedure is triggered by calling \fB__recreate\fR defined by \fBnx::Class\fR\&. .IP [3] The newly allocated or recreated object \fIinstance\fR is then configured by dispatching \fBconfigure\fR, provided by \fBnx::Object\fR, which consumes the configuration options passed into \fBcreate\fR\&. This will establish the instance's initial state, e\&.g\&. by setting object variables and object relations according to the configuration options and corresponding default values\&. .IP [4] Finally, the initialization method \fBinit\fR is dispatched, if available for \fIinstance\fR\&. \fBinit\fR can be defined by \fIcls\fR on behalf of its instance \fIinstance\fR, e\&.g\&. to lay out a class-specific initialization behavior\&. .CS % nx::Class create Foo {:property x} % Foo method init {} {set :y [expr {${:x} + 1}]} % Foo public method bar {} {return ${:y}} % Foo create f1 -x 101 % f1 cget -x 101 % f1 bar 102 .CE .IP Alternatively, the object \fIinstance\fR may define a per-object \fBinit\fR on its own\&. A per-object \fBinit\fR can be chained to a class-level \fBinit\fR using \fBnx::next\fR, just like a regular method\&. .sp Note that the definition of an \fBinit\fR method must contain an empty parameter specification, since \fBinit\fR is always called with an empty argument list\&. .PP Object destruction, such as triggered by an application-level \fBdestroy\fR call (5), is finalized by \fB__dealloc\fR offered by \fBnx::Class\fR\&. .PP In the following, the three built-in procedures --- allocation, recreation, and deallocation --- are explained: .IP \(bu \fIAllocation\fR: \fB__alloc\fR creates a blank object \fIinstance\fR as an instance of \fIcls\fR and returns the fully-qualified \fIinstance\fR\&. \fB__alloc\fR is primarily used internally by \fBcreate\fR to allocate a Tcl memory storage for \fIinstance\fR and to register \fIinstance\fR with the Tcl interpreter as a new command\&. .IP \(bu \fIRecreation\fR: Recreation is the NX scheme for resolving naming conflicts between objects: An object is requested to be created using \fBcreate\fR or \fBnew\fR while an object of an identical object name, e\&.g\&. \fIinstance\fR, already exists: .CS % Object create Bar ::Bar % Object create Bar; # calls Object->__recreate(::Bar, \&.\&.\&.) ::Bar .CE .IP In such a situation, the built-in \fB__recreate\fR first unsets the object state (i\&.e\&., Tcl variables held by the object) and removes relations of the object under recreation with other objects\&. Then, second, standard object initialization is performed by calling \fBconfigure\fR and \fBinit\fR, if any\&. .sp Alternatively, recreation will be performed as a sequence of \fBdestroy\fR and \fBcreate\fR calls in the following recreation scenarios: .RS .IP \(bu An existing class is requested to be recreated as an object\&. .IP \(bu An existing object is requested to be recreated as a class\&. .CS % Object create Bar ::Bar % Class create Bar; # calls Bar->destroy() & Class::create(::Bar, \&.\&.\&.) .CE .IP \(bu An object of an object system other than NX (e\&.g\&. XOTcl2) is asked to be recreated\&. .RE .IP \(bu \fIDeallocation\fR: \fB__dealloc\fR marks an instance \fIinstance\fR of \fIcls\fR for deletion by returning its Tcl memory representation to the Tcl memory pool and by unregistering the corresponding Tcl command with the Tcl interpreter\&. .sp Beware that \fB__dealloc\fR does not necessarily cause the object to be deleted immediately\&. Depending on the lifecycle of the object's environment (e\&.g\&. the Tcl interp interpreter, the containing namespace) and on call references down the callstack, the actual memory freeing/returning operation may occur at a later point\&. .PP The three methods \fB__alloc\fR, \fB__recreate\fR, and \fB__dealloc\fR are internally provided and internally called\&. By default, they are not part of the method interface of \fIcls\fR and cannot be called directly by clients of \fIcls\fR\&. In addition, \fB__alloc\fR, \fB__recreate\fR, and \fB__dealloc\fR are protected from redefinition by a script\&. .PP To extend or to replace the built-in allocation, recreation, and deallocation procedure, the methods \fB__alloc\fR, \fB__recreate\fR, and \fB__dealloc\fR can be refined by providing a custom method implementation: .IP \(bu as a per-object method of \fIcls\fR; .IP \(bu as a method of a per-object mixin class extending \fIcls\fR; .IP \(bu as a method of a per-class mixin class extending \fBnx::Class\fR; .IP \(bu as a method of a subclass specializing \fBnx::Class\fR, from which \fIcls\fR is to be instantiated\&. .PP This custom implementation can redirect to the built-in \fB__alloc\fR, \fB__recreate\fR, and \fB__dealloc\fR, respectively, by using \fBnx::next\fR\&. By providing such a custom implementation, \fB__alloc\fR, \fB__recreate\fR, and \fB__dealloc\fR, respectively, become available as callable methods of \fIcls\fR: .TP \fIcls\fR \fB__alloc\fR \fIinstance\fR .TP \fIcls\fR \fB__recreate\fR \fIinstance\fR ?\fIarg\fR \&.\&.\&.? .TP \fIcls\fR \fB__dealloc\fR \fIinstance\fR .PP .SH COPYRIGHT .nf Copyright (c) 2014-2019 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. .fi ./nsf2.4.0/doc/webclient-xotcl.html000644 000766 000024 00000002030 12161565464 017733 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/comm/webclient.xotcl

    ./apps/comm/webclient.xotcl ./apps/comm/webclient.xotcl


    Package/File Information

    No package provided/required

    Filename: ./apps/comm/webclient.xotcl

    Description: For a sample webclient, see packages/comm/xocomm.test



    Back to index page.

    ./nsf2.4.0/doc/MemStorage-xotcl.html000644 000766 000024 00000001534 12161565463 020031 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/store/MemStorage.xotcl

    ./library/store/MemStorage.xotcl ./library/store/MemStorage.xotcl


    Package/File Information

    No package provided/required

    Filename: ./library/store/MemStorage.xotcl




    Back to index page.

    ./nsf2.4.0/doc/Object.3000644 000766 000024 00000213311 14274463622 015242 0ustar00neumannstaff000000 000000 '\" '\" Generated from file 'Object\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2014-19 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. '\" .TH "nx::Object" 3 2\&.4\&.0 Object "NX API" .\" The -*- nroff -*- definitions below are for supplemental macros used .\" in Tcl/Tk manual entries. .\" .\" .AP type name in/out ?indent? .\" Start paragraph describing an argument to a library procedure. .\" type is type of argument (int, etc.), in/out is either "in", "out", .\" or "in/out" to describe whether procedure reads or modifies arg, .\" and indent is equivalent to second arg of .IP (shouldn't ever be .\" needed; use .AS below instead) .\" .\" .AS ?type? ?name? .\" Give maximum sizes of arguments for setting tab stops. Type and .\" name are examples of largest possible arguments that will be passed .\" to .AP later. If args are omitted, default tab stops are used. .\" .\" .BS .\" Start box enclosure. From here until next .BE, everything will be .\" enclosed in one large box. .\" .\" .BE .\" End of box enclosure. .\" .\" .CS .\" Begin code excerpt. .\" .\" .CE .\" End code excerpt. .\" .\" .VS ?version? ?br? .\" Begin vertical sidebar, for use in marking newly-changed parts .\" of man pages. The first argument is ignored and used for recording .\" the version when the .VS was added, so that the sidebars can be .\" found and removed when they reach a certain age. If another argument .\" is present, then a line break is forced before starting the sidebar. .\" .\" .VE .\" End of vertical sidebar. .\" .\" .DS .\" Begin an indented unfilled display. .\" .\" .DE .\" End of indented unfilled display. .\" .\" .SO ?manpage? .\" Start of list of standard options for a Tk widget. The manpage .\" argument defines where to look up the standard options; if .\" omitted, defaults to "options". The options follow on successive .\" lines, in three columns separated by tabs. .\" .\" .SE .\" End of list of standard options for a Tk widget. .\" .\" .OP cmdName dbName dbClass .\" Start of description of a specific option. cmdName gives the .\" option's name as specified in the class command, dbName gives .\" the option's name in the option database, and dbClass gives .\" the option's class in the option database. .\" .\" .UL arg1 arg2 .\" Print arg1 underlined, then print arg2 normally. .\" .\" .QW arg1 ?arg2? .\" Print arg1 in quotes, then arg2 normally (for trailing punctuation). .\" .\" .PQ arg1 ?arg2? .\" Print an open parenthesis, arg1 in quotes, then arg2 normally .\" (for trailing punctuation) and then a closing parenthesis. .\" .\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b .\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out .\" # BS - start boxed text .\" # ^y = starting y location .\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. .\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. .\" # VS - start vertical sidebar .\" # ^Y = starting y location .\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. .\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. .\" # Special macro to handle page bottom: finish off current .\" # box/sidebar if in box/sidebar mode, then invoked standard .\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. .\" # DS - begin display .de DS .RS .nf .sp .. .\" # DE - end display .de DE .fi .RE .sp .. .\" # SO - start of list of standard options .de SO 'ie '\\$1'' .ds So \\fBoptions\\fR 'el .ds So \\fB\\$1\\fR .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. .\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\*(So manual entry for details on the standard options. .. .\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. .\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. .\" # CE - end code excerpt .de CE .fi .RE .. .\" # UL - underline word .de UL \\$1\l'|0\(ul'\\$2 .. .\" # QW - apply quotation marks to word .de QW .ie '\\*(lq'"' ``\\$1''\\$2 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\$2 .. .\" # PQ - apply parens and quotation marks to word .de PQ .ie '\\*(lq'"' (``\\$1''\\$2)\\$3 .\"" fix emacs highlighting .el (\\*(lq\\$1\\*(rq\\$2)\\$3 .. .\" # QR - quoted range .de QR .ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3 .. .\" # MT - "empty" string .de MT .QW "" .. .BS .SH NAME nx::Object \- API reference of the base class in the NX object system .SH SYNOPSIS \fBnx::Object\fR \fBcreate\fR \fIobj\fR ?\fB-object-mixins\fR \fImixinSpec\fR? ?\fB-class\fR \fInewClassName\fR? ?\fB-object-filters\fR \fIfilterSpec\fR? ?\fIinitBlock\fR? .sp \fBnx::Object\fR \fBnew\fR ?\fB-object-mixins\fR \fImixinSpec\fR? ?\fB-class\fR \fInewClassName\fR? ?\fB-object-filters\fR \fIfilterSpec\fR? ?\fIinitBlock\fR? .sp \fIobj\fR ?\fBpublic\fR | \fBprivate\fR | \fBprotected\fR? \fBobject alias\fR ?\fB-debug\fR? ?\fB-deprecated\fR? \fImethodName\fR ?\fB-returns\fR \fIvalueChecker\fR? ?\fB-frame\fR \fBobject\fR | \fBmethod\fR? \fIcmdName\fR .sp \fIobj\fR \fBcget\fR \fIconfigurationOption\fR .sp \fIobj\fR \fBconfigure\fR ?\fIconfigurationOption\fR \fIvalue\fR \&.\&.\&.? .sp \fIobj\fR \fBcontains\fR ?-withnew \fItrueFalse\fR? ?-object \fIobjectName\fR? ?-class \fIclassName\fR? \fIcmds\fR .sp \fIobj\fR \fBcopy\fR ?\fInewObjectName\fR? .sp \fIobj\fR \fBdelete object\fR \fIfeature\fR \fIarg\fR .sp \fIobj\fR \fBdestroy\fR .sp \fIobj\fR \fBeval\fR \fIarg\fR ?\fIarg\fR \&.\&.\&.? .sp \fIobj\fR \fBobject\fR \fBfilters\fR \fIsubmethod\fR ?\fIarg\fR \&.\&.\&.? .sp \fIobj\fR ?\fBpublic\fR | \fBprotected\fR | \fBprivate\fR? \fBobject forward\fR ?\fB-debug\fR? ?\fB-deprecated\fR? \fImethodName\fR ?\fB-prefix\fR \fIprefixName\fR? ?\fB-frame\fR \fBobject\fR? ?\fB-returns\fR \fIvalueChecker\fR? ?\fB-verbose\fR? ?\fItarget\fR? ?\fIarg\fR \&.\&.\&.? .sp \fIobj\fR \fBinfo baseclass\fR .sp \fIobj\fR \fBinfo children\fR ?\fB-type\fR \fIclassName\fR? ?\fIpattern\fR? .sp \fIobj\fR \fBinfo class\fR .sp \fIobj\fR \fBinfo has\fR ?\fBmixin\fR | \fBnamespace\fR | \fBtype\fR? ?\fIarg\fR \&.\&.\&.? .sp \fIobj\fR \fBinfo lookup\fR \fIsubmethod\fR ?\fIarg\fR \&.\&.\&.? .sp \fIobj\fR \fBinfo name\fR .sp \fIobj\fR \fBinfo info\fR ?\fB-asList\fR? .sp \fIobj\fR \fBinfo object filters\fR ?\fB-guards\fR? ?\fIpattern\fR? .sp \fIobj\fR \fBinfo object method\fR \fIoption\fR \fImethodName\fR .sp \fIobj\fR \fBinfo object methods\fR ?\fB-callprotection\fR \fIlevel\fR? ?\fB-type\fR \fImethodType\fR? ?\fB-path\fR? ?\fInamePattern\fR? .sp \fIobj\fR \fBinfo object mixins\fR ?\fB-guards\fR? ?\fIpattern\fR? .sp \fIobj\fR \fBinfo object slots\fR ?\fB-type\fR \fIclassName\fR? ?\fIpattern\fR? .sp \fIobj\fR \fBinfo object variables\fR ?\fIpattern\fR? .sp \fIobj\fR \fBinfo parent\fR .sp \fIobj\fR \fBinfo precedence\fR ?\fB-intrinsic\fR? ?\fIpattern\fR? .sp \fIobj\fR \fBinfo variable\fR \fIoption\fR \fIhandle\fR .sp \fIobj\fR \fBinfo vars\fR ?\fIpattern\fR? .sp \fIobj\fR ?\fBpublic\fR | \fBprotected\fR | \fBprivate\fR? \fBobject method\fR ?\fB-debug\fR? ?\fB-deprecated\fR? \fIname\fR \fIparameters\fR ?\fB-checkalways\fR? ?\fB-returns\fR \fIvalueChecker\fR? \fIbody\fR .sp \fIobj\fR \fBmove\fR \fInewObjectName\fR .sp \fIobj\fR \fBobject mixins\fR \fIsubmethod\fR ?\fIarg\fR \&.\&.\&.? .sp \fIobj\fR \fBobject property\fR ?\fB-accessor\fR \fBpublic\fR | \fBprotected\fR | \fBprivate\fR? ?\fB-class\fR \fIclassName\fR? ?\fB-configurable\fR \fItrueFalse\fR? ?\fB-incremental\fR? ?\fB-nocomplain\fR? ?\fB-trace\fR \fBset\fR | \fBget\fR | \fBdefault\fR? \fIspec\fR ?\fIinitBlock\fR? .sp \fIobj\fR \fBrequire namespace\fR .sp \fIobj\fR \fBrequire\fR ?\fBpublic\fR | \fBprotected\fR | \fBprivate\fR? \fBobject method\fR \fImethodName\fR .sp \fIobj\fR \fBunknown\fR \fIunknownMethodName\fR ?\fIarg\fR \&.\&.\&.? .sp \fIobj\fR \fBuplevel\fR ?\fIlevel\fR? \fIarg1\fR ?\fIarg2\fR \&.\&.\&.? .sp \fIobj\fR \fBupvar\fR ?\fIlevel\fR? \fIotherVar1\fR \fIlocalVar1\fR ?\fIotherVar2\fR \fIlocalVar2\fR \&.\&.\&.? .sp \fIobj\fR \fBobject variable\fR ?\fB-accessor\fR \fBpublic\fR | \fBprotected\fR | \fBprivate\fR? ?\fB-incremental\fR? ?\fB-class\fR \fIclassName\fR? ?\fB-configurable\fR \fItrueFalse\fR? ?\fB-initblock\fR \fIscript\fR? ?\fB-trace\fR \fBset\fR | \fBget\fR | \fBdefault\fR? ?\fB-nocomplain\fR? \fIspec\fR ?\fIdefaultValue\fR? .sp .BE .SH DESCRIPTION .PP \fBnx::Object\fR is the base class of the NX object system\&. All objects defined in NX are (direct or indirect) instances of this base class\&. The methods provided by the \fBnx::Object\fR base class are available to all objects and to all classes defined in NX\&. .CS +---------+ | ::nx::* | +---------+--------------------------------------Y | | | +---------+ instance of +----------+ | | | |<\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.| | | | | Class | | Object | | | | |\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.>| | | | +----+----+ subclass of +-----+----+ | | ^ ^ ^ | instance\&.|\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.|\&.\&.\&.\&.|\&.\&.\&.\&.\&.\&.\&./ of | | | +-----+-----+ subclass of | | instance | |\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.| | of | /cls/ | (by default) | | | | +-----------+ | ^ | instance |\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.(xor)\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.| of | +-----------+ | |\&.\&.\&.\&.\&.\&.\&.\&.\&.| |\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.| | /obj/ | | | +-----------+ .CE NX allows for creating and for using objects (e\&.g\&. \fIobj\fR) which are instantiated from the base class \fBnx::Object\fR directly\&. Typical use cases are singletons and anonymous, inline objects\&. In such use cases, NX does not require creating an intermediate application class (e\&.g\&. \fIcls\fR), which specializes the base class \fBnx::Object\fR by default, beforehand\&. .PP Objects (e\&.g\&. \fIobj\fR) which are creating by instantiating a previously defined application class (e\&.g\&. \fIcls\fR) are indirect instances of \fBnx::Object\fR\&. .PP Direct instances of \fBnx::Object\fR can be created as follows: .TP \fBnx::Object\fR \fBcreate\fR \fIobj\fR ?\fB-object-mixins\fR \fImixinSpec\fR? ?\fB-class\fR \fInewClassName\fR? ?\fB-object-filters\fR \fIfilterSpec\fR? ?\fIinitBlock\fR? .sp To create a direct instance of \fBnx::Object\fR having an explicit name \fIobj\fR, use \fBcreate\fR on \fBnx::Object\fR\&. Note that \fBcreate\fR is defined by \fBnx::Class\fR and is available to \fBnx::Object\fR being an instance of \fBnx::Class\fR\&. This way, singleton objects can be created, for example\&. .TP \fBnx::Object\fR \fBnew\fR ?\fB-object-mixins\fR \fImixinSpec\fR? ?\fB-class\fR \fInewClassName\fR? ?\fB-object-filters\fR \fIfilterSpec\fR? ?\fIinitBlock\fR? To create a direct instance of \fBnx::Object\fR having an automatically assigned, implicit object name, use \fBnew\fR on \fBnx::Object\fR\&. Note that \fBnew\fR is defined by \fBnx::Class\fR and is available to \fBnx::Object\fR being an instance of \fBnx::Class\fR\&. Using \fBnew\fR allows for creating anonymous, inline objects, for example\&. .PP The configuration options for direct and indirect instances of \fBnx::Object\fR, which can be passed when calling \fBcreate\fR and \fBnew\fR, are documented in the subsequent section\&. .SH "CONFIGURATION OPTIONS FOR INSTANCES OF NX::OBJECT" .PP Configuration options can be used for configuring objects during their creation by passing the options as non-positional arguments into calls of \fBnew\fR and \fBcreate\fR (see \fBnx::Class\fR)\&. An existing object can be queried for its current configuration using \fBcget\fR and it can be re-configured using \fBconfigure\fR\&. Legal configuration options are: .TP \fB-class\fR ?\fIclassName\fR? Retrieves the current class of the object or sets the object's class to \fIclassName\fR, if provided\&. .TP \fB-object-filters\fR ?\fIfilterMethods\fR? Retrieves the list of currently active per-object filter methods or sets a list of per-object filter methods, if \fIfilterMethods\fR is provided\&. .TP \fB-object-mixins\fR ?\fImixinSpecs\fR? If \fImixinSpecs\fR is not specified, retrieves the list of currently active per-object mixin specifications\&. If \fImixinSpecs\fR is specified, sets a list of per-object mixin specifications to become active\&. mixin classes are returned or set in terms of a list of mixin specifications\&. .PP .SH "METHODS FOR INSTANCES OF NX::OBJECT" .TP \fBalias\fR .RS .TP \fIobj\fR ?\fBpublic\fR | \fBprivate\fR | \fBprotected\fR? \fBobject alias\fR ?\fB-debug\fR? ?\fB-deprecated\fR? \fImethodName\fR ?\fB-returns\fR \fIvalueChecker\fR? ?\fB-frame\fR \fBobject\fR | \fBmethod\fR? \fIcmdName\fR Define an alias method for the given object\&. The resulting method registers a pre-existing Tcl command \fIcmdName\fR under the (alias) name \fImethodName\fR with the object\&. If \fIcmdName\fR refers to another \fBmethod\fR, the corresponding argument should be a valid method handle\&. If a Tcl command (e\&.g\&., a \fBproc\fR), the argument should be a fully qualified Tcl command name\&. If aliasing a subcommand (e\&.g\&., \fBarray exists\fR) of a Tcl namespace ensemble (e\&.g\&., \fBarray\fR), \fIcmdName\fR must hold the fully qualified subcommand name (and not the ensemble name of the subcommand)\&. .sp As for a regular \fBobject method\fR, \fB-returns\fR allows for setting a value checker on the values returned by the aliased command \fIcmdName\fR\&. .sp When creating an alias method for a \fIC-implemented\fR Tcl command (i\&.e\&., command defined using the Tcl/NX C-API), \fB-frame\fR sets the scope for variable references used in the aliased command\&. If the provided value is \fBobject\fR, then variable references will be resolved in the context of the called object, i\&.e\&., the object upon which the alias method is invoked, as if they were object variables\&. There is no need for using the colon-prefix notation for identifying object variables\&. If the value is \fBmethod\fR, then the aliased command will be executed as a regular method call\&. The command is aware of its called-object context; i\&.e\&., it can resolve \fB::nx::self\fR\&. In addition, the alias method has access to the method-call context (e\&.g\&., \fBnx::next\fR)\&. If \fB-frame\fR is omitted, and by default, the variable references will resolve in the context of the caller of the alias method\&. .sp To express deprecation of the alias method \fImethodName\fR, set the \fB-deprecated\fR flag\&. Deprecated methods remain usable from client code, but their usage will be signaled to the developer and/or can be tracked using \fB::nsf::deprecated\fR\&. To register \fImethodName\fR with the debugger, set the \fB-debug\fR flag\&. Entering and exiting a method, which was flagged for debugging, is recorded by calling the redefinable callback procs \fB::nsf::debug::call\fR and \fB::nsf::debug::exit\fR, respectively\&. By default, these callbacks forward to \fB::nsf::log\fR, which can also be customized at the script level\&. .RE .TP \fBcget\fR .RS .TP \fIobj\fR \fBcget\fR \fIconfigurationOption\fR The method is used to obtain the current value of \fIconfigurationOption\fR for \fIobj\fR\&. The configuration options available for querying through \fBcget\fR are determined by the configurable properties defined by the class hierarchy of \fIobj\fR\&. The queryable configuration options for \fIobj\fR can be obtained by calling \fBinfo lookup syntax configure\fR\&. The \fIconfigurationOption\fR can be set and modified using \fBconfigure\fR\&. .CS % nx::Object create obj ::obj % ::obj info lookup syntax configure ?-object-mixins /mixinreg \&.\&.\&./? ?-class /class/? ?-object-filters /filterreg \&.\&.\&./? ?/__initblock/? % ::obj cget -class ::nx::Object .CE .RE .TP \fBconfigure\fR .RS .TP \fIobj\fR \fBconfigure\fR ?\fIconfigurationOption\fR \fIvalue\fR \&.\&.\&.? This method sets configuration options on an object\&. The configuration options available for setting on \fIobj\fR are determined by the configurable properties defined by the class hierarchy of \fIobj\fR\&. The settable configuration options for \fIobj\fR can be obtained by calling \fBinfo lookup syntax configure\fR\&. Furthermore, \fBconfigure\fR is also called during object construction\&. Under object construction, it receives the arguments passed into calls of \fBcreate\fR and \fBnew\fR\&. Options set using \fBconfigure\fR can be retrieved using \fBcget\fR\&. .CS % nx::Class create Foo {:property x} ::Foo % Foo create f1 -x 101 ::f1 % f1 cget -x 101 % f1 configure -x 200 % f1 cget -x 200 .CE .RE .TP \fBcontains\fR .RS .TP \fIobj\fR \fBcontains\fR ?-withnew \fItrueFalse\fR? ?-object \fIobjectName\fR? ?-class \fIclassName\fR? \fIcmds\fR This method acts as a builder for nested object structures\&. Object and class construction statements passed to this method as its last argument \fIcmds\fR are evaluated in a way so that the receiver object \fIobj\fR becomes the parent of the newly constructed objects and classes\&. This is realized by setting explicitly the namespace for constructing relatively named objects\&. Fully qualified object names in \fIcmds\fR evade the nesting\&. .sp \fB-withnew\fR requests the automatic rescoping of objects created using \fBnew\fR so that they become nested into the receiver object \fIobj\fR, rather than being created in the default namespace for autonamed objects (i\&.e\&., ::nsf)\&. If turned off, autonamed objects do not become children of \fIobj\fR\&. .sp The parent object \fIobjectName\fR to be used instead of \fIobj\fR can be specified using \fB-object\fR\&. If this explicitly set parent object does not exist prior to calling \fBcontains\fR, it will be created on the fly as a direct instance of \fBnx::Object\fR\&. Alternatively, using \fB-class\fR, a class \fIclassName\fR other than \fBnx::Object\fR for the on-the-fly creation of \fIobjectName\fR can be provided\&. .CS % nx::Class create Window { :contains { # # Become children of Window, implicitly # nx::Class create Header; # Window::Header nx::Object create Panel; # Window::Panel } # # Explicitly declared a child of Window using [self] # nx::Class create [self]::Slider; # Window::Slider # # Fully-qualified objects do not become nested # nx::Class create ::Door; # ::Door } ::Window % ::Window info children ::Window::Panel ::Window::Header ::Window::Slider .CE .RE .TP \fBcopy\fR .RS .TP \fIobj\fR \fBcopy\fR ?\fInewObjectName\fR? Creates a full and deep copy of a source object \fIobj\fR\&. The object's copy features all structural and behavioral properties of the source object, including object variables, per-object methods, nested objects, slot objects, namespaces, filters, mixins, and traces\&. The copy can be named explicitly, if \fInewObjectName\fR is provided, or it is named automatically (in the spirit of \fBnew\fR of \fBnx::Class\fR)\&. .RE .TP \fBdelete\fR .RS .TP \fIobj\fR \fBdelete object\fR \fIfeature\fR \fIarg\fR This method serves as the equivalent to Tcl's \fBrename\fR for removing structural (properties, variables) and behavioral features (methods) of the object: .TP \fIobj\fR \fBdelete object property\fR \fIpropertyName\fR .TP \fIobj\fR \fBdelete object variable\fR \fIvariableName\fR .TP \fIobj\fR \fBdelete object method\fR \fImethodName\fR Removes a property \fIpropertyName\fR, variable \fIvariableName\fR, and method \fImethodName\fR, respectively, previously defined for the scope of the object\&. .sp \fBdelete object method\fR can be equally used for removing regular methods (see \fBobject method\fR), an alias method (see \fBobject alias\fR), and a forwarder method (see \fBobject forward\fR)\&. .RE .TP \fBdestroy\fR .RS .TP \fIobj\fR \fBdestroy\fR This method allows for explicitly destructing an object \fIobj\fR, potentially prior to \fIobj\fR being destroyed by the object system (e\&.g\&. during the shutdown of the object system upon calling \fBexit\fR): .CS [nx::Object new] destroy .CE .IP By providing a custom implementation of \fBdestroy\fR, the destruction procedure of \fIobj\fR can be customized\&. Typically, once the application-specific destruction logic has completed, a custom \fBdestroy\fR will trigger the actual, physical object destruction via \fBnext\fR\&. .CS % [nx::Object create obj { :public method destroy {} { puts "destroying [self]" next; # physical destruction } }] destroy destroying ::obj .CE .IP A customized object-destruction scheme can be made shared between the instances of a class, by defining the custom \fBdestroy\fR for an application class: .CS % nx::Class create Foo { :method destroy {} { puts "destroying [self]" next; # physical destruction } } ::Foo % Foo create f1 ::f1 % f1 destroy destroying ::f1 .CE .IP Physical destruction is performed by clearing the in-memory object storage of \fIobj\fR\&. This is achieved by passing \fIobj\fR into a call to \fBdealloc\fR provided by \fBnx::Class\fR\&. A near, scripted equivalent to the C-implemented \fBdestroy\fR provided by \fBnx::Object\fR would look as follows: .CS % Object method destroy {} { [:info class] dealloc [self] } .CE .IP Note, however, that \fBdestroy\fR is protected against application-level redefinition\&. Trying to evaluate the above script snippet yields: .CS refuse to overwrite protected method 'destroy'; derive e\&.g\&. a subclass! .CE .IP A custom \fBdestroy\fR must be provided as a refinement in a subclass of \fBnx::Object\fR or in a mixin class\&. .RE .TP \fBeval\fR .RS .TP \fIobj\fR \fBeval\fR \fIarg\fR ?\fIarg\fR \&.\&.\&.? Evaluates a special Tcl script for the scope of \fIobj\fR in the style of Tcl's \fBeval\fR\&. There are, however, notable differences to the standard \fBeval\fR: In this script, the colon-prefix notation is available to dispatch to methods and to access variables of \fIobj\fR\&. Script-local variables, which are thrown away once the evaluation of the script has completed, can be defined to store intermediate results\&. .CS % nx::Object create obj { :object property {bar 1} :public object method foo {x} { return $x } } ::obj % ::obj eval { set y [:foo ${:bar}] } 1 .CE .RE .TP \fBfilters\fR .RS .TP \fIobj\fR \fBobject\fR \fBfilters\fR \fIsubmethod\fR ?\fIarg\fR \&.\&.\&.? Accesses and modifies the list of methods which are registered as filters with \fIobj\fR using a specific setter or getter \fIsubmethod\fR: .RS .TP \fIobj\fR \fBobject\fR \fBfilters add\fR \fIspec\fR ?\fIindex\fR? Inserts a single filter into the current list of filters of \fIobj\fR\&. Using \fIindex\fR, a position in the existing list of filters for inserting the new filter can be set\&. If omitted, \fIindex\fR defaults to the list head (0)\&. .TP \fIobj\fR \fBobject\fR \fBfilters clear\fR Removes all filters from \fIobj\fR and returns the list of removed filters\&. Clearing is equivalent to passing an empty list for \fIfilterSpecList\fR to \fBobject\fR \fBfilter set\fR\&. .TP \fIobj\fR \fBobject\fR \fBfilters delete\fR ?\fB-nocomplain\fR? \fIspecPattern\fR Removes a single filter from the current list of filters of \fIobj\fR whose spec matches \fIspecPattern\fR\&. \fIspecPattern\fR can contain special matching chars (see \fBstring match\fR)\&. \fBobject\fR \fBfilters delete\fR will throw an error if there is no matching filter, unless \fB-nocomplain\fR is set\&. .TP \fIobj\fR \fBobject\fR \fBfilters get\fR Returns the list of current filter specifications registered for \fIobj\fR\&. .TP \fIobj\fR \fBobject\fR \fBfilters guard\fR \fImethodName\fR ?\fIexpr\fR? If \fIexpr\fR is specified, registers a guard expression \fIexpr\fR with a filter \fImethodName\fR\&. This requires that the filter \fImethodName\fR has been previously set using \fBobject\fR \fBfilters set\fR or added using \fBobject\fR \fBfilters add\fR\&. \fIexpr\fR must be a valid Tcl expression (see \fBexpr\fR)\&. An empty string for \fIexpr\fR will clear the currently registered guard expression for filter \fImethodName\fR\&. .sp If \fIexpr\fR is omitted, returns the guard expression set on the filter \fImethodName\fR defined for \fIobj\fR\&. If none is available, an empty string will be returned\&. .TP \fIobj\fR \fBobject\fR \fBfilters methods\fR ?\fIpattern\fR? If \fIpattern\fR is omitted, returns all filter names which are defined by \fIobj\fR\&. By specifying \fIpattern\fR, the returned filters can be limited to those whose names match \fIpatterns\fR (see \fBstring match\fR)\&. .TP \fIobj\fR \fBobject\fR \fBfilters set\fR \fIfilterSpecList\fR \fIfilterSpecList\fR takes a list of filter specs, with each spec being itself either a one-element or a two-element list: \fImethodName\fR ?-guard \fIguardExpr\fR?\&. \fImethodName\fR identifies an existing method of \fIobj\fR which becomes registered as a filter\&. If having three elements, the third element \fIguardExpr\fR will be stored as a guard expression of the filter\&. This guard expression must be a valid Tcl expression (see \fBexpr\fR)\&. \fIexpr\fR is evaluated when \fIobj\fR receives a message to determine whether the filter should intercept the message\&. Guard expressions allow for realizing context-dependent or conditional filter composition\&. .RE .IP Every \fImethodName\fR in a \fIspec\fR must resolve to an existing method in the scope of the object\&. To access and to manipulate the list of filters of \fIobj\fR, \fBcget\fR|\fBconfigure\fR \fB-object-filters\fR can also be used\&. .RE .TP \fBforward\fR .RS .TP \fIobj\fR ?\fBpublic\fR | \fBprotected\fR | \fBprivate\fR? \fBobject forward\fR ?\fB-debug\fR? ?\fB-deprecated\fR? \fImethodName\fR ?\fB-prefix\fR \fIprefixName\fR? ?\fB-frame\fR \fBobject\fR? ?\fB-returns\fR \fIvalueChecker\fR? ?\fB-verbose\fR? ?\fItarget\fR? ?\fIarg\fR \&.\&.\&.? Define a forward method for the given object\&. The definition of a forward method registers a predefined, but changeable list of forwarder arguments under the (forwarder) name \fImethodName\fR\&. Upon calling the forward method, the forwarder arguments are evaluated as a Tcl command call\&. That is, if present, \fItarget\fR is interpreted as a Tcl command (e\&.g\&., a Tcl \fBproc\fR or an object) and the remainder of the forwarder arguments \fIarg\fR as arguments passed into this command\&. The actual method arguments to the invocation of the forward method itself are appended to the list of forwarder arguments\&. If \fItarget\fR is omitted, the value of \fImethodName\fR is implicitly set and used as \fItarget\fR\&. This way, when providing a fully-qualified Tcl command name as \fImethodName\fR without \fItarget\fR, the unqualified \fImethodName\fR (\fBnamespace tail\fR) is used as the forwarder name; while the fully-qualified one serves as the \fItarget\fR\&. .sp As for a regular \fBobject method\fR, \fB-returns\fR allows for setting a value checker on the values returned by the resulting Tcl command call\&. When passing \fBobject\fR to \fB-frame\fR, the resulting Tcl command is evaluated in the context of the object receiving the forward method call\&. This way, variable names used in the resulting execution of a command become resolved as object variables\&. .sp To express deprecation of the forward method \fImethodName\fR, set the \fB-deprecated\fR flag\&. Deprecated methods remain usable from client code, but their usage will be signaled to the developer and/or can be tracked using \fB::nsf::deprecated\fR\&. To register \fImethodName\fR with the debugger, set the \fB-debug\fR flag\&. Entering and exiting a method, which was flagged for debugging, is recorded by calling the redefinable callback procs \fB::nsf::debug::call\fR and \fB::nsf::debug::exit\fR, respectively\&. By default, these callbacks forward to \fB::nsf::log\fR, which can also be customized at the script level\&. .sp The list of forwarder arguments \fIarg\fR can contain as its elements a mix of literal values and placeholders\&. Placeholders are prefixed with a percent symbol (%) and substituted for concrete values upon calling the forward method\&. These placeholders allow for constructing and for manipulating the arguments to be passed into the resulting command call on the fly: .RS .IP \(bu \fB%method\fR becomes substituted for the name of the forward method, i\&.e\&. \fImethodName\fR\&. .IP \(bu \fB%self\fR becomes substituted for the name of the object receiving the call of the forward method\&. .IP \(bu \fB%1\fR becomes substituted for the first method argument passed to the call of forward method\&. This requires, in turn, that \fIat least\fR one argument is passed along with the method call\&. .sp Alternatively, \fB%1\fR accepts an optional argument \fIdefaults\fR: {\fB%1\fR \fIdefaults\fR}\&. \fIdefaults\fR must be a valid Tcl list of two elements\&. For the first element, \fB%1\fR is substituted when there is no first method argument which can be consumed by \fB%1\fR\&. The second element is inserted upon availability of a first method argument with the consumed argument being appended right after the second list element\&. This placeholder is typically used to define a pair of getter/setter methods\&. .IP \(bu {\fB%@\fR\fIindex\fR \fIvalue\fR} becomes substituted for the specified \fIvalue\fR at position \fIindex\fR in the forwarder-arguments list, with \fIindex\fR being either a positive integer, a negative integer, or the literal value \fBend\fR (such as in Tcl's \fBlindex\fR)\&. Positive integers specify a list position relative to the list head, negative integers give a position relative to the list tail\&. Indexes for positioning placeholders in the definition of a forward method are evaluated from left to right and should be used in ascending order\&. .sp Note that \fIvalue\fR can be a literal or any of the placeholders (e\&.g\&., \fB%method\fR, \fB%self\fR)\&. Position prefixes are exempted, they are evaluated as \fB%\fR\fIcmdName\fR-placeholders in this context\&. .IP \(bu {\fB%argclindex\fR \fIlist\fR} becomes substituted for the \fIn\fRth element of the provided \fIlist\fR , with \fIn\fR corresponding to the number of method arguments passed to the forward method call\&. .IP \(bu \fB%%\fR is substituted for a single, literal percent symbol (%)\&. .IP \(bu \fB%\fR\fIcmdName\fR is substituted for the value returned from executing the Tcl command \fIcmdName\fR\&. To pass arguments to \fIcmdName\fR, the placeholder should be wrapped into a Tcl \fBlist\fR: {\fB%\fR\fIcmdName\fR ?\fIarg\fR \&.\&.\&.?}\&. .sp Consider using fully-qualified Tcl command names for \fIcmdName\fR to avoid possible name conflicts with the predefined placeholders, e\&.g\&., \fB%self\fR vs\&. %\fB::nx::self\fR\&. .RE .sp To disambiguate the names of subcommands or methods, which potentially become called by a forward method, a prefix \fIprefixName\fR can be set using \fB-prefix\fR\&. This prefix is prepended automatically to the argument following \fItarget\fR (i\&.e\&., a second argument), if present\&. If missing, \fB-prefix\fR has no effect on the forward method call\&. .sp To inspect and to debug the conversions performed by the above placeholders, setting the switch \fB-verbose\fR will have the command list to be executed (i\&.e\&., after substitution) printed using \fB::nsf::log\fR (debugging level: \fBnotice\fR) upon calling the forward method\&. .RE .TP \fBinfo\fR .RS .TP \fIobj\fR \fBinfo baseclass\fR Returns the base class of \fIobj\fR\&. The base class is the class from which all NX objects are instantiated directly or indirectly (typically \fBnx::Object\fR)\&. .TP \fIobj\fR \fBinfo children\fR ?\fB-type\fR \fIclassName\fR? ?\fIpattern\fR? Retrieves the list of nested (or aggregated) objects of \fIobj\fR\&. The resulting list contains the fully qualified names of the nested objects\&. If \fB-type\fR is set, only nested objects which are direct or indirect instances of class \fIclassName\fR are returned\&. Using \fIpattern\fR, only nested objects whose names match \fIpattern\fR are returned\&. The \fIpattern\fR string can contain special matching characters (see \fBstring match\fR)\&. This method allows for introspecting on \fBcontains\fR\&. .TP \fIobj\fR \fBinfo class\fR Returns the fully qualified name of the current \fBnx::Class\fR of \fIobj\fR\&. In case of re-classification (see \fBconfigure\fR), the returned class will be different from the \fBnx::Class\fR from which \fIobj\fR was originally instantiated using \fBcreate\fR or \fBnew\fR\&. .TP \fIobj\fR \fBinfo has\fR ?\fBmixin\fR | \fBnamespace\fR | \fBtype\fR? ?\fIarg\fR \&.\&.\&.? .RS .TP \fIobj\fR \fBinfo has mixin\fR \fIclassName\fR Verifies whether \fIobj\fR has a given \fBnx::Class\fR \fIclassName\fR registered as a mixin class (returns: \fBtrue\fR) or not (returns: \fBfalse\fR)\&. .TP \fIobj\fR \fBinfo has namespace\fR Checks whether the object has a companion Tcl namespace (returns: \fBtrue\fR) or not (returns: \fBfalse\fR)\&. The namespace could have been created using, for example, \fBobject require namespace\fR\&. .TP \fIobj\fR \fBinfo has type\fR \fIclassName\fR Tests whether the \fBnx::Class\fR \fIclassName\fR is a type of the object (returns: \fBtrue\fR) or not (returns: \fBfalse\fR)\&. That is, the method checks whether the object is a direct instance of \fIclassName\fR or an indirect instance of one of the superclasses of \fIclassName\fR\&. .RE .TP \fIobj\fR \fBinfo lookup\fR \fIsubmethod\fR ?\fIarg\fR \&.\&.\&.? A collection of submethods to retrieve structural features (e\&.g\&. configuration options, slot objects) and behavioral features (e\&.g\&. methods, filters) available for \fIobj\fR from the perspective of a client to \fIobj\fR\&. Features provided by \fIobj\fR itself and by the classes in its current linearization list are considered\&. .RS .TP \fIobj\fR \fBinfo lookup filter\fR \fIname\fR Returns the method handle for the filter method \fIname\fR, if currently registered\&. If there is no filter \fIname\fR registered, an empty string is returned\&. .TP \fIobj\fR \fBinfo lookup filters\fR ?\fB-guards\fR? ?\fInamePattern\fR? Returns the method handles of all filters which are active on \fIobj\fR\&. By turning on the switch \fB-guards\fR, the corresponding guard expressions, if any, are also reported for each filter as a three-element list: \fImethodHandle\fR -guard \fIguardExpr\fR\&. The returned filters can be limited to those whose names match \fInamePattern\fR (see \fBstring match\fR)\&. .TP \fIobj\fR \fBinfo lookup method\fR \fIname\fR Returns the method handle for a method \fIname\fR if a so-named method can be invoked on \fIobj\fR\&. If there is no method \fIname\fR, an empty string is returned\&. .TP \fIobj\fR \fBinfo lookup methods\fR ?\fInamePattern\fR? Returns the names of all methods (including aliases and forwarders) which can be invoked on \fIobj\fR\&. The returned methods can be limited to those whose names match \fInamePattern\fR (see \fBstring match\fR)\&. .TP \fIobj\fR \fBinfo lookup mixins\fR ?\fB-guards\fR? ?\fInamePattern\fR? Returns the object names of all mixin classes which are currently active on \fIobj\fR\&. By turning on the switch \fB-guards\fR, the corresponding guard expressions, if any, are also reported as a three-element list for each mixin class: \fIclassName\fR -guard \fIguardExpr\fR\&. The returned mixin classes can be limited to those whose names match \fInamePattern\fR (see \fBstring match\fR)\&. .TP \fIobj\fR \fBinfo lookup parameters\fR \fImethodName\fR ?\fInamePattern\fR? Returns the parameter specification of the method \fImethodName\fR callable on \fIobj\fR as a list of parameter names and type specifications\&. The resulting parameter specification can be limited to those parameters whose names match \fInamePattern\fR (see \fBstring match\fR)\&. .TP \fIobj\fR \fBinfo lookup slots\fR ?\fB-type\fR \fIclassName\fR? ?\fB-source\fR all | application | system? ?\fInamePattern\fR? Returns the command names of all slot objects responsible for managing properties, variables, and relations of \fIobj\fR\&. The returned slot objects can be limited according to any or a combination of the following criteria: First, slot objects can be filtered based on their command names matching \fInamePattern\fR (see \fBstring match\fR)\&. Second, \fB-type\fR allows one to select slot objects which are instantiated from a subclass \fIclassName\fR of \fBnx::Slot\fR (default: \fBnx::Slot\fR) \&. Third, \fB-source\fR restricts slot objects returned according to their provenance in either the NX \fIsystem\fR classes or the \fIapplication\fR classes present in the linearization list of \fIobj\fR (default: \fIall\fR)\&. .sp To extract details of each slot object, use the \fBinfo\fR submethods available for each slot object\&. .TP \fIobj\fR \fBinfo lookup syntax\fR \fImethodName\fR ?\fInamePattern\fR? Returns the method parameters of the method \fImethodName\fR callable on \fIobj\fR as a concrete-syntax description to be used in human-understandable messages (e\&.g\&., errors or warnings, documentation strings)\&. The result can be limited to those parameters matching the \fInamePattern\fR (see \fBstring match\fR)\&. .TP \fIobj\fR \fBinfo lookup variables\fR Returns the command names of all slot objects responsible for managing properties and variables of \fIobj\fR, if provided by \fIobj\fR or the classes in the linearization list of \fIobj\fR\&. .sp This is equivalent to calling: \fIobj\fR \fBinfo lookup slots\fR -type ::nx::VariableSlot -source all ?\fInamePattern\fR?\&. .sp To extract details of each slot object, use the \fBinfo\fR submethods available for each slot object\&. .RE .TP \fIobj\fR \fBinfo name\fR Returns the unqualified name of an object, i\&.e\&., the object name without any namespace qualifiers\&. .TP \fIobj\fR \fBinfo info\fR ?\fB-asList\fR? Returns the available submethods of the \fBinfo\fR method ensemble for \fIobj\fR, either as a pretty-printed string or as a Tcl list (if the switch \fB-asList\fR is set) for further processing\&. .TP \fIobj\fR \fBinfo object filters\fR ?\fB-guards\fR? ?\fIpattern\fR? If \fIpattern\fR is omitted, returns all filter names which are defined by \fIobj\fR\&. By turning on the switch \fB-guards\fR, the corresponding guard expressions, if any, are also reported along with each filter as a three-element list: \fIfilterName\fR -guard \fIguardExpr\fR\&. By specifying \fIpattern\fR, the returned filters can be limited to those whose names match \fIpatterns\fR (see \fBstring match\fR)\&. .TP \fIobj\fR \fBinfo object method\fR \fIoption\fR \fImethodName\fR This introspection submethod provides access to the details of \fImethodName\fR provided by \fIobj\fR\&. If \fImethodName\fR is not the name of an existing method, an empty string is returned\&. To disambiguate between a non-existing method and an empty string as valid return value (e\&.g\&., for \fBinfo object method args|parameters|args|\&.\&.\&.\fR), use \fBinfo object method exists\fR\&. .sp Permitted values for \fIoption\fR are: .RS .IP \(bu \fBargs\fR returns a list containing the parameter names of \fImethodName\fR, in order of the method-parameter specification\&. .IP \(bu \fBbody\fR returns the body script of \fImethodName\fR\&. .IP \(bu \fBcallprotection\fR returns the call-protection level set for \fImethodName\fR; possible values: \fBpublic\fR, \fBprotected\fR, \fBprivate\fR\&. .IP \(bu \fBdebug\fR returns 1 if \fImethodName\fR is in debug mode, 0 otherwise\&. .IP \(bu \fBdefinition\fR returns a canonical command list which allows for (re-)define \fImethodName\fR\&. .IP \(bu \fBdefinitionhandle\fR returns the method handle for a submethod in a method ensemble from the perspective of \fIobj\fR as method provider\&. \fImethodName\fR must contain a complete method path\&. .IP \(bu \fBdeprecated\fR returns 1 if \fImethodName\fR is deprecated, 0 otherwise\&. .IP \(bu \fBexists\fR returns 1 if there is a \fImethodName\fR provided by \fIobj\fR, returns 0 otherwise\&. .IP \(bu \fBhandle\fR returns the method handle for \fImethodName\fR\&. .IP \(bu \fBorigin\fR returns the aliased command if \fImethodName\fR is an alias method, or an empty string otherwise\&. .IP \(bu \fBparameters\fR returns the parameter specification of \fImethodName\fR as a list of parameter names and type specifications\&. .IP \(bu \fBregistrationhandle\fR returns the method handle for a submethod in a method ensemble from the perspective of the method caller\&. \fImethodName\fR must contain a complete method path\&. .IP \(bu \fBreturns\fR gives the type specification defined for the return value of \fImethodName\fR\&. .IP \(bu \fBsubmethods\fR returns the names of all submethods of \fImethodName\fR, if \fImethodName\fR is a method ensemble\&. Otherwise, an empty string is returned\&. .IP \(bu \fBsyntax\fR returns the method parameters of \fImethodName\fR as a concrete-syntax description to be used in human-understandable messages (e\&.g\&., errors or warnings, documentation strings)\&. .IP \(bu \fBtype\fR returns whether \fImethodName\fR is a \fIscripted\fR method, an \fIalias\fR method, a \fIforwarder\fR method, or a \fIsetter\fR method\&. .RE .TP \fIobj\fR \fBinfo object methods\fR ?\fB-callprotection\fR \fIlevel\fR? ?\fB-type\fR \fImethodType\fR? ?\fB-path\fR? ?\fInamePattern\fR? Returns the names of all methods defined by \fIobj\fR\&. Methods covered include those defined using \fBobject alias\fR and \fBobject forward\fR\&. The returned methods can be limited to those whose names match \fInamePattern\fR (see \fBstring match\fR)\&. .sp By setting \fB-callprotection\fR, only methods of a certain call protection \fIlevel\fR (\fBpublic\fR, \fBprotected\fR, or \fBprivate\fR) will be returned\&. Methods of a specific type can be requested using \fB-type\fR\&. The recognized values for \fImethodType\fR are: .RS .IP \(bu \fBscripted\fR denotes methods defined using \fBobject\fR \fBmethod\fR; .IP \(bu \fBalias\fR denotes alias methods defined using \fBobject\fR \fBalias\fR; .IP \(bu \fBforwarder\fR denotes forwarder methods defined using \fBobject\fR \fBforward\fR; .IP \(bu \fBsetter\fR denotes methods defined using \fB::nsf::setter\fR; .IP \(bu \fBall\fR returns methods of any type, without restrictions (also the default value); .RE .TP \fIobj\fR \fBinfo object mixins\fR ?\fB-guards\fR? ?\fIpattern\fR? If \fIpattern\fR is omitted, returns the object names of the mixin classes which extend \fIobj\fR directly\&. By turning on the switch \fB-guards\fR, the corresponding guard expressions, if any, are also reported along with each mixin as a three-element list: \fIclassName\fR -guard \fIguardExpr\fR\&. The returned mixin classes can be limited to those whose names match \fIpatterns\fR (see \fBstring match\fR)\&. .TP \fIobj\fR \fBinfo object slots\fR ?\fB-type\fR \fIclassName\fR? ?\fIpattern\fR? If \fIpattern\fR is not specified, returns the object names of all slot objects defined by \fIobj\fR\&. The returned slot objects can be limited according to any or a combination of the following criteria: First, slot objects can be filtered based on their command names matching \fIpattern\fR (see \fBstring match\fR)\&. Second, \fB-type\fR allows one to select slot objects which are instantiated from a subclass \fIclassName\fR of \fBnx::Slot\fR (default: \fBnx::Slot\fR)\&. .TP \fIobj\fR \fBinfo object variables\fR ?\fIpattern\fR? If \fIpattern\fR is omitted, returns the object names of all slot objects provided by \fIobj\fR which are responsible for managing properties and variables of \fIobj\fR\&. Otherwise, only slot objects whose names match \fIpattern\fR are returned\&. .sp This is equivalent to calling: \fIobj\fR \fBinfo object slots\fR \fB-type\fR \fB::nx::VariableSlot\fR \fIpattern\fR\&. .sp To extract details of each slot object, use the \fBinfo\fR submethods available for each slot object\&. .TP \fIobj\fR \fBinfo parent\fR Returns the fully qualified name of the parent object of \fIobj\fR, if any\&. If there is no parent object, the name of the Tcl namespace containing \fIobj\fR (e\&.g\&. "::") will be reported\&. .TP \fIobj\fR \fBinfo precedence\fR ?\fB-intrinsic\fR? ?\fIpattern\fR? Lists the classes from which \fIobj\fR inherits structural (e\&.g\&. properties) and behavioral features (e\&.g\&. methods) and methods, in order of the linearization scheme in NX\&. By setting the switch \fB-intrinsic\fR, only classes which participate in superclass/subclass relationships (i\&.e\&., intrinsic classes) are returned\&. If a \fIpattern\fR is provided only classes whose names match \fIpattern\fR are returned\&. The \fIpattern\fR string can contain special matching characters (see \fBstring match\fR)\&. .TP \fIobj\fR \fBinfo variable\fR \fIoption\fR \fIhandle\fR Retrieves selected details about a variable represented by the given \fIhandle\fR\&. A \fIhandle\fR can be obtained by querying \fIobj\fR using \fBinfo object variables\fR and \fBinfo lookup variables\fR\&. Valid values for \fIoption\fR are: .RS .IP \(bu \fBname\fR returns the variable name\&. .IP \(bu \fBparameter\fR returns a canonical parameter specification eligible to (re-)define the given variable (e\&.g\&. using \fBobject variable\fR) in a new context\&. .IP \(bu \fBdefinition\fR returns a canonical representation of the definition command used to create the variable in its current configuration\&. .RE .TP \fIobj\fR \fBinfo vars\fR ?\fIpattern\fR? Yields a list of Tcl variable names created and defined for the scope of \fIobj\fR, i\&.e\&., object variables\&. The list can be limited to object variables whose names match \fIpattern\fR\&. The \fIpattern\fR string can contain special matching characters (see \fBstring match\fR)\&. .RE .TP \fBmethod\fR .RS .TP \fIobj\fR ?\fBpublic\fR | \fBprotected\fR | \fBprivate\fR? \fBobject method\fR ?\fB-debug\fR? ?\fB-deprecated\fR? \fIname\fR \fIparameters\fR ?\fB-checkalways\fR? ?\fB-returns\fR \fIvalueChecker\fR? \fIbody\fR Defines a scripted method \fImethodName\fR for the scope of the object\&. The method becomes part of the object's signature interface\&. Besides a \fImethodName\fR, the method definition specifies the method \fIparameters\fR and a method \fIbody\fR\&. .sp \fIparameters\fR accepts a Tcl \fBlist\fR containing an arbitrary number of non-positional and positional parameter definitions\&. Each parameter definition comprises a parameter name, a parameter-specific value checker, and parameter options\&. .sp The \fIbody\fR contains the method implementation as a script block\&. In this body script, the colon-prefix notation is available to denote an object variable and a self call\&. In addition, the context of the object receiving the method call (i\&.e\&., the message) can be accessed (e\&.g\&., using \fBnx::self\fR) and the call stack can be introspected (e\&.g\&., using \fBnx::current\fR)\&. .sp Optionally, \fB-returns\fR allows for setting a value checker on values returned by the method implementation\&. By setting the switch \fB-checkalways\fR, value checking on arguments and return value is guaranteed to be performed, even if value checking is temporarily disabled; see \fBnx::configure\fR)\&. .sp To express deprecation of the method \fIname\fR, set the \fB-deprecated\fR flag\&. Deprecated methods remain usable from client code, but their usage will be signaled to the developer and/or can be tracked using \fB::nsf::deprecated\fR\&. To register \fIname\fR with the debugger, set the \fB-debug\fR flag\&. Entering and exiting a method, which was flagged for debugging, is recorded by calling the redefinable callback procs \fB::nsf::debug::call\fR and \fB::nsf::debug::exit\fR, respectively\&. By default, these callbacks forward to \fB::nsf::log\fR, which can also be customized at the script level\&. .sp A method closely resembles a Tcl \fBproc\fR, but it differs in some important aspects: First, a method can define non-positional parameters and value checkers on arguments\&. Second, the script implementing the method body can contain object-specific notation and commands (see above)\&. Third, method calls \fIcannot\fR be intercepted using Tcl \fBtrace\fR\&. Note that an existing Tcl \fBproc\fR can be registered as an alias method with the object (see \fBobject alias\fR)\&. .RE .TP \fBmove\fR .RS .TP \fIobj\fR \fBmove\fR \fInewObjectName\fR Effectively renames an object\&. First, the source object \fIobj\fR is cloned into a target object \fInewObjectName\fR using \fBcopy\fR\&. Second, the source object \fIobj\fR is destroyed by invoking \fBdestroy\fR\&. \fBmove\fR is also called internally when \fBrename\fR is performed for a Tcl command representing an object\&. .RE .TP \fBmixins\fR .RS .TP \fIobj\fR \fBobject mixins\fR \fIsubmethod\fR ?\fIarg\fR \&.\&.\&.? Accesses and modifies the list of mixin classes of \fIobj\fR using a specific setter or getter \fIsubmethod\fR: .RS .TP \fIobj\fR \fBobject\fR \fBmixins add\fR \fIspec\fR ?\fIindex\fR? Inserts a single mixin class into the current list of mixin classes of \fIobj\fR\&. Using \fIindex\fR, a position in the existing list of mixin classes for inserting the new mixin class can be set\&. If omitted, \fIindex\fR defaults to the list head (0)\&. .TP \fIobj\fR \fBobject\fR \fBmixins classes\fR ?\fIpattern\fR? If \fIpattern\fR is omitted, returns the object names of the mixin classes which extend \fIobj\fR directly\&. By specifying \fIpattern\fR, the returned mixin classes can be limited to those whose names match \fIpattern\fR (see \fBstring match\fR)\&. .TP \fIobj\fR \fBobject\fR \fBmixins clear\fR Removes all mixin classes from \fIobj\fR and returns the list of removed mixin classes\&. Clearing is equivalent to passing an empty list for \fImixinSpecList\fR to \fBobject\fR \fBmixins set\fR\&. .TP \fIobj\fR \fBobject\fR \fBmixins delete\fR ?\fB-nocomplain\fR? \fIspecPattern\fR Removes a mixin class from a current list of mixin classes of \fIobj\fR whose spec matches \fIspecPattern\fR\&. \fIspecPattern\fR can contain special matching chars (see \fBstring match\fR)\&. \fBobject\fR \fBmixins delete\fR will throw an error if there is no matching mixin class, unless \fB-nocomplain\fR is set\&. .TP \fIobj\fR \fBobject\fR \fBmixins get\fR Returns the list of current mixin specifications\&. .TP \fIobj\fR \fBobject\fR \fBmixins guard\fR \fIclassName\fR ?\fIexpr\fR? If \fIexpr\fR is specified, a guard expression \fIexpr\fR is registered with the mixin class \fIclassName\fR\&. This requires that the corresponding mixin class \fIclassName\fR has been previously set using \fBobject\fR \fBmixins set\fR or added using \fBobject\fR \fBmixins add\fR\&. \fIexpr\fR must be a valid Tcl expression (see \fBexpr\fR)\&. An empty string for \fIexpr\fR will clear the currently registered guard expression for the mixin class \fIclassName\fR\&. .sp If \fIexpr\fR is not specified, returns the active guard expression\&. If none is available, an empty string will be returned\&. .TP \fIobj\fR \fBobject\fR \fBmixins set\fR \fImixinSpecList\fR \fImixinSpecList\fR represents a list of mixin class specs, with each spec being itself either a one-element or a three-element list: \fIclassName\fR ?-guard \fIguardExpr\fR?\&. If having one element, the element will be considered the \fIclassName\fR of the mixin class\&. If having three elements, the third element \fIguardExpr\fR will be stored as a guard expression of the mixin class\&. This guard expression will be evaluated using \fBexpr\fR when \fIobj\fR receives a message to determine if the mixin is to be considered during method dispatch or not\&. Guard expressions allow for realizing context-dependent or conditional mixin composition\&. .RE .IP At the time of setting the mixin relation, that is, calling \fBobject\fR \fBmixins\fR, every \fIclassName\fR as part of a spec must be an existing instance of \fBnx::Class\fR\&. To access and to manipulate the list of mixin classes of \fIobj\fR, \fBcget\fR|\fBconfigure\fR \fB-object-mixins\fR can also be used\&. .RE .TP \fB__object_configureparameter\fR .RS .TP \fIobj\fR \fB__object_configureparameter\fR Computes and returns the configuration options available for \fIobj\fR, to be consumed as method-parameter specification by \fBconfigure\fR\&. .RE .TP \fBproperty\fR .RS .TP \fIobj\fR \fBobject property\fR ?\fB-accessor\fR \fBpublic\fR | \fBprotected\fR | \fBprivate\fR? ?\fB-class\fR \fIclassName\fR? ?\fB-configurable\fR \fItrueFalse\fR? ?\fB-incremental\fR? ?\fB-nocomplain\fR? ?\fB-trace\fR \fBset\fR | \fBget\fR | \fBdefault\fR? \fIspec\fR ?\fIinitBlock\fR? Defines a property for the scope of the object\&. The \fIspec\fR provides the property specification as a \fBlist\fR holding at least one element or, maximum, two elements: \fIpropertyName\fR?\fB:\fR\fItypeSpec\fR? ?\fIdefaultValue\fR?\&. The \fIpropertyName\fR is also used as to form the names of the getter/setter methods, if requested (see \fB-accessor\fR)\&. It is, optionally, equipped with a \fItypeSpec\fR following a colon delimiter which specifies a value checker for the values which become assigned to the property\&. The second, optional element sets a \fIdefaultValue\fR for this property\&. .sp If \fB-accessor\fR is set, a property will provide for different getter and setter methods: .RS .TP \fIobj\fR \fIpropertyName\fR \fBexists\fR Returns 1 if the value store of \fIpropertyName\fR (e\&.g\&., an object variable) exists and has been given a value, returns 0 otherwise\&. .TP \fIobj\fR \fIpropertyName\fR \fBset\fR \fIvalue\fR Sets the property \fIpropertyName\fR to \fIvalue\fR\&. .TP \fIobj\fR \fIpropertyName\fR \fBget\fR Returns the current value of property \fIpropertyName\fR\&. .TP \fIobj\fR \fIpropertyName\fR \fBunset\fR Removes the value store of \fIpropertyName\fR (e\&.g\&., an object variable), if existing\&. .RE .IP The option value passed along \fB-accessor\fR sets the level of call protection for the generated getter and setter methods: \fBpublic\fR, \fBprotected\fR, or \fBprivate\fR\&. By default, no getter and setter methods are created\&. .sp Turning on the switch \fB-incremental\fR provides a refined setter interface to the value managed by the property\&. First, setting \fB-incremental\fR implies requesting \fB-accessor\fR (set to \fBpublic\fR by default, if not specified explicitly)\&. Second, the managed value will be considered a valid Tcl list\&. A multiplicity of \fB1\&.\&.*\fR is set by default, if not specified explicitly as part of \fIspec\fR\&. Third, to manage this list value element-wise (\fIincrementally\fR), two additional setter methods become available: .RS .TP \fIobj\fR \fIpropertyName\fR \fBadd\fR \fIelement\fR ?\fIindex\fR? Adding \fIelement\fR to the managed list value, at the list position given by \fIindex\fR (by default: 0)\&. .TP \fIobj\fR \fIpropertyName\fR \fBdelete\fR ?\fB-nocomplain\fR? \fIelementPattern\fR Removing the first occurrence of an element from the managed list value which matches \fIelementPattern\fR\&. \fIelementPattern\fR can contain matching characters (see \fBstring match\fR)\&. An error will be thrown if there is no match, unless \fB-nocomplain\fR is set\&. .RE .sp By setting \fB-configurable\fR to \fBtrue\fR (the default), the property can be accessed and modified through \fBcget\fR and \fBconfigure\fR, respectively\&. If \fBfalse\fR, no configuration option will become available via \fBcget\fR and \fBconfigure\fR\&. .sp If neither \fB-accessor\fR nor \fB-configurable\fR are requested, the value managed by the property will have to be accessed and modified directly\&. If the property manages an object variable, its value will be readable and writable using \fBset\fR and \fBeval\fR\&. .sp The \fB-trace\fR option causes certain slot methods to be executed whenever \fBget\fR, \fBset\fR, or \fBdefault\fR operations are invoked on the property: .RS .IP \(bu \fBset\fR: \fIslot\fR \fBvalue=set\fR \fIobj\fR \fIpropertyName\fR \fIvalue\fR .IP \(bu \fBget\fR: \fIslot\fR \fBvalue=get\fR \fIobj\fR \fIpropertyName\fR .IP \(bu \fBdefault\fR: \fIslot\fR \fBvalue=default\fR \fIobj\fR \fIpropertyName\fR .RE .sp A property becomes implemented by a slot object under any of the following conditions: .RS .IP \(bu \fB-configurable\fR equals \fBtrue\fR (by default)\&. .IP \(bu \fB-accessor\fR is one of \fBpublic\fR, \fBprotected\fR, or \fBprivate\fR\&. .IP \(bu \fB-incremental\fR is turned on\&. .IP \(bu \fIinitBlock\fR is a non-empty string\&. .RE .IP Assuming default settings, every property is realized by a slot object\&. .sp Provided a slot object managing the property is to be created, a custom class \fIclassName\fR from which this slot object is to be instantiated can be set using \fB-class\fR\&. The default value is \fB::nx::VariableSlot\fR\&. .sp The last argument \fIinitBlock\fR accepts an optional Tcl script which is passed into the initialization procedure (see \fBconfigure\fR) of the property's slot object\&. See also \fB\fIinitBlock\fR for \fBcreate\fR and \fBnew\fR\fR\&. .sp By default, the property will ascertain that no (potentially) pre-existing and equally named object variable will be overwritten when defining the property\&. In case of a conflict, an error exception is thrown: .CS % Object create obj { set :x 1 } ::obj % ::obj object property {x 2} object ::obj has already an instance variable named 'x' .CE .IP If the switch \fB-nocomplain\fR is on, this check is omitted (continuing the above example): .CS % ::obj object property -nocomplain {x 2} % ::obj eval {set :x} 2 .CE .RE .TP \fBrequire\fR .RS .TP \fIobj\fR \fBrequire namespace\fR Create a Tcl namespace named after the object \fIobj\fR\&. All object variables become available as namespace variables\&. .TP \fIobj\fR \fBrequire\fR ?\fBpublic\fR | \fBprotected\fR | \fBprivate\fR? \fBobject method\fR \fImethodName\fR Attempts to register a method definition made available using \fB::nsf::method::provide\fR under the name \fImethodName\fR with \fIobj\fR \&. The registered method is subjected to default call protection (\fBprotected\fR), if not set explicitly\&. .RE .TP \fBunknown\fR .RS .TP \fIobj\fR \fBunknown\fR \fIunknownMethodName\fR ?\fIarg\fR \&.\&.\&.? This method is called implicitly whenever an unknown method is invoked\&. \fIunknownMethodName\fR indicates the unresolvable method name, followed by the remainder of the original argument vector as a number of \fIarg\fR of the calling method invocation\&. .RE .TP \fBuplevel\fR .RS .TP \fIobj\fR \fBuplevel\fR ?\fIlevel\fR? \fIarg1\fR ?\fIarg2\fR \&.\&.\&.? Evaluate a script or a command at a different stack-frame level\&. The command behaves in essence like Tcl's \fBuplevel\fR, but can be used to achieve identical results when filters or mixins are registered\&. .RS .IP \(bu If the \fIlevel\fR specifier is omitted, \fBuplevel\fR will skip any auxiliary frames added to the stack by active filters and mixins\&. The resulting stack-frame level corresponds to the callinglevel as indicated by \fBnx::current\fR\&. In this case method \fBuplevel\fR can be used to evaluate the command in the next enclosing procedure call, i\&.e\&., a frame corresponding to a proc, method, or apply call, while skipping frames of filters and mixins\&. .IP \(bu If the \fIlevel\fR specifier is provided (relative, or absolute), \fBuplevel\fR will execute the command in the stack-frame level\&. In such cases, method \fBuplevel\fR behaves like Tcl's \fBuplevel\fR command\&. .RE .CS % nx::Object create ::obj ::obj % ::obj public object method foo {varName} { :uplevel set $varName 1; return } ::obj::foo % namespace eval ::ns1 { ::obj foo BAR } % namespace eval ::ns1 { info exists BAR } 1 .CE .RE .IP Note, in the example above, \fBuplevel\fR is guaranteed to resolve to the calling context of \fBfoo\fR (ns1) despite mixins and filters being (potentially) registered on \fBobj\fR\&. .TP \fBupvar\fR .RS .TP \fIobj\fR \fBupvar\fR ?\fIlevel\fR? \fIotherVar1\fR \fIlocalVar1\fR ?\fIotherVar2\fR \fIlocalVar2\fR \&.\&.\&.? Links one or more local variables to variables defined in other scopes (namespaces, objects, call frames)\&. The command behaves in essence like Tcl's \fBupvar\fR, but can be used to achieve identical results when filters or mixins are registered\&. .RS .IP \(bu If the \fIlevel\fR specifier is omitted, \fBupvar\fR will skip any auxiliary frames added to the stack by active filters and mixins\&. The resulting stack-frame level corresponds to the callinglevel as indicated by \fBnx::current\fR\&. Therefore, method \fBupvar\fR gives access to the next enclosing procedure call, i\&.e\&., a frame corresponding to a proc, method, or apply call, while skipping frames of filters and mixins\&. .IP \(bu If the \fIlevel\fR specifier is provided (relative, or absolute), \fBupvar\fR will link into the requested stack-frame level\&. In these cases, method \fBupvar\fR behaves like Tcl's \fBupvar\fR command\&. .RE .CS % nx::Object create ::obj ::obj % ::obj public object method foo {varName} { :upvar $varName x; set x 1; return } ::obj::foo % namespace eval ::ns1 { ::obj foo BAR } % namespace eval ::ns1 { info exists BAR } 1 .CE .RE .IP Note, in the example above, \fBupvar\fR is guaranteed to resolve to the calling context of \fBfoo\fR (ns1) despite mixins and filters being (potentially) registered on \fBobj\fR\&. .TP \fBvariable\fR .RS .TP \fIobj\fR \fBobject variable\fR ?\fB-accessor\fR \fBpublic\fR | \fBprotected\fR | \fBprivate\fR? ?\fB-incremental\fR? ?\fB-class\fR \fIclassName\fR? ?\fB-configurable\fR \fItrueFalse\fR? ?\fB-initblock\fR \fIscript\fR? ?\fB-trace\fR \fBset\fR | \fBget\fR | \fBdefault\fR? ?\fB-nocomplain\fR? \fIspec\fR ?\fIdefaultValue\fR? Defines a variable for the scope of the object\&. The \fIspec\fR provides the variable specification: \fIvariableName\fR?\fB:\fR\fItypeSpec\fR?\&. The \fIvariableName\fR will be used to name the underlying Tcl variable and the getter/setter methods, if requested (see \fB-accessor\fR)\&. \fIspec\fR is optionally equipped with a \fItypeSpec\fR following a colon delimiter which specifies a value checker for the values managed by the variable\&. Optionally, a \fIdefaultValue\fR can be defined\&. .sp If \fB-accessor\fR is set explicitly, a variable will provide for getter and setter methods: .RS .TP \fIobj\fR \fIvariableName\fR \fBexists\fR Returns 1 if the value store of \fIvariableName\fR (e\&.g\&., an object variable) exists and has been given a value, returns 0 otherwise\&. .TP \fIobj\fR \fIvariableName\fR \fBset\fR \fIvarValue\fR Sets \fIvariableName\fR to \fIvarValue\fR\&. .TP \fIobj\fR \fIvariableName\fR \fBget\fR Returns the current value of \fIvariableName\fR\&. .TP \fIobj\fR \fIvariableName\fR \fBunset\fR Removes \fIvariableName\fR, if existing, underlying the property\&. .RE .IP The option value passed along \fB-accessor\fR sets the level of call protection for the getter and setter methods: \fBpublic\fR, \fBprotected\fR, or \fBprivate\fR\&. By default, no getter and setter methods are created\&. .sp Turning on the switch \fB-incremental\fR provides a refined setter interface to the value managed by the variable\&. First, setting \fB-incremental\fR implies requesting \fB-accessor\fR (\fBpublic\fR by default, if not specified explicitly)\&. Second, the managed value will be considered a valid Tcl list\&. A multiplicity of \fB1\&.\&.*\fR is set by default, if not specified explicitly as part of \fIspec\fR (see above)\&. Third, to manage this list value element-wise (\fIincrementally\fR), two additional setter operations become available: .RS .TP \fIobj\fR \fIvariableName\fR \fBadd\fR \fIelement\fR ?\fIindex\fR? Adding \fIelement\fR to the managed list value, at the list position given by \fIindex\fR (by default: 0)\&. .TP \fIobj\fR \fIvariableName\fR \fBdelete\fR ?\fB-nocomplain\fR? \fIelementPattern\fR Removing the first occurrence of an element from the managed list value which matches \fIelementPattern\fR\&. \fIelementPattern\fR can contain matching characters (see \fBstring match\fR)\&. An error will be thrown if there is no match, unless \fB-nocomplain\fR is set\&. .RE .sp By setting \fB-configurable\fR to \fBtrue\fR, the variable can be accessed and modified via \fBcget\fR and \fBconfigure\fR, respectively\&. If \fBfalse\fR (the default), the interface based on \fBcget\fR and \fBconfigure\fR will not become available\&. In this case, and provided that \fB-accessor\fR is set, the variable can be accessed and modified via the getter/setter methods\&. Alternatively, the underlying Tcl variable, which is represented by the variable, can always be accessed and modified directly, e\&.g\&., using \fBeval\fR\&. By default, \fB-configurable\fR is \fBfalse\fR\&. .sp The \fB-trace\fR option causes certain slot methods to be executed whenever \fBget\fR, \fBset\fR, or \fBdefault\fR operations are invoked on the variable: .RS .IP \(bu \fBset\fR: \fIslot\fR \fBvalue=set\fR \fIobj\fR \fIvariableName\fR \fIvalue\fR .IP \(bu \fBget\fR: \fIslot\fR \fBvalue=get\fR \fIobj\fR \fIvariableName\fR .IP \(bu \fBdefault\fR: \fIslot\fR \fBvalue=default\fR \fIobj\fR \fIvariableName\fR .RE .sp A variable becomes implemented by a slot object under any of the following conditions: .RS .IP \(bu \fB-configurable\fR equals \fBtrue\fR\&. .IP \(bu \fB-accessor\fR is one of \fBpublic\fR, \fBprotected\fR, or \fBprivate\fR\&. .IP \(bu \fB-incremental\fR is turned on\&. .IP \(bu \fB-initblock\fR is a non-empty string\&. .RE .IP Provided a slot object managing the variable is to be created, a custom class \fIclassName\fR from which this slot object is to be instantiated can be set using \fB-class\fR\&. The default value is \fB::nx::VariableSlot\fR\&. .sp Using \fB-initblock\fR, an optional Tcl \fIscript\fR can be defined which becomes passed into the initialization procedure (see \fBconfigure\fR) of the variable's slot object\&. See also \fB\fIinitBlock\fR for \fBcreate\fR and \fBnew\fR\fR\&. .sp By default, the variable will ascertain that a pre-existing and equally named object variable will not be overwritten when defining the variable\&. In case of a conflict, an error exception is thrown: .CS % Object create obj { set :x 1 } ::obj % ::obj object variable x 2 object ::obj has already an instance variable named 'x' .CE .IP If the switch \fB-nocomplain\fR is on, this check is omitted (continuing the above example): .CS % ::obj object variable -nocomplain x 2 % ::obj eval {set :x} 2 .CE .RE .PP .SH "OBJECT SELF-REFERENCE" Objects are naturally recursive, with methods of an object \fB::obj\fR frequently invoking other methods in the same object \fB::obj\fR and accessing \fB::obj\fR's object variables\&. To represent these self-references effectively in method bodies, and depending on the usage scenario, NX offers two alternative notations for self-references: one based on a special-purpose syntax token ("colon prefix"), the other based on the command \fBnx::current\fR\&. .PP Both, the colon-prefix notation and \fBnx::current\fR, may be used only in method bodies and scripts passed to \fBeval\fR\&. If they appear anywhere else, an error will be reported\&. There are three main use cases for self-references: .IP [1] As a \fIplaceholder\fR for the currently active object, \fBnx::current\fR can be used to retrieve the object name\&. .IP [2] Reading and writing \fIobject variables\fR directly (i\&.e\&. without getter/setter methods in place) require the use of variable names carrying the prefix \fB:\fR ("colon-prefix notation")\&. Internally, colon-prefixed variable names are processed using Tcl's variable resolvers\&. Alternatively, one can provide for getter/setter methods for object variables (see \fBproperty\fR and \fBvariable\fR)\&. .IP [3] \fISelf-referential method calls\fR can be defined via prefixing (\fB:\fR) the method names or, alternatively, via \fBnx::current\fR\&. Internally, colon-prefixed method names are processed using Tcl's command resolvers\&. The colon-prefix notation is recommended, also because it has a (slight) performance advantage over \fBnx::current\fR which requires two rather than one command evaluation per method call\&. .PP See the following listing for some examples corresponding to use cases 1--3: .CS Object create ::obj { # 1) print name of currently active object ('::obj') puts [current]; # 2) object variables set :x 1; :object variable y 2; :public object method print {} { # 2\&.a) method-local variable set z 3; # 2\&.b) variable substitution using '$' and ':' puts ${:x}-${:y}-$z; # 2\&.c) reading variables using 'set' puts [set :x]-[set :y]-[set z]; # 2\&.d) writing variables using 'set', 'incr', \&.\&.\&. set :x 1; incr :y; } :public object method show {} { # 3\&.a) self-referential method call using ':' :print; # 3\&.b) self-referential method call using 'nx::current' [current] print; # 3\&.c) self-referential method call using 'nx::current object' [current object] print; } :show } .CE .SH COPYRIGHT .nf Copyright (c) 2014-19 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. .fi ./nsf2.4.0/doc/makeDoc-xotcl.html000644 000766 000024 00000002155 12161565463 017331 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/lib/makeDoc.xotcl

    ./library/lib/makeDoc.xotcl ./library/lib/makeDoc.xotcl


    Package/File Information

    No package provided/required

    Filename: ./library/lib/makeDoc.xotcl

    Description: Documentation tool for the XOTcl distribution.
    Usage: 'makeDoc docdir filename ?filename ...?'
    Called by Makefile.



    Back to index page.

    ./nsf2.4.0/doc/nxsh.man000644 000766 000024 00000003403 13723231433 015413 0ustar00neumannstaff000000 000000 [comment {-*- Tcl -*- nxsh manpage}] [include version.inc] [manpage_begin nxsh 1 [vset VERSION]] [copyright {2014-16 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3.0 Austria license (CC BY 3.0 AT).}] [titledesc {Simple shell containing NSF/NX interpreter}] [moddesc {Command-line interface}] [description] [list_begin definitions] [call [syscmd "nxsh"] [opt "[option -c] [opt [arg arg1]]"] [opt "[arg arg2] ..."]] [syscmd "nxsh"] is a shell-like application that reads NX and Tcl commands from different sources and evaluates them. [para] If invoked without any arguments, [syscmd "nxsh"] runs in read-eval-print mode (REPL, interactive) similar to [syscmd "tclsh"]. In this mode, it reads commands from standard input interactively and prints command results as well as error messages to standard output. It remains active until the exit command is invoked or until it reaches end-of-file on its standard input. [para] If invoked with at least one positional argument [arg arg1], [syscmd "nxsh"] runs a NX/Tcl script sourced from a file identified by [arg arg1] using [cmd source]. [para] Passing the [option -c] flag makes [syscmd nxsh] accept commands from the command line provided by [arg arg1]. If [arg arg1] is omitted, [syscmd nxsh] takes commands from standard input (e.g., in a pipe). [para] [syscmd "nxsh"] can be used like [syscmd "tclsh"] to make NX scripts directly invocable from the shell, by providing the following first line ("shebang") in the respective script: [example { #! /usr/bin/env nxsh }] A (more portable) alternative is: [example_begin] #! /bin/sh # the next line restarts using nxsh \ exec nxsh "$0" "$@" [example_end] [list_end] [manpage_end] ./nsf2.4.0/doc/next-migration.pdf000644 000766 000024 00001063740 13471020733 017410 0ustar00neumannstaff000000 000000 %PDF-1.4 % 1 0 obj <> endobj 40 0 obj <> endobj 41 0 obj <> endobj 42 0 obj <> endobj 37 0 obj <> endobj 43 0 obj <> endobj 53 0 obj <> endobj 54 0 obj <> endobj 55 0 obj <> endobj 56 0 obj <> endobj 44 0 obj <> endobj 57 0 obj <> endobj 58 0 obj <> endobj 59 0 obj <> endobj 45 0 obj <> endobj 60 0 obj <> endobj 61 0 obj <> endobj 62 0 obj <> endobj 63 0 obj <> endobj 46 0 obj <> endobj 64 0 obj <> endobj 65 0 obj <> endobj 47 0 obj <> endobj 66 0 obj <> endobj 67 0 obj <> endobj 68 0 obj <> endobj 69 0 obj <> endobj 70 0 obj <> endobj 71 0 obj <> endobj 72 0 obj <> endobj 73 0 obj <> endobj 74 0 obj <> endobj 75 0 obj <> endobj 76 0 obj <> endobj 77 0 obj <> endobj 78 0 obj <> endobj 79 0 obj <> endobj 80 0 obj <> endobj 81 0 obj <> endobj 82 0 obj <> endobj 48 0 obj <> endobj 49 0 obj <> endobj 50 0 obj <> endobj 51 0 obj <> endobj 52 0 obj <> endobj 38 0 obj <> endobj 83 0 obj <> endobj 89 0 obj <> endobj 90 0 obj <> endobj 91 0 obj <> endobj 92 0 obj <> endobj 93 0 obj <> endobj 84 0 obj <> endobj 85 0 obj <> endobj 86 0 obj <> endobj 87 0 obj <> endobj 88 0 obj <> endobj 39 0 obj <> endobj 36 0 obj <> endobj 35 0 obj <> endobj 2 0 obj <> endobj 94 0 obj <> stream xYn$}5,b;~{(V&*yiGR4=)֩G gTw.%6A@xvN T`')W>5=5 L~8,}[ [ofrVX`S!izGNO<7-ק=?<7+ƈxrlS( >@=/_wO?Ώ ɴ|A 䅨TM ҏW,;oH|xL0oGqUmj35H5}*+)U)0U̫/>55D#ѦC!H7)Ba~J:ܡl10AN8Ayu)\ ?eUzj%z6+;^Wy@ F#c4,u1pŔRW;/GhYs7:ՖYJK-[eq%h)T[ĴwM{dH8P[dX 6ΊbcY]qyN:jjb97v$Ex Ѕuj D%XqBs mC .dJ|ŧ6_4xU6l|Gw(c͛ $,bm9=zUe=}uU%IEcqC[(l)xlVڎªP9A~ QCҪB5 #M(:cd0U01UG&2F8/)j]ʛX#q%*Й@M"ʆp't Wf?H2KcȶNa!.U\ ,v }&ϴ_e2h<~=Q敮'M|frvxɹ9YEn!ҦKvl{˛e`E,Mh*"Mu41?|-<R,7f WkK' 'ZB?m endstream endobj 95 0 obj 2216 endobj 144 0 obj <>>> stream xuRIr1BzƗSP@C3M'aV95D6/FFW<*.ZIסɫZ4ɐ=x8%2NFٮ44lErT*#8gD14xFK`* .RăpgO1(=<6O&ENGXى/sQbҖVnsbp sTض[]ƓQOWz*U'4ײ=f-m]s W}GQS^ϕ=c>Peqc|~ endstream endobj 145 0 obj 299 endobj 146 0 obj <> stream xVy 7(A1iL1>H;%(׋MJT^?xi)bzI:Y"i.Yz:'M(y($Y/ZzX0-d6'a'Kې~9wY0sNH7, Y@*@#8 @ Q`5 - TZA 8Yp\7 !CT@Z>d YB, BPCH @[BFW tA!hz}a ^`WWp:΃wp=| n/7~O"!#J6DX;D#qو H=҂t"==DF>cpab0>0 و)Tab010C w,5c}xl6[==}~pJ8C-KĭZq]>0nǫM@</+w#O2A`I"D\B9pp0J&@"XLl voG$y!ɑJJ$m!UZHWHd2YlG^N7+C ŝ"tQSST 5*6R/QQ?dd|e2dedʼ%˺ʮ]'[.{Rk9[n\~Iy||||u1W!O%aBӥ8G7_ EŊيՊ%JRR J_h,p][sA˂ Ք]yʭ0T>}}5|9~~.SC/5Y*\ \L= |dr_[Bք4| u -3 uˆ o (D.y3J5>=s#+W|pUUW'>Fv {lLDLSWv =[;qp˸!΀2VetHMzѶIn7[y/t0[ZZ / 'Y'[N韪9M;]mhOhtDu;y7ߎ>[}N\y3]Jz}1pK_^~kW^qp`hisӿ[~צ;vw:|={W޿`كa<>{'O垖?SVɹ![C s_בZccgǽ\rUګUͩ]591Vv]{G>,=4c驂O*~f}et:+k7oΤMP[˜%88YĐTL|Jl%P~2{Y@!JBy-$dg5Ps`xBj8ģp"~0kL|YVȏO1|"PvN:BiB_ainn@Fl)zg33 xffnf: d. ? endstream endobj 147 0 obj 2577 endobj 3 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Annots [142 0 R 143 0 R 96 0 R 97 0 R 98 0 R 99 0 R 100 0 R 101 0 R 102 0 R 103 0 R 104 0 R 105 0 R 106 0 R 107 0 R 108 0 R 109 0 R 110 0 R 111 0 R 112 0 R 113 0 R 114 0 R 115 0 R 116 0 R 117 0 R 118 0 R 119 0 R 120 0 R 121 0 R 122 0 R 123 0 R 124 0 R 125 0 R 126 0 R 127 0 R 128 0 R 129 0 R 130 0 R 131 0 R 132 0 R 133 0 R 134 0 R 135 0 R 136 0 R 137 0 R 138 0 R 139 0 R 140 0 R 141 0 R]>> endobj 142 0 obj <> /BS <> /Subtype /Text /T (www.princexml.com) /Subj (Prince - Non-commercial License) /Contents (This document was created with Prince, a great way of getting web content onto paper.) /Popup 143 0 R /Name /Note>> endobj 143 0 obj <> /Subtype /Popup /Parent 142 0 R /Open false>> endobj 96 0 obj <>>> endobj 97 0 obj <> endobj 98 0 obj <> endobj 99 0 obj <> endobj 100 0 obj <> endobj 101 0 obj <> endobj 102 0 obj <> endobj 103 0 obj <> endobj 104 0 obj <> endobj 105 0 obj <> endobj 106 0 obj <> endobj 107 0 obj <> endobj 108 0 obj <> endobj 109 0 obj <> endobj 110 0 obj <> endobj 111 0 obj <> endobj 112 0 obj <> endobj 113 0 obj <> endobj 114 0 obj <> endobj 115 0 obj <> endobj 116 0 obj <> endobj 117 0 obj <> endobj 118 0 obj <> endobj 119 0 obj <> endobj 120 0 obj <> endobj 121 0 obj <> endobj 122 0 obj <> endobj 123 0 obj <> endobj 124 0 obj <> endobj 125 0 obj <> endobj 126 0 obj <> endobj 127 0 obj <> endobj 128 0 obj <> endobj 129 0 obj <> endobj 130 0 obj <> endobj 131 0 obj <> endobj 132 0 obj <> endobj 133 0 obj <> endobj 134 0 obj <> endobj 135 0 obj <> endobj 136 0 obj <> endobj 137 0 obj <> endobj 138 0 obj <> endobj 139 0 obj <> endobj 140 0 obj <> endobj 141 0 obj <> endobj 154 0 obj <> stream x\ˎ$GrWx?..VXa#rfD3f)>_fYUYճq`3Os?O~[zw/_K)ǥҗ?sK+>]aio_R.}wv/{2ok7"oK><˼},Nqa>s55۵m5LM$N1b^;Ж5=wΝ1XSL>SX99?TǗZ:Ŏ=19~g?=w?So֥С{>۷;F뒊u9Ol'gs?To{i־W3!7]X|('z -ӗZc}ۖ>ĥOk9p֘#ΌOC~/8;~O 8_veVrBK>޾MjnkeA( q͈gl/*pcnmKTo!ܾM[lio/C?OcI|~KV޴_:*,yZ\oJ*mk~pojyJe`J^6Aq c%ؔ>%\=涸wߦ#0W"K¬.Rr˷oba%yzFW62xGo"XVg*UgōFwQQ }E)4z2B:L~Q>ꒋKoV|&^((,cwU\zETobnx6GCIC߿}tO _W η-E/Վ#NG[ÒBjt,:V!enp*h"o*O! 7̒Ugu.ef@##ʐSGmvCۀ? _m E=sD(eJRPP&x8D^c= %t,B2T}Xcc4Ӣ KEx6TvKd>2ZvoP|pٞ ګ%-,Wosn2kIvY[\\*X/B|[^Z"_:bMƾ-^j맹Šk*ʔ 0ߠd#n@Mgq D=N%:OKԝ'F3daf_ڑږdyχ",lx!R] Y"~!!DCGđIyHdUl~X%꫑"} pF="#V +uU8*n4ҪMC@ZI[[Оahj%@mģ@29YeD63F-Msk -\<,ֻd,; gjmS2φVZAAN})豅e5QaPMVIq) a&aZuIgu˾Wؽ¬]5⪏ws'IB5F䪹5V\#`&~d־"*CÂu61[LJS2uDUdB}c񐁬t<&/FѱhBE˾٫:k0G"#TS3LZ7٥&Ҳ+0cle[ϰ2np=}ZS3sTOHLW=ބʚM: :CfV\L2)"B֫땄x>"ip;g~C"sWXdOs^`gJ]0p~Z6dxC P`i}:Wj.#R'FvȐ%OHbk1 V"\,= 媨3˵ VjxwGדW@ޣ2(`] pYrC3yRfd& U?yske ;ίETi^Zy"ݥv6N/ͱV"z+jMW,QE-,5LG5 5¬{!: !F$!j3u*DS@NkUv\i85w0 %2QdBv}sHx^?|&0l#˴'#.T;H9YُʼY[2dRNLXYA::0Uc3@VC畡*0W*AU վyDK5ȀH! k¨<7 ybIn)|3`׬!I~AZ)5fDzj~Ka(K7wXur pg]po{2nlm:C4T=!9)ͲPrz:oʼUEa}Us+'0\,v* v!zZlvgKzO>B 5k#2wwacْmˆpUg~a&Ā܍k0 _wߤ#{Y /e9=xK:yj%HᱧƶC,A<B3BXCeldB ȺV9A1C'ty.Ӂ#ٞby3B-:;ih]o\gfzAAb!uZa+2ٱbH^ι^ǀPb$zXBUAL?Q:χA김{NM WЉuAvp]O2\US:cr2ÙZ iݓ'n,5~)<{MCl/ Вk٧$P/;^lUEB{AKIPnD-O w4{RѳS͑&QB%z׫U٬r쉕2[ j[ӄ.~]ǟd Y7g Y%RdAԛCdSi I{l  Ʀμ .9ȐXE*vZMYU+.Pdʞxi}IkUZtX -`~k\+h7Zz,:l!&+C5"~y B6-x j|4I#F&[$H%ƪ*Fk8!esҭ-y"aVZӃ1&Y|-_s\JӁylgExt`ecwc Y1&g_r}t{Z3V0b:o»JWr r,%Y=˫]!? bY‡E4^Bhxb"5*ZYK=/|CNmzqC8? 1r N`*;۠@=ټR8ا4sVxƚtƠ4Z^~5C&N@f$ ]@(ׁ,=50S];ŌqZ~  k]7` pFb͞)2dK(oxrVhfb00+no&-Si9\'ǚΘY_Bjk?lN5?< ߵ$\_Ce3}'tZ7M(q jFͮ#:@W GOӜǂ>~W[8T0$%& 5>xy ò+Rծ>d=ś Ihˎƾ1aNOdY;N>I)}Ǚ2h:]"oN3 f6Uw84Y%ȘhmkН'dTMrЩ҅8[c.@FQ|_g5*\sndΥ Ѱ.~j?ZP%2:2 o/O_?}ן?}/zoOft2ބizތ:*K 㮲 ytO "^))GUQ͕|>|c$_Xfq?ۯ=aq0jÿ}>|"[ xB^zL#s7>[%c(h 䲁Zj֥ {Fyjрk --!@ZJ?'Θ/Ŵ>sa %?':"%{Nk_{̖d;:2Ϊ0,-Ob?|u<;*͸? 1H IܢF>/:<|ޡ2À 3[Cyezf%i|s{{V1͘U%KuAoKVnw]EZܑKHшvщ#I  v7Cf5W~7R+P=K&38Yӟ͏Fc^ANKHAen<4YpiƥQv!'N!'F'$Ac 9q8A>(,ᎳgH猿S.kr>Z68@O7\f5X5?k3pS~nZCg'ROlnLV\p?\&?XH endstream endobj 155 0 obj 5401 endobj 4 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Annots [156 0 R 157 0 R 158 0 R 159 0 R 160 0 R 161 0 R 162 0 R 163 0 R 164 0 R 165 0 R 166 0 R 167 0 R]>> endobj 156 0 obj <> endobj 157 0 obj <> endobj 158 0 obj <> endobj 159 0 obj <> endobj 160 0 obj <> endobj 161 0 obj <> endobj 162 0 obj <> endobj 163 0 obj <> endobj 164 0 obj <> endobj 165 0 obj <> endobj 166 0 obj <> endobj 167 0 obj <> endobj 169 0 obj <> stream x\KsW-tU<x\"-q*Q|]SKi-dʯט}3˵/L6F?n ).cѻ!&xkvݻ@ƅ|nm7(/.>~z. ݻ ;aq^nϋǻnw>֝6Cعna5%i7΂R?8[*~.Ia0%Ā͒DLgo] u-qӒ3GAѪoy% (Id&dtE*-Yך75M*tKGmwQEq9j=R>!Yɘ[גA>uŠZ2B,I)29`1(XB^}jX ZdЮ!-Ijo){.Nh{qg,Ա iUL/ZD3"7d9+Cv>!OɡhHhJxCX ;^-kTF\3&cÅ& Y?aXsȂuE`3 *kC*UlƔ{5oXO{0Ft *{ɻYIr;Ow2QwIVT*åqqD XCW6.HM_/LJmlCĺ/:#R@b)1)t5iNR -C\εdyfQ#Tm2IWqߙHˌ ET6&I* PP~5܌5r*B'FN1+9b] l-. Nd\DEB'b(Vb$+Xj!l~c%U(pz2VyTɞF+GNŒjyK47S.֝O6Z݋^au+/nZv6%dN1Tm˗O-ۭl@2%ȑ"#ȝTSX@$ATڢ0NsCȽKѸ%k]HAf[K3"[.|q!r QsZAU}1W Bg;T蝽Zc(@ yO;<\㕹8ca7U:(G$f tU32t” C? V[htuYwjT+#ۢr5ވXޕ3:sO 'UO{Il:D5JQ!0>.ǧsERHQC$?!>q&w ` - (l6ͧsX&vqv(ЌZxsi-#AG2Cʼnj/YӋG ^wA9}Գ/EJ,Z!ӃbJޗH^78a)c!5PYf6آ"!%RZPJ)M`AZ\w ETYpQqzeu@t()(4nOn$8*%>9rɚDϵ~㚨:,Iփ5F8ꃙ1+gz )|c6@\X*f.`]/on>Pp氃ԙY21_ɟb/Ε(N TCh+kVl:WzC"}"U*ṠjSQ4ڄg`?J%2xTy؋C:%D7@_KХf쥶W6*Sf~>zLԌ'QӖu@ miQJ~X2}/7wwv'jrl~x{6~ZT_W!@܋&w~" endstream endobj 170 0 obj 4618 endobj 5 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 172 0 obj <> stream x[KoGW6X@- 20HC_U=8=ƌl3yJU*#cH(?~=^=ȅsT5PN<[nc'c0-V\F)4~z֏?}x߆ͧ?_v_nxfoDy 75޺h:a@-eg[q`%>zeW|jMc Z 6=v-(YEUKh>?W7=EИ A Pλ\`7[Gbp !b!f9HURny`&.2q}\m4 KQwRE&XydƒIq-`7Kc3xo~AbX|v]:%|nʶ]bɧ4˂nEyΑ$ˣ񳿴{co^3'Uhr,Á#I ;pQ*p~ /q"$a:_כϏ+e:!~ٜJI%|4x['L px=)x lV:.[x|K"IrÁT/SƏ"}Hm$".4 -O6Tsg!t%I.yD2WU`W 85]WF8)[Nʘo K=27>/ZZR\dv6u1T0˵C"pf‰ֹU͐KMA8cP( Lئ?'ZӦQ>Wp!B.!N[6_n=6D( %=d( E=lRPA $h~}^}Z=7"9P EݿW߷l BU2N6p=x-Hܯhb\=$g ELV c&IN rht$ɠ6ĸN2(v=ԯr Q5iDL5(`0a'$| .|=VQЏ5]yG V3Gd^֐÷&ΧS,!sR.:cD*QOq5CcϚ!к!IBGr7$QM퍡n ?T7(-4&.$i'*lfA7( XKHƩ-g!!ܴPb]4}y@H?jј\7_w3@c(\D-&0u*VEj; vhؘUkla|҄{9ٓI-ԟj"'FlvbR!b'zgN?<y}X?* }}u ]rwmMTWJ5j #Z/4& ڮkj#tpɗNc`l -ʬ?6 H 3E]H1]l}GKnqE$QDX)W;r 2b]3g)|$Yt~*FP:P]Ak}$LgES`9B #cNd[p 1#s\͜Y)&^4` 2⻕דǮ 3kk&9ܯ6wnm1rdZxɞ۴fb*5VXvq+[ެwD/[׿–e/ pţuN@-O?wsQ5UK. TVCiђP%IZ3͑$4C38L[yzWu63KHU4 C+5 C•\`&"0(|a<  PPh@[} (lJ&&T<$;S-i>W|"Dsၸ}=<_aopj s/oGMuĨePt2%Ћ{K@Uߙa,in+&guYX3FGV"7f4ahvי3hfL˃ p&@634rsR v RG>Ϻ25R4 gWc\MO^/ZOބi BfBa$mGxU 83g= AF.QWz@?ۚJ?7"=1^(`n\?Nn 3sgV?jW: +7BRGj"KW"jqu@cIs 8 )t87شU ^-3(*2ZeC՝lu n4~ev$o,jnXB4ړUc$aķRn(Ɂ P#)*e4_2G&;V*B]-Z8E}|Ϗ^3;rEZJ(wj>:W;2Q7G`}I`==CF4%#lI IPۊ7 B"W qqpl lMh?^Vϫkjvbjy1ͧʦ22@~/O^> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 174 0 obj <> stream x[n}W b=0рE (wV zrJwBFǨug'#(HdZ69Ky[bYjE#|"?zߨ+B {k0 $5`Cqd/ `shRY̻`s=y@E gΜ`H\T vr^7H;컡G=cJEf!E&K<WQVuͥ=zx^$z)ZAEU8?^בBM,";D$Qn{J!e.Y&Þ0Pg'$L|e$M: VZ2!štJYt)v}xri ¬*1+ԆdC[w1gXG;#056CkcD 1+PgGY[?cEtb]gkCPlKDw.HXM}xbbS2KPƈUϊl@$Cn(ꖂ'( Y(ґb[QHEkD=D#"{*`p̓^%\(m(@ɥω|0Uy/$؁:WtCLRעP;;NA}A\ EOm,vA ꜓ S :zxx]^ڬ>-wvS]Hj!lINT,!"YګPB?w˧ 1 &FszZnW2;آ1'!qTĵ(ߝyC\h:<﫦iΪ3$w)n\toaK˟&RӢakUףF[qo򗿼 4qAPhT)d ǡO?q?K;sor퐘Bpo;6+!.ntc BQпiIǘ,+FlXOd/yS;W)mco^.UF6`̺ƽ`5mXЈ>d@ws", n.hv#,uc> Pݚ$D7Bw3(`}(Hewuz}7摋V~\-j RЉS`p\  K|",ĀFABį8/Y8 :ѝ~&&|,2}#&oQM˘[otmy_fcF UE73I +)-xMQ PgBmC4eY,F/`drgb.5: !C*g"M|IU҈{#ޏPq_˴Cޒ(mP7Г*r[RP1:ZNp'PL UJz$8?oBc`v&K>eFr!^T0*!Re4êXC=D*&:HJ,W>&ަ 5YV\-ob5[^ײ{PCX$WH .$\ML)T{tp*$mS`JDSC8~;ڌӛGSn&^uA*2uW&v"N`3X5g5 4F;9x!lhutb>Qsecd0*(`ȑ.@wh=u9(I80zQ"%2hu7O7ZHNA5Aaw5E`As#ea`6"* tuh [kKQl&[PdRs ?X-w$.4IGӆ<xezNr\Z`łw-k;dyfzSE V2RG.aT gXg{`sñ$JaR 쟜GiFbT̠ GUa9H_h{Z=;hZg퓮>moя?6xڮOi> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 177 0 obj <> stream x\[o\~G@NxA~ȱK lv9Cպ( Wѐp(W.K.) /_R /n%,fs,'%pa1p.o~q}+qGrV7jR}\w~du-O1p&xSD/iĉJߌZ[9? oi'lblAq8's9Ǚl`}|6'Vή,b渟\> 9/FsKO\1אBMCRYJ5y=# V*hRr8x ϡgƁ?Pݰ9ܓg j$|=!85'xoĆ<ɥ+R Y-\RLB9 Vl':\ؓ 8H7$ -5m{pK)U q`q٦kmۥ:%)I/HVbUN<G4kIhU'p~AK`Ė36ž ~;[oHDL"Q6SN3V{wޯZ?3N,35c\Rj旛m&{0kd,09Uظ"!Ѝr=eM4q> w҂kd|"\Ey{YJ@xpG=,5\Uw;0ѹk#[xBì8[|Ul4h&Z&+!wvHb48.ʎ|6Itv'=ըkO%"2x)Yn©t,^klS$[RVg\.}_3 dw4뀗?>?䀠CPs7x>"6@# MZM/ajizQOE kt f Ǒ,z`% p.h$]깎b6Py*9kw2,dD{öpz^ 9sS +*pRL! 8PТ_uh Y6n)s(xY##RKMA"L1[V%W$FZLFb#Y\^zn,pB$x]B(R"z)fP\UoxgTcv/qtIo]0 i 1oPl'3F]5$:zC&"bqNwI^KyC.Zx; #*tܝMcd(mDVs ՎՁbE3%e%dڵ'p%,hF{[ -seН%EZT;$ᗊ,{H =mAYkzs[IrVL|Ex8fbsP:vW%vCݠ9O!DSVͺ`E5pVu;=p#b>1JJ|"A̚͡ yLV S*zX5DL+7&%ǎvo/!kmTZ*0ٿ0*6{.jX#Z!߹h5 *D "ܷmfZNTه균meT13*u ?DV Z )Ͱ5ȋeR;tzm!e=y3yQŶd͢DݙP} %p-o,RKUZhW %BӜ\TY9乲t,*ݚ6oȾI7D,PL'[Lx.rLp*&'Tr>kxRE/pм1gVl$6#BLj1 k4* XhVӻ*-SȦB;Aڥ)#ҟgWRdy rOqvMF<%o4Ѹ޵*Ѧ<^Bv| :&8>Fj/ND"I- pPг`:>qz3GeŜkގQb#L,=ruI6CFŽqJ- 9j FX'ω7UD!4|6_URU |m IwÌO-ϭOvʋ5>ڳ&;&ulZ{뵠*1@wbଉcMQ+v35ZLϪ5W:gxĺS-_Ega.8ʙ2ԀM4aN DNCXc (P3qIYhxMVꂴ'9JɉV!nl*vacݛ9>Lm=tm6V^%f}E& 9!5$׿_BN\?ڶwۧG6%~ Ej/s;^lR6m8J)9O1ThQO򗇻o=e_@)? {:벂u}S@?4Ѕ|[Mo/xK-ȥis#[}%aJvuwmnbg} _B˦Ӌͩ4:L?'t4 . endstream endobj 178 0 obj 5035 endobj 8 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 179 0 obj <> stream xZYoG~ׯ .IGX쑇a_i%ETE_ ə] fUuwͨ6G㛏7ɴF)ZejQm`@??`1X0ωa}cm[[a t[mZm><=MK1M5촑Nq 0>Z8PR&V僠lZK3Jk3&xknMÚݚզ{kY /)֘aƂ!dp҆8㓯(% M=8H{Wpk%gָq(ߤ&# K eK(% 1۩F&l3*"dx؏cXB&f3IU%l&g3Q h 9`f,֝ /]VrcX(RŚ0Np"`m%d`lv8[[oV1n/<ƌӣX ~ 58NP6RҐt2&=lf>ֽ>"diP)Xb٬ǰum|bMfKLf BI5rF8`S.ү`ln] Z@VFY# /K 們Q PJ"o!ԓd~D:MM p7_ `vy|qy.jSЦ*5v\U/[3670f 1oNۺv}[phgn6T,=XsNX2$)\$ 4 'U PlXfmJ&KT19kK$$p&W$.s[6o}- SI!!4& Pv"Mڊ<6䑒fL)ywI?1Nr:&ks#ZS~]V(k( BWnuAv] TnJ^[p.|f :d  H ,j{S)8GN}r@聪  2d*2p-i|mEqZN: 8䭜cMfx^,uh֋Ofs_>4?-^z,A,Ϸf̛|knn_!e |dn>,Vf?mN9WyZo7O8릙o?۶CbD%SGᶖsf#qBX@4(H9$*⬃0NmN|Wb*9>)&|w4ޖ^ I*=7ϋPPЎK\W!_{rw0>P+UNn!V0ƹ[!/1@(#9"t0>etٙFo2i&肝Pbl5|NnnCp .{+ FOj1rѴB>Y?[w<dmGɣr>u46K FLf`#>&xćWf3Kv@4f=GAө{63hG6ڇn[t&|:FyAh}isjPw͘v~LW2tƙ!t׆Ti}}#4ƺb"0tZ_5Uu=NC<ξDj]̿η$b8f] >Ez!?Oԧ)yZQ;&vvY?)=;K <F @]|'ҢS#5SOO`4? T'[eZ?|BZډ Gf8 22Z]iDVb .VPSuB;\0UG R+HT#U֤PUWXZ3}ep }!G׏ўr>#SI~,%d#T ;ȴ 7Wa~\^V'k@q H視%kCNݸgX95-11\2<7 j'hߖŠBpۛ+z`*(U@REtY=*z) .bZi&ơyI\'@ܦ>('yzz>{[XgLPr "`Y8 oFƵ3 8./ޣ6&( Vf7ƷKtGΘ'iG̨W$c&KOU.gVO $SH}nVP߻Nɗ4Z4'B SfɶEqȘm~-r obruӇ}0KMK#bi5k:4y~t;_.C^ˇf|r1)b~Tt10RW 酵/.oDQ(? endstream endobj 180 0 obj 3231 endobj 9 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 181 0 obj <> stream xZnG}W gO~tI6<G6#"{n=%j GQԩXՇ+'j BUBڅoWX4Ʀ V,($5ֶXk"9]bS>hsW3Ql2 */bp<!Mu|odIqIINcwtƵm\cqk;\ԶX L;³Tq)Q3eAQfəG#ʒ3G9^[ 76SH2%ƄR&KY>nM ?S5`ˉ_ftP0$NSR,lL ǏԹwO82%|He3#\KÚ-CO6+B#BJ$9#9k -qmaUnV%M5b(˓_ftŐ0LNSR#(%QCj=3Rd\KG%kY^և8CO6 B#B,Bz=EGefVv_ntP8LNRӷ]h&W"pa}'tv|5؜Nᷫe̽fTj;u+WqUc InXE{ E3SX=NmᘘTONտfjCFV+$m&03@wn:KΤ%Ra f6=|Y꺦tRN}) 2)]RV ~[xaT.R 9^oZǫ$$./* -U+Fב!>eW}7UA^S/0^N=aKP]N 5$LFxS^JL#ق3nWJdDzN[%4os ŧ H?.Ԭ dTt9(pa0I%rAɖU3 j}QV|YuTگv7io@_~E (T(ͺ9[96Zx$#W<+8wꙓJ|BaE~&J)ԶpJ^r2kkP_HNkkOh'KnA}{xT_VT?OHY%'[\m6m~QqlHKdi^_mpuϨ|I0}םJj2IJLdHLx!yx4P I]-ҙw*Y9ey8 ryD*BFݧ 8oծp) F2k =lT.\S P*f7aE!14ATI'pjY 8VJEbCx.q%iN32/E WE?RW \&hd( c2յ5T{,va80Ľ6l 8Ѡq]*菛SXW%m:5Ϊ‰*&L,&Z?=YrҞ F\g1lm@pjԠW(e:vΕֺ 7^aO)Dd9A8R _-o$( xƬTt Yu.,\-N>$GQw#qN2ر3RᨕYz8.9q.u uy+_K\!~:S4H%¡^(gBZ\ɹr)o|Εc[y>""Jc)V G"˴UN\#= W d(@sw-=N}y(@ EÁ|!G,"hbp&7Q_8 x\" R7@?Hg{Dy+z gOOlGQi9>](*-{=;4"cXǛ8>6-9~06e]YE#\$43Vvn~\&a.NRWL8Al 6]]Q&G:>L/>&wEos}yrON腏o"T K&pP $NSP?Ӧ9JC{Bv_0g [2+0e*gEB{to~qLwa ZR8kᄏ"nӊ$n3G^= |뢱͢tjѣB7qZ+ihWl/Mͣdg[O(mK4I%cw=Β7ۋ_ռ>}""N@ƋLYI8x:x> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 183 0 obj <> stream x[[o~ׯX$j(`I1Z7 z+%Q ^Tr.;gvHE;2^ÉT:D4ve==O)eqbUlg晰 6ϴT]Oߩ([,<#FeJ[;o -_)kYN6:AՊȵyGbl:jGdn-*m:Yu.=^P̄X\lCz M^(kXr I9!,(OV>]tϒ|0Bf>gb:5zd%<+WLypIrŔh^ҲbH%k탣c_T@ItϒgR7i~uneƗ|6iQ%-"iXfuzi~W6d6\ϧ$ ;. ]/|%$^ATH"avu>8}R_'& (t`4oS8!I r*h4;th#R0]&N"Iys;-gj%;%Z={xnN t6(,hC_@4^m7@|>F9eFZTC_Fi9 XqS64 #x0MS4|"MS hcLǠ;쇽 :1r*K_Kidڏ ڕ*]q{΄]B{cЗpEЬsUݥ-sl vX8GZH9iGtCz7 m\u&]b!J <>|5>jSQ̀FmB (COi`8KtL(EggMP"孔Ed-_%+qa`L&-E/ыF0jh*YY̷,\ :,hǒ",g]V}q)c].jMi.BdB,RЖũa!\ 2'88ҠJ,{@Ӗ2W8.>"pFF xdhNn&Z!G<9/k#PXd.Y&Z5'B5 !4 Z.Epu&iI = <pr+AR:P@DQ8Ptm{Σ]҉4Ngggg7:0ŀ:5qG/&!NYtn׏M|;m歳>4kyV T*0ai(iTA8zu,`2d^napĦKOJ!ɥgmTPNerj3`/@@< r(TQj$yDW7yP%e(I>AksM`Ie$u7CՄY$* Vzfxk8Q&2 ᵆtj@R.L* \;J8*%0ղTH,7ҹipVgU0iZ0X|лFԮ+v^>H'H3P rEfFL(H\ls{wG_=#R^Vj֫OZtdn:V8*+W1.ctmnG>&ˣ"LzqxGfos2xM_2d3e/u; '?v7ǀz[eR]q:!J{"\+!AݲI)o3&/k0}c `3l:< yyѣ]^3 zZwVSB@85c3~˴bKCr?JTXtYB<]4K3E>Q)a!7iv{")zN6v {^M(đh)[;ZhGKh)呎~|VGcw̎&l?k%zRG8 kTV՟Lf /2o tQ5Q]~F:QoQTz\6?ٮa߯v Sw7Nɾ}+qmꪽ.ivKN *K敓̯f^|wip;uȤ-)׃BT9%חd{퓜BH{cbFSGvԩC=]<ԑCZmcN}e/A~ZMA3.tW:Tnw#:m'A%7YХȬPg͖ ݒNWǼrud_n.į&)`mC({{ʣA<4 ;AZ,9iKLd1=-:( <GLE~(қ{c;c%{P*n  ,W pvUlvBU 6}ܷ _DvZlFgPXj]MQ*no|οÝ"Xf^ѝ endstream endobj 184 0 obj 3074 endobj 11 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 185 0 obj <> stream x[mo]G_q$Hl% P "W׽I vdP̞{ٙ{|#89kU NjlZOxeOZeqwWcj|*i4vo So9">}{aE_xl)~H(jU{|  _y?ǘÑh\:qS >R 쌱8˷MףQ*o΂ppໜ.SLOh?ĘсL9یI)h? ƭ1ay_rQ;9~jL"g\~:Z}Њ_? 3ԟ3Wf 1su ,^pQzbjyWSl9:*!W.1񀽁Pf S9X_(%S?IWଉrJ?]ʙ\|LϷ~XM==}{|x_6 Ĭ6 Z o[ƕ߭FkeXQ- bz3EE@@+w )@ ŁwY#(ނ)݂LdA ,hEFY$[0WT txZ:]`Eм $킋^3z/^ Tg)עXu4{ebG*+UˬcE.qKA撲N(nMi! Gc ZJ(BԚ3 WV̠49` ef)]@%QtƧ 7 hZC 17n(:ԋfC1P"-s ڄdftN,Nt0QӞtBd. $faYXG kJT(lJ^ \$yђAU[D٪ǝCxQAxqH7OET4 rTx *oFzgR"-$K>)Ҭж2kELA*VG+dHH 42z띮i/u!R=vwFM_ӟv>|s ak'y|-8ĢlkQYN-m@TDse X8a @`Ԯ5ݡdžΗ,4%9I@Ѣwң'\j\M:oT! [€pRܴ ^ C)NrEYAQ4E$!PcA/#Zy9XF9Q")I ;H `]<ju!hqyygBGJ ?۪&"QTNdT #&dD-P.F+(N(kqKs$ WGO%Yr*R½-s>}!֟Y(8ԣjܡWω&C;`؉ʔDW:C0D.2uUsG+~־ X+ BܭPF6~Yܔ Dj򐢎\]̍~RbyD9=,D_u|j^yכOTowwm@6Mqx(Pm%VL:I.4Acޫ7 BEYO7ӇR"ZD7@x#GԺLjPĢSX4~H(LHn[ќJ+ʟ wÿ} %' uF5Tdƈ`?v7ϿxsȄSVΫ|UOi#z52L4 ǟ:+>uoUt. ܫy]?dH}N<;,ի^zrAG{ҋ_> /yzDן*J%ܰƁSZU Lj?WMw&ҿO< t."|.w_ݶZ&׋^ZĽ&l 0tcУ%NX5]잞\ %nw0ݝ`8>o925iU)a0Srb`GdUD='7zTJEߕ/¯DK:_u?cB"Qe%8:cO|^^'M>/NȻFRb%r0+G&C؍WT*$*_QPwȧŐNfril6ά'`' |؛^ۺ0#vAE+{oVR? PpAД%h"9D,!7J9R,,A?)yTGH(8^oY;\GF'^^[WׁXH'9m`|C9 UHO L$ 4qZn3Z1Gv: X o6%RrE]-e@fiكti7F[J2^h-̿w~5zF`öֹ<>Njq-#LU:hknn1A : pHNAlW,5)#>xx{z8t䝑ttHFt[M?}w#m~X qiٸlp7d£/ r?3AsY uylKIDHB9R?™-ykbiWrlq[wwDC=4-:/ɸ"=ql%#3Me90oax0hyFWZqNv`J2I@I4l73bgӂ8 H7DFcAPFOb`}D9Πbu࢈eC1%d$kT݌ $\7(Bl,lmfcwFPZm^!_/mkktrll- #w'5WʵRzNe/X|ћ\=9q&Ds\51.Тv+ ZWqj/fEh)nֽmC9 CׯyD >UhnB*P AYHRr!E3M\ƟXnA󖶙n ^n鵛S]cUХ\34BJ]MTZEӜߓRH0iӳ|;FTW!ur|j! u2m/tTNHyu9kp99yp]=g;E?l@9p9 y!MhW9P;XYh6)l9 9U_ UA~7o}vw6,Y10?!]BQR4zHGj"Q endstream endobj 186 0 obj 4145 endobj 12 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 187 0 obj <> stream x[n#7}W>( k/b&@b6~GdH\̿-jdRf^ҰJsJ% >Hɋ}U}s"+xa܇JqU 6gׅ52E=0ZGÊޥ& lnF^ZHju?O|x-!& |VQcd}+u6>?12䏖Lf- k+ 1hEd CMS਀4al J*C$aTJ 0w-`rS w ظ4IFSBÊު ! Fa%phPi@)Tj&O EѶaz"ކ[&5|(Z[=lh 5yL҄! ZSlJĘQ /NЪE9X?% (Z,␓G8* ]29fZ0P3<5a(M Vpɲ]@6R͈VV3* 4J MY fJvPvі&h d_B{A+"MjrG BIeh8bj&+1:SQx- 1NM<Qو)TH5P<G(+Z%5 1,䭪UH5fX \D0Z4DB*54aܔ橙( {- K9d CNS਀4alDJ*C$as|^N}M%@j]ђpŇoGoNLᅶiRgǀqhK` hD6&̅GϧބJ_/җʿ0ᗫʿcķ||ҎX4% D<")nJBWR_-azI=^|+8W~[=^_ʑÑo^a}c ?K˾_EeIV u6e[nǖOSh[pR0Po59=jaMS* ԋ5"OBIPSL5ܕ] :=.5!SW~cpe{iZf*B$C-@An?޺Cx lB LuhdZ 3ywZTg4jW0"(e:EdA%Ӷ ͗!xB/!xBjͩSРowH1 T*ʮ{_Zk3K4v(Nsk' 8g)3:M,i)F)9D tI -#ofG'XUvm|X5<slNUNu6ҝs˼6ShUE+G?huKis5ԣewU S>&R RٚR :o 6l0foC^c=8n-2O|M(9~E! endstream endobj 188 0 obj 2764 endobj 13 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 189 0 obj <> stream x\mk$ɑ_Q_dke06j7,}gzfdA. f=U]]c/쪷:232^j5hʪ<*3HQcOW~{!zDjʛ<.~,ϔg}yf>VϾ\}Z/\sY=)N8Losӕy˞]-x6-5 ,eyVYmV,<;+=z PNO+=.{& =O :AOPTs{0%'Ο 0qx;=h7kq߯OcK4a49eZGϟj??tP9a? q"ڏ)*;1a0=&^l%YL3u F+=)3Oěz>206-. R6O $7x:|؊3n:pyɂ&Ic#l>dlqf(%!/\4<~jP^#l8?~}~0ax.P+XV#P(1X%\ w+EO{ݕswiC91YUG!E&|jb51Q,gᯇL?p~ӧZ>|xiq' ? _\?0K"13]#y( |k0]1޾}[Sƴl3n/>D5Y|P̺w¬W;a1Mzt-/PIIחa=0:d|G0].2w?NriN.qآdZyI.q9F8l4bbk'2[bIBmؾow]Mt.h;_ 5PwYo)P6jYzQodѩwk E"Z%5M"JFnlvkŒ0k 75V488.֤vd3[{SE;f2xNw`! ;Z9c.)dk/d&BXް1D/LܨbIn[&f4f5 <(gv |Bjlj1k9SVȒ>>aA j4\N;fC4l<3!feE@je*$Mak}dfEr{62o(mВ{n QnsV@qet$Yp l(_V4!j- R% F`]p|SFnvJ,+M 6)9FͱGٳȀ1k 6 3XdF(ulх/ :("Y-5#4ҞyDN h3k`b74NR@ߟ)SŢRFnm6fV(tb?JnOĶ`ѩ8u7"k{>=~s wΚ*0>:: hX2 X{Y;#ە@Iqq?R**(;9;e刓j('1Y<@t}YNؓRIq::%CSj+HS昚jQ==¼4sx Zpd;i$TdAk12'GDS78JU26 ބr@v=/j gM8dj6NHlT9Kpi.'p=}k2 -hB#j'marNZ><5(GS6$o&3rHYK.&Qb$DZX0 3"LC+,Q FDxnjBgj(>?/iJcP45TDŽPe(]) IPȈ,:P$aFtn+^Sub>ColJdLԠeZD] uj1d!d4\6%ə g2hO  nG>@.֚ sӰW'/r).M/;iʭ'-7V,L ؉[$J8*tT{E"bc,F-~ܐ`=>i_\vcW*QvRWgΑ yAFsS<'-uyz6Kȣ|J0Z* ª,ٯC0D2eu[!*$IY{R"{'eP"c>ѝxq{ˈ^J7 fHcYek!tR YȯG/gNWB+޿SdY8J6l74) .'cJ$[lV$,OŲԖ}#H@>v<+ۈoۑ5O p=8-J e *`k!ŌA$ۣ rn":*/bz|E!h鵀T9FNzyEkeuBydLc鮎rЙI )kUxC mJ#* 6JN*ˉaT$=iX=y V!Cաl {IEd/`<>_en8Qjt R6 J{:e^ߢlK(2-=94ن`v4Vp̒9!XD  "ɆMHԁl2ٰ߈Ш?ЩxM*&&ͅq}eҎltI0"vM?xkQ;Gu=g_G&O})^0vTu|msA,WS/17]:cX9H&A~P׷ OOñJW\_?g//O_ϯ[V{PF ga=eH@JlPjlO̝+6ѱ O&4h'mH.1RfC'uLrԭW[EzYfMN*yg~J{ tmJ޴t]rwaDE&z#em-f`e9/D[P91y^Đ='%x' >_t7E$lߑ#)j6[#kۘ|1@$_Q10ТUbsEI jrnNfgRS͂5^HU6lP=~B$+#gC8kdr( so1B&/Y&m XIۂ,PSL",4U:f5&lB11Ag914% BFRW󻐚52F:c7Q5|pbT6r3 }gҝS諦C / X, 8[ZMҴӍ "9MydM.@+VdӰ$zۈ6aKTzH^]K G^Iw+IdסK!g1Z^fa>0`i֞ب@QGcC>D.[~ OG(#˜g9 uC֚r|.-c6{$7leӆs bt;(n_L#|.Tv^w.Q!nnES|ͥR'笣(68-GN܁wG 7wiZVeij2*y Z tymjHw 194`& sIZ"Td.۩ aa ܷi^k dсntr=ӣbz[.$ntM?܅`D/_B)sdl$st0p#hό;ɚSN0KSXL(M]Jlh-zݭBNv5=*>Ny{n&xVbo9Ǯf(vnj^.GI5DE5Ю_fl{xە}6HffJE5:}\=\s;Du h b.-7tֶ"i$%I]ql}sMr3. R]Gudچ$yCQ:otLWM'SVRAit9i> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 191 0 obj <> stream x\Ko#W 6l{ -- @`"Zj$.Hm#=_3]5Ms-75Q}w/Rs)D+ک>ݟ/B0|t# l=˚.kY,}G&|Mκ>hIFU6=ol s9lfp)V=!,n%q+#?؉ݗ55G~X#~Fkpqj̜CmZۙq6- 9(݉JLcI1B*Zƙ>۲vPjYÜ bii1- -)-Ѵ-F'v)) 3N;k:К޳sпjC _"^1ba`ZҨ8oqْP =Ѥkśki5~swYط6B feַ.:)mN9Uy{p^څzb\BϘ{A U}s`%/X#e-0yv[c`q8*XKW65%)7ױ׷ǻO՟ݡI{.iUIPWAϬOxfl f)!nˡ7Z) +[荪r)¤v:.,j_5G1j8" T&a!A&QA\ɏD\V9P+f5|N.q'P- ]< !^ȘsI*r7}^Eنܮ?߯5' \.uKTz-iH"jP_\íMP,;V+n``mKx Fhǂcqcc׽w0_4C=פcO^cppYǓC s#4LzY8퐂*2]¥08tl!WV|aJqZxi!D|LCˬ"IɎdwijᘢ- nb焐Y0-8*xȓ 0ˉ!x#*f]TapjOJ425|m;aCJm-2n ր %v&G&ʚٙgEXFHox< |Q@tهG]W0a#ff )/Cѭ L_tDFf64u@P,JLD)AUaX3ј(=j B-{]Tec”E GݡbܸwT$[@$p9(J"%oT58CǬsJ>^5>|3a谇0l(KffJBv RӐJ<8$BQU뮄V[A•(Ey΁ ]S3z ?uݮ?>w[>|dK&b*<%T1"`s>n[?n׽l^u^?}֏mH==P86?ꖏW_^^ޯz" qܯݮOc|XMdZDr=mWn}X n7bir˒+]gj%*i]㽆\[4  EP3C:; ƈ$C!5ܾuVZѻSCsFMK٭f,Tj :Շ3`p_:ӸtU}e!4Y[Rդ؛A q G5o"w%AIZ?}b4#9Tmt1/g-['*q7+b#Oky6 ywn<>-?7!q1!?jR0wO[x&NLTfhQ#NL%$&]ܮO;Hu-cZ<9¦h9u=ϳs"Y )%KYmG9֮T1pY댝*/mC.29l &>™{DS֔>So,9(5'6^۬\-jH͹VP5-#%Yd{Ah2׌HZ{V+(6z PgF :8 Jp0H NJ_ߋ'Wp((*SQP (<L%6ԋTA|-cUQ]P^5D2|dij5 3.'0J̛+TR+}#e'ڡ5GD5boY hن d[ՖLi [8jK),Q^6{%.pT}N9^cp1 v}^n<<2A͋kCIZ iZj;xsFLpүh$ei#EA-RVGlfy$!a:) u*H/j+6sm½qdEE#5qXG%Y}OnΆfkM͞ H ݑ|.-{ӾWФ&yz}! -]Az}sx|UzѥMrҁ'5q|}g[Y MW/jO(xn{y=@_ܞ,oS (9ܱbd|O`/br wL(j{WQ]YA?4ſ*xpy ?|r1)ٷ Gg'qd^G>\.>ssljb՚6F}D~Ce:̚{;F-|uuB`| Q 1Rw bAF9$IuR`F␝ajlYp'gQlgXP[j{N%e^Q 8模FQ:i! I`r/Pɝ< QYPXObyTc Ol1:Ga9K)##,q+M>U1!$/hhiiI-_xdA{6O뜍daIFkBXIJ3U49_65N3C#cΥ@LҮpGeHV}vou>k(4 0ү c]Co/2ۡX ulz>=5m>-nw` 5D^,>m@sW4Ĕӛk_/Om߄aw6lCoXj <6h4#E϶&E-_V endstream endobj 192 0 obj 4413 endobj 15 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 193 0 obj <> stream xko~łBf)`Y1PhV pN>Qwx]QG R˙yz+4?s QPn"B0DpG ~ؔgw9Scla1gIʢnϘhΜ>9z8;&|xE|IpxC|e.np(2#GÜjZwF̷*t(ƙL Ck m&gO̰߱+=YdCBˌyrF9|&eNCučs+v4d$ST F+Y2(d:&|(*M|Ip _!SCtÜj!5> 92J$Yx[~E!ӱ̰s-1=Y>drs.̇LN9.sBg Hs0w+d="x;{k|.y3.J0+N]_No;)|]|'2.[xTqx[d~ 3j0D` *%9`]C o#&Se,"*6ŲMEOl~7/oIQ,UQӖʖVMM֛%rSݣN yVkr[ELnvgI,w%I*%^RJ~QTUbni3"wb/rCWes֜/DM_JO:a:CM2_~|+ Ԭy~=C-ߔE]լ$;R?d %&8 &n/F=f^,*mm}{H%7PR `(m)@Ŷ^/z>+ϤʪZowk;+ FU*=zyN&mi[7bl9! w*JlW7Ц?Mn~>By18Abl>T'kRA6?Ł*GٿzYdT֐ȥG3d6yC5c1$ZamCK/~/>WrE5=Jʲ߶Ŧ$7bkYWvXRWж2b@۳Bp5 6O! {J΀qjX 'r;+u=-̸b'@SI1$ł9b29ɩʟ 0ث.lX]v2'%Do G~5;#A47'af/vI&Ё5p":'@3S*:c ;Auε^BD2a5hD(` @CmZϴA^z~ԾG0kn߶s+eII{+]A$4{Uvy2}k1w 5[h[R6YUpO2cQ[/Áp` >[:_5ӡEvL?Qq>"4Nji}>ov| Ǐxc>~|k { 1hdI@vkk*1,+f;a=mfb*469XB\PK7 n|"$4Tb|B{LIul wVa& e<sJ@~4"bH׻"d*h2)}LȜa e =&n?cXDOiKy+ğbBqhOh#^EZ̥TSF+u:Fp߹Nu9W ݁jcЄ*a'ls[-"F-.HO7{FQb>K(H1fx4TZYІ=ǎbh&7te(h=2BT M-L1 ._g0zƘw(ZTPӞA M!rH e _S *'q sr*yfk٬=Po#~ACiyIɀ ($^COL*jjp(@TFHE.W)w:XFcbH('@_ m ҃I}[BfMi`C$LeM Qou8%Wc4hɝHG3Rd1!Sm#8f]}S/'9n.tJ0nj wASЋ ԍ5!*K6*,$Khp&+05&jѥ=)e;0iXqqZU>mPSSKm19+Pv>'BK*@= ^G>Hm$9 -ׂ#OV$7A;th*|޷3\·9x, \GHݩw!N~x3"ЁwSm!;mZv[z=!d0&f{=1D;=l؋(*dQ8UT1Aީ8io a)qc$+ZP8/r dn"}Kss_ꚞ':l"ٸҽԅ8OE' c{_m:Ag()?\pgA}OYE*P!hٻ tsHlϯ =A˜fE!u9%$DU &#*{fm8ߩ=Qj݋ dޓ6'5VfW|[\P\\D NЎǡԍ@(_ hYm?)w7wqw,qT e fB( 4:VwdLೂk\%h#(iT|FWAA08#3(  ӼFX(=7 endstream endobj 194 0 obj 3101 endobj 16 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 195 0 obj <> stream xZmo_A_C>AR.ЯLLEIK ϒ\6Cgf}eg玕 ]<]8Q Xa(e"+]"ygW_<X҆/dddm5~M^kNߢH]Š%uɼ,+.rk2 GGn3#Q3|" i)\GW&٠^himݯ0,숇kL6- ֈg!r,OfNGcx@Rq,9BLHB*ZҨ aD2f.aE |dy-193 f0!QGG T֢xP/2Z#3h3"}hh-19܆ɱ!ϡ1t;ʦbs3Mi-KCFsDfKϼv993܆yd٘Pʖ3jci移[#?ֿfwh6Oz#=l$10>f0b,_D_z_lE[W}qc7 * jyl^~]_ _Eu(u^rVʺZ6(5p,wۣ*Vj/~iE[M.l/'J`sSCq]s/߾iu".Ь]fm"#VM߶8?t#ۮ7O]նpi֖;V@įوq|?~QϤ#:V]]H $0K|Mt8&^FD )l" NWP7d۬)DD{ncgr|kM:2)ߺ3(^̝{kDx&r^Ӟ&5;MŁ8oN/>GTUVy~!cSCѾzm}%wj{(}@ QAǽgȴZ1g/00»)iu8w$&qdBF~l+ +bM$bx9RAr3lŠϧ6 ~Jb%nXpJB/{3hc!JIz"p]&!i,9;IrT+Ԧ @BLw,7*5 žq|HXdb1xP,ױ:0et ` a8i{4n*A1U 4 1C*fP{T3K"KR."9 '*KDNPF íl X"U&l] CS%A sD Xsb`V *8 OG`If҇s/ل򥖁X 0HxءnuZ}hN&<:<,)շ!IKʪSG""r\ӢIpR!3 !?22\!h4q'LQ$}\#K2g7򆐎&d\y|LjbSEJ!gP̛Ԙ8#4:K,GoOB(1 BpzT!6vEaSD5^%[.p?F̸Rש Sz*-K.[N^œBZ%NVNhtj|UbTwyOUbs3K>^6~W`нyoMbe f~v ~yDzVuDIUW~߀2gN"H"N(>F{k}6}]^v:@1L͡iO@QgG8K<N4s@h!i_ǃ`zYD=cKТ/z_\z ܿ1qa ʇ`]>i_rFw" !FPk 7}}SX)  S3ODPCBr73^}ݞd3:e?C@՟&'I!RI!hm<0~~:5sta?Y_/~)mLvzl DO kѣn*&ʷaLXD4pDLf>&LMnBkFoUyPċ%J72~&!>e`O'-,=qK)\C+f^U}k"EakL𾼦M)*"^){3Oh4 8 J3uz(F-3^T(髏νK ;;0JC=>m7R&GNZGOd4^7t">yp $21J a(yq44|SlA//IAxL?suɱYspso#9WrdigyZKN4aCmT*TT#Z&QN6=5u걘~ȴgnxH"u| MWzK4cVqY\O2)Sri| W$RnjZ\&֖SUjR1; 3he~hB.4@q^.`4֥iyxZT@Kd N>$ q Rԥt̡i !\I-Stwt@u DO+'}N)uw5Qjf2>K`(3^H'f8ƽw4+ ULfy|p~ѻmi";b8~ /ݬ?< PV;+OXܳT1 1i=rw-0:`eћ拎xKh͢Ͳ!,> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 197 0 obj <> stream x[[o~ׯX/nao~qeڦ@ЇPf *I9 ~g;svHQEF90^˅8[ImZvs>R>.=x΄3 xδT?rpY=m4RUE\U3W'~\UE:5 8Ѣ0Nl)8[m;YΎ ʝJ \*8\qj'k.5  ѺIf{fVI{I3H%gәkOg/jVMk J48RΌcy,u3b !NDDk"0[XѤA4F@ˢ\!oz*%RRF_, m#J_i%|<HEe(/@$Nlt3Pd~?i 3"ai ȅ&B:~DC!R (EyA\ەB= Bf˶ZnM3+oԹ~MDAwT(LhZsaNJROI*1k*N,{t#3P$C>-0|`y-kwͶy\lnmFJ@ ;Y|[,7]GF+3/ _͑Nk6&Yfkro6t}鶻=Ż~ub56#@lYV u]N7`Y-~D%stytq PFe+&:4 1Y72ߊ]@O2zsW@h4! 6etIh҆ u7L"R;,C9܌vqq36%Ȫj? ^O0hOA' ^)8>SxWBo> Գ> Q DtԇZ{@{W){c< cAxB1CyS]&`-(aK4[ SԦDu10r2(14ʸE+(;W2]~ )&fWeDd(AwA5L:#t^DcK4> ZFCfА=rn1 Gi+Ws\+X9(z<Ÿ)̕㢡Vpc֡+?i}uf:9k=v֧غmePEn)- B)=1I;Er:FS`8zRg5[0T@泘 (Xd<]\R%heRha!34/YyUGcC<$; 9.3AVLCr}"l1"9-2m f<(m9GV =ӻ4B9*h .Fq FG miҷC7nXv(5dʮ1^nmy5K &_7xټZ=^6xJPjǴ.&_HBv8f}MBeA{n.\ePnWUӛfY lb@Rf*<^7kn/?%oJYXj5*/d) Ϲ'W͓99a,"9 }iS9T̏ A T6'tēp+ߜUpRFwjS#&͏Z[nVAt,ugNV"_]"w endstream endobj 198 0 obj 3667 endobj 18 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 199 0 obj <> stream xZ[o~ׯX$}px}#) Yv[ M(ZZYL$Q $nov3V j93g=UUiB mƨ6l;C%FԪě*&#"8UC#ved-(Q@ ozHkPwK2aA] YZiAud%ѭQZuA Q6 )w"'H*4S"A4<ҴsIaa w >- ;%#%ok+'!: P< 9h+ϻ]/֋nۭ_kv^{v7jyl?wuws 椚P~04%nm5*=[oVwji~?xaƣE4{:{ @!/̡݂-LE2M[٢G ?eIÒ%a@3qAf#:R F4ͳ> ~ Յƨ5;8]xF#^\ώЮx3oVA!v.EAK?ʃR w~i s^_'^ ymw|J S\=V9uVh17 C[W#L- m]6 ն@$O0|d-D_VU} C7c%yBL*xD\Wl]m%v3+ENQ@[o?4Mq:zA4$h (#u[Y,|/rώC^R)s狋nR=ϡh pf)=iU A_^~RȺߍ -J.eHf]].֗tU)_wn ;F{*ҕsr^]J*0Nj%YhUjvPscx]-uL"{!eb9iDViv:+E}9XȏRSg(.O*66pltj*(nZW/Kt%'JJ^>Bh_/IFػ]Ȝs`H_Fr?MCg { (OrAP?uN҉6(9F\6.y6_<=C "b@[~ņ̦FZy mSJ bvv|iQ/Ħ> Zp <ۻv$kiB{^g vɈW@=@Ё?rN| M3h*;N֑wvYt|kh]Tw^\l^N43jT_Y~~/3"d`c^v.^ qGZSAp(ӗc&jһ{![Hn Mh+.7w;n}ѳ81^"4xg7'?K˂E%x.@%֚9n`_rkFi܀0E' Kʐ2wp&T{oh@|ňy_ZєCHX? <; ^s=E 7˟VW?&z󲎋zݩxk/_; xR@Ws,7!=EZhdOVfGG[tCf$qY)q*4Ϥz/ Z`/hylsF!b3w>/Gyށdxv걂bG~%S11i})5Ve%m4e^Agz. oRW##s/3om:W 9V$Ic&HwtvpCThJй dnX"rgvI}\*PϴTtoym]@dmTЂ/wXbNHc|:9n%8a&2k6xCiZ Ojwׯ/ {f;ǧ΀_tâKCn WzME0k;Lɒ&&1҄9r}m֙A7b{7 {)+{9tѩMP籪]VJ4^;_r%)%qwHdYd)900K1,4Zn} WDi6GXB *Xrt87Y{{ |ZHPAba:jDGb 2*2Aѣ]CibnE08J2mdZ&P9i]ZGNAzc ]v7鹶ZQFj |Bw++m`l}  :qf- NKmV#]O,@/޴kbF@ F/kU_.WwG3hqCv4Feևr.NJFL endstream endobj 200 0 obj 3706 endobj 19 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Annots [201 0 R]>> endobj 201 0 obj <> endobj 202 0 obj <> stream xZn# }WO`,,wG8d0VŪDC[ Nte%9]H+/'jCƋ @δk] ǓǤރq%L Zy{!~Ygxs!-.)!]<+v*Ntx R6kxw%ZxzƜ1qZ2344'Qfz>'QRʲ#ҍү!Z53-eca% >5b+،* 4 ]1gIN]1Fɝ#5%OkY04/M5~FW eQCE!PR"+o#Fu6#1_CU6'&Z fa>t)bZE0 HÝR訐ЅbCqi^@ $ULDkY@̇6,}i.0J"v CM "M_݂u%e^j+4cI8Cm}xr_n'wntx"ͧ d5}LO~jlo1p#`uy0f5B i͛{\.l\?/t1ި3jN?Ϭ^lXoWI/H+yq6*M~K֡4eg~^.M{V>yB=}7{42 -A0>K1RLll UxձbUr{sϧ?v[s}:'Q3[X.ؗc šh7 MeDU-X&ɨ36׼XZ u.zƫJ?ƷvQ{jͪdžcͦMڲo%WT\z>>]S`Oz|mU0 xu 0Ra\pE7Ԅyp@~T7m Z:?*D V?rKۃEWFsZU 2 ᷅(8hD(΅un+6/C.& Z{,_) kpֺuR++i,T8(8ԃXc@qAi/" p  x!&akl@34Ab7x,K[c > /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 204 0 obj <> stream x[KoGW ~AJaAR$}t4ɡ>hVUESY-HuчOXuΧ,^҇Ueמ5ai 6kZct00h ղvL0:. J6l1|YЦd=;Aժ01ge MuKگA+:۬54k1[",{a9p [m21, 1U^(#,umS$22FAc_KO˘Ʋ-2}rƔ'KJ3dy eBŌ ጄڶ IkITHm:(LXt#PobqX*&XjiS9UJЕLRN|CPH Y`tki` EGa>4@,ǸʯkE߰TNk War0. ,YD77εMHPcSɶyK.ote'7S}u{GYIӪ~pqj[W?vn~Ur-+WC/9IL=0]miWn[V/yFKFсm6B bZWaWi}_=ǧ,{٬lBDً8TΞ_2h1j4? CުJm!(.$د;^zG$Z $0X]9&%$Fɲ60gMoCb6i^!r9[Woݦ8xݾlT$~}&YCo%:XmZ ҭgL/Ptbcd>Og9dzoC$|/N%cܜ{X\r`_=No>l*Y}=dx*ɺ3*O^zޥg^/?>WϋZ?TSLt`)ekJF '+4#u8lu7VQBg_:MQAs#vRINU^S6Z|l*?S69D?=0NٛaV )E?F[K 0bL. tIJMCJP1:q2Lҏd :%Ĥ1Nǔ,xVe1+}7`l0)cPVUJdhȓ`ںC) iJ6sI1!(6-,MI_ijL `j 7 $J-} 2t O1{ԘNyGsEpFO@|gjkT]#X"R>*'1 ˀ*z\$*p It>}X^k(;e葿YQ gPȽaao` =ۣ)3ݰI*vɑԹM"n4TyCj5 _|k,B6!eE$4ACEe%1jwB>ּwx *)Pm SICF!ڰ2isڌ*%0Ԥ+֚\bVA*Q}VqvcXD&6nNJ]Srx-E;ȭ 3YIsl{+UeGƒo4a觔?v?S!>OSgz7PL! .qNJ<\AU 's$峔 r_^!Se5@Ж6zcʊD.YIFl6^bw΄Nh^.>- X FNdټx%1xp8;^~6_R¢9S6@:bA0j3]'\z֖,hP#( JB0 OfQi@ pKJ$CM 2뚨@f\J-,%i +,<;#OWܣ6#H8!``5e?Y=ߴZLĄO-C4&nBj1h&jh'V0"bM.ܦ)">Fpؘ;4 ZkȊuFx҉#rSϥQt# m(RRh|9>Zy4JQէ=!Б )~,QC_.fDCf&&4tﰂ:(tA':zݜS+%JepfdX U#3LKy~@75d)l8K MȉlEJ5']wLFD3΁CL |3Ac:^1[zކtAyUe\}o^QXV#5NnZ{͎:!m{1a{o A ;F{kiyVuH>XZyK]6~=4(${bt!#(Өyy̘d LnCq>bۇf[{3e;.WSQ& yxD v8\ȓ֦eI'1YIYS8y@<9ˏe1Z+)J)kg3TIJp 4 t-[! x._Mvg7zxȋ~,c F9bʈC_6:t@ 9FMR}OKRAMZ5>{M5Ԃ\=膇qNVqk.,uZ?K1ҼfpYN9i^LC0G{q`^$#1_X9o yܹ @> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 206 0 obj <> stream x[Ko#W `G~F ItYdKi!jW=aWM"^`WfUu=>G r Q>Dl |Y]<!Ě#j{&<ڧVk?_<'-6 * ڧZ#NmZGo-4ikШdxzӇFl&d,`/ka`}K˞}fVŭ]~e&f3׿Wc3ɛm [a12%=;V1>SLkU>|IY4Ti-\^)RabZި4oiPbl6͌=Z1N#v0ʴViI\=vVZb+]z56kWL - [iWuc}^1ΧΑZ#Xe~ṲƦZo3S+%R\kvŴQiҲAxW.o=M)(47F5ÏHTsȱ;o..ѭח旋ސ] GzsSų?Vv{Y~]?=v}zrTRd1޸ x(T]I~b\N$D ,Y.lL-qZBq*r.?`Sxfo&Cb*PF1Ciچחo(+ݏ[嵃^?~sBPgTJLM)<3jrv]m/X)U:q}]tןc>ݏi2̝5IiَfC29YE,~ȼn X~BК͑k ה"pn1mׅe) W^R 4BHN t=bwwOkB-bP9QAr<s0'U%ف2J3e/=}Ω$/x暇v~J7¤v|8}piu• so5kY}1!RV";3#6SR{g՜͒w3lv%O`q؝풯q ߚ_`6}X?~yYPqxd;̣ꙆC걆YQG1ѽ:F a =6h2ЬqE3KqJ!)Lؾ ?gPr4~ݱbj\V0o]%/lN~\sgY]d8h9Ic©Y.q<2NH0%>u>N:[sULIz3'g4b2!¨#k.Ug`40@UI빎rzM'#1X4Z~WDlݭ;" |'c08ƃ79o>+ٶcQe.քx4NK t%( XU8JrwWaq#Ø !Hg%kB9.j"x9#A0O"*CDZcƍYsM6Kb m{Pt\;8Fioz)B) \R[}AT|陮>Dg&qSRk Cjx($Y9sMsZ:[ф,d}D^[wQ7^BKzLkہgpuBbljRV/Yԝe-mu@"l{zir&L6e"ejU.I@_d p>F8Ihn-م]QdN 輭 ˨!mQ**RZYD7IɄ6^gga荩=%T.LkZ>rJLted4MΠihA}, 1f+qe:6ŪGa)>K*^!(Fg/+j `5FvZyreHEs/=ȧ N,4b)˓;!1 rz8I3c5AB<6^Qv\aΕA`?5=/Ԕ|I59, N@LfX,aA&dHg=#0ХDz`._J]g,Qy>/]wjLiJU<%q aq3O<#z|D`GD0y80ʡEADrJ} RB-E&BtVm1LlݖW0(iuX-0 ̱5Hʓ^Ͷ&i> $@$v-Hr-sL7I d[C3VtV'yΦafáWcqP40f0xŗ}Hfr'@nΡtz_-I3+vкqMnj.o#/әcH0x=y9IH (򛶄3OAbu 1v};bu-5,2 VqrX.p0 數>{X9.WkV)+|P.3xA.4oW꣯/u &d%SH_^LKL<~2Gu;0aK;;iĜ endstream endobj 207 0 obj 3338 endobj 22 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 208 0 obj <> stream x[[o\~ׯX/nӼc@I^´f&(NDã2T'SMbr 3y}pBQxPʆY0-,5qo2bep1aӀ9\jV(p")R]#J8kQ} 543A8|ð@J.Cl8v73:ٰ)y"i_[XHц+'6 g2g|ði@B.5|t5N4Ӂ>&EF1DR fs( c}J4m0%VdhanamX 0eb æAs ]@8"$L:󯂃JaZC3s7 DΡ27UB0PmyjR0 Ea)t5aˈ8[i. Cȥfaz)"5򯄃JaZC3s0\690&5nzzk](+[j YcL2g+ ärBXՆQA)Q:ZCx\+&dDUT$k|p `palJ.Clhk}wh H )yBCMܯ-,$KEd s h\cX\3a4 h!a'SD@\gUpP""Y)Lkhfqa9\؆Qpeqa<8LY(+ 5qhanaNȊdm2b4 Cȥo R#E:k_ 'Ȉ> 1Y+LkhfqWAΡ27 \ ʔe2T6̂anamX5qo2bep1aӀ9\jV(p")R]#J8kQ} 543A8|ð@J.C|@ guYP^L1ql" ^_x0eb4 !R7LxcF"[Fk q"l q0bt 6Kn6R/ _C6>M:śvyu\&[,Qz_6z}|u{I1$ IYB8>+D0t6Axwu0ecH6)ʖno)e/ݿy{>?w N٣}y=DApXeb4xw=rz4Ӥ >p..>p.pz+Ҿ_޳6vynKp{*=2hk G6ͯ/yys]oahA.a-d' bv?o%5q!ӓ B֜'~E;&*Z*ȕ5mmU[J]Y`3T pZWb֘ zGP1ֹ8 ]Y|nYS TZ9[ 36/ 4#MhLu& d\!d_@2¶u09yu[yxI-ig9a(>>:o^[F]ծ_5dA:R(/\ׂSȢ֩MeSa*x\Reh] W_~,a+P6…PFNd lEgLݴCB{Ph4Z rY~ 1u/4J8cY 16?QZ=NGۀoe\f(Uc +wl#1^*m[256ʩm{T\N1=ri6E@a]78HGoTU6U8d6ȕ@ l)j4Х8se@e ۧ- #h-{VԹQ/WLYCf&zu6=Mc+Q:9"EPx@e_yw==r63Cp'{>ԅ܋٦rRw8ux*TvpV+! ka** ëvwBÓ % <Az/b۫eljKRX[99,w'Dxʏ{|f0Daf}v ,}ΰaS\YS(KQv1] Yѕm~4ԩ΅fҿdѮx| jnx" j+0/-ro 8U 絪ݯ;\Sja;$UBz;a`kk~9LaXzKmQL气G6 SIS85 3pi aw"d|DTLZ9`aS»*aXTp*``3ڴhaP-BRZXz jtm+ |:*n#|S02OBSða-mw$0LOFDk0*a)'aCoV--腯pmG/|b.X +F`t`HYYpNHP1bSё\F0&]PhePNik(SP3UCT)S;ABv|ՓMᩩ[z9S7љ{j:@>3TiڤC nf}vt\<+ۇ[[ۮ[6K[yQjxkKn_ZԊ5v9 endstream endobj 209 0 obj 3242 endobj 23 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 210 0 obj <> stream x[ێ}߯ Vh@Z@=r%ڼ,H}|N͐3]=E.VRtթYh|&(TkR1M4buo7 ! A6**6|7l\ }y )Q'*)hFLﴑvq 0J؇P2uaZ˝{S}{8^g[vc_ڵG6VcgPdՖS1L'Z I 2Lwv#,ĜsC|X `t&`"P0e+X\@ j жժZdFy*F4ZB(FgbSmùqq(2tp^ȿb̀b% +Miu19`G8iA9`Dk%Āmg0Vfca1f*c|5,2#ټ<5jyk?v 5Ť j,MIߙdGa*egݝf ymA&j2dl.b [FwTQWޕB <~6'`{UP&z3Z"ؒmĩFjw]rQ3~blܔE^ʼnBs5\f;c+θVJ) f~<[ ]s7w'XkUAb5hKV#삱L` ű@;&S4j] yc%nKh6" 霐5-T s06p|`@LPFBD'‘*Ecֵ(OR&S,mFFw{⒟t`A.~?߮#M&Tf e4|PmO^჎PI?jӹUUi 8Yo[g?BgX M߻4_4Lt4qa9CYVT|րZiU RXw,aĕM#w''V*]"Qom$,#P5J1ӝ"<o73|> ̷#&a)ĀtFR- $jd Mʩ8ve: Ŗ^P:.:OLr/#}+Ym_mRBΩ۠qR%ܫWʕ{/k ֛=xDgsȷp\3{X.>-獀謽t^EȲ^ 6}QuW6gDyNFYχ4戊aj>urp)еda=]8PAz+Um\n#ڕJ,Z"z :Nf#|B][*K>Jz$Wm`*m4CzT!&=*x8 !\훜fou %Bt"Hi;[PѪXMnQt@ǫrP'L)`S.ŅOU&VQĕ~2K:H7e-|:1@whiU\P/:cF…bg|nI@)o-:Wd%<t `;$[n&׻ZLrjFnoBu ]J45|'o;)Z]Z+d\:k4Sɇ뺴R.Dq&$ڸ+qM5\M`GWK:6Q}9Au.K G4G&v" E&۶Eu7YgUEa"g5Se`OkpoYRYy:k# Qu)fo(լy=u{OTĞjJZV-xLV0ٷoٜ261jD_TnOϴ]6ߐ^Fծ$Z.ֳz+z)dכz'ֺV{^>aP?J4R :o i=)IF-1 6^lp Xkϛs<*rTɂ wi?vn<dte|BX-_a7-vCI2VYyөQ? ׄԫW}ab m̐˜褰;u\B#d*l< **4dEPeAT yUzٕ>[@ڇHoyDrÄ.)ꂮ>OPԱE|{ImGt+>J\ΖƉ&E'}9:о =vA0tcnp(D89ҟ ㌯ !C^Cd ϐR\so|e 2ZOq見ftS n5/cWF ا1h:BqP@6/P{*e_/!gq K`*'IQ w T|nD802i2\_aR ۖr>U SqUO ƫ6su){-Wұ^U2QA{)w$е0Q]GowD;Cli-28=dS]c+[/P'(5t+51>|\¡/zt񎰒جv/eXcxpypj[H"}bDyVq]c_j endstream endobj 211 0 obj 3716 endobj 24 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 212 0 obj <> stream x\[o ~ׯ8_Y ,; )ꡯ%Jut IF_r$ayL?r>ruLWuKvp ?8t{q XL)S?/akr_ ]Z]K_.a?EbFhӼc(]+~QgM7PCivqŴЯtuÏd 4^AF}Rv;F{ f⍎R;?"7L(+0%0Vӎ5tYБ L*c j&V3~8zJqH7#|[c 3+Ȉ>AE'9 .$ \CEHMl9wS5 Sl6,0簈vrH[SF۹aUp)Q@k c;ۙDi#d%̄b Pvښ0 N3'\CEHOkdWͤW[o2e\a8-1簈6kFǶ'sêR-$ZCf!aJhpEt[Ȩ~sY8F{ fp!ah4J-Bj¸M E{bʴFXJ'K,a& 9,Rɚ0 K1'ZCFOՇ4"Ӊ?͑Qbp0:8͠0j4r !=al?L(+Q-1簈6LmMOeU[H- P B¬=44O?͑Qbp0:8Bhh5ZԄ9 ڄ5FS5 [W}7Η`|5|Ot!;j[~\uwWwjG)k hT.3t> hFĞ52wT~4o_n~rxp=9؀Ǝqt>G4Ѐl;nAP ]-U-;o24CRc\DQ9YY%ϐ2Yj:*\WB*B`Pjq(SQ3BEHY*)0tOPbakL10L.L*RCpG>ժidXep)Cq~XK 2ײ߯>=|O4~#Jzߗ??=},aTG C-bVTl!=[{n'k|z}}:|z~e!2T_2>T,puj!eh-<;P), >U|XiP85%$ܱHΌqyXm_#,3IۧpYgŖc`\*aZP'Cņl" &Q;0z+wER\xVu__v7w/nۛgAiso*\9=RchXa!#U(D.tlِƅcJ*E~lr@"z,Y^N>S/_آ W[h B [z =3U$w~ u*~pfBfg{^I4N"((Rď. -.I]왢@~ m=nm®!=tNP#N|We"}LHeUͶ A> cCR/As?Y8 )qG:uS$ߏ* hZb0Ұ#CRTM1Po摥 걄LAe>L;L ¨$/6=**I,?Ә,@0xe;5qpc$D *CAK &.AI;Wt;q1,bGWp 6~Jyu!BHs(L;K!E'=P+_I]apQVykL%zn?w\? ׁ5\+V)'`D{ EZ/`vn(M.[8:}-^lTtx[Jyjy ʠ $*C1Btܻ_y,Ď6ݠ).2[ :J64z:^+?C@{wMH;9aD@X=Th 22@ B(-E > 7yOLFv\q>b3Z-o`f uΑt6Dh<}ڜąVvpb_^)|žGU \.b?B0q[ywtPC2?LX2x=q#>,}%|#9 ~Ӌ!zЄk!B | BuF^D߿t") ez6XqBe5BS Uk! F_{㡧.ɦa;Ti(9?~{쮻ϗ>[Ha~zx؜j|l S蜉sm  #MBj 58w S8<`չ*X.bﳍY%}:~} ZcH?>vߪ7PP%]v7 7G.%[F ׎дpےmɱp[rP *2&pa8sb-&A^)g)VsqЈ䭗Д:T{C0X*>?o)6=z&ѵܔgwJ ft`+c2ObrHLĄ\.Lt8NSN)u<:T-Cbx<<~=̴ 3>tːjoq]j35 YG;G;ifD!$7/ը3hbsZlVņ\ LjS.35fϾˆ<&qx^WΏC7W컋(o\8p3CbNIA͝Tñ^79ⲚS\ZAN Im"vɅUK,}W quӮu~۷#]n̄*yjї/e jMj 占!ژw. $Ayu3X endstream endobj 213 0 obj 4073 endobj 25 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 214 0 obj <> stream xZnG}W y~15,+Ů)3ˋ@Rsz.==Mr$#UU}ԍzq(T%]8_,vCc,UоAas#YrtwDst7Kc،amj+K`^qQzfpYkɛ;KP1X͒YBP Չg5WQAG) 8s"g8K36)< ta7הQ<珴u|rHjSat`oz$a"ѶV;|gj=OD|V~ P^jGG7ְ7RK7I4`joGseɔ|O,τS1kj)ynKb?0\z>: =өPbZ$WvN^x5d6C^RQٔuRP2()Ҁ{u9a 1H(f7<ՅiJ|J/R34H=ˏ!2I@<=f}R{Q* ЪdGAMuT8_ӊW%tc~r\mf֖u  [8c!uDmjWW?n\=?g{q\#{xQ- @$Z?kAajΜMCPI R̞@mWL=PQFܢmjh>mMs9REЎ{iυ,Z318I`e'GA s|j˔ҡOj~;BD ZVؖZ2} # "SAHNaTIt3#T`64{!5s3~jp#p63qnêuINd #_]eb &#=ze-@LcFS^<סV E_3Wp :`ΔSW$ǥΙ]%_X|$ܧ'mfɺiٔFCRzhTPcTȼdg萖 JC~[Q%Y(ˡ$-/|207E1PuUJe&nK~b.jdkhxaYrx&&=we6ۮ1"}Hd4N[,w~`oXh32Ba4WmT/2%eĹ}-mu^,W^^֫zQwE+`%j'jf|?Vje4 vj>V`/?Ou莀 ,Bm AxjZC_^UۗuE'Ʌ/D8AAvbETݔM .5 kghgYKf}~tV}8߽`RͶOoPҖ`Y=*{G;6mX&b#\̷0%iB`":r2->_l|mBM.-e[~ڟm9qgp':ǖClyJUqZwZg4s]lgfH/'6)傅4 y'4&qxhODJ_T<Ƽ/,햄4CeClN[Oe$EJuFz~kE'ҋ^w~_E=p7H+~*||mw?jz<4L(ns,1fh+O m~p&kȦlVhCTw?S= endstream endobj 215 0 obj 2906 endobj 26 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 216 0 obj <> stream xZKo#7W4df<X rE۶jɐ ح&%L.VU(gIS(*ე՝D2~܀Z-̄퍑u'&N?"s(Zfq,k![" w~4ȆFIU舼?Z2̵QM4sTFdAt #Q 6:3I\&n)~,;i-*Mv&9^3| 3`hb$`'*CM!JsaJ%Y$8")D:/SȰ}J19q0SG- xaj$JBdPs._p B:{d2o')DdL&S@8t'4tbP^f BG Ne1h\LDt[Pn n^ |LRR%.9 o5|믪nR?ڼT?,6/ApD<`P@l6w\ |e{qej~_VuE^9,V}xܾF+uSogE,kkdr" {;>v`{kuZ:$q!OGX*y2 \0#˕fuXm7 j4^usG V$⺠낔7)\8\?W^#.x"Xm]Q8x|RYNM"珷L$iIfwzy=aP뙣 Q-|K=ϼ<16l(㘖qPwnUjҭ=Ͳ{ST׆}0Lz@hAj(8v}-]ǦZ-֫"L |k>dԣ y 3 vwj\?5vPwSD%'njal}Cg6΂)k j/{skZÞ!xقXU+bI1u=S.fCkP;{rbə;Z sh1!a1U*(q]\05k&p1 sd9gg v }6M,g}Zj4 fSYR\o{;IIzz#V:divu?BeV3`Y-b5,4':Gx&l _S=-EP_tĻHTdLnK?X{TY< c_`mpN0S #[/ {ESOup??VOz' FOk̼`8kY+tfpS\I5j8վYPkv7^9],G!yQ#e퐺 i?/PX h9*j᜸֓4X8|HC[gU#;!܍ Irf+J1Q 3:U&&#h#G|x3&,7 4z%/pBY=9NhM!'"kL,Zŷ]XE HJB1i8:>FpJWnלgFEOMzOM-aD-\O·"'sP`# RA = ;#eR"X:cT +/?Rpоz]%%a" mGsN*+5'qYȞ E+`W<αELC l3ؒvSVOPQlqm Q- #4)+ ""9EASKNrX|{ql;l={,u$`2圉Sz^=}uὕօkKqkk z Y*DLZ dX9?Ϣ*=d˙,N5JmW̮r8nJy$ƹk]= aHwy5䯸k.;S=/ɫgT+n5_eM઩ߐ cO{cɨeVxg3QHvUx%Yyh!5[pUۻOӫuOjim;DufnxC+Ƿv&^ÿeqݒ!A% endstream endobj 217 0 obj 2566 endobj 27 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 218 0 obj <> stream xZKs7WL9eˆ~ԺueCt!IL%upaVH> Mq4ӕLr++%SNJJ|\vEkݠ<qJqxL昖͚7,dKWdz 얊 ֢F΂tWXca|ue%j:(:E3\ ¥ ;dcdhkf7`#$sZ3?X"0)3;Zr1cE!J|]8Mero/tjhk+Zd) z k|d0kWX9`J4%%j8o#j`Z"FCG5:Z1=uٯ8CSRN #A^BYb1 Ƶv#F|@\_#nxh֎nH1ǰn,֊S<`-*+GLt arH.1]_# B`s?Lb]@Fc͇ΰVrd0%6CQ=+)lx󈣨G=]zN|upuQTZ2$ʪCP?.7rպ>oH9ԃ1Yg (Tt~6zR.Ѯ`։sڵ 2[i]LvimYߍMPL,wiq0[LF@7S&.տ Iſ~"sxM׿_rT<<}?42 # ]=@ ggXb{bt6l][uEj5t)tG}Kk],VI2)kvk\$W>+&e-0055 Srq:q<҃&\ݴkz~2fPW/Tg M^FUusL!8WOê>ʙ&*[HW"+~詓-(Y_L[>iNe7l$ܼ{.?`Z )RڛY̶I^*.>T&%ZT45@#e&T.(:xiL!6aMNRBfDDTketgی SQ9i=CMp1aBA+Pl B)kG9pkRwi˅а*nؙ'Ĵs#3[ҪfILBNADΜ"Y]SWhEf A0Hfܝ$)uYwF7Bw Ӻqm()z@n$Ru&HsX>.esиoOue]5{bqrMkMG E}6fNy;Ɠ #Нt<Ӌ}n|]>7m?E;vy)z} 1xMtG.*;ôR/Yif_?~{wjb9̗}QCP zvS7Q/[5W_ժ c7D#ɦemyx21eB0Lsoov9;E}^U=<澣bP/=1RG"Jvz8QT&zQ.QV {i.'3D %\%"6zy!(?f)itwDBy&^ɱhռ)k$\DФ0]ndTg_7*ڞr,ĸ<#B 1*B%'w,^c%VGnuiU>i?1FSNJ dt~lclF;#gƧ-`J F.4yy=3[rjx?xqvf6Wx 2U&"t.OutĠN OuhLbU8,='&:{*'DOtT4^5ҜPȠM  ŶuMXx![>eG#V$[v2R8tT >i͍qi(-n8bo\f6o ,]Hs.镾cC:UVqKų< t~8W Bkq~ (\]t6D#B~XL>4,dl !rǯ J}@] ie]B(N6h/Se\#QRI.T6sܯ ߤQW5u塆eE>,dٚ"z|yOup_y'(Tht/컢F4%„t endstream endobj 219 0 obj 2739 endobj 28 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 220 0 obj <> stream xZn#}W 9F}F{ փlH! \JY`RWsjjbBWNԂ1Vk>j>pm.tFc,vC{!Yb{ӽg>`hKXLNgI-DdW\PkK$."YB*M;|Z'lPFY^h;|тp}DgQ2o [r0e JN Pr8#~>[0Y) B.ba40%,X1Iт!"G."ل`2DB4,9;S1w1E*9l`- T P#`  YBIU6|` ) T1 )̈-a!oiji$F d`2DB4`rF۞" !r#["EK R-(6Z0dG%CVC O)&z94gB23h d؟8OM<Q 'FDN*Dv3iMmfҋ82mHLI71%,mm+݌dt7#ASЂ6fsL0қZemC8l`F- ۲' -2xL҂!anF"OQ F"0F 6 є fЖ% 9b%p&C!R hyǀID:0TET0@s*Fۄ`0J8!9)ax׻ FцX!ݚȔfЖgeFGd#CEX \D2Z0d"h !UZ0^iu|$S}SGCGD0#@2*"-2xL҂!S( Nub-:` 6 }NydJ3bhKX> $HVlB0Dh !UZ0F`xS)20/ m`F- [> -*8LNBN*D cså20+x:P&w}Жwx~t6Z0D䈕E$C!R '#W+A*`+m`- Ç|A PUD΃!S( yơѳ牋c@ 'Z Pt)HQ#PFT3"cڑj)OK_lJ39Q;EK@DL#xbrB?6la/{W_\g>..ޅXqS~YnW/y~xl32`άH(*,_)@^>ﮓPʻu$ 8p3XZ680 ez]73v-nϛmsYۗ~l׷鎕!udRߊB k7DyW/5OͶUVjOs`<=xiWu(Č2PMn5 o鳓&\},ivnyifdWBf4LW[W$f@؂?s0!BO 5*0=sCh']w3t2YFyhI7gDbkTuDM=(*}pw 9C\Mq͝ߣ)jj8ִzͺ^TWht[)½Y լs8n͍{$ij5YV}1H8CY ]p'郼ϡN ҅iw9*ORGq0(W&Y s'l5wtU :WiӉ3O<Աt+ MY|(@ګSswZW}f) m5ާ_>Qv\|X0 L\w77Y1p2|M}Bxe٫b.\saD 09q(cl&^חm! 9 uG,naTr.j"uva/Hۢ;#{" FX/GzKOG'#SNw~]{pwy$Ǒ/Et|?qWS<ԩ:ƣŮ\|]'mO"&UD`'kG]WE۠ϗOv/eSlPLt(O+ ;tvdנK~Qcs|)֓v2',$;gmxEx|Ar @ AN^  endstream endobj 221 0 obj 2884 endobj 29 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 222 0 obj <> stream x[nG}W g3-  }ȋ"S6 NWur$TNURk|2]h;}AM>mqEF{ѫu0MsF;،ӏ >ֺ<Ř]ҰSc7GP F:tD> gЭ>qGf:wmTUG`|?y\ S3%ILIؖͥ 3!.,I]Qk0Pi)^Om" ϶\03 6Ld-gJJ!(K VՂq>:$`6p,L0 XboKہyaV $ÂAmB,mCaR"&4l– &2 Ea C ``79B:cI_26NѦ-NB1dҟl([p`px8D»Z#”DxI0mlwXd|mx7+ A#5 Y;`8L9Ȥ?ySAJ  FPatlfA)dl [Iy6備15,M#۰`@d pd Am`!j͂`=S+e:pj_y52%rԁFP.u#CP0J%'̔D0%+0eI&S_Qؠ`Pd pdX0 !DY=`8"D:ܼ9`@#(C ``79B:C %'nJ"2$+VRM`f c Kx.mRaȌBԚ {0Wt̿sjdҟK<  %\ #G(Q`tPuo`Szfx'VqWRM`:t6(Y`@6!j 0S|!R3r8_4F&E)`@#(C !#CX0L׽>LI$Sfd w%ٔ f0ְ/6,\  lFQkv(p"\)SS3r8ͫI., 4"08 v#CX0q0ڨ)dl0]Ey6備15,|J: DfH ,fP؃0ERfp؟W#\"YLhE`p(`P79B:~ fJ"l” &akX»W() ۠`Pd pdX0 !DY=`8"D:ܼ9`@#(C ``79B:cº/0s7v̔&YA]Iy6備15,m+@N6,\ ق`P4BZ CaJan^Lsga0u A`%L l].L/zg@8| RiA)~ENYؓ2Q4pI&I@Wld2ߏ w/CpX`E@> .tхw7M!% 6wm'U}COW?*TzscsO71 pz?wOۯ_n?o_!:w0}%&@Ob0 _Xַ3CKX =s/wO)A-4"g;`r]kuY7vr&MK׸*^.*[(PUbaOQ^.wMKj"=% ]K NA. ]6J?P{XLS0ؓ#UDjYS}(RyȖ^A6OUɲ,K Li0M|Or],Q}K~}0NoOO]%ӫI #IJ|SFo1oWΗs}8pr'/ٯIa X#/;:{O=1GrRkqrIhtYqc]&U:]/V&n]`2k1X#[R\x# B'ӖM eTCbi1-G |BhsBsq4xWЀRߠ>bs g+2-&!{ۚ(Cc`[E|˪O5+teN߉ڎ/KUwb|?EN!t=rCpY\dr۱Ω|]uQE/oP|~eN;-;6ׁ3 \xy橑 Kg|1H4WCn$3]OE'Tp̮r$rtg9*|sq: mlᱸv˷K9Yܢ55u@Ez.6jKz#}5G?k*a endstream endobj 223 0 obj 2902 endobj 30 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 224 0 obj <> stream xZmo6_!_rE+"ds([ٳJgH9+u™yyHZV5SBu]YgJ…ٌ?ӷW`%mD+]kQ'-`]3ؤ`sDL/WO1%,I[X oK,.&BYr#9{k z!h) ӔZ4#F'ڶS{ўH5>[#AF5ibKS"xp\¤9e=S c(iN)#DžKc;&2褀Mf#T0EqD/&2bep1x4 h!G͌`6=V#qR8Ȩ?yfS"xp\B^0,C1 fbH7NdS|є fzKXLm>hDF .&ٌ`84fF0KG+q8)GJdK<3)L<8.`869ci00ƛdRLz:_)$D0C_"p~l 2d`X4⦠‰#B*@R?W"X"iLgq yl r%/Sł#Ke[kѩhbє fЗ72Ga"#VlF0 CQ3#MA#8`j#y%2%bƔzpF0C1 &Q,V@&%T(݈lS"/ao%j$hcEF .&/!)p∐J8q28Ȩ?yfS"xp\B^0,C1 Fƒi/nLB&%TH#OL`"E*GbcEF .&/!)p∐J8q28Ȩ?yfS"xp\B^0,C1 \xȦZNESlĔ @4oS ' 5\' yㄑCڤ)J {V0[OGdqh|9hK3d_B磈p0K8# DΡbZl.:`sAlt(!DS B_B_ EJd fxt%N' ``8.Eb~Qz?6# C+=}hw.ZVrH <#Q?T' lַ$lcOWP~>t}=mvccw|y}vۮz}`()S7佀 X wnj(!aZ8 OROW-t~m/*4 Fi"aWK W\\VqKdݚ eL:Upm2g`g߿}醓Xe~|컟V}z ؁Kuӄ"uPߠ"۟vb%.{ МVH=0C|C{QkṆ 7<V8+&(B;%^/Ywmf '!`ۂh^^Ct1z2NKHRUgih@z5nZ`·& EQ d?/o}̶(ZәNZGi`aUm!].e h}oyθџI < V"Lmj+690q x  L[i|a d7L8f>D:v?j:_Qܧt]AnnFܬe&fu,R5(!s:}sMmze/=R"ҭ_0w,!ᆟ077o7wQRԲrs* l8_#c[nc霰f]|8NS﬊5 I4/7v.Y5z]ޫ3U.UۼOR_F%:a{ܜl` * +6n*ITua(8/a8G ˑx_"G4/JiZi=LJՍnKi@ʏGUC؏?4Ԍ'y]kX|[tdgpX8?{0Ms7􊍨<c endstream endobj 225 0 obj 2339 endobj 31 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 226 0 obj <> stream xZnG}W /40X`/A}eV J$'=3iRc0VU{ՌT݇dzBV}/ƌ_>6'vbU}ٞXe{nq:_ Ǘ,>' %;d{/HӦvq xRmC6–iFԃOʣ̜bppǛpVggPl*b<:cY 6hk]Ȝ|Цe!)\wl„KHٝՑOV"+v4$Xit a4{X39DfMÙg-={m(׺0Mk[([j'칄1-K ثp> jUqJ.d 1%&e{et a4{f'1a/ް7Plj~Eٞi .ܓ0-k[([j&G20>*R**LXLKXwΚ Ӓ"iP 9vN^^h\8>k]/'o.([Z,',/lǽw(]^g{;_jǫ橺b5:d/5xbz͗뇛OO7w^}|aSK%Ĭz/9*;`]4&/o_֢`* $gjG^Sqebb*tХOm8^=j[BիCz9p V]N$D ,Y}^Pho XO  <2Ǫ;JŽ2,-7Q\ڊY{8#s>Ag3v1}ׇ _Ўa 't{w>=P>pr쓱1~KF%ohaMsF_ҽ̨9?4jHQĻzxW.Py-cym.ڈ*f~Rp^>v (9ƺ3w"?͚ZPœfTroc}v{U@Xc8IVDN8.;c]p8M!"%{,⓳ ɮTL4}*#_y2I`a蜔*ڬ81z= zloJh8OKDH"0 T? 杈}4Qm3t2H=M$\0)aUNs85R='1OGJJsZP;ˉm$sdXγS,࡝D#"^r뚰< \[\p W`Qcϊ%0.T"]ha@ʛ,P|7 Ⳛ(޹(M-5h;*0S;Hkϳ4mܬE4tf־ḓL)n6,M}`1^RZ9wq"Fq)et<ޟ'*; /Gk* s)BLkÊu+ԥ唝"%\kVv"hJ B;: MpnC09KM>z.%5dH22\q*`#&4Q``m\ȪH`2Jȶ~1^F8`/0@@8䋩cKC"o4G%01Q3+>uVZ\VbxL"h eHJcg}8/g*AF#,hփ(Q̑>#Rֻil~-vcvfsוލߍ+;ȩkQsrL+Xd{U)g%oeY'{sd3Ge JuF={ (MϺd歖Dq٣p:Ђ𼪈%Ċ @Ke\Qۋ%oXS@8F+l,xSpS.mn)ѭY̳izW!XNEǪ_LhRIF+/—FEԣ RL`s hTIdӐ3žRZyGsP)M=-IDS]$~VcH %*B1uEQ E5/cU']פxd0XNHݢ!`c+d0Gp[ZjZREBF"Qj v!g#A#3x=H)9H: i!˧Η9H J E(VsU&tHR鯽gѳ,q>+N͔ʗ{*N4 JCE'xA><"2\qd%ѤTJȈau S8-pe7_n7G똄bxȓPr{qqߝ~tQ2C>xKw{oIRcLY·vC__J'(^X6YWCw[i+YX/zz".^n-PlAҍxֵ8\p:E4-wU兯Hxx4,Z7V~JJC6Q7Zt.ֺt'C! endstream endobj 227 0 obj 3137 endobj 32 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Annots [228 0 R]>> endobj 228 0 obj <> endobj 229 0 obj <> stream x[KoGW {HQr,:JKDrUӤpdMUuG9}97J.b}qWs:Sff`x:}{,ߔ/trLŧTr|#N7j,6[a>LךKA3 fyLs!J[w|;ldi _TߚgҐ\ЫXLZfni2 (μ_6 US yKLt(]mGz&kԅ;3XRۉ ޿ )ڐ,Az^['w>%鬰 OX]!+'#B#'\C {敺7^R`z'K5JMƇ\R!L9mR@MJkeR\j^m6BQm:hPd=J rx:JBsXaps˶B2l~6#;b*c9rrWpc|zτTY&Q^<.%VȲ݇#h믟«N[SΗ󷯫 tB/_Vyȿ|Sp zEWp_"K,gAAˬnhSJ;+7V,ZȔ)[ R`oI?Hi7 1+DI"J}K0)Or2x`O1ҡBƸ4zAJ娤[8J!qhG8d[:6 0P aadH\@~nn?onLͪt8ODi. QV*3.jSYjC3(x"+dYc\th:Wc4hbF+axJA&hYhYXHM4{,iw]e8xom"-j8rr^*  0RuY8&BBIm toixUmrLf``!o;X#7S_#Qx.]zjVfk<ׂ=MЮj@RFHiMf?0 ZC- /pݘQ A`'2dPQ YT,¢+̼.L|tPd7-t #t4?VVk;T鲙 |rf3؄ܚ 3t T:tw? ,^8|BM jvg3/[k565kw5 l# fŠAG:Jq+RVAIEÚ8)(=Б$}Y%Y.TM 8gRF05:oV6 ԙD-SFA UT,5z'rႎV@uz[[gsth<ҕSO2y<JO6Z$༚Q+Mv=*?ڻSճI`"?`8@/>$\s`l2ggJ匨P6I )osݒb{tJtHN tc6$ѷ s[PAs+gbF(חTfejZ'=c$QaWFbi'іn < j,Fz9X鬽h/@I)Z!Q_wF'U]LF('{h\pkAFLc(ScCi-M/j\3iZΒ"sZZ H|=Hp޿Mjh]89'MF3ݢ1']i媟xBovnZqAM.PerR^Ee:6o;2T%tv7Ovi# VQ . J*G:IdpMNmvu؟Bx 0~zA#0zg( 04s3K:0{Q~TbJ5)N-_rʴV449ffL]}{ǹQ {  Кь.wV_R' v0E^nt}dd,1dMׂp'7^<[up+)מbR'Zx+'Xhz =F).=r(&l_\xyd8<:-$~ܣW²6}4ѕ{L="Waۇ1pttAF#_rPc24:t'(ZI j<}" 4/e WO5鹂:ܭ> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 231 0 obj <> stream xUMO1ﯰKcό"TJU94dEfE94Kyo޼{ X.HPJ (dPܕs֥$F0wb:L҄:A,tW,[Y IRȊ"4uyWWOum˛>YӐ;!QmHDK2CSmTk+u>a^mpћ2!upb2/$UOŀJqv.w#1/.'5qyiLCBW_ [=lH*}%Ӫ P: *ݍGڋI\QsgJ1|yi6 44OŨ,q=)429ghu"uqms/d 3Dv[4\)Y1a0*EYkt$@UC~pY+hP֣}9E#Iq0DFKgAN]q4kn˧gNjߎ~1|9XhבCěƇK ^r ^񴚇$$~܈yy\ 4{'&!*my7CFSWϲ|J{*O۬btA1 TȚXw:-O=E)/Q8 <Ɇ͗yEM{|ea8VZ6Eޖ~8z2[f|KcşH֥yN4%A:| 8 endstream endobj 232 0 obj 767 endobj 34 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>>>> endobj 148 0 obj <> endobj 233 0 obj <> endobj 234 0 obj <> stream x|y|Tf̚ef2I& &H$B(h `[dV,ZRZ-(EҸEyfB_觿w]޽sBZ1wiijY96p/O]b6k[;ef4[/^9o? dG2k4=[!B#߃fP)F斎\Z7CD[4PK̶4&>^/?rB"jk]ߌm큶N>(@tP"yHNXDZ FSmg w=(|gdfe#Fsw~CFVV8OA/Hc(h:sGE `>q8 d rM!Ws;BSnGB6T9! *AT,`3?Q\;N%!;V4ގ^G{Og?DqPG,`/N7vq&_ } xfp2N;GL_{`m6݆́hk6Y`JTm>8J&.7+v81kDb⹸ w41~]ME.z@]B!N# ' d "_2Gng8ǣ44UQV h+ڇ^lϠ3X 8j<߀>~gsL\KI'w;H^r1FYb>bc-l{3\&5/3w_p%TFb؂'7vGГ7_~tx}Dcpyp.b܂o=`<~'ed *In Md%\;6rB0)L&SLcaRv5ncbtnmpor.q| Ba ō3E6('Qx=pu: ۇ^Fz!L߅/27Rt9ͨp^E+5xIi)Do튏q:6%l2:FcQFwt'MI&hRㆪq7*){J=]J33U^wϱJ;g\_ݕzwO*f*{s7zFw6wW5Vp%P? t;Ё{Ш5vhTژ=x33z9=[y>熮`̌I;;wSPB)4i!tcz[c[jqkHcI 4&\lT3 Ò;za$ëxhMBw[m^4GzXY߃&:$R8her0<=[go(Itt&X@=M%(AsJcXgTQbzM=k'Ghj Wp54VCn0opkk"5|[DAAS! m묊!P J˨ "ĺ}SwQeA8`Y7Bs:022":M%;= "&)94볁`,hJG`,:]#,PAXUĺzVH@tCzW Y` 8e2CwwK^Oϡn F\!E*Hk'*MkЪ4 *.J"Pp%?Da?N0JG\CeC),e C)(\+)G(\} { J۱ kCS(\(<)<pO)(#!_M]0yG }wʏ/thB_EVKaQJGynE P_nm$.+yAӮ{cm&˕(6ϐBL(N T;X]Ϛt :F5{l22tNk`O J8Qs$nWRpCel-O\o! r_R ԉV=K^%'E4zb#0jY-ȃS}S9Ɵ5|gq,+Fߕrnnx}s_^:{4=4ȆK6NF1%bsFWUi`fy M;Q'ckQ(8"u:fqCtN4i^9_E юjxC; KAe@Ծ#S~АMx &3['LI3g3g/b%_"_"}*y;\7>;=vBɓS9?Gtj5ĭ6j{6ZQ@1@\XT\tU4(ɬO3ZW3_Ɯye=>A&!1Blaj|Vls>5ap8 cXK(dwy,[0ωNS=  /j(+ hDS)EDdlyIA~4q.HY ʲG(!eiv\x_J۾uGGvMDƎӍ˘'O7 XDnTMxZk͸kն1&V7 ǨE zuLŔ.)"ƂYoir%S}1Y wo/ncF~_Ei֮H7reKGߔd?ykxK&J,EA]:Vjm+eh 9ZCu^SYȯ<xb̦bÖHgkG̖ C,`S]5N(cP,%~ /F%k ;z19ٝ!Ei9msRxn]8'@ɪY񒇼=ޯ7:*n!{zP YGM<ܼ%8 )Z17ol=uicRE ʾx/,Z,\MӦϚ5}Zٹuٲ~WgWV=+c,ɟ;w´iT@( ͐J%.^o9^[u7Z݆؜X6vsC=cc3Ӈ*>*?1Q X*c9&6[Э{ 7!Thk;kVV|ŌcucD_{ $iܱ[G1kyJwN{4יFn_9U~ma{lM{ bdR Dn6D0|>:?X'yA [n745R%|j ߬I`=̣n>k,g;+.z 'q'qG0&,>3-4fbn6fʹё4* dqA4m|}7%{`!VTE*V{jZop%ɽ;j';k9>Ò~!:*Qv9(J p*ǀ5AGρ9联A,98~t9*`r.?W||N)=}!X i,bQ|'vj1IPk8P=K(*W5ѳHWhk9Rk%6x{eU*ڔKeb˽.$m*N@P7&(3I(q$&={WcyM66XE,F "\ @bOQ%N@0ڻa\C'WldQW}^_ze\x#tRypAz͛Gl<俾  *@]0 GF91Ip& 9CI+Yj*TοPK$'!t;ɻ4,D9du#YBeYWpDaU s(TP~J:~% g<`sEMq( *g"8IXS*#e0Q  T {&1)uKrj55nZe8"p ldKEj,m{Tg&~|OZ?= K~l{`J!8HµXa* wr|QVxRM萴YQTqFP"J4BTUbZƕhq#Ӹo܍3.߫b9Qv+Sm31fFe2*Aӫ&}&(Q%"N/ƤȈw2>b}Q3/8U)q OCq@2#Fh)8z ")(?G[-tms]Ω}rhk3P&[g7t9 |D>8.ť ,dySEmWkAl' ~:i7ߙ ,0}i[H$Ə,xwj)NrB1J#%t >ԤR-)d0K i?/YȌ#&JI z kz'Nlyv4ÖgmS"tTU3h] [WzI YiNPi 05b:bhԻQ!ƫ5Z*o;?ۂ9+,Zq̟ˏO]/)*Y>@ǯng+xi|NQ/!OyПo%T"i1&V ^}59YB5ƾ)WoUaQ vdER̗UVE]sIa_a2FBX]Gwj!މ%{$noo8\ҹm7t_<֝gx6VH@o6\I&>Q 62IC_^Mħ +5j\W7Cy!?<\ƒ?x,eK3`k`FQGh ߦDw ;5Kr#4ݚ܃G=s74'ONnhgg9V0'Q8|;ҨQ LcVapE^` pFP1{ءpIB~pDyA=E7oJ)VU Hx{iC*V)pG6,`= [>G$'d>8='Ė0t4a8),Z7bxO>uAٙM`hIf s ijMFff +L,ud᥿t?k䓈:6D}hJ~=|8aーcPYX1m@C/e&H3|wBˆxܧ^7m"LlN ?06b2ZTZ7il{TG9G%;ssu˲ຒ]gXYȵwewaBnT!%I&Av'rzLs]:I8>rT\89ŀ}eưCJ.|b U4pi  ?:5)/ckW$o`Xͷ37"čܡЅq)yW:zwVb q/[w[IW,k35nR4-_v³qoNWk j5(*9brwyƌv]Pڝ攧KA݊[S-E (;f ''066STثr 6c1妱Oy\x)%#@ nqNa8b`- D8.XYsĻyT Y[hզ؛(lQBV%|IkXΜ^KK֦:\ aJ36avivݒƎj*7pnaN|GTKXjY:gZgf8O>s_tã u)~U1|bG2b4V$0E ڵZu&~KÛm!* ϳ}ar ^k OV $2p6M'۰W3+I4q¥[ҴG*Rbr>` doB6t[y6w ΂ jlS Q4Ճ=Zr䂧t B>hs3@vz@#WU΅PFe} 4| } -̧'e$ۗ?|Gqo19)tK_r+fr{#\m!Ar9قO%qugأrJdyc2UEܼ!"{apߝ}:F_ʦKQaۀv# S~1y{ݒakF4KRJ~-{=.d(HH͞|t߶>Y2nݑ엗;(yVG{˱?p _O7r/'ʤ$HYFLHh Z,gt/z&V_FtP,g궅bS̨G 3}-Kgqȇg73⶟֒uE^]Uօ=ܛJy03L} M|8x@iHĹLyَ'RI{3t<?cFÃhRszMM"pO:[N 2d9FtG"o8y=ZLKqOs0aqkr48.ĿR_iP$ !JF%&b!Q]ix؎&yK-_q/\gWOPZmn%2$U@>`ޫ9 My;udgLt`GtAI(JWAnȷC' pK=(pq$˜vrQ@ۉ߲#GEH #EŃu:/tx MDU#kBWc%~F-Ld :ќ.AM:3mщ V`cX '_S;]2n1;drȔq ƆVM&dևXRqLX?M3)qYcW%!g6E#]I\ n#GcOʧmił.1u-`g;J [eMY]S*vN6|bGRvvQt h4z.")gwֈ=`'WK#Qqw ݂;\k ɒ.q4D:z##'ԯgȏH@5dvȦ:)fձN:ѬqE]Wdp&QU +iHj XDe:jtҊ5qX%>-;S f#^ n'~ҿ?ĪkܗS0r IjatV&9D" 5>;3qހvSt#2HPcI=5# ײ31O3l]"[bKʨ9R6t@n& |CǨXFSTǤdĸVZY3#$)(gM,Bm3Kj2Qm#3kuMߥ NJ$,$ccFF (i4> (wr!sTN"7Q_yG҆ ii{N-gsrYUkka|V[IVc`5>!#ʥ0>"ϔc/*Fʞw'ZǾ25EamF6ܷ/a.Nu9L˛8G>f(yA*ة;IYjӚf-NujNs5X\dw^Ut_wSϦL~ah̅eE- VKmf7SيPkCNi;čOц#5Z%RC&Tcxeh&u0B#G23I8O^!Wblي+az8<-QZ:X2X2"$%1o mN Cym&]*?xr}&1^~q^{(JÉĆYD6OS~u;V=WoabV?>+<>¾~@ {rv|&*ZQTkjHf5x!FJ[j5Kx @m@{",Dhqhi2دY7:(!CމH Gpi/tW'7 k4z_j󩧩穷QPцy>V02nzVt"]jf&ᣣZIQqϤRQPhNB.av+HhA>CrIkX4P{~C`hllYXnVq nZr~Dx)L#Vu/,e$lIKLtr8[^| YYQlLoQT׾4w닧4Fr|C[H|G^E;=Nȳ!_KeHtO$/h gXvA i'7 =hjd]ۃa|*y"fCán5ՐAMR o|H&mg94dС9{0~dE!]:jBj !M @AyQ7A:Ϡs@چ 5~gPo; i7B @ E(ގ sk Q#/ ]A(@ 3 K !S!z3BiP:̛E*$Th1+< $mb*eg"BR̠D7Hߊɶ#=y( (&7Qĕ"0FvI&'"˘A]E&62&Ρ8ϟ(}X@Lwf|9 (Q`.G` cV+0D`1U`$%q+@bE:-UJq LwiPpR*0)')pƍ 8^v)أ8AY} \J_*HV"iFZrXY>V+>s2rrmmQ-m;Kdi{I{܂%+jw{ ܺxyǂ%˔w:ih]<UVظsQ5jGMh @9sy&iJ@ewW9}4m5ݼu;㋮iiUFAkkzVl SO;y[sђt&P%0F͆By 30r$g60/0G>/[;0в}|cMQF@ `8~UFUy!~/j$Rw;7?+gnn w;/'83(3>WKMˮF::C2iZ5/hZ1=0i4-7 :<҉sZz'j,m2,Xnrô ;ڛZ[ ֫Ou/ {Zyǻ%4KӛKVi,G{a":Ϝ$ۛ:Zso~ 7hnnZ27xYKٴǟnw,з}yKw{ގ,d&æA6KZ,W' (Z^t,X?@,e۸:niiK/o OnkdNuIbwiYme ,Ԍous姟H  zdD9.H*bqn*%iuH5g]kκucRUCU(Q+{tD/d#- IDWxJqPRğ.B.mb-wu{]o do$Y,E^KT3]>u+\Wj~dxG!p=߿Ni~pֶ^u-$Op$&fÃXҸf&]Sʃ8US;)WFG/LT0 O+%q=LWߓGOn5V4x{6u6{v_'*ɍ4Ӽ)г9t4GI}hZՔ}Ӥ@e$i?"'V\S#Uй&y"k> endobj 236 0 obj <> endobj 237 0 obj <> stream x |E\Us_===sߓLIH. Bȡ( Q]E]P]ETXsQt]5|OLBw&LuU1\穧Bf 1[Z8k#uJ-κxIqrs0K ,8wet BlYg}muMkͅSJhvt%y ]ΚLWF]κt1{ Ag-#^Xڇ2._%8U/5+оo>;BX=a5Z`4-V萜.!w`G(D!F(A_p ^4(b)Eh821<<ɼG@מ.F+J Gч!F2LfDԌ@a6WØ֡~<+e/"38J}0kE2Nx: ߁'SK!1 s52e1o~yQ%2h _)NVW"il.W_).ی=ES`ԗk2zB?,1؈ 4|I  WOdb`Oe7or|wU:btJ-;/{ -XGpwcNzryff+wmgcA2`ɨ} q&w؅OSL</‹q_ o;;C5a8`R,r YM6; ӘLse>g96Vcٙeacc f+ ˝9;OH*a\oo@E<c}s`vÈ*`caSp>0z?w?nW`}95L&=K֓n>}Oę4S0-L̍p?c>b>e `إ+Fs.}5jriE1ia^'b[h j' +i¿!?Lj ~Ǵ34"w/D>mH""t35=3Z2=E?Qi3o5ds{;ۂEK7h[vo.P4&F,$r3 a z/ ܋ۉH~"p/lO |8-T!-@wdХ܎gU f'w0YLϓk$'MXBBHP}/H9 t!@iŻ6T0%Qh}}p?lVPC1$3ākꑆ;AA<_Iynx-ƣ9̅d+=;ڤM۠G&?C-"\C̑|G>>Bv3(x'|t<~wb3 a- GAܕ7 gjeaofg/b/y݋^kح{恍Dը t kG> Zt>zm 5L84/ u 9t]Qy<Ąȍ%r1>@00 >cobPMvA@wKm$π̿cv\QڡKm*AQ֍5ʐIJkKsSAʊt4YǢp(rJ.j1NaQzxd`w|f7UFۑY1k@ t8LG*p9'T\ 5#7E= S~HGWUԺ;,؍gwx36m9Ʋ4`4Angdlj8@vG #YgwO:|'(Kw㶳"Qdh-ԟֶuԟ ΣwnnHZqKfLώ=knfV >;yA&\\h|^bk^6WX^3a!Zvt5\1s[`G_#wLOл*ߜp3s~bL {E7xYhۭl@FBݭHǬa "Z1MOS`+fʜ}jM=FOYLG9;xVF25TO9hYp|:0}6Pd^m n0wkb\${ĞYm*~V}T h clQ۵e{ȼb.>s;cpL(D |sfC{لvlDJE̤{vqL{?}f8y+86N;K{Na"'158|܎tB_moxHF<rz1Ve{tzJGts3Gc(_ԓ?LR7O+{pv g^8=+'hŊ3W/ rW,>=7{G71n%hqxSq8iF6m3vt{Şth7 հ V Cۊ+5;464;46֦lVU!>CXuLѠP?|~|:6sFN^,}N_eꃡ08q]">~1O՝2X-Poz^Tq;*hϑ^^p6oUeeJId,6:PP1S<2 4'0 ?5>VȘJF((Y5E WݦFwǀ6?/ U~:PW'JL]MpHPp<!:%)- ;jk Q[S쮩ͨ$Kvs&.XmE]T,i,}[Ф1O݁@rw;xu7#NIz3vc1j8% r1@֮$RhVQZ f`_c"޿l |=αY[xӢw RgLԁ3# q$$N:O;3ɂ<1brF_r=f6)O!rhbpDvtA8Fk4 a6Q}lc{ X  ѩT j3D%% q^ ekx#kh]pn+}Bt?`e8\+zcT&//'eJ3-gF_wps8OTbz1$K6h,*b(Hv$^xQ A (|=4V} 2zFx0MGXOPxdڃUlz3VX_%f4dQ )_yՃEr6ez;{iI7[@x]^{qܕBԨ(>|AX:M%(5(/Ի v#ݹoq2/9֭s8_Z]6YT.rwhe&;>wZd Z[fv,04J 㦱m #4Mit:Gfl])T|i;8UXNzVCaFB}7Ro9Bnv: 䦫}PM@3iƎS}-\ Fqàͷɟ_mw##Z}*zUQS˳UGd# {DR{nŌvi̞!T1^e#K/Foy#ި7dm؏T{8dΊhQPG&G' ŷ_C)*  5FS .Ɨnd cX|php ԃ_˜Z4C̻|ޱY#YHyS0"s ;j$D+/kmfNl3s U'7 ٞ1#!䏠D$בajd{G賖3J)k XB+rXkYH7knF=Uf\M__^(p+55 f R]Sd,=MKxi՚F7-Qn1 B Pi(-RF8x]n OpP6(-d1~ZfB5(ERP=+JENW0jr1ct'$jkZ{6'F_SIJ咆iKJFݲ|7W6ֆno>½M/ص7rvQi;sGz6 zOOGkQZhrys"Zs})Sb_1&)/^BVbK}33ʼn<b5 ݃YA)o .CN&m}R=B00^\FTFNo *X0d vD Q(uՅ]A>j!?EY_ZzjX軮I8qYk0ss޶Y|vqBH]yEsǗ,xN*9g]$)9 US]]=5V. P'oowp~h+ E *I͔*  i"^$%  |xs [Hs8,x {pv \Inh-_m H؃q`R?QjdB\.U`4h.X&`Gm\"+(t>G]X|",EjjKRؗ\}ςmN{fmeyT{r{Mke>l>e>^ v3G:^1UMJ'n]`ޡՇB-/ ٠Or0=Zņ5s}1;9420:` klhgWSEGŝ*j)7h`i~_SVUمC}"fGPH8B-stn 1I{]>mgfـf /ove?">_ u.4UwYZX9=M6ln/'b1eIX@F(Q+sHB0<a;ɤXAPLOC}=WjhxG* Z7`DHvMZFPO'1w `q(~-, -j ;h9N:Zuަ0_z:7(ڷߙfs,OՙbJg8ôѶ -Ķ_8كȸ-Qg189:wgAdQU!> N'Jz$m/7ݗ^nn-jn!d2['L(!t5l3oMlNK˚hɻ'ĝص=]Ag, [{qRL= g"p}[c]]u3fG 0 WL36Ϧ hZ6jh+1BHƖںh(`8$IrDˤhY{şQ\p}/vfThD 3jU5NV[b4LxJȋj+5VÐI31YM%M};S $[g`sZj Յ CmzWgkڰF4XZ/ 5~/ݫH@aXA4T??~9#[Sk4񮦙__9o\Ebw ΅M,{+6:mpmn Fr..on#/Dt5)ǓHi]Zm j32ٮvI$,a/@eUfo@|ѰN=nq <'eBʢlrR^nq={; hEKfhEol)spLjyfzS9 P;i5zDPѩ_kT`T>{GvvU4US=[~ $h'`\}jeZ_{ݯPf灏}Ї^BY!/Jj|ӥS/_2kԬ,]z x_S1ѥ S4o'ssb~خ;586tJttk-mL 9 ybROEV_=}<%vq;k[k !D>}eDJ/q篪DGb6s\an570/2=Z%YC |Ưw{a^˻34 ~S/+]NH Ћj.`UOajDӂh4XXVcHN 250w񮦶>1>27 Hh{jzBF]j{ॵ^޾vVV +37&n¥-ޜ\~ϜtlJrR4cҨ ʥ-0 K1쓨W.-qjE9ҼbfqTԺiiskSa=aUrF6CSdsJ 2cA KRk\?3{ⶪ@UEUk[%7,@Mf;pW!\"PtS!oրH뒊t5 }PC:OS4Yfa+5I4/cJ|h‹ ַAJM|c޴3GyS-)IpOM2PI*S  ;R1Fn i9z6..A=I(?]h/z}wG}JxH>gf?C6bKm63bC0 'p, TNSuM]uum¤QVװ>Q \q%E!<%EI%TIWޓY0 z}>?&"!P"tSSLX<8S^O 8R^WTLf7zTO(h$f$%NLhJ"I(B-27q qzNJ30Y`1r"ك +=o]nxa(;PQMg].[^n*VʇjRs vZue4`S]':Ӏk/D]8Yo!ypf9>Bˑ|7*htϦ>Oj4^i%lZKīLfM V+/LTJpI2]RJbFV=DWt,3EL>wOP/|Q2SXFI|G{0FytA(jmEim]NࡇۅEvfvly6:4;f_P& RE./OU ֋%XPpVj;TH0eղ"3<;+Y [6#B:)XpgKasnmA2>_$t/_鈬}Ez{_xGzO͹$Wێڙ w!4 ^-Es~&M;} }<j.})I+*\Dm'Qhv'mOqk?v<"=z\OO:]qwWKåS]c3lgp}5Vghp &QzI[žpm1,,9ckB Dk]"t&wElg!HBu1KPEW;'HF/ Mz?*хi\E CO&Lw}A;m@/Эӭou #̵:?d[--[j.n]4n- 9Lky}1y`]E-gvܴ;&܆ns_}w`+kr{Ƚwp[@LMAebݬGGGlPltbXS0B]q/>V`bELd4O~8zts·G?~Mo@nɉMջN2-LC*5cB򈪅 :]LTBN,,?Q ܾ`[`{R](8n~|sq^Kggǃ>3bxoMlR?7U=&{}g}S%9EȨQ_/`ZT'>9"譗{PU;ӻڼޕާz?cQHqUeߓ@ N?BV}@r\NJ?*p+NS*xH) &k;^jwuXu|LNppt0ho;s;Id領IGuwC=N}UTa:9b_PNW'` SaA7T]Dp%k/u q .jwߠWqpVa[ a($拁m@e@6R)Hmb//R?'ہŎjq5]Bo"Sѝj ΢Tc2 5R~N[9YR.,[9E,m|GmHNٷ NSp@|x%lQKNM[nu6A @(v `g-8M,\հ} *'&Oꨃ>\Ľ? -oȭͭAm9OB:CϤC/HdsC u% (:Hs.~x4B&wU@ܨ79p+F( sT:'G6~p r3͹Ȇl1 P=A6Yk~uv,Ymf4\[崯lûXl"5/_-.a{l'l<*99Y0q )%wsѢO $QܪfX,<~|ԗIZwӚ!4 o\(tf*Aux2q#˙.hd/q_Y&^]ӽ^F|Tݳ f6n*˸3w++ܺU}Z/ w"Cgw&B.!]׃(gK&Ę ![fFD tt!ЌCC;CC޹2iײZyPL=4P:pJzi6JE'Za>75[.7w"]GFG6 r}_;P@~8ĞUǝھ-R%B`L\׷5{ol A4ZϺx)Ϝ; 8{YtVws.7ܥݧf7N3w YyQ n)L\qv1lJm+,9^`igm hRƋ3|!<ѺK#92M\$QNہD8<|烠{A,d.7Z2nsʤ\i,9ug6ӳ5؏5_y՚fSo::uh."W_ɿ=\xKL-px+r_*dusGNHp)p`m-~/<@gٷ_}‹/UZԤW/,EHzTICGB_ƾH袎4,866619;#16_I6Ky.vOw;'qԭѺeNrI!^ӽֱ&u@: ~ %uMg(b6; b(N&m@|U˩M]D{KǗ .IW':i@SHWɮ̀_ͼDVWO߱w{s~uw'l'R|\7]taLe* 0o=tn)SiBzvq rF)\b4l* |8!я&Q826Xh|˦T鲾Ϯd aVq¿#T~9UU9[* &^Ss\.Wb=mr7U3}l,)?.{Rۋ߻޻~ZHuc^vK_*k>h dV'(*=RM,2y#?\-Ydo7Cz{,,\s3Ev̋kZK; BNMI5/FOg8؈׈xSPXtlܫC-3d6JTfMTc t*زc>]wCVU~{8E_i[{vnjmlѽ{O߭symb@$t(:]a>Yt2}ohsjM/jڎVTVWq0 ɒ w=buQo]Êi0 vV$=M #ggP%JTQ嫡 .|ʿ M(hlp;TNhv~4( bqb/-;iYQk/>b_U4e?/3%ٯaPHs G إJiXy|DN-Tplф͒W8y;zxO &/bQMXz*ZrHgOg'r)>w֥:c~OW5&n,CULzg>#$c:Kl2,cYWүnjzvq/H[Y6l*ܰb5iݓ`J4:C al |Yx ~ |1 ?=z4ӈ>uyӘ|kj+Yb9ujλ}*g, -炔)%=PX&i>hVxzQ;y1KXy4SRm5'[39vIJ|?~Wb?ec3k׋#hm$ jԯýT7菚ր;0=#aoըڢrD&.&B j2y7T!iu5tL&ǒx,Ech6#f"]QDD(QQF5ee415 <7bb mX{cɵ̲ f*333Lj# ;~> 3 PvHkvвWT'A>RsSMˣ lkqeٰ-/D}Mtm&V.levXZX-5).-(®N 8xԏbr&؟Ds q OZ{ag8/9)UV,Tqf Շiocw܊q5\G8B Q"H u*َ :|R(q*Eq'χ]!As;9P}\헵/jNQ: P0V͡L6*MAzkmlSlm!n3olL \dllNWT50b1gdPn&S& }[6ŗ<8/.\^+}QOon3]e:rl>Z-" o&70?@f 0# ɘ`#Vi9b$`kQՍZ@A|bX`\Acн_25( oWUx+Sl{2m9GXW9]pj:VO^ 0G+`R1ƀX`.5 \]wE?Sci*?|]˻",|J㊶ߞ ogCLȉG)JSb^ïF>]7<[o }ϿI@͜hdԌRVLMio5PPhg}tIPH"liaXOEE`MO M/1Ӂi/>30Ք}Xxl5/~zW0w7Ӄ집UP.SZ|k&ɤr6hϳ,W^Pnv}W~jLBw s>YRJWO0ICEk- [j^P1lzwפ5 몬O|W]_轷I +QTO3)իߐ\8 :NDE:!>녹sRX[4 w߳o=̾g%{.ؒ?NW4hm{m= ij&`\DRxAQM,̟~E˞HXw!pLL n,S=@I-D1Ӷz%5ƓsՐ͟6\{ qqaO`,SO .k42F6(N+ViȎ EpHX#X94L  tH- R]Gz5-dv>#?SCiAg$yII)ryyeGs'G'_!rID#]Qeښ(8,Jh;}h4Q aXjXIH~ڰӰv`Մ6V竐}>ʮ; OU,5,t"`: (Lt98L!ى EJE0f&Dc7ZP0h\ge8Z-+RJ,gFef .فĉoVdT5d=҃S,LvYdWꪬM *4g-\A.F 93QTRCfhß9o{N7e;ݮ#N:1}Tjn.JMK)iSԯ;;~:U;qR,w B:I0'e5vI}̍s}*I3Zw禳{VΧC`$"?] pE{Fdٲ^9#!ǖƉɃ!VlXF󪃄\$v9rlR>n {Uwp\+lQu.\g(=w=kK'3(ۇpIφwvɾڶ&{,nk{⾁7ٛ_yv7,F*^v lE]-m+m)Ȃ JG`` XZm`C0J/.)o7̰ J+XTh{<\=9_}Ңkww.<',m}iQTl f}: }'WX/ l/ W+5ZL7H_޴emW>N?@;]|z_]ۄdV_ckl? ͖ϦAP=ʱ@PYlOfs[eoaZjka*j;/2eA*\.iʴWHo+qG?EUsbw|)MɏҒ/F뷝֛ FkI}wHc9G?T*6/q fئw5>\=3`ldy4v!tw{]Ȕo3cIz}+2/L#Z]Qkq83IvI1y\)9R.˳(TYkb;uA늜;|‰[t=z+k` uL )\?ňiW!-oRll K`42OE>kGb5׾R/![z#c_V҉W޷ djtzz\-|0>oYn-\Hb yH)jr0QޣbkT\z=P,7 bBRXENPm7l׮x0sG~ƱڢFA&q t~z7,鮀ud..Z\>؜/G/gb t U:ٙpʺUlG \Z5x2g>d!@ecQJSϵ+bcf&koI0P>w Zs#-~QeW~˖V/[7{/ @L W4,Ap t|$̢w8{H1;BBji UtdIR=(^AZK%66l3NLly7T[S}7+׈xEB4tކSEE m%% 6WFVwl^X>4B4#_4 4Þ-і-O Z[?|鿍F=Yv_ӟ _?G0{˅[H`Xg7_@ޑva+ xtOzw7ql5݀(9g<`p`"uMjBQ#KgtGr>yJȏ=dL 7xDj"ciQtvDGlб}Id.^|upD"Z 6whhSDˉ*_=QM6EcD!Z4KTGDԌ~=?'P{ ^-뉶g`?.`878Eoic^GJ||Ftck =~M;q^<:2=@Oi.CGO.Lh& 3F%φNZ,tQžȠh.CGO](Ox k5Dl[ʫ>TyՇ*Pu:U^ʫ>TyՇ*PUrޔQQFfD]:?gOv.g/v3C^$>&s\: L| ~/rޘQ~cF^t]~D :Z n jYSҸ!qШALFq( aOQRQh&0pLH_ C> []{TkrPˡP#rPVb48*;נnEͣ6JK O +jxrc¢n+B1'%tZc =pPxL+&kh=dE鸥nHS8FE>-BQȕEli%@EP&2bE !AaQ~ U\wq!?.zEߨy4 *Ԝk *Ay^vuC0d bj .zo\ uI}W:$y\TtFws^MAoB'j]5GgGJne$⩃Q-'"X|F *b#)&EjX4l$ifDM$aCiS*zbx2'Uy&p@K{dPbI%H;J|˩ƔⶎR!es*"Pm<Pc)N֬$h*5M'D2 rO|,Dx47v;FlBxHlp$#-hllptbISqe(E( RŠ0XFQҙF*J%w7OuXZECa%Mv h1䒊KĐP|h<) Q -:0>H)C}(T# qqBFDWǩjN 8u姏0| 0+/gڱ#GK?Fu.J]Sx Ɛ~RaeCE m4 he ZApct:%\+_q9>IdrQHˀp$sA2I x M&hHbB$!-8fĬ:$&_5r D X~F *-$*uKGq]i;Ζ.P/`08"]-|qZF.a9ZԘP"|SS@TTK8!WMt ȕ(r%N9] ^g`9җ ,wщaFHfX H*@ V@!0)x|/8+:(m-p,n;-;:Z«DJc1C$~"E88c+q@ .8x 1O8?v57oS}MJO0ڲ}-pJ'g+h_O}Jǎ#羖{mAxVt7o|o2ҾnxAzVZ->+o鈴c]#Yp"HzܤVqez.Aoj}I:nQgX k:1|D1|t[,N7>̼f}0v~{ L7R8ydR@2ݘF3_}׮Lu5~Oѡ-ۧ]_|g e:mE*WDѝ<<T'S9I 4+~|d/>NNEnYgɛx 0` 8$"ax!5+D :-[ endstream endobj 238 0 obj 23035 endobj 150 0 obj <> endobj 239 0 obj <> endobj 240 0 obj <> stream x{y|TE޷N/Hڐ ȢBhi!!( hPֈ JX 0 踢8#88?|S!M CgܪS:uT%]7cUbD7}D)=ovGsYfqrGųZ4+؃-ƦoQ݋}`<y[ںnzkj ~׵5!Sdd`7r}aWb}Gg`~"&# @P.!!4Z)KFSp{̇= 1Y~ᔘF~ΞM-_t 6>$*RV G{p=lW8Dfx8!u~h- a.x6^?m8XO|%! +@2*8z>ݏ׈OGOXVt\t a">`~x×Vr 펞(|fU?d"8jlG=E$sI@6R!V5GƧa 2p7>-7(g)$ g=0H6M&e^JQ7R7QbOBf)"FGOD38:脛qv/I8?)!z|z6y&$|F&)RRF*6P?ҭF>/(bfp>%ѿFʔq,g18Jg=H.rMZɃ9|^d…d2Svj 5jzw:N=BG3,gL531mV|v0;}̛l1;^ku,-=fn=':\WQg6`H2J a 3aäzQzfFmx~ںZz<C)WVF-?Ԕ`K&y.ÞhZ&AjTJ\&JoU55bۈ XTui>w}i/-CD.ҌtwFOO oo@%|U=|]iipwe_UwKoeCvw(t3Eqn\bDlQgVTYRll8iZeESeX4y* +M`fgL/mZ[g^rS"\7U5{kb1׸sS-nZYBqNELܰR,jy˽-s\$g|ߤB DCdVDOadۃe0JIY`6i5[\ڙEM6Z}!uLlúڕOF{%q9SxA[!\cS2)2,6I&T9^!@sJX9*˦@ %ȋ2)W{9sxHʹ5¬ldKs@lu Cx+ #'9'JdŔQS*19# UgBˍN;|FH#$Fx`O>ΧM+;T}?ӫ1r{ق-7MC4.knMKwҡ=oD"1-~p8V[㢊Uf=3RPxPE:^Np&[ɦzG=q?( ZZ2U6=ND² }1X9KsXWWdbUU OMrZm:[d*UE)YBQ"g EYy6Od8n<-RiwLʔa2M$rKqQAb4Aogvv;z4Lya|\0_נOƲcznk5ݵrʟ։TYq[=AcDl%|%'^Cz5c _֛/.sGT._wYR|cUEN}oVl[LX|a<^{#o"k?Aw=m~+rnGrC66S2tXĀU5ynZsP @A᳷xN nӣpJdK*JVk^jHi9)JP%-˱Z]=sfn<cļ`7~/ѯ0rAe6A1Kr2t 6.>F LR,M@L\jt]D4h㽌k_aW8_ݳ'~>s:Ȟ:~GH$'>mo'IɿIo %L%NQNLpR*)ZMM >D߳qmm+9wZcD JERc~6&:»/R.ȁHz-QZ̰ESNhO(:Ot_/ Z*/2q!?A0 =o`83GVWAji#2D;mP$*i;#GJ9#gT*DmyPU$/RUSSn5 PhN0Z2-h7$ԠʥÒg`5twH>7Jxz,EcZkFwxJOv%W GQjv|Afٱl,Ɇ~##t vQLdy؎0 ~ԏY'o<¼QIn|! !>%! jLɲEmQu$Z$e!++>@3#dٔ\-h\lg#\O;|Y֜9q ӦiJGͣE"2Hh|0SS ;i)%lFzW$-ij!L4SL| FN+MIMvWڐuѓ̜7Y/E(Y8EsAϟcnj}9Ҥu>sݩKNqu_mhj<9l=Qoe8r/v-w\wvVRIso+F!UWC69A4~p},s 뮏.;w{ 'EՈ-{dϏ߰=bl'T\M(!7ia05Ht4̀Oq,a)bAudfF;VٳUОQ3֓H.xqyä߷3>SZJ^wlG3Q?ZOKvA~-} '͐W^Y -ù;iᔾd?~t̼F^XxCG.ꤤiɂzXP_hQ<<5cy$f0>^QNskw\m_3y_XF\اd{ͤycyx}auݙZQխ{1mh!;Aђ_SxZ wyf]cdžlm^}ä=ž\o+PAG1 .5()E`y, @"I% D4)/Wec#nmO/n`<=&#+vrzbAG͡EL֖'?4Iԣ3KToDICL@͂"lg-Sءy/"ϜQaP8W:t +o@-Q0Zmx7tj웤R`f BK oFĪ J? FZɰ[' C708@ O}2{sݴB>\ s]$aǦーoiTȹ`iv au\pjHPf*(Z50 aW$Ŗ,dzR՞#CK[izķݔ!'ƚ0"Vh35 k&:y$(}Aj=fX^~WJƑ=~l`œK,=3nںtz18G6P3xFE-\hj]0jACeZ2 j 6=)Xu~Rw0Ce"\T=($8Te-Mf=C(9E:>,S E2Cwɶtrd_SN\<50;ٿXXXJuw8wi43l1l3 E(_JΤ-/zqdnMSd2!˓esYLyT+Lkvξ!8pnX\b "qY!,ZKp)9vQzxIK)/\BqO_Φ-W޹ʮ}3w4ovkep/~O 8={*TIJ|맷\[=!Tj;+۩Pѯ);gTjOB>Tl9\kCI.jc)j]4/<Ǥ&fHb^fdMŻ/7o系w9*5:pfG0XYWjLXL ݞgq?QC# (^0XVC~`rTrmX&IRaQط/!?B{~k/](AkGlٷ=_;7o83%COo9J}HklD'x2qBA3P-t3Y>;)jJf,Y˞`^a1A^LmO%vCto~x-6r M72rP$\ 駃zKߦk&ǒIC>*ErS;zC^ΩgyM߾@t2"'I;w4o[o!C#c賸^\F7MHȯ3lffNi@`_fAgw k1Mx3Sm6Z(4NeӖKS [5RVZZ*G3djәq,eǤD}q4Sƕr/1@&hs{8R5Yv::q&9rw˧#pc*cMf& ],foA+H)6+>|![_b̥DRw_Wꠜ*V ]p {p,`(PO`0Vj{? WZh`>X6CrV`* 8Z1͘A`Jyp;% bٯû/^,8,,N犇'hE#?`a&lczWr)pLwKIp29I 4g`bja.)|.ipQ8f@F1 5*9,crX2Hז08@ctLi ?Z.aQRO¢M})aH.aVk%̉mp%$%K?ƞd.a/Sn sb\¼JX@,{$,CHX)ϗJjUjiG$HX'/af һj $NI"yYVMmuI‰RvH$䬐K*'ai 'I|*T$"b}lĹg!ƭĕ q^& E$ ɣK;8;#7;}eGǼ{t{[Ǣp{Yn(=u~{⎰jwbɔyZ/^ wjn^4&CEwFC;N &`07/짳d}Ǯ2VDi>y.}up\gpK$8fx[DT:gG8/CMOgٷُz%=cOώƘ\fQ"Xɲd'PfwA s~"Vĝݔ)qf.X9T0ܭ ݍpsBԥp)9>{:Fxa{-Xv7h_cp|14B%Y-j߽Ǚsc_s86lr4o [9u7οpW18 \97잽gÉ,(I8$_SrGi4Hqy-CR~q͍]: q߷',jNh Olhy|vXA%}*])'C.[%PAurG?+Me2(mqUE i?Gߦ)v9rEu U‹O"lwǜ齕a }wXzf{ta1m ux}sݳ/S=[VٕWO;;'vhtV.v)52bLqzqzqX<+[/BtWֺSL>XWOv\  endstream endobj 241 0 obj 9401 endobj 151 0 obj <> endobj 242 0 obj <> endobj 243 0 obj <> stream x]j0ὯB΢9R0ȩ,rO_,^c)<)/qXMsSZM?ݒmiiy L7Sn/\qb7u]k75KQX > stream xԽy`ŵ/\ݳo=>3=3U=4ڬie[l˒lY۲2vo a1@ vnF @I^BHGA#}U5e MOuuuM9SjГ7-۰dtᙣ@òpՕ6/ }}Vg<WXo]MըBSoÒY[%VE_@0i5 vnY1zhL<sf$R\T5Z7Mffw8]n@0TDcDH+35u bSsKk[{]3g;?OGapzW MF ȵ>B #>sy< Fv[+,MPll#`&x[A/%-61^phx2tP `'xr=__mG}0Xn{@?Z ,h?gf 3/JvjT ϫTWUSI<E#P0}v9vb6 zVըUJ\&04AbN7(;>?C|gFOԹS3toio3t_Y 7-_˷9coY>2hYL_PHgUe2g*TTj;z7BRR@Ibg`=#A\0y馩X2K匌.挸 8̝_:t,˗,B[x0gd5wApmC<&Gt[][-}g >v>f[CsgzՇ64Cm<uֶ=MHT 7.l[:&2Ҵm5b̒С|%˛󽷜/0o< "]@]aȕ_]-x`VgB h+^:Qgeϣ5ZVC7]=W:# £_9G,'aǜhE8/Gїi)P} :@1Q`; ?1* ds&ߕ4ՙ 0&Δ4I$ mO C  IhUUYNY$O_TrښL]nO%7YUS[]'9ԗ_\ ȘA03^71QcF)IJQo[vE)[*vl2e.8\ۓ :vRq["2?iduj$ Fc cQg:LiR19i}ҥ.ܻ U4MRըV!ʤӗ!6O :kq+ zg/1|t gѼǟtW34HxY9PM~>3 ٴWjfo[熏okswu,sp{LtXAVɒ2Q6)ȒZQK a^>\+u53 `['@ZϯlWS N.#AdI=Rd1T~F|Jh,C5xE2gA,J}'nG0~쳹 ~x >g`.[ ؂q#{~Z %!(8hN#Na MdCi4)C`D܏r>/A=Prso;?7s"yыfBɊNI9llZj~lJ$jtOu@K*E,fHFaT+vx1$Ni ZBձayr9,B2_feK+Z+Ŋ6BTFHYNNv8=ISުdHq]mY+rJBcC46QRh &tuZd ը@7 ݅QbX#b_RۿY!rb}BbVMa+ju}u*tE_,wkUmNO,MdT=MJAVuj\ST舆4[L3OvȄϓdH -fg_~㏳M{>>yͧ;z~Y/l>_3fk8g\(}rЈhz6^T)UXzB P3J@vTxUB+aɡ=9GD~&AAG).%* 2AZ1lS)aڏ:GrUDBƤ3i-4MDБŞ1R۱AidD&3Ǔ6"mEϓ -R6.Sl|8pH0dI>#áPd=@{PpS!ŸP(%ʦSH % a6!l0^6;NLzc*C_*+\>Hsx{>ou}iM5n9ۘnɜX_cɪo_pgN1Pm շUo(O<}wtgS0b(C!g)hi6 !·YlMӻfϱs/6Zihhhus3_,VYKC=fBaW?O@W_vHsS̈́ے郵|-ul/ՋD7En'A/GJ"\881DC-1B~,_ l)PX,S!R b+013'\0[ {kj%f,ņMx]׻w뷯l19̔VUQW[{j '.ߺf,]՚iTtׇfG37,^[Vzcv/熢PY VĄY6V.ܸһHU 60]@CIVIM2PRL5H0| -ӈ4 dd0`Ąx*y *!|0+A,1a 1|误EnSM1)=4<&>t:OL>=d~rib7?m2#y#ռ ?<^!kvGWJRݷpe>Ӊ}_Tro>1=3F2JLܲņvғ~.(ɴqbR@N6j"-*Dm20Rj0A;ff3:C/LV2V){31:Neu +s&,Ųj![U""@J4 Q(D(bPM KԤ:]ПxZcCCp=FU&*5Ȋj&ݕ<;\Vl_} ;nl;>)koA=˗'O<[Ӭ^`+8jy p"HB*4vhG(¤H#RwTDj!%R"j-u=%(!GQ!s։R$ʂI2+<≔oEŘRELdvR]4LF壓^n.<'_c$gJANtv#NUDmê@]ƋG &ooLkU w{jݗZ1nrp#pdTvfT?jm|IN#) cv[ A %\xJ{#7}R a\V fF8yYJ2[9R9Z$H LtHc1|1_(+&.P4D3NXYp)ʡko6}}/~{m|멗'V ~C'G{غy:F^ knbuv,47Vણ7r73Ӌ0a@I TV[ni W)6X*X&_f LZqI#ny%(Lo%E%]>$衞Lw=eWO诚H8ѵℇhS2)#+T^*HUL~=uQMa RIFfݔC#*  &N񟸦 >jzewN:]V0N KiF"e)MS> ZBCȂn0 , CR0+SF^4ߟr)a4+ e}L`n4 94ű M1H&DP@`p((`r4r{{o=j<@ hVxUH4|Rl0$ī^;F8s[B/LkJiYyME*5{icI3G ƓP(+4 {DG w0\}S+8W`LCnP%G&^0s:(wuOm J[g';$¡j}8ttPFY_ U=,i!BF6iKȀVhPnK4D0&[[Zy`x^tnQhֲͭPQTe2}vN7UTD%vVpM18 VT1_8} iW$V2$@\(%䇢@mTfwُ+Kj 0Ewա(Eҟoc?˗'R4L$x$H}٩}ʕ*+Q=RB1oz{Z-2yVgelkۦTн7ֻG-+q?uGe J A%<O׵-2kpw܊]'hSglj=;B(_huf]&(R%# wOa_ \y=MyMdUlfa aS`jfcm;gOz ÅޝRe)_Ji!O!tZG3 A,Al j&mI=-%ȟJXzylVGˊ/9=MX?@*5՗[x1=4/_RhIg|uV߼9s}Ghs.,F,. gDG;;QI˅ߟS#' DZ+xڌy%|Pp@ƽs|"{QFL(pBvˎkK%-ʷ˷˷ȷ| ֗/cbG,#{KS؂}yYE-$glؘ{s!i{;?\l UǾ[XK}|udtjV:[r?.Y>3DmU %*kKL=^@;>ck\ˣ@0q4s nװq<ʞO *'"Fm4Nm,}eȊYJbT W(Q_A8X~Q76.&RXp g(=0K@ UM9 ڊl*p&pI QH (:GXŮHngh4R^3 {+BQLݮ1&]֎RLzamR Ý YR z[M-T|(w#QF܍Dn.*A<:P^cj6ㆈH+t~uiHk=vڗp'G-;w<يu4Nknjl;0oS3/t'YKb͂!e}2|9)-U~\$}ݾa-/[./,]&)C-':Bb!rM \6|TqY!._u!4&RS>&nt4?M˜D2XVI7ٍq}-d߿b 7iry/E!&oeU`_\#$l.pO|op9y&4xGwgk)mh]˶ǞyOraDbO`f,3]!3J4nmڇGXt7 z'w6<4aC뿘 y,3wbS?%^'(1z\.  tA?j[HiL~f] 3|87A)T!VL+L]dP1R-V$2-K= TT+t8.QLJ*\ݨQ45Fhd/+v%Vaa"‡d DLTxBN$|S,/kw^ʄCs6m6T%8|A (R32\)vҚyAʪU4€)EtW1Ф-ӔzAQŧL;qĿurT.Ay2'𸼃qx ZoXj"?`^ ]dbq]sz5cw:I__0)$lI qn7*&BީQlQ98Qv]D\ʾx {n3;BWvr|[1ؤS0BC HO*vN"ӧcB(">xXQ4 ?GްT\r[tfy67UnB&o_`RSֵ0EvHYb(3 8">i3'f"ȭ ;uA3mfW)†[#RFN;7Ē|B@ l B AغN~Y Clݔ ]TϟBo]?2/<8j8Q]M6yxݎGR5էǥ??h%#7-[-]'q޸=9ؿl9B_=.1,M|Wǿ7o2N6*e26qsKk'N;Ly=K{Ӕr.qkIZYZRVfS<"ͯq ?.eWR)_0kS+ Ck ԁ=[Y~?՚\/_LFQQ۔\*'וM { %^ʑ7ߐVZ،e U[ U-/F5GOX3@'f]Q`?o^0cT t-BgajĴW'䇹=c0 z')n_lH욹x{_C{r8Wk:# ߸wWy,k9 q]E:s@DX,C:؋N:3o݅ɯGQB" Z\!咠Kj5nt]h`4%3Z5ktywgay9Bۍ|cu}uc{}{c_bUR#?H'Ssyr>F_hJ9jQݣfIg? q'$Xc.Da>2N&hjZUy^?X -֣coT^Զ#ML۱yZ}K"Fzs,x _<ܰ:G;e>@!GUđ97e*­Ȝ/7Ե]߿2>vg3$8[,72].^ .LN442h6O͘H` pe.gD٭qnNIC<؝Sa>8I+w=vXpl,\q.?NCC'}%#q.׹xVnbk.: 6 V ")+ UP5F:B=g@MŅT zWІ DKI99.LAt;z]PvrOEc{:k-# zܟAE/K8{SD A 6* N>_+%~ciO=jTko˾mqT+"wmZh=CwIKL{{m}݅ ;1Y o&5^2Nhʱ\l6+γDHxóF6x C5Szn~T!oTJ]UЌҬ *i)^;  )c"KLA^=5ݼT!QZb Oh@vZ;eGH hȳA&4O XmJ3l%soͽT}fյJN{>Uk)ެ37'{ f=&:cq<ܪ -VJq vwdo#'͍V"j*UH,,i)p[M2E'J_/Wօf;;@g_  kc7(vm~ίVZTl܍jFQQMVt+Z5CA!AGV>_~b3"+ #0 KQ哽mov1_J@{-Ne:)eݶ.] WL_VS46r'֏ SM BPu~~q/ws4YBՕ^IkJx+絮HnO*n.*ѨTO5{Jέޚ*^S*q=*{k릷۸ Eqk۸ m֏GTL88 EC ]#ΕWzinUYnoM&+;!ԓ4fLrS !7\? ᦓRIOX.a+ 3t1*J&.|4U]~dMRb(N]Qo}wsYNᬺs+c|;u[Δk|k8+ӱ=9:(KNz5ngU4x?%wd+*  0W apPVmˬ:gK/&贲Hw$vsc=LΉg c-C}gϔ9w\,`'}E+$I=9ҩd»YϨP?^$݈''?ν!Nv蟂?hZB zp$%B7h]P{yD{}Tqi HeB=f !0m"fFbBc!*Wq92$ ىG(>&wіw*-7F0L?Hd-* d*ofegm6+m_j !t![Ɨ5ߚ K(1cqJ;NBٱVvX0 +oӃ0Р:4Ҧ;l콁4&USgKy7k֤ivUR$M3-}kA_X fzl_/sYCvoY9d?$Ν&u/?a*jբ@׍XAx+C@/(rUc8m| pP%p& V&K-{o!͙3#0($vB讠e+ClXT]uam{* /U.s"QXQ{4(:;X%Nf(kn| )$? '`ЪIE/Ƚyq}m3%fpµZYю9oվ&*=6{)ݪE[&S͹ߙqOm0}vo7М,@.7 x*JygR)D1tF3ml XVJL`dz2m'."DpDK1i,D]|VfMfpaMbEb|L⧦.*̖)-<;ZHX۞Jfl#\ ?%{k_:gt,8#5!x͑L퇐.>yٍ L Ĕd"g)T]f_Fqy4%oQy0pȖ/;e5g< ^aĽ8G#NtcR\(oflwv$KW%X-%]C* !qf=`lׂ2=5oni֍\DS@Z殇jv랸7j&zip9mڹB+DbqpX8Gms$ Xﮀ8ma mdR-V-=j>&}Їx_ԓC >Bd\85TP6ib|x!R"~6=bEh+kdt!GGzl]1]Jsd>I"щ^qlFt3n.@>ye%-D.o̶|G:#k~21P ^:k*qϊʇZ&Y}C*\o]?HGrrﮕ%Z`V pđ#Ԟsh X&3*!B|Cn:TCW TMiXp5Jr֝~6e1f}7END+n8,"N B,iERq_!&?Y_[Qn~O$#AV?(?Y^c!x_ m޲xhq~}'_bp| ci6x?[@V,]z%CsmeAyYG(.Bu)-㫎V_= ?^g?J% |ߪר]6}|LPPnŐ*A|"(C d+Üi*#R&NY]1XS!w2c_ɋY9LL!)[YN$ɂ{&bHW-F˘B%klU`<]+SPe9L7pD2鮮tmgQY.S,O~×c=*ΟSE5V]ۋ TH..ruQZM@Zm8&u0z~1a3 77rny "*=NyI /SG>C:yO~&oH5%:K =-<ߦ5xugz SwD=!V70,& O7kg›"6~/ё59̆*Popnhᗯ8Gį2~6 9lhY!G!92r #E#SDQ34Pb|oyʪi-#aT5GT#|=3TuRt&G%ے %j"c,sQsMy:<;<@]iimթoҕSK>I6<uB]ќ$܏k2+ ko)d.J-<0k@1$a =Y"b.`)HdJ9[`Y>R ^HmK͌| ax{fH]?뭀Ԯ6Y%VjF­p:$bc\{#[`PhZMXO$v5^yErP11^:Gwߕre!WPPolA%)ܣPmo=t:dl"[Cr6 <[(Kk7ܪu-1g:Yڄ|[BZeT/˿tz3jV X5j9R1J}6tl6mw@JV}JC|;Ԟzꡆ /Fh QtBZC1u׷waz5d.R {"O JPLwx9rS9DH@`7 xK$Ox՘0Ra٦e2Q/&X8B-:{P߂s DX?&GB" 37Qp)m0"X.tqgW458C+Ok2Ъѝ WjLqZp!ʗke:|V,CANR;!RA7dWe/XMXQsgm>-N) S{b 1]QTx6iC!b ;\ݮkڻGe }W7tɍqWbW"DWvQnL}5KQl1c$TxJ4 I7|}lԢ-mpO[g<6=Zy=3ݽ>"C;f5۾6#2T)ʔ)?c$MTCOxj 7%&.:vo=!aX&H=BB-=$a6KGi&ZSchln75\㽡I~fd-}8a1q@j~KA󄵅@;y&&na[[ڽ}> xaμ^D70wP\LaGD`X)2BuPiĭ=:c-5Q&ȇjUUsVmc1ըn{d4:Zc?᧽ػ1:FBXѓ2 ,iLRh4p,%bĉ KF,qwD7і1v*V4 P&d^0kʇFs>,sj6d){;S #O5u) #}o^לu|xyb׳yc`qMpAha45hVm=1WY.`6s -3Dp:C5ݥ9;h$$AǍ\XvR>*-dZd (<0eE{/>dOR43c-S\ AqOJh5ɧܟzV/1Ŝ[{G`:įz`N~O .qF%b~יJTyq;|:R56daSxya9BS0~8ѩq-w8ٰ'q,[-߬VR@Lrrw+'+B%ԡKFԶtJЌiai0z\)!Ք|"_oLo^Ǒͩa#/)W^ }EeC'5%{0T{`n%vFT.#WwchwkNWO_*Vi'[﷚% u՟ԫ-g,A(+nYp fD]G>s):%̲O3Kr R.c߯Q"?RhDi GÞF]舆('ޙy"-x].37% (p4m(9#<) g֫Kb~W)a=|4? *%;ZZx}K/Ug'iYs;h;2wh;ީD*^H%IhiׯM$әt8P؉|ҕ,D;nLj(~s}?2Sr֫T UשDMybBVVWBEfsjjVTkwxv=J\'CUTTJM-s>~Y3~urW#D5qjTOAi' M)*,p"ͺR,$6|aSp8t_%n|sxoL)!*T]bI d A]_ﹿvݒaoL?06i8IPk{ƣܑ^ϟ%HLVơ[xD>舙 .\.b=F(d..pU&&ku4+#JJRuN'Y )y2;xϳ^}ܑj]̈cj@ݜ S=:JԪkq8R8qkk8YcXظqC> ZXWZ;ȊbzGGX'6lȭ!Pdqڂٔ#N) W#!ԤϾ)RF%J:kHdMJleRm{7&-׹F2T16/\?[ػpKY4+BlޅM7)= ["6jvtZE㿹;NfVz&ٱ~4C3Hfj`I_99 $Ǻ)[t{F:Njgt13^M"LO]>iv|ůQz>FH x6akQԞd{DҔH$=NܯSt:.N$jsY$tIu=B4M~ IJnz=Z4Rm!Wٵ@Eu>vمey({D*' E@^ ٽ+!mX Q|ļ汞DScҴIZM4&&yhis@{Piw|?sg{L1UE?}ݲ0N keW3x84lg>nAՀC.?>;9cT۷}? :%O;zI% 5 S ךdJ+ip:22t2$G$K _[Ȥ8qw͍k,5}P5q^PQŕI)fs[71-FVtrQu/Yw/[.a~U» feG'|n 낺՚%y3K n[Sl =4HeYvw͜֌q;G>96s/%k6"%m6bF<@~3$d u'<fHjBBgBQoz8'y 1%Lk˞=--{vV5;ʜhɒP,[ܼ̩(>2b(-QY/] l n߁2+a1UkA e; en,Ra6{A#lUjU{8b݋Np;ß0Ǟm 4CP7uEj 3b1XP2" | 0iXO:dTQތu澈'Q2`!ֿyŨoZJz`I 2 wS<*Poε(W#zs=ހnF}&@۟q꒬dL:jkaBN<s)Vb${I{|Rˮ:#!c}BPU<*ր ZUE*&ޥbÈ`dTT0q*6B&+x5QL,`S_PB'(Qc}3`U"^b:HXHUgT>PwUD}Pšo(#v F$ GPMyc:S8*{ g IG@T$#XGmֽF,gxZ͵k\viť.;G,mkk\/H~ɷYr䬔<>V#9m6+%eĂ۳޼*5*UMD_\rmOr9vU 橍]nՈunke,EaFZp>Yja5b*pKkl2w mxPZqˢ/z%_K&:iM*JG3^Ċe,.- ۆi(B;rIn9Gn]DUǘ;\n'zҏ-LHUL Hwa-NsaOcX)lS,E]u' {6iڼ4EEfsGGGNX=fqlޖN3oJm  n7|al-Șq!qGSi IxDskA\`G>14K6/mHq!rC6Lk,Ӝܛ1v JLl $M.+Fz*W5nlO9yƐq>'~y'DI+$Lel#RMJeJ%m80Nӊ4UK/OTF:̹ ~esQijgB `)Es>br1T;(}ji:1 VS|L?}"MEu*v7Qٱ6-VUxRd}JGN5*u1^%Ox8`^:;zM˥j$~mIyE(AL;kr_ѸvTǤ_S3uGd'xDiLDVsm[6ɧ:&ī2$v3mtUlC9/7C=:8ˡ#cH ^ЉԱVa,;I5e'ж/o y:'d>/W1.T9Boʹgȯ@)}qo1=r~˲"k}f"![Pl}Cp|y^8g>WrܦssZa٣ ?> DBDoo/8 ݇8b>9rMM3ޏ^*ʩx41x*I8Օ n~a{Y֣)?~3K{k/Z]g$w0=]̏Soww7{WjaK,ήt͚m.56ef3LisMRLS`LHL >#<2*:Y7m )ˎ~t(eY宠uG[ LG/19˟%67b.02ϯI^&qEm .Lt endstream endobj 246 0 obj 22103 endobj 152 0 obj <> endobj 247 0 obj <> endobj 248 0 obj <> stream x: T\g03 ` sgpa0£$!B J6jhmS]k֮u/{#UnC][jn]=vS㞅!:ĕ'w,̜ANKEVs&w9S0Bc7xK;2?BS30O~H8{`|tlbeiR4~NKLJn:pDžɉ#HT1F'&GDFBj+M B܏@>ҭ. %FRjEfw8]]"_yO;}JJmB hchRxsB amBSY & g m'Z3 c6S(WTmŊv%ol(I +Kz2՗:2YUfGC^ af] Ƚq]+_@m}`Y00Da:PITꀳ:ȽҜ498'uH# \o\G;zFṳ'0up   p2l2Eqe[5=<^O ϟ3% B˨lSv XǷѥrCgomviLSg}-bOaObyٕY˽,a9"N-(ׁsӠtΪQH]$`bc5q xOHC@2E% -'-{s"ZFċgg{rZQHC8?p Nxٮ.%Fbp9PEEd97!Tu.RXYJPfKl,ZDa7Mz7 ðAX"R"YkөZK&k)ݦ֐S"Vbk0R\~Kme?]GS}G1[󞲚{wO .?+wSC~ =$MʀX)T 2k`"P S6``zPe%8)5F,D"h1V|k۾g0%Mv$}gMvñIۊO[AQ(Fq&+-L9#a 2^!F\bVv`(t4b{slûUZUʖ-A[P%Ϊ(k~ߵzXIׁ\~"kK~΂lZ\E@v=M:e֗WwC4=pw9f"4#H׸:7-06X"R]6a#X%W z#ւ$0\圌-4pOoc.SH/?#JS‡7+J./a#A³»`'.(!X; 5#S Rf@%ɲDSJm$f7g_xtSw?;?*_~tpA h1ę\gsPTbfE^c+w *Gt9NS_@< M[ebv;QalNukk%:ڗQ G[wgzaw};Ӝl5z^%P%eRۯng[̿nvYp, W:)=F9po3ڕxW0qweE =y8_dG #%9#āF:Rp ^D.⺈N[NۡR_%|h8یA6D߃&lY123Jk%K8T;klX8SӽRo[Co_qzJ^߫ )/ݞͯhegboJ]5`l54+^FiP":\r$>,6Zq`@; lhE+Kx!KE*"ďXJ55;#քA ,%qQZ1}މm2M mX˺u9]owvxfbzZ_xpejww9$.FQ 8β ⊉s]Ad>sO8(.YmT&2}A(98>cXL=7:$ erG@$|=oJREh_ .BS,0Y~xvL@ggu^7|bЉ^U薏u(xL=xn::-1('/-[F{;;NES IMs}ǎ?v_Jknݟ8tݟ1T}}yO0,#<ޢ?J4g`mٹ-J>NjẖL~~ jO傋H/צ9wffjst;fl{EfƲBp4E1|'b`b5+6n%y/㷠^oAõCiΒ v@+qb,`f$ ĺ+N"Qd3 3i(3[ 6]hBi-[x6["i9ҋH͸F{4)̌1*r+%*.^Cc;M3t&wZZnɦb_mj@MMut>oٺmnmk< :we2 =vgG0nr|q}[[sC{)Z]ɄFL+ $s,[b,+<"6.ĉeuB$ \Iٸ42D@Rnϐ4;T.곉6f}}JQ~ӺXf0*Ěx<.=x LL4cgV#(Ib(]ʰ}'z%\C"弢kֶ9|߄}wB6l8Ȧ"6|ʪW?ӶF8ds5,W*ea}X@@Z5y`/hMvR*UՌY U36&`\"cY)uȶh;ڽ fO ^1 ֓T b 6!6ũ#|2ziUeo?}n9} Z'+thCCf<.N}ih'zpDyA[ET%`qU#s$ԛ9mԸIӾV6,ꑠO*\RyRN2D"NPf\Vəu DE W6tmƯhW;x{?l*`ЬzP!EX'Ҭ]*ٗr_JAH CbP"r̈́aIkazUXmʿK6CoWyC~\uPI]ɱvv 4k॥ҁl\kU<ˌ0ie04W.`HfWk8aLfN9W km\z}mɆ=!`ߴ.=jp_h,ڢM{`SH)ٲr\Džπ`r,i*$"x1Ί--ETnuiQJ3Y :5ֆ!?V5g:*=WL'jjeuy q)h/_0u]?^"9>Zf'ߚVuqSM\D|⠎.&8HiO&p [y|mݢ.Tg{"޶EQܷYp&Xn"uCI7\-;DQL*Z<گ3i~Oos&{Wѿ>^kXy<z{^ױSH"ϼwzvW!jl¯c!&]9rM߃JWQC^Lx*?Af(%ӱ`rQJAحI$3Wڹo%FHTx!iQjb^:ɉɑcz( _%_zxJt?+vy雿K_~'%v}ϿD0zhV'0EhMCY P5oՠJoZ`$70PΏ#t4 fa<XM}.}4ӓVGI:x&?>QJ{?i8NܞB`n8f`?Z^%cxOpI<ě?̓k}w *W%U]Tٰve_gw\eHO# endstream endobj 249 0 obj 5568 endobj 153 0 obj <> endobj 250 0 obj <> endobj 251 0 obj <> stream xX{XU_ ܸ9 *7=ci8jh(G8 4$GL(/TVZN1BSb4qԲB+9t=zyC{yyZ{Z{j(cPsWTr5tp Eot E%Յp O(PV, >=G>&,Emve+#Vg9ßB%|N1(7>MeRGںPƦt*ݯ#N;fG@=HVLn8QT5z_/TT"a5BGk*V8- uڰ-NB`̆kp ra#ٰ/Dx[˄(],2Fp;7 B8-厼q323f` WccMj&\]oPGF}=^AOL\D89,J‡Wpkv⡦NEouo`%w|g,OZN<b)F0QWs>kJר*MQ^d4J4Fi::uϿxד ˁ)/’ƏWSXI AcO\h]@GM7^#ĥB|"M[DEe4z;cÌZ7öPO'_ KiZ~[¸Ξ))R0*Oe̜0!97'MeyYL7^z}5(3;lS8_?P~UwYָ?v5z@Wg#Ky1QZԣB4Ţ~&fˣ9(xuDhHTD!FM1]Xr)KwvhSru)\Bp%vK,Ò5Pf偽nlp\2zlO |/y;S]6iu_L56~(@üG"+WgԨ-&7mWפ=U[4K%G"td.s,8yfv+׬wȲsxo@(dYDza l zYǼj^ Ây' PSy*8ܞNm[^i@Y)R72`F»ep6}͖Qֽ׽>-ۤIhqɬ)QuoTk>v̗0&0!8l2x>5u 0hõXZ1?߫Nr-7~o i/u=ke+-_\C\ܵΣn73[޾Qj͏Z3'rqg[Cc`1ƻZ/My4XDĉ\1 a05]3&/6co{\I#!H#(C5.5Dt&!gm `~@uk,&& lsJtr&eI_qHθɹKֻ=tGiqUʩu?-.ya}o}')_{yV-yj_ݻ ?}mS{_wawC彏Sgauo5>p,Tg,rtSoq`Het+ׂaȚ0_S7x׻ܿzvMXpcobdnˤ_ۻ sDmTzbIg:?:V;|(*?*?q|TNjp 9J vb,Dl1cKmvǿxEf>g#4zpV(o $``C 2wr$sexX,sT`J=!\2g(s#.s/\W*ǏW#HQ<1s70!!KKPcKej"Qjq|ȎW^>ĦB} 뗹 \q'%sIɭ'7G'W@e'ZUmqNh?\ j5 \;0Rނ,3d~,*}q jJ'Y&YR<GVRb_tU؜KMv[eU%̲b[iY\i+!P>˱cns.+wM| q2eC*4V+JE2[bn!dMU7Hdq.g f(rۗM+"ۊUa!pI}leC`w3o/5߲ ۇLpnr(kjtڝSQ(p7[kyqIetp:TY v,ˑ:Q]u&ݴ1iæWZm=go=|eMlpVW-u'{ x/c._\.PP_! RA dSnH{-==˖?tzOneBx!SC2Բhb}y7_s"maxu ;t0fB ~/0³e]Lj˱0CΣ8̼qh# >b Zf2?ܢgk1wC5Ƽ<0Ǯ!a#AB't N_"¿~O~KK?=PJ*|Lī$I+Ŀ"LMxK/?#"DŽ7ᇄ G.{(i%iSpm' O'|b?F(Äo"!n?G?K]]0$ɟ4LC| k$ }/1GVn!Lsn"# JbE  gl{ !p>> endobj 253 0 obj <> endobj 254 0 obj <> stream x| \\W{ـa%s@&,IfQըoՉ+Zvk}ڪUJVk*=ΰh~p}sι3 !$GG5{Ucy!BӵgU~ lml]Bԯe[c~ޞo~Pq xBzޝ×)?D_tC杝ĨIN TI#S2Hѭ@\=0Rt0 @x>xFH|"#Db$" JY(+Jl֞py_~Dr|@ ع|T-L5@M@[7ΡNoGUDoQFroAh@P-zCChG?D?G (nFףJh%7sy!! 4^"X੅kP"cd$AATJ!:4o" 3Zԅt(FEf$HB5z6Ga DKu!%t>zfWR, |9ެ tYƖjMF^ըUR!OI%bP@&⦪3fjritrb#͒J ^N mO#]QUA5Ǒ6NBhdHvG/nؗ LQ#Fgd)@ucgeO53$(rotE=ΝQ DP29{EQEEUq1/:{&U*+vtwn:ag`#e`߬Fz1#wG5h>dKZYxFjojJEL},Ng㷯l]\j6 x,,= S1rsJݱ3;Ï*~ |H/,L?56vD; UqdV6{UUx`jkbs:9+dAbhU[O *F@VqK`>Cq1Ҝdȥ aQ16V`k::'glq*ؙXzmnVOkj:zRK@ͪ֐ծnK6%V ?@@YjMkpjt Љ'$X$lyxݎ$@"~dek"͢-ևztss%5\|(Yq{V8aDy\[JYɶEZ)Lɼq ,ˎ*5Xz +׷y)H$gD;T%, ,WUr`⌚8Pz h8+V+Vo=H䊖ևIL5 Hz i$fG'QuY$EMPG/$eCFl&!6vcknXj =cm>Xխ}smya>Xp؞䰝 @  ;2z'a~NIA>>% v_=@9'?1(]3Iqʨ"iHv]#.֐ nIųzL فTyXFugPY"=(z"KT*7_w *0ޚ?]E@P0 (GQ!s"R"wկ>'|w|q,]OA4<TmTT9VLbN _j}b>% g.m#YU[W73{_Mi߁kf^K牓Gg~~?}뭐@krb; , E~(X-%Rc%'ĔX-yR"t~hj Լ&  ιf9> vGK}`+IL'=}[R?")}\ffT{PjfT'6r, I 2}T.'ߝ/-]eg]ӗ7XX}LmSl(<\~R9MH*Bfl8΢pQ]?\$-=f/PuU6WUW;C'Y'jQ"fٍD.MRik!E8bݤ\>.'+Bw﮹X*7TuNwx}&&_ԷGER֦lMٓ"H @ՔUF!iSO1f]z Iy A1 #lQ1F zF[ VЖiޢޙ5P R'HWvsVwZZFM2qٷM9I9zdFᖙmoWtR cU3P:Jr,Q)ʬ2W}i[҃=`.uQ)S4zVdK}zCW^_᫈VtTPdO#C˞P㎷Kl `rDhSa%r1d[ȳrֱ; 0%@n} uX$*q/IL~ѕ/=[f&HdCaV䬜˥TdS"uf}yE`&\cڧM'k LJS&UGR̦vp;˺\̕!> ~$[@?},eu!VA*g}=\S54Fl11J $/ FGBLFg ~%Ac؀w?SnÈ;S{ jӑiPgq[bv}9{{P|7iwU@/Mb)|;"A Y"ݒBx}Oحkü[]m)&?"'1WX|:](6޸zzƜg` *@9>* RYYaQai^Q̽`2:2b e%FY bB[^zA1f^>@6ƹv8@uQ_E;i޸˃1.]AC^qsrd.L/,_^ɹVW}R9W5˘uS0K&׬, M"9sz db F)2}IJ[N h>k,|@~`+577yC'iM҄z{H6o h?{)-.g1$'R#]4h̊tD5cU/Cqg~r!ĥ\+ÓSi1~!K͔,ST Ȣ6SKހ)&ݓJkNMK5* TfK].!$W9iQa%uŌfJ4Vz F$*4Bpx]r @0d8&fF0{Ic9P,y:| )hPE PҜOf Alj5P`b5gP>_Z;'_|7 s/DUX/u"vu#ݾې1#kAS=u-y˨  ƧB$Զ==sH(fL Gi}w'}+y53Cİ 0u't=^K'h!Òl/(t2UI4sEqeB?㥚v^*.0\Pd.wV4J0eF,H[4?`#K_9HVn* J<"UBؙ,u#׫PMVtQv8:"Hz77 BJ~TW>h4:d:++JҹtǏ@0}F&:!}>sF-_j.N'ŏ%VҜqT:'oJ+C =9.C %*Rgm@,qzc$ uyBkryk:lqKmm+6.O{5aMKGR2l鉈uߓcŸ8dKK}.lveel3p]3,A18iW^XE>_EWer|zK~xq4TPGIѮ۷n_on6i > {wRy8T,R0HO Ze4].NXIGܰJqg"W6<1ePBƵԺͣŞͫOeƼ\wχxck{m'ck[g[!f_,IG+`KGj1UJeiiM6:]L ];=5?u_곩Tyx֫Q)f5փ|Knx/>sد祂VŎ"l^fVNdǨKD(ū߸[S'Ti⾙zC܁#M1r[;7e130g+X"!C!R$Ԅ y6Z^)xKȟs:-Cq+#z+/H!^Wh3 1 f*@*җYn(CGs>.]&(o| *;%60+\M3A6.~H\d5.9'6et_OjG]g>]&c_0^)A_[T"PuHսulRr?hl~5VryWG6 !I:rS܄K}Zߢߪҋ!G\k#l>Jm͝ƥK8%Td,~`0I!^|ވK*~PNFPOh7ئ<;auj=PŖ zjEjVlg 14]VØJm[zT=`Q Q0Rca V".^*Y,ܤs)MvQ+zbɛhdSa\D2d`1:,R3I:8|䙿ojO '6wc2E(,d/j6$BiV_I%tQ~@6W͙ib_8StrͼgCַ&{f:ct?m-?D gVV2DWWSjx(o( pOPGebQLKiKK@v(;,E)(-D(ʣTJJ!IF[,q|M |s-q܃^4h (ؾ䄟mn G ~#|eE]sΘi!o@f׆7ܵ@BVos*z,\ eEV{$<٣ܒ\*a崛.k- \ͩr}upD#xO`4!oyNx^7nU팅sW~  n,=^2`⣁D8D}6k9QnKfފPlrWu67H$m2͸=(Uez~`)\ITdW3%|l-5YڪU'rzj5=}ƺ bǣg}ϜtF-09N \+~-/ &gPP]A:)56(RA%MRyՠ*k<&$^1X  |s/9 ͿI(cBo]~rulnK;d2U__\VgYeUTOFt~c< 25{y.>s]#+Ԩk# gc&s ?X%̥KDP9I5f `掚Lhqxs u@o`@ }}z\7ZK=ZNMT޹z_1Q,+3WK^] {w} oS݃璟i_U/65WMY~Pc-$,v64XY*SM V&EW^Ϯ⌛7m>^]Q3L\w}?ҹfWe9':kV$a6c_|kK,e jJy==}qmO$Q?(DFhNv를lڨ\*wˋ5.(K)W+"[h=8谻ЕHu%±'de%=]q,}C2,<<>d$NJvI;ڣ򗢍l+I/([DA ՟{Xӝ+ U<\p}Sk§T:b'yR"?_~O5&. gպ2缭}b{WQ*ǭ$y\i4ZN *'hrXSY٣\o)=5A$Djl6IԋC9Іv妐`U0{cĜYީ;=bgKgm8@MhʫXE>sl]w(^- ( d|Z&Ro!B]f3dM|7A)?AO^칤p%wڙBʇƒ%_g 3 [?w>*5oAx5&8BJo1w ;Q=2sZu(*>UڜAQjɟ~Q.XD7“}]igKK^YZaS k} (fXL@:PNH*Bjhy!#d !S3Bf'B#ק1/" _oF|3_=]75.$V"0GDuֹ/ʡ|C M" &i yQ(I mOBK'ix IR$$ $DY><2*ɻ4h3<-_J8MA"I P*%i1ΧIxZ7$i0nXM %zKZ N$-D6AWA$-Fܒ%")IKQLV_&i%j Wr6I|%?IKO!_%MKJsxZ iS t OW7J$ xZ7I<8H_H0w+IC;%<)I!ǟҗq^LǓ4eUlS^+fUᾁ]le?o[ggpOOwnm඾dMص=CВ-˻$ 9¥U/,Yʵod;m}C==`gw.Yz}X`î7 Ww }`k`d`_PnU túa(&2F؝ؑ:kbc=;1-"k+tOG(u.j Ͼ]]#xZlwP:A>zv s}fe=;F vU}C0. ̢ydA/=;1}k];1w&F ̓902f{u:= &;<+ݛsnrv vzpC>TF B}h @z;{A>M]Z^f-*n~@=B|A%eA|@5A.9\V4 NjʅJ,ZyP/ x@=pKzt Az-g('%(5W!~3ǥ-sq}l{9 s\Y>m|01`uCj'<aMY[K~#£aHcg2̯ s#X4.H@)Q_;cNp'G M#]g|˝Pgfgc 8ܹY o[~GɒYE! V.Q^MW'\_҅~~_P>--s{;i:%J *% k.)kFT_7;. |F~^:eFߚ﷑QݲٿUW&/ǴHωA Y9܇ !A*\LM7P~Eo.%Lw-nfn>\]Bu+{uR쭷3I>%an08\nbTgFߕ[|I sL໾q_{m7ן0.w1C)]}jSOQD#g?:Y!7TsR9RD~yh{cPփ?H>x7n3u]Gq9r;?p?4oBD!o{x= #~=z>iogXӇ_?q3$pXR?ONOX?ŝ#GGɇIóy!3 U#L{,̉1s%\c|h--t;ǂ4t,z,?6Z٣ˎ8ؑ#Gȣ33eU,СbHy;;ܽ{O$;*32iGt%kmҚ0- hu (1>jɨ,VrR.Eb g# Q4Ctr2J>BQgLХ JT"a 5Zoä{ qIWLT:Iq(K$^} Iy [㱴x>&KkO|?ޯ9C3}&:G܉8ER> endobj 256 0 obj <> endobj 257 0 obj <> stream x |Sו0~{Od=If-IO%ٖ-`7Wvcbc`-! 1!!i2$i5)d3~36$tMtJڦ;~] >I@N;lsd#R{G04`w6m};_ 6@Hy ޮA{TAMB({wO.r928݅{fK(;LG*2kG(_FH+oFBGzmɷ уÈC8BX ߌhH,+*Lp!!7!Śa;]ny>&B_TM#ȏ SxAJ?*']KGpx2ɘnXmFR*2)𬥲U\d9,eEnd츩\(7͢ ||fq,"`C#̔Tݳ]VtvB*gk>'IǾRV ,tAPkaj.PHΚՇf)o5Ft THPc^syʃtKAg2q^~`65L=xE[;Ck3H hhou:"jru .l)BL<fՅfkE6z2ŵ.rokkS Uo_XY NEOi}PAlZK{Ɪ+gZUdDWՖD%@ #tV®_ZIl /`:@T*yBA 0whMMKȭMujЫzYߣY)}t#+z#5SS5_39uyVg S՝0kK+<l̓mlg?. YZasRŖTIaDv@ K>@h]AomZ ēn 8)6"ޒT&AXQ V&%Ot@8t}Y Mc4WJ8qU J~ Sr907MpLN_ȟD;Px.R ex. "ӰQn2;~?;YXƉ`#cb 6^n^~:0MN;!x4Wʙ8S$Z3g'ٜ̌CE5RPR*xҏd XQX`٘xt.? ϕZ/ :J;*ߑۑ≰URӥWXɏ00]̗>}w{Lu(vqb,hJn{-(0-v{i㽼t?-fvRQӂfXjQ) D{[,nǭMcQi:GSӜs[QDl"+%̅@0b\ Ƚ_`Ur%B]Lr{ #&L'NnR~^HZ|=^gqwniKmy?[u}md7P畜:z~i~e~Q_TȌt-֤֣+H:$RࢴUUI#Բ[SOkmi+IdyIBEe*6-X'/iéxs< 2L\+>&1>ex1NHU9Q8`(ǵY,*+цY#"vH̱c.:BRR踟]rWȯ-ifj L| K}Zt틛tAֵ+k%Pj迼&M׾3&3u*(leSZjr*[y&#≫!|HC/&=|iDX!=wz$6ae嬕.?:t~ HáX@Nіp)(gt*?\t { bNZi)qWA$R$.>嫌NƭS7$A%hKM~*q[ ^)ȭh *+;IRS/>c*T9Iɚ4x2krm'WIfX#[7 8S?$$J\@h{X>W5U4,m~zbزǕ^MՌ= 33:Ag8lb]үiBĥ*"=~UX/.?n2,vEY+:ǽ#۰\QZW_,*{mڹ}[gwSd'K>u _(h=)^&JX`+vA5\Jke+=h$*/t  ˌ a XJtJ&en{pN'g{o>+;Y=[o>ސ]^V;6l,u_~MX){߸u:5մӯw/׬DO)6^ɚ8|.EEXӌjaPgGQ O,9[NB9g E|&La]AL -*6Q>=SpiYr=,p,BDBLܽ\]%݂BX Lt }'\G>}%C5ۅ7oòiɵiqCuc5>yޙ03X_1jet^X(6 *}tH yߊk(zu:݄Rюh !8""Dd'Fhjݦ:]A)q!T- RA\y3LRAB\WS wa"E%J/ j.Oqb'V5,ih` MGm>S/F;: ola>eص(i`ƾ}s'Uh&Z%OYT]jgYb=jth:!g1aEn[Qkvy3bOZwy2<.D[_k8k~՟nmڂLkOyi Pc}뭜nSpLE)q 9;[z䜅GkB@ nA+||\.w{;I`{Gq;Kو`nZ}1c!dUJD 4tDAb͈2)E Y{˽pA׶[=uKh/LuTd)rCהL]l䖂5i~U˵(e=p6%rHWJ^2 VOE^!UV5 uj*f(1z:aF&xfA0KlM*:sösnxǹJzՕ ߇m3OaٙB0Kzb:<ށm]a}{_i#w|޾3|'?jmII7dB{MeGNٰX YNӝeWMЃ R2%kg2e ;cSMVtbEX? yFRKOɞ~qlK]7Z2fZ ?/3{$)dzZtlNP'hcJ)=|f"t<ڣ@(( KjGLMCV_=`6>uęcjOD'%&uꙦ?y)42%C_HĚ2@]}9~xToD!z=4"E&=$e-NT"J4t g<o4MW-Mk*%+3!e`KT> HKb %Fk* DhڢxDFB֔%n_&Are45&=cBM5,={;;#+WoKnop;a=wB#6ԵfPLrd][CkO/-]U7-*޿i`1|比VT%䭁u9*G+E\r 7՟PcgVnFeVjzU?~7ܷXf{#.x`A 6r[ }Cǀvo%ѿoKH?}S* -2RFV;~ x2t枍V1nUOcܜwT-usYV l\)b+6̀tˊj,jRfQC*H2d!CZ2afIF iD0X &'oxQz G&GPB POqgɪo=s(.xQ&L}V; ZoF|~:سx#T$fJ4jl !% \c FE{iL3MW-ݔ=oeq_-SYrkuuzUjj "B8OѦS߽v: k uq+kHL6X$&4WPH)ͽ)ÊD%NSii!NUEFTbu Y{+3JƦs9Z\VDO:suڢj,_Vuuθd ڌʝ3ص]zWӺgY5k||mi6ek^vFN+<}㒦l[,g(W&/uRzmZ9L#^-1AdՆ÷)!+9$SCgb[wRE -H$FSG[]].{CG}/OܞU<}nlP~=~uM?Z[+:zC0/`i?%R5r--UɇwHӖaeS5Ƒ2e9ItrQᢷCW P.J ,sD D629r=-k,{Zs,raʮڍ3jJ 0;ѥ-FGfgZreWU)Uh.xcp"{zQU`Pֳ,?S<8)5":d}55guf1CWBJm( #a7l-NV`v=7}3D"+kd&/U"P"g %h},>HF0I1&IbϦijCPm9zrTr5#rv\z5Kl^q-0zڞ-zy&!=.Pq%"Ɠ2Άmr"cHN19f8ҳ)^[X7GBBH?E[aԂkVNW]֮.Tle}'|;SBtn$&?#(͠2Ym T35ٓU+K' ɀӍz{K jhy0,:E!gEob\&[,)5Bvҙـ9MM qϓEiq[.7c#ycW}:+^N_-~֤qG+"wDKuj,j^c3Y/gx2$[AP_ffNxnfx{Pf%60mb# |Rr7L³Yo}v.ZYg%ٳRH q5sds$^tGirzבL?.L& z)٤dUe 좹+ l𥭍Ǿl|]W]jWe,Ά罦%/6T9s;햐_4GsB[RcJٜ~6iu"r*pa+kI\C$@B$H! (L+r<JIYđvG{ˣgۍm9T{\\iTЂŚCH".aIj6vmJK*=@Kp8llsڲyi)9yTb.Akڭ h9i6fh(ؖ-MDDVr7- )7BׅY#Y꿂UǜRmTk2L$Sr3H!|n:J &}}nxqhX~5F2Xesyĺ.Lۤr]km (oPo&پža⚪]?C[еܠsmu,:2gz0Hkt&@4TZhNwk4+Zlicl4Jw єF,F*?1&(5jg,s!/K# nw&&:x #naeR|PĮX6@^&RP-]v%JHrxxN24h[ilE.~<QwQ? lC!;>٣XH( %4)<ۨ}MUK^BүJ7 Uӏ y._GèVvA]J!:y 53QkB TK{d #z$i<ʒLeHP*i[i?`&2D+>"@wʡǣI_DHq!ְt! dF(}!ԙ!ݵ}!;X:rX| p-~+p'-(z( (!Z]Io[I$i]L!&a$ 5J -IRL2tJ\4X( 7`oNCAja4$ '.?'aeP&RK_'aa, 3BkEXx5O "*z$Q$L$L50ؒ98RN2 3(Cҝ`w%a 5-9:y+I ?!*0a5SAs"xV!I Ff8$ (jE@H OŐzIQ$1>]q! 3ȣ&a"l%$ *0WQ$ (0'?IS"!U^H _߉pI墜$ tT",ү $a/&ZlZ ^ԩZ`x#CCʡᡑ9A~@_(wwdwoONmH@׊$x wdz9{ yyyّ oj^<(;0;w#}c#=HWO!Rv0 ~_;5;w CC;FzGs*F`m=|64Ǐx@ݶc|(?;c`u8SP;"Gzƻ{30:<iktCޝc9|j́߻c+t}ƟIؼg`gHr8&Y4(XKD2`D#0kОC]'94>6<>%m{obll,޳gOΎrv t )Fè >pݽh uZxA @v c ډ>mPsK}[#3vKmO~{_ uCʅw@ТZQH<wB@;Q,G~KֻEJsnW  b\<*Q{Q6*[ W.#h7\Dz9y?"ԎX3"Vvs>]h8G4 @_^.끴>A"4uGhK%) FqD="z6q$^h5''AhKwW}o=*+[ e>ǫu iKlvbMfސIL g9p6iYZISa$4#Q#L9gIqRVHVVhLLS M?oclK䜶Lѥrȹ|> endobj 259 0 obj <> endobj 260 0 obj <> stream xy`E?^U3{gz'L9B™ x@ VWă]sEW]p, z*c]*==;zsSB1ϻxE+@+ay_\w|mGR} .&Pk\|#tً_';2, #t.M^x6/2怺]/{n[tťy7ЦjھleOq0Ca5?0" J]Ϥ F6s + r{`($ 1UYo46eǴ*0qR6Ϝ?W+BNU(Yg\ڊDBRmF-( ?ۡe!1>FCU@! ~d.mJ8 'Q yB/+*7v,1O!GD(xT eSI|lԇW3̯ #5I=UE8ԍ~p-GOn@ahu@(Ttځ!O /B] ՠe'ף[9BoTtЍh'zpd<'c`^e>.t"|S cw9z):[p9jr:c`Ct|*On.<^o4GwQ k0g&(V:_3A+nGBOCR{meqw%˜֢ԌC%hC0q,6< ;L&}d9}CۂT{5C_'b7{ 'l܋~95ߘ{5w FMpN4CaVMh z` <se|CD udI$ `.gfdv3Ó),(\^xُ\ ס[}0/W jO]@==| ߌ/ KԄ#9,~77Sa“nfg̼fvǮbaǾQժVWg{BocȂ|@"PaI3:hz-ǁh|>G_A?˰EZ\6/«|^[Fxޏï=x=08'Md@=I撅JF.xpmL@5S@I33DoOwc+_qs!{Ken#^e?a… 5h" #U̥r:6j9h봚2eF@oG::*qd>TU7'3O |gʙr4r&-2l^ BI\!ٸ|`P9M `mhۦML\Lm:=PpDmÎqX.G[64FՀ;2mD0/:mn$O(]ϋ;"̢| (̀z@5qMmnq>Ѱ `s;xwҀcՠ!2qѭfCsqnذ.8[C4{$6od(:}(C-њ%mdBdц%}0! hv[[8m FBHIm0ktRhn3qtaH\OiFE  BOFAh m8 NW74,N5zz*EF0푡N_QǸ-R!0h/DqEDH82uy<Y!C]s4y(Dg΅5U\v$G[Zlsh˚R} ߝnG̜ڶyJ#N77ض8ft7K։s)[95 1S˔ WRkppסݺPE—*9;qYcN:>{ timؠ;l,28BdǦ*CiLU = qݔ8]?|Ozz:` es\pEs\/eʨu,Cw qQooeثZBe^p&)c*S(!Gj(5b+AZVku` &*dffZެocgvylFrB9&W{ubL<7Hij[<6ena_쯤(EI__8(iGN} rģP@nrGӄ~֙īg!s|ʫ`PHQ#xC}ut1LL]L^Qƌ.o>!zz,랼Ax[Z}(k^[8Jͪvxe$[l|d fqTL ~M5ZKvTQ[ &-g: a4.S5q]B[kRuZmui; eh] MMX[mc;%3fYIOб!by1ԮCkjOӞ:@.B>Avd)^>f:Դ14$$W$pn~kS[D yt74<4;&,4 rG ϖѲqd8U3ZjQL0{tvHf&>6agv:xB]V*+וy{]m>@*L֡YV>2dee>Q mK쪮Bg,63Gm&+bI7=S?[p[ Z~:p9-F-wkXCFgޤo (}W,F ۢjӂWN᪪si9ȣC{IHF ^~A~q)S 1;:Fp6!43mNln~<4z0AIb kfsPp>:Z[Bǜ0idn4 W~ץ ، ^8id?L\tr*_^wm/q{Q-ٖX8C+B'te?Y|X-=#}Y, [l/S 孧roλct1j2sXϋ2m0u;}{|^GpiMfBZT7{`a_$9|.#ޥݠ#n~piĖxko&I{?dL\2p`ϕ&P , 5?&\y%Hƍ(";ee=e{4t1O.e8$Ο{?[҂i<:/TT=FwD:Ai1kdr]Lڎk)[oy ܆"/&g9 WE0Y&747R 9~+]yc.\]C:}PlZ=#~gr޵q290|N`^;?x ϗ%UF;rvbwWFu>o<4hX=tZ( E=hڀiQP{\ღn߃{pE=FвDl^_嚻s쯮{ZgBILs߯|;uC.1ƛޙ[S0g/[r :} hETv&<b~%Z{ Z2q٬rCm5^-<3IMIc֔4dxX|<|IJ1Ax@bXWqPrK*ve)hʭQ#s'io>3=^W U8\90N4u }SYR=:tHÐPljZT*䌧 GFY8f O>FOXD§MʫQ2%jSy[EnWP6z`z+:O ߸竄Z?լX音yA]vձ{\wUon[xW^u+E⽅ #T6r#h0a hr#{Q|MMk[z'04nZs8:1sgs>SEӪ. ^Z]\_Qq[lG3Ti`hKt>~^/Wlz֋=핕D{(6W39d;lOu{U_XI ʃ2|lh0M II+$>C1G\=4۫ MM#\+!t(یv$ 'u%&C:(T8Y3̘q/[;pM_5[ZuM?]v;MN;kɊ7ƥOz)]pwwY+k]qε::*{ dE-,NVٻ ]n㟖 2V^d sf 'ۤ 'lܱ9V OHoR`U+#r|&2ػ2/0# pu"':(NFhYA#m.#ܧï#]Ԫ>7ԌzEv!)cc#BQBցdAтc*1fH@ge0@ZXoP|6?{kao@N_Y>ԧ[hXj_X 0qFޥw&݆{ͪ 777&ފPtit]Yu `2떱kXsJdtZΟc%? 3x-ݦզLɘѷ_,}IH>r`[Ģ5Eߏ )tgYxm,r(SXcrN5u=sb陵4!dNe喳sU3mݫڙoOGjWEkSJr({@Ux 戹ܜBlM,HL*pUe%`f>np$^^HuZ5C0 t]vWʑpqtX* - -xW8enGQ7l/;B<)H@J,GK(L"|"K)YPxq--SS=칻N2Wx[2A!uJ r%2ठ5o ËwL gn=Avc%T4n3t߿v/_0obSsЈ4k`klg9+?Pjb ]]MGwΈ'n<y5z?%WŢQ &lx̢(ٯ%Aj*Z 6 6:#.GnݝE%]<e89$qb=4?/+xU)WJL6+@%M֫@Zs >HHr'@&M"0휌/H^b\cձز*ZK 5E3_qq9:$Y%i]NS%`e%Tgg)YrE=}QfʲLI9NxJ[e' 2kFT~_fo3\gƆ 77|9gBƞuo\*9CWNqanjVos Z&߷olj xCՍ/u@9nV.q&ԱM$UAdNY i &i⣉&-9HL ǀ89#AJ J3 GQ'. \!qOFQ<ftDvNЉND.h"Hq+5ΌaLH71*ahDAb]JݠNiiJD~R2:JPnX/u6z\n-'A7wMpude,2UVJޕ킧$;eEjZ*Xuʂw;Ae<mnyIoL᭱>@&40 5vZSuEcﭢ@:L]Q+{{Hrw0 q]b^d~xNp1r6U 6/wR&g9=ٻ Iש SxU2̲zε5ZP7;]@Qjѡ@:!m݁4"mAj.>줔{qWuRm3wr9GAuן5HXwpIs塓}GhKw~Gt|` Yuy`nf1CC^4j>qZuB3 DJ#Wth 6AlD4`ѤM 패oW1v, ^Z.O,4+*8nyCt)E(2@i8G bIRIQ=d?pHUo1[}t_8<Ҕ8Y2o^--be>َ$A2mY 0Y&" ɵUhk&ה&ioҗ/s^͹;/"XHfќ @$Pv翅oBm6WZfEg  c±xBtmC;*^f5ZVQtl@2ȉe1O-D"ť9hZj8P|^2&1'L`XF`YQJaMH0t}TtZ}/R@LU bZ%-AJz&`6!鰔hRuM=ֱ/h}վ/}ңiU63Fm&C2MFjlHs&Igs3)ӕ92PhJ0jl'3Vmf_gdݝ6fۇ _iq):vAFRSrz䄂H 8$C?ov$)nbփ#LRsh:P=khdg2 0{SepIkFS4q9cRnWCC?5YR0 ۅ>9K蠌gy \2s9Ya}[&KP34y "J>)yb":)No-Vbѐ-9i˰^Wtȡ` /9pcf:Ry1Oz}4Xg h*Ũ cѨ&,/:HT&}^KD+~~("ّV{˼^*>܇26F,*Ewњ挡->ↇNU!edNQ2 jlȪ,qM@G59֨^r[fU^zܫj;2t ER.a% 5Fs)0_4p JY |]lKѠ>.n(+8[DcDmԢ,è d/<=.?[p?͋ ށF7}TίΏ4X2Һ'w&w+rL`LفTWFw?=XyWE˕ ն iCIT>ۖJ)~˹ԥ6f?*#N+=Ex0]?/=tϚÓy&[deF\XYߟYw"II4a;ggG{*mM77vTKxryyN559BaPe,ۙ}cArd-ZkDmV0k+Sx! @; t!ZIyo|pet5bc:FXV0U]w\:445TR٠xh=:dX0J:W+N>1DR!uWGk'(W\{F㙝ӂ`;[qc[%mZ%G('?e4'惎7[L֌UGXoy7HvEJH;Ť>kys64g㒽0_ \N- O_:[Pk +6UlNu:SCs+,XX>p]_vBφxVSXlW318+ $h $xIHRb0LMU5"dT"_UJ`:]UiLZD 7M  u0`8 6ouQ/ +XywUF^$$XeGdPl; ,ccTY%ȨgH )NoCmVj(dR \=)(4x뽣<' IJ bҨYQnwtQjQ?ףHͣA ?r`9snXे毿02姞D.Y_-c=Fk@4u]EuΧA xԅ'J7;MY|8 1fy'L9{Fpsgwy3n}t +ds4yz[7esti)WL>p{eIDSnltLcc;L2c&bfnJ%uLyYcL+v&KntKV41m׌crxd $/[{ַgQ:&>б=%yᣀYG(Qr}Mu?L?L6`PD q[8 FQc>,S glNGq8vywAMVR^Q/V5L^N'/0°ꁟ_3fbssofoQ/M4m ;+mE3=sEۤje䓀b(θ)]NhjAԀxyi%y3gy\.{Ɨ&.GZta-]k{ oLDY[tG} rd8Y[E~rJyɝ̖ 9j^;k;ca y6y!osP$`_Rw|D)9>uas*:"F9M%TZN5\"1ԺZ4+?u˹|lv)b;X|1W^hkvbotл{(qJBD7dgm}e"cv.ʫ["5OT=Onrt;xp7³|xQUǢT =)G]Jݣ:a?>Ƈ| 9GZM.Tߤ_Cj<чwc&a Շá!f}I>XOYD'F`sȜd ٛdmlfsLh$"/#b뒠&::NƢSShI jQD`DhSM|SHtA%/N, K+h^*ƷQ?_ilq$\~nd xXjD<*spaKoir(nᆓrv}ptb*][W\X vGH%AI.IRb2(ulK :.QGeidi kA5EOEIر-)`lCtkÓ Vȥw4B;u9ܴ#BIJ"Ǝ|MC'89Zl(F[񒊴krJqMӓ`o|,v %qP[QUr}$!O NocEv5*+Аb>ZrTsQCb. 6Q1{ mӸ |jRgɦ\3keCWLmWz?G^j73G>OP&! +lX:?~ R*{, F:$FkAIKDqrC>{dҺVY1{՗^ʳzϻVwI`n)~WNkX^¿ L7~֜4_P H34$NZ{Ķ=4]7'u^R8K: (~Rwx0>==־m#AoDFf{t;춒36`q/Τx)tzC IFcҤU&6.ԸW}XM*tN9l)mJQg1RIl}-g*1y#7HݡrD樐utuj/>=F# ^$$-̔eS\IN;i|_k()H^u~:ѫ~Q7?y8:)+-XQ}}s"Ers '3X%^i- ^t<zB԰HDw&U]_~_h aH7iظ ͒~2S0ӽ]HH4v'Xn@ ܚL&6&$T w7sPKtozcHM/:Taӕ=~!}tG1#k t7>r>&DBίXC7Rc`iM^}.t&Оgcyj?E=4jF3fnSiolS/y+޾' \ E^$ަz-9M~[@#WU^~LZa"sluĬ N&٤yyktWܯSΨh &/oHh.o2m5=z4X߸оKowcVM:>s{tz!%b6@PfVWf8Ѱ[i典3!`0!kN%5Sʵ塠Y2w/͸׼|yyYevt`s8%0UԞ_bg{^xk}˨}G6]۵m1EG^x7`/w\v٫G(pB8q^j\K>ۓ `N.iJ :zGWC!@鑁rz ASj7%qbpT^c>UDUkXlpN͈b.6~o㮏دYnNéL"HcqT!OYLT;?D P~,mW?-V.Zj*I3"QϷNK0MOwE!C8|LGe\Iykc{Q(ܱ ͮ=fߦwg:LF W_]?V9}׌ p7n[o-\MYƳ_z޸amipX?F Cëqeǜzԩ;-SD5$J&g*ި8R»U9+S9:9tYmx)M_c7v{n\8,Ƀout8^2^n\xm~qkdxP~* nO'՜eXhBxtZ av(rTpQ"͸MuᎺ绿_ǰ**bp8Afr+\!V)eN[\h$\j;K.#uBloTT:wYTkt:uҺ^RFV]Aֹ["9H2u8XW][^v7vlR\4FגּIT19[aA?D:`qS(OK~<.X8;G)J<(ϝ|7#SiaBy`*1ȋm{  :ZVks.'6Y2kFVb9bG"y8PňwA9-` >N㟃|E LuIN:9!tl[*g$k ˄ .Ue]yQklƇ7?N9wZk˱qCNea}pjY=a~Ux NيzTkR3?NFn-ɯf%{Q# tYͺ la/6F2nk6 v hdEoPRn`H4.3:}A+Rc ƀ_xr#~Or(6Uv;i`A:t54zÙKZ{>ċC]T_xƙUU Fܚ7[<ڟu^yބY^vq:ϻJx-nZl˰tEƊZl3e*s[ <\Te15㆏>vO_/8n]GG*ts -Gb*K,4QJ[e(/Q 7Ɗ5@ oȜ\fgIMPr;*+q9KTZ(* E3xߐ2:j Y@Xh bW sNOUU: 梀{40p"ڀ=.5~Ԛٔ!`klS@)AzwMO?ego}Pڼ[yXvc3YaYrK7?ٓ q?o!C-u꘥LJ 7؇|0-_|_.ûҰR`uvCIsZ{z߃j{g]׫wޤ~F\M!/ iP.=;S<O(͞d[-4{ޖaSf?9k/ȹ"u~]9x +mMv[μ~zKc_oi:oz'5{_'3݊|ԯ xw\nDXV n Q~Ж(xcdfTe_zwŦGQv/ǒ?7XtED145 C|{fr[ >gO?7P3:"*wPsg^jcY/&#^"xmb'cسh<6db+3g˸?p2Mk|-j/y&WK*W k9yw\sypocc<~N˴շ'Y[dB*qyPq4񜕺Ɉns=^Yn uУ P$'L%!<z]l^/ުú4Ggg39!_P`4ϕɴE<-{EWQ5Lֵ\_)Z5$ __xMpðQYI`+so~. =t2 90=G~mnX6 VEW66:[Zm8G&y;}v1=o]wH"MO$g^ mD/mxF6|XLE&bpկ7^oŃs=fmO>vK鉶cƏbhc̱ձ7ԫZ>WrvV#JcxėKCd=jtБ >yqTɣ4gMqn;ͩ8ZOhYXEӫkJqqolE"D7D>S&?9L$)Pγ1Qdlç+h,nlܑp_8c_y؁= GDѢ/#;n@"g8+Ds] .$G9M* ;ߨPQMjQ)%Z>pEvԷuݗ ŗ{C67 ?=1X N[N.6 ڽ=ҪTO hAde[^۰#NvTE),H2\Wmeb*gj~ [tz},IH9t"O juIb>qBGU'r .Y;E:/F#|*.t//#O&!¤#[1?[CϯWs$ !Z.O()j5SyjŘ(g `骕NWH8GB{~6:n]η1&1\R—XJ" 5T;o" wRk{]KI,EnsCǭd :`tEAx;H$Dc5bR`eY~y(g>-aصY+1nzvT柂͞7MKOj?vQ&@gw9_y|zpF1z ,X^(=D`8qx7#fp)oa|:ƼxVf5Qv纽\oY{ۑۅn3L嶻FDϫLcθN4-{ڨI xP\"KxWHT0cs) RQf dtj'PIEv#*+ `dɣlՂZTWGԓjN=㮼SN"sٯvBJaChpVK*dkΆG^X\\WWV3N(⭬H(*TFٯ%v(ֆV+li2W4&hmo-,>Yw.gn l&}մ4aGg_V?f(Oը wx;N`51ct`@X"Ac W [V >(¼j&cۄGGo1o's3Q d:efPDD3%D24ZrXg f|ڤc1\=J@En]qN-i5뤇m53y|@˹?L{d_"  BwbE`EEfvkWSVY6cTBv:R9oׇ4j-/SsF ժy~.i٬ԭe5daq!K/qgX XF˛Wvzv7n۷ۧ|K.fӈbǐi(&=z5 j [k`,_Ee۰:`rYm.O?%{Jf +n>׺cJ*!lD=E7kov)"'/Ef]ƇbXF~u9, -bœFg~Shv*oGi!俟q^ɟ\2iqWװscXM3N(vL8k!8IgrXU낙ؽ*Z|50H-8Cö{' /Ͳ9D)YvGs5 oZTo Uo2/igb~| @AqC' )[DNoOp]< ,&F_H|08p m/r@o}('}~?QL7o| G!\Cp#B0B @9*jG a A(4P Q*!1Be Tq+BlB(+Dl?"{ \7 nZ+ZBkJCmw#րІm2xw"t+uBȷnڗ]vGhȊP}Q]IգaO q^kHE4:bl.KACgTp.~@~o FkP[\^S9uM #(y (O567S ?EIՌUUp52\K\C.Ջ #P2Vp-֮*T S\MW(8@q i mZ1s4'8/r˸2./r˸2./r\Wpﺂ{C3( q" B1JNFW!,')n N6a \O_$^~FnRC9I'r}\7H˙TpRGrtC9:=4QIZrt)8m?W\}qe(7 !\#UTe_ ~B{)E,E;ODk!jȟC4?ԻJR{i.Z u}骋.G<'"z\'jDPH|hE+|tyה؆֡~k!I}D9zBQڌr>%J hhz)uZq{hHI4Gi?D\ .{hr$Oun͛y}5pw >nJ-Q=Z]^rvAhkwS,4R;FVRBRV/9A+:ERbyΥjk^ODB*3;9p7a5/ ݐR n@Efp P T w s7UKclϨy_1v ;hg0{"4NTN'8M8&Dbe⥉1\+YțoM\6v}Wk^b76e7BXzzHYʶ~* r`!]26ͤYr|^Pt4t`@*P`$4([X5 ;Ucc4<7?JKmU`@ "IKM:XWR7@]22ey.c{q]qm1eWH?o4^ѸraqFcjz|qwMȈ^*ΧnAiԈ1|h/+Q .$q\*lLA_L &Bԋ^D>\ 0~^P;|vN;@;\.hâY93qNqSq 8rYJַkiYU2r`0ǠUhƶ2֑]u8u1ude1ڑMG0B#̭coó$&u9QnKtGGrnp5X/57^٪.s6aZ&C/WhK6X-ȵr \405<~R;|vxvxv8.ۺnj;ZG։d#Yx MǘfҴ77vt£tz]IzBǬIt(PxhyL;OS:BQ#m#)BҴ!J4$ QvK4@ M,~ 5ktC:_)E%xѯ>1,G=F4 ԋCq?6*IK˗$ $f%ɵq;$ mk冦F074J@ǽ ; Pb2Mقp:#/_4 endstream endobj 261 0 obj 27650 endobj 262 0 obj <> endobj xref 0 263 0000000000 65535 f 0000000016 00000 n 0000008041 00000 n 0000013819 00000 n 0000026831 00000 n 0000033559 00000 n 0000038256 00000 n 0000042454 00000 n 0000047844 00000 n 0000051418 00000 n 0000054817 00000 n 0000058247 00000 n 0000062748 00000 n 0000065868 00000 n 0000071113 00000 n 0000075894 00000 n 0000079363 00000 n 0000082946 00000 n 0000086981 00000 n 0000091055 00000 n 0000094218 00000 n 0000097821 00000 n 0000101515 00000 n 0000105113 00000 n 0000109185 00000 n 0000113614 00000 n 0000116888 00000 n 0000119810 00000 n 0000122905 00000 n 0000126157 00000 n 0000129415 00000 n 0000132110 00000 n 0000135603 00000 n 0000139765 00000 n 0000140887 00000 n 0000007977 00000 n 0000007821 00000 n 0000000472 00000 n 0000006089 00000 n 0000007650 00000 n 0000000081 00000 n 0000000186 00000 n 0000000310 00000 n 0000000629 00000 n 0000001309 00000 n 0000001872 00000 n 0000002546 00000 n 0000002958 00000 n 0000005452 00000 n 0000005607 00000 n 0000005736 00000 n 0000005864 00000 n 0000005979 00000 n 0000000748 00000 n 0000000923 00000 n 0000001055 00000 n 0000001200 00000 n 0000001465 00000 n 0000001575 00000 n 0000001733 00000 n 0000002022 00000 n 0000002176 00000 n 0000002307 00000 n 0000002431 00000 n 0000002697 00000 n 0000002830 00000 n 0000003111 00000 n 0000003239 00000 n 0000003377 00000 n 0000003515 00000 n 0000003649 00000 n 0000003777 00000 n 0000003936 00000 n 0000004078 00000 n 0000004210 00000 n 0000004369 00000 n 0000004487 00000 n 0000004616 00000 n 0000004792 00000 n 0000004919 00000 n 0000005048 00000 n 0000005187 00000 n 0000005333 00000 n 0000006271 00000 n 0000007040 00000 n 0000007191 00000 n 0000007301 00000 n 0000007423 00000 n 0000007545 00000 n 0000006372 00000 n 0000006497 00000 n 0000006633 00000 n 0000006773 00000 n 0000006933 00000 n 0000008309 00000 n 0000010600 00000 n 0000014985 00000 n 0000015158 00000 n 0000015293 00000 n 0000015428 00000 n 0000015563 00000 n 0000015699 00000 n 0000015835 00000 n 0000015971 00000 n 0000016107 00000 n 0000016243 00000 n 0000016380 00000 n 0000016518 00000 n 0000016656 00000 n 0000016793 00000 n 0000016931 00000 n 0000017069 00000 n 0000017207 00000 n 0000017344 00000 n 0000017482 00000 n 0000017620 00000 n 0000017758 00000 n 0000017896 00000 n 0000018033 00000 n 0000018171 00000 n 0000018309 00000 n 0000018446 00000 n 0000018584 00000 n 0000018722 00000 n 0000018860 00000 n 0000018998 00000 n 0000019136 00000 n 0000019273 00000 n 0000019411 00000 n 0000019549 00000 n 0000019687 00000 n 0000019825 00000 n 0000019963 00000 n 0000020101 00000 n 0000020239 00000 n 0000020377 00000 n 0000020515 00000 n 0000020653 00000 n 0000020790 00000 n 0000020925 00000 n 0000021060 00000 n 0000021195 00000 n 0000014463 00000 n 0000014813 00000 n 0000010622 00000 n 0000011115 00000 n 0000011137 00000 n 0000013796 00000 n 0000141155 00000 n 0000155393 00000 n 0000179496 00000 n 0000189889 00000 n 0000213448 00000 n 0000220003 00000 n 0000021330 00000 n 0000026808 00000 n 0000027192 00000 n 0000027329 00000 n 0000027466 00000 n 0000027603 00000 n 0000027741 00000 n 0000027879 00000 n 0000028017 00000 n 0000028155 00000 n 0000028293 00000 n 0000028430 00000 n 0000028567 00000 n 0000028704 00000 n 0000225445 00000 n 0000028841 00000 n 0000033536 00000 n 0000238881 00000 n 0000033826 00000 n 0000038233 00000 n 0000038523 00000 n 0000042431 00000 n 0000252441 00000 n 0000042709 00000 n 0000047821 00000 n 0000048087 00000 n 0000051395 00000 n 0000051673 00000 n 0000054794 00000 n 0000055073 00000 n 0000058224 00000 n 0000058503 00000 n 0000062725 00000 n 0000063004 00000 n 0000065845 00000 n 0000066112 00000 n 0000071090 00000 n 0000071381 00000 n 0000075871 00000 n 0000076162 00000 n 0000079340 00000 n 0000079619 00000 n 0000082923 00000 n 0000083214 00000 n 0000086958 00000 n 0000087249 00000 n 0000091032 00000 n 0000091329 00000 n 0000091466 00000 n 0000094195 00000 n 0000094486 00000 n 0000097798 00000 n 0000098077 00000 n 0000101492 00000 n 0000101771 00000 n 0000105090 00000 n 0000105369 00000 n 0000109162 00000 n 0000109441 00000 n 0000113591 00000 n 0000113882 00000 n 0000116865 00000 n 0000117144 00000 n 0000119787 00000 n 0000120066 00000 n 0000122882 00000 n 0000123173 00000 n 0000126134 00000 n 0000126413 00000 n 0000129392 00000 n 0000129671 00000 n 0000132087 00000 n 0000132366 00000 n 0000135580 00000 n 0000135877 00000 n 0000136015 00000 n 0000139742 00000 n 0000140021 00000 n 0000140865 00000 n 0000141905 00000 n 0000142103 00000 n 0000155369 00000 n 0000156149 00000 n 0000156345 00000 n 0000179472 00000 n 0000180181 00000 n 0000180373 00000 n 0000189866 00000 n 0000190379 00000 n 0000190568 00000 n 0000191229 00000 n 0000191207 00000 n 0000213424 00000 n 0000214130 00000 n 0000214321 00000 n 0000219980 00000 n 0000220643 00000 n 0000220828 00000 n 0000225422 00000 n 0000226143 00000 n 0000226342 00000 n 0000238857 00000 n 0000239589 00000 n 0000239784 00000 n 0000252417 00000 n 0000253212 00000 n 0000253417 00000 n 0000281159 00000 n 0000281183 00000 n trailer < <022C2DF4E3DE46B69F6B596F79C0CC8C>]>> startxref 281334 %%EOF 3 0 obj << /Type /Page /Parent 2 0 R /MediaBox 265 0 R /Contents 94 0 R /Resources 266 0 R /Annots 267 0 R >> endobj 264 0 obj << /Type /Annot /Dest 268 0 R /Rect 269 0 R /Border 270 0 R /BS 271 0 R /Contents <> /DA <2f2f48656c76657469636120313220546620302067> /F 0 /A 272 0 R /Subtype /Link /AAPL:Hash /197cb0f14655f1d109bcbcf7ee84b219 >> endobj 265 0 obj [ 0 0 612 792 ] endobj 266 0 obj << /Font 273 0 R /ProcSet 274 0 R /ColorSpace 275 0 R >> endobj 267 0 obj [ 142 0 R 143 0 R 96 0 R 97 0 R 98 0 R 99 0 R 100 0 R 101 0 R 102 0 R 103 0 R 104 0 R 105 0 R 106 0 R 107 0 R 108 0 R 109 0 R 110 0 R 111 0 R 112 0 R 113 0 R 114 0 R 115 0 R 116 0 R 117 0 R 118 0 R 119 0 R 264 0 R 121 0 R 122 0 R 123 0 R 124 0 R 125 0 R 126 0 R 127 0 R 128 0 R 129 0 R 130 0 R 131 0 R 132 0 R 133 0 R 134 0 R 135 0 R 136 0 R 137 0 R 138 0 R 139 0 R 140 0 R 141 0 R ] endobj 268 0 obj [ /#2320 /XYZ 0.000000 305.000000 null ] endobj 269 0 obj [ 97.200000 283.082200 168.193700 293.308300 ] endobj 270 0 obj [ 0.000000 0.000000 0.000000 ] endobj 271 0 obj << /W 0.000000 >> endobj 272 0 obj << /S /GoTo /D 276 0 R >> endobj 273 0 obj << /F1 148 0 R /F2 149 0 R /F3 150 0 R /F4 151 0 R /F5 152 0 R /F6 153 0 R >> endobj 274 0 obj [ /PDF /Text ] endobj 275 0 obj << /DefaultRGB 277 0 R >> endobj 276 0 obj [ /#2320 /XYZ 0.000000 305.000000 null ] endobj 277 0 obj [ /ICCBased 146 0 R ] endobj xref 3 1 0000286753 00000 n 264 14 0000286878 00000 n 0000287120 00000 n 0000287158 00000 n 0000287237 00000 n 0000287687 00000 n 0000287751 00000 n 0000287820 00000 n 0000287872 00000 n 0000287910 00000 n 0000287957 00000 n 0000288060 00000 n 0000288095 00000 n 0000288141 00000 n 0000288205 00000 n trailer << /Info 262 0 R /Size 277 /Root 1 0 R /ID [ <022c2df4e3de46b69f6b596f79c0cc8c> <022c2df4e3de46b69f6b596f79c0cc8c> ] /Prev 281334 >> startxref 288247 %%EOF ./nsf2.4.0/doc/persistenceExample-xotcl.html000644 000766 000024 00000001604 12161565463 021624 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/store/persistenceExample.xotcl

    ./library/store/persistenceExample.xotcl ./library/store/persistenceExample.xotcl


    Package/File Information

    No package provided/required

    Filename: ./library/store/persistenceExample.xotcl




    Back to index page.

    ./nsf2.4.0/doc/mixin.man.inc000644 000766 000024 00000010636 12501766547 016351 0ustar00neumannstaff000000 000000 [comment {-*- tcl -*- manpage fragment for mixin method, shared by nx::Object and nx::Class}] [keywords "mixin class"] [keywords linearisation] [call [arg [vset CMD]] [method "[vset MODIFIER] mixins"] [arg submethod] [opt "[arg arg] ..."]] Accesses and modifies the list of [term "mixin class"]es of [arg [vset CMD]] using a specific setter or getter [arg submethod]: [list_begin definitions] [def "[arg [vset CMD]] [const [vset MODIFIER]] [method {mixins add}] [arg spec] [opt [arg index]]"] Inserts a single [term "mixin class"] into the current list of [term "mixin class"]es of [arg [vset CMD]]. Using [arg index], a position in the existing list of [term "mixin class"]es for inserting the new [term "mixin class"] can be set. If omitted, [arg index] defaults to the list head (0). [comment {Therefore, by default, any added [term "mixin class"] takes precedence over previously added classes in the overall linearisation of [arg [vset CMD]].}] [def "[arg [vset CMD]] [const [vset MODIFIER]] [method "mixins classes"] [opt [arg pattern]]"] If [arg pattern] is omitted, returns the object names of the [term "mixin class"]es which extend [arg [vset CMD]] directly. By specifying [arg pattern], the returned [term "mixin class"]es can be limited to those whose names match [arg pattern] (see [cmd "string match"]). [def "[arg [vset CMD]] [const [vset MODIFIER]] [method {mixins clear}]"] Removes all [term "mixin class"]es from [arg [vset CMD]] and returns the list of removed [term "mixin class"]es. Clearing is equivalent to passing an empty list for [arg mixinSpecList] to [const [vset MODIFIER]] [method {mixins set}]. [def "[arg [vset CMD]] [const [vset MODIFIER]] [method {mixins delete}] [opt [option -nocomplain]] [arg specPattern]"] Removes a [term "mixin class"] from a current list of [term "mixin class"]es of [arg [vset CMD]] whose spec matches [arg specPattern]. [arg specPattern] can contain special matching chars (see [cmd "string match"]). [const [vset SCOPE]] [method "mixins delete"] will throw an error if there is no matching [term "mixin class"], unless [option -nocomplain] is set. [def "[arg [vset CMD]] [const [vset MODIFIER]] [method {mixins get}]"] Returns the list of current [term "mixin specification"]s. [def "[arg [vset CMD]] [const [vset MODIFIER]] [method {mixins guard}] [arg className] [opt [arg expr]]"] If [arg expr] is specified, a guard expression [arg expr] is registered with the [term "mixin class"] [arg className]. This requires that the corresponding [term "mixin class"] [arg className] has been previously set using [const [vset SCOPE]] [method {mixins set}] or added using [const [vset MODIFIER]] [method {mixins add}]. [arg expr] must be a valid Tcl expression (see [cmd expr]). An empty string for [arg expr] will clear the currently registered guard expression for the [term "mixin class"] [arg className]. [para] If [arg expr] is not specified, returns the active guard expression. If none is available, an empty string will be returned. [def "[arg [vset CMD]] [const [vset MODIFIER]] [method {mixins set}] [arg mixinSpecList]"] [arg mixinSpecList] represents a list of [term "mixin class"] specs, with each spec being itself either a one-element or a three-element list: [arg className] ?-guard [arg guardExpr]?. If having one element, the element will be considered the [arg className] of the [term "mixin class"]. If having three elements, the third element [arg guardExpr] will be stored as a guard expression of the [term "mixin class"]. This guard expression will be evaluated using [cmd expr] when [arg [vset CMD]] receives a message to determine if the mixin is to be considered during method dispatch or not. Guard expressions allow for realizing context-dependent or conditional mixin composition. [list_end] [comment { A [term "mixin class"] whose spec is featured earlier in [arg mixinSpecList] takes precedence in the [term "linearisation"] over a [term "mixin class"] whose spec is listed later. The computed, overall [term linearisation] of [arg [vset CMD]] guarantees to maintain this local order of [term "mixin class"]es. }] At the time of setting the mixin relation, that is, calling [const [vset MODIFIER]] [method mixins], every [arg className] as part of a spec must be an existing instance of [cmd nx::Class]. To access and to manipulate the list of [term "mixin class"]es of [arg [vset CMD]], [method cget]|[method configure] [option -[join [list {*}[vset MODIFIER] mixins] -]] can also be used. ./nsf2.4.0/doc/langRef-xotcl.html000644 000766 000024 00000362447 13443231440 017346 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./doc/langRef.xotcl

    ./doc/langRef.xotcl ./doc/langRef.xotcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./doc/langRef.xotcl

    Description: XOTcl language reference. Describes predefined objects and classes.
    Predefined primitives: XOTcl contains the following predefined primitives (Tcl commands):
    self
    computes callstack related information. It can be used in the following ways:
    • self - returns the name of the object, which is currently in execution. If it is called from outside of a proc, it returns the error message ``Can't find self''.
    • self class - the self command with a given argument class returns the name of the class, which holds the currently executing instproc. Note that this may be different to the class of the current object. If it is called from a proc it returns an empty string.
    • self proc - the self command with a given argument proc returns the name of the currently executing proc or instproc.
    • self callingclass: Returns class name of the class that has called the executing method.
    • self callingobject: Returns object name of the object that has called the executing method.
    • self callingproc: Returns proc name of the method that has called the executing method.
    • self calledclass: Returns class name of the class that holds the target proc (in mixins and filters).
    • self calledproc: Returns method name of the target proc (only applicable in a filter).
    • self isnextcall: Return 1 if this method was invoked via next, otherwise 0
    • self next: Return the "next" method on the precedence path as a string.
    • self filterreg: In a filter: returns the name of the object/class on which the filter is registered. Returns either 'objName filter filterName' or 'className instfilter filterName'.
    • self callinglevel: Returns the calling level, from where the actual proc was called from. Intermediary next calls are ignored in this computation. The level is returned in a form it can be used as first argument in uplevel or upvar.
    • self activelevel: Returns the level, from where the actual proc was invoked from. This might be the calling level or a next call, whatever is higher in the stack. The level is returned in a form it can be used as first argument in uplevel or upvar.

    my methodName
    is a short form for [self] methodName and can only be called in a context of an instproc or a method specific proc. It allows certain optimizations and shorter to write.

    next
    invokes the next shadowed (same-named) method on the precedence path and returns its result. If next is called without arguments, the arguments of the current method are passed through the called method. If next is invoked with the flag --noArgs, the shadowed method is called without arguments. If other arguments are specified for next, these will be used for the call.

    myvar varName
    returns the fully qualified variable name of the specified variable.

    myproc methodName ?args?
    calls the specified XOTcl method without the need of using "[list [self] methodName ...]".

    ::xotcl::alias class|obj methodName ?-objscope? ?-per-object? cmdName
    can be used to register a predefined C-implemented Tcl command as method methodName. The option -objscope has the same meaning as for forwarder (instance variables of the calling object appear in the local scope of the Tcl command), -per-object has the same meaning as for the method method (when used on a class, the method is registered for the class object only, but not for the instances). This command can be used to bootstrap xotcl (when e.g. no methods are available).

    ::xotcl::configure filter ?on|off?
    allows one to turn on or off filters globally for the current interpreter. By default, the filter state is turned off. This function returns the old filter state. This function is needed for the serializer that is intended to serialize the objects classes independent of filter settings.

    ::xotcl::configure softrecreate ?on|off?
    allows one to control what should happen, when an object / a class is recreated. Per default it is set off, which means that the object/class is destroyed and all relations (e.g. subclass/superclass) to other objects/classes are destroyed as well. If softrecreate is set, the object is reset, but not destroyed, the relations are kept. This is important, when e.g. reloading a file with class definitions (e.g. when used in OpenACS with file watching and reloading). With softrecreate set, it is not necessary to recreate dependent subclasses etc.

    Example: e.g. there is a class hierarchy A <- B <- C Without softrecreate set, a reload of B means first a destroy of B, leading to A <- C, and instances of B are re-classed to ::xotcl::Object. When softrecreate is set, the structure remains unchanged.

    ::xotcl::finalize
    Delete all XOTcl objects and classes and free all associated memory.

    This command has the only purpose to delete all objects and classes of an interpreter in a multi-threaded environment at a safe time.

    Background: when XOTcl is used in a threaded environment such as for example in AOLserver, one has to take care that the deletion of objects and classes happens in a safe environment, where the XOTcl destructors (destroy methods) are still able to run. Without ::xotcl::finalize the deletion happens in Tcl_FinalizeThread(), after thread cleanup (where e.g. the thread local storage is freed). This can lead to memory leaks in AOLserver, which allocates e.g. some structures on demand, but since this happens after cleanup, it will leak. A simple ns_log in a destructor might lead to this problem. The solution is to call ::xotcl::finalize in the "delete trace" in AOLserver (as it happens in OpenACS).

    Note that ::xotcl::finalize is not intended for application programs.



    Class: ::xotcl::Slot

    Class: Class
    Heritage: Object
    Description: A slot is a meta-object that manages property-changes of objects. A property is either an attribute or a role of an relation (e.g. in system slots). The predefined system slots are class, superclass, mixin, instmixin, filter, instfilter. These slots appear as methods of Object or Class.

    The slots provide a common query and setting interface. Every multivalued slot provides e.g. a method add to add a value to the list of values, and a method delete which removes it. See for example the documentation of the slot mixin.

    Parameters:

    -name Name of the slot to access from an object the slot
    -domain domain (object or class) of a slot on which it can be used
    -multivalued boolean value for specifying single or multiple values (lists)
    -defaultmethods list of two elements for specifying which methods are called per default, when no slot method is explicitly specified
    -manager the manager object of the slot (per default [self])
    -per-object specify whether a slot should be used per class or per object; note that there is a restricted usage if applied per class, since defaults etc, work per initialization

    For more details, consult the tutorial.


    Class: Attribute

    Class: Class
    Heritage: ::xotcl::Slot
    Description: Attribute slots are used to manage the setting and querying of instance variables. Parameters:

    -default specify a default value
    -type specify the type of a slot
    -initcmd specify a Tcl command to be executed when the value of the associated variable is read the first time; allows lazy initialization
    -valuecmd specify a Tcl command to be executed whenever the variable is read
    -valuechangedcmd specify a Tcl command to be executed whenever the variable is changed

    Example of a class definition with three attribute slots:

      Class Person -slots {
        Attribute name
        Attribute salary -default 0
        Attribute projects -default {} -multivalued true
      }
      Person p1 -name "John Doe"
    

    The slot parameters default, initcmd and valuecmd have to be used mutually exclusively. For more details, consult the tutorial.


    Class: Class

    Class: Class
    Heritage: Object
    Procs/Instprocs: __unknown, allinstances, alloc, create, info, instdestroy, instfilter, instfilterguard, instforward, instinvar, instmixin, instparametercmd, instproc, new, parameter, parameterclass, recreate, superclass, unknown.
    Description: This meta-class holds the pre-defined methods available for all XOTcl classes.

    Instprocs

    • alloc obj ?args?
      Arguments: obj: new obj/class name
      ?args?: arguments passed to the new class after creation
      Description: Allocate an uninitialized XOTcl object or class. Alloc is used by the method create to allocate the object. Note that create also calls as well configure and init to initialized the object. Only in seldom cases the programmer may want to suppress the create mechanism and just allocate uninitiaized objects via alloc.
      Return: new class name
    • allinstances
      Description: Compute all immediate and indirect instances of a class
      Return: fully qualified list of instances
    • create objName ?args?
      Arguments: objName: name of a new class or object
      ?args?: arguments passed to the constructor
      Description: Create user-defined classes or objects. If the class is a meta-class, a class is created, otherwise an object. The method create is responsible for allocating and initializing objects. The method can be overloaded e.g. in a metaclass if other initialization behavior is wanted.

      The standard behavior of create is as follows:

      1. Call the method alloc to create an uninitialized object.
      2. Call the method searchDefaults to set default values for instance attributes-
      3. Call the method configure to configure the object with the values provided at object creation time. The method configure interprets the arguments with leading dashes as method calls.
      4. Call the method init to allow initialization by the class. The argument passed to init are the values from the passed argument list containing the arguments up to the first '-'.

      Create firstly calls alloc in order to allocate memory for the new object. Then default values for parameters are searched on superclasses (an set if found). Finally the constructor init is called on the object with all arguments up to the first '-' arg.

      The create method is often called implicitly through the unknown mechanism when a class (meta-class) is called with an unknown method. E.g. the following two commands are equivalent

          Car herby -color red 
          Car create herby -color red 
      When a users may want to call the constructor init before other '-' methods, one can specify '-init' explicitly in the left to right order of the '-' method. Init is called always only once. e.g.:
         Class Car -init -superclass Vehicle 
      Return: name of the created instance (result of alloc)
    • info args
      Arguments: args: info options
      Description: Introspection of classes. All options available for objects (see info object) is also available for classes. The following options can be specified:
      • ClassName info classchildren ?pattern?: Returns the list of nested classes with fully qualified names if pattern was not specified, otherwise it returns all class children where the class name matches the pattern.
      • ClassName info classparent: Returns the class ClassName is nesting to.
      • ClassName info heritage ?pattern?: Returns a list of all classes in the precedence order of the class hierarchy. If pattern is specified, only matching values are returned.
      • ClassName info instances ?-closure? ?pattern?: Returns a list of the instances of the class. If -closure is specified, the resultet contains as well the instances of subclasses. If pattern is specified and it contains wildcards, all matching instances are returned. If pattern does not contain wildcards, either the fully qualified name is returned, or empty, if no match exists.
      • ClassName info instargs method: Returns the arguments of the specified instproc (instance method).
      • ClassName info instbody method: Returns the body of the specified instproc (instance method).
      • ClassName info instcommands ?pattern?: Returns all commands defined for the class. If pattern is specified it returns all commands that match the pattern.
      • ClassName info instdefault method arg var: Returns 1 if the argument arg of the instproc (instance method) method has a default value, otherwise 0. If it exists the default value is stored in var.
      • ClassName info instfilter: Returns the list of registered filters. With -guard modifier all instfilterguards are integrated ( ClassName info instfilter -guards).
      • objName info instfilterguard name: Returns the guards for instfilter identified by name.
      • objName info instforward ?-definition name? ?pattern?: Returns the list of instforwarders. One can call this method either without the optional arguments, or with the pattern or with -definition name. When the pattern is specified only the matching instforwarders are returned. When the definition option is used together with a name of a isntforwarder, the definition of the instforwarder with all flags is returned in a way that can be used e.g. for registering the instforwarder on another class.
      • ClassName info instinvar: Returns class invariants.
      • ClassName info instmixin ?pattern?: Returns the list of instmixins of this class. If pattern is specified and it contains wildcards, all matching mixin classes are returned. If pattern does not contain wildcards, either the fully qualified name is returned, or empty, if no match exists.
      • ClassName info instmixinof ?-closure? ?pattern?: Returns the list of classes, into which this class was mixed in via instmixin. This is the inverse function of ClassName info instmixin. If -closure is specified, also the classes are returned, for which the class is indirectly mixed in via instmixin. If pattern is specified and it contains wildcards, all matching mixin classes are returned. If pattern does not contain wildcards, either the fully qualified name is returned, or empty, if no match exists.
      • ClassName info instnonposargs methodName: returns list of non-positional args of methodName
      • objName info instparametercmd ?pattern?: Returns a list of registered instparametercmds the class (or empty if there are none). If pattern is specified, only the matching instparametercmds are returned.
      • ClassName info instpost methodName: Returns post assertions of methodName.
      • ClassName info instpre methodName: Returns pre assertions of methodName.
      • ClassName info instprocs ?pattern?: Returns all instprocs defined for the class. If pattern is specified it returns all instprocs that match the pattern.
      • ClassName info mixinof ?-closure? ?pattern?: Returns the list of classes, into which this class was mixed in via per object mixin. This is the inverse function of Object info mixin. If -closure is specified, also the classes are returned, for which the class is indirectly mixed in as a per-object mixin. If pattern is specified and it contains wildcards, all matching mixin classes are returned. If pattern does not contain wildcards, either the fully qualified name is returned, or empty, if no match exists.
      • ClassName info parameter: Returns parameter list.
      • ClassName info subclass ?-closure? ?pattern?: Returns a list of all subclasses of the class. If -closure is specified, the result contains as well the subclasses of the subclasses. If pattern is specified and it contains wildcards, all matching subclasses are returned. If pattern does not contain wildcards, either the fully qualified name is returned, or empty, if no match exists.
      • ClassName info superclass ?-closure? ?superclassname?: Returns a list of all super-classes of the class. If -closure is specified, the result contains as well the superclasses of the superclasses. If pattern is specified and it contains wildcards, all matching superclasses are returned. If pattern does not contain wildcards, either the fully qualified name is returned, or empty, if no match exists.
      Return: Value of introspected option as a string.
    • instdestroy obj ?args?
      Arguments: obj: obj/class name
      ?args?: arguments passed to the destructor
      Description: Standard destructor. Destroys XOTcl object physically from the memory. Can be overloaded for customized destruction process.

      In XOTcl objects are not directly destroyed, when a destroy is encountered in a method. Beforehand, the interpreter looks up whether the object is still referenced on the method callstack or not. If not, the object is directly destroyed. Otherwise every occurrence of the object on the callstack is marked as destroyed. During popping of the callstack, for each object marked as destroyed, the reference count is decremented by one. When no more references to the object are on the callstack the object is physically destroyed. This way we can assure that objects are not accessed with [self] in running methods after they are physically destroyed.

      Return: empty string
    • instfilter ?args?
      Arguments: ?args?: instfilter specification
      Description: If $args is one argument, it specifies a list of instfilters to be set. Every filter must be an XOTcl proc/instproc within the object scope. If $args it has more argument, the first one specifies the action. Possible values are assign, get, add or delete, it modifies the current settings as indicated. For more details, check the tutorial.
      Return: if $args return empty current instfilters, otherwise empty
    • instfilterguard filterName guard
      Arguments: filterName: filter name of a registered filter
      guard: set of conditions to execute the filter
      Description: Add conditions to guard a filter registration point. The filter is only executed, if the guards are true. Otherwise we ignore the filter. If no guards are given, we always execute the filter.
      Return: empty string
    • instforward methodName ?options? ?callee? ?args?
      Arguments: methodName: name of forwarder method
      ?options?: -objscope, -methodprefix string, -default names, -earlybinding, -verbose
      ?callee?: named of the called command or object
      ?args?: arguments
      Description: Register a method for the instances of a class (similar to an instproc) for forwarding calls to a callee (target Tcl command, other object). When the forwarder method is called, the actual arguments of the invocation are appended to the specified arguments. In callee an arguments certain substitutions can take place:
      • %proc: substituted by name of the forwarder method
      • %self: substitute by name of the object
      • %1: substitute by first argument of the invocation
      • {%@POS value}: substitute the specified value in the argument list on position POS, where POS can be a positive or negative integer or end. Positive integers specify the position from the begin of the list, while negative integer specify the position from the end.
      • {%argclindex LIST}: take the nth argument of the specified list as substitution value, where n is the number of arguments from the invocation.
      • %%: a single percent.
      • %Tcl-command: command to be executed; substituted by result.
      Additionally each argument can be prefixed by the positional prefix %@POS (note the delimiting space at the end) that can be used to specify an explicit position. POS can be a positive or negative integer or the word end. The positional arguments are evaluated from left to right and should be used in ascending order. valid Options are:
      • -objscope causes the target to be evaluated in the scope of the object,
      • -methodprefix string inserts the specified prefix in front of the second argument of the invocation,
      • -default is used for default method names (only in connection with %1)
      • -earlybinding: look up the function pointer of the called Tcl command at definition time of the forwarder instead of invocation time. This option should only be used for calling C-implemented Tcl commands, no procs etc.);
      • -verbose
      • : print the substituted command to stderr before executing
      See tutorial for detailed examples.
      Return: empty
    • instinvar invariantList
      Arguments: invariantList: Body of invariants for the class
      Description: Specify invariants for the class. These are inherited by subclasses. The invariants must hold for all instances. All assertions are a list of ordinary Tcl conditions.
      Return: empty string
    • instmixin ?args?
      Arguments: ?args?: instmixin specification
      Description: If $args is one argument, it specifies a list of instmixins to be set. Every instmixin must be a defined class. If $args has more argument, the first one specifies the action. Possible values are assign, get, add or delete, it modifies the current settings as indicated. For more details, check the tutorial.
      Return: if $args empty return current instmixins, otherwise empty
    • instparametercmd name
      Arguments: name: variable to be provided with getter/setter method
      Description: Add a getter/setter command for an instance variable with the specified name. This method is used for example by the parameter method. Example:
          Class C
          C instparametercmd x
          C c1 -x 100
          puts [c1 x]
      Return: empty string
    • instproc name ?non-pos-args?" args body ?preAssertion? ?postAssertion?
      Arguments: name: instance method name
      ?non-pos-args?": optional non-positional arguments
      args: instance method arguments
      body: instance method body
      ?preAssertion?: optional assertions that must hold before the proc executes
      ?postAssertion?: optional assertions that must hold after the proc executes
      Description: Specify an instance method in the same style as Tcl specifies procs.
      Optionally assertions may be given by two additional arguments. Therefore, to specify only post-assertions an empty pre-assertion list must be given. All assertions are a list of ordinary Tcl conditions.
      When instproc is called with an empty argument list and an empty body, the specified instproc is deleted.
      Return: empty string
    • new ?-childof obj? ?args?
      Arguments: ?-childof obj? ?args?: args passed to create
      Description: Convenience method to create an autonamed object. E.g.:
          HTTP new 
      creates ::xotcl::__#0, a subsequent call creates ::xotcl::__#1, ...
      If -childof obj is specified, the new object is created as a child of the specified object.
      Return: new object name
    • parameter parameterList
      Arguments: parameterList: list of parameter definitions
      Description: Specify parameters automatically created for each instance. Parameters denote instance variables which are available on each class instance and that have a getter/setter method with their own name. Parameters are specified in a parameter list of the form {p1 p2 ... pn}. p1 ... pn may either be parameter names or definitions of the form {parameterName defaultValue}. If a default value is given, that parameter is created during creation process of the instance object, otherwise only the getter/setter method is created (and the parameter does not exist). The getter/setter method has the same name as the parameter. It gets and returns the parameter, if no argument is specified. With one argument, the parameter is set to the argument value.
      Example:
          Class Car -parameter {{doors 4} color}
          Car herby -doors 2 -color green 
      Return: empty string
    • parameterclass class
      Arguments: class: parameter class name
      Description: Set the parameter class. The parameter class specifies how parameters are stored and maintained internally. Per default, a method "default" is called, to set the parameter with a default value. I.e.,
          Class Car -parameter {
            {doors 4}
          }
      is a short form for
          Class Car -parameter {
            {doors -default 4}
          }
      For specialized parameter classes other methods can be called, e.g.
         {doors -default 3 -updateWidget car}
      Return: empty string
    • recreate obj ?args?
      Arguments: obj: obj to be recreated
      ?args?: arbitrary arguments
      Description: Methods called upon recreation of an object. Recreate is called, when an object/class is created, but a same-named object/class exists already. "recreate" is not called, when an object is trying to be recreated as a class or vice versa. In these cases, recreating is realized via destroy+create. The Methods "recreate" performs standard object initialization, per default. May be overloaded/-written. It calls another method cleanup which handles actual cleanup of the object during next. That means, if you overload recreate, in the pre-part the object still contains its old state, after next it is cleaned up.
      Return: obj name
    • superclass classList
      Arguments: classList: ?list of classes?
      Description: Specify super-classes for a class. "superclass" changes the list of superclasses dynamically to classList. The method returns the current value of superclass, when it is called without arguments.
      Return: if classList is not specified return superclass(es), otherwise empty
    • unknown ?args?
      Arguments: ?args?: arbitrary arguments
      Description: Standard unknown mechanism. This mechanism is always triggered when XOTcl does not know a method called on an object. Supposed that there is no method with the called name, XOTcl looks up the method "unknown" (which is found on the Class Object) and executes it. The standard unknown-mechanism of XOTcl calls create with all arguments stepping one step to the right; in the general case:
          ClassName create ClassName ?args?
      Unknown can be overloaded in user-defined subclasses of class.
      Return: Standard unknown mechanism returns result of create

    Procs

    • __unknown name
      Arguments: name: name of class to be created
      Description: This method is called, whenever XOTcl references a class, which is not defined yet. In the following example: Class C -superclass D D is not defined. Therefore Class __unknown D is called. This callback can be used to perform auto-loading of classes. After this call, XOTcl tries again to resolve D. If it succeeds, XOTcl will continue; otherwise, an error is generated.

      This method is called on mixin/instmixin definition calls, istype, ismixin, class, superclass and parameterclass

      Return: empty string


    Class: Object

    Class: Class
    Procs/Instprocs: abstract, append, array, autoname, check, class, cleanup, configure, contains, copy, destroy, eval, exists, extractConfigureArg, filter, filterguard, filtersearch, forward, getExitHandler, hasclass, incr, info, instvar, invar, isclass, ismetaclass, ismixin, isobject, istype, lappend, mixin, move, noinit, parametercmd, proc, procsearch, requireNamespace, set, setExitHandler, subst, trace, unset, uplevel, upvar, volatile, vwait.
    Description: This class holds the pre-defined methods available for all XOTcl objects. All these methods are also available on classes.

    Instprocs

    • abstract methtype methodName arglist
      Arguments: methtype: instproc or proc
      methodName: name of abstract method
      arglist: arguments
      Description: Specify an abstract method for class/object with arguments. An abstract method specifies an interface and returns an error, if it is invoked directly. Subclasses or mixins have to override it.
      Return: error
    • append varName args
      Arguments: varName: name of variable
      args: arguments to append
      Description: Append all of the value arguments to the current value of variable varName. Wrapper to the same named Tcl command (see documentation of Tcl command with the same name for details).
      Return: empty string
    • array opt array ?args?
      Arguments: opt: array option
      array: array name
      ?args?: args of the option
      Description: This method performs one of several operations on the variable given by arrayName. It is a wrapper to the same named Tcl command (see documentation of Tcl command with the same name for details).
      Return: diverse results
    • autoname ?<-instance>|<-reset>? name
      Arguments: ?<-instance>|<-reset>?: Optional modifiers:
      '-instance' makes the autoname start with a small letter.
      '-reset' resets the autoname index to 0.
      name: base name of the autoname
      Description: autoname creates an automatically assigned name. It is constructed from the base name plus an index, that is incremented for each usage. E.g.:
          $obj autoname a
      produces a0, a1, a2, ... Autonames may have format strings as in the Tcl 'format' command. E.g.:
          $obj autoname a%06d
      produces a000000, a000001, a000002, ...
      Return: newly constructed autoname value
    • check options
      Arguments: options: none, one or more of: (?all? ?pre? ?post? ?invar? ?instinvar?)
      Description: Turn on/off assertion checking. Options argument is the list of assertions, that should be checked on the object automatically. Per default assertion checking is turned off.
      Examples:
          o check {};         # turn off assertion checking on object o  
          o check all;        # turn on all assertion checks on object o   
          o check {pre post}; # only check pre/post assertions
      
      Return: empty string
    • class newClass
      Arguments: newClass: ?new class?
      Description: Changes the class of an object dynamically to newClass. The method returns the current value of class, when it is called without arguments.
      Return: if newClass is not specified return class, otherwise empty
    • cleanup ?args?
      Arguments: ?args?: Arbitrary arguments passed to cleanup
      Description: Resets an object or class into an initial state, as after construction. Called during recreation process by the method 'recreate'
      Return: empty string
    • configure ?args?
      Arguments: ?args?: '-' method calls
      Description: Calls the '-' (dash) methods. I.e. evaluates arguments and calls everything starting with '-' (and not having a digit a second char) as a method. Every list element until the next '-' is interpreted as a method argument. configure is called before the constructor init during initialization and recreation. In the following example, the variable set is called via configure before init:
          Object o -set x 4
      The method configure can be called with the dash-notation at arbitrary times:
          o configure -set x 4
      Note that if '-' is followed by a numerical, the arument is interpreted as a negative number (and not as a method). If a value of a method called this way starts with a "-", the call can be placed safely into a list (e.g. "Class c [list -strangearg -a-] -simplearg 2").

      See also create.

      Return: number of the skipped first arguments
    • contains ?-withnew? ?-object? ?-class? cmd
      Arguments: ?-withnew?: Option to overload new to create new objects within the specified object. Per default, this option is turned on.
      ?-object?: object, in which the new objects should be created. The default is the object, for which contains>/tt> was called.
      ?-class?: In combination with option -object: If the specified object does not exist, create it from the specified class. The default is ::xotcl::Object
      cmd: Tcl command to create multiple objects
      Description: This method can be used to create nested object structures with little syntactic overhead. The method changes the namespace to the specified object and creates objects there. Optionally, a different object scope can be specified and creating new objects in the specified scope can be turned off. The following command creates a three rectangles, containing some points.
        Class Point -parameter {{x 100} {y 300}}
        Class Rectangle -parameter {color}
      
        Rectangle r0 -color pink -contains {
          Rectangle r1 -color red -contains {
            Point x1 -x 1 -y 2
            Point x2 -x 1 -y 2
          }
          Rectangle r2 -color green -contains {
            Point x1
            Point x2
          }
        }
      
      The resulting object structure looks like in the following example (simplified).
         ::r0
         ::r0::r1
         ::r0::r1::x1
         ::r0::r1::x2
         ::r0::r2
         ::r0::r2::x1
         ::r0::r2::x2
      
      Return: number of the skipped first arguments
    • copy newName
      Arguments: newName: destination of copy operation
      Description: Perform a deep copy of the object/class (with all information, like class, parameter, filter, ...) to "newName".
      Return: empty string
    • destroy ?args?
      Arguments: ?args?: Arbitrary arguments passed to the destructor
      Description: Standard destructor. Can be overloaded for customized destruction process. Actual destruction is done by instdestroy. "destroy" in principal does:
          Object instproc destroy args {
            [my info class] instdestroy [self]
          }
      Return: empty string
    • eval args
      Arguments: args: cmds to eval
      Description: Eval args in the scope of the object. That is local variables are directly accessible as Tcl vars.
      Return: result of cmds evaled
    • extractConfigureArg al name ?cutTheArg?
      Arguments: al: Argument List Name
      name: Name of the configure argument to be extracted (should start with '-')
      ?cutTheArg?: if cutTheArg not 0, it cut from upvar argsList, default is 0
      Description: Check an argument list separated with '-' args, as for instance configure arguments, and extract the argument's values. Optionally, cut the whole argument.
      Return: value list of the argument
    • exists var
      Arguments: var: variable name
      Description: Check for existence of the named instance variable on the object.
      Return: 1 if variable exists, 0 if not
    • filter ?args?
      Arguments: ?args?: filter specification
      Description: If $args is one argument, it specifies a list of filters to be set. Every filter must be an XOTcl proc/instproc within the object scope. If $args it has more argument, the first one specifies the action. Possible values are assign, get, add or delete, it modifies the current settings as indicated. For more details, check the tutorial.
      Return: if $args return empty current filters, otherwise empty
    • filterguard filterName guard
      Arguments: filterName: filter name of a registered filter
      guard: set of conditions to execute the filter
      Description: Add conditions to guard a filter registration point. The filter is only executed, if the guards are true. Otherwise we ignore the filter. If no guards are given, we always execute the filter.
      Return: an empty string
    • filtersearch methodName
      Arguments: methodName: filter method name
      Description: Search a full qualified method name that is currently registered as a filter. Return a list of the proc qualifier format: 'objName|className proc|instproc methodName'.
      Return: full qualified name, if filter is found, otherwise an empty string
    • forward methodName ?options? ?callee? ?args?
      Arguments: methodName: name of forwarder method
      ?options?: -objscope, -methodprefix string, -default names, -earlybinding, -verbose
      ?callee?: named of the called command or object
      ?args?: arguments
      Description: Register an object specific method (similar to a proc) for forwarding calls to a callee (target Tcl command, other object). When the forwarder method is called, the actual arguments of the invocation are appended to the specified arguments. In callee an arguments certain substitutions can take place:
      • %proc: substituted by name of the forwarder method
      • %self: substitute by name of the object
      • %1: substitute by first argument of the invocation
      • {%@POS value}: substitute the specified value in the argument list on position POS, where POS can be a positive or negative integer or end. Positive integers specify the position from the begin of the list, while negative integer specify the position from the end.
      • {%argclindex LIST}: take the nth argument of the specified list as substitution value, where n is the number of arguments from the invocation.
      • %%: a single percent.
      • %Tcl-command: command to be executed; substituted by result.
      Additionally each argument can be prefixed by the positional prefix %@POS (note the delimiting space at the end) that can be used to specify an explicit position. POS can be a positive or negative integer or the word end. The positional arguments are evaluated from left to right and should be used in ascending order. valid Options are:
      • -objscope causes the target to be evaluated in the scope of the object,
      • -methodprefix string inserts the specified prefix in front of the second argument of the invocation,
      • -default is used for default method names (only in connection with %1)
      • -earlybinding: look up the function pointer of the called Tcl command at definition time of the forwarder instead of invocation time. This option should only be used for calling C-implemented Tcl commands, no procs etc.);
      • -verbose
      • : print the substituted command to stderr before executing
      See tutorial for detailed examples.
      Return: empty
    • hasclass ?className?
      Arguments: ?className?: name of a class to be tested
      Description: Test whether the argument is either a mixin or instmixin of the object or if it is on the class hierarchy of the object. This method combines the functionalities of istype and ismixin.
      Return: 1 or 0
    • incr varName ?increment?
      Arguments: varName: variable name
      ?increment?: value to increment
      Description: Increments the value stored in the variable whose name is varName. The new value is stored as a decimal string in variable varName and also returned as result. Wrapper to the same named Tcl command (see documentation of Tcl command with the same name for details).
      Return: new value of varName
    • info args
      Arguments: args: info options
      Description: Introspection of objects. The following options can be specified:
    • objName info args method: Returns the arguments of the specified proc (object specific method).
    • objName info body method: Returns the body of the specified proc (object specific method).
    • objName info class: Returns the class of objName.
    • objName info children ?pattern?: Returns the list of aggregated objects with fully qualified names if pattern was not specified, otherwise it returns all children where the object name matches the pattern.
    • objName info commands ?pattern: Returns all commands defined for the object if pattern was not specified, otherwise it returns all commands that match the pattern.
    • objName info default method arg var: Returns 1 if the argument arg of the proc (object specific method) method has a default value, otherwise 0. If it exists the default value is stored in var.
    • objName info filter: Returns a list of filters. With -guard modifier all filterguards are integrated ( objName info filter -guards). With -order modifier the order of filters (whole hierarchy) is printed.
    • objName info filterguard name: Returns the guards for filter identified by name.
    • objName info forward ?-definition name? ?pattern?: Returns the list of forwarders. One can call this method either without the optional arguments, or with the pattern or with -definition name. When the pattern is specified only the matching forwarders are returned. When the definition option is used together with a name of a forwarder, the definition of the forwarder with all flags is returned in a way that can be used e.g. for registering the forwarder on another object.
    • objName info hasNamespace: From XOTcl version 0.9 on, namespaces of objects are allocated on demand. hasNamespace returns 1, if the object currently has a namespace, otherwise 0. The method requireNamespace can be used to ensure that the object has a namespace.
    • objName info info: Returns a list of all available info options on the object.
    • objName info invar: Returns object invariants.
    • objName info methods ?-nocmds? ?-nomixins? ?-incontext? ?pattern?: Returns the list of all methods currently reachable for objName. Includes procs, instprocs, cmds, instcommands on object, class hierarchy and mixins. Modifier -noprocs only returns instcommands, -nocmds only returns procs. Modifier -nomixins excludes search on mixins. When the modifier -incontext is used, it guards for conditional mixins are evaluated.
    • objName info mixin ?-order? ?-guard? ?pattern?: Returns the list of mixins of the object. With -order modifier the order of mixins (whole hierarchy) is printed. If -guard is specified, the mixin guards are returned. If pattern is specified and it contains wildcards, all matching mixins are returned. If pattern does not contain wildcards, either the fully qualified name is returned, or empty, if no match exists.
    • objName info nonposargs methodName: Returns non-positional arg list of methodName
    • objName info parametercmd ?pattern?: Returns a list of registered parametercmds the object (or empty if there are none). If pattern is specified, only the matching parametercmds are returned.
    • objName info parent: Returns parent object name (or "::" for no parent), in fully qualified form.
    • objName info post methodName: Returns post assertions of methodName.
    • objName info pre methodName: Returns pre assertions of methodName.
    • objName info procs ?pattern?: Returns all procs defined for the object if pattern was not specified, otherwise it returns all procs that match the pattern.
    • objName info precedence ?-intrinsic? ?pattern?: Returns all classes in the precedence order from which the specified object inherits methods. If the flag -intrinsic is specified only the intrinsic classes (from the class hierarchy) are specified. If the flag is not specified, the returned list of classes contains the mixin and instmixin classes as well as the classes of the superclass chain in linearized order (i.e., duplicate classes are removed). If the pattern is specified, only matching classes are returned.
    • objName info vars ?pattern?: Returns all variables defined for the object if pattern was not specified, otherwise it returns all variables that match the pattern.
    • Return: Value of introspected option as a string.
    • instvar v1 ?v2...vn?
      Arguments: v1: name of instance variable
      ?v2...vn?: optional other names for instance variables
      Description: Binds a variable of the object to the current method's scope. Example:
          kitchen proc enter {name} {
            my instvar persons
            set persons($name) [clock seconds]
          }
      Now persons can be accessed as a local variable of the method.
      A special syntax is: {varName aliasName} . This gives the variable with the name varName the alias aliasName. This way the variables can be linked to the methods scope, even if a variable with that name already exists in the scope.
      Return: empty string
    • invar invariantList
      Arguments: invariantList: Body of invariants for the object
      Description: Specify invariants for the objects. All assertions are a list of ordinary Tcl conditions.
      Return: empty string
    • isclass ?className?
      Arguments: ?className?: name of a class to be tested
      Description: Test whether the argument (or the Object, if no argument is specified) is an existing class or not.
      Return: 1 or 0
    • ismetaclass ?metaClassName?
      Arguments: ?metaClassName?: name of a metaclass to be tested
      Description: Test whether the argument (or the Object, if no argument is specified) is an existing metaclass or not.
      Return: 1 or 0
    • ismixin ?className?
      Arguments: ?className?: name of a class to be tested
      Description: Test whether the argument is a mixin or instmixin of the object.
      Return: 1 or 0
    • isobject objName
      Arguments: objName: string that should be tested, whether it is a name of an object or not
      Description: Test whether the argument is an existing object or not. Every XOTcl object has the capability to check the object system.
      Return: 1 or 0
    • istype className
      Arguments: className: type name
      Description: Test whether the argument is a type of the object. I.e., 1 is returned if className is either the class of the object or one of its superclasses.
      Return: 1 or 0
    • lappend varName args
      Arguments: varName: name of variable
      args: elements to append
      Description: Append all the specified arguments to the list specified by varName as separated elements (typically separated by blanks). If varName doesn't exist, it creates a list with the specified values (see documentation of Tcl command with the same name for details).
      Return: empty string
    • mixin ?args?
      Arguments: ?args?: mixin specification
      Description: If $args is one argument, it specifies a list of mixins to be set. Every mixin must be a defined class. If $args has more argument, the first one specifies the action. Possible values are assign, get, add or delete, it modifies the current settings as indicated. For more details, check the tutorial.
      Return: if $args empty return current mixins, otherwise empty
    • move newName
      Arguments: newName: destination of move operation
      Description: Perform a deep move of the object/class (with all information, like class, parameter, filter, ...) to "newName". Note that move is currently implemented as a copy plus subsequent destroy operation.
      Return: empty string
    • parametercmd name
      Arguments: name: variable to be provided with getter/setter method
      Description: Add a getter/setter for an instance variable with the specified name as a command for the obj. Example:
          Object o
          o parametercmd x
          o x 100
          puts [o x]
      Return: empty string
    • noinit
      Description: flag that constructor (method init) should not be called. Example:
          Class C
          C instproc init {} {puts hu}
          C c1 -noinit
      The object c1 will be created without calling the constructor. This can be used to draw a snapshot of an existing object (using the serializer) and to recreate it in some other context in its last state.
      Return: empty string
    • proc name ?non-pos-args? args body ?preAssertion? ?postAssertion?
      Arguments: name: method name
      ?non-pos-args?: optional non-positional arguments
      args: method arguments
      body: method body
      ?preAssertion?: optional assertions that must hold before the proc executes
      ?postAssertion?: optional assertions that must hold after the proc executes
      Description: Specify a method in the same style as Tcl specifies procs.
      Optionally assertions may be specified by two additional arguments. Therefore, to specify only post-assertions an empty pre-assertion list must be given. All assertions are a list of ordinary Tcl conditions.
      When instproc is called with an empty argument list and an empty body, the specified instproc is deleted.
      Return: empty string
    • procsearch procName
      Arguments: procName: simple proc name
      Description: Search which method should be invoked for an object and return the fully qualified name of the method as a list in proc qualifier format: 'objName|className proc|instproc|forward|instforward|parametercmd|instparametercmd|cmd|instcmd methodName'. The proc qualifier format reports the command used to create the method. The only exception is instcmd and cmd, which refer to commands implemented in C. E.g.,
          o procsearch set 
      returns
      ::xotcl::Object instcmd set
      .
      Return: fully qualified name of the searched method or empty string if not found
    • requireNamespace
      Description: The method requireNamespace can be used to ensure that the object has a namespace. Namespaces are created automatically by XOTcl, when e.g. an object has child objects (aggregated objects) or procs. The namespace will be used to keep instance variables, procs and child objects. To check, whether an object currently has a namespace, info hasNamespace can be used. Hint: In versions prior to XOTcl 0.9 all XOTcl objects had their own namespaces; it was made on demand to save memory when e.g. huge numbers of objects are created. requireNamespace is often needed when e.g. using Tk widgets when variables are to be referenced via the namespace (with ... -variable [self]::varName ...).
      Return: empty string
    • set varName ?value?
      Arguments: varName: name of the instance variable
      ?value?: optional new value
      Description: Set an instance variable in the same style as Tcl sets a variable. With one argument, we retrieve the current value, with two arguments, we set the instance variable to the new value.
      Return: Value of the instance variable
    • subst options string
      Arguments: options: ?-nobackslashes? ?-nocommands? ?-novariables?
      string: string to be substituted
      Description: Perform backslash, command, and variable substitutions in the scope of the given object (see documentation of Tcl command with the same name for details).
      Return: substituted string
    • trace varName
      Arguments: varName: name of variable
      Description: Trace an object variable (see documentation of Tcl command with the same name for details).
      Return: empty string
    • unset ?-nocomplain? v1 ?v2...vn?
      Arguments: ?-nocomplain?: possible error messages are suppressed
      v1: Variable to unset
      ?v2...vn?: Optional more vars to unset
      Description: The unset operation deletes one or optionally a set of variables from an object.
      Return: empty string
    • uplevel ?level? command ?args?
      Arguments: ?level?: Level
      command ?args?: command and arguments to be called
      Description: When this method is used without the optional level, it is a short form of the Tcl command
          uplevel [self callinglevel] command ?args?
      When it is called with the level, it is compatible with the original Tcl command.
      Return: result of the command
    • upvar ?level? otherVar localVar ?otherVar localVar?
      Arguments: ?level?: Level
      otherVar localVar: referenced variable and variable in the local scope
      ?otherVar localVar?: optional pairs of referenced and local variable names
      Description: When this method is used without the optional level, it is a short form of the Tcl command
          upvar [self callinglevel] otherVar localVar ?...?
      . When it is called with the level, it is compatible with the original Tcl command.
      Return: result of the command
    • vwait varName
      Arguments: varName: name of variable
      Description: Enter event loop until the specified variable is set (see documentation of Tcl command with the same name for details).
      Return: empty string
    • volatile
      Arguments: :
      Description: This method is used to specify that the object should be deleted automatically, when the current Tcl-proc/object-proc/instproc is left. Example:
          set x [Object new -volatile]
      Return: empty string

    Procs

    • getExitHandler
      Description: Retrieve the current exit handler procedure body as a string.
      Return: exit handler proc body
    • setExitHandler body
      Arguments: body: procedure body
      Description: Set body for the exit handler procedure. The exit handler is executed when XOTcl is existed or aborted. Can be used to call cleanups that are not associated with objects (otherwise use destructor). On exit the object destructors are called after the user-defined exit-handler.
      Return: exit handler proc body



    Back to index page.

    ./nsf2.4.0/doc/nxwish.man000644 000766 000024 00000002535 13723231507 015762 0ustar00neumannstaff000000 000000 [comment {-*- Tcl -*- nxwish manpage}] [include version.inc] [manpage_begin nxwish 1 [vset VERSION]] [copyright {2014-16 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3.0 Austria license (CC BY 3.0 AT).}] [titledesc {Simple windowing shell containing NSF/NX interpreter}] [moddesc {Command-line interface}] [description] [list_begin definitions] [call [syscmd "nxwish"] [opt [arg fileName]]] [syscmd "nxwish"] is a shell-like application including Tcl and the NX extension as well as the Tk toolkit. [syscmd "nxwish"] creates a main window and, then, reads commands from its standard input or from [arg fileName] and evaluates them. If invoked without [arg fileName], then it runs in REPL mode, reading commands from standard input. [syscmd "nxwish"] will continue processing commands until all windows have been deleted or until end-of-file is reached on standard input. [para] [syscmd "nxwish"] can be used like [syscmd "wish"] to make NX scripts directly invocable from the shell, by providing the following first line ("shebang") in the respective script: [example { #! /usr/bin/env nxwish }] A (more portable) alternative is: [example_begin] #! /bin/sh # the next line restarts using nxwish \ exec nxwish "$0" "$@" [example_end] [list_end] [manpage_end] ./nsf2.4.0/doc/adapterExample-xotcl.html000644 000766 000024 00000002300 12161565464 020713 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/scripts/adapterExample.xotcl

    ./apps/scripts/adapterExample.xotcl ./apps/scripts/adapterExample.xotcl


    Package/File Information

    No package provided/required

    Filename: ./apps/scripts/adapterExample.xotcl

    Description: Simple adapter pattern example class (FTP requests) taken from the paper 'Filters as a Language Support for Design Patterns in Object-Oriented Scripting Languages'.



    Back to index page.

    ./nsf2.4.0/doc/Announce2.4.0000644 000766 000024 00000006243 14276140336 016023 0ustar00neumannstaff000000 000000 Dear Community, We are pleased to announce the availability of the Next Scripting Framework (NSF) 2.4.0. The changes are mostly perfective improvements in terms of bug fixes, Tcl version compatibility, and API consistency. See below for the details. Diff stats since 2.3.0: 182 files changed, 26862 insertions(+), 20338 deletions(-) Major changes relative to 2.3.0 are: NSF now compiles and runs with Tcl 9 (core.tcl-lang.org/tcl main branch at the time of writing, August 2022). This way, NSF/NX/XOTcl can be used with the Tcl 8.5.* series, Tcl 8.6.*, and Tcl 8.7.* and Tcl 9.* on Linux/Windows/macOS. One can see the results of the compilations and test runs on https://github.com/nm-wu/nsf/actions https://ci.appveyor.com/project/mrcalvin/nsf-2ylk0/history Selected changes worth mentioning: - Maintenance & bug fixes: * Tcl 9: For the first time, NSF now compiles and its test suite completes with Tcl 9. Kudos to Jan Njitmans. * Tcl 8.7: o Support for the Tcl 8.7a5 release (core.tcl-lang.org/tcl branch "core-8-branch"). NSF compiles and its regression tests execute successfully (including TCL_NO_DEPRECATE). o NSF is now TIP-538 ready (Tcl starting relying on libtommath as an extrinsic dependency). * Fixed type name abbreviation bug: Previous versions did not handle cases correctly where an application type name starts with the same character sequence as a built-in type. So it was not possible to define a type "object_id", since a a spec of the form "x:object_id" was interpreted as "x:object" ("object" is a predefined type). Now, such type name abbreviations are not allowed. * Plugged a small memory leak when using mp_int (libtommath) data internally. * Fixed a crash when using volatile combined with method "configure" in XOTcl 2. * Fixed crashes due to internal cache mismanagement of flag names processed by configure/ cget. See https://groups.google.com/g/comp.lang.tcl/c/F9cn_Ah4js4/m/eL22xbQaCgAJ * Fixed exit from non-threaded NSF builds (will not hang anymore). * Added a warning when a slot name hints a typing error. - Build environments, automated builds: * Made "Makefile" more robust in light of file paths containing whitespace characters * Due to Travis becoming unavailable, we moved to GitHub Actions for automated builds on Linux and macOS. Windows builds are still served by AppVeyor. - XOTcl: * "dict" is now available as a per-object method, similar to "array". - MongoDB: * Tested the NSF MongoDB binding against latest stable releases of MongoDB (5.0.9) and MongoDB-C driver (1.22.1). * Fixed test case for gridfs and file renaming - Documentation: * Improved wording and corrected spelling in man pages, tutorials, and examples. The detailed changelog is available at https://next-scripting.org/xowiki/download/file/ChangeLog-2.3.0-2.4.0.log The Next Scripting Framework 2.4.0 (containing NX 2.4.0 and XOTcl 2.4.0) can be obtained from https://next-scripting.org/. Please report issues and wishes by opening a ticket at https://sourceforge.net/p/next-scripting/tickets/. Best regards - Gustaf Neumann - Stefan Sobernig./nsf2.4.0/doc/current.html000644 000766 000024 00000013367 12422512320 016310 0ustar00neumannstaff000000 000000 nx::current -

    nx::current(3) 2.0 current ""

    Name

    nx::current - Return information about the method callstack

    Description

    current ?option?

    This introspection command provides information about various details, to be identified using option, on the callstack. The command is invoked from a method body. If option is not provided, nx::current will default to option object (see below). nx::current operates on the Tcl callstack and is aware of NX-specific callstack and stackframe details. option can be any of the following:

    • activelevel returns the actual callstack level which calls into the currently executing method directly. This activelevel might correspond the callinglevel, but this is not necessarily the case. The activelevel also includes intermediate calls, such as nx::next invocations. The level is reported as an absolute level number (# followed by a digit) to be directly used as the first argument to uplevel or upvar.

    • args returns the list of argument values passed into the currently executing method implementation.

    • calledclass returns the name of the class that provides the method implementation to which the intercepted method call is to be redirected (only available from within filter methods).

    • calledmethod returns the original method name requested by intercepted method call (only available from within filter methods).

    • callingclass returns the name of the class which provides the method implementation calling into the currently executing method. See also callingobject.

    • callinglevel resolves the callstack level of the originating invocation of the currently executing method implementation. Callstack levels introduced by method interception (e.g., filters) and by method combination (nx::next) are ignored. The level is reported as an absolute level number (# followed by a digit) to be directly used as the first argument to uplevel or upvar. See also activelevel.

    • callingobject returns the name of the object which is calling into the currently executing method. See also callingclass.

    • class returns the name of the class providing the currently executing method implementation. The returned method-providing class may be different to the class of the current object. If called from within a method implementation provided by the current object itself, an empty string is returned.

    • filterreg returns the object (class) on which the currently executing method was registered as a filter method (only available from within filter methods).

    • isnextcall will return 1, if the currently executing method implementation was invoked via nx::next; 0 otherwise.

    • method returns the name of the currently executing method. If an ensemble-method call, the name of the bottom-most ("leaf") method is returned.

    • methodpath returns the combined name of the currently executing method (including all ensemble levels) in an ensemble-method call. Otherwise, for a regular method call, the result corresponds to the result of option method.

    • nextmethod returns the name of the next most specific method implementation to be called when invoking nx::next.

    • object gives the name of the object on which the currently executing method implementation is evaluated.

    ./nsf2.4.0/doc/filter.man.inc000644 000766 000024 00000007500 12501766547 016506 0ustar00neumannstaff000000 000000 [comment {-*- tcl -*- manpage fragment for filter method, shared by nx::Object and nx::Class}] [keywords "method filter"] [call [arg [vset CMD]] [const [vset MODIFIER]] [method filters] [arg submethod] [opt "[arg arg] ..."]] Accesses and modifies the list of methods which are registered as [term "filter"]s with [arg [vset CMD]] using a specific setter or getter [arg submethod]: [list_begin definitions] [def "[arg [vset CMD]] [const [vset MODIFIER]] [method {filters add}] [arg spec] [opt [arg index]]"] Inserts a single [term "filter"] into the current list of [term "filter"]s of [arg [vset CMD]]. Using [arg index], a position in the existing list of [term "filter"]s for inserting the new [term "filter"] can be set. If omitted, [arg index] defaults to the list head (0). [def "[arg [vset CMD]] [const [vset MODIFIER]] [method {filters clear}]"] Removes all [term "filter"]s from [arg [vset CMD]] and returns the list of removed [term "filter"]s. Clearing is equivalent to passing an empty list for [arg filterSpecList] to [const [vset SCOPE]] [method {filter set}]. [def "[arg [vset CMD]] [const [vset MODIFIER]] [method {filters delete}] [opt [option -nocomplain]] [arg specPattern]"] Removes a single [term "filter"] from the current list of [term "filter"]s of [arg [vset CMD]] whose spec matches [arg specPattern]. [arg specPattern] can contain special matching chars (see [cmd "string match"]). [const [vset SCOPE]] [method "filters delete"] will throw an error if there is no matching [term "filter"], unless [option -nocomplain] is set. [def "[arg [vset CMD]] [const [vset MODIFIER]] [method {filters get}]"] Returns the list of current [term "filter specification"]s registered for [arg [vset CMD]]. [def "[arg [vset CMD]] [const [vset MODIFIER]] [method {filters guard}] [arg methodName] [opt [arg expr]]"] If [arg expr] is specified, registers a guard expression [arg expr] with a filter [arg methodName]. This requires that the filter [arg methodName] has been previously set using [const [vset MODIFIER]] [method {filters set}] or added using [const [vset MODIFIER]] [method {filters add}]. [arg expr] must be a valid Tcl expression (see [cmd expr]). An empty string for [arg expr] will clear the currently registered guard expression for filter [arg methodName]. [para] If [arg expr] is omitted, returns the guard expression set on the [term "filter"] [arg methodName] defined for [arg [vset CMD]]. If none is available, an empty string will be returned. [def "[arg [vset CMD]] [const [vset MODIFIER]] [method "filters methods"] [opt [arg pattern]]"] If [arg pattern] is omitted, returns all filter names which are defined by [arg [vset CMD]]. By specifying [arg pattern], the returned filters can be limited to those whose names match [arg patterns] (see [cmd "string match"]). [def "[arg [vset CMD]] [const [vset MODIFIER]] [method {filters set}] [arg filterSpecList]"] [arg filterSpecList] takes a list of [term "filter"] specs, with each spec being itself either a one-element or a two-element list: [arg methodName] ?-guard [arg guardExpr]?. [arg methodName] identifies an existing method of [arg [vset CMD]] which becomes registered as a filter. If having three elements, the third element [arg guardExpr] will be stored as a guard expression of the [term "filter"]. This guard expression must be a valid Tcl expression (see [cmd expr]). [arg expr] is evaluated when [arg [vset CMD]] receives a message to determine whether the filter should intercept the message. Guard expressions allow for realizing context-dependent or conditional filter composition. [list_end] Every [arg methodName] in a [arg spec] must resolve to an existing method in the scope of the [vset SCOPE]. To access and to manipulate the list of [term "filter"]s of [arg [vset CMD]], [method cget]|[method configure] [option -[join [list {*}[vset MODIFIER] filters] -]] can also be used. ./nsf2.4.0/doc/parameter-xotcl.html000644 000766 000024 00000001522 12161565464 017744 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/scripts/parameter.xotcl

    ./apps/scripts/parameter.xotcl ./apps/scripts/parameter.xotcl


    Package/File Information

    No package provided/required

    Filename: ./apps/scripts/parameter.xotcl




    Back to index page.

    ./nsf2.4.0/doc/Announce2.0b3000644 000766 000024 00000004606 14274464600 016110 0ustar00neumannstaff000000 000000 Dear Community, We are pleased to announce the availability of the Next Scripting Framework 2.0b3 which can be obtained from http://next-scripting.org Best regards - Gustaf Neumann - Stefan Sobernig =============================================== Announcing NSF 2.0b3 ************************* Major changes relative to NSF 2.0b2 are: * Additional Features: - object parameters: call method "assign" on slot objects, when it is provided - include "-returns" in introspection for aliases and scripted methods. New subcommand "info method returns" for nx. - better compatibility with XOTcl 1.*: * invocation of objects via method interface follows per default the XOTcl 1.* conventions. In order to obtain the semantics of ensemble objects, the object properties "keepcallerself" and "perobjectdispatch" have to be used. * better handling of XOTcl 1.* configure commands (starting with a "-") when list property is lost (Many thanks to Zoran Vasjljevic for the good example) * use different version numbers in serializer to avoid mixups between XOTcl 1 and XOTcl 2 when both packages are installed * Improved Code Quality: - improved performance * rewrite of alias handling (alias reform) * improved branch prediction * significant speedup for handling large numbers of subclasses (subclass reform), avoid repetitious computations * significant speedup on mass-destroy (e.g. on thread exit) - provide better protection for deletion/overwriting of base classes - fixed potential duplicates on diamond inheritance - fixed unknown handling for "-local" and "-system" dispatches - improved compatibility for windows compilations (c89, __WIN32__) - fixed potential crashes * during method caching * error messages * implicit deletions - follow Tcl convention on error messages (start always with lowercase) - better handling of multiple errors in a single command. - return GMT dates in Httpd as RFCs require * Improved documentation - fixed typos, improve wordings * Extended regression tests MORE INFO General and more detailed information about the Next Scripting Framework and its components can be found at http://next-scripting.org ./nsf2.4.0/doc/mixinStrategy-xotcl.html000644 000766 000024 00000014527 13317121442 020630 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/lib/mixinStrategy.xotcl

    ./library/lib/mixinStrategy.xotcl ./library/lib/mixinStrategy.xotcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./library/lib/mixinStrategy.xotcl

    Description: These methods provide support for managing "strategies", i.e. mixin-classes, where only one kind of a family of conformant mixins should be registered.

    Naming conversions for strategies: All strategies must follow the naming convention 'kind=implementation'. Examples are the persistency strategy 'eager' specified as 'persistent=eager' or the persistency strategy 'lazy' (specified as 'persistent=lazy')



    Class: Object

    Procs/Instprocs: add, mixinQueryStrategy, mixinStrategy, remove.

    Instprocs

    • mixinStrategy strategy
      Arguments: strategy: Strategy to be added
      Description: This method adds or replaces a new strategy from the mixin list. Strategies are named following the convention mentioned above.
      Return: old strategy
    • mixinQueryStrategy kind
      Arguments: kind: strategy kind
      Description: This method searches the mixin list for a mixin of this kind (starting with $kind=)
      Return: returns the matching strategy
    • add construct args
      Arguments: construct: (inst) 'filter' or 'mixin'
      args: to be added
      Description: add the specified (inst) 'filters' or 'mixins'
      Return: empty
    • remove construct args
      Arguments: construct: (inst) 'filter' or 'mixin'
      args: to be removed
      Description: remove the specified (inst) 'filters' or 'mixins'
      Return: empty



    Back to index page.

    ./nsf2.4.0/doc/secure-webclient-xotcl.html000644 000766 000024 00000002217 12161565464 021226 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/comm/secure-webclient.xotcl

    ./apps/comm/secure-webclient.xotcl ./apps/comm/secure-webclient.xotcl


    Package/File Information

    No package provided/required

    Filename: ./apps/comm/secure-webclient.xotcl

    Description: A sample secure web client that queries an secure web-server. It needs to be adopted with different https URLs for testing...



    Back to index page.

    ./nsf2.4.0/doc/package-xotcl.html000644 000766 000024 00000006635 12161565463 017370 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/lib/package.xotcl

    ./library/lib/package.xotcl ./library/lib/package.xotcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./library/lib/package.xotcl

    Description: Represent Tcl package loading command by an XOTcl object. Enables tracking, tracing, and verbose output of package loading


    Object: package

    Class: Object
    Procs present, verbose.
    Description: Supports all Tcl package options plus present and verbose.

    Procs

    • present args
      Arguments: args: packageName or -exact packageName
      Description: Check whether a package is present or not. Similar to Tcl's package present, but works with Tcl < 8.3
    • verbose v
      Arguments: v: 1 or 0
      Description: Toggle verbose output on/off. If on, package prints the locations from where packages are loaded to the screen. Default is off.



    Back to index page.

    ./nsf2.4.0/doc/next.3000644 000766 000024 00000020610 14274463622 015010 0ustar00neumannstaff000000 000000 '\" '\" Generated from file 'next\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2014-16 Stefan Sobernig , Gustaf Neumann '\" .TH "nx::next" 3 2\&.4\&.0 next "NX API" .\" The -*- nroff -*- definitions below are for supplemental macros used .\" in Tcl/Tk manual entries. .\" .\" .AP type name in/out ?indent? .\" Start paragraph describing an argument to a library procedure. .\" type is type of argument (int, etc.), in/out is either "in", "out", .\" or "in/out" to describe whether procedure reads or modifies arg, .\" and indent is equivalent to second arg of .IP (shouldn't ever be .\" needed; use .AS below instead) .\" .\" .AS ?type? ?name? .\" Give maximum sizes of arguments for setting tab stops. Type and .\" name are examples of largest possible arguments that will be passed .\" to .AP later. If args are omitted, default tab stops are used. .\" .\" .BS .\" Start box enclosure. From here until next .BE, everything will be .\" enclosed in one large box. .\" .\" .BE .\" End of box enclosure. .\" .\" .CS .\" Begin code excerpt. .\" .\" .CE .\" End code excerpt. .\" .\" .VS ?version? ?br? .\" Begin vertical sidebar, for use in marking newly-changed parts .\" of man pages. The first argument is ignored and used for recording .\" the version when the .VS was added, so that the sidebars can be .\" found and removed when they reach a certain age. If another argument .\" is present, then a line break is forced before starting the sidebar. .\" .\" .VE .\" End of vertical sidebar. .\" .\" .DS .\" Begin an indented unfilled display. .\" .\" .DE .\" End of indented unfilled display. .\" .\" .SO ?manpage? .\" Start of list of standard options for a Tk widget. The manpage .\" argument defines where to look up the standard options; if .\" omitted, defaults to "options". The options follow on successive .\" lines, in three columns separated by tabs. .\" .\" .SE .\" End of list of standard options for a Tk widget. .\" .\" .OP cmdName dbName dbClass .\" Start of description of a specific option. cmdName gives the .\" option's name as specified in the class command, dbName gives .\" the option's name in the option database, and dbClass gives .\" the option's class in the option database. .\" .\" .UL arg1 arg2 .\" Print arg1 underlined, then print arg2 normally. .\" .\" .QW arg1 ?arg2? .\" Print arg1 in quotes, then arg2 normally (for trailing punctuation). .\" .\" .PQ arg1 ?arg2? .\" Print an open parenthesis, arg1 in quotes, then arg2 normally .\" (for trailing punctuation) and then a closing parenthesis. .\" .\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b .\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out .\" # BS - start boxed text .\" # ^y = starting y location .\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. .\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. .\" # VS - start vertical sidebar .\" # ^Y = starting y location .\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. .\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. .\" # Special macro to handle page bottom: finish off current .\" # box/sidebar if in box/sidebar mode, then invoked standard .\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. .\" # DS - begin display .de DS .RS .nf .sp .. .\" # DE - end display .de DE .fi .RE .sp .. .\" # SO - start of list of standard options .de SO 'ie '\\$1'' .ds So \\fBoptions\\fR 'el .ds So \\fB\\$1\\fR .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. .\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\*(So manual entry for details on the standard options. .. .\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. .\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. .\" # CE - end code excerpt .de CE .fi .RE .. .\" # UL - underline word .de UL \\$1\l'|0\(ul'\\$2 .. .\" # QW - apply quotation marks to word .de QW .ie '\\*(lq'"' ``\\$1''\\$2 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\$2 .. .\" # PQ - apply parens and quotation marks to word .de PQ .ie '\\*(lq'"' (``\\$1''\\$2)\\$3 .\"" fix emacs highlighting .el (\\*(lq\\$1\\*(rq\\$2)\\$3 .. .\" # QR - quoted range .de QR .ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3 .. .\" # MT - "empty" string .de MT .QW "" .. .BS .SH NAME nx::next \- Skip to the next most specific method implementation .SH SYNOPSIS \fBnext\fR ?\fIarguments\fR? .sp .BE .SH DESCRIPTION .TP \fBnext\fR ?\fIarguments\fR? This command is invoked inside a method body to call the next most specific method implementation in the list of available methods\&. This list of available methods is specific to the current method-call context\&. This context is set by the usage context of \fBnx::next\fR (method combination vs\&. method-call interception; see below)\&. The optional \fIarguments\fR are the argument values to be passed into the next most specific method implementation\&. If omitted, the arguments of the current method call are automatically forwarded\&. To call the next most specific method implementation without arguments (or to suppress argument forwarding), \fIarguments\fR must be set to an empty string\&. To pass an empty string as a (single) argument value, protect it as a list\&. The result of a call to \fBnx::next\fR is the result of the next most specific method implementation\&. If there are no more further applicable methods, the result of \fBnx::next\fR will depend on its usage context: method combination or method-call interception\&. If \fBnx::next\fR is used in a method body for method combination, the result will be an empty string\&. If \fBnx::next\fR is used in the body of a filter method for method-call interception, the result will be an error\&. .sp When executing a method call, the NX dispatch mechanism computes a list of applicable method implementations for the method name requested from a given object receiving the call; in support of method combination and method-call interception\&. .sp For \fImethod combination\fR, the computed list contains any object-local method implementation and any method implementations inherited by the object from the classes in its precedence list\&. Examples are overloading method implementations in the class hierarchy of the object, as well as from mixin classes of the object\&. For \fImethod-call interception\fR, the computed list contains the applicable filter methods, again ordered by their definition order according to the precedence list of the called object\&. .sp To retrieve the next most specific method implementation to be invoked by \fBnx::current\fR from the internally computed list, if any, use \fBnx::current\fR\&. .PP .SH COPYRIGHT .nf Copyright (c) 2014-16 Stefan Sobernig , Gustaf Neumann .fi ./nsf2.4.0/doc/Announce2.0b5000644 000766 000024 00000022471 13317120773 016107 0ustar00neumannstaff000000 000000 Dear Community, Since releasing the Next Scripting Framework (NSF) 2.0b3, we have received feedback from early adopters. Many thanks for the helpful and the constructive comments! This feedback triggered an internal discussion and led to revising some earlier design decisions and naming conventions, especially in NX. The new naming conventions improve the orthogonality and the clarity of NX programs. Since the release of 2.0b3, there have been more than 250 commits to our code repository. The implementation is very stable and has been used for more than two years in production of our large-scale, multi-threaded web environment inside NaviServer. Most of the changes happened in NX and, therefore, on the NSF scripting level, without the need to modify the NSF C layer. The implementation of XOTcl 2 has changed very little. The Next Scripting Framework was tested with Tcl 8.5.14 and Tcl 8.6.0 on Linux, macOS, and in windows environments (MinGW, VC11). This beta-release is supposed to be the last release before the final 2.0 is out, which should be soon. Below are the most notable differences in 2.0b5 as compared to 2.0b3: a) NX 2.0b3 used the following conventions to define methods for instances, object-specific methods and class-object specific methods: /cls/ method foo {args} {...} /obj/ method bar {args} {...} /cls/ class method baz {args} {...} Introspection was possible via (in the same order): /cls/ info methods /obj/ info methods /cls/ class info methods The problem with this convention is that e.g. "info methods" operates on different method records, depending on whether it is called on a class or on an object. This breaks a basic inheritance contract with the programmer: As nx::Class is a specialization of the most general class nx::Object, the same introspection operation (e.g., "info methods") should return e.g. object-specific methods for both class objects and ordinary, non-class objects. Therefore, we adopted the following more orthogonal conventions to define methods for instances and for object-specific methods /cls/ method foo {args} {...} /obj/ object method bar {args} {...} Introspection: /cls/ info methods /obj/ info object methods Note that we can now use the same mechanism to define or query object-specific methods on objects and classes. The same applies for aliases, forwards, mixins, and filters. The new convention imposes a little typing burden for the code writer, but reduces the potential ambiguity for the code reader, who is trying to understand what exactly "$x method FOO {args} {...}" means. For convenience, we provide two packages "nx::plain-object-method" and "nx::class-method" to switch to the old conventions. A verbose tracing mode can report usages to ease migration. b) Parametrization: NX 2.0b3 followed the XOTcl conventions of registering by default same-named getter/setter methods for configuration parameters used in object creation. These getter/setter methods bloat the method interface and risk shadowing inherited methods, leading to unexpected behaviors for beginners. NX 2.0b5 adopts a Tk/itcl/... idiom by offering a cget/configure interface to objects as generic getters/setters. To obtain parameter-specific getters/setters (i.e., the old behavior), the flag "-accessor public|protected|private" can be set when defining properties and variables. c) Further clean-ups of the introspection interface ("info"). In order to streamline the interface further, we followed the idea to use "... info /plural word/" to obtain a set of handles, and then to make a separate call to retrieve the details. Therefore, we now provide ... /cls/ info methods /obj/ info object methods /cls/ info variables /obj/ info object variables /cls/ info slots /obj/ info object slots /cls/ info method parameters /methodName/ /obj/ info object method parameters /methodName/ /cls/ info configure parameters /obj/ info lookup configure parameters ... to return a list of handles. The result list can be filtered in each case by specifying a match pattern. Each result handle can then be used in a separate call to obtain details: /obj/ info method definition /methodHandle/ /obj/ info variable definition /varHandle/ /obj/ info parameter name /paramHandle/ These are just a few examples. In NX 2.0b3, we had e.g. "... info parameter definitions ..." leaving a beginner in the dark about the parameters actually meant. Also, the introspection interface made mixed use of plural and singular wordings for different purposes (e.g., retrieving collections and/or detailed information on one item). Below is a more detailed summary of the changes. The Next Scripting Framework 2.0b5 (containing NX and XOTcl 2.0b5) can be obtained from http://next-scripting.org/ Best regards - Gustaf Neumann - Stefan Sobernig =============================================== Announcing NSF 2.0b5 ************************* Major changes relative to NSF 2.0b3 are (in addition of the items (a), (b), and (c) above) are: * Additional Features: - Serializer: * Added flag -objmap to Serializer method deepSerialize to make serializer to provide mapping only for object names. This makes the serializer usable for object/class copying (-map is too coarse) * Made "ignore" method public * Due to the split between serializer and object system serializer, the "ignore" settings were lost - Allow explicit unsetting of -per-object flag in 0-argument "-flag=value" notation (all built-in commands accepting this flag) - Better compatibility with XOTcl 1.*: - Added "/obj/ info name" (as alternative to "namespace tail [self]") - Test-suite: added summary with statistics - Traits: added property/variable inheritance - MongoDB - Added "nx::mongo::db drop collection /name/" - Returning status from "nx::mongo::db remove" as success (0 or 1) - Adjust to object interface - Reduce verbosity - Add error messages for slot lookup failures Updated MongoDB interface - Upgraded to c-driver 0.7.1 - Zested with MongoDB 2.4.4-pre - New commands: * mongo::run * mongo::cursor::find * mongo::cursor::next * mongo::cursor::close - Adapted interface for c-driver 0.7.1 (e.g. new optional name for mongo::index) * Improved Code Quality: - Fixed functional bugs: * Copy did not copy aliases and ensemble methods * Automatic object destroy for half-baked objects (when e.g. configure raises an exception) * Handling of required configure parameters on later calls to "configure" * Fixed potential infinite loop in pattern matching for precedence lists * Handling of full-qualified name patterns for private slots * Invalidation of per-object parameter cache - on mixin changes and - on deletion/adding of per-object slots * Handle cyclical superclass/class dependencies during object system finalize * Fixed a bad interaction between Tcl's apply (pushing lambda frames) and the variable resolvers. The variable resolver was not able to resolve variables, while the command resolver was still working correctly. * Don't allow "method" to overwrite child objects - Fixed potential crashes: * Avoid crash on object destroy, when the same wrapper-less aliases was registered on more than one object/class * Fix crash on "nsf::my", when this is called with a single argument outside an object context (many thanks to Markus Moser for reporting) * Avoid crash in case NsfParameterGetCmd() is passed a plain value (without a parameter spec) * Fix potential crash in method caching when commands are renamed by Tcl (many thanks to Arthur Schreiber for reporting) - More code cleanup and refactoring - Released version runs all regression tests without memory leaks with Tcl 8.5.14 and Tcl 8.6.0 - Build system: * Improved compatibility for windows compilations. NX can now be compiled under windows with the native window tool chain (VC11) and as well with MinGW (Many thanks to Stephan Adelsberger) * Update to latest TEA * Follow new naming convention for auto-tools (using configure.ac) * Fix compilation when DTrace is activated (missing parenthesis, many thanks to Victor Guerra for noticing) * Added compile macro NSF_STACKCHECK to provide stack monitoring/debugging (especially useful for multi- threaded programs, where stack is more limited) - Fix compilation when compiled without threads (many thanks for r.Zaumseil for noting this) * Improved documentation - Fixed typos, improve wordings - Updated tutorial and migration guide - Use slashes in generated syntax to distinguish between constants and placeholders. Example: /obj/ info method definition /methodName/ * Extended regression tests MORE INFO General and more detailed information about the Next Scripting Framework and its components can be found at http://next-scripting.org ./nsf2.4.0/doc/htmllib-xotcl.html000644 000766 000024 00000002742 12161565463 017423 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/lib/htmllib.xotcl

    ./library/lib/htmllib.xotcl ./library/lib/htmllib.xotcl


    Package/File Information

    No package provided/required

    Filename: ./library/lib/htmllib.xotcl

    Description: This package provides the class HtmlBuilder, which can be used to generate HTML documents, or a part of a document.
    Authors: Antti Salonen, as@fishpool.fi
    Date: $Date: 2006/09/27 08:12:40 $



    Back to index page.

    ./nsf2.4.0/doc/upvarcompat-xotcl.html000644 000766 000024 00000002451 12161565463 020326 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/lib/upvarcompat.xotcl

    ./library/lib/upvarcompat.xotcl ./library/lib/upvarcompat.xotcl


    Package/File Information

    No package provided/required

    Filename: ./library/lib/upvarcompat.xotcl

    Description: Provide a version of upvar and uplevel that provide backward compatibility such that these commands ignore inactive filter and mixin frames (upvar behaves the same whether or not a filter is installed). Newer scripts should use upvar/uplevel [self callinglevel] var/command instead.



    Back to index page.

    ./nsf2.4.0/doc/metadataAnalyzer-xotcl.html000644 000766 000024 00000032001 13443231441 021233 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/lib/metadataAnalyzer.xotcl

    ./library/lib/metadataAnalyzer.xotcl ./library/lib/metadataAnalyzer.xotcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./library/lib/metadataAnalyzer.xotcl

    Description: XOTcl file analyzer for @ metadata. E.g.\ used for doumentation with xoDoc (but in the static variant StaticMetadataAnalyzer which uses the dynamic variant in this file).

    Sample sample usage:

    	    package require xotcl::metadataAnalyzer
    
    	    # instantiate metadata analyzer object
    	    MetadataAnalyzer @::m
    	    # make this object be known to @ and turn @ metadata processing on
    	    @ analyzerObj @::m
    	    @ onOff 1
    
    	    # read in some metadata tags (in sample file) & execute the file
    	    source lib/testx.xotcl
    
    	    # turn @ metadata processing off again
    	    @ onOff 0
    
    	    # print out all collected metadata
    	    puts [@::m print]
    	    


    Object: @

    Class: AnalyzerCmd
    Description: Recreate @ with metadata analysis functionality.


    Class: AnalyzerCmd

    Class: Class
    Description: Class that overload the unknown mechanism of @ to provide metadata analysis.


    Class: ClassToken

    Class: Class
    Heritage: ObjToken
    Description: Token for Class metadata. Contains additional parameters: "instprocList" = list of all instproc token.


    Class: ConstraintToken

    Class: Class
    Heritage: MetadataToken
    Description: Token for @Constraint Metadata.


    Class: FileToken

    Class: Class
    Heritage: MetadataToken
    Description: Token for @File Metadata.


    Class: InstprocToken

    Class: Class
    Heritage: MethodToken
    Description: Token for Instproc metadata.


    Class: MetaClassToken

    Class: Class
    Heritage: ClassToken
    Description: Token for Meta-Class metadata.


    Class: MetadataAnalyzer

    Class: Class
    Procs/Instprocs: print.
    Description: Handler class for building a metadata runtime structure

    Instprocs

    • print
      Description: Print all collected token information to stdout. This method is also an example how the tokens can be used.


    Class: MetadataToken

    Class: Class
    Procs/Instprocs: print, printProperties, sortTokenList.
    Description: Each collected metadata element is stored in a token object. MetadataToken is superclass of token object classes. Each metadata token has two interesting parameters:

    "properties" contains list of all described metadata properties. E.g. can be printed with

    	    foreach p [my set properties] { 
    		if {[my exists $p]} {
    		    append c "    $p=[my set $p]\n"
    		}
    	    }
    	    
    "name" contains the method, object, ... name of the metadata element.

    All metadata token are aggregated by @. Therefore,

    	    foreach mdt [@ info children] { 
    		if {[$mdt istype MetadataToken]} {$mdt print}
    	    }
    	    
    prints all token.

    Instprocs

    • printProperties
      Description: Print metadata properties to stdout.
    • abstract print
      Description: Abstract method for printing a token to stdout.

    Procs

    • sortTokenList l
      Arguments: l: token list
      Description: Sort a token list with names. Since names are autonames, this means order of appearance in the program.


    Class: MethodToken

    Class: Class
    Heritage: MetadataToken
    Description: Token for Method metadata. Contains additional parameters: "arguments" of the method, "returnValue" of the method, "obj" name, "abstract" = 0 or 1 (whether its an abstract method or not).


    Class: ObjToken

    Class: Class
    Heritage: MetadataToken
    Description: Token for Object metadata. Contains additional parameters: "procList" = list of all proc token and "cl"= class name.


    Class: PackageToken

    Class: Class
    Heritage: MetadataToken
    Description: Token for Package metadata. Contains additional parameters: "version" of the package and "type"= either "require" or "provide".


    Class: ProcToken

    Class: Class
    Heritage: MethodToken
    Description: Token for Proc metadata



    Back to index page.

    ./nsf2.4.0/doc/nxsh.1000644 000766 000024 00000017207 14274463622 015020 0ustar00neumannstaff000000 000000 '\" '\" Generated from file 'nxsh\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2014-16 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. '\" .TH "nxsh" 1 2\&.4\&.0 nxsh "Command-line interface" .\" The -*- nroff -*- definitions below are for supplemental macros used .\" in Tcl/Tk manual entries. .\" .\" .AP type name in/out ?indent? .\" Start paragraph describing an argument to a library procedure. .\" type is type of argument (int, etc.), in/out is either "in", "out", .\" or "in/out" to describe whether procedure reads or modifies arg, .\" and indent is equivalent to second arg of .IP (shouldn't ever be .\" needed; use .AS below instead) .\" .\" .AS ?type? ?name? .\" Give maximum sizes of arguments for setting tab stops. Type and .\" name are examples of largest possible arguments that will be passed .\" to .AP later. If args are omitted, default tab stops are used. .\" .\" .BS .\" Start box enclosure. From here until next .BE, everything will be .\" enclosed in one large box. .\" .\" .BE .\" End of box enclosure. .\" .\" .CS .\" Begin code excerpt. .\" .\" .CE .\" End code excerpt. .\" .\" .VS ?version? ?br? .\" Begin vertical sidebar, for use in marking newly-changed parts .\" of man pages. The first argument is ignored and used for recording .\" the version when the .VS was added, so that the sidebars can be .\" found and removed when they reach a certain age. If another argument .\" is present, then a line break is forced before starting the sidebar. .\" .\" .VE .\" End of vertical sidebar. .\" .\" .DS .\" Begin an indented unfilled display. .\" .\" .DE .\" End of indented unfilled display. .\" .\" .SO ?manpage? .\" Start of list of standard options for a Tk widget. The manpage .\" argument defines where to look up the standard options; if .\" omitted, defaults to "options". The options follow on successive .\" lines, in three columns separated by tabs. .\" .\" .SE .\" End of list of standard options for a Tk widget. .\" .\" .OP cmdName dbName dbClass .\" Start of description of a specific option. cmdName gives the .\" option's name as specified in the class command, dbName gives .\" the option's name in the option database, and dbClass gives .\" the option's class in the option database. .\" .\" .UL arg1 arg2 .\" Print arg1 underlined, then print arg2 normally. .\" .\" .QW arg1 ?arg2? .\" Print arg1 in quotes, then arg2 normally (for trailing punctuation). .\" .\" .PQ arg1 ?arg2? .\" Print an open parenthesis, arg1 in quotes, then arg2 normally .\" (for trailing punctuation) and then a closing parenthesis. .\" .\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b .\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out .\" # BS - start boxed text .\" # ^y = starting y location .\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. .\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. .\" # VS - start vertical sidebar .\" # ^Y = starting y location .\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. .\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. .\" # Special macro to handle page bottom: finish off current .\" # box/sidebar if in box/sidebar mode, then invoked standard .\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. .\" # DS - begin display .de DS .RS .nf .sp .. .\" # DE - end display .de DE .fi .RE .sp .. .\" # SO - start of list of standard options .de SO 'ie '\\$1'' .ds So \\fBoptions\\fR 'el .ds So \\fB\\$1\\fR .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. .\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\*(So manual entry for details on the standard options. .. .\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. .\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. .\" # CE - end code excerpt .de CE .fi .RE .. .\" # UL - underline word .de UL \\$1\l'|0\(ul'\\$2 .. .\" # QW - apply quotation marks to word .de QW .ie '\\*(lq'"' ``\\$1''\\$2 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\$2 .. .\" # PQ - apply parens and quotation marks to word .de PQ .ie '\\*(lq'"' (``\\$1''\\$2)\\$3 .\"" fix emacs highlighting .el (\\*(lq\\$1\\*(rq\\$2)\\$3 .. .\" # QR - quoted range .de QR .ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3 .. .\" # MT - "empty" string .de MT .QW "" .. .BS .SH NAME nxsh \- Simple shell containing NSF/NX interpreter .SH SYNOPSIS \fBnxsh\fR ?\fB-c\fR ?\fIarg1\fR?? ?\fIarg2\fR \&.\&.\&.? .sp .BE .SH DESCRIPTION .TP \fBnxsh\fR ?\fB-c\fR ?\fIarg1\fR?? ?\fIarg2\fR \&.\&.\&.? \fBnxsh\fR is a shell-like application that reads NX and Tcl commands from different sources and evaluates them\&. .sp If invoked without any arguments, \fBnxsh\fR runs in read-eval-print mode (REPL, interactive) similar to \fBtclsh\fR\&. In this mode, it reads commands from standard input interactively and prints command results as well as error messages to standard output\&. It remains active until the exit command is invoked or until it reaches end-of-file on its standard input\&. .sp If invoked with at least one positional argument \fIarg1\fR, \fBnxsh\fR runs a NX/Tcl script sourced from a file identified by \fIarg1\fR using \fBsource\fR\&. .sp Passing the \fB-c\fR flag makes \fBnxsh\fR accept commands from the command line provided by \fIarg1\fR\&. If \fIarg1\fR is omitted, \fBnxsh\fR takes commands from standard input (e\&.g\&., in a pipe)\&. .sp \fBnxsh\fR can be used like \fBtclsh\fR to make NX scripts directly invocable from the shell, by providing the following first line ("shebang") in the respective script: .CS #! /usr/bin/env nxsh .CE .IP A (more portable) alternative is: .CS #! /bin/sh # the next line restarts using nxsh \\ exec nxsh "$0" "$@" .CE .PP .SH COPYRIGHT .nf Copyright (c) 2014-16 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. .fi ./nsf2.4.0/doc/Announce2.0.0000644 000766 000024 00000011176 13317120773 016016 0ustar00neumannstaff000000 000000 Dear Community, Since releasing the Next Scripting Framework (NSF) 2.0b5, we have received more feedback from early adopters. Many thanks for the helpful and the constructive comments! Since the release of 2.0b5, there have been more than 450 commits to our code repository. The implementation is very stable and has been used for more than two years in production of our large-scale, multi-threaded web environment inside NaviServer. Most of the changes happened in NX and, therefore, on the NSF scripting level, without the need to modify the NSF C layer. The implementation of XOTcl 2 has changed very little. The Next Scripting Framework was tested with Tcl 8.5.17 and Tcl 8.6.2 on Linux, macOS, and in Windows environments (MinGW, VC12). Below are the most notable differences in NSF/NX 2.0 final relative to 2.0b5: a) Pluralism reform: Use plural names for structural features of objects and classes, whenever potentially multiple elements are provided or returned. This rule applies now consistently throughout NX. Here are examples from the introspection interface: /cls/ info superclasses /cls/ info subclasses /cls/ info mixins /obj/ info object mixins /cls/ info filters /obj/ info object filters Similarly, there the plural is used for configure options, e.g.: nx:create create Foo -superclasses {C D} Note that abbreviations are allowed as well: nx:create create Foo -superclass {C D} b) Dispatch by arity is gone in NX. XOTcl and earlier versions of NX supported a dispatch-by-arity mechanism for relation slots: o mixin; # arity 1: get value o mixin M1; # arity 2: set value o mixin add M1; # arity 3: use arg 2 for slot methods The problem with this approach is that it is not straight forward to provide meaningful error messages. In addition, one might be irritated about the result of e.g. "o mixin add" (leaving out a class to be added). In the final release, we removed the entailed complexity by relying on a fixed arity of 3 (last form above) for the default slot methods: add, clear, delete, get, guard, set c) Support for querying computed parameters of methods. Earlier versions of NX had several methods to query the parameters for configuring objects of different classes. The configure parameters are determined by the inheritance order in the class hierarchy and are relevant during object creation (e.g. methods "create" or "new"). Now, these configure parameter can be queried using the standard parameter introspection interface for e.g. "new", "create", or "configure", such as in: nx::Object info lookup parameters create The above command call returns the parameters which can be provided to an "nx::Object create ..." invocation. Furthermore, these computed parameters are returned in error messages. d) Support abbreviations of non-positional parameter names (for plain methods, nsf::proc, or "... configure..."). To avoid surprises, especially for computed argument lists, the minimal number of optional trailing characters is set to 4. e) Updated MongoDB interface: The interface was extended in various ways and is now based on mongo-c-driver 1.0.2 and was tested with MongoDB 2.6.5. The driver can be used nicely with e.g. Naviserver by using the c-driver supported connection pool. f) API changes: nx::Object info lookup parameters create /cls/ mixins ... /obj/ object mixins ... /cls/ filters ... /obj/ object filters ... Simplified info methods for interceptors: /cls/ info mixin classes -> /cls/ info mixins /cls/ info filter methods -> /cls/ info filters /obj/ info object mixin classes -> /obj/ info object mixins Dropped methods: /cls/ info mixin guard /obj/ info object mixin guard /cls/ info filter guard /obj/ info object filter guard Instead, use the "-guards" option of "... info ?object? mixins|filters ...". Added methods: /cls/ mixins classes /cls/ filters methods /obj/ object filters methods /obj/ object mixins classes g) Added API documentation: Using tcllib's doctools markup and dtplite, we now provide manpages for: nx::Object nx::Class nx::current nx::next nx::configure The Next Scripting Framework 2.0.0 (containing NX and XOTcl 2.0.0) can be obtained from https://next-scripting.org/ The detailed ChangeLog can be downloaded from https://next-scripting.org/xowiki/download/file/ChangeLog-2.0b5-2.0.0 Best regards - Gustaf Neumann - Stefan Sobernig ./nsf2.4.0/doc/testo-xotcl.html000644 000766 000024 00000004071 12161565464 017124 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./tests/testo.xotcl

    ./tests/testo.xotcl ./tests/testo.xotcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./tests/testo.xotcl

    Description: This is a class which provides regression test objects for the OTcl derived features of the XOTcl - Language. This script is based upon the test.tcl script of the OTcl distribution and adopted for XOTcl.


    Class: TestClass

    Class: Class
    Description: A meta-class for test objects.


    Class: TestSuite

    Class: Class



    Back to index page.

    ./nsf2.4.0/doc/nx.css000644 000766 000024 00000002674 14274463622 015117 0ustar00neumannstaff000000 000000 @media print { body {font-size: 10pt; text-align: justify;} #header {text-align: left;} .nx {font-size: 90%; color: #000000; font-weight: normal; font-style: normal; padding-left: 10px} table.nx {border-collapse: collapse; border-spacing: 3px;} .nx-linenr {font-size: 90%; border-right: 1px solid #DDDDDD;padding-right: 5px; color: #2B547D; font-style: italic;} .nx-string {color: #779977; font-weight: normal; font-style: italic;} .nx-comment {color: #717ab3; font-weight: normal; font-style: italic;} .nx-keyword {color: #7f0055; font-weight: normal; font-style: normal;} .nx-placeholder {color: #AF663F; font-weight: normal; font-style: italic;} .nx-variable {color: #AF663F; font-weight: normal; font-style: normal;} .listingblock {font-size: 80%;} div.toclevel1 {display: block;} div.toclevel2 {display: block;} div.toclevel3 {display: block;} div.toclevel4 {display: block;} div.tableblock table { page-break-inside: avoid; } div.listingblock pre { page-break-inside: avoid; } } @page { size: A4; /* DIV 15 for A4 paper */ margin: 19.80mm 14mm; /* Not supported by Chrome, kept for later reference */ @top-center { color: #717ab3;font-style: italic; font-size: 80%; content: string(chapter-title) } @bottom-center { font-size: 80%; color: #717ab3; content: "- " counter(page) " -" } } h2 { string-set: chapter-title content() } ./nsf2.4.0/doc/xowish.1000644 000766 000024 00000016342 14274463622 015360 0ustar00neumannstaff000000 000000 '\" '\" Generated from file 'xowish\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2014 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. '\" .TH "xowish" 1 2\&.4\&.0 xowish "Command-line interface" .\" The -*- nroff -*- definitions below are for supplemental macros used .\" in Tcl/Tk manual entries. .\" .\" .AP type name in/out ?indent? .\" Start paragraph describing an argument to a library procedure. .\" type is type of argument (int, etc.), in/out is either "in", "out", .\" or "in/out" to describe whether procedure reads or modifies arg, .\" and indent is equivalent to second arg of .IP (shouldn't ever be .\" needed; use .AS below instead) .\" .\" .AS ?type? ?name? .\" Give maximum sizes of arguments for setting tab stops. Type and .\" name are examples of largest possible arguments that will be passed .\" to .AP later. If args are omitted, default tab stops are used. .\" .\" .BS .\" Start box enclosure. From here until next .BE, everything will be .\" enclosed in one large box. .\" .\" .BE .\" End of box enclosure. .\" .\" .CS .\" Begin code excerpt. .\" .\" .CE .\" End code excerpt. .\" .\" .VS ?version? ?br? .\" Begin vertical sidebar, for use in marking newly-changed parts .\" of man pages. The first argument is ignored and used for recording .\" the version when the .VS was added, so that the sidebars can be .\" found and removed when they reach a certain age. If another argument .\" is present, then a line break is forced before starting the sidebar. .\" .\" .VE .\" End of vertical sidebar. .\" .\" .DS .\" Begin an indented unfilled display. .\" .\" .DE .\" End of indented unfilled display. .\" .\" .SO ?manpage? .\" Start of list of standard options for a Tk widget. The manpage .\" argument defines where to look up the standard options; if .\" omitted, defaults to "options". The options follow on successive .\" lines, in three columns separated by tabs. .\" .\" .SE .\" End of list of standard options for a Tk widget. .\" .\" .OP cmdName dbName dbClass .\" Start of description of a specific option. cmdName gives the .\" option's name as specified in the class command, dbName gives .\" the option's name in the option database, and dbClass gives .\" the option's class in the option database. .\" .\" .UL arg1 arg2 .\" Print arg1 underlined, then print arg2 normally. .\" .\" .QW arg1 ?arg2? .\" Print arg1 in quotes, then arg2 normally (for trailing punctuation). .\" .\" .PQ arg1 ?arg2? .\" Print an open parenthesis, arg1 in quotes, then arg2 normally .\" (for trailing punctuation) and then a closing parenthesis. .\" .\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b .\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out .\" # BS - start boxed text .\" # ^y = starting y location .\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. .\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. .\" # VS - start vertical sidebar .\" # ^Y = starting y location .\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. .\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. .\" # Special macro to handle page bottom: finish off current .\" # box/sidebar if in box/sidebar mode, then invoked standard .\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. .\" # DS - begin display .de DS .RS .nf .sp .. .\" # DE - end display .de DE .fi .RE .sp .. .\" # SO - start of list of standard options .de SO 'ie '\\$1'' .ds So \\fBoptions\\fR 'el .ds So \\fB\\$1\\fR .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. .\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\*(So manual entry for details on the standard options. .. .\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. .\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. .\" # CE - end code excerpt .de CE .fi .RE .. .\" # UL - underline word .de UL \\$1\l'|0\(ul'\\$2 .. .\" # QW - apply quotation marks to word .de QW .ie '\\*(lq'"' ``\\$1''\\$2 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\$2 .. .\" # PQ - apply parens and quotation marks to word .de PQ .ie '\\*(lq'"' (``\\$1''\\$2)\\$3 .\"" fix emacs highlighting .el (\\*(lq\\$1\\*(rq\\$2)\\$3 .. .\" # QR - quoted range .de QR .ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3 .. .\" # MT - "empty" string .de MT .QW "" .. .BS .SH NAME xowish \- Simple windowing shell containing NSF/XOTcl2 interpreter .SH SYNOPSIS \fBxowish\fR ?\fIfileName\fR? .sp .BE .SH DESCRIPTION .TP \fBxowish\fR ?\fIfileName\fR? \fBxowish\fR is a shell-like application including Tcl and the XOTcl2 as well as the Tk toolkit\&. \fBxowish\fR creates a main window and, then, reads commands from its standard input or from \fIfileName\fR and evaluates them\&. If invoked without \fIfileName\fR, then it runs in REPL mode, reading commands from standard input\&. \fBxowish\fR will continue processing commands until all windows have been deleted or until end-of-file is reached on standard input\&. .sp \fBxowish\fR can be used like \fBwish\fR to make XOTcl2 scripts directly invocable from the shell, by providing the following first line ("shebang") in the respective script: .CS #! /usr/bin/env xowish .CE .IP A (more portable) alternative is: .CS #! /bin/sh # the next line restarts using xowish \\ exec xowish "$0" "$@" .CE .PP .SH COPYRIGHT .nf Copyright (c) 2014 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. .fi ./nsf2.4.0/doc/next-migration.txt000644 000766 000024 00000240213 14274463622 017457 0ustar00neumannstaff000000 000000 Migration Guide for the Next Scripting Language =============================================== Gustaf Neumann v2.4.0, Aug 2022: :Author Initials: GN :toc: :toclevels: 3 :icons: :numbered: :website: http://www.xotcl.org/ .Abstract ***************************************************************************** This document describes the differences between the Next Scripting Language Framework and XOTcl 1. In particular, it presents a migration guide from XOTcl 1 to NX, and presents potential incompatibilities between XOTcl 1 and XOTcl 2. ***************************************************************************** The Next Scripting Language (NX) is a successor of XOTcl 1 and is based on 10 years of experience with XOTcl in projects containing several hundred thousand lines of code. While XOTcl was the first language designed to provide language support for design patterns, the focus of the Next Scripting Framework and NX are on combining this with Language Oriented Programming. In many respects, NX was designed to ease the learning of the language by novices (by using a more mainstream terminology, higher orthogonality of the methods, less predefined methods), to improve maintainability (remove sources of common errors) and to encourage developer to write better structured programs (to provide interfaces) especially for large projects, where many developers are involved. The Next Scripting Language is based on the Next Scripting Framework which was developed based on the notion of language oriented programming. The Next Scripting Frameworks provides C-level support for defining and hosting multiple object systems in a single Tcl interpreter. The whole definition of NX is fully scripted (e.g. defined in +nx.tcl+). The Next Scripting Framework is shipped with three language definitions, containing NX and XOTcl 2. Most of the existing XOTcl 1 programs can be used without modification in the Next Scripting Framework by using XOTcl 2. The Next Scripting Framework requires Tcl 8.5 or newer. Although NX is fully scripted (as well as XOTcl 2), our benchmarks show that scripts based on NX are often 2 or 4 times faster than the counterparts in XOTcl 1. But speed was not the primary focus on the Next Scripting Environment: The goal was primarily to find ways to repackage the power of XOTcl in an easy to learn environment, highly orthogonal environment, which is better suited for large projects, trying to reduce maintenance costs. We expect that many users will find it attractive to upgrade from XOTcl 1 to XOTcl 2, and some other users will upgrade to NX. This document focuses mainly on the differences between XOTcl 1 and NX, but addresses as well potential incompatibilities between XOTcl 1 and XOTcl 2. For an introduction to NX, please consult the NX tutorial. Differences Between XOTcl and NX ------------------------------- The Next Scripting Framework supports _Language Oriented Programming_ by providing means to define potentially multiple object systems with different naming and functionality in a single interpreter. This makes the Next Scripting Framework a powerful instrument for defining multiple languages such as e.g. domain specific languages. This focus differs from XOTcl 1. Technically, the language framework approach means that the languages implemented by the Next Scripting Framework (most prominently XOTcl 2 and NX) are typically fully scripted and can be loaded via the usual Tcl +package require+ mechanism. Some of the new features below are provided by the Next Scripting Framework, some are implemented via the script files for XOTcl 2 and NX. === Features of NX In general, the Next Scripting Language (NX) differs from XOTcl in the following respects: . *Stronger Encapsulation:* The Next Scripting Language favors a _stronger form of encapsulation_ than XOTcl. Calling the own methods or accessing the own instance variables is typographically easier and computationally faster than these operations on other objects. This behavior is achieved via _resolvers_, which make some methods necessary in XOTcl 1 obsolete in NX (especially for importing instance variables). The encapsulation of NX is stronger than in XOTcl but still weak compared to languages like C++; a developer can still access other objects' variables via some idioms, but NX _makes accesses to other objects' variables explicit_. The requiredness to make these accesses explicit should encourage developer to implement well defined interfaces to provide access to instance variables. . *Additional Forms of Method Definition and Reuse:* The Next Scripting Language provides much more orthogonal means to _define, reuse and introspect_ scripted and C-implemented methods. .. It is possible to use NX +alias+ to register methods under arbitrary names for arbitrary objects or classes. .. NX provides means for _method protection_ (method modifiers +public+, +protected+, and +private+). Therefore, developers have to define explicitly public interfaces in order to use methods from other objects. .. One can invoke in NX fully qualified methods to invoke methods outside the precedence path. .. One can define in NX _hierarchical method names_ (similar to commands and subcommands, called method ensembles) in a convenient way to provide extensible, hierarchical naming of methods. .. One can use in NX the same interface to query (introspect) C-implemented and scripted methods/commands. . *Orthogonal Parameterization:* The Next Scripting Language provides an _orthogonal framework for parameterization_ of methods and objects. .. In NX, the same argument parser is used for * Scripted Methods * C-implemented methods and Tcl commands * Object Parametrization .. While XOTcl 1 provided only value-checkers for non-positional arguments for methods, the Next Scripting Framework provides the same value checkers for positional and non-positional arguments of methods, as well as for positional and non-positional configure parameters (`-parameter` in XOTcl 1). .. While XOTcl 1 supported only non-positional arguments at the begin of the argument list, these can be used now at arbitrary positions. . *Value Checking:* .. The Next Scripting Language supports checking of the _input parameters_ and the _return values_ of scripted and C-implemented methods and commands. .. NX provides a set of predefined checkers (like e.g. +integer+, +boolean+, +object+, ...) which can be extended by the applications. .. Value Checking can be used for _single_ and _multi-valued_ parameters. One can e.g. define a list of integers with at least one entry by the parameter specification +integer,1..n+. .. Value Checking can be turned on/off globally or on the method/command level. . *Scripted Init Blocks:* The Next Scripting Language provides _scripted init blocks_ for objects and classes (replacement for the dangerous dash "-" mechanism in XOTcl that allows one to set variables and invoke methods upon object creation). . *More Conventional Naming for Predefined Methods:* The naming of the methods in the Next Scripting Language is much more in line with the mainstream naming conventions in OO languages. While for example XOTcl uses +proc+ and +instproc+ for object specific and inheritable methods, NX uses simply +method+. . *Profiling Support:* The Next Scripting Language provides now two forms of profiling * Profiling via a DTrace provider (examples are e.g. in the dtrace subdirectory of the source tree) * Significantly improved built-in profiling (results can be processed in Tcl). . *Significantly Improved Test Suite:* The regression test suite of Next Scripting framework contain now more than 5.000 tests, and order of magnitude more than in XOTcl 1.6 . *Much Smaller Interface:* The Next Scripting Language has a much _smaller interface_ (i.e. provides less predefined methods) than XOTcl (see Table 1), although the expressiveness was increased in NX. .Comparison of the Number of Predefined Methods in NX and XOTcl [width="50%",frame="topbot",options="header,footer",cols="3,>1,>1"] |====================== ||NX|XOTcl |Methods for Objects |14| 51 |Methods for Classes | 9| 24 |Info-methods for Objects |11| 25 |Info-methods for Classes |11| 24 |Total | 45|124 |====================== This comparison list compares mostly XOTcl 1 with NX, some features are also available in XOTcl 2 (2a, 2c 2d, 3, 4). === NX and XOTcl Scripts Below is a small, introductory example showing an implementation of a class +Stack+ in NX and XOTcl. The purpose of this first example is just a quick overview. We will go into much more detailed comparison in the next sections. NX supports a block syntax, where the methods are defined during the creation of the class. The XOTcl syntax is slightly more redundant, since every definition of a method is a single top-level command starting with the class name (also NX supports the style used in XOTcl). In NX, all methods are per default protected (XOTcl does not support protection). In NX methods are defined in the definition of the class via +:method+ or +:public method+. In XOTcl methods are defined via the +instproc+ method. Another difference is the notation to refer to instance variables. In NX, instance variable are named with a single colon in the front. In XOTcl, instance variables are imported using +instvar+. [options="header",cols="asciidoc,asciidoc",frame="none"] |====================== |Stack example in NX |Stack example in XOTcl |[source,tcl] -------------------------------------------------- Class create Stack { # # Stack of Things # :variable things "" :public method push {thing} { set :things [linsert ${:things} 0 $thing] return $thing } :public method pop {} { set top [lindex ${:things} 0] set :things [lrange ${:things} 1 end] return $top } } -------------------------------------------------- |[source,tcl] -------------------------------------------------- # # Stack of Things # Class Stack Stack instproc init {} { my instvar things set things "" } Stack instproc push {thing} { my instvar things set things [linsert $things 0 $thing] return $thing } Stack instproc pop {} { my instvar things set top [lindex $things 0] set things [lrange $things 1 end] } -------------------------------------------------- |====================== === Using XOTcl 2.0 and the Next Scripting Language in a Single Interpreter In general, the Next Scripting Framework supports multiple object systems concurrently. Effectively, every object system has different base classes for creating objects and classes. Therefore, these object systems can have different interfaces and names of built-in methods. Currently, the Next Scripting Framework is packaged with three object systems: - NX - XOTcl 2.0 - TclCool XOTcl 2 is highly compatible with XOTcl 1, the language NX is described below in more details, the language TclCool was introduced in Tip#279 and serves primarily an example of a small OO language. A single Tcl interpreter can host multiple Next Scripting Object Systems at the same time. This fact makes migration from XOTcl to NX easier. The following example script shows to use XOTcl and NX in a single script: .Using Multiple Object Systems in a single Script [source,tcl] -------------------------------------------------- namespace eval mypackage { package require XOTcl 2.0 # Define a class with a public method "foo" using XOTcl xotcl::Class C1 C1 instproc foo {} {puts "hello world"} package require nx # Define a class with a public method "foo" using NX nx::Class create C2 { :public method foo {} {puts "hello world"} } } -------------------------------------------------- One could certainly create object or classes from the different object systems via fully qualified names (e.g. using e.g. `::xotcl::Class` or `::nx::Class`), but for migration for systems without explicit namespaces switching between the object systems eases migration. "Switching" between XOTcl and NX effectively means the load some packages (if needed) and to import either the base classes (Object and Class) of XOTcl or NX into the current namespace. XOTcl Idioms in the Next Scripting Language --------------------------------------------- The following sections are intended for reader familiar with XOTcl and show, how certain language Idioms of XOTcl can be expressed in NX. In some cases, multiple possible realizations are listed Defining Objects and Classes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When creating objects or classes, one should use the method +create+ explicitly. In XOTcl, a default +unknown+ method handler was provided for classes, which create for every unknown method invocation an object/class with the name of the invoked method. This technique was convenient, but as well dangerous, since typos in method names lead easily to unexpected behavior. This default unknown method handler is not provided in NX (but can certainly be provided as a one-liner in NX by the application). [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- Class ClassName ---------------- |[source,tcl] ---------------- Class create ClassName ---------------- |[source,tcl] ---------------- Object ObjectName ---------------- |[source,tcl] ---------------- Object create ObjectName ---------------- |=========================== Defining Methods ~~~~~~~~~~~~~~~~ In general, both XOTcl and NX support methods on the object level (per-object methods, i.e. methods only applicable to a single object) and on the class level (methods inherited to instances of the classes). While the naming in XOTcl tried to follow closely the Tcl tradition (using the term +proc+ for functions/methods), NX uses the term +method+ for defining scripted methods. XOTcl uses the prefix +inst+ to denote that methods are provided for instances, calling therefore scripted methods for instances +instproc+. This is certainly an unusual term. The approach with the name prefix has the disadvantage, that for every different kind of method, two names have to be provided (e.g. +proc+ and +instproc+, +forward+ and +instforward+). NX on the contrary uses the same term for defining instance method or object-specific methods. When the term (e.g. +method+) is used on a class, the method will be an instance method (i.e. applicable to the instances of the class). When the term is used on an object with the modifier +object+, an object-specific method is defined. This way one can define the same way object specific methods on an object as well as on a class. Furthermore, both XOTcl and NX distinguish between scripted methods (section 3.2.1) and C-defined methods (section 3.2.2). Section 3.2.3 introduces method protection, which is only supported by NX. ==== Scripted Methods Defined in the Init-block of a Class/Object or with Separate Calls The following examples show the definition of a class and its methods in the init-block of a class (NX only), and the definition of methods via separate top-level calls (XOTcl and NX). [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # Define instance method 'foo' and object # method 'bar' for a Class 'C' with separate # top-level commands Class C C instproc foo args {...} C proc bar args {...} ---------------- |[source,tcl] ---------------- # Define instance method and object method # in the init-block of a class Class create C { :method foo args {...} :object method bar args {...} } ---------------- [source,tcl] ---------------- # Define instance method and object method # with separate commands Class create C C method foo args {...} C object method bar args {...} ---------------- |[source,tcl] ---------------- # Define object-specific method foo # for an object 'o' with separate commands Object o o set x 1 o proc foo args {...} ---------------- |[source,tcl] ---------------- # Define object method and set # instance variable in the init-block of # an object Object create o { set :x 1 :object method foo args {...} } ---------------- [source,tcl] ---------------- # Define object method and set # instance variable with separate # commands Object create o o eval {set :x 1} o object method foo args {...} ---------------- |=========================== ==== Different Kinds of Methods This section describes various kinds of methods. The different kinds of methods are defined via different method-defining methods, which are summarized in the following table for XOTcl and NX. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # Methods for defining methods: # # proc # instproc # forward # instforward # parametercmd # instparametercmd # # All these methods return empty. ---------------- |[source,tcl] ---------------- # Methods for defining methods: # # alias # forward # method # # All these methods return method-handles. ---------------- |=========================== In addition to scripted methods (previous section) XOTcl supports forwarder (called +forward+ and +instforward+) and accessor functions to variables (called +parametercmd+ and +instparametercmd+). The accessor functions are used normally internally when object-specific parameters are defined (see Section 3.4). In NX forwarders are called +forward+. NX does not provide a public available method to define variable accessors like +parametercmd+ in XOTcl, but use internally the Next Scripting Framework primitive +nsf::method::setter+ when appropriate. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- Class C C instforward f1 ... C forward f2 ... Object o o forward f3 ... ---------------- |[source,tcl] ---------------- # Define forwarder Class create C { :forward f1 ... :object forward f2 ... } Object create o { :object forward f3 ... } ---------------- |[source,tcl] ---------------- # Define setter and getter methods in XOTcl. # # XOTcl provides methods for these. Class C C instparametercmd p1 C parametercmd p2 Object o o parametercmd p3 ---------------- |[source,tcl] ---------------- # Define setter and getter methods in NX. # # NX does not provide own methods, but uses # the low-level framework commands, since # application developer will only # need it in rare cases. Class create C ::nsf::method::setter C p1 ::nsf::method::setter C -per-object p2 Object create o ::nsf::method::setter o p3 ---------------- |====================== NX supports in contrary to XOTcl the method +alias+ which can be used to register arbitrary Tcl commands or methods for an object or class under a provided method name. Aliases can be used to reuse a certain implementation in e.g. different object systems under potentially different names. In some respects aliases are similar to forwarders, but they do not involve forwarding overhead. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # Method "alias" not available ---------------- |[source,tcl] ---------------- # Define method aliases # (to scripted or non-scripted methods) Class create C { :alias a1 ... :object alias a2 ... } Object create o { :object alias a3 ... } ---------------- |=========================== [[method-protect-example]] ==== Method Modifiers and Method Protection NX supports four method modifiers +object+, +public+, +protected+ and +private+. All method modifiers can be written in front of every method defining command. The method modifier +object+ is used to denote object-specific methods (see above). The concept of method protection is new in NX. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # Method modifiers # # "object", # "public", # "protected", and # "private" # # are not available ---------------- |[source,tcl] ---------------- # Method modifiers # # "object", # "public", # "protected" # # are applicable for all kinds of # method defining methods: # # method, forward, alias # # The modifier "private" is available for # # method, forward, alias # Class create C { :/method-definition-method/ ... :public /method-definition-method/ ... :protected /method-definition-method/ ... :private /method-definition-method/ ... :object /method-definition-method/ ... :public object /method-definition-method/ ... :protected object /method-definition-method/ ... :private object /method-definition-method/ ... } ---------------- |====================== XOTcl does not provide method protection. In NX, all methods are defined per default as protected. This default can be changed by the application developer in various ways. The command `::nx::configure defaultMethodCallProtection true|false` can be used to set the default call protection for scripted methods, forwarder and aliases. The defaults can be overwritten also on a class level. NX provides means for method hiding via the method modifier +private+. Hidden methods can be invoked only via the +-local+ flag, which means: "call the specified method defined in the same class/object as the currently executing method". [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # XOTcl provides no means for # method hiding ---------------- |[source,tcl] ---------------- # Hiding of methods via "private" # nx::Class create Base { :private method baz {a b} {expr {$a + $b}} :public method foo {a b} {: -local baz $a $b} } nx::Class create Sub -superclass Base { :public method bar {a b} {: -local baz $a $b} :private method baz {a b} {expr {$a * $b}} :create s1 } s1 foo 3 4 ;# returns 7 s1 bar 3 4 ;# returns 12 s1 baz 3 4 ;# unable to dispatch method 'baz' ---------------- |====================== [[method-deletion]] ==== Method Deletion NX provides an explicit +delete+ method for the deletion of methods. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # XOTcl provides only method deletion with # the equivalent of Tcl's "proc foo {} {}" /cls/ instproc foo {} {} /obj/ proc foo {} {} ---------------- |[source,tcl] ---------------- # Deletion of Methods # /cls/ delete method /name/ /obj/ delete object method /name/ ---------------- |====================== === Resolvers The Next Scripting Framework defines Tcl resolvers for method and variable names to implement object specific behavior. Within the bodies of scripted methods these resolvers treat variable and function names starting with a colon `:` specially. In short, a colon-prefixed variable name refers to an instance variable, and a colon-prefixed function name refers to a method. The sub-sections below provide detailed examples. Note that the resolvers of the Next Scripting Framework can be used in the XOTcl 2.* environment as well. ==== Invoking Methods In XOTcl, a method of the same object can be invoked via +my+, or in general via using the name of the object in front of the method name. In NX, the own methods are called via the method name prefixed with a single colon. The invocation of the methods of other objects is the same in NX and XOTcl. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- Class C C instproc foo args {...} C instproc bar args { my foo 1 2 3 ;# invoke own method o baz ;# invoke other object's method } Object o o proc baz {} {...} ---------------- |[source,tcl] ---------------- Class create C { :method foo args {...} :method bar args { :foo 1 2 3 ;# invoke own method o baz ;# invoke other object's method } } Object create o { :public object method baz {} {...} } ---------------- |====================== ==== Accessing Own Instance Variables from Method Bodies In general, the Next Scripting Language favors the access to an objects's own instance variables over variable accesses of other objects. This means that in NX it is syntactically easier to access the own instance variables. On the contrary, in XOTcl, the variable access to own and other variables are fully symmetric. In XOTcl, the following approaches are used to access instance variables: - Import instance variables via +instvar+ and access variables via +$varName+ - Set or get instance variables via +my set varName ?value?+ or other variable accessing methods registered on +xotcl::Object+ such as +append+, +lappend+, +incr+, etc. - Register same-named accessor functions and set/get values of instance variables via +my varName ?value?+ In NX, the favored approach to access instance variables is to use the name resolvers, although it is as well possible to import variables via +nx::var import+ or to check for the existence of instance variables via +nx::var exists+. The following examples summary the use cases for accessing the own and other instance variables. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- Class C C instproc foo args { # Method scoped variable a set a 1 # Instance variable b my instvar b set b 2 # Global variable/namespaced variable c set ::c 3 } ---------------- |[source,tcl] ---------------- Class create C { :method foo args {...} # Method scoped variable a set a 1 # Instance variable b set :b 2 # Global variable/namespaced variable c set ::c 3 } } ---------------- |[source,tcl] ---------------- ... instproc ... { my set /varName/ ?value? } ---------------- |[source,tcl] ---------------- # Set own instance variable to a value via # resolver (preferred and fastest way) ... method ... { set :/newVar/ ?value? } ---------------- |[source,tcl] ---------------- ... instproc ... { my instvar /varName/ set /varName/ ?value? } ---------------- |[source,tcl] ---------------- # Set own instance variable via # variable import ... method ... { ::nx::var import [self] /varName/ set /varName/ ?value? } ---------------- |[source,tcl] ---------------- ... instproc ... { set /varName/ [my set /otherVar/] } ---------------- |[source,tcl] ---------------- # Read own instance variable ... method ... { set /varName/ [set :/otherVar/] } ---------------- [source,tcl] ---------------- ... method ... { set /newVar/ ${:/otherVar/} } ---------------- |[source,tcl] ---------------- ... instproc ... { my exists /varName/ } ---------------- |[source,tcl] ---------------- # Test existence of own instance variable ... method ... { info :/varName/ } ---------------- [source,tcl] ---------------- ... method ... { ::nx::var exists [self] /varName/ } ---------------- |====================== ==== Accessing Instance Variables of other Objects [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- /obj/ set /varName/ ?value? ---------------- |[source,tcl] ---------------- # Set instance variable of object obj to a # value via resolver # (preferred way: define property on obj) /obj/ eval [list set :/varName/ ?value?] ---------------- |[source,tcl] ---------------- set /varName/ [/obj/ set /otherVar/] ---------------- |[source,tcl] ---------------- # Read instance variable of object obj # via resolver set /varName/ [/obj/ eval {set :/otherVar/}] ---------------- |[source,tcl] ---------------- ... instproc ... { /obj/ instvar /varName/ set /varName/ ?value? } ---------------- |[source,tcl] ---------------- # Read instance variable of object /obj/ # via import ... method ... { ::nx::var import /obj/ /varName/ set /varName/ ?value? } ---------------- |[source,tcl] ---------------- /obj/ exists varName ---------------- |[source,tcl] ---------------- # Test existence of instance variable of # object obj /obj/ eval {info exists :/varName/} ---------------- [source,tcl] ---------------- ::nx::var exists /obj/ /varName/ ---------------- |====================== === Parameters While XOTcl 1 had very limited forms of parameters, XOTcl 2 and NX provide a generalized and highly orthogonal parameter machinery handling various kinds of value constraints (also called value checkers). Parameters are used to specify, - how objects and classes are initialized (we call these parameter types _Configure Parameters_), and - what values can be passed to methods (we call these _Method Parameters_). Furthermore, parameters might be positional or non-positional, they might be optional or required, they might have a defined multiplicity, and value-types, they might be introspected, etc. The Next Scripting Framework provide a unified, C-implemented infrastructure to handle both, object and method parameters in the same way with a high degree of orthogonality. Configuration parameters were specified in XOTcl 1 primarily via the method +parameter+ in a rather limited way, XOTcl 1 only supported non-positional parameters in front of positional ones, supported no value constraints for positional parameters, provided no distinction between optional and required, and did not support multiplicity. Furthermore, the Next Scripting Framework provides optionally _Return Value Checking_ based on the same mechanism to check whether some methods return always the values as specified. ==== Parameters for Configuring Objects: Variables and Properties Configure parameters are used for specifying values for configuring objects when they are created (i.e. how instance variables are initialized, what parameters can be passed in for initialization, what default values are used, etc.). Such configuration parameters are supported in XOTcl primarily via the method +parameter+, which is used in XOTcl to define multiple parameters via a list of parameter specifications. Since the term "parameter" is underspecified, NX uses a more differentiated terminology. NX distinguishes between configurable instance variables (also called _properties_) and non-configurable instance variables (called _variables_), which might have as well e.g. default values. The values of configurable properties can be queried at run time via +cget+, and their values can be altered via +configure+. When the value of a configure parameter is provided or changed, the value checkers from the variable definition are used to ensure, the value is permissible (i.e. it is for example an integer value). The sum of all configurable object parameters are called _configure parameters_. To define a define a configurable variable, NX uses the method +property+, for non-configurable variables, the method +variable+ is used. Optionally, one can define in NX, that a +property+ or a +variable+ should have a public, protected or private accessor. Such an accessor is a method with the same name as the variable. In XOTcl, every +parameter+ defined as well automatically a same-named accessor method, leading to potential name conflicts with other method names. In the examples below we show the definition of non-configurable instance variables using +variable+ and +property+ respectively. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # Define class "Foo" with instance # variables "x" and "y" initialized # on instance creation. The initialization # has to be performed in the constructor. Class Foo Foo instproc init args { instvar x y set x 1 set y 2 } # Create instance of the class Foo Foo f1 # Object f1 has instance variables # x == 1 and y == 2 ---------------- |[source,tcl] ---------------- # Define class "Foo" with instance variables # "x" and "y" initialized on instance creation. # The method "variable" is similar in syntax # to Tcl's "variable" command. During # instance creation, the variable # definitions are used for the # initialization of the variables of the object. Class create Foo { :variable x 1 :variable y 2 } # Create instance of the class Foo Foo create f1 # Object f1 has instance variables # x == 1 and y == 2 ---------------- |====================== While XOTcl follows a procedural way to initialize variables via the constructor +init+, NX follows a more declarative approach. Often, classes have superclasses, which often want to provide their own instance variables and default values. The declarative approach from NX solves this via inheritance, while a procedural approach via assign statements in the constructor requires explicit constructor calls, which are often error-prone. Certainly, when a user prefers to assign initial values to instance variables via explicit assign operations in constructors, this is as well possible in NX. NX uses the same mechanism to define class variables or object variables. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # No syntactic support for creating # class variables ---------------- |[source,tcl] ---------------- # Define an object variable "V" with value 100 and # an instance variable "x". "V" is defined for the # class object Foo, "x" is defined in the # instances of the class. "object variable" works # similar to "object method". Class create Foo { :object variable V 100 :variable x 1 } ---------------- |====================== In the next step, we define configurable instance variables which we call _properties_ in NX. XOTcl uses the method +parameter+ is a shortcut for creating multiple configurable variables with automatically created accessors (methods for reading and writing of the variables). In NX, the preferred way to create configurable variables is to use the method +property+. The method +property+ in NX is similar to +variable+, but makes the variables configurable, which means that . one can specify the property as a non-positional parameter upon creation of the object, . one can query the value via the method +cget+, and . one can modify the value of the underlying variable via the method +configure+. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # Parameters specified as a list # (short form); parameter # "a" has no default, "b" has default "1" Class Foo -parameter {a {b 1} {c "[info tclversion]"}} # Create instance of the class Foo Foo f1 -a 0 # Object f1 has instance variables # a == 0 and b == 1 # XOTcl registers automatically accessors # for the parameters. Use the accessor # "b" to output the value of variable "b" puts [f1 b] # Use the setter to alter value of # instance variable "b" f1 b 100 # Return the substituted value of # parameter "c", something like 8.7. # XOTcl substitutes always when it sees # square brackets or dollar signs. f1 c ---------------- |[source,tcl] ---------------- # Define property "a" and "b". The # property "a" has no default, "b" has # default value "1" Class create Foo { :property a :property {b 1} :property {c "[info tclversion]"} :property {d:substdefault "[info tclversion]"} } # Create instance of the class Foo Foo create f1 -a 0 # Object f1 has instance variables # a == 0 and b == 1 # Use the method "cget" to query the value # of a configuration parameter puts [f1 cget -b] # Use the method "configure" to alter the # value of instance variable "b" f1 configure -b 100 # Return the (non-substituted) value of # parameter "c", and the substituted value # of parameter "d" f1 cget -c f1 cget -d ---------------- |====================== In general, NX allows one to create variables and properties with and without accessor methods. The created accessor methods might be +public+, +protected+ or +public+. When the value +none+ is provided to +-accessor+, no accessor will be created. This is actually the default in NX. In order to change the default behavior in NX, one can use +::nx::configure defaultAccessor none|public|protected|private+. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # "parameter" creates always accessor # methods, accessor methods are # always public, no "cget" is available. Class create Foo -parameter {a {b 1}} # Use the accessor method to query # the value of a configuration parameter puts [f1 b] # Use the accessor method to set the # value of instance variable "a" f1 a 100 # Use the accessor method to unset the # value of instance variable "a" n.a. via # accessor ---------------- |[source,tcl] ---------------- # Define property "a" and "b". The # property "a" has no default, "b" has # default value "1" Class create Foo { :variable -accessor public a :property -accessor public {b 1} } # Use the accessor method to query # the value of a configuration parameter puts [f1 b get] # Use the accessor method to set the # value of instance variable "a" f1 a set 100 # Use the accessor method to unset the # value of instance variable "a" f1 a unset ---------------- |====================== Similar to +variable+, properties can be defined in NX on the class and on the object level. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # XOTcl provides no means to define # configurable variables at the object # level ---------------- |[source,tcl] ---------------- # Define class with a property for the class object # named "cp". This is similar to "static variables" # in some other object-oriented programming # languages. Class create Foo { ... :object property cp 101 } # Define object property "op" Object create o { :object property op 102 } ---------------- |====================== NX supports _value constraints_ (value-checkers) for object and method parameters in an orthogonal manner. NX provides a predefined set of value checkers, which can be extended by the application developer. In NX, the _value checking is optional_. This means that it is possible to develop e.g. which a large amount of value-checking and deploy the script with value checking turned off, if the script is highly performance sensitive. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # No value constraints for # parameter available ---------------- |[source,tcl] ---------------- # Predefined value constraints: # object, class, alnum, alpha, ascii, boolean, # control, digit, double, false, graph, integer, # lower, parameter, print, punct, space, true, # upper, wordchar, xdigit # # User defined value constraints are possible. # All parameter value checkers can be turned on # and off at run time. # # Define a required boolean property "a" # and an integer property "b" with a default. # The first definition uses "properties", # the second definition uses multiple # "property" statements. Class create Foo -properties { a:boolean {b:integer 1} } ---------------- [source,tcl] ---------------- Class create Foo { :property a:boolean :property {b:integer 1} } ---------------- |====================== In XOTcl all configure parameters were _optional_. Required parameters have to be passed to the constructor of the object. NX allows one to define _optional_ and _required_ configure parameters (as well as method parameters). Therefore, configure parameters can be used as the single mechanism to parameterize objects. It is in NX not necessary (and per default not possible) to pass arguments to the constructor. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # Required parameter not available ---------------- |[source,tcl] ---------------- # Required parameter: # Define a required property "a" and a # required boolean property "b" Class create Foo -properties { a:required b:boolean,required } ---------------- [source,tcl] ---------------- Class create Foo { :property a:required :property b:boolean,required } ---------------- |====================== NX supports in contrary to XOTcl to define the _multiplicity_ of values per parameter. In NX, one can specify that a parameter can accept the value "" (empty) in addition to e.g. an integer, or one can specify that the value is an empty or nonempty list of values via the multiplicity. For every specified value, the value checkers are applied. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] --------------- # Multiplicity for parameter # not available ----------------- |[source,tcl] ---------------- # Parameter with multiplicity # ints is a list of integers, with default # objs is a nonempty list of objects # obj is a single object, maybe empty Class create Foo -properties { {ints:integer,0..n ""} objs:object,1..n obj:object,0..1 } ---------------- [source,tcl] ---------------- Class create Foo { :property {ints:integer,0..n ""} :property objs:object,1..n :property obj:object,0..1 } ---------------- |====================== For the implementation of variables and properties, NX uses slot objects, which are an extension to the +-slots+ already available in XOTcl. While very for every +property+ in NX, a slot object is created, for performance reasons, not every +variable+ has a slot associated. When a property is created, NX does actually three things: . Create a slot object, which can be specified in more detail using the init-block of the slot object . Create a parameter definition for the initialization of the object (usable via a non-positional parameter during object creation), and . register optionally an accessor function (setter), for which the usual protection levels (+public+, +protected+ or +private+) can be used. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # Define parameters via slots Class Foo -slots { Attribute a Attribute b -default 1 } # Create instance of the class Foo # and provide a value for instance # variable "a" Foo f1 -a 0 # Object f1 has a == 0 and b == 1 ---------------- |[source,tcl] ---------------- # Configurable parameters specified via the # method "property" (supports method # modifiers and scripted configuration; # see below) Class create Foo { :property a :property {b 1} } # Create instance of the class Foo and # provide a value for instance variable "a" Foo create f1 -a 0 # Object f1 has a == 0 and b == 1 ---------------- |====================== Since the slots are objects, the slot objects can be configured and parameterized like every other object in NX. Slot objects can be provided with a scripted initialization as well. We show first the definition of properties similar to the functionality provided as well by XOTcl and show afterwards how to use value constraints, optional parameters, etc. in NX. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # Define parameter with an # attribute-specific type checker Class Person -slots { Attribute create sex -type "sex" { my proc type=sex {name value} { switch -glob $value { m* {return m} f* {return f} default { error "expected sex but got $value" } } } } } ---------------- |[source,tcl] ---------------- # Configure parameter with scripted # definition (init-block), defining a # property specific type checker Class create Person { :property -accessor public sex:sex,convert { # define a converter to standardize representation :object method type=sex {name value} { switch -glob $value { m* {return m} f* {return f} default {error "expected sex but got $value"} } } } } ---------------- |====================== The parameters provided by a class for the initialization of instances can be introspected via querying the parameters of the method create: +/cls/ info lookup parameters create+ (see <>). ==== Delete Variable Handlers [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # No syntactic support for deleting # variable handlers ---------------- |[source,tcl] ---------------- # Like deletion of Methods: # Delete on the object, where the # variable handler is defined. /cls/ delete property /name/ /obj/ delete object property /name/ /cls/ delete variable /name/ /obj/ delete object variable /name/ ---------------- |====================== ==== Method Parameters Method parameters are used to specify the interface of a single method (what kind of values may be passed to a method, what default values are provided etc.). The method parameters specifications in XOTcl 1 were limited and allowed only value constraints for non-positional arguments. NX and XOTcl 2 provide value constraints for all kind of method parameters. While XOTcl 1 required non-positional arguments to be listed in front of positional arguments, this limitation is lifted in XOTcl 2. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # Define method foo with non-positional # parameters (x, y and y) and positional # parameter (a and b) Class C C instproc foo { -x:integer -y:required -z a b } { # ... } C create c1 # invoke method foo c1 foo -x 1 -y a 2 3 ---------------- |[source,tcl] ---------------- # Define method foo with # non-positional parameters # (x, y and y) and positional # parameter (a and b) Class create C { :public method foo { -x:integer -y:required -z a b } { # ... } :create c1 } # invoke method foo c1 foo -x 1 -y a 2 3 ---------------- |[source,tcl] ---------------- # Only leading non-positional # parameters are available; no # optional positional parameters, # no value constraints on # positional parameters, # no multiplicity, ... ---------------- |[source,tcl] ---------------- # Define various forms of parameters # not available in XOTcl 1 Class create C { # trailing (or interleaved) non-positional # parameters :public method m1 {a b -x:integer -y} { # ... } # positional parameters with value constraints :public method m2 {a:integer b:boolean} { #... } # optional positional parameter (trailing) :public method set {varName value:optional} { # .... } # parameter with multiplicity :public method m3 {-objs:object,1..n c:class,0..1} { # ... } # In general, the same list of value # constraints as for configure parameter is # available (see above). # # User defined value constraints are # possible. All parameter value checkers # can be turned on and off. } ---------------- |====================== ==== Return Value Checking _Return value checking_ is a functionality available in the Next Scripting Framework, that was not yet available in XOTcl 1. A return value checker assures that a method returns always a value satisfying some value constraints. Return value checkers can be defined on all forms of methods (scripted or C-implemented). Like for other value checkers, return value checkers can be turned on and off. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # No return value checking # available ---------------- |[source,tcl] ---------------- # Define method foo with non-positional # parameters (x, y and y) and positional # parameter (a and b) Class create C { # Define method foo which returns an # integer value :method foo -returns integer {-x:integer} { # ... } # Define an alias for the Tcl command ::incr # and assure, it always returns an integer # value :alias incr -returns integer ::incr # Define a forwarder that has to return an # integer value :forward ++ -returns integer ::expr 1 + # Define a method that has to return a # nonempty list of objects :public object method instances {} \ -returns object,1..n { return [:info instances] } } ---------------- |====================== === Interceptors XOTcl and NX allow the definition of the same set of interceptors, namely class- and object-level mixins and class- and object-level filters. The primary difference in NX is the naming, since NX abandons the prefix "inst" from the names of instance specific method, but uses the modifier +object+" for object specific methods. Therefore, in NX, if a +mixin+ is registered on a class-level, it is applicable for the instances (a per-class mixin), and if and +object mixin+ is registered, it is a per-object mixin. In both cases, the term +mixin+ is used, in the second case with the modifier +object+. As in all other cases, one can register the same way a per-object mixin on a plain object or on a class object. ==== Register Mixin Classes and Mixin Guards [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- /cls/ instmixin ... /cls/ instmixinguard /mixin/ ?condition? # Query per-class mixin /cls/ instmixin ---------------- |[source,tcl] ---------------- # Register/clear per-class mixin and guard for # a class /cls/ mixins add\|set\|clear ... /cls/ mixins guard /mixin/ ?condition? /cls/ configure -mixin ... # Query per-class mixins /cls/ mixins get /cls/ cget -mixins # Query per-class mixins (without guards) /cls/ mixins classes ---------------- |[source,tcl] ---------------- /obj/ mixin ... /obj/ mixinguard /mixin/ ?condition? # Query per-object mixins /obj/ mixin ---------------- |[source,tcl] ---------------- # Register/clear per-object mixin and guard for # an object /obj/ object mixins add\|set\|clear ... /obj/ object mixins guard /mixin/ ?condition? /obj/ configure -object-mixins ... # Query per-object mixin /obj/ object mixins get /obj/ cget -object-mixin # Query per-object mixins (without guards) /cls/ mixins classes ---------------- |====================== ==== Register Filters and Filter Guards [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # Register per-class filter and guard for # a class /cls/ instfilter ... /cls/ instfilterguard /filter/ ?condition? # Query per-class filter /cls/ instfilter ---------------- |[source,tcl] ---------------- # Register/clear per-class filter and guard for # a class /cls/ filters add\|set\|clear ... /cls/ filters guard /filter/ ?condition? /cls/ configure -filters ... # Query per-class filters /cls/ filters get /cls/ cget -filters # Query per-class filters (without guards) /cls/ filters methods ---------------- |[source,tcl] ---------------- /obj/ filter ... /obj/ filterguard /filter/ ?condition? ---------------- |[source,tcl] ---------------- # Register(clear per-object filter and guard for # an object /obj/ object filters add\|set\|clear ... /obj/ object filters guard /filter/ ?condition? /obj/ configure -object-filters ... # Query per-object filters /cls/ object filters get /obj/ cget -object-filters # Query per-object filters (without guards) /cls/ object filters methods ---------------- |====================== === Introspection In general, introspection in NX became more orthogonal and less dependent on the type of the method. In XOTcl it was e.g. necessary that a developer had to know, whether a method is e.g. scripted or not and has to use accordingly different sub-methods of +info+. In NX, one can use e.g. always +info method+ with a subcommand and the framework tries to hide the differences as far as possible. So, one can for example obtain with +info method parameter+ the parameters of scripted and C-implemented methods the same way, one can get the definition of all methods via +info method definition+ and one can get an manual-like interface description via +info method syntax+. In addition, NX provides means to query the type of a method, and NX allows one to filter by the type of the method. ==== List sub- and superclass relations While XOTcl used singular words for introspecting sub- and superclass relations, NX uses plural word to indicate that potentially a list of values is returned. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- /cls/ info superclass ?pattern? ---------------- |[source,tcl] ---------------- /cls/ info superclasses ?pattern? ---------------- |[source,tcl] ---------------- /cls/ info subclass ?pattern? ---------------- |[source,tcl] ---------------- /cls/ info subclasses -type setter ?pattern? ---------------- |====================== ==== List methods defined by classes While XOTcl uses different names for obtaining different kinds of methods defined by a class, NX uses +info methods+ in an orthogonal manner. NX allows as well to use the call protection to filter the returned methods. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- /cls/ info instcommands ?pattern? ---------------- |[source,tcl] ---------------- /cls/ info methods ?pattern? ---------------- |[source,tcl] ---------------- /cls/ info instparametercmd ?pattern? ---------------- |[source,tcl] ---------------- /cls/ info methods -type setter ?pattern? ---------------- |[source,tcl] ---------------- /cls/ info instprocs ?pattern? ---------------- |[source,tcl] ---------------- /cls/ info methods -type scripted ?pattern? ---------------- |[source,tcl] ---------------- # n.a. ---------------- |[source,tcl] ---------------- /cls/ info methods -type alias ?pattern? /cls/ info methods -type forwarder ?pattern? /cls/ info methods -type object ?pattern? /cls/ info methods -callprotection public\|protected ... ---------------- |====================== ==== List methods defined by objects While XOTcl uses different names for obtaining different kinds of methods defined by an object, NX uses +info methods+ in an orthogonal manner. NX allows as well to use the call protection to filter the returned methods. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- /obj/ info commands ?pattern? ---------------- |[source,tcl] ---------------- /obj/ info object methods ?pattern? ---------------- |[source,tcl] ---------------- /obj/ info parametercmd ?pattern? ---------------- |[source,tcl] ---------------- /obj/ info object methods -type setter ?pattern? ---------------- |[source,tcl] ---------------- /obj/ info procs ?pattern? ---------------- |[source,tcl] ---------------- /obj/ info object methods -type scripted ?pattern? ---------------- |[source,tcl] ---------------- # n.a. ---------------- |[source,tcl] ---------------- /obj/ info object methods -type alias ?pattern? /obj/ info object methods -type forwarder ?pattern? /obj/ info object methods -type object ?pattern? /obj/ info object methods -callprotection public\|protected ... ---------------- |====================== ==== Check existence of a method NX provides multiple ways of checking, whether a method exists; one can use +info method exists+ to check, if a given method exists (return boolean), or one can use +info methods ?pattern?+, where +pattern+ might be a single method name without wild-card characters. The method +info methods ?pattern?+ returns a list of matching names, which might be empty. These different methods appear appropriate depending on the context. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- /obj\|cls/ info \ [inst](commands\|procs\|parametercmd) \ ?pattern? ---------------- |[source,tcl] ---------------- /cls/ info method exists /methodName/ /cls/ info methods /methodName/ /obj/ info object method exists /methodName/ /obj/ info object methods /methodName/ ---------------- |====================== ==== List callable methods In order to obtain the set of artefacts for an object defined in the class hierarchy, NX uses +info lookup+. One can either lookup methods (via +info lookup methods+) or slots (via +info lookup slots+). The plural term refers to a potential set of return values. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- /obj/ info methods ?pattern? ---------------- |[source,tcl] ---------------- /obj/ info lookup methods ... ?pattern? # Returns list of method names ---------------- |[source,tcl] ---------------- # n.a. ---------------- |[source,tcl] ---------------- # List only application specific methods /obj/ info lookup methods -source application ... ?pattern? # Returns list of method names ---------------- |[source,tcl] ---------------- # Options for 'info methods' # # -incontext # -nomixins ---------------- |[source,tcl] ---------------- # Options for 'info lookup methods' # # -source ... # -callprotection ... # -incontext # -type ... # -nomixins ---------------- |[source,tcl] ---------------- # n.a. ---------------- |[source,tcl] ---------------- # List slot objects defined for obj # -source might be all\|application\|baseclasses # -type is the class of the slot object /obj/ info lookup slots ?-type ...? ?-source ...? ?pattern? # Returns list of slot objects ---------------- |[source,tcl] ---------------- # List registered filters /obj/ info filters -order ?-guards? ?pattern? # List registered mixins /obj/ info mixins -heritage ?-guards? ?pattern? ---------------- |[source,tcl] ---------------- # List registered filters /obj/ info lookup filters ?-guards? ?pattern? # List registered mixins /obj/ info lookup mixins ?-guards? ?pattern? ---------------- |====================== ==== List object/class where a specified method is defined +info lookup+ can be used as well to determine, where exactly an artefact is located. One can obtain this way a method handle, where a method or filter is defined. The concept of a _method-handle_ is new in NX. The method-handle can be used to obtain more information about the method, such as e.g. the definition of the method. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- /obj/ procsearch /methodName/ ---------------- |[source,tcl] ---------------- /obj/ info lookup method /methodName/ # Returns method-handle ---------------- |[source,tcl] ---------------- /obj/ filtersearch /methodName/ ---------------- |[source,tcl] --------------- /obj/ info lookup filter /methodName/ # Returns method-handle ----------------- |====================== ==== List definition of scripted methods XOTcl contains a long list of +info+ subcommands for different kinds of methods and for obtaining more detailed information about these methods. In NX, this list of +info+ subcommands is much shorter and more orthogonal. For example, +info method definition+ can be used to obtain with a single command the full definition of a _scripted method_, and furthermore, it works as well the same way to obtain e.g. the definition of a _forwarder_ or an _alias_. While XOTcl uses different names for info options for objects and classes (using the prefix "inst" for instance specific method), NX uses for object specific method the modifier +object+. For definition of class object specific methods, use the modifier +object+ as usual. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # n.a. ---------------- |[source,tcl] ---------------- /cls/ info method definition /methodName/ /obj/ info object method definition /methodName/ ---------------- |[source,tcl] ---------------- /cls/ info instbody /methodName/ /obj/ info body /methodName/ ---------------- |[source,tcl] ---------------- /cls/ info method body /methodName/ /obj/ info object method body /methodName/ ---------------- |[source,tcl] ---------------- /cls/ info instargs /methodName/ /obj/ info args /methodName/ ---------------- |[source,tcl] ---------------- /cls/ info method args /methodName/ /obj/ info object method args /methodName/ ---------------- |[source,tcl] ---------------- /cls/ info instnonposargs /methodName/ /obj/ info object method args /methodName/ ---------------- |[source,tcl] ---------------- /cls/ info method parameter /methodName/ /obj/ info object method parameter /methodName/ ---------------- |[source,tcl] ---------------- /cls/ info instdefault /methodName/ /obj/ info default /methodName/ ---------------- |[source,tcl] ---------------- # not needed, part of # "info ?object? method parameter" ---------------- |[source,tcl] ---------------- /cls/ info instpre /methodName/ /obj/ info pre /methodName/ ---------------- |[source,tcl] ---------------- /cls/ info method precondition /methodName/ /obj/ info object method precondition /methodName/ ---------------- |[source,tcl] ---------------- /cls/ info instpost /methodName/ /obj/ info post /methodName/ ---------------- |[source,tcl] ---------------- /cls/ info method postcondition /methodName/ /obj/ info object method postcondition /methodName/ ---------------- |====================== Another powerful introspection option in NX is +info ?object? method syntax+ which obtains a representation of the parameters of a method in the style of Tcl man pages (regardless of the kind of method). [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # n.a. ---------------- |[source,tcl] ---------------- /cls/ info method syntax /methodName/ /obj/ info object method syntax /methodName/ ---------------- |====================== [[info_configure_parameter]] ==== List Configure Parameters The way, how newly created objects can be configured is determined in NX via properties. The configuration happens during creation via the methods +create+ or +new+ or during run time via +configure+. These methods have therefore virtual argument lists, depending on the object or class on which they are applied. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # n.a. ---------------- |[source,tcl] ---------------- # Return the parameters applicable to # the create method of a certain class. # class can be configured. A pattern can # be used to filter the results. /cls/ info lookup parameters create ?/pattern/? # Return in the result in documentation syntax /cls/ info lookup syntax create ?/pattern/? # "info lookup parameters configure" returns # parameters available for configuring the # current object (might contain object # specific information) /obj/ info lookup parameters configure ?pattern? # "info lookup configure syntax" returns syntax of # a call to configure in the Tcl parameter syntax /obj/ info lookup syntax configure # Obtain information from a parameter # (as e.g. returned from "info lookup # parameters configure"). nsf::parameter::info name /parameter/ nsf::parameter::info syntax /parameter/ nsf::parameter::info type /parameter/ ---------------- |====================== ==== List Variable Declarations (property and variable) [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # obtain parameter definitions defined # for a class /cls/ info parameter ---------------- |[source,tcl] ---------------- # "info variables" returns handles of # properties and variables defined by this # class or object /cls/ info variables ?pattern? /obj/ info object variables ?pattern? # "info lookup variables" returns handles # of variables and properties applicable # for the current object (might contain # object specific information) /obj/ info lookup variables /pattern/ # "info variable" lists details about a # single property or variable. /obj/ info variable definition /handle/ /obj/ info variable name /handle/ /obj/ info variable parameter /handle/ ---------------- |====================== ==== List Slots [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # n.a. ---------------- |[source,tcl] ---------------- # Return list of slots objects defined on the # object or class # # -source might be all\|application\|baseclasses # -type is the class of the slot object # -closure includes slots of superclasses /cls/ info slots \ ?-type value? ?-closure? ?-source value? ?pattern? /obj/ info object slots ?-type ...? ?pattern? # List reachable slot objects defined for obj # -source might be all\|application\|baseclasses # -type is the class of the slot object # Returns list of slot objects. /obj/ info lookup slots \ ?-type ...? ?-source ... ?pattern? # Obtain definition, name or parameter from # slot object /slotobj/ definition /slotobj/ name /slotobj/ parameter ---------------- |====================== ==== List Filter or Mixins In NX all introspection options for filters are provided via +info filters+ and all introspection options for mixins are provided via +info mixins+. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- /obj/ info filter ?-guards? ?-order? ?pattern? /obj/ info filterguard /name/ ---------------- |[source,tcl] ---------------- /obj/ info object filters \ ?-guards? ?pattern? ---------------- |[source,tcl] ---------------- /cls/ info instfilter \ ?-guards? ?-order? ?pattern? /cls/ info instfilterguard /name/ ---------------- |[source,tcl] ---------------- /cls/ info filters \ ?-guards? ?pattern? ---------------- |[source,tcl] ---------------- /obj/ info mixin ?-guards? ?-order ?pattern? /obj/ info mixinguard /name/ ---------------- |[source,tcl] ---------------- /obj/ info object mixins \ ?-guards? ?pattern? ---------------- |[source,tcl] ---------------- /cls/ info instmixin \ ?-guards? ?-order? ?pattern? /cls/ info instmixinguard /name/ ---------------- |[source,tcl] ---------------- /cls/ info mixins \ ?-closure? ?-guards? ?-heritage? ?pattern? ---------------- |====================== ==== List definition of methods defined by aliases, setters or forwarders As mentioned earlier, +info method definition+ can be used on every kind of method. The same call can be used to obtain the definition of a scripted method, a method-alias, a forwarder or a setter method. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # n.a. ---------------- |[source,tcl] ---------------- /cls/ info method definition /methodName/ /obj/ info object method definition /methodName/ ---------------- |====================== ==== List Method-Handles NX supports _method-handles_ to provide means to obtain further information about a method or to change maybe some properties of a method. When a method is created, the method creating method returns the method handle to the created method. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # n.a. ---------------- |[source,tcl] ---------------- # # List the method handle of the specified method, # can be used e.g. for aliases. "handle" is the short # form of "definitionhandle". # /cls/ info method handle /methodName/ /obj/ info object method handle /methodName/ # # For ensemble methods (method name contains # spaces) one can query as well the registration # handle, which is the handle to the root of the # ensemble; the definition handle points to the # leaf of the ensemble. # /cls/ info method registrationhandle /methodName/ /obj/ info object method registrationhandle /methodName/ # # For aliases, one can query the original # definition via "info method origin" # /cls/ info method origin /methodName/ /obj/ info object method origin /methodName/ ---------------- |====================== ==== List type of a method The method +info ?object? method type+ is new in NX to obtain the type of the specified method. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- # n.a. ---------------- |[source,tcl] ---------------- /cls/ info method type /methodName/ /obj/ info object method type /methodName/ ---------------- |====================== ==== List the scope of mixin classes NX provides a richer set of introspection options to obtain information, where mixins classes are mixed into. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- /cls/ info mixinof ?-closure? ?pattern? ---------------- |[source,tcl] ---------------- # List objects, where /cls/ is a # per-object mixin /cls/ info mixinof -scope object ?-closure? \ ?pattern? ---------------- |[source,tcl] ---------------- /cls/ info instmixinof ?-closure? ?pattern? ---------------- |[source,tcl] ---------------- # List classes, where /cls/ is a per-class mixin /cls/ info mixinof -scope class ?-closure? \ ?pattern? ---------------- |[source,tcl] ---------------- # n.a. ---------------- |[source,tcl] ---------------- # List objects and classes, where /cls/ is # either a per-object or a per-class mixin /cls/ info mixinof -scope all ?-closure? \ ?pattern? ---------------- [source,tcl] ---------------- /cls/ info mixinof ?-closure? ?pattern? ---------------- |====================== ==== Check properties of object and classes Similar as noted before, NX uses rather a hierarchical approach of naming using multiple layers of subcommands). [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- /obj/ istype /sometype/ ---------------- |[source,tcl] ---------------- # Check if object is a subtype of some class /obj/ info has type /sometype/ ---------------- |[source,tcl] ---------------- /obj/ ismixin /cls/ ---------------- |[source,tcl] ---------------- # Check if object has the specified mixin registered /obj/ info has mixin /cls/ ---------------- |[source,tcl] ---------------- /obj/ isclass ?/cls/? ---------------- |[source,tcl] ---------------- # Check if object is an NX class /obj/ has type ::nx::Class # Check if object is a class in one of the # NSF object systems ::nsf::is class /obj/ ---------------- |[source,tcl] ---------------- /obj/ ismetaclass /cls/ ---------------- |[source,tcl] ---------------- # Check if class is an NX metaclass expr {[/cls/ info heritage ::nx::Class] ne ""} # Check if object is a metaclass in one of the # NSF object systems ::nsf::is metaclass /obj/ ---------------- |[source,tcl] ---------------- # n.a. ---------------- |[source,tcl] ---------------- # Check if object is a baseclass of an object system ::nsf::is baseclass /obj/ ---------------- |[source,tcl] ---------------- # n.a. ---------------- |[source,tcl] ---------------- # Return name of object (without namespace prefix) /obj/ info name ---------------- |[source,tcl] ---------------- /obj/ object::exists /obj/ ---------------- |[source,tcl] ---------------- # Check for existence of object (nsf primitive) ::nsf::object::exists /obj/ ---------------- |====================== ==== Call-stack Introspection Call-stack introspection is very similar in NX and XOTcl. NX uses for subcommand the term +current+ instead of +self+, since +self+ has a strong connotation to the current object. The term +proc+ is renamed by +method+. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- self ---------------- |[source,tcl] ---------------- self ---------------- [source,tcl] ---------------- current object ---------------- |[source,tcl] ---------------- self class ---------------- |[source,tcl] ---------------- current class ---------------- |[source,tcl] ---------------- self args ---------------- |[source,tcl] ---------------- current args ---------------- |[source,tcl] ---------------- self proc ---------------- |[source,tcl] ---------------- current method ---------------- |[source,tcl] ---------------- self callingclass ---------------- |[source,tcl] ---------------- current calledclass ---------------- |[source,tcl] ---------------- self callingobject ---------------- |[source,tcl] ---------------- current callingobject ---------------- |[source,tcl] ---------------- self callingproc ---------------- |[source,tcl] ---------------- current callingmethod ---------------- |[source,tcl] ---------------- self calledclass ---------------- |[source,tcl] ---------------- current calledclass ---------------- |[source,tcl] ---------------- self calledproc ---------------- |[source,tcl] ---------------- current calledmethod ---------------- |[source,tcl] ---------------- self isnextcall ---------------- |[source,tcl] ---------------- current isnextcall ---------------- |[source,tcl] ---------------- self next ---------------- |[source,tcl] ---------------- # Returns method-handle of the # method to be called via "next" current next ---------------- |[source,tcl] ---------------- self filterreg ---------------- |[source,tcl] ---------------- # Returns method-handle of the # filter method current filterreg ---------------- |[source,tcl] ---------------- self callinglevel ---------------- |[source,tcl] ---------------- current callinglevel ---------------- |[source,tcl] ---------------- self activelevel ---------------- |[source,tcl] ---------------- current activelevel ---------------- |====================== === Other Predefined Methods [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- /obj/ requireNamespace ---------------- |[source,tcl] ---------------- /obj/ require namespace ---------------- |[source,tcl] ---------------- # n.a. ---------------- |[source,tcl] ---------------- /obj/ require method ---------------- |====================== === Dispatch, Aliases, etc. todo: to be done or omitted === Assertions In contrary to XOTcl, NX provides no pre-registered methods for assertion handling. All assertion handling can e performed via the Next Scripting primitive +nsf::method::assertion+. [options="header",cols="asciidoc,asciidoc",frame="none",valign="middle"] |====================== |XOTcl |Next Scripting Language |[source,tcl] ---------------- /obj/ check /checkoptions/ ---------------- |[source,tcl] ---------------- ::nsf::method::assertion /obj/ check /checkoptions/ ---------------- |[source,tcl] ---------------- /obj/ info check ---------------- |[source,tcl] ---------------- ::nsf::method::assertion /obj/ check ---------------- |[source,tcl] ---------------- /obj/ invar /conditions/ ---------------- |[source,tcl] ---------------- ::nsf::method::assertion /obj/ object-invar /conditions/ ---------------- |[source,tcl] ---------------- /obj/ info invar ---------------- |[source,tcl] ---------------- ::nsf::method::assertion /obj/ object-invar ---------------- |[source,tcl] ---------------- /cls/ instinvar /conditions/ ---------------- |[source,tcl] ---------------- ::nsf::method::assertion /cls/ class-invar /conditions/ ---------------- |[source,tcl] ---------------- /cls/ info instinvar ---------------- |[source,tcl] ---------------- ::nsf::method::assertion /cls/ class-invar ---------------- |[source,tcl] ---------------- /cls/ invar /conditions/ ---------------- |[source,tcl] ---------------- ::nsf::method::assertion /cls/ object-invar /conditions/ ---------------- |[source,tcl] ---------------- /cls/ info invar ---------------- |[source,tcl] ---------------- ::nsf::method::assertion /cls/ object-invar ---------------- |====================== === Method Protection As described <>, NX supports method protection via the method modifiers `protected` and `public`. A protected method can be only called from an object of that class, while public methods can be called from every object. The method protection can be used to every kind of method, such as e.g. scripted methods, aliases, forwarders, or accessors. For invocations, the most specific definition (might be a mixin) is used for determining the protection. == Incompatibilities between XOTcl 1 and XOTcl 2 === Resolvers The resolvers (variable resolvers, function resolvers) of the Next Scripting Framework are used as well within XOTcl 2. When variable names or method names starting with a single colon are used in XOTcl 1 scripts, conflicts will arise with the resolver. These names must be replaced. === Parameters The following changes for parameters could be regarded as bug-fixes. ==== Parameter usage without a value In XOTcl 1, it was possible to call a parameter method during object creation via the dash-interface without a value (in the example below `-x`). [source,tcl] ---------------- # XOTcl example Class Foo -parameter {x y} Foo f1 -x -y 1 ---------------- Such cases are most likely mistakes. All parameter configurations in XOTcl 2 require an argument. ==== Ignored Parameter definitions In XOTcl 1, a more specific parameter definition without a default was ignored when a more general parameter definition with a default was present. In the example below, the object `b1` contained in XOTcl 1 incorrectly the parameter `x` (set via default from `Foo`), while in XOTcl 2, the variable won't be set. [source,tcl] ---------------- # XOTcl example Class Foo -parameter {{x 1}} Class Bar -superclass Foo -parameter x Bar b1 ---------------- ==== Changing classes and superclasses NX does not define the methods +class+ and +superclass+ (like XOTcl), but allows one to alter all object/class relations (including class/superclass/object-mixin/...) +nsf::relation::set+. The class and superclass can be certainly queried in all variants with +info class+ or +info superclasses+. [source,tcl] ---------------- # NX example nx::Class create Foo Foo create f1 # now alter the class of object f1 nsf::relation::set f1 class ::nx::Object ---------------- ==== Overwriting procs/methods with objects and vice versa NSF is now more conservative on object/method creation. In contrary to XOTcl 1 NSF does not allow one to redefined a pre-existing command (e.g. "set") with an object and vice versa. Like in XOTcl 1, preexisting objects and classes con be redefined (necessary for reloading objects/classes in a running interpreter). ==== Info heritage +info heritage+ returns in XOTcl 1 the transitive superclass hierarchy, which is equivalent with +info superclasses -closure+ and therefore not necessary. In XOTcl 2 (and NX), +info heritage+ includes as well the transitive per-class mixins. === Slots All slot objects (also XOTcl slot objects) are now next-scripting objects of baseclass `::nx::Slot`. The name of the experimental default-setter `initcmd` was changed to `defaultcmd`. Code directly working on the slots objects has to be adapted. === Obsolete Commands Parameter-classes were rarely used and have been replaced by the more general object parameterization. Therefore, `cl info parameterclass` has been removed. === Stronger Checking The Next Scripting Framework performs stronger checking than XOTcl 1 For example, the requiredness of slots in XOTcl 1 was just a comment, while XOTcl 2 enforces it. === Exit Handlers The exit handler interface changed from a method of `::xotcl::Object` into the Tcl command `::nsf::exithandler`: [source,tcl] ---------------- # NX example ::nsf::exithandler set|get|unset ?arg? ---------------- ./nsf2.4.0/doc/make-xotcl.html000644 000766 000024 00000001464 12161565463 016705 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/lib/make.xotcl

    ./library/lib/make.xotcl ./library/lib/make.xotcl


    Package/File Information

    No package provided/required

    Filename: ./library/lib/make.xotcl




    Back to index page.

    ./nsf2.4.0/doc/ftp-xotcl.html000644 000766 000024 00000001730 12161565464 016556 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/comm/ftp.xotcl

    ./apps/comm/ftp.xotcl ./apps/comm/ftp.xotcl


    Package/File Information

    No package provided/required

    Filename: ./apps/comm/ftp.xotcl

    Description: A tiny FTP client



    Back to index page.

    ./nsf2.4.0/doc/simpleFilters-xotcl.html000644 000766 000024 00000002361 12161565464 020610 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/scripts/simpleFilters.xotcl

    ./apps/scripts/simpleFilters.xotcl ./apps/scripts/simpleFilters.xotcl


    Package/File Information

    No package provided/required

    Filename: ./apps/scripts/simpleFilters.xotcl

    Description: Some simple examples of (inst)filters taken from the paper 'Filters as a Language Support for Design Patterns in Object-Oriented Scripting Languages'. They demonstrate filters, filter chains and filter inheritance.



    Back to index page.

    ./nsf2.4.0/doc/Script-xotcl.html000644 000766 000024 00000003611 12161565463 017230 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/lib/Script.xotcl

    ./library/lib/Script.xotcl ./library/lib/Script.xotcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./library/lib/Script.xotcl

    Description: A small package to instantiate an object, that represents a script.


    Class: Script

    Class: Class
    Description: An object of type Script becomes automatically the command line arguments evaluated as "-" method calls during creation, e.g.
    	    Script s -set r 5
    	    
    and a call with cmd-line "-set v 6" of the script, results in an object s with two vars set: r to 5, and v to 6.



    Back to index page.

    ./nsf2.4.0/doc/Class.man000644 000766 000024 00000047142 13523544304 015512 0ustar00neumannstaff000000 000000 [comment {-*- Tcl -*- nx::Class manpage}] [include version.inc] [manpage_begin nx::Class 3 [vset VERSION]] [comment {For the time being, we do not render keywords & terms; and the corresponding reverse index}] [proc keywords args {}] [proc term v {return $v}] [keywords "base metaclass"] [keywords NX] [keywords "mixin class"] [keywords "re-classification"] [keywords "submethod"] [keywords "method ensemble"] [keywords "linearization"] [keywords "filter specification"] [keywords "metaclass"] [vset SCOPE "class"] [vset CMD "cls"] [vset MODIFIER ""] [copyright {2014-2019 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3.0 Austria license (CC BY 3.0 AT).}] [titledesc {API reference of the base-metaclass of the NX objectsystem}] [moddesc {NX API}] [description] [para] [cmd nx::Class] is the [term "base metaclass"] of the [term NX] object system. All classes (e.g. [emph cls]) are (direct or indirect) instances of [cmd nx::Class]. Therefore, the methods provided by [cmd nx::Class] are available to all classes. A class [emph cls] which does not have [cmd nx::Class] as its direct or indirect superclass is referred to as an [emph "application class"]. By default, when instantiating a new class from [cmd nx::Class], it becomes an application class with [cmd nx::Object] being set as its superclass. A class [emph cls] which is explicitly declared as a (direct or indirect) subclass of [cmd nx::Class] is referred to as a [emph metaclass], that is, its instances will become classes as well. In other words, a metaclass instantiates and subclasses [cmd nx::Class] at the same time. [example { +---------+ | ::nx::* | +---------+--------------------------------------Y | | | instance of | | .-------. | | +--------'+ instance of +----------+ | | | |<....................| | | | | Class | | Object | | | | |....................>| | | | +---------+ subclass of +-----+----+ | | ^ ^ ^ | \...|...|................................|......./ | | | | |subclass.....(xor)......subclass| | |of +-----------+ of| | |.........| |..........| | (metaclass) | /cls/ | (application class) |.............| | instance of +-----------+ }] Classes can be created in the following ways: [list_begin definitions] [call [cmd nx::Class] [method create] [arg cls] [opt "[option -superclasses] [arg superClassNames]"] [opt "[option -mixins] [arg mixinSpec]"] [opt "[option -filters] [arg filterSpec]"] [opt "[arg option] [arg value] ..."] [opt [arg initBlock]]] To create a class having the explicit name [arg cls], use [method create]. [call [cmd nx::Class] [method new] [opt "[option -superclasses] [arg superClassNames]"] [opt "[option -mixins] [arg mixinSpec]"] [opt "[option -filters] [arg filterSpec]"] [opt [arg initBlock]]] To create a class having an automatically assigned, implicit name, use [method new]. [list_end] The configuration options for direct and indirect instances of [cmd nx::Class], which can be passed when calling [method create] and [method new], are documented in the subsequent section. [section {Configuration Options for Instances of nx::Class}] [para] Configuration options can be used for configuring objects during their creation by passing the options as non-positional arguments into calls of [method new] and [method create] (see [cmd nx::Class]). An existing object can be queried for its current configuration using [method cget] and it can be re-configured using [method configure]. [list_begin options] [opt_def -superclasses [opt [arg superClassNames]]] If [arg superClassNames] is not specified, returns the superclasses of the class. If provided, the class becomes the subclass of [arg superClassNames]. [opt_def -filters [opt [arg filterSpecs]]] Retrieves the list of filter methods currently active on instances of the class, if [arg filterSpecs] is not set. Otherwise, activates a list of filter methods for the instances of the class. Filters are returned or set in terms of a list of [term "filter specification"]s. [opt_def -mixins [opt [arg mixinSpecs]]] Returns the list of [term "mixin class"]es currently active on instances of the class, if [arg mixinSpecs] is not specified. Otherwise, the class is extended by the list of [term "mixin class"]es provided by [arg mixinSpecs]. [term "mixin class"]es are returned or set in terms of a list of [term "mixin specification"]s. [list_end] The configuration options provided by [cmd nx::Object] are equally available because an application class [arg cls] is an indirect instance of [cmd nx::Object]. [section {Methods for Instances of nx::Class}] [list_begin commands] [cmd_def alias] [list_begin definitions] [include alias.man.inc] [list_end] [cmd_def __class_configureparameter] [list_begin definitions] [def "[arg cls] [method "__class_configureparameter"]"] Computes and returns the configuration options available for [arg cls] instances, to be consumed as method-parameter specification by [method configure]. [list_end] [cmd_def create] [list_begin definitions] [call [arg cls] [method create] [arg instanceName] [opt "[arg option] [arg value] [arg option] [arg value] ..."]] This factory method creates an instance [arg instanceName] of [arg cls] and returns [arg instanceName]. [example { % nx::Class create AClass { :method init args { next }; # initialization method for instances of 'AClass' }; # defines a class 'AClass' being an instance of 'nx::Class' ::AClass % ::AClass create anInstance; # defines an object 'anInstance' being an instance of 'AClass' ::anInstance % ::anInstance info class ::AClass % ::AClass info class ::nx::Class }] [method create] accepts the configuration options [arg option] available for this instance, such as those defined by properties of [arg cls] (see [method "property"]). [para] Note that [method create] is called internally when defining an instance of [arg cls] using [method new]. [para] By calling [method create] on [cmd nx::Class] itself, the created instance will become a new application class [arg instanceName] on which [method create] can also be applied (i.e., it can be instantiated). If the so-created class has [cmd ::nx::Class] its direct or indirect superclass, [arg instanceName] is referred to as a [term "metaclass"]; that is, a class whose instances are again classes. [list_end] [cmd_def delete] [list_begin definitions] [include delete.man.inc] [list_end] [cmd_def filters] [list_begin definitions] [include filter.man.inc] [list_end] [cmd_def forward] [list_begin definitions] [include forward.man.inc] [list_end] [cmd_def info] A collection of introspection submethods on the structural features (e.g. configuration options, superclasses) and the behavioral features (e.g. methods, [term "filter"]s) provided by [arg cls] to its instances. [list_begin definitions] [call [arg cls] [method "info heritage"] [opt [arg pattern]]] If [arg pattern] is omitted, returns the list of object names of all the direct and indirect superclasses and [emph per-class] [term "mixin class"]es of [arg cls], in their order of precedence, which are active for instances of [arg cls]. If [arg pattern] is specified, only superclasses and [term "mixin class"]es whose names match [arg pattern] will be listed (see [cmd "string match"]). [call [arg cls] [method "info instances"] [opt [option -closure]] [opt [arg pattern]]] If [arg pattern] is not specified, returns a list of the object names of all the direct instances of [arg cls]. If the [term "switch"] [option -closure] is set, indirect instances are also returned. A direct instance is created by using [method create] or [method new] on [arg cls], an indirect instance was created from a direct or indirect subclass of [arg cls]. If [arg pattern] is specified, only instances whose names match [arg pattern] will be listed (see [cmd "string match"]). [call [arg cls] [method "info mixinof"] [opt [option -closure]] [opt "[option -scope] [arg option]"] [opt [arg pattern]]] If [arg pattern] is not specified, returns a list of the object names of all the objects for which [arg cls] is active as a direct [term "mixin class"]. If the [term "switch"] [option -closure] is set, objects which have [arg cls] as an indirect [term "mixin class"] are also returned. If [arg pattern] is specified, only objects whose names match [arg pattern] will be listed (see [cmd "string match"]). Valid values of [arg option] are [const all], [const object], and [const class]. Passing [const object] will have only objects returned which have [arg cls] as [emph per-object] [term "mixin class"]. Passing [const class] will have only classes returned which have [arg cls] as [emph per-class] [term "mixin class"]. [const all] (the default) will have contained both in the returned list. [call [arg cls] [method "info subclasses"] [opt [option -closure]] [opt [option -dependent]] [opt [arg pattern]]] If [arg pattern] is not specified, returns a list of the object names of the direct subclasses of [arg cls]. If the [term "switch"] [option -closure] is set, indirect subclasses are also returned. If the [term "switch"] [option -dependent] is on, indirect subclasses introduced by [term "mixin class"] relations of subclasses of [arg cls] are also reported. [option -closure] and [option -dependent] are mutually exclusive. If [arg pattern] is specified, only subclasses whose names match [arg pattern] will be listed (see [cmd "string match"]). [call [arg cls] [method "info superclasses"] [opt [option -closure]] [opt [arg pattern]]] If [arg pattern] is not specified, returns a list of the object names of all direct superclasses of [arg cls]. If the [term "switch"] [option -closure] is set, indirect superclasses will also be returned. If [arg pattern] is specified, only superclasses whose names match [arg pattern] will be listed (see [cmd "string match"]). [include info.man.inc] [list_end] [cmd_def method] [list_begin definitions] [include method.man.inc] [list_end] [cmd_def mixins] [list_begin definitions] [include mixin.man.inc] [list_end] [cmd_def new] [list_begin definitions] [call [arg cls] [method new] [opt "[option "-childof"] [arg parentName]"] [opt "[arg option] [arg value] [arg option] [arg value] ..."]] A factory method to create autonamed instances of [arg cls]. It returns the name of the newly created instance. For example: [example { % nx::Class create AClass; # defines a class 'AClass' being an instance of 'nx::Class' ::AClass % set inst [::AClass new]; # defines an autonamed object being an instance of 'AClass' ::nsf::__#0 % $inst info class ::AClass }] The factory method will provide computed object names of the form, e.g. [const ::nsf::__#0]. The uniqueness of generated object names is guaranteed for the scope of the current Tcl interpreter only. [para] It is a frontend to [method create] which will be called by [method new] once the name of the instance has been computed, passing along the arguments [arg option] to [method new] as the configuration options (see [method create]). [para] If [option -childof] is provided, the new object will be created as a nested object of [arg parentName]. [arg parentName] can be the name of either an existing NX object or an existing Tcl namespace. If non-existing, a Tcl namespace [arg parentName] will be created on the fly. [list_end] [cmd_def property] [list_begin definitions] [call [arg cls] [method property] [opt "[option -accessor] [const public] | [const protected] | [const private]"] [opt "[option -class] [arg className]"] [opt "[option -configurable] [arg trueFalse]"] [opt [option -incremental]] [opt "[option -trace] [const set] | [const get] | [const default]"] [arg spec] [opt [arg initBlock]]] [include property.man.inc] [list_end] [cmd_def require] [list_begin definitions] [include require.man.inc] [list_end] [cmd_def variable] [list_begin definitions] [comment {::nx::Object variable ?-accessor /value/? ?-incremental? ?-class /value/? ?-configurable /boolean/? ?-initblock /value/? ?-nocomplain? /spec/ ?/defaultValue/?}] [call [arg cls] [method variable] [opt "[option -accessor] [const public] | [const protected] | [const private]"] [opt [option -incremental]] [opt "[option -class] [arg className]"] [opt "[option -configurable] [arg trueFalse]"] [opt "[option -initblock] [opt "[option -trace] [const set] | [const get] | [const default]"] [arg script]"] [arg spec] [opt [arg defaultValue]]] [include variable.man.inc] [list_end] [list_end] [section {Object Life Cycle}] [cmd nx::Class] provides means to control important stages through which an NX object passes between and including its creation and its destruction: allocation, recreation, deallocation. [example { /cls/->create(/instance/) .---------------. exists? [false] .----------------. .-------------------. ---->|Class::create()|----><>---------------->|Class::__alloc()|-----------><>---->|Object::configure()| `---------------' | (1) `----------------' ^ (3) `---------+---------' [true] | | | (4) | .-------------------. | .------------------. `->|Class::__recreate()|-------------------------' |/instance/->init()| (2) `-------------------' `------------------' /instance/->destroy() .-----------------. .------------------. ---->|Object::destroy()|---->|Class::__dealloc()| `-----------------' (5) `------------------' }] Object creation is controlled by the factory method [method create], provided by [cmd nx::Class] to its instance [arg cls]. [method create] produces a new object [arg instance] as an instance of [arg cls] in a number of steps. [list_begin enumerated] [enum] If [arg instance] does not represent an existing object, an internal call to [method "__alloc"], provided by [cmd nx::Class], runs the [emph {allocation}] procedure for a fresh [arg instance] of [arg cls]. [enum] If [arg instance] corresponds to an existing object, the [emph {recreation}] procedure is triggered by calling [method "__recreate"] defined by [cmd nx::Class]. [enum] The newly allocated or recreated object [arg instance] is then configured by dispatching [method configure], provided by [cmd nx::Object], which consumes the configuration options passed into [method create]. This will establish the instance's initial state, e.g. by setting object variables and object relations according to the configuration options and corresponding default values. [enum] Finally, the initialization method [method init] is dispatched, if available for [arg instance]. [method "init"] can be defined by [arg cls] on behalf of its instance [arg instance], e.g. to lay out a class-specific initialization behavior. [example_begin] % nx::Class create Foo {:property x} % Foo method init {} {set :y [lb]expr {${:x} + 1}[rb]} % Foo public method bar {} {return ${:y}} % Foo create f1 -x 101 % f1 cget -x 101 % f1 bar 102 [example_end] Alternatively, the object [arg instance] may define a per-object [method init] on its own. A per-object [method init] can be chained to a class-level [method init] using [cmd nx::next], just like a regular method. [para] Note that the definition of an [method init] method must contain an empty parameter specification, since [method init] is always called with an empty argument list. [list_end] Object destruction, such as triggered by an application-level [method destroy] call (5), is finalized by [method {__dealloc}] offered by [cmd nx::Class]. [para] In the following, the three built-in procedures --- allocation, recreation, and deallocation --- are explained: [list_begin itemized] [item] [emph {Allocation}]: [method "__alloc"] creates a blank object [arg instance] as an instance of [arg cls] and returns the fully-qualified [arg instance]. [method __alloc] is primarily used internally by [method create] to allocate a Tcl memory storage for [arg instance] and to register [arg instance] with the Tcl interpreter as a new command. [item] [emph {Recreation}]: Recreation is the NX scheme for resolving naming conflicts between objects: An object is requested to be created using [method create] or [method new] while an object of an identical object name, e.g. [arg instance], already exists: [example { % Object create Bar ::Bar % Object create Bar; # calls Object->__recreate(::Bar, ...) ::Bar }] In such a situation, the built-in [method "__recreate"] first unsets the object state (i.e., Tcl variables held by the object) and removes relations of the object under recreation with other objects. Then, second, standard object initialization is performed by calling [method configure] and [method init], if any. [para] Alternatively, recreation will be performed as a sequence of [method destroy] and [method create] calls in the following recreation scenarios: [list_begin itemized] [item] An existing class is requested to be recreated as an object. [item] An existing object is requested to be recreated as a class. [example { % Object create Bar ::Bar % Class create Bar; # calls Bar->destroy() & Class::create(::Bar, ...) }] [item] An object of an object system other than NX (e.g. XOTcl2) is asked to be recreated. [list_end] [item] [emph {Deallocation}]: [method __dealloc] marks an instance [arg instance] of [arg cls] for deletion by returning its Tcl memory representation to the Tcl memory pool and by unregistering the corresponding Tcl command with the Tcl interpreter. [para] Beware that [method __dealloc] does not necessarily cause the object to be deleted immediately. Depending on the lifecycle of the object's environment (e.g. the Tcl interp interpreter, the containing namespace) and on call references down the callstack, the actual memory freeing/returning operation may occur at a later point. [list_end] The three methods [method __alloc], [method __recreate], and [method __dealloc] are internally provided and internally called. By default, they are not part of the method interface of [arg cls] and cannot be called directly by clients of [arg cls]. In addition, [method __alloc], [method __recreate], and [method __dealloc] are protected from redefinition by a script. [para] To extend or to replace the built-in allocation, recreation, and deallocation procedure, the methods [method __alloc], [method __recreate], and [method __dealloc] can be refined by providing a custom method implementation: [list_begin itemized] [item] as a per-object method of [arg cls]; [item] as a method of a per-object [term "mixin class"] extending [arg cls]; [item] as a method of a per-class [term "mixin class"] extending [cmd nx::Class]; [item] as a method of a subclass specializing [cmd nx::Class], from which [arg cls] is to be instantiated. [list_end] This custom implementation can redirect to the built-in [method __alloc], [method __recreate], and [method __dealloc], respectively, by using [cmd nx::next]. By providing such a custom implementation, [method __alloc], [method __recreate], and [method __dealloc], respectively, become available as callable methods of [arg cls]: [list_begin definitions] [def "[arg cls] [method "__alloc"] [arg instance]"] [def "[arg cls] [method "__recreate"] [arg instance] [opt "[arg arg] ..."]"] [def "[arg cls] [method "__dealloc"] [arg instance]"] [list_end] [manpage_end] ./nsf2.4.0/doc/info.man.inc000644 000766 000024 00000016333 12776662115 016160 0ustar00neumannstaff000000 000000 [comment {-*- tcl -*- manpage fragment for "info *" subset shared by nx::Object and nx::Class }] [keywords "method filter"] [keywords "submethod"] [keywords "parameter specification"] [keywords "type specification"] [keywords "method handle"] [keywords "method path"] [call [arg [vset CMD]] [method {info info}] [opt [option "-asList"]]] Returns the available [term "submethod"]s of the [method info] [term "method ensemble"] for [arg [vset CMD]], either as a pretty-printed string or as a Tcl list (if the [term "switch"] [option -asList] is set) for further processing. [call [arg [vset CMD]] [method "info [vset MODIFIER] filters"] [opt [option -guards]] [opt [arg pattern]]] If [arg pattern] is omitted, returns all filter names which are defined by [arg [vset CMD]]. By turning on the [term switch] [option -guards], the corresponding guard expressions, if any, are also reported along with each filter as a three-element list: [arg filterName] -guard [arg guardExpr]. By specifying [arg pattern], the returned filters can be limited to those whose names match [arg patterns] (see [cmd "string match"]). [call [arg [vset CMD]] [method "info [vset MODIFIER] method"] [arg option] [arg methodName]] This introspection [term "submethod"] provides access to the details of [arg methodName] provided by [arg [vset CMD]]. If [arg methodName] is not the name of an existing method, an empty string is returned. To disambiguate between a non-existing method and an empty string as valid return value (e.g., for [method "info [vset MODIFIER] method args|parameters|args|..."]), use [method "info [vset MODIFIER] method exists"]. [para] Permitted values for [arg option] are: [list_begin itemized] [item] [const args] returns a list containing the parameter names of [arg methodName], in order of the method-parameter specification. [item] [const body] returns the body script of [arg methodName]. [item] [const callprotection] returns the call-protection level set for [arg methodName]; possible values: [const public], [const protected], [const private]. [item] [const debug] returns 1 if [arg methodName] is in debug mode, 0 otherwise. [item] [const definition] returns a canonical command list which allows for (re-)define [arg methodName]. [item] [const definitionhandle] returns the [term "method handle"] for a [term "submethod"] in a [term "method ensemble"] from the perspective of [arg [vset CMD]] as method provider. [arg methodName] must contain a complete [term "method path"]. [item] [const deprecated] returns 1 if [arg methodName] is deprecated, 0 otherwise. [item] [const exists] returns 1 if there is a [arg methodName] provided by [arg [vset CMD]], returns 0 otherwise. [item] [const handle] returns the [term "method handle"] for [arg methodName]. [item] [const origin] returns the aliased command if [arg methodName] is an [term "alias method"], or an empty string otherwise. [item] [const parameters] returns the [term "parameter specification"] of [arg methodName] as a list of parameter names and type specifications. [item] [const registrationhandle] returns the [term "method handle"] for a [term "submethod"] in a [term "method ensemble"] from the perspective of the method caller. [arg methodName] must contain a complete [term "method path"]. [item] [const returns] gives the [term "type specification"] defined for the return value of [arg methodName]. [item] [const submethods] returns the names of all [term "submethod"]s of [arg methodName], if [arg methodName] is a [term "method ensemble"]. Otherwise, an empty string is returned. [item] [const syntax] returns the method parameters of [arg methodName] as a concrete-syntax description to be used in human-understandable messages (e.g., errors or warnings, documentation strings). [item] [const type] returns whether [arg methodName] is a [emph scripted] method, an [emph alias] method, a [emph forwarder] method, or a [emph setter] method. [comment { [item] [const object] [item] [const nsfproc] [item] [const builtin] denotes methods provided a [term "baseclass"]; }] [list_end] [call [arg [vset CMD]] [method "info [vset MODIFIER] methods"] [opt "[option -callprotection] [arg level]"] [opt "[option -type] [arg methodType]"] [opt [option -path]] [opt [arg namePattern]]] Returns the names of all methods defined by [arg [vset CMD]]. Methods covered include those defined using [method "[vset MODIFIER] alias"] and [method "[vset MODIFIER] forward"]. The returned methods can be limited to those whose names match [arg namePattern] (see [cmd "string match"]). [para] By setting [option -callprotection], only methods of a certain [term "call protection"] [arg level] ([const "public"], [const "protected"], or [const "private"]) will be returned. Methods of a specific type can be requested using [option "-type"]. The recognized values for [arg methodType] are: [list_begin itemized] [item] [const scripted] denotes methods defined using [const [vset SCOPE]] [method method]; [item] [const alias] denotes [term "alias method"]s defined using [const [vset SCOPE]] [method alias]; [item] [const forwarder] denotes [term "forwarder method"]s defined using [const [vset SCOPE]] [method forward]; [item] [const setter] denotes methods defined using [cmd ::nsf::setter]; [item] [const all] returns methods of any type, without restrictions (also the default value); [comment { [item] [const object] [item] [const nsfproc] [item] [const builtin] denotes methods provided a [term "baseclass"]; }] [list_end] [call [arg [vset CMD]] [method "info [vset MODIFIER] mixins"] [opt [option -guards]] [opt [arg pattern]]] If [arg pattern] is omitted, returns the object names of the [term "mixin class"]es which extend [arg [vset CMD]] directly. By turning on the [term switch] [option -guards], the corresponding guard expressions, if any, are also reported along with each mixin as a three-element list: [arg className] -guard [arg guardExpr]. The returned [term "mixin class"]es can be limited to those whose names match [arg patterns] (see [cmd "string match"]). [call [arg [vset CMD]] [method "info [vset MODIFIER] slots"] [opt "[option -type] [arg className]"] [opt [arg pattern]]] If [arg pattern] is not specified, returns the object names of all [term "slot object"]s defined by [arg [vset CMD]]. The returned [term "slot object"]s can be limited according to any or a combination of the following criteria: First, [term "slot object"]s can be filtered based on their command names matching [arg pattern] (see [cmd "string match"]). Second, [option "-type"] allows one to select [term "slot object"]s which are instantiated from a subclass [arg className] of [cmd nx::Slot] (default: [cmd nx::Slot]). [call [arg [vset CMD]] [method "info [vset MODIFIER] variables"] [opt [arg pattern]]] If [arg pattern] is omitted, returns the object names of all [term "slot object"]s provided by [arg [vset CMD]] which are responsible for managing properties and variables of [arg [vset CMD]]. Otherwise, only [term "slot object"]s whose names match [arg pattern] are returned. [para] This is equivalent to calling: [arg [vset CMD]] [method "info [vset MODIFIER] slots"] [option -type] [cmd ::nx::VariableSlot] [arg pattern]. [para] To extract details of each [term "slot object"], use the [method info] submethods available for each [term "slot object"]. ./nsf2.4.0/doc/Storage-xotcl.html000644 000766 000024 00000024533 12161565463 017376 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/store/Storage.xotcl

    ./library/store/Storage.xotcl ./library/store/Storage.xotcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./library/store/Storage.xotcl

    Description: Simple generic storage interface for hashtable-like (persistent) storages. There are several different existing stores, including a memory storage, a GDBM storage, a SDBM storage, and a TextFile storage.
    Date: $Date: 2005/09/09 21:09:01 $


    Class: Storage

    Class: Class
    Procs/Instprocs: close, exists, firstkey, names, nextkey, open, set, someNewChildStore, unset.
    Description: Abstract storage interface class (superclass of all storages).

    Instprocs

    • open filename
      Arguments: filename: database filename (or filename base, if more than one file has to be created)
      Description: Each storage object represents exactly one database table. The db has to be opened, before it can it used. If it is not opened all other methods return errors.
      Return: empty string
    • close
      Description: Close associated database.
      Return: empty string
    • exists key
      Arguments: key: Key to be searched for.
      Description: Search for a key whether it exists or not.
      Return: 1, if key exists in the database, otherwise 0
    • set key ?value?
      Arguments: key: Key to be set.
      ?value?: Optional value that might be set
      Description: Set or query a database key in the same way as Tcl's set functions.
      Return: Key value.
    • unset key
      Arguments: key: Key to be unset.
      Description: Unset a database key in the same way as Tcl's unset functions.
      Return: empty string
    • names
      Description: Return a list of keys in the database (functions in the same way as Tcl's array names)
      Return: List of keys in the db.
    • firstkey
      Description: Start a traversal of the database, starting with any key.
      Return: Name of first key.
    • nextkey
      Description: Proceed with the db traversal. Requires a firstkey before first usage, otherwise it returns an error.
      Return: Name of next key, if one exists. Otherwise an empty string is returned.

    Procs

    • someNewChildStore
      Description: Create a childStore according to a preference list depending on which storages are available. Currently the preference list has the following order: Gdbm, Sdbm and TextFile.
      Return: name of the created storage object.



    Back to index page.

    ./nsf2.4.0/doc/object-class.png000644 000766 000024 00000141511 12501766547 017034 0ustar00neumannstaff000000 000000 PNG  IHDR^X<hiCCPICC Profilexy80ƾo}we=k Y,!$DBD<*Q)![5z\?}]sל}}> ـjYY۰0ԀP;cc}?)qX(˷;-/ӟNI  BY a F{8@|b@sS5AL[O7pdk~.~BEC?EB|oP|hL bΓ89Xjr~ @s[v&!+ 7[GJ@:80/ 0h3 ӇK#hؓ))8ӑW0J15pue689ù7xk8mDRDŖ$$%,dnvɭ+ПW஘Tܥ2AIEͨâˬǢOo@gHgkdbjbj`iYruͰ'KG$N,BheSW 7cw} Oe/%>2~2@MqM[HXhbXnWJ# r^+KQXT3=%650-_vHf蝠,l\y<T? ƋJJoa1~U~;֚4d65q6>dnazJѺ6^8CsIWWSnީg2[( NA:W4ߦ^G1~vg]l{?bbzYxykJzFɷmn})Cgew}g?ώccHf{8Qy 8%KHIBFE+E7`bw6mCU=͋S(UJ$IJ=ٗQ0>z!:E*jUeEZ:7tEd?6yfl|9֟mmW)r>㼏^rrskqLx:[c,,mAh8G\fBIEMv$~,,0nJ]IwoHeßK{tw1o$0(ZUk(J 6?n$koZm{HumqTm']t7x\{ lʰKQO gLO^x=ƙwYsA>h?4sE%e卯#+Ւonl[h}KsouAã6'XX<QT#h%R$ERPS+ч203˳xbd;dę{O@CPpHhXxDdTtLl\ }.X+j( )S)LGii*iih ?2(7L70v51274'7?X8bĺ6^u:4@;ǺלkW~1Bl^Pnp^HahiXUxu}.Dދ*BZL쵀X8&: 7%%'9KMOä̀gݔt͕C`^}~VAx}J1W QzxY{yqEb%=jjZjSp O7F45G!|EFQ٬5?cl(l ճX EOJ[;o՝SDnjQ^0o-isN,*.60 +9Qb}1EmoFhTӓmnM>ĥơ7רL#\iQGD}}t+C/P{rfl6GE_0K_YW66q[wv~Y  DtP(~B aް$X-lgk±rPGD"!D0xxcG HOc /~B$¿e+НCE~Đf5 f%ms'|L̶,L,3g Xٖ89E? 6_4f,5gIDIzJYK(Jq(+_08ԧTjZ w:Rz.1FCMy,_ e-:.qs[0f6P ]7by+VB|"CRM4 ۓw̲rd֕;URW U֨&*6;k}|ӤDOC#u7O6L̈́*}_r0_eW6emoYn'ToѼ[phcKz |O'wߚOiLJ(2 &3Sv9e'uSP3eW? SoK+VOS`SS'7?CNgΟ'0Nτ<|n;A=(j@Ow 6vdC ʁ*7񛸏 IDATx \Te5#XhhAdhjR*檡R(O֦Ɇdjglu+41Za1&͹g93 ߾k~smmmF   zFH   `Fh+   i4 @7  f f8  F H   `Fh+   i4 @7  f f8  F H   `Fh+   iJ[[[6@U 0U~ Ois>f ~nC1&0}6s;4et!`LU{ZM}4k:ZmcW X7#@"g7o!{JICn'![( `6TK/믿JWa{ +ĉj?&\ y4vVс@-iKlʖ${n\-g C+%_erȖsEx)W'@Y#7>0ZH2FV*E|*a9B ȱpU&u% !dRds%@O4R(PY2\hllܱcGSSRj~eb NDN: $o޼yC !Z$=7Iq26K#:! E}g}۝FA@M˗/s]dr 0! 8R.2/"_~a?Hcƚ(XXEZ|+4]%aW2Sri$4BK#m%i1ݑ _sSZLm审8[n]u|fa3266=DvA+M[۽ZܱF>2EYlvHKfp &`ԭ߳lILi!I/҂NkɆc~E4n_2_2^EbRR^jZ$~~Bs]T%(.)+mֆP2뉷4*10=ELIZy2@^@@AQCH#Ktn#EA 8’eKL))G\,;%yZ[F.8ViSʣvK'=P?7=]ݷU#A}W r:*1.zjyš)d2̔Jg9]ٶTJ/_dfn,l]{LGGU+xWD[&ԗ)Νk[5=ZrQ4}ZQer}Y]}!!!ں#4ΡiϞLmp &ljHKr_<! MIg/_j/]DOihh(///))/,X@}G-VNQ(*nH]apnH /S*KsR:tfѵ0E^`,]%bO洵XP!߬r^EBVa$g[oڭ0fm ӍϷ>6k-MMm1YơȨIm "尸yd w`+xZ$&ꊷ+/~eMZCRI6E ((((((((((((i !){gbE6Mpi_"h26 G.hʑȼ”4CNi^sH ;hK*\)^4dµ1: Nl034j]{ɷl0c'WJJۼZ`Y X]!MJʫgFuiq+LKmb,JgVM% GjN G6N\ųF^Tt68WZ wyYwZ.4YdMk7xrQc, /s$Odi"4e,/Mi Aʵ &iܶaAىﮟ~xBIP'OQ`Rt"&Fԫ"!1A2RBY蜓~eO{E:PJNrWLL@|XSAL9B/!%JDC3]T&$&+ML=dLIURR[7UiE &ipaaGp4RomlH  r5M+Gs\dF/\ʤYũaLn楓NX2uokel|Kr1M3~ }=[6n9YW$IoϺѸcݒӄG 78v0|}锤&YcM ,Pprν %I'I#yA&3 Kb6em~q٦IS9&(gUVe7Ӵxg ^xVAw.򌘗wN*՛f.UP$6T ~L:|*dο@)OYT&)KA6ЄPkj#hz=ΤaC?yL1G3<  &cQJr^ o5waVs'\LG 3i/ Y(%%wdzŎ6ńE瘤ֳeCITwkSneӖQCˇdb8k*.Z^W[XY@ 9=*b +_<<  DD(KtD;ho̠b( !62$5hm>WI9{՗/ St@ yAÃp0pp,3a iKԭc[Gi$=:ifSJbלvML+>Y~SYevfCLݾ?  /ZkRt՜4~)UJ~C=Ԫ.qM $Y,[4y+զ)V Vޞcfcm [\fO{h94co4I1wZzb&JL &O1@4nԵxJ E ^ N/|ÄТ?b^>ӒLg.V-N}9M'T3 7I.Dc5{uןL:QL]ӕ1vIҎR>Y XP.K]5vt?xcmьM4>nGߺ2YRޟ9;NjcGǛ(ﱼ]Q߱bѣGR=:8s~{КV'M2(g%"2(@,-&ޒF0d鵊bEdFiezYT,*e,tq~"/]4ۋ 4{[j݂hGvp[0qcWjw1L;60jcŒEW阦hYq4~⾳̿ ,"$wUh =>9;ڔVgL@2MlaE<]qj%GΕ1=|Xb8_r%T#SIɮ-SgV(9l8$< p4Z=.`?{a[Ej_sG.>_(y>?Q222XY7ʜ['&%g[u% =1xJtN4jj tq}w&9E5s$2̌=bj&~k1MG*;䚞^$f/M MeNHZ\} V 6 8X;i-_v7y6F rpP["':>%_yxxoCxyeL䫂y[H7|e֪e^L,\E_V çHb YZWegSĜKMmjIHɱĒ_sav,dJas$ӳ.ʜU{W_ vBdlŷ=kO˲K0t{TX-e/hSYLR1ַ~{߾}Ԟ%^ˋw  3lo^VܢGzC !atpҼ>X6V}S~ܥCFq^iUu?ˏc^-0U4.eJk˪*\tyaUZ`/4-]KuSs5CV(LҦONGޯ*v].Ab )_2+z" K8WmGA]""p˥"|"c3rȘΦ{VjrYp22Ģ*|{d=eQX|Oq@opUdtUٹ:'M3  Fs!G  1P&ΉMlODy~z.&>?3ƀ}Ѿv^j/H;zjp|/Rgz#)}Z`S {@@@JɓJS@g@ Ь~F:a%pW)8X P@UM &"8xHgo@@&HMDp,F-MF  Y 1Z 6@@@=kc  6 @m"g4zhA@l4D"iт$i  EYIh@@<ѳ7F   `&"8xHgo@@&HMDp,F-MF  Y 1Z 6@@@=kc  6 @m"g4zhA@l4D"iт$i  EYIh@@<ѳ7F   `&"8xHgo@@&HMDp,F-MF  Y 1Z 6@@@=kc  6 @m"g4zhA@l4D"iт$i  EYIh@@<ѳ7F   `&"8xHgo@@&HMDp,F-M2VSSS{~ A"=QOi<$&W!~xɓ'+Ja@ Ь~Fv8 t@J#"vu P@=pcH/i:٢i$X'uƌsSh VwbW^^^^3Nt|D7"ПT;SMqAAtϫZ}p]T\1h@@!Ҩܤ Cp[Oߚ0iM>ҍA@@ƈ%4,hm rlCՓkF:,u'!!}erA0Ph[Zo_L6V0puƄfvvqЬ 2iեǎz!7ED9A7@@^Sk&&tCG+&R527vŮFt ĵܨT~ ܴxБfŎ8u^cW+qN }p2+  dՂUSWCTg=>OĤFterJJj(ɎVJ  Y}"^cw46Ίg |"477 Ziȏs*pޓm SD7AXYͶb   n'oY9%_.Ĭ|5K)z\k١L8/VBLqHڻ2ԇ^;|v KQr~do+g9E8\8&[· b*-X`&{FQf8)^ų_(\IGDvP  Hդϻ{*QԐyl;;p5i4&_4հ\lnWRM(E %Fz?a6= @@'Ab؇ Xwנ9ܛ_S2`M~APՆ% ;cxIc`Ϋ  w-w*[mJUOYPtFazEaiA   @W{aȂ"zbT   FQP@@\хv    }AmH ,t@@/@2p!FY*@_4e  B .U zX}0c,=uFj/ O#zOi8Y!~tBwtז}Mw/zhLՁpwזTZ0/F zT{ ?jQ9O^~W /[,hKO%akGYj+K+ IDAT8fld:;4ZA&nn}5V~usT;~kD@빟&y-2}ij5:zo@U_=kԔg8Z=:<|бsSwiL{t'N5:xJS[}dEWة4kT7Un[;2޸$y[|8ߡC}n9qdБQ'NvrCG*Κ:>0Ї (c#BdYIU{WXFq7f 0g4p RqNT V $fU<~g,;Ѕ ĜY Ui3U"iJtT6∸seyhꇡmrG$$)hYʵsB#h2eA Z  't8(q@[FJ<]H :@Z))K[5?jtSѳE:W^')F71_wS-;.ko-d'vS ŕ 5;jy#yw??}TK [&oD8qk+OOf ÓƵnb?Sbњ4kK7DLOD`ƥc>yMMa7X3g59n!43|TDDdt493 ^$yR]vK}Bsfl)lk5^*'6ٱ="NqzFcE{x1/ă%ߧ޽WܬCFo|/'b?噉Om j"UJyy!݉O;KB%Ί~V,(rM>هߠgA#cfZ~Y^`wX*dҾsE/jxlvpRiܗî)IRWJfsFyt5WqozQ{2NLS[!z_IMh't-?ՂFzV\I:k+z<{vNJO'nqXC7ōrŗa   TiB[5kCGDztSrnuZT{VRbz1#vbk0Wt| |om~ 2` WL+'pZid!S 71٢*0G]Ќ5ۓ$.<5*%iY蜺ܩ__\g#RģX̧yԽ5EIJUP+>agLA¦}UtP   NCi:"Qn9ٲ%ً2N-5,h^Y+O}[}U7o bNͪ<ɳ%aĘ0EDtzG-lkPLC w-i֜qEQغޡq0jl$%ini$H\NϙCpZ/l gjk>1{rٹ,(,2(sҿYtC=xt/[M呯~9xS5.~御zk ֨8.Os`Up0Ӏa'F;N>]QQq7Y n &i6: kyDߔx}%%P]]M~<[oƍPRz1HcvZO-^>8)+li={FRWW/13$59pXG @~FYuSHhbء@DDĜ9s4},+++--㏓|}}KCCC`[k>A:!i6>|QfΜ)˛⊠ ^w}tm@@رciI]IV$UW]eU V \  23ׯo_ 9 o#bbbyXxa\GKx?ˊѵl{$@GC ?\d 9 0[n4i}ݐNap^ii5ږVG.4gxA7E^kΞg׵cƒ ],VaA#DŽKn0S/uŋ ZL&L^nԖ~zy qLhեǎz!7ED̚j-m}i9~B0jIp*8/iӦ=s,**{+)kt߮Rz)/k?4w<X#_ХF*TY C*ª}1<.M:9W`j9/UM[[!>[;*n^i?H:߬ eRksg.5!5H,2XY'#|ȭ1)RfW .D{c:'9reU*.4tp^i ե`ĎjEq^J)qW|sҗ^]߬Ti_ 9Z<ղ]A 7\/)]5VT.[,ɎSܰ4ptb| j;c]W @G_SrrO?駟C&O }GA׸1iᆖ (W54W'X΂2Ѩ|ƨjZZ);eu oi8RTŌeҒf5Thk"{SeU4{aw'ˢ2Yڃ\kiwXtã9gNCZϟO' -Bt>r׮]:MX%Ҙ,c^\v ɀ2~'dNjAm٢J?s b@䜏+{ dxd`@ ].9/On\OaD/|>G)Vzb}L}+'?gNb~пH[ń cHUe nMqqq ubpnBQ0t?(zrT$gc'H*=nŊ7t=}< ǀV2}4=nYQ5o۽:ŨN2/x_´:+JRS<@ 9Hz};>Kp\B_N2\;Tv??UjL^xu^#,]TsJ,PsΛXTrtWN`;i^kmU]w'0}tzd+]?C}o̾]xlGGDV呃'/ u[D="NAA_*A>PÃH5Gyƙc߱MX?6h 8Ʈ*^,SrΚ5+v>b杙_oV2 CBYHl uԱpF\*@I1{R(ЈP[;M`v-Ƞ0cz,@NNPg2h@ x4_Mr}<#H>A rss#O< z.x"H'u#Np `{cHc7;4@@A h(  YuLa}iYƔ%Xq0@ܕg}bŊK.1~$Ҩ)WLn n  z-Z7tb`GQ& @f^  &MDcۻwێ?FtWЦ.6כd|xYn:  GEӎaw}2СC/^. FilMOA^?Ci<;b!oaahOpNBuO<>rQIhl{J@@qܘ1c{90@!zEư4!]G% i,HlO¤q/_cJWzlgGhWGA"(s!8**Mg8,Q2(Y".@ \O]3gp]o߼3[eFVSSSkh\E *eiV*cqx?vmz2^F䐇1 +r1vE  "Fz.k믿#hQԈJ:%\HȦaKZhE1#N[F8^Yp&kz'RDjLHRd58=ߟ={ўUҝ  UuB9r񪫮bKH'/c@~F6UfD@ u$gӘVI&iIZHȠ$-Y4ڿG{YXXHN=:mڴԃvBG6?ZR\L<%)^.7@p4R<, i rrcK]@?Tr#!dOZV`ؾq,gΜ:iY__Op[?jkO A@=6wd)]2J#ajYB@8FY@QdS1-i!-~(M"'%m4Zy,**o%K]ZZ:~x6L&idВ2Li㈕!ƪbM͹q΃>HWUUAx/&NKÕ,<"P"s%;HJIȓ~؎%@??5tPZқ('::ql[MJ@)&8l拴$f@J+(GQ`{: Z(‘A0?jJΔOLiIOKFZ"PPP@x7N0ViIOoI
x?~j„  -`IJXa9 FG;kp4%*@.C63FZ%RLI'E"ٮՅzKW|駴,X@'{ݺu?uT\{{*giIRdHK'JdPsHǜ{p4YXҒr(nqc9,I'?*/"H_J^5Mo|Ǵ5%%p,₉_{%ÖUlsV=m1?Tzt-J7nV_aUz'=[k0B_8-INZ2$%SA\T RrHQI7 nt䬑E#SG)PIޘȐMI cɠ%(fILY=ҥ u.ggg.ҵ6wuW'~W:ĦnpR|IВZr$m]|XB}ފ\UNޥ=y70O[B7N"Hi}d6E/$o,\R2#̈́lVD*fubsR; >t\JϟtΪ[Y%7XВr X&d0jӝZڳJ_ZUSܼ4' ۳Ntt.*yw |]@H#G)0=2(2]"rμK0uN{:lٲQF-'MRpn0Jٴs:2(ߞAC]i^*9%ǗFַh/UK;'S2ؔCrzG|˧%m.'˱wL=ԩS]wOvkKc I6gF}fHYP飫ݱ>c!eO,{d麅12AWN4Q \PV讔?o&\p}lSDŽ&7 Æ1 a'XM'OX@ Oiȶ Σ"˞YڤZrqVkA pe8|L,VY&[y!!OʡU lŻW!.^x766/>xG;'8~O&~Ϣ\Lʗ sМR+ WkN*hת")26clp^J0:Jwڰm£ S)eNs3F-kT* B3C;+*AAq YmC3B(7 )Rf+g볔*VQb}Ί+{8i6օOg!)d<))KȠoxbRc dff.7ST3S)*K5t $ɠ"Uv  "SWפ'srݵ4:H\ً~\cschq8Yu^,A{ISvT?Tm}EyxKiO̼wm_1%tHWA+͊ _ Wz)$e-X [ַ:b=׉kl!B^6 eA?L&`WK`,:ҳ,w-r&#@)zcjj*w*;P={CݨE:!|]։s'MŦ$73x Glik[yyꒂlLP+R-_QR*oVXq"|`XJM%U|Pm\ϖacJWb+.N/!j] S*| @wS?STn6lX7j`E,@rPmӧO;#] Zh RηJ=֖~^6w΅k6Vے2nޥnk>2djZ4Mh]gG \ok+d uG&ERaa +O|sAqT9٥o#G\c'/v!/WUU-R TFu*1nU=;~RL91:تOtѐNLQ[}P]FKh芅;oo~k۽RӨQ&t]bt9y$cՆ| Sh\ĔYy9>}ip}QqGZ7Q,;unpδoLcg ޼g7AkJ@YUl٬ocXxYPx~71&%_ZɮٙdM\HK.ɍ!+Q'(Y뢡ȻaDroqqqK57:6Fg6lު&o`HS2XWcȧ^}Ƥ9p@2lBݨ߰j;bHuIljتJo0nl.K#$d!{OǍ~L#DHL7]=k:Dog۬ի-ށlOAx.m}yٹ{0i;8+wi뫫ZC|:zE_\ jy{XL 5gho`YZ_]CSN' 9&ĖrMFok5---%%i p\  y 1bN @;Ń  Gy#S<  y 1bN @;Ń NF_~7;Y"it݉xg鍡/ۏG~AFD+/^ܵ4v|A@cc#k֬ٿ``_W:|D܊ѭv'nI.Iݰa#T N;KMMM˗/_-`wXȬwA  ]BЇ~822Gn(]#i/x1+7FќUA@, @-`@@ @=#@G}w['4zXA |GƍnΜ9Eݖmw-.G 77WR]t3fvFٕ6z=4?7p.N7oDA .Zh2l .t1aMW'@y>׮]{wF7؉0ztko6 F n31pAsυ ^zQF`e$itQ%&W-!ph @@^F{I@{^j^%iU@DkEXJuϠ_ F~DŽw}4}t7 _1*p9=ٳ~~~tG?7UX  kzzIH*zf-G̞=ǀ|#I`ЮGz = t100JDI` Ks̡zÇJzТbl.z6U 2Ws7@/4XT DСCƍ{=h[4@ h4e˖?~>"i#h܏#""6mDwe;7F3 25=m۶mZn7xCPFg"it+׿E7f;wN.Y+t `/H ⋤wy'MÁ܏)FK ;;{…﮸+.j_ E킀;GJ@ӕy1n%i}@=vM7w f nC1pzSRR2fzբ*E : S]wJ7-O?4u]'-p YN&~!䮻ڲe-B@ @9Zg$PYYy뭷3Q x8cG'}g@E 6LRˇ]dE[dQ/гgϺV[% ZW%it=~@ k] {4@@[[믿~7է6 @$ .N@v>oVT.Y޶8c sl%i]SNM4~ח_~O]vٳ'88ت32A w tcǎ͈SQQA?4|G曇zr@8H#G\oVdX #))/k?7| p_W^r%.;9k֬0@:!i6 xgxG >mw `Dp^_~%"âtb\\iE>VA$Fξ­ }AKfvs<㛮;äVw֡C֮]KW|@,@-`UO- Nn?zhGzW&LQ;|@_H#ntWlm4 &h/v[&&;`6/Bt~199X5{챈nVdtD/'5-un0zcNK* `!~ҭGh|{"CםҵRKfϞ]TT~+r@:"[HKWY&[6Imʋ|7-)Q>[KAFiَ첲2;pA>X%[(m !Hs577S&}3]d҂EZqhNJ@W\}#F| OH;O>]ZZJGV;wVN@i|!?KʧG/X!͡۷oHg}Q[LL̬YfΜI([A,B(dǰaîja 36@\ޏ@hz)8_x :p*#χ %F.x)mZ%˗vp$@aFQCwlz :z}d Cp4>q]dH<ԑV!@% !(j}/= 7/4p42c!ɰHm'̾:MccIa2ڇ͉pSO=EsӧO'Qg^yL).A>H'ޓ p4Z.K\ YZw]kg~~MiוMGGOG]Eij)J*>2i-B5L~z[6iaNA2>>w7L(R(N{ "bs"*䐦dВN0üslX ?\Rdm[ED܌W4V9sLݓ]U=*(H)ؒ v (3te {ʠ)J'>YV ;]j-պׅ_~LVu<3?uhV׹gԑ5+cn2Aҿ^&~S􏖔,"IYMa`@ !/ү]2Xr l$o~r KKƮHL=6fZx0n4Va.*=Niylof5ʖ];~#@ÞRDEsGJ2Tk$3~U}ҰF?гS~8K}7o_] B2^ YNjTm=~ƒ 'gZT]{a`%I=dT wVՎsd}^Q'=N[ UGԼNUaߔnXpVO jm&I?Ș&)s~(5|V_n 0Z5V+8!C< wU[~t~V&Ce|ǟN;^sЮ-OϠ!ud掔C,xUz^iaA?s֭|QJt])l>~~гG =vgEE=ɓ'NXh)%%Fv(JyYT08VP)mmJU[E׺ivzQttNZDQ*ɱ,bUCY弊C3TI<*ַZ[aReo}mmJLU"}vK)OcYk$3C$XcD>3?!qg}[rͷTV|X!@B(jAGMSY_ekqw}V*B+k%Io~]ų+*V;6mܹsNqV_`" '@oR<,;PS/cf4hM] >y)YQNi^sAt`M8і.Uv|']rOl.5wU%߲ ìX PR2|͟ kqj̡O÷k8dv1٬])2͑c6J-Zd}h:3j5u+*WO6/גQsBJǎW1~x h;.ݻwwqIk-%r(RR0A,Yh՞FDIsvTRO0UmK]? 8TIYY):yJMs*Zt0^=L SޢW;,tItR2g֧V~Hj9Chjd5RA 9s>͜(sD Y99I <³gm^U¢ /+M"1k{Qq ؼ7ճA_0j( W E~q$;Z;UPR\b|4 &?ȄȝQegE ɡxLS,hKAr lWŋ B &@2zҷN=999Guf27H# E6nA{4-.DM ;bΚf."t<򃺚f7-0 IDATDo>R0xX؀"pea:b?APuQ( Y\g(TXF3 AAдн4NZ'iGhx4uB"ւ25~y |`=](x]%6Cuե?|Ϳmf̩#3OQ#k̼KFz){gU6А 6X@h cPuZ[`m+1mlP+J%[fb9lJ )l`0({fyy9:%hGG.uNԕĪ0{Q³C2zuY)vqE6:@aGBi O.SEoᅬs=477?~pdTTsW$'^2;tƩBHTѰş#͠UF&e5 s2YsB1_-뫈f֖b*G?3U̳ o ({{26BbK8.kօOBT ӜUlN+wҴys{E"1-ɏ;c4=Mۤx&FӪn57|h.0o+/FxOm4@|ù6͖`r^җ2+5|J8 ^;H\mt2!8kh=-rM7ar$aX\ũuNH,cgXF8[VG3&WM]gV-Re5 ?UlmY ] Eإ~Atj@cQq}EqOkjoLqw)"S%r>;5͘=bUd_ն$"Ӝ!dYָ2{סT6 P'\B"[X|D%Ui|!-mP̖,CYl1~>7oNAIH0M35X\c_ihS]SrMH !,짮x;d[$/tѥYm^?%4R\J+H(bdn\%8f=kN<ᏦR=Iky*BC?*,KX:[g Q!Q+O]eJܛ3)Jiy\iɋYԳ^m J5G] St2MY~W_$3dL[Y;/dثHQ9BEiƒkMhA)ᖹj&g}V%P*X8QMn ކ.\sXXo~߱r^Z ծ}ᷞl}4'"YU!B⟫j3!†ٶ9;,>-:=/Ca.C\9tiʪ9*+Y39(;E[X _Р=F[[WPTkemIJlqp=@Xټ)9G@v6.DKFI* ä>,ti4?(uh#0,j8p 8y%gi .6QX"~߼pCc67 oIF CxiR-29*7 *~Xc'_uZ]k&;4isqZ!B']'Z+)~;Fv%IXFa_},#EH'buEӏͪo_*:`Ŋ䍳O[*,bsj XE//'zߩBkT 'MBFmxS[SK,9'soD%^d%kDe+"q!c6̙3SRR0{ョrÞj\gz =gL?mF"b &aΝ;=Qj~y;? Jw!<<C=L Oۻ)jlQnѺ[>o9u?W@nUZ6}][38kvм@!F$=G<{ѓ?d`2$xnNγӧc,kߟ7Or' hcGyJcR^s{zzo)^t?0:ؽ3n"##n'JM:X|յ_ y/X@/) ;SP;_x_r+|vg^ CmfKᒑFD' }+m>Wf܅1jZ^^gϞgyF žR7VEE6K۷ǖ WvM4J33YSNv"@FMըF/9_]p`n=uz¥Q#UWҭpTY"0jmǪq:e!~۪U*=Hkc魻'\[Uj ]@w/9%F$<5 ~ӟ^H(w&0ڧJv)kvԅD\m x ;>5MC#w$08jp =AǒH8 ӧOK;XBG.&cSS H ERׯ_?7Dd!M-p2:bC~-bvG,3 :"}L4:WHJ=&V;Ua~~~}Nn8X D 'Og?^.} .6 ut ]OLSI歏;K oŋq.)_xl|:(HlBPuK#nDz<@PPU{⫚_c]wg89Pq"K>#XO<b6/vkyWƞS@ I^s޽?0N}ꩧЏ!(F`͚5kǎx fDS&D`DQ.--/_,_(2-«ܞVwHq<5 C;޽'%!n!99BډɐRO*U}?Wt%itŧJu"B"x tSUC׃ѡ9Պn?H'6E}x_]!<11QBv"0 H'2eA_]Î!{t9o?? -p՞L Edwuw8M-;mkISJltzҘ؆t/_X{wDŠ@D Wڹs'KD{챵k❢ C=|ؽt1]swd~b L^T}sNrSSfzMB$ DL`Ϟ=/j5&b`0Z[O%{6!B++F^|şԯ2Ӏ꘾`%-|׎9R__#.^ƿ=bu([vMSxϟ4]{1T;ϟ6?&)Ww;L_Y [m|xCOt>,ݰegKqpȄ/ALRC|6Foڵ%i)_kwj5tڒ.EJvMnHPnC\&`c r/\^HMۏ;O>p6~-]NerrrƘ5E'@-MЂЎКЦво*6^can,ŗUcvYPםoG= '.ōb>6 v7&j+O iSLlTYuBʔ*G(צ҉UY}[sPwpCF)s"0>~zΜ9Xw78$JId旃=Fyf7})7˪?5b^RiyyTöP{%w ?<ߚ}{G߰pTY>3xq;-xQǵU&OpoSxW[|opS|``͖C S Q cLx[!3 I%/ы2{L_UV}p9b({׿'8n9QS'Vs7i~5{7 Y]ŹUbW\@O׷RY qQWoґE5{YS=Y8{7[J%g}g$ӧOGSl S[0w}Og5j)2{I%>UŦ-٪;].yHtrgyq_jא6f\ 9G݃PZ>ć`JWp`\c`NttL{ҔȤ|("@\@KK ;8ظbEN͋Ϩ[]ƗqrWz|)o dhs&5'or k ʔp Z^^SV&В.Z1[g,T_!Q,^?0sJcSx(ƨ]/)3G6ŜpY1wȝTmi!G.\$-w KVkpR%d7q$ǖR&CO>zj,&ijN]&$^*U^I%vUY]R~aݺf-5NܒEI%;woHS_/zٴq8~_YQJe%,>m}Bv*X+3_z熤 fc -rKRtvM;Hq{8~2H$]QQ~) ~湧Õ_d^6bP^lK'$}c `֍K@ccM"ov=,!+ߏeP%E_`_CB>5Rסr@{BPJw' rH'0%O&Fh!lZ g}9IeHMÙ@%pq!t޽{c׮]?O.Z1[7!@F7yTM wޔgϲڞ-% $ゑ!D`|`f t?aro00##$@8BP%ú lwY9јe#!W4Cu$ C q:aOTlJ>%ڽFF#Xb6u60PJvC9(AoW0#QN\\B"0F3gD 8e8ftF|.T*"`M?҃F~(ɔhkt?6o,Y=d46I>*#l1Cщ]Gm%ai?A*? D3qJ"@ it'H'Dq&@8@)9"@pv$D) o~SdI8))"@ IgXeOP,Bhn DpJࠏ%C:iF'}pTl"@/y1I .GرcI=X Doq 8z(̙3---NGZT'\~@u*EX"@pl8ɓ2,88رK:M4LYfӧOS=s+7p6::G/SY/3 E$//ϽLu`8"[c-TJXN D` vm8qSD"pnF"%A DTG4 ,Z2!D8/;?g/fk8NUzen8"h@uDB<=F"@p^cW[S᮫xt}ͻ@I͠s^ sWc pR T=m:/ Ǭy!JI@nɐ9!]Wߞ;MFy]PRRW 6&.(XDM+nZ!qӵiYSdԅu/g,EժJc mvw6._'$?T @՗=|{ IDATfbO7D'%[owuu4:jOSwYURm^佛:wUtky[.¯(5;ZgJJkEZC$,@91ޙEWZ){wuM,cd D8+*p +}£uR 5tKZOuZU}AgVf溎yEq-5B 9Uȡ@i,ս5*]$3vywTʗIYbt%D87{X¹k2;4v?mW3Bw eT~e TK) Ҕ ~*6,V "mbWy ?ßqB'ZSP]gpœ\ޅ_QqL++i2>ݪ4c&B"@\]z=s׺B}JGR"}0'''+Iꥪ[i_vTo\- CbcvAÓ[[[;Nz]{k$^]1M ~`|!IV"@sضm*Y饲3?|"ngYF2K'7 av͂,e.l;~FaL"cMGZ1Mk|1K?dzkKS&!MD'#jf̘A8O*Y #(Ŝ+.FQt-? KX^}0^G M())AV^=}t.A{GX= ? -dck %2x]ouQR䊨+gΞʖ&~ny`9Ŋ6cNmxr!D8#ݻwO>3~e"q2'.թx7!Y#hhYVqōE58,<@i;p׹ko q OJy߶< .е{9ۂو ##~w7tȂ;}(sUJ*?Caf{{ ^qO,{K\?-a4.܃X64f]ӆ=E#66J椘w1̒fˉ_0EI"Tq* ( 6e:(շ(YfVhP_N-U&V71lޕflZ-f[t1}OlC@L6Kٰ-=+NY-m2wOZUWKWK"@p*P[OmirǴi^s21-._,$ [.b^y ^Ӧ͟6-@g lLyo1AӐo@t׷UӒN`咰߻_Fee^&/kӼY&]|d D 84r_nmVoѾ)e4F a9,v1*TDN)ۺg]Qc8u(;askyfzO:ʳLhM`(  D8'KIq:Loo9ݏfT{јL5;OeԚ݃ mGOT1'8OoknDϫי;E-}m*)W{pfNޘ='0OR@"  D8qٳzy}C}GW_EHxT%ʔ!J@ @Wr?YUdm@M|/}"@_~ycg,s*WfPG Eӟ?"4Nw%D8)zO>7o^YYVa&i#@Np)۷oz7jۈ+C8bT"W/K,f+--?Ww4< nEף/RRR[ݪN0CժtK܍@g'[w y`䂙9sfffuI/G}tW`4kAB09ݾ*co?tqppȭ .r$DkP`l`;0B;@BD_{R_H~1k,h-idwx裏C}#I|ȗL=v= Z*Ç~oopҴsjV҈ѳ41t7}}}!0s}硗/oAin7l*4Zclްb_oX5fտu^̽r>6EUW=l@c#s  D`+fK,Y|W_}u̙ӧO#X`l8}(пn:tC3M* &;pFn-merEG+8}ot3O[lY>VaFd{ڔ %%uKhh(^_e+g0---VxywH?3)^|B@5ء`d4X?/xוJD4֤fgim^:Jczlƾ~B>efƄNNPI<#x}J0'0P;165J[1/6F~_|HCo'iӭQ&)vtpb{v9'!qZɱ܁`_5tB>qe{4Bz+&k 3έ[^̂A#G@<)oavimm((-֭+g7dã X(:MO%:VQ{4>#ڞ1b3brYWSu|dUGTwϟԵ.¢w27ZT= .5ٔh,IlakzagWF<4ϟ2ٹOŴ 6t>TB^JiI  BFV`̿eJM`1sA=CRuKP$IHz+F.V&<<3Î08YpEয়~*E1!fHY84_)*JUM,7PWQP+:5弈q\憊 т[07bWy`z~L( b!߭,_N׊R5wl7)::;tвϲܪq0n[MY>^} uk<[۟C02DL6t1a\@LbO+ض 9SZaA ĄO^)`Ԃ}X*utRюIؼ Wk׾{ bkpp0D0d#ǗFuJ (C~HEc%+ BF]d!\2$dY3]-Fij9m7:qI NxY9a߽LҍhJViX"R' S@@o=I%($V>X"RJH@AJ~ƍ555LDD."Uy얙H ljN<5 ~4b[ky(c3%kQ?UAʈu ss؅}F}(1B(С p&x .0(Jyx 9 ^c}/I AZ;U 1Td.i] ,uVP5W͘\ D`  f~*f j[\aO//9JeaLolD2`9 ~|dekzeD#D `14R\0%a[m:wMmcAS{T Ώf@5;WQeұWé_2/"@gQ(R?-ui-\jQ //(yU]^0SA ' I1ܡ/J/@Np'\ujperXnu^w6Jajiuwχ]=,p,$n;\]'LwL_&naGi,-6>G%i>=,] D4^yDd1{^B״iM PK|Qjo}_na_cqA111ӼV1Mlز *e\f\7&Sܢnȗ"@K#i:<xd[ok6Ci$,㠱_'q2o2G2eƈ|l6Gx_AqطY]'̔-8*%~{)[ )D  DL5iؗve@ 0Qaq[zQ0`NH𭨨xwrrrpZs6Hs7찈1pr=o7Ζ.΃;{ bZwk?o;7yLanI^^ރ>X+V`=8 Xa{a2,2v C\eQG\ b[˔PK7{wr(?U{ȍ"@:* D!F7|Te"@Iptȏ"@ܐI>t2 D Gq8:G nH :U"@#@8#D7$@L pviڰt;-ٰ%7iҥImVn%"@pkξHVpXY[q1y/^"{^A"@}|1+IΆE>tG NFqod~/]2ٳzL&f2ϔ"D1peyBUUiS(m%Oi$uoXl:CW$56eDqr$Hbq:2}]K++-Ty1AyYXM7D"xy\Qձɿ0ڢ%M=]5ȇ^V2sդֺ? ҿ4);̬Bp\m^佛:9))USBHv"@p+Malak@݇krb[jdA5aUao`pp0y&{]$`b;BDmBͰ/wSXxTPysNUk]˩k{"b_gJ @Qs_Z[3BlgYnUQ ޲87=cq8P8պ,ֿ_qW$6tW, _ʕVy\gFLk}5#Tx{PFWְ4+IJvP(,^q˛܈ D 84|:t)Z P9a-^eWŬ5=Vm¦o{/aԛ7F[=!p>0*=DZVyoMaNNNVC`qi(Մ> K@ށjqҨ~|2r|NU1Fjb*, Ġ8AFv>^C -sҘ64x+q_hJgYF2 }"@+pPiz*ߦ2+y}!Mε&9v :bp 4"r"D$qZv q;ww:l {꜍ۈb7/cfjij{cN D Ҩ?Dc|[f{ŃJ"@h 84&c-c D AQ;r7~Dq&bNiqPrD%fD"0H'*I NLщ"@&IDP4 D 4gy>merEGY+,Ur"@\I=DךlhQJ*"Nh@ՁLJ##PQp7kęĦu<;01}͑>JvИ2/Diu^ ahoi>yh:%CvX|%dT~|"@&qhSc6k7VJw(iYj%aLӈԅF]ݛJ̺RL hJ3~E/ʹE$Skp-HnӛrU/Eib]ݢCm̀rɸ,PT.$FD"02.B-T X d7 RS LlNթÃ=t\𴾤W5<}`HMq{U?ѐ"IXUzDUV,s=,I( m`GUZp&=)oasZg\:.#Ӫj_d?^d'DKpi̪ۻ.:dr?uYL*K;gX^|y,۵[GGE॥0>OH z̨RSʏ毌輺,K,7eB3jѯsGmX.,ː+߭2*p6\.P~ B͈a)[Q;\nQ`!D8FJ)gxx7Ó[[[;Nz]{kvUVݚpɺExe+ `海q,l8DgNڑmﳗ%9s|'X>`"džR5EU孴AD"0B߯9۪*>JH#F'g2zڱ#|e \ZEoo4v M.2ܭM_BF;|w̖h(f|1WMZ'{dc^;1!WgnH CptiTqDX5,HR͐h墫𓄂';fF-*}a 4^ZCwD"0<1>q՞7fH'Qv&Q)Or9!Jl/~\t$bJNQY3gx+V%iD,cwk{(+fK&fƜ0ϱĵ""@23Du0FПq'^}d\'R޷mYA .bY0r\?9Eamq|1Y  D\OѤn?#'ۘ.#L ̺q {L9.p,0 %裲/wO6-88%q01{,׈xʌcGWL,D"0:/*.swjǦqysJr"lL?j_{:5ebMaj%W^N?/1͚ 1A^c&B glV AJU6u 1ixwRawq"@84WjAy2͗).Oǒb6S[ {ڴi^1JWNKb}5{Tdw=f\>Qj@*Ɣ 5YT|y U^Qe՘Hi#l1UU`fQj!%/7<¸b >{"@epxib,<`:aYWq4ʟ~B~;(c3D櫈XwƸM~(X(%̉R>ae[o(!=8yH']r8q}Pm @0 UN!|5E o?Ap9~{z X{$qGU(L| Wls`<!LvW|O0qQ`e콀>QCL PX+ʈ(=w@1D2 mQd$q-S;"@ P hjJq DJSi^}"@dp\ifcf& A nMa5*VV pgC'D)!฽)A"@ i D $8"@I#} DX iA7D"@H;@ DI!D"@H"@ H-p  DF"@ @hn D4w"@F tC DD"@,4Z"@ $ D"`A"@ i D 2;Ǻ1tzD2Bn,Ax7Ba*`|2D"@FE{x m:Sݚ_NbnۚMn' D&08M0#- 00Yd fh0 f ND\^#rS}$(id :jx{Ѯ4ڼW8°b]aL4F\Eh ?6OB? ! dae:pRp|qdOtǭ5 E[T_8) *6p(/bӕ6o4{aA]pd!:+CQq! ,hhh ĕa#|aXSUlebQ"D 4@Ŷ qha " "&K"24v({Lba^q&T"SJ1!obʇ0 w"I#|W N_x+;i]/0;|Y֚[ 3˸$C`ܤRJ ۫ˈ QdW4oDap"ł/nF8ىk`s|Q\dpevL]m\HJd"6х,D\F,v ֞!rh?;I0QjESDA\ٰ* Ȯh , kH(D4U$vkeX"vv($HRH pH 2idW+X&܊m XePETgid@dve^pA  6[ŋ! ;Yt\a K&S2&ohaQ0;9"$ a`A+*L܊DI#kbS mWSL ̂?`Wz0TYw vjց_~XL.̑Aɚ @x$G&it/ qR4eycvXЌ;.h ̓W_D'Qp +&f Y(J q _ш2X0b jAxJUXCeR6 2):2 ³^#"X%NDj&|qEhh#2xFh/hPid5UU%3 KHa|]$NM \!/V$@5E;,,θ$F`Qlᰈ;3h ;<4o *\GX+ sĕa!C\ J䍩pa}G3G.7w٭+$0n҈6rC`Afu` @z@0"L^,DeVêV k,2 d}G: /Q)YDv`HvJT"0MƉ:@ۘ $…Y(CJn @kv;\XKHf1)"0F)h( SA"6c v&,n nJDu&#( Ddpe‰`0`kqLT"0S^lh L 0h"Y#pRub3Z(Z(ZaqҺS#0OR2aCjR 2\a†LU( .,DeX taUJ ##Q "kD+EjI3cD.bBRTA2%\(S"0X{A[\5vˮ8숀 ^#Oj],Rdr(0z`(2_&;EH],ى 5Z5],: [X:<&/0.O*H&Dհ: bbW% hn+. E&*?PW* ! mR;Xݺ)*kw|m]lc p+hV@D`7㘴,)#"@ L`jzLF nNzn"@5Fk"tO nNͿT}"@&@hM D 4O H= D9F7P DI5'D7'@_> DX i&BD"H @'Dk$D"@ܜID"`Mњ"@ it/U"@ 4Z{"@ps$n"@5Fk"tO nNͿT}"@&~/(2IENDB`./nsf2.4.0/doc/Object.html000644 000766 000024 00000243070 13532210305 016031 0ustar00neumannstaff000000 000000 nx::Object -

    nx::Object(3) 2.0 Object ""

    Name

    nx::Object - API reference of the base class in the NX object system

    Synopsis

    Description

    nx::Object is the base class of the NX object system. All objects defined in NX are (direct or indirect) instances of this base class. The methods provided by the nx::Object base class are available to all objects and to all classes defined in NX.

     +---------+
     | ::nx::* |
     +---------+--------------------------------------Y
     |                                                |
     |  +---------+     instance of     +----------+  |
     |  |         |<....................|          |  |
     |  |  Class  |                     |  Object  |  |
     |  |         |....................>|          |  |
     |  +----+----+     subclass of     +-----+----+  |
     |       ^                           ^    ^       |
    instance.|...........................|....|......./
          of |                           |    |
       +-----+-----+    subclass of      |    | instance
       |           |.....................|    | of
       |   /cls/   |    (by default)          |
       |           |                          |
       +-----------+                          |
             ^                                |
    instance |.............(xor)..............|
          of |         +-----------+          |
             |.........|           |..........|
                       |   /obj/   |
                       |           |
                       +-----------+
    

    NX allows for creating and for using objects (e.g. obj) which are instantiated from the base class nx::Object directly. Typical use cases are singletons and anonymous, inline objects. In such use cases, NX does not require creating an intermediate application class (e.g. cls), which specializes the base class nx::Object by default, beforehand.

    Objects (e.g. obj) which are creating by instantiating a previously defined application class (e.g. cls) are indirect instances of nx::Object.

    Direct instances of nx::Object can be created as follows:

    nx::Object create obj ?-object-mixins mixinSpec? ?-class newClassName? ?-object-filters filterSpec? ?initBlock?

    To create a direct instance of nx::Object having an explicit name obj, use create on nx::Object. Note that create is defined by nx::Class and is available to nx::Object being an instance of nx::Class. This way, singleton objects can be created, for example.

    nx::Object new ?-object-mixins mixinSpec? ?-class newClassName? ?-object-filters filterSpec? ?initBlock?

    To create a direct instance of nx::Object having an automatically assigned, implicit object name, use new on nx::Object. Note that new is defined by nx::Class and is available to nx::Object being an instance of nx::Class. Using new allows for creating anonymous, inline objects, for example.

    The configuration options for direct and indirect instances of nx::Object, which can be passed when calling create and new, are documented in the subsequent section.

    Configuration Options for Instances of nx::Object

    Configuration options can be used for configuring objects during their creation by passing the options as non-positional arguments into calls of new and create (see nx::Class). An existing object can be queried for its current configuration using cget and it can be re-configured using configure. Legal configuration options are:

    -class ?className?

    Retrieves the current class of the object or sets the object's class to className, if provided.

    -object-filters ?filterMethods?

    Retrieves the list of currently active per-object filter methods or sets a list of per-object filter methods, if filterMethods is provided.

    -object-mixins ?mixinSpecs?

    If mixinSpecs is not specified, retrieves the list of currently active per-object mixin specifications. If mixinSpecs is specified, sets a list of per-object mixin specifications to become active. mixin classes are returned or set in terms of a list of mixin specifications.

    Methods for Instances of nx::Object

    alias
    obj ?public | private | protected? object alias methodName ?-returns valueChecker? ?-frame object | method? cmdName

    Define an alias method for the given object. The resulting method registers a pre-existing Tcl command cmdName under the (alias) name methodName with the object. If cmdName refers to another method, the corresponding argument should be a valid method handle. If a Tcl command (e.g., a proc), the argument should be a fully qualified Tcl command name. If aliasing a subcommand (e.g., array exists) of a Tcl namespace ensemble (e.g., array), cmdName must hold the fully qualified subcommand name (and not the ensemble name of the subcommand).

    As for a regular object method, -returns allows for setting a value checker on the values returned by the aliased command cmdName.

    When creating an alias method for a C-implemented Tcl command (i.e., command defined using the Tcl/NX C-API), -frame sets the scope for variable references used in the aliased command. If the provided value is object, then variable references will be resolved in the context of the called object, i.e., the object upon which the alias method is invoked, as if they were object variables. There is no need for using the colon-prefix notation for identifying object variables. If the value is method, then the aliased command will be executed as a regular method call. The command is aware of its called-object context; i.e., it can resolve ::nx::self. In addition, the alias method has access to the method-call context (e.g., nx::next). If -frame is omitted, and by default, the variable references will resolve in the context of the caller of the alias method.

    cget
    obj cget configurationOption

    The method is used to obtain the current value of configurationOption for obj. The configuration options available for querying through cget are determined by the configurable properties defined by the class hierarchy of obj. The queryable configuration options for obj can be obtained by calling info configure. The configurationOption can be set and modified using configure.

    % nx::Object create obj
    ::obj
    % ::obj info configure
    ?-object-mixins /mixinreg .../? ?-class /class/? ?-object-filters /filterreg .../? ?/__initblock/?
    % ::obj cget -class
    ::nx::Object
    
    configure
    obj configure ?configurationOption value ...?

    This method sets configuration options on an object. The configuration options available for setting on obj are determined by the configurable properties defined by the class hierarchy of obj. The settable configuration options for obj can be obtained by calling info configure. Furthermore, configure is also called during object construction. Under object construction, it receives the arguments passed into calls of create and new. Options set using configure can be retrieved using cget.

    % nx::Class create Foo {:property x}
    ::Foo
    % Foo create f1 -x 101
    ::f1
    % f1 cget -x
    101
    % f1 configure -x 200
    % f1 cget -x
    200
    
    contains
    obj contains ?-withnew trueFalse? ?-object objectName? ?-class className? cmds

    This method acts as a builder for nested object structures. Object and class construction statements passed to this method as its last argument cmds are evaluated in a way so that the receiver object obj becomes the parent of the newly constructed objects and classes. This is realized by setting explicitly the namespace for constructing relatively named objects. Fully qualified object names in cmds evade the nesting.

    -withnew requests the automatic rescoping of objects created using new so that they become nested into the receiver object obj, rather than being created in the default namespace for autonamed objects (i.e., ::nsf). If turned off, autonamed objects do not become children of obj.

    The parent object objectName to be used instead of obj can be specified using -object. If this explicitly set parent object does not exist prior to calling contains, it will be created on the fly as a direct instance of nx::Object. Alternatively, using -class, a class className other than nx::Object for the on-the-fly creation of objectName can be provided.

    % nx::Class create Window {
      :contains {
        #
        # Become children of Window, implicitly
        #
        nx::Class create Header; # Window::Header
        nx::Object create Panel; # Window::Panel
      }
      #
      # Explicitly declared a child of Window using [self]
      #
      nx::Class create [self]::Slider; # Window::Slider
      #
      # Fully-qualified objects do not become nested
      #
      nx::Class create ::Door; # ::Door
    }
    ::Window
    % ::Window info children
    ::Window::Panel ::Window::Header ::Window::Slider
    
    copy
    obj copy newObjectName

    Creates a full and deep copy of a source object obj. The object's copy newObjectName features all structural and behavioral properties of the source object, including object variables, per-object methods, nested objects, slot objects, namespaces, filters, mixins, and traces.

    delete
    obj delete object feature arg

    This method serves as the equivalent to Tcl's rename for removing structural (properties, variables) and behavioral features (methods) of the object:

    obj delete object property propertyName
    obj delete object variable variableName
    obj delete object method methodName

    Removes a property propertyName, variable variableName, and method methodName, respectively, previously defined for the scope of the object.

    delete object method can be equally used for removing regular methods (see object method), an alias method (see object alias), and a forwarder method (see object forward).

    destroy
    obj destroy

    This method allows for explicitly destructing an object obj, potentially prior to obj being destroyed by the object system (e.g. during the shutdown of the object system upon calling exit):

    [nx::Object new] destroy

    By providing a custom implementation of destroy, the destruction procedure of obj can be customized. Typically, once the application-specific destruction logic has completed, a custom destroy will trigger the actual, physical object destruction via next.

    % [nx::Object create obj {
      :public method destroy {} {
        puts "destroying [self]"
        next; # physical destruction
      }
    }] destroy
    destroying ::obj
    

    A customized object-destruction scheme can be made shared between the instances of a class, by defining the custom destroy for an application class:

    % nx::Class create Foo {
        :method destroy {} {
          puts "destroying [self]"
          next; # physical destruction
        }
    }
    ::Foo
    % Foo create f1
    ::f1
    % f1 destroy
    destroying ::f1
    

    Physical destruction is performed by clearing the in-memory object storage of obj. This is achieved by passing obj into a call to dealloc provided by nx::Class. A near, scripted equivalent to the C-implemented destroy provided by nx::Object would look as follows:

    % Object method destroy {} {
      [:info class] dealloc [self]
    }
    

    Note, however, that destroy is protected against application-level redefinition. Trying to evaluate the above script snippet yields:

    refuse to overwrite protected method 'destroy'; derive e.g. a subclass!  
    

    A custom destroy must be provided as a refinement in a subclass of nx::Object or in a mixin class.

    eval
    obj eval arg ?arg ...?

    Evaluates a special Tcl script for the scope of obj in the style of Tcl's eval. There are, however, notable differences to the standard eval: In this script, the colon-prefix notation is available to dispatch to methods and to access variables of obj. Script-local variables, which are thrown away once the evaluation of the script has completed, can be defined to store intermediate results.

     
      % nx::Object create obj {
        :object property {bar 1}
        :public object method foo {x} { return $x }
      }
      ::obj
      % ::obj eval {
        set y [:foo ${:bar}]
      }
      1
    
    filters
    obj object filters submethod ?arg ...?

    Accesses and modifies the list of methods which are registered as filters with obj using a specific setter or getter submethod:

    obj object filters add spec ?index?

    Inserts a single filter into the current list of filters of obj. Using index, a position in the existing list of filters for inserting the new filter can be set. If omitted, index defaults to the list head (0).

    obj object filters clear

    Removes all filters from obj and returns the list of removed filters. Clearing is equivalent to passing an empty list for filterSpecList to object filter set.

    obj object filters delete ?-nocomplain? specPattern

    Removes a single filter from the current list of filters of obj whose spec matches specPattern. specPattern can contain special matching chars (see string match). object filters delete will throw an error if there is no matching filter, unless -nocomplain is set.

    obj object filters get

    Returns the list of current filter specifications registered for obj.

    obj object filters guard methodName ?expr?

    If expr is specified, registers a guard expression expr with a filter methodName. This requires that the filter methodName has been previously set using object filters set or added using object filters add. expr must be a valid Tcl expression (see expr). An empty string for expr will clear the currently registered guard expression for filter methodName.

    If expr is omitted, returns the guard expression set on the filter methodName defined for obj. If none is available, an empty string will be returned.

    obj object filters methods ?pattern?

    If pattern is omitted, returns all filter names which are defined by obj. By specifying pattern, the returned filters can be limited to those whose names match patterns (see string match).

    obj object filters set filterSpecList

    filterSpecList takes a list of filter specs, with each spec being itself either a one-element or a two-element list: methodName ?-guard guardExpr?. methodName identifies an existing method of obj which becomes registered as a filter. If having three elements, the third element guardExpr will be stored as a guard expression of the filter. This guard expression must be a valid Tcl expression (see expr). expr is evaluated when obj receives a message to determine whether the filter should intercept the message. Guard expressions allow for realizing context-dependent or conditional filter composition.

    Every methodName in a spec must resolve to an existing method in the scope of the object. To access and to manipulate the list of filters of obj, cget|configure -object-filters can also be used.

    forward
    obj ?public | protected | private? object forward methodName ?-prefix prefixName? ?-frame object? ?-returns valueChecker? ?-verbose? ?target? ?arg ...?

    Define a forward method for the given object. The definition of a forward method registers a predefined, but changeable list of forwarder arguments under the (forwarder) name methodName. Upon calling the forward method, the forwarder arguments are evaluated as a Tcl command call. That is, if present, target is interpreted as a Tcl command (e.g., a Tcl proc or an object) and the remainder of the forwarder arguments arg as arguments passed into this command. The actual method arguments to the invocation of the forward method itself are appended to the list of forwarder arguments. If target is omitted, the value of methodName is implicitly set and used as target. This way, when providing a fully-qualified Tcl command name as methodName without target, the unqualified methodName (namespace tail) is used as the forwarder name; while the fully-qualified one serves as the target.

    As for a regular object method, -returns allows for setting a value checker on the values returned by the resulting Tcl command call. When passing object to -frame, the resulting Tcl command is evaluated in the context of the object receiving the forward method call. This way, variable names used in the resulting execution of a command become resolved as object variables.

    The list of forwarder arguments arg can contain as its elements a mix of literal values and placeholders. Placeholders are prefixed with a percent symbol (%) and substituted for concrete values upon calling the forward method. These placeholders allow for constructing and for manipulating the arguments to be passed into the resulting command call on the fly:

    • %method becomes substituted for the name of the forward method, i.e. methodName.

    • %self becomes substituted for the name of the object receiving the call of the forward method.

    • %1 becomes substituted for the first method argument passed to the call of forward method. This requires, in turn, that at least one argument is passed along with the method call.

      Alternatively, %1 accepts an optional argument defaults: {%1 defaults}. defaults must be a valid Tcl list of two elements. For the first element, %1 is substituted when there is no first method argument which can be consumed by %1. The second element is inserted upon availability of a first method argument with the consumed argument being appended right after the second list element. This placeholder is typically used to define a pair of getter/setter methods.

    • {%@index value} becomes substituted for the specified value at position index in the forwarder-arguments list, with index being either a positive integer, a negative integer, or the literal value end (such as in Tcl's lindex). Positive integers specify a list position relative to the list head, negative integers give a position relative to the list tail. Indexes for positioning placeholders in the definition of a forward method are evaluated from left to right and should be used in ascending order.

      Note that value can be a literal or any of the placeholders (e.g., %method, %self). Position prefixes are exempted, they are evaluated as %cmdName-placeholders in this context.

    • {%argclindex list} becomes substituted for the nth element of the provided list , with n corresponding to the number of method arguments passed to the forward method call.

    • %% is substituted for a single, literal percent symbol (%).

    • %cmdName is substituted for the value returned from executing the Tcl command cmdName. To pass arguments to cmdName, the placeholder should be wrapped into a Tcl list: {%cmdName ?arg ...?}.

      Consider using fully-qualified Tcl command names for cmdName to avoid possible name conflicts with the predefined placeholders, e.g., %self vs. %::nx::self.

    To disambiguate the names of subcommands or methods, which potentially become called by a forward method, a prefix prefixName can be set using -prefix. This prefix is prepended automatically to the argument following target (i.e., a second argument), if present. If missing, -prefix has no effect on the forward method call.

    To inspect and to debug the conversions performed by the above placeholders, setting the switch -verbose will have the command list to be executed (i.e., after substitution) printed using ::nsf::log (debugging level: notice) upon calling the forward method.

    info
    obj info children ?-type className? ?pattern?

    Retrieves the list of nested (or aggregated) objects of obj. The resulting list contains the fully qualified names of the nested objects. If -type is set, only nested objects which are direct or indirect instances of class className are returned. Using pattern, only nested objects whose names match pattern are returned. The pattern string can contain special matching characters (see string match). This method allows for introspecting on contains.

    obj info class

    Returns the fully qualified name of the current nx::Class of obj. In case of re-classification (see configure), the returned class will be different from the nx::Class from which obj was originally instantiated using create or new.

    obj info has ?mixin | namespace | type? ?arg ...?
    obj info method has mixin className

    Verifies whether obj has a given nx::Class className registered as a mixin class (returns: true) or not (returns: false).

    obj info has namespace

    Checks whether the object has a companion Tcl namespace (returns: true) or not (returns: false). The namespace could have been created using, for example, object require namespace.

    obj info has type className

    Tests whether the nx::Class className is a type of the object (returns: true) or not (returns: false). That is, the method checks whether the object is a direct instance of className or an indirect instance of one of the superclasses of className.

    obj info lookup submethod ?arg ...?

    A collection of submethods to retrieve structural features (e.g. configuration options, slot objects) and behavioral features (e.g. methods, filters) available for obj from the perspective of a client to obj. Features provided by obj itself and by the classes in its current linearization list are considered.

    obj info lookup configure parameters ?namePattern?

    Returns all configuration options available for obj as a list of method-parameter definitions. They can be used, for example, to define a custom method refinement for configure. The returned configuration options can be limited to those whose names match pattern (see string match).

    obj info lookup configure syntax

    Returns all configuration options available for obj as a concrete-syntax description to be used in human-understandable messages (e.g. errors or warnings, documentation strings).

    obj info lookup filter name

    Returns the method handle for the filter method name, if currently registered. If there is no filter name registered, an empty string is returned.

    obj info lookup filters ?-guards? ?namePattern?

    Returns the method handles of all filters which are active on obj. By turning on the switch -guards, the corresponding guard expressions, if any, are also reported for each filter as a three-element list: methodHandle -guard guardExpr. The returned filters can be limited to those whose names match namePattern (see string match).

    obj info lookup method name

    Returns the method handle for a method name if a so-named method can be invoked on obj. If there is no method name, an empty string is returned.

    obj info lookup methods ?namePattern?

    Returns the names of all methods (including aliases and forwarders) which can be invoked on obj. The returned methods can be limited to those whose names match namePattern (see string match).

    obj info lookup mixins ?-guards? ?namePattern?

    Returns the object names of all mixin classes which are currently active on obj. By turning on the switch -guards, the corresponding guard expressions, if any, are also reported as a three-element list for each mixin class: className -guard guardExpr. The returned mixin classes can be limited to those whose names match namePattern (see string match).

    obj info lookup slots ?-type className? ?-source all | application | system? ?namePattern?

    Returns the command names of all slot objects responsible for managing properties, variables, and relations of obj. The returned slot objects can be limited according to any or a combination of the following criteria: First, slot objects can be filtered based on their command names matching namePattern (see string match). Second, -type allows one to select slot objects which are instantiated from a subclass className of nx::Slot (default: nx::Slot) . Third, -source restricts slot objects returned according to their provenance in either the NX system classes or the application classes present in the linearization list of obj (default: all).

    To extract details of each slot object, use the info submethods available for each slot object.

    obj info lookup variables

    Returns the command names of all slot objects responsible for managing properties and variables of obj, if provided by obj or the classes in the linearization list of obj.

    This is equivalent to calling: obj info lookup slots -type ::nx::VariableSlot -source all ?namePattern?.

    To extract details of each slot object, use the info submethods available for each slot object.

    obj info name

    Returns the unqualified name of an object, i.e., the object name without any namespace qualifiers.

    obj info info ?-asList?

    Returns the available submethods of the info method ensemble for obj, either as a pretty-printed string or as a Tcl list (if the switch -asList is set) for further processing.

    obj info object filters ?-guards? ?pattern?

    If pattern is omitted, returns all filter names which are defined by obj. By turning on the switch -guards, the corresponding guard expressions, if any, are also reported along with each filter as a three-element list: filterName -guard guardExpr. By specifying pattern, the returned filters can be limited to those whose names match patterns (see string match).

    obj info object method option methodName

    This introspection submethod provides access to the details of methodName provided by obj. Permitted values for option are:

    • args returns a list containing the parameter names of methodName, in order of the method-parameter specification.

    • body returns the body script of methodName.

    • definition returns a canonical command list which allows for (re-)define methodName.

    • definitionhandle returns the method handle for a submethod in a method ensemble from the perspective of obj as method provider. methodName must contain a complete method path.

    • exists returns 1 if there is a methodName provided by obj, returns 0 otherwise.

    • handle returns the method handle for methodName.

    • origin returns the aliased command if methodName is an alias method, or an empty string otherwise.

    • parameters returns the parameter specification of methodName as a list of parameter names and type specifications.

    • registrationhandle returns the method handle for a submethod in a method ensemble from the perspective of the method caller. methodName must contain a complete method path.

    • returns gives the type specification defined for the return value of methodName.

    • submethods returns the names of all submethods of methodName, if methodName is a method ensemble. Otherwise, an empty string is returned.

    • syntax returns the method parameters of methodName as a concrete-syntax description to be used in human-understandable messages (e.g., errors or warnings, documentation strings).

    • type returns whether methodName is a scripted method, an alias method, a forwarder method, or a setter method.

    obj info object methods ?-callprotection level? ?-type methodType? ?-path? ?namePattern?

    Returns the names of all methods defined by obj. Methods covered include those defined using object alias and object forward. The returned methods can be limited to those whose names match namePattern (see string match).

    By setting -callprotection, only methods of a certain call protection level (public, protected, or private) will be returned. Methods of a specific type can be requested using -type. The recognized values for methodType are:

    • scripted denotes methods defined using object method;

    • alias denotes alias methods defined using object alias;

    • forwarder denotes forwarder methods defined using object forward;

    • setter denotes methods defined using ::nsf::setter;

    • all returns methods of any type, without restrictions (also the default value);

    obj info object mixins ?-guards? ?pattern?

    If pattern is omitted, returns the object names of the mixin classes which extend obj directly. By turning on the switch -guards, the corresponding guard expressions, if any, are also reported along with each mixin as a three-element list: className -guard guardExpr. The returned mixin classes can be limited to those whose names match patterns (see string match).

    obj info object slots ?-type className? ?pattern?

    If pattern is not specified, returns the object names of all slot objects defined by obj. The returned slot objects can be limited according to any or a combination of the following criteria: First, slot objects can be filtered based on their command names matching pattern (see string match). Second, -type allows one to select slot objects which are instantiated from a subclass className of nx::Slot (default: nx::Slot).

    obj info object variables ?pattern?

    If pattern is omitted, returns the object names of all slot objects provided by obj which are responsible for managing properties and variables of obj. Otherwise, only slot objects whose names match pattern are returned.

    This is equivalent to calling: obj info object slots -type ::nx::VariableSlot pattern.

    To extract details of each slot object, use the info submethods available for each slot object.

    obj info parent

    Returns the fully qualified name of the parent object of obj, if any. If there is no parent object, the name of the Tcl namespace containing obj (e.g. "::") will be reported.

    obj info precedence ?-intrinsic? ?pattern?

    Lists the classes from which obj inherits structural (e.g. properties) and behavioral features (e.g. methods) and methods, in order of the linearization scheme in NX. By setting the switch -intrinsic, only classes which participate in superclass/subclass relationships (i.e., intrinsic classes) are returned. If a pattern is provided only classes whose names match pattern are returned. The pattern string can contain special matching characters (see string match).

    obj info variable option handle

    Retrieves selected details about a variable represented by the given handle. A handle can be obtained by querying obj using info object variables and info lookup variables. Valid values for option are:

    • name returns the variable name.

    • parameter returns a canonical parameter specification eligible to (re-)define the given variable (e.g. using object variable) in a new context.

    • definition returns a canonical representation of the definition command used to create the variable in its current configuration.

    obj info vars ?pattern?

    Yields a list of Tcl variable names created and defined for the scope of obj, i.e., object variables. The list can be limited to object variables whose names match pattern. The pattern string can contain special matching characters (see string match).

    method
    obj ?public | protected | private? object method name parameters ?-checkalways? ?-returns valueChecker? body

    Defines a scripted method methodName for the scope of the object. The method becomes part of the object's signature interface. Besides a methodName, the method definition specifies the method parameters and a method body.

    parameters accepts a Tcl list containing an arbitrary number of non-positional and positional parameter definitions. Each parameter definition comprises a parameter name, a parameter-specific value checker, and parameter options.

    The body contains the method implementation as a script block. In this body script, the colon-prefix notation is available to denote an object variable and a self call. In addition, the context of the object receiving the method call (i.e., the message) can be accessed (e.g., using nx::self) and the call stack can be introspected (e.g., using nx::current).

    Optionally, -returns allows for setting a value checker on values returned by the method implementation. By setting the switch -checkalways, value checking on arguments and return value is guaranteed to be performed, even if value checking is temporarily disabled; see nx::configure).

    A method closely resembles a Tcl proc, but it differs in some important aspects: First, a method can define non-positional parameters and value checkers on arguments. Second, the script implementing the method body can contain object-specific notation and commands (see above). Third, method calls cannot be intercepted using Tcl trace. Note that an existing Tcl proc can be registered as an alias method with the object (see object alias).

    move
    obj move newObjectName

    Effectively renames an object. First, the source object obj is cloned into a target object newObjectName using copy. Second, the source object obj is destroyed by invoking destroy. move is also called internally when rename is performed for a Tcl command representing an object.

    mixins
    obj object mixins submethod ?arg ...?

    Accesses and modifies the list of mixin classes of obj using a specific setter or getter submethod:

    obj object mixins add spec ?index?

    Inserts a single mixin class into the current list of mixin classes of obj. Using index, a position in the existing list of mixin classes for inserting the new mixin class can be set. If omitted, index defaults to the list head (0).

    obj object mixins classes ?pattern?

    If pattern is omitted, returns the object names of the mixin classes which extend obj directly. By specifying pattern, the returned mixin classes can be limited to those whose names match pattern (see string match).

    obj object mixins clear

    Removes all mixin classes from obj and returns the list of removed mixin classes. Clearing is equivalent to passing an empty list for mixinSpecList to object mixins set.

    obj object mixins delete ?-nocomplain? specPattern

    Removes a mixin class from a current list of mixin classes of obj whose spec matches specPattern. specPattern can contain special matching chars (see string match). object mixins delete will throw an error if there is no matching mixin class, unless -nocomplain is set.

    obj object mixins get

    Returns the list of current mixin specifications.

    obj object mixins guard className ?expr?

    If expr is specified, a guard expression expr is registered with the mixin class className. This requires that the corresponding mixin class className has been previously set using object mixins set or added using object mixins add. expr must be a valid Tcl expression (see expr). An empty string for expr will clear the currently registered guard expression for the mixin class className.

    If expr is not specified, returns the active guard expression. If none is available, an empty string will be returned.

    obj object mixins set mixinSpecList

    mixinSpecList represents a list of mixin class specs, with each spec being itself either a one-element or a three-element list: className ?-guard guardExpr?. If having one element, the element will be considered the className of the mixin class. If having three elements, the third element guardExpr will be stored as a guard expression of the mixin class. This guard expression will be evaluated using expr when obj receives a message to determine if the mixin is to be considered during method dispatch or not. Guard expressions allow for realizing context-dependent or conditional mixin composition.

    At the time of setting the mixin relation, that is, calling object mixins, every className as part of a spec must be an existing instance of nx::Class. To access and to manipulate the list of mixin classes of obj, cget|configure -object-mixins can also be used.

    __object_configureparameter
    obj __object_configureparameter

    Computes and returns the configuration options available for obj, to be consumed as method-parameter specification by configure.

    property
    obj object property ?-accessor public | protected | private? ?-configurable trueFalse? ?-incremental? ?-class className? ?-nocomplain? spec ?initBlock?

    Defines a property for the scope of the object. The spec provides the property specification as a list holding at least one element or, maximum, two elements: propertyName?:typeSpec? ?defaultValue?. The propertyName is also used as to form the names of the getter/setter methods, if requested (see -accessor). It is, optionally, equipped with a typeSpec following a colon delimiter which specifies a value checker for the values which become assigned to the property. The second, optional element sets a defaultValue for this property.

    If -accessor is set, a property will provide for a pair of getter and setter methods:

    obj propertyName set value

    Sets the property propertyName to value.

    obj propertyName get

    Returns the current value of property propertyName.

    obj propertyName unset

    Removes the value store of propertyName (e.g., an object variable), if existing.

    The option value passed along -accessor sets the level of call protection for the generated getter and setter methods: public, protected, or private. By default, no getter and setter methods are created.

    Turning on the switch -incremental provides a refined setter interface to the value managed by the property. First, setting -incremental implies requesting -accessor (set to public by default, if not specified explicitly). Second, the managed value will be considered a valid Tcl list. A multiplicity of 1..* is set by default, if not specified explicitly as part of spec. Third, to manage this list value element-wise (incrementally), two additional setter methods become available:

    obj propertyName add element ?index?

    Adding element to the managed list value, at the list position given by index (by default: 0).

    obj propertyName delete elementPattern

    Removing one or multiple elements from the managed list value which match elementPattern. elementPattern can contain matching characters (see string match).

    By setting -configurable to true (the default), the property can be accessed and modified through cget and configure, respectively. If false, no configuration option will become available via cget and configure.

    If neither -accessor nor -configurable are requested, the value managed by the property will have to be accessed and modified directly. If the property manages an object variable, its value will be readable and writable using set and eval.

    A property becomes implemented by a slot object under any of the following conditions:

    • -configurable equals true (by default).

    • -accessor is one of public, protected, or private.

    • -incremental is turned on.

    • initBlock is a non-empty string.

    Assuming default settings, every property is realized by a slot object.

    Provided a slot object managing the property is to be created, a custom class className from which this slot object is to be instantiated can be set using -class. The default value is ::nx::VariableSlot.

    The last argument initBlock accepts an optional Tcl script which is passed into the initialization procedure (see configure) of the property's slot object. See also initBlock for create and new.

    By default, the property will ascertain that no (potentially) pre-existing and equally named object variable will be overwritten when defining the property. In case of a conflict, an error exception is thrown:

    % Object create obj { set :x 1 }
    ::obj
    % ::obj object property {x 2}
    object ::obj has already an instance variable named 'x'
    

    If the switch -nocomplain is on, this check is omitted (continuing the above example):

    % ::obj object property -nocomplain {x 2}
    % ::obj eval {set :x}
    2
    
    require
    obj require namespace

    Create a Tcl namespace named after the object obj. All object variables become available as namespace variables.

    obj require ?public | protected | private? object method methodName

    Attempts to register a method definition made available using ::nsf::method::provide under the name methodName with obj . The registered method is subjected to default call protection (protected), if not set explicitly.

    unknown
    obj unknown unknownMethodName ?arg ...?

    This method is called implicitly whenever an unknown method is invoked. unknownMethodName indicates the unresolvable method name, followed by the remainder of the original argument vector as a number of arg of the indirected method invocation.

    variable
    obj object variable ?-accessor public | protected | private? ?-incremental? ?-class className? ?-configurable trueFalse? ?-initblock script? ?-nocomplain? spec ?defaultValue?

    Defines a variable for the scope of the object. The spec provides the variable specification: variableName?:typeSpec?. The variableName will be used to name the underlying Tcl variable and the getter/setter methods, if requested (see -accessor). spec is optionally equipped with a typeSpec following a colon delimiter which specifies a value checker for the values managed by the variable. Optionally, a defaultValue can be defined.

    If -accessor is set explicitly, a variable will provide for a pair of getter and setter methods:

    obj variableName set varValue

    Sets variableName to varValue.

    obj variableName get

    Returns the current value of variableName.

    obj variableName unset

    Removes variableName, if existing, underlying the property.

    The option value passed along -accessor sets the level of call protection for the getter and setter methods: public, protected, or private. By default, no getter and setter methods are created.

    Turning on the switch -incremental provides a refined setter interface to the value managed by the variable. First, setting -incremental implies requesting -accessor (public by default, if not specified explicitly). Second, the managed value will be considered a valid Tcl list. A multiplicity of 1..* is set by default, if not specified explicitly as part of spec (see above). Third, to manage this list value element-wise (incrementally), two additional setter operations become available:

    obj variableName add element ?index?

    Adding element to the managed list value, at the list position given by index (by default: 0).

    obj variableName delete elementPattern

    Removing one or multiple elements from the managed list value which match elementPattern. elementPattern can contain matching characters (see string match).

    By setting -configurable to true, the variable can be accessed and modified via cget and configure, respectively. If false (the default), the interface based on cget and configure will not become available. In this case, and provided that -accessor is set, the variable can be accessed and modified via the getter/setter methods. Alternatively, the underlying Tcl variable, which is represented by the variable, can always be accessed and modified directly, e.g., using eval. By default, -configurable is false.

    A variable becomes implemented by a slot object under any of the following conditions:

    • -configurable equals true.

    • -accessor is one of public, protected, or private.

    • -incremental is turned on.

    • -initblock is a non-empty string.

    Provided a slot object managing the variable is to be created, a custom class className from which this slot object is to be instantiated can be set using -class. The default value is ::nx::VariableSlot.

    Using -initblock, an optional Tcl script can be defined which becomes passed into the initialization procedure (see configure) of the variable's slot object. See also initBlock for create and new.

    By default, the variable will ascertain that a pre-existing and equally named object variable will not be overwritten when defining the variable. In case of a conflict, an error exception is thrown:

    % Object create obj { set :x 1 }
    ::obj
    % ::obj object variable x 2
    object ::obj has already an instance variable named 'x'
    

    If the switch -nocomplain is on, this check is omitted (continuing the above example):

    % ::obj object variable -nocomplain x 2
    % ::obj eval {set :x}
    2
    

    Object Self-Reference

    Objects are naturally recursive, with methods of an object ::obj frequently invoking other methods in the same object ::obj and accessing ::obj's object variables. To represent these self-references effectively in method bodies, and depending on the usage scenario, NX offers two alternative notations for self-references: one based on a special-purpose syntax token ("colon prefix"), the other based on the command nx::current.

    Both, the colon-prefix notation and nx::current, may be used only in method bodies and scripts passed to eval. If they appear anywhere else, an error will be reported. There are three main use cases for self-references:

    1. As a placeholder for the currently active object, nx::current can be used to retrieve the object name.

    2. Reading and writing object variables directly (i.e. without getter/setter methods in place) require the use of variable names carrying the prefix : ("colon-prefix notation"). Internally, colon-prefixed variable names are processed using Tcl's variable resolvers. Alternatively, one can provide for getter/setter methods for object variables (see property and variable).

    3. Self-referential method calls can be defined via prefixing (:) the method names or, alternatively, via nx::current. Internally, colon-prefixed method names are processed using Tcl's command resolvers. The colon-prefix notation is recommended, also because it has a (slight) performance advantage over nx::current which requires two rather than one command evaluation per method call.

    See the following listing for some examples corresponding to use cases 1--3:

    Object create ::obj {
      puts [current]; 			# 1) print name of currently active object ('::obj')        
      set :x 1; :object variable y 2;	# 2) object variables
      :public object method print {} {
        set z 3; 				# 2.a) method-local variable
        puts ${:x}-${:y}-$z; 		# 2.b) variable substitution using '$' and ':'
        puts [set :x]-[set :y]-[set z]; 	# 2.c) reading variables using 'set'
        set :x 1; incr :y; 			# 2.d) writing variables using 'set', 'incr', ...
      }
      :public object method show {} {
       :print;				# 3.a) self-referential method call using ':'	
       [current] print;			# 3.b) self-referential method call using 'nx::current'
       [current object] print;              # 3.c) self-referential method call using 'nx::current object'
      }
      :show
    }
    ./nsf2.4.0/doc/slottest-xotcl.html000644 000766 000024 00000001452 12161565464 017647 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./tests/slottest.xotcl

    ./tests/slottest.xotcl ./tests/slottest.xotcl


    Package/File Information

    No package provided/required

    Filename: ./tests/slottest.xotcl




    Back to index page.

    ./nsf2.4.0/doc/Class.html000644 000766 000024 00000216644 13523544313 015710 0ustar00neumannstaff000000 000000 nx::Class -

    nx::Class(3) 2.0 Class ""

    Name

    nx::Class - API reference of the base-metaclass of the NX objectsystem

    Synopsis

    Description

    nx::Class is the base metaclass of the NX object system. All classes (e.g. cls) are (direct or indirect) instances of nx::Class. Therefore, the methods provided by nx::Class are available to all classes. A class cls which does not have nx::Class as its direct or indirect superclass is referred to as an application class. By default, when instantiating a new class from nx::Class, it becomes an application class with nx::Object being set as its superclass. A class cls which is explicitly declared as a (direct or indirect) subclass of nx::Class is referred to as a metaclass, that is, its instances will become classes as well. In other words, a metaclass instantiates and subclasses nx::Class at the same time.

    +---------+
    | ::nx::* |
    +---------+--------------------------------------Y
    |                                                |
    |  instance of                                   |
    |   .-------.                                    |
    |  +--------'+     instance of     +----------+  |
    |  |         |<....................|          |  |
    |  |  Class  |                     |  Object  |  |
    |  |         |....................>|          |  |
    |  +---------+     subclass of     +-----+----+  |
    |   ^   ^                                ^       |
    \...|...|................................|......./
        |   |                                |
        |   |subclass.....(xor)......subclass|
        |   |of       +-----------+        of|
        |   |.........|           |..........|
        | (metaclass) |   /cls/   | (application class)
        |.............|           |
        instance of   +-----------+
    

    Classes can be created in the following ways:

    nx::Class create cls ?-superclasses superClassNames? ?-mixins mixinSpec? ?-filters filterSpec? ?option value ...? ?initBlock?

    To create a class having the explicit name cls, use create.

    nx::Class new ?-superclasses superClassNames? ?-mixins mixinSpec? ?-filters filterSpec? ?initBlock?

    To create a class having an automatically assigned, implicit name, use new.

    The configuration options for direct and indirect instances of nx::Class, which can be passed when calling create and new, are documented in the subsequent section.

    Configuration Options for Instances of nx::Class

    Configuration options can be used for configuring objects during their creation by passing the options as non-positional arguments into calls of new and create (see nx::Class). An existing object can be queried for its current configuration using cget and it can be re-configured using configure.

    -superclasses ?superClassNames?

    If superClassNames is not specified, returns the superclasses of the class. If provided, the class becomes the subclass of superClassNames.

    -filters ?filterSpecs?

    Retrieves the list of filter methods currently active on instances of the class, if filterSpecs is not set. Otherwise, activates a list of filter methods for the instances of the class. Filters are returned or set in terms of a list of filter specifications.

    -mixins ?mixinSpecs?

    Returns the list of mixin classes currently active on instances of the class, if mixinSpecs is not specified. Otherwise, the class is extended by the list of mixin classes provided by mixinSpecs. mixin classes are returned or set in terms of a list of mixin specifications.

    The configuration options provided by nx::Object are equally available because an application class cls is an indirect instance of nx::Object.

    Methods for Instances of nx::Class

    alias
    cls ?public | private | protected? alias methodName ?-returns valueChecker? ?-frame object | method? cmdName

    Define an alias method for the given class. The resulting method registers a pre-existing Tcl command cmdName under the (alias) name methodName with the class. If cmdName refers to another method, the corresponding argument should be a valid method handle. If a Tcl command (e.g., a proc), the argument should be a fully qualified Tcl command name. If aliasing a subcommand (e.g., array exists) of a Tcl namespace ensemble (e.g., array), cmdName must hold the fully qualified subcommand name (and not the ensemble name of the subcommand).

    As for a regular class method, -returns allows for setting a value checker on the values returned by the aliased command cmdName.

    When creating an alias method for a C-implemented Tcl command (i.e., command defined using the Tcl/NX C-API), -frame sets the scope for variable references used in the aliased command. If the provided value is object, then variable references will be resolved in the context of the called object, i.e., the object upon which the alias method is invoked, as if they were object variables. There is no need for using the colon-prefix notation for identifying object variables. If the value is method, then the aliased command will be executed as a regular method call. The command is aware of its called-object context; i.e., it can resolve ::nx::self. In addition, the alias method has access to the method-call context (e.g., nx::next). If -frame is omitted, and by default, the variable references will resolve in the context of the caller of the alias method.

    __class_configureparameter
    cls __class_configureparameter

    Computes and returns the configuration options available for cls instances, to be consumed as method-parameter specification by configure.

    create
    cls create instanceName ?option value option value ...?

    This factory method creates an instance instanceName of cls and returns instanceName.

    % nx::Class create AClass {
        :method init args {
          next
        }; # initialization method for instances of 'AClass'
      }; # defines a class 'AClass' being an instance of 'nx::Class'
    ::AClass
    % ::AClass create anInstance; # defines an object 'anInstance' being an instance of 'AClass'
    ::anInstance
    % ::anInstance info class
    ::AClass
    % ::AClass info class
    ::nx::Class
    

    create accepts the configuration options option available for this instance, such as those defined by properties of cls (see property).

    Note that create is called internally when defining an instance of cls using new.

    By calling create on nx::Class itself, the created instance will become a new application class instanceName on which create can also be applied (i.e., it can be instantiated). If the so-created class has ::nx::Class its direct or indirect superclass, instanceName is referred to as a metaclass; that is, a class whose instances are again classes.

    delete
    cls delete feature arg

    This method serves as the equivalent to Tcl's rename for removing structural (properties, variables) and behavioral features (methods) of the class:

    cls delete property propertyName
    cls delete variable variableName
    cls delete method methodName

    Removes a property propertyName, variable variableName, and method methodName, respectively, previously defined for the scope of the class.

    delete method can be equally used for removing regular methods (see method), an alias method (see alias), and a forwarder method (see forward).

    filters
    cls filters submethod ?arg ...?

    Accesses and modifies the list of methods which are registered as filters with cls using a specific setter or getter submethod:

    cls filters add spec ?index?

    Inserts a single filter into the current list of filters of cls. Using index, a position in the existing list of filters for inserting the new filter can be set. If omitted, index defaults to the list head (0).

    cls filters clear

    Removes all filters from cls and returns the list of removed filters. Clearing is equivalent to passing an empty list for filterSpecList to class filter set.

    cls filters delete ?-nocomplain? specPattern

    Removes a single filter from the current list of filters of cls whose spec matches specPattern. specPattern can contain special matching chars (see string match). class filters delete will throw an error if there is no matching filter, unless -nocomplain is set.

    cls filters get

    Returns the list of current filter specifications registered for cls.

    cls filters guard methodName ?expr?

    If expr is specified, registers a guard expression expr with a filter methodName. This requires that the filter methodName has been previously set using filters set or added using filters add. expr must be a valid Tcl expression (see expr). An empty string for expr will clear the currently registered guard expression for filter methodName.

    If expr is omitted, returns the guard expression set on the filter methodName defined for cls. If none is available, an empty string will be returned.

    cls filters methods ?pattern?

    If pattern is omitted, returns all filter names which are defined by cls. By specifying pattern, the returned filters can be limited to those whose names match patterns (see string match).

    cls filters set filterSpecList

    filterSpecList takes a list of filter specs, with each spec being itself either a one-element or a two-element list: methodName ?-guard guardExpr?. methodName identifies an existing method of cls which becomes registered as a filter. If having three elements, the third element guardExpr will be stored as a guard expression of the filter. This guard expression must be a valid Tcl expression (see expr). expr is evaluated when cls receives a message to determine whether the filter should intercept the message. Guard expressions allow for realizing context-dependent or conditional filter composition.

    Every methodName in a spec must resolve to an existing method in the scope of the class. To access and to manipulate the list of filters of cls, cget|configure -filters can also be used.

    forward
    cls ?public | protected | private? forward methodName ?-prefix prefixName? ?-frame object? ?-returns valueChecker? ?-verbose? ?target? ?arg ...?

    Define a forward method for the given class. The definition of a forward method registers a predefined, but changeable list of forwarder arguments under the (forwarder) name methodName. Upon calling the forward method, the forwarder arguments are evaluated as a Tcl command call. That is, if present, target is interpreted as a Tcl command (e.g., a Tcl proc or an object) and the remainder of the forwarder arguments arg as arguments passed into this command. The actual method arguments to the invocation of the forward method itself are appended to the list of forwarder arguments. If target is omitted, the value of methodName is implicitly set and used as target. This way, when providing a fully-qualified Tcl command name as methodName without target, the unqualified methodName (namespace tail) is used as the forwarder name; while the fully-qualified one serves as the target.

    As for a regular method, -returns allows for setting a value checker on the values returned by the resulting Tcl command call. When passing object to -frame, the resulting Tcl command is evaluated in the context of the object receiving the forward method call. This way, variable names used in the resulting execution of a command become resolved as object variables.

    The list of forwarder arguments arg can contain as its elements a mix of literal values and placeholders. Placeholders are prefixed with a percent symbol (%) and substituted for concrete values upon calling the forward method. These placeholders allow for constructing and for manipulating the arguments to be passed into the resulting command call on the fly:

    • %method becomes substituted for the name of the forward method, i.e. methodName.

    • %self becomes substituted for the name of the object receiving the call of the forward method.

    • %1 becomes substituted for the first method argument passed to the call of forward method. This requires, in turn, that at least one argument is passed along with the method call.

      Alternatively, %1 accepts an optional argument defaults: {%1 defaults}. defaults must be a valid Tcl list of two elements. For the first element, %1 is substituted when there is no first method argument which can be consumed by %1. The second element is inserted upon availability of a first method argument with the consumed argument being appended right after the second list element. This placeholder is typically used to define a pair of getter/setter methods.

    • {%@index value} becomes substituted for the specified value at position index in the forwarder-arguments list, with index being either a positive integer, a negative integer, or the literal value end (such as in Tcl's lindex). Positive integers specify a list position relative to the list head, negative integers give a position relative to the list tail. Indexes for positioning placeholders in the definition of a forward method are evaluated from left to right and should be used in ascending order.

      Note that value can be a literal or any of the placeholders (e.g., %method, %self). Position prefixes are exempted, they are evaluated as %cmdName-placeholders in this context.

    • {%argclindex list} becomes substituted for the nth element of the provided list , with n corresponding to the number of method arguments passed to the forward method call.

    • %% is substituted for a single, literal percent symbol (%).

    • %cmdName is substituted for the value returned from executing the Tcl command cmdName. To pass arguments to cmdName, the placeholder should be wrapped into a Tcl list: {%cmdName ?arg ...?}.

      Consider using fully-qualified Tcl command names for cmdName to avoid possible name conflicts with the predefined placeholders, e.g., %self vs. %::nx::self.

    To disambiguate the names of subcommands or methods, which potentially become called by a forward method, a prefix prefixName can be set using -prefix. This prefix is prepended automatically to the argument following target (i.e., a second argument), if present. If missing, -prefix has no effect on the forward method call.

    To inspect and to debug the conversions performed by the above placeholders, setting the switch -verbose will have the command list to be executed (i.e., after substitution) printed using ::nsf::log (debugging level: notice) upon calling the forward method.

    info

    A collection of introspection submethods on the structural features (e.g. configuration options, superclasses) and the behavioral features (e.g. methods, filters) provided by cls to its instances.

    cls info heritage ?pattern?

    If pattern is omitted, returns the list of object names of all the direct and indirect superclasses and per-class mixin classes of cls, in their order of precedence, which are active for instances of cls. If pattern is specified, only superclasses and mixin classes whose names match pattern will be listed (see string match).

    cls info instances ?-closure? ?pattern?

    If pattern is not specified, returns a list of the object names of all the direct instances of cls. If the switch -closure is set, indirect instances are also returned. A direct instance is created by using create or new on cls, an indirect instance was created from a direct or indirect subclass of cls. If pattern is specified, only instances whose names match pattern will be listed (see string match).

    cls info mixinof ?-closure? ?-scope option? ?pattern?

    If pattern is not specified, returns a list of the object names of all the objects for which cls is active as a direct mixin class. If the switch -closure is set, objects which have cls as an indirect mixin class are also returned. If pattern is specified, only objects whose names match pattern will be listed (see string match). Valid values of option are all, object, and class. Passing object will have only objects returned which have cls as per-object mixin class. Passing class will have only classes returned which have cls as per-class mixin class. all (the default) will have contained both in the returned list.

    cls info subclasses ?-closure? ?-dependent? ?pattern?

    If pattern is not specified, returns a list of the object names of the direct subclasses of cls. If the switch -closure is set, indirect subclasses are also returned. If the switch -dependent is on, indirect subclasses introduced by mixin class relations of subclasses of cls are also reported. -closure and -dependent are mutually exclusive. If pattern is specified, only subclasses whose names match pattern will be listed (see string match).

    cls info superclasses ?-closure? ?pattern?

    If pattern is not specified, returns a list of the object names of all direct superclasses of cls. If the switch -closure is set, indirect superclasses will also be returned. If pattern is specified, only superclasses whose names match pattern will be listed (see string match).

    cls info info ?-asList?

    Returns the available submethods of the info method ensemble for cls, either as a pretty-printed string or as a Tcl list (if the switch -asList is set) for further processing.

    cls info filters ?-guards? ?pattern?

    If pattern is omitted, returns all filter names which are defined by cls. By turning on the switch -guards, the corresponding guard expressions, if any, are also reported along with each filter as a three-element list: filterName -guard guardExpr. By specifying pattern, the returned filters can be limited to those whose names match patterns (see string match).

    cls info method option methodName

    This introspection submethod provides access to the details of methodName provided by cls. Permitted values for option are:

    • args returns a list containing the parameter names of methodName, in order of the method-parameter specification.

    • body returns the body script of methodName.

    • definition returns a canonical command list which allows for (re-)define methodName.

    • definitionhandle returns the method handle for a submethod in a method ensemble from the perspective of cls as method provider. methodName must contain a complete method path.

    • exists returns 1 if there is a methodName provided by cls, returns 0 otherwise.

    • handle returns the method handle for methodName.

    • origin returns the aliased command if methodName is an alias method, or an empty string otherwise.

    • parameters returns the parameter specification of methodName as a list of parameter names and type specifications.

    • registrationhandle returns the method handle for a submethod in a method ensemble from the perspective of the method caller. methodName must contain a complete method path.

    • returns gives the type specification defined for the return value of methodName.

    • submethods returns the names of all submethods of methodName, if methodName is a method ensemble. Otherwise, an empty string is returned.

    • syntax returns the method parameters of methodName as a concrete-syntax description to be used in human-understandable messages (e.g., errors or warnings, documentation strings).

    • type returns whether methodName is a scripted method, an alias method, a forwarder method, or a setter method.

    cls info methods ?-callprotection level? ?-type methodType? ?-path? ?namePattern?

    Returns the names of all methods defined by cls. Methods covered include those defined using alias and forward. The returned methods can be limited to those whose names match namePattern (see string match).

    By setting -callprotection, only methods of a certain call protection level (public, protected, or private) will be returned. Methods of a specific type can be requested using -type. The recognized values for methodType are:

    • scripted denotes methods defined using class method;

    • alias denotes alias methods defined using class alias;

    • forwarder denotes forwarder methods defined using class forward;

    • setter denotes methods defined using ::nsf::setter;

    • all returns methods of any type, without restrictions (also the default value);

    cls info mixins ?-guards? ?pattern?

    If pattern is omitted, returns the object names of the mixin classes which extend cls directly. By turning on the switch -guards, the corresponding guard expressions, if any, are also reported along with each mixin as a three-element list: className -guard guardExpr. The returned mixin classes can be limited to those whose names match patterns (see string match).

    cls info slots ?-type className? ?pattern?

    If pattern is not specified, returns the object names of all slot objects defined by cls. The returned slot objects can be limited according to any or a combination of the following criteria: First, slot objects can be filtered based on their command names matching pattern (see string match). Second, -type allows one to select slot objects which are instantiated from a subclass className of nx::Slot (default: nx::Slot).

    cls info variables ?pattern?

    If pattern is omitted, returns the object names of all slot objects provided by cls which are responsible for managing properties and variables of cls. Otherwise, only slot objects whose names match pattern are returned.

    This is equivalent to calling: cls info slots -type ::nx::VariableSlot pattern.

    To extract details of each slot object, use the info submethods available for each slot object.

    method
    cls ?public | protected | private? method name parameters ?-checkalways? ?-returns valueChecker? body

    Defines a scripted method methodName for the scope of the class. The method becomes part of the class's signature interface. Besides a methodName, the method definition specifies the method parameters and a method body.

    parameters accepts a Tcl list containing an arbitrary number of non-positional and positional parameter definitions. Each parameter definition comprises a parameter name, a parameter-specific value checker, and parameter options.

    The body contains the method implementation as a script block. In this body script, the colon-prefix notation is available to denote an object variable and a self call. In addition, the context of the object receiving the method call (i.e., the message) can be accessed (e.g., using nx::self) and the call stack can be introspected (e.g., using nx::current).

    Optionally, -returns allows for setting a value checker on values returned by the method implementation. By setting the switch -checkalways, value checking on arguments and return value is guaranteed to be performed, even if value checking is temporarily disabled; see nx::configure).

    A method closely resembles a Tcl proc, but it differs in some important aspects: First, a method can define non-positional parameters and value checkers on arguments. Second, the script implementing the method body can contain object-specific notation and commands (see above). Third, method calls cannot be intercepted using Tcl trace. Note that an existing Tcl proc can be registered as an alias method with the class (see alias).

    mixins
    cls mixins submethod ?arg ...?

    Accesses and modifies the list of mixin classes of cls using a specific setter or getter submethod:

    cls mixins add spec ?index?

    Inserts a single mixin class into the current list of mixin classes of cls. Using index, a position in the existing list of mixin classes for inserting the new mixin class can be set. If omitted, index defaults to the list head (0).

    cls mixins classes ?pattern?

    If pattern is omitted, returns the object names of the mixin classes which extend cls directly. By specifying pattern, the returned mixin classes can be limited to those whose names match pattern (see string match).

    cls mixins clear

    Removes all mixin classes from cls and returns the list of removed mixin classes. Clearing is equivalent to passing an empty list for mixinSpecList to mixins set.

    cls mixins delete ?-nocomplain? specPattern

    Removes a mixin class from a current list of mixin classes of cls whose spec matches specPattern. specPattern can contain special matching chars (see string match). class mixins delete will throw an error if there is no matching mixin class, unless -nocomplain is set.

    cls mixins get

    Returns the list of current mixin specifications.

    cls mixins guard className ?expr?

    If expr is specified, a guard expression expr is registered with the mixin class className. This requires that the corresponding mixin class className has been previously set using class mixins set or added using mixins add. expr must be a valid Tcl expression (see expr). An empty string for expr will clear the currently registered guard expression for the mixin class className.

    If expr is not specified, returns the active guard expression. If none is available, an empty string will be returned.

    cls mixins set mixinSpecList

    mixinSpecList represents a list of mixin class specs, with each spec being itself either a one-element or a three-element list: className ?-guard guardExpr?. If having one element, the element will be considered the className of the mixin class. If having three elements, the third element guardExpr will be stored as a guard expression of the mixin class. This guard expression will be evaluated using expr when cls receives a message to determine if the mixin is to be considered during method dispatch or not. Guard expressions allow for realizing context-dependent or conditional mixin composition.

    At the time of setting the mixin relation, that is, calling mixins, every className as part of a spec must be an existing instance of nx::Class. To access and to manipulate the list of mixin classes of cls, cget|configure -mixins can also be used.

    new
    cls new ?-childof parentName? ?option value option value ...?

    A factory method to create autonamed instances of cls. It returns the name of the newly created instance. For example:

    % nx::Class create AClass; # defines a class 'AClass' being an instance of 'nx::Class'
    ::AClass
    % set inst [::AClass new]; # defines an autonamed object being an instance of 'AClass'
    ::nsf::__#0
    % $inst info class
    ::AClass
    

    The factory method will provide computed object names of the form, e.g. ::nsf::__#0. The uniqueness of generated object names is guaranteed for the scope of the current Tcl interpreter only.

    It is a frontend to create which will be called by new once the name of the instance has been computed, passing along the arguments option to new as the configuration options (see create).

    If -childof is provided, the new object will be created as a nested object of parentName. parentName can be the name of either an existing NX object or an existing Tcl namespace. If non-existing, a Tcl namespace parentName will be created on the fly.

    property
    cls property ?-accessor public | protected | private? ?-configurable trueFalse? ?-incremental? ?-class className? spec ?initBlock?

    Defines a property for the scope of the class. The spec provides the property specification as a list holding at least one element or, maximum, two elements: propertyName?:typeSpec? ?defaultValue?. The propertyName is also used as to form the names of the getter/setter methods, if requested (see -accessor). It is, optionally, equipped with a typeSpec following a colon delimiter which specifies a value checker for the values which become assigned to the property. The second, optional element sets a defaultValue for this property.

    If -accessor is set, a property will provide for a pair of getter and setter methods:

    obj propertyName set value

    Sets the property propertyName to value.

    obj propertyName get

    Returns the current value of property propertyName.

    obj propertyName unset

    Removes the value store of propertyName (e.g., an object variable), if existing.

    The option value passed along -accessor sets the level of call protection for the generated getter and setter methods: public, protected, or private. By default, no getter and setter methods are created.

    Turning on the switch -incremental provides a refined setter interface to the value managed by the property. First, setting -incremental implies requesting -accessor (set to public by default, if not specified explicitly). Second, the managed value will be considered a valid Tcl list. A multiplicity of 1..* is set by default, if not specified explicitly as part of spec. Third, to manage this list value element-wise (incrementally), two additional setter methods become available:

    obj propertyName add element ?index?

    Adding element to the managed list value, at the list position given by index (by default: 0).

    obj propertyName delete elementPattern

    Removing one or multiple elements from the managed list value which match elementPattern. elementPattern can contain matching characters (see string match).

    By setting -configurable to true (the default), the property can be accessed and modified through cget and configure, respectively. If false, no configuration option will become available via cget and configure.

    If neither -accessor nor -configurable are requested, the value managed by the property will have to be accessed and modified directly. If the property manages an object variable, its value will be readable and writable using set and eval.

    A property becomes implemented by a slot object under any of the following conditions:

    • -configurable equals true (by default).

    • -accessor is one of public, protected, or private.

    • -incremental is turned on.

    • initBlock is a non-empty string.

    Assuming default settings, every property is realized by a slot object.

    Provided a slot object managing the property is to be created, a custom class className from which this slot object is to be instantiated can be set using -class. The default value is ::nx::VariableSlot.

    The last argument initBlock accepts an optional Tcl script which is passed into the initialization procedure (see configure) of the property's slot object. See also initBlock for create and new.

    require
    cls require ?public | protected | private? method methodName

    Attempts to register a method definition made available using ::nsf::method::provide under the name methodName with cls . The registered method is subjected to default call protection (protected), if not set explicitly.

    variable
    cls variable ?-accessor public | protected | private? ?-incremental? ?-class className? ?-configurable trueFalse? ?-initblock script? spec ?defaultValue?

    Defines a variable for the scope of the class. The spec provides the variable specification: variableName?:typeSpec?. The variableName will be used to name the underlying Tcl variable and the getter/setter methods, if requested (see -accessor). spec is optionally equipped with a typeSpec following a colon delimiter which specifies a value checker for the values managed by the variable. Optionally, a defaultValue can be defined.

    If -accessor is set explicitly, a variable will provide for a pair of getter and setter methods:

    obj variableName set varValue

    Sets variableName to varValue.

    obj variableName get

    Returns the current value of variableName.

    obj variableName unset

    Removes variableName, if existing, underlying the property.

    The option value passed along -accessor sets the level of call protection for the getter and setter methods: public, protected, or private. By default, no getter and setter methods are created.

    Turning on the switch -incremental provides a refined setter interface to the value managed by the variable. First, setting -incremental implies requesting -accessor (public by default, if not specified explicitly). Second, the managed value will be considered a valid Tcl list. A multiplicity of 1..* is set by default, if not specified explicitly as part of spec (see above). Third, to manage this list value element-wise (incrementally), two additional setter operations become available:

    obj variableName add element ?index?

    Adding element to the managed list value, at the list position given by index (by default: 0).

    obj variableName delete elementPattern

    Removing one or multiple elements from the managed list value which match elementPattern. elementPattern can contain matching characters (see string match).

    By setting -configurable to true, the variable can be accessed and modified via cget and configure, respectively. If false (the default), the interface based on cget and configure will not become available. In this case, and provided that -accessor is set, the variable can be accessed and modified via the getter/setter methods. Alternatively, the underlying Tcl variable, which is represented by the variable, can always be accessed and modified directly, e.g., using eval. By default, -configurable is false.

    A variable becomes implemented by a slot object under any of the following conditions:

    • -configurable equals true.

    • -accessor is one of public, protected, or private.

    • -incremental is turned on.

    • -initblock is a non-empty string.

    Provided a slot object managing the variable is to be created, a custom class className from which this slot object is to be instantiated can be set using -class. The default value is ::nx::VariableSlot.

    Using -initblock, an optional Tcl script can be defined which becomes passed into the initialization procedure (see configure) of the variable's slot object. See also initBlock for create and new.

    Object Life Cycle

    nx::Class provides means to control important stages through which an NX object passes between and including its creation and its destruction: allocation, recreation, deallocation.

            /cls/->create(/instance/)
                      .---------------.   exists?    [false]   .----------------.                   .-------------------.
                 ---->|Class::create()|----><>---------------->|Class::__alloc()|-----------><>---->|Object::configure()|
                      `---------------'      |      (1)        `----------------'             ^ (3) `---------+---------'
                                      [true] |                                                |               | (4)
                                             |  .-------------------.                         |      .------------------.
                                             `->|Class::__recreate()|-------------------------'      |/instance/->init()|
                                          (2)   `-------------------'                                `------------------'
        /instance/->destroy()
            .-----------------.     .------------------.
       ---->|Object::destroy()|---->|Class::__dealloc()|
            `-----------------' (5) `------------------'
    

    Object creation is controlled by the factory method create, provided by nx::Class to its instance cls. create produces a new object instance as an instance of cls in a number of steps.

    1. If instance does not represent an existing object, an internal call to __alloc, provided by nx::Class, runs the allocation procedure for a fresh instance of cls.

    2. If instance corresponds to an existing object, the recreation procedure is triggered by calling __recreate defined by nx::Class.

    3. The newly allocated or recreated object instance is then configured by dispatching configure, provided by nx::Object, which consumes the configuration options passed into create. This will establish the instance's initial state, e.g. by setting object variables and object relations according to the configuration options and corresponding default values.

    4. Finally, the initialization method init is dispatched, if available for instance. init can be defined by cls on behalf of its instance instance, e.g. to lay out a class-specific initialization behavior.

      % nx::Class create Foo {:property x}
      % Foo method init {} {set :y [expr {${:x} + 1}]}
      % Foo public method bar {} {return ${:y}}
      % Foo create f1 -x 101
      % f1 cget -x
      101
      % f1 bar
      102
      

      Alternatively, the object instance may define a per-object init on its own. A per-object init can be chained to a class-level init using nx::next, just like a regular method.

      Note that the definition of an init method must contain an empty parameter specification, since init is always called with an empty argument list.

    Object destruction, such as triggered by an application-level destroy call (5), is finalized by __dealloc offered by nx::Class.

    In the following, the three built-in procedures --- allocation, recreation, and deallocation --- are explained:

    • Allocation: __alloc creates a blank object instance as an instance of cls and returns the fully-qualified instance. __alloc is primarily used internally by create to allocate a Tcl memory storage for instance and to register instance with the Tcl interpreter as a new command.

    • Recreation: Recreation is the NX scheme for resolving naming conflicts between objects: An object is requested to be created using create or new while an object of an identical object name, e.g. instance, already exists:

      % Object create Bar
      ::Bar
      % Object create Bar; # calls Object->__recreate(::Bar, ...)
      ::Bar
      

      In such a situation, the built-in __recreate first unsets the object state (i.e., Tcl variables held by the object) and removes relations of the object under recreation with other objects. Then, second, standard object initialization is performed by calling configure and init, if any.

      Alternatively, recreation will be performed as a sequence of destroy and create calls in the following recreation scenarios:

      • An existing class is requested to be recreated as an object.

      • An existing object is requested to be recreated as a class.

          % Object create Bar
          ::Bar
          % Class create Bar; # calls Bar->destroy() & Class::create(::Bar, ...)
        
      • An object of an object system other than NX (e.g. XOTcl2) is asked to be recreated.

    • Deallocation: __dealloc marks an instance instance of cls for deletion by returning its Tcl memory representation to the Tcl memory pool and by unregistering the corresponding Tcl command with the Tcl interpreter.

      Beware that __dealloc does not necessarily cause the object to be deleted immediately. Depending on the lifecycle of the object's environment (e.g. the Tcl interp interpreter, the containing namespace) and on call references down the callstack, the actual memory freeing/returning operation may occur at a later point.

    The three methods __alloc, __recreate, and __dealloc are internally provided and internally called. By default, they are not part of the method interface of cls and cannot be called directly by clients of cls. In addition, __alloc, __recreate, and __dealloc are protected from redefinition by a script.

    To extend or to replace the built-in allocation, recreation, and deallocation procedure, the methods __alloc, __recreate, and __dealloc can be refined by providing a custom method implementation:

    • as a per-object method of cls;

    • as a method of a per-object mixin class extending cls;

    • as a method of a per-class mixin class extending nx::Class;

    • as a method of a subclass specializing nx::Class, from which cls is to be instantiated.

    This custom implementation can redirect to the built-in __alloc, __recreate, and __dealloc, respectively, by using nx::next. By providing such a custom implementation, __alloc, __recreate, and __dealloc, respectively, become available as callable methods of cls:

    cls __alloc instance
    cls __recreate instance ?arg ...?
    cls __dealloc instance
    ./nsf2.4.0/doc/current.3000644 000766 000024 00000024503 14274463622 015521 0ustar00neumannstaff000000 000000 '\" '\" Generated from file 'current\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2014-16 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. '\" .TH "nx::current" 3 2\&.4\&.0 current "NX API" .\" The -*- nroff -*- definitions below are for supplemental macros used .\" in Tcl/Tk manual entries. .\" .\" .AP type name in/out ?indent? .\" Start paragraph describing an argument to a library procedure. .\" type is type of argument (int, etc.), in/out is either "in", "out", .\" or "in/out" to describe whether procedure reads or modifies arg, .\" and indent is equivalent to second arg of .IP (shouldn't ever be .\" needed; use .AS below instead) .\" .\" .AS ?type? ?name? .\" Give maximum sizes of arguments for setting tab stops. Type and .\" name are examples of largest possible arguments that will be passed .\" to .AP later. If args are omitted, default tab stops are used. .\" .\" .BS .\" Start box enclosure. From here until next .BE, everything will be .\" enclosed in one large box. .\" .\" .BE .\" End of box enclosure. .\" .\" .CS .\" Begin code excerpt. .\" .\" .CE .\" End code excerpt. .\" .\" .VS ?version? ?br? .\" Begin vertical sidebar, for use in marking newly-changed parts .\" of man pages. The first argument is ignored and used for recording .\" the version when the .VS was added, so that the sidebars can be .\" found and removed when they reach a certain age. If another argument .\" is present, then a line break is forced before starting the sidebar. .\" .\" .VE .\" End of vertical sidebar. .\" .\" .DS .\" Begin an indented unfilled display. .\" .\" .DE .\" End of indented unfilled display. .\" .\" .SO ?manpage? .\" Start of list of standard options for a Tk widget. The manpage .\" argument defines where to look up the standard options; if .\" omitted, defaults to "options". The options follow on successive .\" lines, in three columns separated by tabs. .\" .\" .SE .\" End of list of standard options for a Tk widget. .\" .\" .OP cmdName dbName dbClass .\" Start of description of a specific option. cmdName gives the .\" option's name as specified in the class command, dbName gives .\" the option's name in the option database, and dbClass gives .\" the option's class in the option database. .\" .\" .UL arg1 arg2 .\" Print arg1 underlined, then print arg2 normally. .\" .\" .QW arg1 ?arg2? .\" Print arg1 in quotes, then arg2 normally (for trailing punctuation). .\" .\" .PQ arg1 ?arg2? .\" Print an open parenthesis, arg1 in quotes, then arg2 normally .\" (for trailing punctuation) and then a closing parenthesis. .\" .\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b .\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out .\" # BS - start boxed text .\" # ^y = starting y location .\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. .\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. .\" # VS - start vertical sidebar .\" # ^Y = starting y location .\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. .\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. .\" # Special macro to handle page bottom: finish off current .\" # box/sidebar if in box/sidebar mode, then invoked standard .\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. .\" # DS - begin display .de DS .RS .nf .sp .. .\" # DE - end display .de DE .fi .RE .sp .. .\" # SO - start of list of standard options .de SO 'ie '\\$1'' .ds So \\fBoptions\\fR 'el .ds So \\fB\\$1\\fR .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. .\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\*(So manual entry for details on the standard options. .. .\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. .\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. .\" # CE - end code excerpt .de CE .fi .RE .. .\" # UL - underline word .de UL \\$1\l'|0\(ul'\\$2 .. .\" # QW - apply quotation marks to word .de QW .ie '\\*(lq'"' ``\\$1''\\$2 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\$2 .. .\" # PQ - apply parens and quotation marks to word .de PQ .ie '\\*(lq'"' (``\\$1''\\$2)\\$3 .\"" fix emacs highlighting .el (\\*(lq\\$1\\*(rq\\$2)\\$3 .. .\" # QR - quoted range .de QR .ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3 .. .\" # MT - "empty" string .de MT .QW "" .. .BS .SH NAME nx::current \- Return information about the method callstack .SH SYNOPSIS \fBcurrent\fR ?\fIoption\fR? .sp .BE .SH DESCRIPTION .TP \fBcurrent\fR ?\fIoption\fR? This introspection command provides information about various details, to be identified using \fIoption\fR, on the callstack\&. The command is invoked from a method body\&. If \fIoption\fR is not provided, \fBnx::current\fR will default to option \fBobject\fR (see below)\&. \fBnx::current\fR operates on the Tcl callstack and is aware of NX-specific callstack and stackframe details\&. Except for the options \fBcallinglevel\fR and \fBlevel\fR, calling \fBnx::current\fR outside an NX object or method will result in an error\&. \fIoption\fR can be any of the following: .RS .IP \(bu \fBactivelevel\fR returns the actual callstack level which calls into the currently executing method directly\&. This \fBactivelevel\fR might correspond the \fBcallinglevel\fR, but this is not necessarily the case\&. The \fBactivelevel\fR also includes intermediate calls, such as \fBnx::next\fR invocations\&. The level is reported as an absolute level number (# followed by a digit) to be directly used as the first argument to \fBuplevel\fR or \fBupvar\fR\&. .IP \(bu \fBargs\fR returns the list of argument values passed into the currently executing method implementation\&. .IP \(bu \fBcalledclass\fR returns the name of the class that provides the method implementation to which the intercepted method call is to be redirected (only available from within filter methods)\&. .IP \(bu \fBcalledmethod\fR returns the original method name requested by intercepted method call (only available from within filter methods)\&. .IP \(bu \fBcallingclass\fR returns the name of the class which provides the method implementation calling into the currently executing method\&. See also \fBcallingobject\fR\&. .IP \(bu \fBcallinglevel\fR resolves the callstack level of the originating invocation of the currently executing method implementation\&. Callstack levels introduced by method interception (e\&.g\&., filters) and by method combination (\fBnx::next\fR) are ignored\&. The level is reported as an absolute level number (\fB#\fR followed by a digit) to be directly used as the first argument to \fBuplevel\fR or \fBupvar\fR\&. See also \fBactivelevel\fR\&. If called outside NX, \fB1\fR is returned (which is the default for \fBupvar\fR and \fBuplevel\fR)\&. .IP \(bu \fBcallingobject\fR returns the name of the object which is calling into the currently executing method\&. See also \fBcallingclass\fR\&. .IP \(bu \fBclass\fR returns the name of the class providing the currently executing method implementation\&. The returned method-providing class may be different to the class of the current object\&. If called from within a method implementation provided by the current object itself, an empty string is returned\&. .IP \(bu \fBfilterreg\fR returns the object (class) on which the currently executing method was registered as a filter method (only available from within filter methods)\&. .IP \(bu \fBisnextcall\fR will return 1, if the currently executing method implementation was invoked via \fBnx::next\fR; 0 otherwise\&. .IP \(bu \fBlevel\fR will return a number indicating the stack level of the currently executed method or script, or an empty string when executed outside an NX context (e\&.g\&., in a Tcl proc or a namespace script)\&. The resulting value can be directly passed as \fIlevel\fR to \fBinfo level\fR\&. .IP \(bu \fBmethod\fR returns the name of the currently executing method\&. If an ensemble-method call, the name of the bottom-most ("leaf") method is returned\&. .IP \(bu \fBmethodpath\fR returns the combined name of the currently executing method (including all ensemble levels) in an ensemble-method call\&. Otherwise, for a regular method call, the result corresponds to the result of option \fBmethod\fR\&. .IP \(bu \fBnextmethod\fR returns the name of the next most specific method implementation to be called when invoking \fBnx::next\fR\&. .IP \(bu \fBobject\fR gives the name of the object on which the currently executing method implementation is evaluated\&. .RE .PP .SH COPYRIGHT .nf Copyright (c) 2014-16 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. .fi ./nsf2.4.0/doc/configure.pdf000644 000766 000024 00000204636 12422512322 016417 0ustar00neumannstaff000000 000000 %PDF-1.4 % 1 0 obj <> endobj 6 0 obj <> endobj 7 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj 10 0 obj <> endobj 5 0 obj <> endobj 4 0 obj <> endobj 2 0 obj <> endobj 17 0 obj <> stream xXKsFWL$TveF*\*] rH!E < U~Lu\sDl3 V B$8\:Z27[7ZJQ,ZR,E [ˣ"N>ţCnY5/S'8J)_dE𣱤L{ .?zn?fq ۰*u\%A*wT=l]y.)V_FgwIÊDq2Cp{yś J}{$uI1 !mUNS5DXώ~L"=Nπ cAlӶN 3C(ru7xj%Jb$$V#J1 }HAw45ʗY]ʽ@e]H^QD6,iJ (=@i`_—FǨջN*X12dKTtv>D۳:hv"J@3Q;]v +ѰiVfos@Kx%ht r

    El,PVÓ;!dY4{\x"$-8$ Q6cH6'mw]̟ S<Υ_ eXO!A=8V\N"dN(<_58e`b MFfzVLO mE5{C/#!d/gOQZRg+ O[ݢAeZakmn\9F dO(Ǣð!L+XTXSCCo|c(;PfliP ݥ.K )W}hw./5q;xm#M`(zBI 8)vʕy0)ϑް@!t 8KGTxA=4Y":ײ?ތ&rxF5U}7S~l)Pk.gZT endstream endobj 18 0 obj 1952 endobj 26 0 obj <>>> stream xuRIr0BzT%9x.!ؓT*'-hht`ACXCd3<Ȉ`Hjܽn1U\h-CWk!4ɔE{R9/p:KKm\pO+]ih؜ 5(*PY 9#3]0TDΦh?tq*$;{A?cSbrYМTaejdEI[4Z#d_ )>JKmEmҩW]ںЦ90kiր dZ;/ZzVv}&X˜qc|T]~ endstream endobj 27 0 obj 303 endobj 3 0 obj <> /ProcSet [/PDF /Text]>> /Annots [24 0 R 25 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R]>> endobj 24 0 obj <> /BS <> /Subtype /Text /T (www.princexml.com) /Subj (Prince - Non-commercial License) /Contents (This document was created with Prince, a great way of getting web content onto paper.) /Popup 25 0 R /Name /Note>> endobj 25 0 obj <> /Subtype /Popup /Parent 24 0 R /Open false>> endobj 19 0 obj <> endobj 20 0 obj <> endobj 21 0 obj <> endobj 22 0 obj <> endobj 23 0 obj <> endobj 11 0 obj <> endobj 28 0 obj <> endobj 29 0 obj <> stream x XG0\U6-B#D^ʨLH@AYDLL2#I&jb$d_L6Θu8ƛHwAɝ<7UT9UN:unFQ7⢷j!l_S~>|Ukg!"$|zU?{$"bsSCGWN@S¾E>P㛯7:A(?ue"C皆Mm߀PIu 4=sPޅֺ3>@_ 03BXDFAD$ɱf*2MffO@(t')vy5h&P:Bz Q KP A厞IIF!KW=>YXC};BOFsE:ѽ(-ADKM݆n~.A?ED7D@Ut$O"4藢& h2ihv>2܍A?Q _)*GQ6%PEw]mAPIEE'Ag]nFc*`_6:B8#A:DЛ؎菣Q$,} <oN~.Gu/}#eџG_DV/1|}`h2hd>݈^@ooV4-_Xl![w$mHۅa<: =BD. 1F .A~lԉC`??W5߇H|EeF{~XȈ EΏQm>3= ;:7qᯈBFvS|._HEUj"F<y;\m3fFx C@џ@r|%o+m%wF*aVzM߂q4n =̅~8)o3Id~ ‹iTlϥ4GB>],Z/#` -H<*$aK,\ ߀4@$=@b@Md< >9AN.n9w9mn>>Nq|-[p  yH$1E׈?I4EvHJp ɵނx`#H"T# <vQu1vA<|u>yT_A[E'P /K{{}:MCO7E )%CŸM|5^T|.[ѻ-7# O#]7+%/xOh7q_w5 fD^쳭=A֊og"ki 0X EZ_Es`.Ca5Ka|Vrʴtt|I>j5 EmEDux߉>ķ>)iDK8)aK8 <#J8}z,O`*`%z}2MDAdAkI-wU${6 LC/7|iW_`h%/C?U竀z/jkg͸tx: )h;~/EFa ƽP xJ?@iW; gtgLh1i8%</@E ;CwLHSt1=kJ%zKJM-).* O˝31=!+3#}?ͧyǥ$'y.#1nZ&AUdIx`4qVʨٳsh c*CTͺ&32bJ(WG)U+E9~-J֏/J:y p>0h3͕Zk3C64Y_  E3@ \^욎B\3$@Prf㯤 53+}ڜ!\ҿ"3B#AlX0Z U8~+ZQ06 q t [ƭ =P5ƶ&s;g[4Zܹs\X3GZxI`@U5\[7Ð Ul~M~R3;$ E}$} :fj;}dmCeJo"ڹhsG<Lb5[4imc#XբQb*DH[$5~S1͚Ε@Z \FXRQ:Snk;!^#[(JdԠ}lj"R)8 s&n'SmV Unj}>hB kbe H#=7P"epűtaGHX 347ګ.fjEX{h[ %Tp$dQ^1JL 5"3F*6+dkU1LӔ lq)CS]TH:N3HՒ;ws,6kgΆh f Ⱦm3G?zЬjax*+A3zx^o_f%5aIEV3jh--i0zȬ)y@G򬂕Wc:VX+!*ЌgR?)G8J|#, H`؍3KQM|t05n.X&@u&l3xQ MBa "âA% gdCfUs2SuӼ,p?g|SwjnDJ^RB<ў\+ЌŶs"_rzE:4 +,8"+)Vd4)cGW+,o!z&u()+2[6iwٜ+q24g*L_7ėMߋ*lV&蠞nw{eגk!JHH=Ii' ;/2杚o=>q*NU.*4dMqh:Sج$Mw /vĀ0x3"vC/ʗ\ /hP,ہtuJH~}}ssfJy(@ʁTَRZ 7J}?UNZq&:jZA넮M}!O#htטk$F9A9tBXQrºxƍ _ie|A>ěh(֞~T[,G>`]: rR'"߃]ʦ5?N/^ٷLuy`ɰJЇz6[S^qa_!p(#ٙow">ՄxJp&xݸuӝ&b2ag?&ś@z& TרC572[wzxzytbx<>)<ڈO O)SܺЌOQg+j Cu ̲"|KNȐ?mr ӟx'ecQ,U G5!O A7O0JҳK$/%A p& }ķ}ukF=[jNuORǪ'$Qq& REq)~rw3zZNQSцԜęVlhhar{I)O9i.T/ N'uL|ŋκolzWr$bɟ~ǵؗq±ȯmJ7_"};6pES=gf n2'-o]uo$bY/>˪N|f,7)NV?4Ԁv/+< #vJɒXő*2`Cf3&+8vFlK)=SJZ"~m%\8<|x/;ָFڿoԡ.ir|Lʻd"(6/X-$i<1\,CQv*wwjxi~عỨfW; O7x\ոeyf&ͮ%&],[;+)k?:%',fG|*eRnYf?4%zRD#>;vcnwpk6kaCZ?ls4n0pra`JԠMTC}q2eB&*g+bUM )U~2ה\7Mu#R9>V*ߩ=.e9|~F>?QTMM6F6uj Md ZiV7ͼTIJJLLQ%k|P%yQQTI]iyAQ"%)_4!rDMA,SP͙A͠!JaIE252PMC4)Z(/+J>'rO @ tyB*D5cs?6ObfVɵxIPȗti[a4bv!ҁ{i8ݘΰi?XKj-MXۇKV z>b8G aѡ^FC:bv@vj6ӝH ?U,#S#'nf7|&ǿ '%v ]g7}IM 3%9QdN&Dy:c>_| g3d( lb$M ʋ!8'?9,ėdNr 7M^ #pwL6Į6A͐nfRb!ܧ+IA2F=k%d"In¹$SF D $%$KLgүɇsĐI&i$Ј)"f ԇ`X#58!p/@w#+iLV gpZ~>>~f^ƒYHL&e]h丅!0bپ#qck$dKHrؓ܎$)!Ǥxr$ΙyPHZ4ԵT=>-;'UROTkf›-/,r= l0vEZON<)k+ZW#["G#-x򧽽ȻCS#"?< AjGsS=Јz( $KZx_ v[lFVXhM͋OHZzx4\Ia _k~o5c-V7/'$&"Gs L/d5ӻə=bH͏5}ZK֘-o9^Pg2oHQ3}eѕ&fU _nM_w,rU[S`g>/x>H)ȟpᇸkf̽(xnS;q[ꡬW'psu4 MY&SgևZuyiZٸʾגz[Rwv?=yM´^iӮWŀm6_b *SeZɿtmδ>EULb3MJ&uluV7q&M(dȡ٘9IZ0] _y=c>'[qua ̌Ikn_Uk[l=9|^ײg:=p.p2;'ᴋ.>S> %iPz#l^b%*KZn6BDuӔPy똪N5*f>؍]GAf7}b6K#eћ\%v](8m[~'b9puɝXCouE"_Fܵ}di6?Ҫo4,L+ 箺[p5Ծ&O`:t JҭR$ $爄dJ(i8m6\MH7Ex⑇š^aål<I,##ϝ~:a,5 ^@|WtC᠊y8xN`Vuj xxxպA;_},Dxu H>XOB {,n=I=Bɲdp OWM>\ HK9Ex'[8|TjX2~:XjfKy{>rUHqNL(N(v̵ur[T{m6Z Xvx9쇜$  2hM1Tҩm)ҁkIsIb5Q[kRK$Ք_nީSz ;h u3}$PAy傖^]ʁg~E/yOWuCEy;ѳt KD)dgJP~fm/SW7'r"M.g 7%n|_=a<'}k2XRzrjСmA-`WƠܮd6כm'9 Z{6!91NaP-M+}O:xM7Hȇs1掻j\=q,AٓSqࢧln=+̭@l,VQ0sxv(T b( BX|c@`/B]u:+4̭=:hL5:(+ Gv-`ZTt5pztc0!\;_nnvqXnh<۴RgN@n^b=in0Ot~= yͪjn ᴑDfN 9#+ITd_eµ.*bʼnNqV4t-&$JAp3ɲڮ[?u9!$^zN6NkiA5k/Gp$r+2J-bOA ZN|v0~䁮M3*_RE>{Ϩ_,sD(WlLݖJFS[Lݓy CR鸂Tp[jkӗMXKu\}9-`"Ϊʉ.b&Cєiv9&#Qtl?K?#y8;ȕ 1aXfzo4 C{kM-ĖVZr:I? (RX>+nBį!8˩Y'  ҍmOo_}ge;W>w 8{_zҁ;/9-{%HϜljT+[ )qkE*V*NuCu Y%^%PA#}Tc20Ύȇw>a>r|Ş`}NGwK r8(r 5NIfh4GpA8K δ]7isvح2Om9S`1`W\zb@C,lXق9qF>dNg&'Nxɸ'o G|CT4c3 Nٟou:< .KXuG3+ P3•Xd'Qw7ɜn*J)>-$}#ub**g\! aZ(YvF\s`䍯~v'v[w&iaqg䵯y_ԯnC+Z~=>+fXX%t \lnb1zNcHʌ O6$ ֘#&$mﱓ[݊20Gn챕 lgTWW^v%]]YI"9k}Hw]f[m-pKIT>#78H΄ QNfñذ"OXxZS:_!22 p9G[>#.*ݑ={nq5M[u~OE+gD2[yr4ߓNYJbXwIjHSTi+o8't>CVT?Rj# _Pϫ&$Eue,^qu:_Z?ǿ?zS:pQ8; UG)2}p8thBN0M A(h0ěO0Eu427 z (G5a@=!gh5)0jXWw qPg:hyFNWIlrYy8Rnel㴟@u(?yU_'Ry8#p'qiP)J RpWqJtMmqTlMq2}q2|<]S8kl/q9UЏj> <4,VhoE cz3֒zoaR6@d3j1؁:^uR(@_Ck`6,5M+N&-,* ثd_ŴB[sZq泖f{"U3:XK bȻ1kh2* GL:j3.ʱ9tZ!odmlͣ3נ:XFpD+X#^Q)b#rtmcVdcM5s)Ji?kreXOH-jE\{/8^Fr.hcmbY#:\:x#O͵j6],Uo[??j'u1N*QkC)ſIkyyڒ&m^mMZEkG[kGCgKIZڵڢ͝EM:645N*hiX;umTVѪ˚:V8)o5eeGUIZ#oY5h M4t\Ziжt]KgS 5vhҡlZҴ~hKhVѰejmU-+mQ m~ֵ 'j A[е&׶vi4lֺ7 uZgزm-4Z[G T& 뵶kZ:+63˜h@`m]+;66 cFزnڮFP6"D뺵 Z5+1茼ξi=%bZ5(Fl*FmlݸnmkCJhM>֮ζNiU347mXC6ۏ:- @B*9Ƕjf1΋Zuv(2w ޱՏH?kf`3њhR_D5R7 ӳ@],m#̸s3 gBA2'ΔO1P͜Y/ T.(ʪl&KSr#1hyh]:*q3䄶T8>a?^})繻Oi0iM3n:;``(G\ʃD@[ʌ~'`;avJ턕 BCh4ܵۈvA85+G:Ysbσ*1&)f*;lO`d>9(|=s}.w~\6>w2eh \F']\ (*&vxC^(SC"L$ǩ;=08M6xlSQ8TB>y5/S)ȇd<F ^> aNozq%3@ ZH?HױNH]67i6h6mmrG=pG=zzAzQ Q Ռ88G5pTG5ЁC8tơ:pC8tƑyy#8#8GpGЀC 84ơphC 84a+pX8a+pXO$1C1Cc8c8p /Xq`9Xq`9,q`9,Sd `6[ m   d#!1p#!pGpGp0a=p QQ\kd8kI7V[ C eEE nD B v""K\HWAjAH I { !EI[tLJC =A(D'ZН, אae$;Hu6~+ٸ\!by: ƌ22gW.o8c zWz!t"Hr Cl] IC DM {ńoTÙY|83@8s™+ >2iT{$4?Oԅ3'<o /E^.0o ˀla;@ AathkIqa4iao Q&]x,&BzX7xOy~ły|J?WGr~pJ|z>}CwP};Ƚ ޠ'o7ۙsһ;]K *&5Cjp"=48˻٫{3%_T(ʏ>Om|iQ?iit4C&4i*%v*eʲ,ʼLd$'9ӚD}|'4n%#s"4*Rx DU+~.\3p^PQ*$U_^ӋP"1ZRӏd?z1kk۹]fn+UY}<YX45jqM@jm("ڪ?0  1ͬ f jk6bm@v5 eRd Q2'3(Q.؁GЩ&2T1=ͬ4F Fs"ތ Fp 5~ 6uI:b6X(Izp 4MbMb_M3orז?lTuC;ԽBztUF64M-JwK?mE/\RTOo++)hcՔ@g:VY42:V9UfPьڊ+bTd_ m:5i>> endobj 31 0 obj <> endobj 32 0 obj <> stream x `E8^U}M3sd2c@4r$n"(To<*끰덫Q>YWU$fݯwW'#4Ԅ̆ -xn;vX,H| !qEs~,ٜKWZl!4Yf(m{ ra?eWh? '.]8c aӮ\$-|Ќ#lڂYB?I.])F tٻ%%BH#aDCGn D"+Z6;NEȇP09f/dAa*Nt^ڣgYyEeٝްT?}(KPx$GkXNm1s[-ܚ]چōYzv}01=VZ$r _L *E CpEZy? ށV#+Ch݂g.GSg GE)3)skcqK(fP{Q7n } g>zgd~@B_c?^l4gYaT~\0%3"syW]7]h/|[ы(ք2'JPO zҵр"Pk?& pU]F=pWZ^ǽ\l)џ?pQx")" d'L)ND#1'},c$!'lFR|=~A9w4 F} ZnAOc'\ŷM>O~dx.6 ۄ&]oAnm/n4w[2@*̀\Ty@{vw b|>J~8 g+ >w'2 Yd1H -} 'q*g<\17fq˸=\3 9w; |S`~*9050ExSRTU/t4Z#KI{w- =蹮2qt+)m6T4AS6\[Hpؗ#I> ~l&I_nǡyy7?ƿc{|kvaD@{?s=&:}%1`n#Or ^& _X6O^\qd$pQ'6u^Bü>垁&F'x.H5h ZYV9Q?m%W`{h)t=Џ-~@C@OA {I+#0h-oǢə'ЦtY J6% mëWE(). "And=#K_vѷ/<q6!pw!hMh:Q~O@dgfy247s)^@K&o0ޫ,26n<X0[?a|?j]UYQ^ֳGin%‚d"?Fr¡`z.C۬Ix`T20>!ڜlh!C4h֥9 M=9N{g͙yy&֣5[It`<|h@<ڊ'-u6`F[@f; E~xtZ3MQ=~y~i9¾{OۙߧL[O?7@|{@b+m$1WCVp R;H-B=9UVנZ6pVQ^YqRA^U{w⛓#.ídYt,1"#qD"8!/ş׿B#z@a1O?R[4{% ?1[t}=C?5ph>e>&O^n3#rp60"'n56ݤZ{ E*oߘ@Є׼C8'$ %wjɭ0iy5 mC@C:# Sp'+"|oTUi 5i[-g a`Ky`8agyq-YndI C]SzB$BF68h#yC#DsA{6Z>XFt>Ps: {!9 ""nF nMEEUՎ (?ѧ }煗,Z66_iy& /_N\$=̜D02P+Qt(%ma 9kDo%VCG:hR;my E{cO-Jz'(߶dv+STrimk?pRj{ԴCzz\.%zUV3% r (*KlmA_9=ɗy~53\{|pG>;[7'pW8%버S~FjJ\WvQ"O$GB5n0Q2TJR*ӓT*_䬮#k{UYLхүPzk@E!nR}{r zMǭߨK)Y <9+l4OC2(^ Ms()'GI%$zInoŽwqo0$ WmUҊ١:7Vqʜ`')=MrAZ:W,F8!%D(ؒ{v2ׯ|0xctksv͜`ȋHt::@~9Iݯm^ׄp]<GIr@x7Kydm S Jf?'[thB4L Y(WVȋWHMJiPvR bp^L^z ck)^jtS5kkxHawVyP˫nSCoQĀs fZjHVkyavfڶJ\({o$-J5|y(/ QXs5Xk)EPk%W-vI`=\p;tӃcFRNuzRJ2HR(+$LF>Po/.^JZDy?bR 8{ͣmooMuf%;::pa|_:`hqM`Hy292q? 5Q-| 3KMfV6R?m…k=7Ϧ9BVmNLizDnj@d= L{ =pFDAKTB_kF.7=}Vrl{JOۍkqlN žJOF$J]!x{?+`4Inwѧo}7o=t']6†K2]#'пbJkmm@lP']Ud&pR.IU{UOL\X4qhYYE˃W,_1!d!n:Z%} A0|K> G냣E)ڏG!v Kî>;{tQ 蛯?fQ\oo^wOogAԁ͑ ًmv)[2QXZ`R>2WnqׅWI]ux"Ui&omσG`%I"jĀμ񨤹8m\pKDVȐE XESY7v46lPGk4n5ۥNjtLֆ5A&m4LZ϶E[yG>iP^\ Bzw-7L=J9P*Ʈ} #Oώ/o"p*xe_PȲ)..*B-d'E"F9D'5H1/ZEFkM@Hjaz4z,ɉD5f,f@6D3RXU;EՃ=h; 8,$AgT:fn4*wĺf6DZ2NQ(3(7Ξ!}'>oU x%{CYaݾY:͙BGq8;:}gb`0?jMcd= QPwA&KvV3[anG"𲞴_Qq0חZE"30=E )/6PF^}L`y|R!W̷|^/<︤K/߹) ZsBzpO}'k-yVw9pĽ|6ߓ3|z'ʞs7O|zp>v;!  ;|sHEc(<Ƣ/bbQ8YO ⭂gc6 ec6 D'K pAN2`K@rŝ 5B?mr)kd@ 7#jj~x( œ%'$d<ĐnWT|ɇ-sZ걨iĘG|0sӴ*zja5ڃ 7Py,van mQPUsC9s*ISr.*eSM$:dP'@HvTk P5OD/{E|@b`ĥ<|l, *Uk&p՛oHa~'Mnw%dPNBDPQɗLY$n+B7H(v$pB qGx9FؐzӜM= KoȷYU!E"x`Zf܈;ĉUj v*T27hsB9ËA1.^_*:4eR־ʸxv:-7ӓHΒ?]^;"}[HSYA,hx^܇Qڰ`pF_BX9-JsOE2hdQENV4Eխ(ȉ2GB݄`QSE J$`Ȋ|*Jc I!9{ jQčEncǀ@;<0CeD*ϳZmY:mVh*n:6S)5A}(&{tX ki&k)Nٿ:3H-d ͧ;k$c+o\ß?Gp#҃V\8N=]9Q!"݌*"kqq*ԧxhqxz뚢[= V@'O <_x0poO -8Bm*Z$_%m(J+꒡lKcjV{]?)GU zi~,O-ZXD¥ZmͶMlaٴl}ͷ7ymt&f sV^pXB 3 0Mӧ!9˧f7|g<{>h;8wؗVra+0pu+riSuٗB7)e >̹a W\5meΫ[_|0cڅݯsǷ]}#kpff̭ӏ~DoWulhșh6墰|z^ Ycֲ27R('LΏ_ܧ|Og@p?`4╞_G^l| E^oԷDPX~mvt(s֎r+̇ +̥Dn~\o/vTQ0 (U'֧FC|,CǙp״/yd']!bfZ-Xi%._o?`6|k GěVn}[[p.({ ?MG?߽'@M;ȇF-c{4#`nZBks@P|s+r,VN!)Dlvcwe8rf={We*[A$`XALr!sࠒc6]Φ+efj!V ٚ9m^Q ;ĀymmkMf߭;DY-!3=!)^ @N;jZkfWçzp0w+]|H0} p߂DDP1^h4.Q@(rJԤ$^r_rO&s_< /XDUT[2HX4>6QQPTrDW-a,E=iBn+(a20/)^Oy\IG|X_/ %LZu5Sk>/;F~Y"7՚:R-~=csQ`؃f*Ăl¥#ŀ\Igpp'*zHIg#hPlG 3P-+LЗ`m-: gnW,MAV -;i\qta:VҫhȜD]珱Ym߮kv^vq[~[o@֦PЉ"xqwӇ|m9JrEZD$Vio˝ [\^ *(s {~ ',V(dI}S߾&BY7 8}4>R|d|FY>&A(%; |D>&r; G6맰\+^a=,& ɵ!`A lM+h DA^YV"/@ k!d8TKq*L);{TdzjWwQڢ:.3־- Y0r)}-=w:R}(P'H@ XD,*H-&B>.M}rHv* VG afhݰ٭BSr$V aN9/QƵ+PVvIU*C`e"H,x6i4W+dJ e-^Kp7I,}3QESyY9SC_(g)W)DQPdpz+`_YС#"v4b:₶1wbATZxI pˡԡ*e Ud$d- č1tDbeN"s ,aM2[qh!4 DȐy ׷m볯!wV9ilǯT_.Zl*Kx9_i\!^%-:ȅZ lg7r^aYcW{o#'=h}#VEcu,b&Y )6;DdIHq6b-amͼoTQ-e+f]:J1Lq\XXP HaWT34u,C֏ӯi/d9A% X FQtr2ԘmW%*9Δ AVjY I)7\NIAKNbwh6+"ITtv͆i݊' %:J h} `ȣx:q=Ups \O]g3(0T}BVꜺR5IמSkz֗J6.˰qZQ-J^ex a@,#;%s7X2vJQՙ}t^pޠz;B~I7ǮsdV|5[ݽjT Nׯ5f>bBaJ%pxXk6WwGEy rY}o"%+= v@Y;cU, ig4Řz@H@d==MMl7A%{AQW[UK"NS')ϑV/{__*NuNo;)dguӊBMEάeV;mtnuӺ"ډ]_EDOtVNjDiQg('v^)i|exGM%-]KF.:V^ 3`+/Smr+,V(me5l$V/]e?09ZUu+O5΋UF㽠TKh*Z`;1[K?Hߎoh73gZºt=+}<Hs*؝* =Z4+TP0 ҙbA=ѾC JdwZZiP !:glt5zV˭+W򬶮wlpnpO٦?V];tpץC}F;gtvL"8]AWp\ 0*+.Z(Ii0 =vn% i8TKNl<40C [FT롍ҸZU_!-JPv6<0}ޯ:rm B~8tp+lYkyiH͜]u;ުj%RS3,2U`VTBR<:wߒ!>GRP ^$%}i+'Vl C9|aW\Nˎ Q/g>Bro"Cgd-ZAEOЁJzpUd wmƹwﺫ`^>^8!,F.]Dඩ۬z|q{-D[ӻckKGwyҀR|l_]|]VhTQT&ťB~eQuA\)t7}wl_" L0{@_y`ث#o|ՈӟgD1-J:$IDޤDyqe.JawP.ǰO( TQX{%{"UVC!u@q;(g?u0ȑ#kM7M<<$.ٺ<=WG^3]9zEQKeu;+^{ }x+lM|>K}_q݂ G=iCsQ ا5Yj_~b/eGY?.;#Q㗫_Aǧ&OlFOlv~)g2 ϠElY&[rBab]^CayXF ༗8m{g)leXD8v!,kxFv,l/e-~ ïe Sh-me@v;ka,vXbZ | c~SѰFnBXhV'"EHur! ڵű !=!ϭ" ,  C(62tmp~-Gs?P $B#T*GjaB./ 4§ L2Bc4?8Q zI^tT`43|hUC029/ ۣ0A6, st}滜CAscYXBY ΖeoV)J<+,L$x0J,w9G@PE8xP0. [x΄e4PhVo3ۥ=!vw rNn8( `?-]o,K1(#=PoƣhlG2Xhk{KiGKEcm\ -e{`; ^pf?Kٱ9rAoէ˙ߜ$siQT wzTwjD3B8͆;u];7~NeLF2vG {Q4il|eZJޠ+~}+$؄l%@]\AMq?0ts4c5m:S:c C:R[m?Cm>߽oәwνwۗdeI65XqBm2he3r" Y = |nI$,)>WRzb&UoNV 츬,tFgkVM'dii!>%X9%)sJלiJ~ZְP1Px~,9k}LRJ">)OH}ՠϾɠwSHLizkEeRmW9nf_i"~1YJeFFkXNȳ\W":0\Fqe QnXqWUT5`P #y`(`z׉<< vlxx@`f1Mt G[RNًRFꗠЫŬ[%qB;῁j\]eNl:^`8e;U2Yu0}Lq)  i-9>a~SGWO%FKFKO|-!Dy͠J3 4CllF5}P ~o>X 3ШqS(5.jez0[*jRyjF5i?j&UT qAفO)EEkkqMX|X=?H|E-}Vͧf+ðBl8@+F+pX֙Awn$~^Rfk@Lg `DϧxQ&֜OW ~_t9λ.Zꦽu7k!"9r'%~{]ث79N.Ǎas0q$әW|rSO|FMLHf}=Ȩ{%%B]4d^'1n{.Gw¼!2xC9z SxV}+GP #9cҲGz#äbmh^njK|*40d&lDc&2#DH?vGBqw+p8%px1ÎGm.X^(I5K |;8__/9$'U7sVih Jj!8f\]Bo%.Iq[%uJsrnrNΤ)Z\..LJCF5`|tz48ý2tD3uZ m^'݃C~-mwEᅞ-[:1m`\=-۸[G"js{\Dy 5lshum9!7o{mՙ%ܭRa,0E4UO;#Pb3V鼶FbHP(wbi$ endstream endobj 33 0 obj 21235 endobj 13 0 obj <> endobj 34 0 obj <> endobj 35 0 obj <> stream xz XT׵330^C8G0D(0F% a0ikBLW$ƘG4Mڴ&7_n6Mz1$}X}?z^{u c R~ @wԥoV &wrɉz:Wv `Z?nzMQލ+uv}WHFCHID<׽_(~xjķ- ™-0~ӿҏx@i|،Y NA;: ib;g)_ȥOipQ0wcxpG~!Y^Wb F$ddi$^D%ZIoG_gpX8!.!|$woc¹pwxw0 Us \ n.nqp?<OB&/$%t-t-}O5 -}~D&XD< 9*aE !&QYMQbuA E7]n!wto҃^/կw]ҿ* R)$,}Mz113:y~O Q>DE.CSWw*$4Y3IvB0>'HCCxw~-jaqėE}fG(>vb%^&YzWaȡfkC? ;}2IddAЩ2N gyyOcԑnZI$M~Hަ .ݯA1@|SX-t pw9Jxo?G3Op v n*[q/<*1Vq82kEsӅaWWe>5@CS47ͨm+~Ŕ"tϦMcw1Jujh_a $m8Ҝ7!ͥolg90ah<թV-qk<3<qqm 'aWcv=iDƳG;pAcM۰.[ß.{)E- d1`ȟG0/T >.xYA-*v>X߄Úa̳تr6D{4\mc,r4i㜙$mbӜmvL-)hș AO_hkhiR]mmiE3Liib&nfHSlP?=䎐dT mٔ/ ?dxwyXbl|,|{:,к-æYXwWՕmPx6*ۇ'~W§Lߌ&1[)FƖ |Po4F i[<:yM*S a*à`QgO8r o44@{j4(`7q:W///_XOJsz)&%&/,)/ko?tKɦ5ICY'y%sOZ\yVx-G۾P}w4eYP=*wڕzӺkK縶m[a1.\XH2& 'l-]qRqA*T7xre4;>;199)f3Rs͹)v ϵ2ѻ EJk*f^ɰSS(gLN6nVdk{&n F1"/:P@z^Ω60SiM6L)\pT93;۸.oɓ="Ǟ3xGr_G= HX(-p_Jv:MlE(V2\B!"xB-Z|Y).m]|^Ȫwwm{'cR9{pWY-&oDfe #k_siEjaB#^ <CiNܕu ĜގKn`[Qي<فU{F/T=V XAUlITKOJ[6gnV|ImFGdtsQWbb,*8 J!'+UIs`nZY%v:|7=,AЦAE7+X5]F+#;?=sS|O}(#H/}˓S'uOQW_3rý/ _p~V|sK,^kiIn-N*S\beu.[,8**NƇ gN~@sn2r65K"]rwސETȰQ%f,e`۔k.4HۚFB49]&0η̞Ӯ2\"c5]UVZ#F8~؊Emi5qZYD,$fIlH~IdCJ y#O{wZSu͵ӳbʫ{utꃣk2yZXpzCB>q^oxp(棆.shUdA8 bɠϒ Y,MKjZ̾R] _qWiKͲ:'̢sX@Tqjp96^`Xf|JCEZt(cOoEĶ[ PnMѢ/T9^s8Uc;X:-;-,߉nC3sI0!Z >&O ˇVGcr >d 1s iAK#N/f^>M60 =0h=Ե:>9yyLZ_)"[bwƊ{„ adgO9%B=[dxa,sz[v^աoZr]w?8u\о*,[ylT}jHվ)4럿gKOvސ.a2|VZ6jL\zL쫨4+ sZ*#?!/GV@D6 9y`ܪ>*hfUpB1D6 h_: OL!Y=7E`OG`=!bQ#;.a@.n&V:]{nU\6z!H%E`#t"l;Q3'{!M:a?,,>[c"}a tC ^H5Xk`-_k Z5Xkg)j =EP Dz2Ec!`"0{3['pFÉQ1La7fD`&p2"07r81F`cp:?ΈeWz&"0Yc|fn< h{iy>Q 1/b,f*4rom-t##m=9^Flڪ*1J{X a?3CNk|vpz?743s)~S 2> wsMz/tq̳o mĴ(~Aq;cEL tH=E+g-e3k2ye3~-Z#6m.no:~mHge{֪{"gQ ɼ9͚&ك, VK=j5>x}}u;0n x;=^wꀻ>=h1H`ۯjś=ԢvoBք8\ѶQxT;5M}ހCm Q>v`_ (ȚZ{K]m6Զq8V݃}8uA墒fߠRlNp»q=,Ÿ5эO*'=6V֏I }x<6Vz4^%B1ڊÏ`GǶn|mC^_U_q*7޸X2# ?2^Xhl4/#`[W5^7%#I0c"vx<-rF80wӄuu`yͼjˬ4omoy>ryr]g<POd8S!HbJ!(U J> ^R ʫU*#7/!ɩ}}f0HXUr#Y Df%gqQ>:\*cߕ)SB8*畿(O)*k=LƔQꁼ}iQT6sJҧrVOv(MjYYr+W*IŅڼ!O*NeaZ†>,PJk|eݓ|46[q)Fbw1i4r4\Y"K#eH4R$8li$CJ4dC!`2 zh0$_+F^f^daj(1PX5 u3PM ~hSCKPg_AuPqEJp.$7+uAi5M݌ =D`cS2m(&pUSo+jn)ˬ+kiQ?lQ~hWi\RJ6":dU|$9X€pFs]Pi Xň0#8C3#'u @ ``A7bEr endstream endobj 36 0 obj 7146 endobj 14 0 obj <> endobj 37 0 obj <> endobj 38 0 obj <> stream xW{pSי,[BBȀ-?c^!̣IJ%[2y8`J`4!dIjJa;)dknIq]mkW4ݿ{=~wG@=vs&sҴSf!ѿ\s{K/^m0ޭWb8~U@a17LEv!⧅; G;3ZcMA h`Gh&_H>xko:XG`TP̓ē^'"`{ +F _l6sBev⇤N#Fԉz5$`?!l8i({D=iU5>5${<NH&Uf%VJ^oe)Y%45XGٞS3j)c|0&N& [HEi56*<,tg:|=5qؠ;QN)a(^81װB\ _*өs8Iwo `%eчU,p]{Rc`| VE$@<)!bWXɤP'&jj\O t%Dko)=+jjĕꪔ*%RHL*UMp77$ku5Bg]jjdM'IHRu*IITGzyx]/J˃R8ՙ^)6B ΄ϟ{ JtGTæMrp2=+ԮMT&|U\SN\M\ude)G*g#l($”BrMr.g7Hp+_RAP=zԨ3W.'鯢f5Ք_LkG/)@BO/^eJnӍ#eVva;0w_kqLz LFtݐ %Cec!});]99֝;#-sK ^$s sMd쳽s+DGg^Xwx7c6* = \RGytӓf\Xs2m /.OW0ux;ΠAz)]5J"V |`!7h/U=r@$-R4ډ'ip6EkHHZz?ShF|Bޘ#, ӦtN0_h=P+i wJg%oYY5$-ok*)ʹRc!-)"- ҄,f+K#P IY*Sl:uP|[(X*[k P y%eYY ,oqYewRygC H`(ob2u<Fcm}B:i qjh(I JVu*#ixC$z+NL5$ JTyjI_G1DK4TF!?ibd /|V&Ⱦ$Q$A(~㰙d1u<$]N(GFA(-$KHI_b UIg;̇R:gzRQi!]SQ]zglkS󌫘)ۉl꿃$~Y߻OmKaoﹱ߁(?m2nkĽ-=^m=Amg;NӋO^rvّ;21eRmƘۢxz57oMl߄tO8-4"5cȄAdl1Ѝ 2>I7xmc \ǼM7L>׭uڱƄkd\*W q.Gqecp7VWYyu7VY!.17،". WNr^= +:xEΥ:pNYm܁m ",:|v^V,!QI>{̼؂Ńϧ=EF1gP ȈE qt^hB{\gq ,M{N#h9eém|R9w.FR9Nɵ)9OSyd6ͱ\gC'dys9ey6ޏYh@+1xlrHkPˍh P&3F #0vl endstream endobj 39 0 obj 3425 endobj 15 0 obj <> endobj 40 0 obj <> endobj 41 0 obj <> stream xW}tUnNC>:4I'$BH%`@HHt&!c dF2-qѸΎ0e9s3z<* ?v:x{WU;nE[2IN0gu[򫱿d5э KWVbc}7N~_m$oHA6ג&Q'6nY{T뛪CYLjSOOjic+Au 8>PH8 _I@G$@`_˼ujŠ['nvdp$ok=Gh^>C.u@LPHz~$Mpk?%A&i3 Y!*a?@ 3u}ԟd3:֢d/"i)uxC/j1*RbяiϾ4mW^I|My }ff4m{oB0y/} `Ī1zQ\e>4TzeR _ZOHO0<\QYGϕ@}dǬڑ5;=A)naf \Af-rhG{(Pt{<ʼ+N= J)u)qsDƭ{z9ghGO185 qA 4c;k^[x=^TA#O=A?gKkA:c@w2I `0zajyZ.E_uבcgS'@|yI3xf:Y!ͭ>KdnYA;٬#i#N3vVn+F\_۞`#- u:}r#$QRR@~g?vYpL0vDUJ f>7غifM6 <`Hx:e u mm#aPAy2p(u0m}$ۼֱLʒ\ ϖ[le̬i7LĦݐDNHr餣9+}'ZgLY04f"IlYZ7,RXz\9xG䙞et9o[[Tt4;^=)+?Xky-IM()ԧT[)tkR[IviC|.=#&Yy^B~D^E~836q}/#v\ LE!tÖ\\$hxR4Vxo˿ЗRǖ/XfSd_;w5mjGڻO?Mw8ewb{Xݡ~6L4RMl1'plLbz.IɰzunS,YLNNbGϏ$GxB̕3=zO'Ê}S92.6f'Y_.a4C% +7 0sY@⌁6قn%qm Nd]^+mHУĝv6).8ji" Ӌ"dcL[9OG\LY|dÞfإE[W?t[:ڰ^ړ-tX͐Cםݖ]IF )WOCeJ5%U#F9]hMerNv|vnfuVScBkɏDA_`o]p'LD;p xѡ$RnGFa#,%f6cFϣ9^HZ0oDŃ^vx]PbK_|pXs3Ygꫨ|sOvn˝۷<ѥYʽWZ!zn0PCǍkmf"Lh4(%]^:١7:.jnQ#12*]J};2L-Sp[n_tN:WW0R!0<55Ŭ¹+%$Wp7$^ i)I. _F'HO&ZП8r _S jPQL2pzqZؓvni>.ΤK&M{-<_c7Ϲ:Rv0i?.zD,=t'=k-6,j+mԟJ|l9!G.9I/SRɴUrt)1_F_,n7:;N#x8-Sqɑ8#8LxyiF|D֘l$tp)Nlq0O6CT-ܦ溍ʳJԩ%ʜh>,lS֩ʆmP[æƍJY!4HQV 5䎛S_TcZHK-λ%Xߴ5T_W8=S75\)I SKӯWk"Z947+M5WncuKsenSCCSr2VMhf@`I@% Iг&ЏTQ4J~I"dijM^k%ꛫ*fjdc_Gv4q,h|x$!mU&j6,\.i\:Hq<6nʷGѴRȧ]jDhG"oi3he\kFf 3~&m췐DշTY[q(nasj?:\+ĤN~<#p| ~|SkO |]o&:U#_)ėWxI'O/ėv'~OD@e8_  1_К.6V`L>z30y?>Ɵ :Cq3D? gST<ԏ8qP&Sx$~@A32 :ǥ1O?&G&/r} /G{= |$> =#'wWỿ,ؽǻøku:5];>+pg?IC=;Ǝ0emN*]`-[[[;~:I`Sy}7oͩɎu&IL a5-Wݏ I!Ua!_|uo'a\54c f+jkW96+p+x \(KW-lŋ:b:qXVse|| @ξ)0fxg QL%+xi?̘KV)X,pi_ X$P`s<ߊyasuax ̖<Wzf S$4'q3M<Mi.N4Rڏ)>"00'p$.;&6Qw tYGF Zέ "Lchh$+F \/T^2MvkY YzYwxwE_`4uj endstream endobj 42 0 obj 3871 endobj 16 0 obj <> endobj 43 0 obj <> endobj 44 0 obj <> stream xX{xTյ_d&O0 CHx"PI@0IH&DrE*6EyX- Z*VR sfb_h~ߝ>g^{k=&8"'a|.I`yKҚ @J/_#IHx@3*)*}䡙)cp tKį&OIic gE V?TZXېN|βҢ_ ]UշYʢhƓ0 sV7 s0?cjŞw*yZZA~0K8?;ְDonz͆NsdI`: xNp/X\v \SҶ`;q1ųRxJӚB44 $4}KPNbJ p6Ja&(#XuuҴK)Ӹmlb+d`ywJ u/y0NQޝ jM^(mgYta:>YV'x$XyMZ74i2@.Wl\$sĻȲ-{>~\L-)XA?+ 6^Pr^hf?B3irXI|-6~ !-R1k kChX~^5P;Ve$:-g@|WRwXEl)!˜[1[}SGQ}~ y0-o=Z1wȢ|euGV瓆A U $Nrb)yĴzsc\.gnkǔ֎W~>2߱5 "6DXZ"oL+8>~wޠFYQnEvV%4d+ʿ%Y./QMBA0>+%RJ]aV㲺Jd˜?f_Wj(Iݴ$0Fh0,yp.=hQcCIl@֊\j )\WDVeJ%õWZ J*-26mPʰ&%M^ѭbk$l2]J:.kݓe=_rhF$ Q ie[MItw+]urT`+=<‘ܽ%Ŗ>x6y,q^fY&O#G휐9`kf p|W߈ޑ҇Oy8$b &j!? j O4?w@=Ֆ9! 5N͘ @\mR\z沺ͬ>$&6qE\;O7R Zn|(ٸ⯃0HF ؠ_mtxzP+3 ^]V5W}ŬM栾n+]vZ5]j^ĭ)=ǟ[gG`QT0ʼ Zv"C/Rhs58ߌmnk ar٠18ec@ծ#dH5KȅJ,Y,[765>ՙJVV[#Fm6Ϧjp%CL zルgJ5Q,6@G䧏/*ۿko߰Ut*nk8:Sxԁ<[ŮZ6x_S|}|ͣ*o^ꍎ41Th m6۸HF=6|K'ɯ Wc*#|olVDsؼnU}='n.~ˋ|-~љϝ'GgL[5 => RѦ 4Du7Q߮$іGnE\l} rI3SE8.;6.`:d{#*7zڭ-c -1OjsS8^/KI@žTl[z$W0W37S9HɌcjSdTpj?5k>o_uMμ7s79i&[j홙k$s?Ku%a/оOF.3zbh,6ի G+uOmbΜߥ/8Գ ب#N!g)\D==kaT)px{HOllJInnQ;|, l(L i- ypk8ݔ<rd@DZc߾.ո]g{Z2dKIfeMƾ)*e:U-6aU7q u!VGe(Wu5=~@N>hKE,q[a=('~%PPkևQjuޢv`;l] k'BzwR[%#zQ+DɞԎx:.kNy R-Tj4@sNj^K&HG(:ʁ64CO\ w|]-<8qZA7-)r4fOVnƿ顇/4#KJژ(؈zÂg maRi6jgc+U._RLOMrXTP6/>ss2% ; KB#2 + KjF/Z䜪rN-*\RK\T|jŋ +Ud;&Ҋ҆ԬwT,r:WJ +q˙{/^\YT5ylXPEJa"IJI[i,"YLg$]@*^ SFT5 HLŤy*/VUϫ:A*vR+S5WA: Hzi|!qew̡ JBuEEo%mr'i-^ $@+ΣUk|K9d򦚾0 RT&3.uS߼WDU3uRsվ2J3E$["ҿFߞȖ X^ ~n= 3]%jcs^tn8V :L}ڨ E}&zU:dϟ5ę!U^3=*QpU9I0o@!x# ^\oC~-_o}|敯ſ}vN "/xَ_5c%qx颏_jƋ>R_S QGshE7(/:9gxNkc?tO}h~hO<^o{o!f<'|G-~Da%uMqp6 ߨyx+yo_^nH^piVBۃ?[+6%p3ߙ;V݊/_ /F>| 1 _ EfZdM!ز1ܘh |o7 |XF>nj};8YviDyv!A??H *"~;'p2Kۆ |0'DH>^8p,qc07sH3d[K^^ʳ헀^38=&5jǤ?z}(#Ʉ7pq,8ˇCӢI8D$;,0sJ&a2tiԝјBTJ$&yr&%$;&%eD'abn0=8@/ \nCCyo.gwՠ3 'a'0V`/¶JLF )04DpGFIh` Zsk6Zh~L؅M<4CؙC lBs.Ā!^٤GF P: jjHF #sxnI\t), |ukY_o~bvM endstream endobj 45 0 obj 5214 endobj 46 0 obj <> endobj xref 0 47 0000000000 65535 f 0000000016 00000 n 0000000784 00000 n 0000003405 00000 n 0000000723 00000 n 0000000582 00000 n 0000000080 00000 n 0000000167 00000 n 0000000279 00000 n 0000000382 00000 n 0000000489 00000 n 0000004861 00000 n 0000021117 00000 n 0000043379 00000 n 0000051467 00000 n 0000055829 00000 n 0000060641 00000 n 0000000840 00000 n 0000002867 00000 n 0000004181 00000 n 0000004317 00000 n 0000004453 00000 n 0000004589 00000 n 0000004725 00000 n 0000003664 00000 n 0000004011 00000 n 0000002889 00000 n 0000003384 00000 n 0000005555 00000 n 0000005746 00000 n 0000021094 00000 n 0000021845 00000 n 0000022031 00000 n 0000043356 00000 n 0000044015 00000 n 0000044209 00000 n 0000051445 00000 n 0000052103 00000 n 0000052293 00000 n 0000055807 00000 n 0000056465 00000 n 0000056659 00000 n 0000060619 00000 n 0000061296 00000 n 0000061481 00000 n 0000066784 00000 n 0000066806 00000 n trailer < <80BDBCFE43F1C6B1428F6D8E16C65863>]>> startxref 66903 %%EOF ./nsf2.4.0/doc/Object.pdf000644 000766 000024 00000555222 12422512321 015643 0ustar00neumannstaff000000 000000 %PDF-1.4 % 1 0 obj <> endobj 25 0 obj <> endobj 26 0 obj <> endobj 27 0 obj <> endobj 28 0 obj <> endobj 29 0 obj <> endobj 30 0 obj <> endobj 31 0 obj <> endobj 32 0 obj <> endobj 24 0 obj <> endobj 23 0 obj <> endobj 2 0 obj <> endobj 39 0 obj <> stream x[KoHWs,~?H `>seD_Sjm꾗$nWu=ꫪf3*8FpŃEt尢.h S[8yQWLˌ3#Tn-g^:5 _!0%rZ/3dA2U\ A1#MgaqH;&Yff7TǽO+'^5fvIo.o닓U]Y_+WW˿yBQ[o{ <\&:.E+Qlp/ Cǵ5-UixP$fo] g+Kڕv4#AFC3ɠTqxO#_^]o~_Zk)_~-xa0dͻ?>vhzm`YbVв,r(a/zMrb{` GGk-N!78ftYuT|xsG5T#<\-2g-N벸]RaB΄,jW-L k5mô/۪s>wDva.>]^F ][v?s}Ax0)wryR$hߑZo04@` a^T,fBY쯺#Y*0oz$+ѥ.!g쐏Տզ* Saە.  URYDŽwzP85EjSS~n/݃.俄>)gToIVsKFIClkDWH @aY9$aTjH%[jOr[/rt{i tP#:"hx7Zm~-?3ӊAT$/JR1GCB:F)-*֡I;J!52m—0ghʹ0X.4@͸^AW5A 0rNIÛ*e>}_I?-*`]=9# #6:=4%o콸uƩS5R(R*jԛv$<$LCQ('s,-@ ":ĀEdѡKӋOq(P:J.Y\$*=.>/#";$#zoeF3{jU49 X m7}>ZR;8jVd endstream endobj 40 0 obj 2930 endobj 85 0 obj <>>> stream xuRIr0BzT%9x.!ؓT*'-hht`ACXCd3<Ȉ`Hjܽn1U\h-CWk!4ɔE{R9/p:KKm\pO+]ih؜ 5(*PY 9#3]0TDΦh?tq*$;{A?cSbrYМTaejdEI[4Z#d_ )>JKmEmҩW]ںЦ90kiր dZ;/ZzVv}&X˜qc|T]~ endstream endobj 86 0 obj 303 endobj 3 0 obj <> /ProcSet [/PDF /Text]>> /Annots [83 0 R 84 0 R 41 0 R 42 0 R 43 0 R 44 0 R 45 0 R 46 0 R 47 0 R 48 0 R 49 0 R 50 0 R 51 0 R 52 0 R 53 0 R 54 0 R 55 0 R 56 0 R 57 0 R 58 0 R 59 0 R 60 0 R 61 0 R 62 0 R 63 0 R 64 0 R 65 0 R 66 0 R 67 0 R 68 0 R 69 0 R 70 0 R 71 0 R 72 0 R 73 0 R 74 0 R 75 0 R 76 0 R 77 0 R 78 0 R 79 0 R 80 0 R 81 0 R 82 0 R]>> endobj 83 0 obj <> /BS <> /Subtype /Text /T (www.princexml.com) /Subj (Prince - Non-commercial License) /Contents (This document was created with Prince, a great way of getting web content onto paper.) /Popup 84 0 R /Name /Note>> endobj 84 0 obj <> /Subtype /Popup /Parent 83 0 R /Open false>> endobj 41 0 obj <> endobj 42 0 obj <> endobj 43 0 obj <> endobj 44 0 obj <> endobj 45 0 obj <> endobj 46 0 obj <> endobj 47 0 obj <> endobj 48 0 obj <> endobj 49 0 obj <> endobj 50 0 obj <> endobj 51 0 obj <> endobj 52 0 obj <> endobj 53 0 obj <> endobj 54 0 obj <> endobj 55 0 obj <> endobj 56 0 obj <> endobj 57 0 obj <> endobj 58 0 obj <> endobj 59 0 obj <> endobj 60 0 obj <> endobj 61 0 obj <> endobj 62 0 obj <> endobj 63 0 obj <> endobj 64 0 obj <> endobj 65 0 obj <> endobj 66 0 obj <> endobj 67 0 obj <> endobj 68 0 obj <> endobj 69 0 obj <> endobj 70 0 obj <> endobj 71 0 obj <> endobj 72 0 obj <> endobj 73 0 obj <> endobj 74 0 obj <> endobj 75 0 obj <> endobj 76 0 obj <> endobj 77 0 obj <> endobj 78 0 obj <> endobj 79 0 obj <> endobj 80 0 obj <> endobj 81 0 obj <> endobj 82 0 obj <> endobj 87 0 obj <> stream xZIoWQ3il2$BVɪq[E^mMJ{-,p ΂ _^:S>_7[8ђf_ɤW` &ZX].@im5BњqPuխYř45t+=JJgðM;R zX..nLh#GmyeaI3E)\.Hqqfq>Z3\1iH5(RZ~ XcH5HH5 KÃa,r iA *R5J1eMcЮw^R{/2,u!cԇV}PJb`Zʅ j,'5]AS'd`ix*Bo/~"I89>/(gz?*f &園> uPsJvC:T7wbi ڻy=cyb.TB"n2dը{m )6HY)c@ydjHFpzsqHG@UcZ})_˧根 \T9rDN(f8ILUnb4 BXGCBu%%#;z{4R.:$oܞ&s~'&eIk w2I?KID  J<QQowK8&p*z:,vOtٔ# ϱUC->_8Bc11)-:gyq+nNYN6)Ip2*ylxǜz^OޥQ<έAe}aru 2-hWVH5b̰f5nn, \jcdorqdї($v`5U5%cXlJI*`Д{F)04sadB[(C+9 \9sa2bGhӺy=0Ji+W ]Y;&vVA4iưhOBiEjB@kMg2Z1xI\Yb *Ew"9ݔ@P[=a (*θ_Ch/1t^VHRYG 'DK$I,(tj%$瀤 Jz T*n>aChav9%_'"HԄ.-HQ=TH?_x`2r&<M08kqkU Ch8ѝX4|oC75b5Ç(š 02&A*}U46+&iY[zSKO7 OF 6ɅzӒ~Cdnš%-uc}OdK;<=8͖1+r82! zy3U,Bd7lƘ)xc{@Azti[V>fDqe_jUن2F 3tdnM3Oo7qŇo1Z6nߣ"Q[թgJ'Vc0OO7S"Ҭy2Ol9<%R{fL" Qj3"m1#JhX9r)ofc)Idmf b~F]/8ǵF}gBaNzɄss|ͣ)zA-bF/^'hHQxzwe0]$j C'ET.Ef6*NPX,A^Bo\zҊKK*?OdAK(8-wP^zE7mX LnM3huL5AD(=NJ eI0z/n'Po>7s{W?=?]Vs<"R -3 3'rQs6ի}yqqևIF${tG)4%`Os,hj?ѳ(^FS8O>-A1pR iPy^C*H meɺ:l7-*7[]Ċ7#ۆ;lĿ%~PWQBáW7!E}z@YjC7$Zn<7@4)Goۤsk\hXr]'/t΢U_r}9XS~C >9$U%k c Г; 33_ZЁK|d:qL!;a}5^X2OcA.$/Pj)Gns`m|b}11Am_KiDa -Ez rяH?>AWa@K(-@u#ERa:x2&\q_wB%@!I'8Vz]x27HªvU@)ݶw,;2 endstream endobj 88 0 obj 2868 endobj 4 0 obj <> /ProcSet [/PDF /Text]>> /Annots [89 0 R 90 0 R 91 0 R 92 0 R 93 0 R 94 0 R 95 0 R 96 0 R 97 0 R 98 0 R 99 0 R 100 0 R 101 0 R]>> endobj 89 0 obj <> endobj 90 0 obj <> endobj 91 0 obj <> endobj 92 0 obj <> endobj 93 0 obj <> endobj 94 0 obj <> endobj 95 0 obj <> endobj 96 0 obj <> endobj 97 0 obj <> endobj 98 0 obj <> endobj 99 0 obj <> endobj 100 0 obj <> endobj 101 0 obj <> endobj 102 0 obj <> stream x\IsFW6}eV3&lv|)Aܵ?~H 1P{ȷ/@VjieJ9/Oo,H -\兒XXqy"Җ,Mrɵ6ڞ͵j5tN!D)V\soJ.PB4E=eTY_*@Tj)` ?n )%KptLd TJ@G=vt*w`v oԝ5; oeKۈ8,EMr O+7KMT,.6KodhpkF/,| `\5,g`\n/I &xag+v)(:M򤄊>'>lUOp<=BeLpPզpxWdJ*0\.m5tOZoQM6'{>ycS1!23Aʖ 6@4%3fenp.Vf"byvi4qSZt8b "5:/Ru(!SQŦx؝ausV1)FkE8/0~eO@E lBp*zDTfE;>cQmw.3tܭ+вt 4Ey&29S)١<{by[^[kI.]g+d"t֑ YjE%G3`xes s"= -{͕KY|8!\7J0h l4t"ID!愳X=/EXco*O BjgW!":DC&QY!;cc ;+&b0?޿r-Z"C ᎛&E{aqz8,bh*[NW|P{Jj9jD 7rђF9FO4D|9N4M_7KdDsFDsz=6v^ Զ4鼎M:W& a5+-2J;I *(([6;uHo~rHw8Zi9X0@)3@(33'@M[L>9'WYT!i1.לdVMG-YۺMe , lgg8Q|IF&Z`UB3*0,GY6Odz&yt}?<)l|sY*I-Ϟa5yIL Q?*ZETYw]Цx[{;PMlz 1q9'T php46 Gkd/DfJsUlOiOŏ~!J{B?(>/lỿ|wAK0u#x?cPDr_mw3p{A3bc5;yR l{9]v`r. 0u؀"oYӐ"*>ƌj!qcȽsKU-F)X_(RDޠ% O{K2$՚Δ,d Ǝ5\$pI3;f8:>X::qM0{(Sh^C +9*ԟ:q[ |zE1s!33 XwRg!u,A=]qĭ^нGU^\>Y+BE=~WK vԀqGc/|TRTm/e1RNQ!lOGE|l :o{-8ʳ]#|8TA"Q1){G$PEL(Ǫ_t+Sg0·Pv'{)Q\' _>A+~h$ @Ǿ7ݫ0㉜;fZ{3f\H|{c4 @Q$ ?L!"9> Fc{Lw -Ok|2ڈL2|itE|zwC ]jiDnXRX"e!<)t$jTwu: cѢDHN6'd[ Gdym6ėils吅OcP P;OEC8exy. IiWm~mkh]UبfZ70NGn"3}tXa4u%HxV;Ua㑂u P7xwaT_^)'ՙ}Mw{Pqq6iEvK*CrmCz` u*' rUDJ$"AS񡪵Kxw]N5@A69U4'e3Xn(Ԟx>σ[O"쀦e" RV9vH%岜&qlUr=b'sH>{=w^,ӽ*w<<_xKU d#[5 hxZDo+1t|Zqâ<^FE)=ߣ=4am_7ͰBʧmY\} e λBHުhb!&@H8m'Y=@l=*(er'nWZ+TC KJ EPԭGa8m? ,鯍AuV:} ܠ.rog+!p{S Q?J@o|9qF^r[ it`Ly%ZtCn8&[B`y)}YFͨ>?Uq'LŌQQz#G;#® ռqzP\t;,Gnwyl:^ghiXqtJ$um$e~㲕Hs|;R"4 * g2 Mmfzcf/',i ^/@I!> /ProcSet [/PDF /Text]>>>> endobj 104 0 obj <> stream xZKoϯeo`Ov;f搝$DܕE<,UwS$h,UUw}.dZQP?pi)TiBr&REe+KYt_>EVSJ!*Y)@θJ2,~)9.9ND)Ott 4dƠϟ̞1*V\YOdrS.]= Y{Cr&2n??4/^oqH\SS}=b=n9_V-^5fׇV((,q³.eCNې'Jq)~c"h+WAyQ`Ji)\n X]w"MRVMxj[=!=nǕlJB5dCˆbی`_ B&X&] A3jJ;f FIC{ E+ }C1(ԜWH2#@yIGq 9howwz&dO;`֭s:,PqGsM}h<]S~!cUY^Y#9N(WG#&Wh Dh-mЈXL@XCٱ (Slp+ yDrhSpW Kd?g\G"l䪊G+ܢ0MBv8f:&w2dn$("1}l7ǃ$C{3b0<#*/` ~s9W!n"͢`eINY$J΍W1or瘉DA?ø':ᦼlg}g؊TqEͥ ^{*SP0.P4*) νC6R\ůҌ09 0$E!_hg)eO#ޕ}}cu֬|=>KJQi/MJYt0)yNRVN$%BQT,}E&,q-w?{ f /umPS1?zf{2:c?3 ;_:t<9GDg<(ڱы AKMKNytվl 7 Oe6Ts2 r'R( ; c$ ou,Cp~rP/lq9*'@Q{nzc'ެ>Ia$c6eYkҦ%K?A`SoZн(9S2=Yp;ZM%|iSo.e/+ϻM kŠM>;D;RKw#E?Y"N#q8%G !i)OADOoW6>M inFqfĬzAOevn^JŬ{;2*&hҷ"<|A>/l7z.+2|>R]J?9ўщ*B GI@)=`ִ]X)ua'"cu/(($} V| +D +^Rdwe/ۤ_i>%Ntzۮ_s3~qu~(%j'ήi Gڝ^ 魩X3&@^ }2ڶ.vߋ6BdD^݁'IEGϒ®$CyD> /ProcSet [/PDF /Text]>>>> endobj 106 0 obj <> stream xZKh0V~?C;6CY (9!竞7$6.UU_WףyV׬ ͤ3I+3cʋLJ!{V=GȪT%=LeVk\f{\B><vNź=!/o?"`[[N[VZ4!ӿfRX"_C4O>^Ѥ"`p. 2saODQDa|jpd #ܳMq[|yس?VEֻmX%[yy8>co|bL!b_MŜ/`;ٳ_B2?l4E$AT@x]5_KqND7K+ ^H=Szu1qA0yui-S ,Wȩ7EuE+f$!rZ"YW(: _!pL}_,wbyۭ'Km/QH7~MO]UPzC/U,՗fFKLU8+a;AR]T I$%c?+ rrq.xB pAfRqïQ9%RFGH s%*yV(2Rt -Q0DtEi{>3䴤$XϔmK]rȏ<%|zpŗY]E0oU'xʤ⨭ɔ@Mz6&h 35˹6!;cEVpBDbV+#Sl o?@7v.hCMtmqW:?V!Z|=ٻ2+'Xlwf'c%uE:z8$O*&дT ,?C6ꦙCÝ=_z|"iMD7[z  T(gO8&˝%!t&Cl~ߢ<b3 '.3t?㥔h-erHD-RNHu+xiyx{ƚ 'nP۶YϹWpO0FFߙ:v'm_VnccG~m&昿[cSmJ^1}@1 E+kfnF*LMc7#Ms6B&l'޽b5~#(CӐN}h'/n r}b+c 6$㢫bPޠR WI =P3Z]PlB2)^''IO LgnQ}ηX4#IIצmoj,)$N _Ufu*gG~UT<0rk_T': nJH^,Q'6#IƁsS ekjxszUqz4֜&I<މKRz83rnkKJ7ZpG!7-b$tSq~:R]aՖi;+R=DR{|M.ӣ#u}+f(^D4gݱҋ"tp)a`WD6nj MW_.;,ٳ/{EחHOD}+Є@DZSi! WG0,'uobƩrGQýaq:zvYW)H^WAr}1c|WC)9+x2 뒎IǦb)vqE 6j7VEU˙kY}@CB͹3@km޽1}3F9M2Gf/jZ{vo?_ aʏLCԑrom_\veI'~?◖lDQZ zTzK}QŤcWtر(V8:>G.o#Ok(|± vi: ]h"͕g;g񨴧i ^>r!㌺ؠOG@j]P gwmMHd8P=!TmW?w1I%vԊK&5Bnn$03 ~K endstream endobj 107 0 obj 3158 endobj 7 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 108 0 obj <> stream xZn}W ƪn*OyHz@Pp2*=€تu9g2Uu2M O^% &։L.}~ T J2]`@hθ$)P$,sA2;8fO  W~Nh$)Iӧ SXJ)R贅Sa%'QoBtP̑eg=DJ&`vγ}!432Q>g.qC9Ba'$뛿hr|?L`Si'a[`T&H]Q Dqoc |uLvrM5JKcd%Lr)\dQ:yO(mZ~MT^ȺZݏ&~Z2-HhAj(k)e)xᔜ2ХdӢ5oپ7ץTGSrBK&%)9qMT3)q\N .%aڐЂgl6!cqc ThPHm ! --@u0%LZ)J(:S+o!&fA/}) B XT6ؐc.r Oכ"&euQHIȋ  Ҫ1|Gso'Sm K72_X@QBÒ7/ +aOL|i ?T\[2?WKy~Kh B|\ZX5Y>6o^=_vbUx2FZ"tc@nI U.fKS~>RFb{ $u"><8Xrx?W =d}ړp l/rZ~Άڕd{^s0H~Z$j IօxxkD )tbIȹ 1X^X*ý /P[xCʧ%-2MQ]Xe]lG/dS|.Vc}I[4UII~ןڼr2F$J_j.ث" o wQf&9bI96lu~kk&BF7q[=+ܾ40ZQ:et CMPIh~]Et6ҟyg*ٵYaDzd|jg3CGpi% {mzw{;=vYFǟC] 8BݝZ/|Wc 7,KҥΕi k Ua uVQ!/1$ $sV1܅>?1 LkpK4sO7;*/YQ@MXU#1- RCs3:bJUDsQiֺqV&kJ=`9QK}q|cMg:">N cƒN00~h\ؿGpN=ڷV> /ProcSet [/PDF /Text]>>>> endobj 110 0 obj <> stream x[ێ}6<v_&F$!<~H ITHeϩ&)"O3˭>U]uI^2Z\ӍP6XJŔZ3-m`ev TJ2,0 4OR:ᖤM\2C-#|"siօ)j)lbSy(]oIlF-v|H'NMxП?p@D8}\oƿ67߲l5[gձ,>/_ٗ_o ce%LYhY.o ڦU TXl|ڇ8 QkO'B%U…%L{(FLtw%.NJ T ! (&DW<7K_(N7BޓI i q}5(mHn bٚ|_Yz8lUz̋-`bKlsz}yr6o}1J^(?OX)> ^Xz_~}jg.O|`{蓐wrǜ Ox,-?>z{ jx'! J<$IX0`\צR*O.HNܫϫm[71TUqz ᤞ"JcʥdU ^/`Dp?o B )~W]ZP@~!]Z3I(bw5Q9l -oKLJF#Z#3Ņ8#T%n€cz/:* O2/jb$v[_clR_㎙OBA7Bs*255\-¡1w5zڿh-x '@%+Sos:q@׬53]9{J˜C\`fk zB$t5h[ |Q@h ( }ER#{Ǟr3sͦ"!o9=]SYwVbwfޱU',zMǬeڹ2<hpz"ҋ:G_:\m ]N7ǽzQl%`{]Zp/K+}\}j7 ]L*Q''iD@t(t+`rU_r=P+D4GL,]_%PѱwZ4/)u(zjG1|t)0Z\)Lt|}ljPSNmFi"5 Hv}>V|Wh" )lOÄcYһL66$CZ C7fl> u1 ] hxT+5S%쿄ZL؁XsBW;1iV _<40KGNDgIQܤ-f/'*q{((S6*>a6BԬG_)KEI(F("W\ܙElҨFt~?Ld@RB9K# !Q[@(r4gˉ„~GZP\|?( 8JV,-Ǯ`"]Dv]Բ{c*QFM5Fps! IApaC=2.ca/WF-V N -FR.tKEVugp\,ò^a 04-s B'* ].1ϰ8ߠ##zeϔn8}6XC+LbK;}0TcwlXl8V3*!Ꞟ=lzv#~=6_F>uwXxd$;]!. J+LEUOhI'"Ww϶x%"=CNN{ڍs;|DNlhsl=#c{?H,hT7]'n̥8y.[yÔ7|рA].j6ojp:ԲˀP7۾Y(]Bި _)4wJ(醖cJ N.8P}zShCȌ~>Su_2v6;a%u/oNpp-}XrsԩJH5⍺p?TRh 0N#Q,Q4ZhdUZbP_zHў[_~7zUns"b8Ľ̉z0c;οb!]zu38.nvX>mMOu˒f4D!V{}tp bM~U#/m*3uuFL@D232N; 3*9 R:~muѼ=}v_oZ2=:g>?3iB endstream endobj 111 0 obj 3418 endobj 9 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 112 0 obj <> stream x\I8rWvhb#abn;:KČzRԼ$9%R3!g,/Oeε*3]8ϹR2c,,K>Zdpp+K">:/0T~O;L*farUh}~Zfǿ}>*+E. 5w lÉ#SpLW6bTyY($|^\6J)sf X1í\-2v&RSv-;?gRn]_yn3 /W՗){>_crI!*Zʍʕ/KʜqZU.TC8ƂrIrZ_>@gL\nZ @PhɺS0\bu-wE:8m]4z0J<0ҤO@F5vY3"r~XG]H,? `$Vi&#rHg({84+X S6Wq$+Z9d a+V$`HX}~SzeFJ\WJIBR(YJB6)!%Ւ^kXק ?߯Jfnk}kF[Zb#e% :`YHI<KEar% 6콈%&% M}=wHrZ+$|ɐrJ9{뒅b!%N$ݭZ+DIS;4JCV$DRcsGPz8Q=ֈoa}vZ"iòw(f_`uT\IK>CqUY*/~J/̑m@ǂG-/ySV_o?clR#)|%K (Y.^ cK3eeC;8;ü7Y(K|c8N' D-R(%j@8FB8F}p%)Rw&Xp3{ 0m( "R ʰ08/ H(Q I( :7jY P*倂OxVtZi N` ꆱi#Qn( )lkH%s$DH<. h!Y[hHqǐ-"~NSAjCV \so^꧅N{;yKm'OQ (`X;y}Lط^o-ᷝV(Fhgq2vv5Xr$ҕNfc(|bN( Y yp/8[2HB|̶rbԒDVF>?+RLP-(0*0b9_o/KV]q?M\ e~|%_*5。+JWPAsApyc}ᚊ?*; ~27P@@bMÜ +J8sZPD@d]K=\zԄy;GAvZCN'-Bnᦎm2gc`9g`j6R'w#S ' h! ^FZq/H*fQOEcJ%ͩ/C9Zp+$|^\1SRh s؋!Mr86v(aELE|\8 K"O wTA5Z wT㧒w.,wT# K}:ۥ~Cbk c)ƐE 4Ϙ ٷ ʿcZHJ%[~k[kFMfqnN X[Mf5$Z >dnHUWHZ 9Zl9I t |>G8yvvn:2P<&n Cd}:a6xLkD<8b]5K#tǍ"^8I4"yi;!'CX*Y(%)i (}C9e[P"ZV6z|Q$x gEAuQ,@%!==,^w:Jz:F= dcyvQ;n:_8倦,kl (l{0Hb,e@ʲ/F~u};̑ʈm #)j䱾025]. L+$[,aM1RMS*Pr3/y~κ5:r6Mo[nOHmm <+Bרç`K6r*T5߲b21LD|6`L\Pg6OS' 0i K$L $0x1? y(Q&cy9yyᘻ8 2heKEKh#Pv,m%IzOr"Y%ʆH.WS:*T8ौ8L!A/d$q'j@xA*715H:dޯm{lQRf#3p|AVN8 u;@A}W62rp&3ɫ :SP8ų#I+X?+3-+g/#Hljct}'>}!MbЏO5-Q!ԦEkCFM)gTe wWZTs:s|?IW:Bˆ1Qkz?rR55 Vwn zDҋ.?9޳0Q#*ȉ3ssc٧4;P[4u!R3_hblB>3+E?:v\Xl3'kY;ݳ>ͩsF4'>jKZo|߽h~3[ڈF%J2؈hXrIƂ>~v@A8 ='cpnեt,R]c(פ9y2r͕|Αe$+\RzսF=T%yӥ-NgN\-Ӣ/  [}z/aͦ?Dy]Y\XTlRtۦx%8n5"nDŽ$!{[QK)ݸyPϩSb 4(#;eK29@l+^:I=x^+iΐ} QvA7vaA@#M,a-_3$7ДGnt~I5!U'p$5G qi0 nr U.,fcZhK W{v~euw >5's@C+m`ƝԸLʭr2.CVܸ]8V{皦'tqcg]o^Ӥ\m^Kwkpʲ^{[ +`DKzzJ]5_qaR9,B<:b5m~ kΪWLJ{g!x>^`H' kH5JG3jI8u6+AV$iZMlYx;$iMmlϋf?M;b֒x&un7c?=}N)\,᫙"VH'BpeIQ qZ+E M}['n)mD)TŚɫìeHW| sNXwEz^'SRdNk$ ᎝e|8(>Ɍ5$C㔂O%tSpjwi; 0} $ǫkTt-~.\T&'mut!w'Z$}x1ok&7tʚc[$\dF̀Rйq\V'@*vd,N܅f8%6Wdk7pw/4nft8t )\jȆ>En|?.B }3^n@c8q3!̐A 69JAZ"D/=<:1HMٜ8>`4}{"7D> ZH?e&kU7) endstream endobj 113 0 obj 5384 endobj 10 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 114 0 obj <> stream x[r)pLʃ!`.l*Sl\hEZǕ)%>ɶt݀ʸF+r.ə9WNvswd[ef}{(ٺ=;Xv[uCղJhM&xkT.٦x,[o;Vmܕ=+}W5֬\|3[L[5ݖ)i'-Z^ê--`'uvXzPܱbw,7];{4qaRrifBpoZ*F*|Hn!y \)""ʸ~]'%-'?I52;k#ޛ`ߪkYY4`[]u宨gm-=†T{n[a얳F%u>},-w+ڗۦf?~.),42,oۮdjWv%"()bldkfkR<n QNjv_ݰ!X ٶh1~n+ٰAN)Ěxױ%Krq.z1E`JZdD҇hq0IĐPn•S<-:Ib׬%?:0g#[x kyla D<6{H?37Yl(: | 19AJ9r :!E>aH/VrKdK(8Jh>g3OҬ_9ŵ D!aJʙ^piuJ2pZ7Њg2s:7n!e9f ~WNJs 8%󸪁KTaTg:-6i/Mf@BQ H=~daU}ss}x6H˕aN=_8Zә0$zUix~("7f^ /7,.` k`19mʦ ) (Z?ބHiGPzvդOEUZcqj AW%BgXv[n:VQJ^H}y|R{VT^f@HexEUڑveeױE1_+) W8>z ҎʨL!q{]/<D皈2< oc}LS?f'f*-@@X% 9C :>6fxZ29nU^a4;;M_bMMO|SCC2ͤN"6mEx8Ķ38BB38Z/BaD.s/UsGJ; QZLu׹@L:sf $D0b6K&9} 9A/)i6}qD^@y-S37vt6`L,ʤ 4^M8Ϳl@4hn7)>3`kIJ4? &Ǘ\Z@D?8_ Ndž\'L>q$>U c CY][FٳGj=V\q i0 *ItƓapP ⥗4-)nn~@M0u yduh=~k}Mw;]!iO p=ǏtvzYte2YU$2ϑ\K- D- ] R _PF%2RNx5 Oy|,=ON\6Ji?J4o=WN9 93k\r#'pR^/i@#g-lyp~5 Jx @ E 1b%Du Bf.N$az<lCBR؟ z0z*t-5t˔P̶LcWVFC#Zzf%„금HK%"Up<tI"~1C,:PQSYyУtô!&9OKOq9]T4ARv 9%U ,]ve(U nC9 K$| t.*=Ȫv #`23ʒwsɀzgrwhL1= -PpnG`-C߻C>X^<Ls! ~"Z^5I|0o%*5Zn u5N54M/4:N {“OxfTm>\JifH(sNW gx{"DYW}& ͏_0~7<w<)<񶺧[K 0eZ{g*!M(–YlL} GCQ#c8BJ#p/Pq?h4eRtӴ\+zn2 ۲rF^H7%Dd}>2˂\G# 8.IS_Sw(ml)F6 (;ە+b5E4 Iź'sVVG!,7Xu D*vu =YGOemGJ% 䪋y/Ef͝9Œ>XkVmxS˚=V-FgJ:ColI$tSW/Bc\cĮExTԮŤ^Sfh38i//djCm(<ӹP+2`*)Ḟۂ`ez3Z9!YkӥAj%\~݇1i3:,u۴pGr%^=Oeo`cg8^jB!&Ktibpkd4/?3>D梷 endstream endobj 115 0 obj 3600 endobj 11 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 116 0 obj <> stream x\r+p\jD%OM h-x,X OԒ|[eOoXU£7\XDGXZD$E޼/wu7&?E/U^6}t]7!%.~X7"a1s@߶FhUٛ??FQ("Ń*ObAX{"#?MOWPN< Y%><>Ⱦdǩ'bA`$/&?e&%t촶_}]^etJE쭤ee å(G_"ȁvCAv;⤤O plADd'8D٤uQ-s|SyfuTg\Eı >#קU%eegH}[#!~o$ ~"23">W UNpUYslvP#0HjiT0qa ~tQi"`wG%v}`HB9 F;isz1 -PSf/yGt|*8 P[‘P>=&C,nkz`RD*xrkmmCݓ~g'BOtOOTu㥚fȝW|Wa?}k^D!/JQkF'6zn7 n?0?@M!~^`ty8\Y|(q9v))_I3{[C,T(4P)#*gD pX\==飱pS  9=:$U\yj`Ҧ~Q$O痴駶&r*/҂LqBe?Z?( Ҷrg;I$TyA9/%+_.S|t[E-PK-}~)4!":LX$PT .FnFsf Sͮ,*W٢]S1ìWbzC+! u浮lpe4L$2|ع#uel/`cs bais~x̥ϐխ);͂V!J,}Ďq|lӭcZfV1.K^ ZBHdZ+6/hStDjmvj7'4a9d:"=y-a~NKXd44nWo* *?KA5mn(i-Y KKt/xT+hg]iswu+ݹob3׼//Y嗐-΂ ' -cІ3ILPZ:R.M^^[ i(V[õ][Q(όmwpOm565)./K- A/Qb:BfDX/xu]CgWd$_2Bo3!E Rey8'z /.CAmXh9"wZޣE!>ҭ i^L0q|I"+i:U:Mhщ~"rX&D?ql/xDc{xfuq39ace7 y˃'L^qR -{v۽w:J+ٽ_z{_ }r%-^JD\BEڤ @J8-TΊx~_{LG-q PvQYZu&;=z;Qjz1d9"BbȹocG{qtpgdS4*g Q&z] ފ Tp"M6Xz/gTwW }Sdb7/(NT%:B2O˷FZSZj-@\(&`}wӿwLwYt{28P<@{y>Dqui=<۳\ޟVE3x/k _XJMVcH8]"k)~ |۽YDږK?t k3ǀǎѳǎ!DdG9,#N_'xpm>]Ӌ9o\ x'3nC ~Pe! j/l7ٺ\$0rg_Kg08=l 3^C}3S1 Mmg ņ[`NuC؇"QAguϝ}XxS{ EwJsZ~(!|ӮDZ{UչWa[Rt״*qta[[Fm u.$=d=L*u"4Bه0,بhT endstream endobj 117 0 obj 4171 endobj 12 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 118 0 obj <> stream x\Ɏ+Hd)$XˆE>R!Kwp~ԒՄu NDtFd,/"Gd/t2g}fLLYpֲK//xSP4$ 2.#QȔ'"H3ȏ9BNd;ݽgB}w/^?Ot0s5>O;^H8Ӱ>]N~*Cqtcݱ`KPKYy>di^IH;I"ڴC쥂^.t=~~,+/W& jgWbTySy"v@%ZF0ROXF-'V<<^z)OP03CɒnN+}&v$[<|om'ς|w]'VCM#UBlk83? Ƙ^%H_)҅HXDLG"ck9`5eoD=kwpr)R^GvGu ycR\b%kMVѸTn=N P j~%a;fI.^6ԻXj.ΔLlT̬weh 4F:;|{Lw[gJ2ig4VqΔRgJJ h7S, AʝCPB 1ʮD.(g5of$=)+Qn}W }J(vkq%\p‘M)DtC4Rһ4^/K Z՚|pMW#k}$G4 )N}A/9#!ܫ֗y)ɧ2n$~8ZlBl5Lːk@ӺfLւL '҂ Fۀ{|ei/\0˯iC~BdmAL#Vߪk0.D[9{n`AX\ r\HG@A,H2n)=FoMBzJJuMIATaDž6#Ⱥ˵,|/e 8 3Op"# #$D$QI \J 1#5|: <5B<hb.wt\TGx<!R]_ϟ@j< ?u5'C^2q| != Jj|$CH+%789cǩ5nǩMX];Nkyߊtz+55PtڇB&J *vPzJNъ\y*(QܭI?,O5?]<^]!)sim\j'KWMDR 267ؿjGϝZ O_Svz|$Z_)z<}}$xi>:K轜Lzg$~z4ԴTmVP-HHkyŨt%fϾYr ?yZ{$|'Ƿm~Us3"S@t@e ao.*NKM~.N@)%rE,FEgޢu g5<\_P1ai | T˟8s;k&,eq,OwU8M?Ԋ;"IlH$vDh"u\ڒ {wEb¨&wAϳɫFWH)pWp Hάz++yy]Y|kTCO\)RE,k*ZعϘS'ψltҁSgB׻No$CpG( endstream endobj 119 0 obj 3922 endobj 13 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 120 0 obj <> stream xZn}WHL/~ X ?Q,FC?s49NSΓuv_>Bh#0pX-}% 37>dх_/8|YДvײU扵V-{m+vx!ңYx*7Qxtu*0!eMuW.**Ȑ.xBl!/!$)ci@Ah tW^@}\߀^uWI99ZvO.*TIYHct&YB( !I:x-֮ŦP¨k"pQ!*׾}B}C(t>- ۗUhIʙxwuxm-{m}<-6 vdom>"#T]3x%!άÃ- l;lIq6<&uI8[Dg;s5Z0dPQABG0HnǶ=$ HO!x59O<)HМ0<+$4$t"S { PKujVϓ7DF DFbӪ"OBAB&WF^*2Pi7Eq-Pl *Wl%{i(B@My\AMXr-qr57-d\6{ïotB"4U'W҉}TXz2ǃ/7ee #Кf#ϊk%h_}<Լ2riB* 3.Ę5MxDkBM4=x~z0T݈֫lƘ,wm=P$;.^ꆘ\,ٻZvs?D鼲Zn4 B )gV} . By6 ]Hݓ0}#2Щ_#w,T~<20XEF+)#+d0;lޒQpĨ>QeEJELE1/Bҥs?c=crϾVH$tPCngsF˞'R6Ra.Ktsmߵ)T$!xpjW4HAh\ow'Did))zX@6VɅXH$&l,uIfr: . :Gd&*Yc;{]9pW[hKʡ"s.{)x)涓!w9Q=h}~.]&ݮk./my_:Fk|X۩$U…`GxC%:\M3[M$.: ؍..&Sg]9хeBƶ{VU aVYRn箰cԏ[5H3f%KWBp",'f. 3q3n٘v G:Qв󽉳J5#~*r8VD/;t4[2[@oRInU?PF8Di6^7ÈSPPW΢E[cUQHVȜFgEtF-Ua '־OEC6}8KsuUhzfG}VAN_RI!GJmc;ZVcz5yѧ!H(w:<25cjyWj(,Tb⪺>ƀFJ]Ue;\'QQ%#&W9CQ\@(WNm} _*ٜrHz~9 ~-)'_}"10Ǎߢ}xM؋Ҝ Lӗ+7i4p y1q?H(OY>,Yp:TcpX $BS=M9=|(f j?}]zVچeK߈r ,⮥Y$BsY>D>Ad#bAҹA*q^1:ҘL(?]N"<O(No \9a;Ռ!KrJYara3O/D`s=cw<'3-`ԞNf9ꚣ;AwYAz<67]ж`B7.ȵZr]gwbP?T%m۹*H_oM݇XG"iBpd#~}Ľ}{}RmOoG-9Z(?E endstream endobj 121 0 obj 3231 endobj 14 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 122 0 obj <> stream x\nI+XP1/>`S]ɠT&;3)?BU4p[왛;??}`%W_>pJg/5tBO//ՌO~??ܺR m&uן[G$.r#~9]׺V߾_R˵8x/bB@,5 rS\UUq0ׁH€H"V##Jcz&6QALJRxT]8Oث8̖%3%1w(^Ҽݚ󩸝x/Es*NO/:TGZ}a3ZLz>S_.gҥQ]Nx9޿|v '|ɹ /[D1 Ϸ؊i̩ l ?ԗ؂a (wV /{mǖ=:r۱%% UV̢CN%c6ꗘRH׾.Nq+UZ!cS]ccKlsSbw0~SLz _[؈ ߬-'ӥU}Zn$P{{]s.+gJ,/(*3ȳ9W&"aiD<x9f aE ZSa}C[> >W,\z`G4iղcUbsz=г>ܺGЬ7c}b=Ur[r]G,BX$:T|EPSrܰ8)KEn@gKe(('y2"P{}wEX!kgAư@#r2kBwrXҾjů$C툂JZI ^{R <#H1ł9ɱ `^t~?GW.!s"t>G LVݾJ:!gHc][F"L45R?7>uFN#-ɲ^ppN'%Jvd6*5it_t6't?6 UL3zd"q@)u/8V| zLհ5Sv69חy/5wֳ@`%߯6aG7< 7aϑ_Z"ϩn{<"Z_;n)| .%ig|z2p4GvviGL2iHҫV)'lӶE [4`c1kǟ|kAXvn;"7cQB#Kk3fwȔfEJf%QIgdД3h( R jn'u[ڡfofs*&{I9 ` BakIhcȹҶVFynlB@L(wSfBQޅrl8"=mrSAH)Zנ>̗ODVlۘO b+8V|+F{Z߃15I߼?|HV'!]HLm`G8'LΡV?|nə(1^5GPzĈ[B]C –jvdv\'Q$sroxf Cc9)G;d-I3[/a~_E.bTn#_"ڙ Dq2f m'ftEnBե~h/N bPZ2:)-YK}¾55I08@'ZRS FW=g>7_+\X!,"VЁ*{'ޚ4lD'Ύ(&Mxf=xq˫7"$i;s4 D䜈3WXEfh`j&(oaewGCNb$0;uvMi8鷼Lcw2'9C/ɀ˱SS~"r#rD ,DE5c!aQWyL1Myp eڟҗz7:ͼsVR쾯ݲț@4?Dnǚ'n{|<]_ζkVwG!8/K c: p?|4Ԣ^.0T9Q,ìԉ )#~;06+@Ni5a^K(^Y%k/Kq4s;/]0K 9DTTyiGsJ D*`s\teFtp;uNB^pNڜ|yGN@c9c@ 'V)2r)_4S{"D#:;U\Om{Z\O l\DlղayjvƕmlX{N3Kf9[Η"a..zVsZdzf~NDu`F:'ѐRPK9R\`c;VCF6:a.tּ<c3(4jwfu.\ea# o= BF v4@Jh<2qCQ]"`KvWu73 xr%{I^YD4 m/.DٶmT3b)p2l1%PIlL,u{GW#7)OkQL6; /<#"|bWJ /S vE&lxKFȹ(f{'th3ƣc-MxïFkCoDD}JܸwOo40 y:mRǾ1J[l- 6toE@#uvmr0Q0GF^pN%B8v~ᰫLGT()N#xJ{ lN~f=eXNȘ/+Ce@Fزhf=w bٓ\\kݜ2_lfOxD6{+V@w:VG(9uX>8L(wW lyV顰p$ٔc %V&4@t6JL|{nNC%]`kN=.|i/z{ks=,kB_]K>i$H^:=4H3D}e/xfsښ ~JD1fSo]G Avc ʯcY>{O.:}ODVwD&TzbJ f1*کȡ~v3]k}qఉ5:hN TL^/ot9{K;:Vp"t Ե2eKc"ڄLt 4πLJQG %N Rüp3DYfu'8Q/ٔ?ؘPneNQ'!͔Nd7VѦuX-Fm ׬1 O;5c̷3C>t!v\0̃uSXuQ.=!W*/'w\X2ܭGjDDTlٸ._Нz:3]X*GSN:1ǘ*@P5/I>ϥŽxoUs &\**>[AJD Lߖ0?My r##"rCFIkZOX_ߟ{wX Yp'@S ۡM‘^>~n5o F.[r %Ȃ[~R T({b endstream endobj 123 0 obj 4344 endobj 15 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 124 0 obj <> stream x\ˮHr+X2$)/ =gC0l7UrXCVI-dYdURmm"'#A4ßc"5Fhj+%RgN߿R'H/N&M$?c2UTX"R㉲T/ äb~a:6,UQɗ?N\/O|?¬Y>aS#קU3cg¥z)DISs8]z=! r)&898 Q\ͩM.E|߮yU>19oER?: , C*+e*FʝTOSƉ}zSJtI9M'}klS-B.31 `@m+o:T="9ԧK^YJ^+Lwb=@d,= {#w7Hf6Nl~y_/iϟˇ[YUS \J+ls\cz࿴u??D%?T c~g 2l?A?5{oߊkCq,N6seqfSSǛBڲfiJ F?J&9<& `|*Oͥ,Zt~Ϳ5HV7N6sCފk}!9MdTM旲>%@џ+M~VdL+ "~+/kOqױsE ICH<↱sƁf j*'Y4?2ϑ5wO^٩"D V;g<-b(n!"P uBaeI~_2`_dos[ 'z\["ȟ[o[diX+,E' LR؉j(12OBy ޺3[CiODVYK'{N_/Vmw囷=,"4EUocVIT_/I>9-NDݧ/8g#k\'Bɉ!pEO]" U`ߙ!GP,: TPN7 n)+,u4 !tmub([W7X*@2]"UsSy@m3ꪝgˌ{Q7Q*ON7VvYϝc=]*' Ƈ3Մ 6q3]LwsmSMA)&Ԛ=\5 d˗k_yФh+w Hɋ>|CW*; {C9{Dž\Bs|Ɛ#2CWcg_/' /x{o[X Jf{n\f7eQWeK#N_A,g /:wppx|-4G`ph&H+c3j $QݳwxFZ ÚVYM hL:2W־D*]qZ~ͫoY3c|H{gɾ=Ha_c>H4.$#=QDw2 *<7:3VURlD~"' Z=.)Oz dN@acC.o$AA/_PyDDS}\JE"\kuoQ=4噺WT[%CFUca "2LČ"cԜ!uu1yeS˛> ufiɧPS\bMiThC&?myQrU彙P{W@dQT^0.y稴F;ӛpVtW[nF>]1BO><R%`4຋_ !7S0뎌7irdpd1>qOdSeaG ;Z#~.Łs)JK>%x=-B$$٩mDt**>T(jr`.UUIe>\I}6Oœ&2yΤ;d4S\j-Li_%]*A@p2h">?i3;s5lQxsQM'xU7m3:L6/W۟ a労Ā+:T1)ẖ|^l^ͻzRkje=9-?$ '*fg+./r,!G"`'Ĭde endstream endobj 125 0 obj 4300 endobj 16 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 126 0 obj <> stream x\r6+L9 L%UW%]6Խl4H^d4ԏe)%1SnNѩ\%'.5*˒5y,ڇ.uS\^kwI㟒2&Ւ$Kޟ.G?\~渓;nExH2FwF@QC$Vy!rMB:e^(K'pHҙTi0- ?$wmRɹAT&)||m^I<aqL3;k~ {Wɹ/"껧)۲K_s|/Erz(N?O3T~XTm&:Hڇ"iNw mK´'0@y_`G O#l7Ew?LJp4'Kǂ'|O*x.)[|W,-v0?OmqNB!R+;BxwU47.cC(F5#!*/B"mP{OSStu[rE_˦1d@ a#P>4 z!~ 8C2㩳1+OfmJ}#.e !l|\wiIHȤw7'!Gbek4̼BuH;!İaܩ[/` ]к:3,< 9 yt"V ꧗)((kVrʌo`m.J$8ٍ;ΰq'%G \4~)΋G3 |ݽ :?DC7Zma*XI2H`>;8 '\Gdeh#(vN6 }L"^:&r Ծ5{qE[塨v[*z?Z+h%F_f$42/^^GX( V}}}Zc1^i]Ϧd-–p87OtSTd+S ;![/UוF{_ҿu9i717~/G |=o[:tvjJ_f(}jz6 n]|5ӔdT*4? /a,̙zp>z4^(ڃT_xp)ΐ$̶H/KyEQԋ_Oi >%ԥlڤ< =bfF iLP^PAuD3dp`V3v([ugyr;m/YNJuN?yɅ~FL (}eMVuĊ``}>03>GQ4x/d#JffJ#ڑ.uߥ?S^V 3>EHB,¡!)יY%d}N>Bfe_xc).U\lSv9fF F+i3F@͈C`gչ:MxvW" y' 2!~Ґ2V >Ɨ+`xN+u FQ TSLߒ[bgzj4fh>E3:rOo5 R3(}**B4'Vl&0F+мt`wr&?=? ix?5{11wLd:\  qnչdqĢ:\7¡: ׆/uSg鿝S?#҂FmAcAF GTHt>BeѮ>3(}Y/qٿ6,<0(M{%8u r-%$fW} iRXTؗhpLW-f`17u%6BW_ ש2bikAB] ӵ~\ f6[,B1~>FB>=a nᩭ[üN7iZ^=j G2ǢIQ({.?:@~D?+ڗI1\(}4^9f%m7üi*C!4uh Y^(:n & xvP6Jg;!:e¡K_@ tZZoUa WsdY򫕪j|KUu,آoU~ݪBhsK7Buwǯ)Ak> Yz(ĻM(^T?>]2x}p(}Azh ܾ_x5PI+}+[\au\oD!8':~p]&<:җ7y!6B%(Gp=Ԭ-m6jQhX'=/.`wI>)ESۑU~!} fDPvS88Px7/f^(cɢVs_}(3|ZKm<=fѵ8:Q֢:eqnX,vtsbV 6ux6S,kN'5x a-%c"FFà<)*keE @h)ۇkw5+ I@ [Vߓz!y.EpM N\ 1Bx!d=EBu _x4/Ls~Nu>,]om<'gЌY,݁[-|fol 7pBq;Li]:uc`l]d ͖3 d̽:זLӈu.&$9ۿ8:SM4#-љP&.:s~]ЅU8ѧ[],ql̰v*1 L+1􈍡Lн(} ^-d«0_A)Qqr#hƼS.^A Kp#fthd N@]<%(J9⊉Oa3FHЅmp4@DO]hmCՃs.xn78 ^Pg{Z$l/z5h@DbOj)C٥=W?oے5JxTWE^H-x,Bv;q17ˁNl!c*3ZC$wEQ%e\^$'7ҡFXK нм!tVƨb. ݲSRxus%%u qZ4M(6Et1+&;J#ԩ库24ɸ[vj=z$O~CTo )~uDܹw_vjftnj ѵ(KyoS5X|_RС@dII[ ]jڼ:uwɪ?IT i8A^o]TrmRلV endstream endobj 127 0 obj 4194 endobj 17 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 128 0 obj <> stream x\Yo8~c¥o_33 @Cm(3Jwb~~A]RRn:"+ˊq'Felnҙ1"W(2nrm˝:;UPJF "S8ɒrH\Ι'*r9}O_& XA΅*˾r窩\vTMC ic۪a0Tz"ljn5:xIj(Rj-O#dm3F ]cL82"4*%z Jf|1|{-ߩ QW{;GgҢԂ+ D-%w ESfY1=I}vOz}M}A8KOoe (v$o+=g6w {mTU#`nS6?c Յ;=OSRbNllW+ ]ܶˈ5NUS(ʊe F?LG?,~JQ](DA6IP<̹#"TJCH]p#\u~:y%$9^RI&1'Hk3㋌V</;#|L #aG{Zq$=QQ{5":|?;dRJfET\ρs E"ޏA4erC( CvA |NXhuSBS`Px*@(_h;ȡK&zȢKQ8 רIC6i._p{G%Np]䇻*l%YŚAy7cE mKoI#i O$!0xx_.JFi6M $j5hfYFi ۍc04CXw1/09-}dF`Y/+ZP|^)fsEfĦmv~?p`55ڏH?c?i0ϐ329\_\+]Q.[H=K;9{X}9[৤E}B~>x@ @Nfăb P ͷ3&\%߃e.+q2ZC-8?0'{yBy~Ԑ)n( :T1ʝ kbpҵSΥ: }ڮNvw1k}%9XReӉQw^pdBU l}hzrs~k8uv.*pZXHV֝~{ 4<. xR^'hN`V3cct03T(սoթ]7Dkkc^#(-y?8?e ۚǬ6po<'77QuD6\͹5lQHbmE@b'܀f%5hw3bkX!i]L76Nc?i0ϐ6nl4\g siWMƤ A=tN6`?qK4qQ-QNpˬKW@ѥJrw3ApiH"B-}&se&Ci:$a C>Nصl”eL4ʕA2c+_B dۉCm b j⣁OR[EX (WF\bX/M+>H*J(OcS>$^7Α˯Oy7r5~asZu%W]'=yb`Tᐂ}3.415J87s/̳ǜLc̥y2~"m,9HMOHv#.sqo3nz"}-c Չ mRDtN}8Skc?Owp 'coZ>ퟚ;dpSHH[.z; wf]C<{TyT?GRE" d] gXs5a!Uf3X~}˅cn3.xXy#5+[QI="" MD߮tG&Rp̮RqW(1KdcDW6kkY31.<z?fNia\-M;!{{!8_r7) sEf;v}T-9As `!M{~ҳ'-zۮU/o/stj5Ɉ~U~cϑM0nm/Ҵ]6l7m%mm?(P }^ILlN戔 7QtX4 K]tJ=RYsC]~ڶ:O{Ώt9Tϥ:_?[vw/ٓmmvFP hCə޻cMiݱ}z_߸(-P!/*K-z&J- ="kЗs֑1WHP[4tJj TZenrO0QҊ[afk5K'"+z"@P̈́FHtB̌u2iY5ruqa$]G3{i5!2U[$~hH3i)%6L58cؗ5}+!;51X1H|VrDܙ-_D\9=9!qB~1'Jh -[+F3kO7 DkzZEϯRJ4!!dR9ozP'Zy~{}Ǘ+Sh m @08% A2vVQh_FU-=[?Z]LHʶs ;8F4> /ProcSet [/PDF /Text]>>>> endobj 130 0 obj <> stream x[Ks8W2 ' чݝq*jIJwb~|Ų g& I8k%5kJe9`@5 Lfa$]F)OU 4htøLϬD wdftج2c'$kUF}XqvK8 Ʉ6 -,jk/x)dkCPp{eW}s^㥼$u&K#go%n(*w^*E>PlN8^;(msȶrIEc/i%v[-yrUF38[$M} ` @5 %a.! qRx} {J?"T(Sِլ7M4Kx\CQXl COT;Dz{tY2ddn|1ƹj%y⎜ e72[=PY_ۥE`.*\(7_ZQx ʹ@6 Y40t=3C\djBNiQ]—ʠ@u%:uC]H:vwvZ407=eR9h|ýj8L쿬\ ӱ R Q.|EyFfx.WE!c-ID@.PEi"Ipo+@Bo3]I}{ G!OWG*eI EA#˻CKu{,_s6EK.m6 _gۜH67WT _q䏗# ~0nO2C@#Lb-wF@? H81tC$ H8 7M݅?E‰5R c]E?73`|&*-ۃO@N@'QnErJ?k*o^Y׾X뫂 T[ԧ ='Zrz4~M!@pᎀʔMOX#;c-Op 9.l!n$QY' =nYH? ,j./Ͻ&?Z˨n7O,\ol 275Rj 8-vϦD1|7MIZĉk蒐!IH1\}%0YXN3uĉe,<ZgF@ ܆ج Ϝ,9oKE"<\nc sjl!݀uE~֤E6Vt}{jǧ8j*p5_ ށ& hC@WE iO8`qq+E*5VcHU \:n}Bށ/VSxB- od0,e"[r֡Xt$y.G-EZ[WmX R/X\Z;"jJi:qӌ5CYh[{ jw-zߔrVO8`~(D{JXW{A$@xC$+@#|C.%<3#\pXIɹ8!QbEF59C@W%&%gNv P\x{AH#Pqtf䶤a>9=yA\O k |YTn f3y`4t_GG9whO8cu~b{?Pz%q I `)I$Y.~k]-);6(/[3ɬMضYwk ڶ XYM:^J[ҘMh47Kj, /Kx:4yQ~C$>ә_g{hėXMڪFS}9z~ 1 ɹ1A7xQ1Fz4Qx["AztZHxf`okHH~xY1 db'/*IE햊4 iA*" 1+HviR7f+1)~7q~%,Y✱ or{xxSYpcV7sIᲃ \I*nlX]M& ԥu/ Luq]Uq1c,7"T:f {*ߪ߫3[ -G{TnjXK 7ڶ/' qlYZ4Yd^-161VCa(SH>J,|:(;Ty۾F$RmM&;4>I?$4Y _Р/Ҹ_>R(IsWHsdQ^ OrquDGO-iZ5d_KIRwZCx1CQ;>8LVξ~} C|%> /ProcSet [/PDF /Text]>> /Annots [132 0 R 133 0 R 134 0 R 135 0 R]>> endobj 132 0 obj <> endobj 133 0 obj <> endobj 134 0 obj <> endobj 135 0 obj <> endobj 136 0 obj <> stream x\KoȑW@ϢCkni.TbiJn"JVeRgGDFD;J(~(~0U4i x)RҌ?"m2~XDAYSZ6;qytB_~Yݧ_K]6ŗ;^2G<+ d9֌. ֘[syyR0J=m2ˁp,hu~߽n ]1gJiž K]s:Տů6ԴoMtW=hI퐃)hO Կp+Upҕ3? _oNaZNߋH 񯘍0%7ݑR^mSq-<]y΀4TNJ<K@PlBBkkW9ktݮ[(ͪN(7ĮF~ϻ\rrϛ)>S|m&iF3C]ŗkHsl'Ǣz:ՇN_ĆN9&Xi2Y@M c\3Jd8%߫CS=lcP"yA{l G:G2V:o=rHKhG2`<9G^#( ɗ؝.u k|DpH& $܋DZJ,~1U=lMإ(zI%GE Ld %zh,2#|]% ~5 %xъ0؛y%)ClLҼ#QIh)7G̔7l SIzDN_IWvex <5qe+)Kut(M*z |5t2oΒڱR3*~z:=~nTTiSo]:fط#Z. =vuy )m.:՝N )LuB6NU(jn4G[d473"a0S="{kXPDf~kgpܣ$E\gvYU5t쐉±lNjg縠4ޗ}QLGQUcY\UqSb^*z4nIe%ZWmCQ;8%)ѕB(NZmOŦBgC_?ŇD3'~o2),o?Û huR"jCL5Ls~ܻS*#C `2kDP7~_{) P~u/fwV#~oEu?o[PL"s Be _=^IE=Z3t5C؏p>#klJUuT8q /+,˟RDY˝E/4B#EAf7KTִE@|Ӿqo5iVX5tEDU7|C==> n c(\C}oC׫~d4/f ѾsVS?*ڷC,LxxB%cWR (fa#ɽy4RaΣZ-J ޗ}\I֡4Nו.+ڀDݩQK>m5խ"k/wO.f?6 ]4O}欽.gmy![_JEaĪ[8sunZb ʹk [p5jx%>ӭLks)># ڏxAyv7 jqva }Fґŀ(FyIdŅU4((NBgMsD@ZMM|9Cg2 RCr:$+tL=_"$IM@2fL>5odHYGm ^iNV\mL Ѩsm@)-PXc̤#)heˣ1.Z9N<_yJsIeOkb2[G5Ve8WzC30ld&gi-di37}63ih&S_ϤϤavwR4^r go'a2Ipx؍ zzzsm%Z0K87I5b@et5j  q̤FC>gB3G}O0-B@ֳT]Nԕz$ ܻ |4zpWW5_S_}eTOL]M{3][4@!Ӿ=n8| Ӓ=ܤkTn 4_emYYR2tڤX樯vIgv7M̏&㬅FSM}.',OZ`9\ &lrlOxL76ΜqCagaRsE(BŤl,|}5l`[ _k3LLI튫b[Q+—.PIk .}mℇIgEp=s;=^+<Ňk1xVc{O1/jCc}yD28N٥e+Q@As9m5[s4)ZEF؁]kuk1nh^yJs8ӊv3ZJT"5dtW&9 FdkXChh, w\ Ȉ?K3[*խLks)>#  M} Ѧţĕ3ut!;2Oe꥿]sp,RAmC]}_JC~/+B=+ķZudƫRb>\2zNtj'B,i_@]vߦ{މ2{__KWh}5ڻ ?aX쪶zo_&wt;]e<>u6Q.<&Qʤ1CнC̵)5'g$gT-%5z1 9^2mLL1Оn,qf> ts {‘9X;)}0wj%~~SjVU}tUD(*J"y8Qo2)Y!dEb4!ʆ)<=>h蓼@8(Y^{WAO<,|۱*|j"z:h1 :C+[|  PFg_7>$kh,5Ǟ%>]qGGhs@@F@8(˧,^RrM6AtՏ0=PPEM*m۔E5,<폆%1,5$3k2Ɇ|1, }0,/ayhEXXXYeayYay~V<` `=v3ck}z;ݔsv8,N<2 C4 7Cc§!VHpXҜ&]JZhnW(?y4zpyևңG#J{G=zA5 AXd^ɣKѳ:,iO 'w:5RΛ.Dkx-ue$V4K[s<5xKnTMwW/ ]0q14zSբդ^v?m_P"I?􇂻b]@[ endstream endobj 137 0 obj 4018 endobj 20 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 138 0 obj <> stream x<˒䶑 \9z(AeCXEkǺ\Un,MV?7|, :̔27E3PK {aBg(M,τ$rq.%Q2Ӕrҕ7 a/n$2&8 XX6aR16+r_9Q/wO%iUېע~)su$6xb{8dYQF~ xi 5(P<ʤS+ɮ+ ,P‚r\KT#@mߪ xVq 2KAMPLJ炃δEm3?!!' 'T5 Cڿb8+@^} jχbWc$ QΤȍhGr1"uUq_z^El'6Hkv$q@2 ._ /l&^&+s]/eT` 1 kY%j* 9H4Zq t̓;9? gYs4Oi)5蟿/ZN . tWr\gVrx6­-rOg:DYk k>ZH3vNf?v?ؙ\G`isV<3D.I\ [vW?f/m0f)v[A=w䡩dphLW.mWxpv]Ʌe{i.W(цSD6LN)zmw'ã7e/&ӸSfE 1t'k1^WK "; "z,Iq߾SwOU*Վ{?5VjsI_ߪ$'c3mӯ"ťA l ↜~kIWUeWRJkkQ"|;o{5T+%[L!)«B +" ~(]t]@6w@#CHxaoqI1N`L?{WI\(ȮP]q w%==>zXpˁ&')htF$xPa}DO?HnWXuCW<^.y& 8L@H:35>+ٗA a4Ih%M!`, .3> Ny@Eì<]P. șݒĘ%NnIq 5%l 8Mw\ x \4 69]9iD:{i~#|yOR~nϞBtO sj> gO83t''G1Ϟpf /]]pyf-˙0Syry,O9hl'gog.0mbS)Lt<+P?,IMVIF=yGޞXqHqLBw@X"F2g3)7N)G! 98,((Y\ڑ'd!X%]`,fԵS;z&*;eBU ,EZS5O=,Q%̐XIbB`rc<Uh@JNh[@aٚ3֭`8ﰹI@/0hJ@9܆r9^8Y*AkǗ/7H)kU#y͎]Po>Ltk۠OP!w?,r5{rhC=*.yr%ԨWHZx* .HB8zH2(il Q|.$Whjum$|c&\n< odr;$![kkGHƺ;/f䷠0r( E9tY6 8/P&]$HӺ{ FO)4Fgu{I$H!6ߒ`a]unTϱsxDÓ6z3:Fg 9Ŏk 'I?{I?W {؂88q@5Hk`P[s ?9oBamgY iь~61G Xfw\N:;6d\/  / ̩OLK#P:QH$5Z]kػ 2Hri\!bCçzE=VoToN{Vf kf~IVe"$9kFx󮫞~hp~Sf=|=Gc f4 'rܿtI<>_uj,Ck?LU(s@9O&a K!ު]>&X CNMS:Ґp_,7A% ,̕!\ >St y(r%' _uem " /,ڹB7 W| yhƛ ?g EAbTn(DZE,<^9Iu"a(Y32l笌7 F.nC}m>b΍aRZWCWwų4G&YIײ{lįC&ZjwDVc5e׵)wU> /ProcSet [/PDF /Text]>> /Annots [140 0 R 141 0 R 142 0 R 143 0 R]>> endobj 140 0 obj <> endobj 141 0 obj <> endobj 142 0 obj <> endobj 143 0 obj <> endobj 144 0 obj <> stream xYnF}W4,$/4IbmAfH6@qz$&#r93$EI#(rw]OU°@jUY5DraFq jw\(paTlyOAV_MH |HR7c)VeFCgH2FG10~(8)ᛰ N4i_^Jr!eckZۏKv88 ;9.g-"\:6+Y-dLaT+QAV͖KZvruI)[}/'6H NH`yvz>dzOg? dKIKM,OMb0yY> jʬ]r)n1+kvjްj^OF~*I `qwmGQ^vuOp+鍽H'&qV\}jeb$Xsk9LDFds1ν$&ц5 4]NE*,IGsŬv WN1@- D'{#3첚9f[rJǐu]AGJ^3eU$`U$A6a]ŲejjCU6lQc_N`cYdOƚˋl9[UE?mv?eN`JB?\.ɫ% 7C؝z ⱑ*t^Oz mjT@COck_h{G_",!t~_$/ޅGGryr&RqSM5937jUp!=Bf{VaC V\**Wv mQEݡ$C/Vh#x~ OF7=f7h~ [+c&*kHN[G ۿAgL)S92qA)`jf>ܡsQ{aQwrIUuh vn¹(QDdFv^~ӄd>ިyHEԈu?'Tr 49pK@ ҞN ;t`#Xr11,:GFp=>o–Ub|҈: eQ.ܭ m?ԃOـf8O.ܤ9zW[(XL|$ 4}t}yVHй8*V]m?؎yMz(*TF$]G-15ĺ~ HB+Gy 0=Ҷ:f`SH4[!Tx0ԬVuE&"1:q%RKP)SMjiHMW(ub,uw^!tmnj7$@ DbQ-lY4Dn0g7%ъ ~6Īz_f1MÛ*z_ i,]ֺ` OqqZcoSeYeĔ`@WxfR?xR6 ~;v2~}`NV9&q~Z_.|sKfaxxboޟL??Ο^Dʄ6)zZjSu %hRqžo/xwk> /ProcSet [/PDF /Text]>>>> endobj 33 0 obj <> endobj 146 0 obj <> endobj 147 0 obj <> stream x xTE0\Uw޷$};!B""A# $@B؜l*8*6HH1:;3:fu%ߩ3ݩS=ԩSܪ!#jGL5osP_aۂUmꏣ~'.l^t,2-[pF!dq 4ڱ';BS  l$O[|}K fYӂ:1im?{}ݚf1]ŐW]طG! !iE[,}P탴'~1oCFJ<~0"zʰq<(kdd(VD.C(RCiY9ܼ!C "J@h?|(IP)ZGSp#9Ngau^<M@,1G"v`JC.4 M, U/W|sl?oC/_XJdh? 5/Pu~$h:v:>|F_Sf Fc.t;;!=Bb> ֈRP*B±c T~¸݊va/@GQI 3{4FjGaʝ~;xdGYS#I1]z+@/װk屇b/ ':e| ?rw{84Hd  ϙnAϣWoz4̀''cg'^cACv%ڍ:`Fgq͟Iv`?H!]OC(xԆCa=9OKpމ'I|ϊ-l?=169  ݀o!=-:</|M$JfFRG:x ߃_HDZO7=7&|LFc8&ƴ03L7&9v(;`f +ܓ / %.]$į# `^7`|Y Kq%“Z܀o.~?  Dd4AH@6;!% f25rYlg`aN3_0}0kn6]coqWq9{] |~ 8 Äf]b3N9:X[/8 1,@yar& bxY;kloϢb' hb$&'ߓ+{{}r5DO6NgtA35@O><߈Kz.q13T{Xztւ}5kb } }@?`.5h7QhAoET:[ d:DwހΠ/ Q{NG_`*Cú[Hqܵe%ZXG-&:XУ mCvh=E_aNDžUvn?wG~(p{z$Sf(XB_sE(e9bj5z|L0a=qĵw& -0Ny 3x z9o@'m< FZp3PgXߣQ=Tu j;T(MZ7S/oA˅?i[j[bE-Cey긐NJڍNjO'v6 BugqځkqoW[4cCc\tP6hj>ݣ MT/T1t0;N3 Vv B;PhL%7Actc;1j#mUn[AkP}ݵs:j k[Rqp2Ө-Վisi\] c@_^Y};0j O#V#UJ *N_Ch-]vH1[tk>;|-3焂Pu]EA2}mWSTq4[4hXCzs UMYL1 MPɜ4F іá|1ꨇinQFrڿKWBH@K%| pG8ܑCED s 8yɰPBCSu# isyw"-?\AjiM@siؽ6|Hwb?ⲏ[<CuCjFj9- Vͼ,~.ua$?ׂP^{11vB]PXPjj9}qPKO.uK`1"|y~e˰3na_6T͜e|Y]%(-[*Cj-uݱ!U m!Ⱦ-j&;vtj b1JИ!iA o1wNݦs: &ckTL9=`hz)XJs*͡* IDߣ!Ԯײz_Ѝ^&a >y` V"8 ݤ\#2H(F^碄93ưyʹٲIe`DC ֠5" 齠qG,dZE6r sxC`Xŭ2c0oE1YQd*r\.3r7&3j@MvtKT>[m4 --v8db\8,z|xL]id1RPfβc(a$)&ǩHBbDdT%,g>T^) \CX+)"鰹],w+Ci_IMNF`!d,`L<$S^D;A7 )'3tHbc[G1lN@q3*F$-}cNOV??x#i${@> `)iQ)`XS >|^jAF,pt!z {y$ÑL2,(VL7MNڛٱӬ{FEwkUkM>_/3^jWov`ukoQ@,%0ii*MɫҋɟwwMVţz;֫\^[Ee/OL/ӗ8ayAoRd\$`n_^TS ."TdUJSy*.WQᰒaV%#f⢩Ȕx:=ׇw|9zQ<2`;y~4p| # k_c_yO46y^~voTŗƳc=cc}b'͛c\lvAI&Oڟ,P&M^!y{b2$hIMLi0}PB.n<[ Fb3s L| e5 οIT>-@kZ`bkQT|JvZK)=J)+*hZ?y2v ~c@WSMjڜ&HÇW-kpf8JVT+L B߅G4TY,Fb_9(zJ?ރ?,zu K~k_=kS3OI,eWI[^ n0s;Wt9;$(vW0`R4LLd®nL4Ko'v^^?(Ju0ٽc/́ѥX8x.N '4_u½@ޜ|6!gk5 ͶQUj-Mr C5t]u %lE  BԴIX1NzuaU5s&_h7n\κ~95x%t~4^=qN}mٰl+n}>z3s?VC4?3pV0X 8TvViy_\[_{M/c@,uu*xIt+f{S[dgWf9xeG7J)Ó,N~мmZ'I8`DT\|AKPQUF7rm}T;?{J&oY&82'3@&Ҵt?5`Ƨ0o(1r+#Fkn87j_sN, AB&F,*NRVq mj0 F9l%ܸ-! BnHL12YXA m,rxQ|ɣd/9"Y̼@8H4>,u!]4) ]"QXh!漆 ls5-gkZ<5T|lRHn>hpFnHx/n⡉m|Ÿ9$E$Sި0̨H#1hGcQԅ<;|xBuP0 =]{їH\KxR;za QOR+kp~>p4W59XV :%>+7SyING(5fUG:Fğ̷<`F%Cv؟hC<}!{ꐂ!d#UEG7ڕ7tFYvԴ ǗnѠ/|] ;cɥN}4i?hzQ@E^YWeBC0PiJ傠 KQy'2dOn45,jY/6窫&澵־My g[_$o9++fI\Otd<bɷI].e]]w.eLَlJnt' v$I,>n*W;]Cg`P[==A^\cEfEU,x[4'bj˓7+HI=@`侽˿.1/-T?Pqgak<)jztx62kT2[c:&|`?[_ٳj?_sK 񽻯lUW_:Ptz( K]ծ.=̿T,t"z3XH$J,R(DR^AJe bv+O"Tn@!Gjo+Y8>eyeefz;B?s˞U9 f?xLe^gRڮ]!r pæ%K$ |CȀ >T`LTL " 8"}&-;[3ˊ\ze]4n:p/[~Kr_e~m o%Ԫ<.bE"(NS@kLg#>P` >EF9v2}#I}E9;VqX}*h)U)U* ~w~ϲfy|Y)x5Lia O%bfx6-+IؕK6lUSNWWOM΃LlPUHN-H%=2:v_(پ}>X|4*o O_8hfd&֠SQ)'j<ޞ;V\(d }qٱ}E|M쵒e76c @'+rt.INgm08JAA:9Qߠ+lR5TSi6=^k"dR]ו/s5 o^2!s++hy8Tc*M끦A<M jAWa$QJS NrI p\3wc91H$̇t1TSބC&5AJqwJ#;𰡹ZZDfJ FShA٬xMq{ ӵ F &C0#aZ5)iDDVGHݱ]T{4iBKWk,Y$Vr䲪//"iaHGsk7]-$*@NKʧgWiF".o'CY.˫ZV UlT%_-^-͑olD)Y^d'nIH`,qFA(BUF:f)"j̈FPP 20"Hˠ;g`H-$2aXbBH`bĀ%u&.3#\ E,_pܠ l5H Pa{0[lK_8])y2G S-5݄mkZya"}ج&jY[H.H%+Z>rs0.Y0a$PKu/6O_K^}^7xwFh.6`j(k7Z&X=̋]0s"du2,RBHJ2U -15֚nHlڒWgz<.ɒOC^kr !blU#M!A ,cA1UK|jLŵx;ރ;p/YWˑ<حwܣtoX'ЛvBf9[9Hí5n SUn?ɣo&ҿvKS=@NͽYl&V*B˾F(3WSqj1qiljehDkzi. t].YԏUHk7 n!z~7M;Xy{ =*>8MkE&mCF^t~eAqji$=ǷR|Nj|-JR]x̑t!2ci2/V<4v+?isK/h\CũN*O8?NbNf_8Qv4ʋhQtx$\-Vv(;)G\8?n5tg?_g~ {~֏+P^/㥊o>]Nu>eÊaS w:ow,}/׵pVM'~ud??>|v<̈́/D?Q]uPf.7znxع2$WxRz'j؅av KǏ2;,!T­n$EHxe͗+ثk ]ny.Tf_f_dHA`D2"J o0s+;kvgobD9!}JI*^CbYV/e.>!u'hUayDfvZZZPP0Bwx.*::rD%x4?ߌRE~2ʘeXXe8 L /!(BE[,$.4!O'Vi{uB2~۷&2lgw5_E>THrZPk)M iYy#MiHZ~W`DH̱#lrr..BƏVf$kyP+y|`7i{&9ZLPP"hC 1[2U8N1DpV OEynOqs7q疾>(ϝu(u!n=rݙ[4pɑii&\M `W-5T3a;ptO}J(VoKX7uW1WE`?ZWMmUZɜ)|$}W%xMsJJW}V,90$XzMB [6PZOlllOu_̎4DZU*8=}l4c&t.kN)J6a2,8SE\wK٤'UiVERk BBOcW>&XgZq'F콹h皃-2am-5?sOt3я~<6y~Y@{9/mKڵhktYIv_R^|Rtx}sF_P3/|/L_^֜ O kVi5C Dy/Љ27{3uጙw?5M{0jll|\mK.ԜҞBF0g;0NtVx$..*5 -0;lTR,Fe'(z]iqNAVL|hK _S ' ~`Qa?>8H 7co-↺Mo|j 6{!ʅW-#zG +ӃX'M;ǹ}ҳn(:xr%_)OIyt?{Y~|x^dJ$95NlX9p2N]R솔ܡdj5Fm^çd5~Oyԓj(< l48y)M)SKPL0< ×Fi9U:m dTy .j )6g?ґ /Hmע-K1}Qpc>Ow97~1KDCbr%vӺosh¨gE-ܴΔkhzf{؀}•ǎ.)Lny⡇؞Yϱ uja R:<O, K#s쌃` ej2#Hp. r(ijZ䀄c|m;WjZdg4{x7A SW[vqb]g>//Ƈ09bd%YeN5p,OG 3l`KLĐ>q/W9Mg1Ի.1) jS=>{<7z/5V[U__?}jF.3T-(7#\˽}?D]Hbd20FE򗸀83] }&كw < vWw#LDx" 2NU&?{Tݞ;Q~ #f=*$|Irȷ땜d_2;e!XLEɰYŵV Tj?#9 ʚpmNCԒD(S7rjLhP!-3"F'%3ٞɠL5 3fzZ6&^s`V{&*I?~a-0nqtRϭ{n2/Kjf.QPȵ+9m!)F/΋f3zbY3][[wD |`nn/O{j3ڭy>W\,,R* ˗ **M` U61zߨlِa4SLƋۈPr9/;0eZg(p:z:mZ鄶0(@n;5O O x/v@ /i{NeGl^+je}ڳw;{Oܟ&e:/KFn 2V] n"+8J_O ;qgd`W4zXLt\c؀,>hő_*X{/ARoob<ޭeNW~mpx;ERS=`&&+Kw ~.AtklP3SW_]sC}A 褒:u.QEO/$zgζ)0Ů;ο6N%=rVLOדu{`v+JFi%21EeII11IldTsզjwov^yoy{ъ~, G3Ŗ wժF Ϳs?- 4rB{ѻ0n=lj%PgVnL0=sk~]F\Wش+w[i*P2s~a?O:֪QrέCG B)Τn/]C+QV8rey"xøm;FH,=p3w7f;n]I'ئ)_G-A_Ody mܱq:o:88P:5{̩#X/=P?OT.BSxwQ!C穛OYCEVrC!3)sg/ t'3o'?)6n<  6,5E#^YH4t\Hv:N' `'IEIgD,{6>ȠGK {Ƿ`YۿzN6c#;4`|FՈ8y (A# 5MF},䎰IG2=i W.̀d K!X*5ORV` YSry~ @3SX=J Dm,bUP! _ܓ8 {&NU u ]ob@A_0[\#љ8nެQ^όs呔8O%Ocm(pVF<N#IaOpH)h022xf<+X F?.!yeBYl&'eəơ%U+ɕxaaWsk5jFm6_S)+9pN|Θ#ѯA Ư90h4gA 5$nCƧ ScxY*AFz1FD0kd8 H"/ DZ,`F$fbYGK'# 1|H^Ӌ=76|I>OۍJ#D߫1=VMl߈CT d4AY4#-9ʚ'<b[ԚRa80:ځ/cgGd'4yȆ[vi[WXK gL(Xŗx\W r Ov)r;BNϊW3j^^oawG?d $X͑rW!O#9V.]`!ӳxiF0+ ,9HD΋'5+-d\I>cPmtO. wE}{bvNCI)?n~[轂>$Fa ᖁ;qh edJ`5~miiW Z>Ϊޅ>݅7G3NJo #tś0v9dⰝ1Z"d4iĹ0"|# hxG~E!G|3d0V0zFfrHн,0_'f*NtP`VF O dA(Bfhcy)8orT"@}B$O" d6BW 82B!1"9 ,9>4C(z &-SBC*F(8|P)B#s*/@H{oH}з!V,83 2L?KGs&HDm As/0߀w&`yУ ,,.0'` m{짆Sb~ُ.0Y0A,H Ȑ'H CF.7W$`pSr? XB&`} #cg+0|,ܒ"V)Wya[fMW7a_^ tXr"K 8pq88?q8puO'`Jw:l?;- E)bP7<>bof*i5 EIRVq6&`:}:l<$`vP|70#~N(w'`SEK RҌL/a?Sic9d}N%`: %`9^N0;:C#-pG0#[),8 At7jo4/Ɓyy,B4h1jtjB!Y/ Vi\z!P32HC"߆VH* - ~ڨ[@qV$b ( hD B+{(y5u, 3-2:snQ#͂\#(*P?y9#؋u*U 6[z`0"TZ"O\y\4 &5uعP6UǫUiy2:qΫh(* )D:vΫg9Ns u\&fyk/RBIS[:o:}f<|}/Kй"xj۬KI=`@Fu)G~x]O[s^rXCY>R*Qx?~isߪ\Q0XV/k9iiӟ7 t8PZI_EI.T)W۠J'vEiC[.I< Wg.nP'5-oj[ܠmjmnjkklZ>Dl:q ꇌnm[6iY@zJFnh]=!ԬI ZV4-l֛fƛ7PԶֺZM -jr f-olkWgյ5@MjԴ V.okmlX13iTZq"u… 7z/?eX7 p bGaaTh5Z0# `̮.E}]{6ZaES!LB {tꉩK6*~+  1~kEb OTf9 H@ |t<.R+3qu`*dle9Y9@Xƣ70&Td€,%(~:gqVFG6C+wrafe]ph#3Ȝ l \hy' 4ʌc 2 i%A22w~EǏ֨.wПv0wܩ?|{WB4:Bx=@u-0S[`R[@j6C|̬F!ڣiY=cgJ}]bf.8|1m]nOaӳLNJnO;4wg񩁎.:%Ǚ$`eL2 t@ ray2CޣMHH;zɛEAަI3z|vDȳGbA>$="Hv_ t.H:M.J,}g8?۟l4 I/J9H=6 ϐbnP"}"NHW)@'O;Q<75?ph >ޕ< aiLFa<F{ "y!vSky^ `/WUG+NP _ds'[1htY3:TNnES c!܄Xo p^a%ՠMG3hzf =GޣYJG-mnӦqJ!&fƭ%UlP ܢHpm*R%*R !Qs* x#AqD17ʉk޳ b7xg&^y-(3QQQQf[QfDDDD""". epAL \.IIII& L$A$A$A l66 fa1b"Sf DDD8ie~bH H Hҫ<<<5k`1˫#V 4̈́Ah BLAAAԙ3Q[CY8yqu^l~ EwE=֪PU?3]qk`a[0sa6wUwn ^gzLJFW5wj@[YVji }C4n *;W r_V$=**_=4Ϩw갽J+JN'11IkTS1Oy̚G̰9n>n~+dZeeXϜi`?f ( p>dlK[x^z Fa6+ zuQ8cfMzW8+(ㅦyBmOy )PRr.н%R\2"|ҕRI N?6pI>;fGgYO=ZS-tV}$%o%pϟ\ nw yDnVVI0GpOD/~I~ ;k68Blφ#kD"G^ ܱ nH)$SqCJr0}辋uvX= <q4Y_y9XYn׺wϼ9] |8g7&w^p!'ƺ;'|t>ev,> endobj 149 0 obj <> endobj 150 0 obj <> stream x |E7^U}3sdIB $Ѵr9Ap T5+*'HٕuY]vu=EE(]u̼Ō~3=U<9F!&ĥ6M?uaۛB͛aǴeK"C ʟ!$p7WoAHg]b' O d}E#fϘ:)PFPP|),~/a\Ӧ"Ƴݲ S/>EV?\?u oG`[ԓ ,^6#t z| ޭ{ O#0=BXDF!+ɊͰ;.Nj|@0΍DQBx!**VRڽGY={UTVӷ_K.5/|A\1ag:XF?CK@x8Z&NtK2 B;.<B/int#/F/z$IPs; S mݎM`_kt3Z˽Z,0QhO-EѧG qSjbԽ'Г TPMw?ЃS|p&8m%;$k@(j8N Y B/VF.> ߛWˑ:w/8H<Qn=;́~ .NsĜg)+P$B` 4[dB"swBAѝY/}h|5W >OS22#sFW/o wGL++~X= =;) XVFp7&|'~ ;q+D" <"r%y -7Ъ\3|sq>K,lv / E]EFI%7$7'&[SAnaF!@w.{3pnaFF6?<> l!!\NF24fr/i%98qC7[­6s-ܛY<|Sy|/SWWd Q6ҥ(iHo E ]eƭq]???OAӹ:Jv d5n%r?G|%:< AsID ljߢv0p墎o"ߋ: Z WΗpoOoG*v47 WDFsx5O7.Ž\ qdpQV4A7t~ UU+HEpMt~#qVDлj9n n=-Ey}=?NUx6Hj5֠DOxxT越Ga{3d ݇.3b >8(*%mh`ŀ:o$BROS{QwUp t7ځ&oD Q$<\L SFC6_L_CyعTxmCcPmjS"@ѵJtz H {ROө\٩Ht=) hT4nވfRK90w(0ZKn7{Y{%5USUYѫgyY%݊ h$7 >r:j5U%Q9QHKǮ;ݏM]*Z"P5sZ" gp̟i4;Ft/ EZ E|X}X-PFA#-!2e5 3hAQR7p^YxClFbci ZAS=q`4Z߽.oSvq@nC{)=qSm(ѧǦOҲmĮGt]_׀ í7 [Ze*ݿAanE]qn&]"70>CAc'Ƣ-Xԁ=.f{ {z`XmnZy4ΑŴE-ih/]6N ÿZE(6h=P`"b^\35S#DHxRRҭeix)ۯ^b l`(۩`QJ;Lt-4ޏk{YVRB##qHSHbɭDvΟ8ׂ=g6zȠ 62瀉\dJ$ȱ;O;~"cm \jpdppEz]FR2lWr~/j6vƍEǀ7ǣ-hHfRGҥ>b '2̔C{`"76lږj61bj2N[af~ ]'7c c&M+a)1:J55ƀoG Q]M帤UU nu=s5 ŭ[J/ Bl$Sm7l9 -w|~_mz8HB'[M |E>{{ a$[=W%}7JHr$_q6~8 +TN{Q8ڳ7`y(䢊H\=|(Y-yyw.PrPS{EaUZ#`ez.24G.rIB%wE/X^nW8+0__XvP?py z8ЏVOzϿ{k-yKܵŢx]Ц% $ ]!㧸FDp3&xH9$ !Ns@z0;wpUѤmKLІdhV [.m^8pMg)jk8N}z% ?uYQxI F190[܉_U273LDQ  mðmE[kAAVNZ,iSU2f͵sL)~Ng + h5@K W93dUP$G9uNvO_'Ӧ9s7WeJziC-ŊU+)h\bDUj#w=XҞi&N4K?zPqZƝ*Iyom[ws{\jΛV] oa_ܔ}ԇdx?x6ݜuW>کhᨆL&s]0A' ّ(pD0"CEih,q8P]jkNb%J1(JU \eo%}~Shj%[%nX|N8BYngL0v aʢ^zB8LCV8imES'5Dr >FPY;mi-]EtPw8${L$.ZG.MEE8/EG6nKҫk!i^ӧ[W:V:owv|"x:$A#daCu4e*@@X5dQ|=pB9!6Fڱ  66Ltu-pZAkd Y@n=ifvB 'JYX(Ԥe%/JĢw4(ޛX &Jt<x?u_~lrx׮j3|k30'pԗ8g}&_aʪ%:j鶰!>\-1#RR/s~H;ЯGq](2ȲO/ rWy3溦{ZVY6n>iQN,bJji؂Zu'6 4X<% B">ɑ&iqaS'3/#6w-|Er.UiwO)f)Iq$eNГirAZqc'c_f,fiH(5kl|k}n.m9\o_oiNz7)|-z,_=nuS]G 0RapfoD}Eߩ ù_x"' IHa]sDt /q/ 6SE<U|AT3'R"VLPjcZ$3/V)5EfY\3N!mxoRc|i04ԜWWY̓l6n_" |G5@ۦVQuzz ctS֛FUfZ {5CzppsvL6wF+&'|2yxTGcǧ% ? YհrPl<YI>"`&eӨP>&8 A+r6lv>QPV>k !1pn:]VDt҆m`hZmgoQT3#y)fn7@H|LH| eqUȆ׺? KrA\ԢaMaX8^Q">yduG9vIo+ҺkӄME;"t0{`yɝg~߁w}lޑ?%MNZmu@97`^GfP/׆s `Qش`TUP ,j*1faA)ee7cn{,%dy~갫 Is|C獿lܵóZ;n8q_'Ԯ;kĢ'q3K&< ;'o{ݻay-4G-yJa9[sC2hlboh$~ ja ƣߚ5ԝia WU50+`DĉRg*S}XoAk}IG\G7Շie p8Ћb4(A102GG4, Ea%٨py%6_R6e 'Z`m>.|rٳN:=ͮf-\P:11ݐ3e1Huf} 6Yc-7?Oͼ)ξ)v>U<[ّe)O[P`pjN>Q쌤v}(L##B0ffSMGh:*GKbԦgPwDF\Нf7<팋^|ܪ~3vgBl&wg~`Vle`uxS7/#g#K x ?8';B@jȫDǼ]Ė)~7萎@,;;vc,ŮmEkͲڭ/ǵӚcW u*iUjDQڳ*xń5c B(j_P$c~-ۤ3'.javFx=~7$N9/IPɑI{)£eѳO2_ KLl/ Եȴ:vc^Ƚq>f޲/y4}?kAOh 0i t g#W#i M];mhU?_) &9u53)L o2 YX$f<}L_xdRaf,Usk"5h]^;7߸&nX6 bn5F ]arܱ|P"jCSZDaO>q-Fn;@ڎ9ujDuw'W|>Iޞa+oc7?h˒2+O5皏zkmW'꘺,d4{o|tgMs>y3cڮ7n~< /kp|n Yj3L@ 1 #ˌrc<[i06pk+㴡B=OF?,*[x+*CYu #Dl,"t"Gܴ AF M 9504ӡG j206QSkֱN t\"7KM~a{4a#7@{jk-Ltnz( G6dbg 8󏭌邘<,ڜ(?IS#N]Lp9@0Ng+q:|E#hpW:EXFwx欵wOhͦ/%k^9l-&?o}Cg\TEY{zrW=3.(>M|ՊTsL}%,?!82RL$ ݖӌrOZrW-'ɜح{NM,w ErXƻ&g rnt=hځ ;XȅthoQ53ZU63s0qە(2Gd,5?_okpr8.Y핉W>줛,ck{p=OTwu#v%s_<~dr^zS_[z }[²,I@JXCD#pTJc+#jBԀW4e lɒir;Y?ʕM8+Y\ҲJ8uZ胂4KXthݦagWO.?Pm}| 1߮І A ]A7i(NQ%(LpFh0a+q lXWa /d=a7gQi ?YT s̅UiWwr84:#5l?ﯦ0@> B'qύ|G u + 4Tvn8wĶ[[Qm}hsKIsEk/nMuoaMS`;%`5Ezs?B/McLoEm @zڳŨnfhjA|2():G*' (2lm-˲YH8-߭;&OLqQMG";t2aQ}v@721Ṱd!MDZ şAᗉ<uo~ ]pm)K&|bg ݇@ohIwÂMhV$+DD^͠mԠYDM'?d{rD=r8quJJ+AĄ\[l- fh0af`l-eaX.Q6ta+ K;N "/c5޴dI?,Ē3eJ,&ݙD7Μ 7#b]$(ua(PWXJeY#\mmIq%S\nU riItZ. YX~*ly-Vҩ Cd{܆{SY!kpQ؀m l/DIa!;iN|n(:wN& a w/_+ ͻ֢ñ"8Fg~cUimfjkiMSmՇw$[I=X1AVG1;a8_]W)Xx19~wrpbCo?;Gatrvë84tW>âݧ(-D$ {NVxBI湈( YD(2Ғ&`윈h8.vPkMMrA,pNes+IJT4;Yfdm /G3>{AWX, h*G ^bj)+]tv.Xt's(i=ꋓ +0W9rI f Vӹ&jN6 zar KjA~+$cG:GzDa2g 1as5xRV/HtDtlZd2 4[PP֎O,r]ƼӠ jv2}@1 x/O{G8{|G^N>OOu_a/v<mA>,a"Ìa]aחqyތe#" j:wUco1'; oF;z&Δ+4[KlRhAlі|#P +t?lm-_N<}72[z 땡+#cɡEr Zu~N[+.bvݦ+ >f1e-A3LPWz~|ҬOZDh2L+XG .Y[ˢoUQ"e\  2sËGɸInacB̢)MBh="H9x# Gaְ#4Ҭftf}Kgg&@pgـWq` tu@A.f(H\?=rMt˗Sp@HZFm /Fq{#FՎ޾h}co"`3eҬ0p_*@}{0V=]s/7mzD0:2yzs<'*ͦm}EVw֜ Y}.%v@amawݡ-4I|ͦ(LM>nGr )x4 nXL$"4; D_dG1h/;m;I3O)VQX͖6 Ci(i(n8 Zfn f4S,JC8 tYN& 䍯~b7 u_LQ(y]@Vko'{ĦȌ!HP'o6cFξWV98U3V: VlegAgqtuA#qX*ҺY|?Fxtv>.Ri%CDDsO)A=Y:ܬ(>΁qڬ 6 tj0fĢqSհh:)X":uqZ@#̍ԉކQ#*S2fbi2'j]|JF<}oO'6q߮.bQ re|&͕Gau:CI̠ը;Ԙt.)XLox ɽ!9b憪`rXo^"PPҨtTkzNr5JKt^%l O-o |)">I+ %wF{2W V])ԯ1V`uZfglL$ʒ")N"RUMDrAqaQD ڈTT LEW2&7-GwHr7hzN#=c}1Ś᪳ MHoP Y p}ii=6`5 `SڲĥΰtH=~ w1j@@;Ʒ8:j/\]rU:~A}+S)*B}HwT(@bKnՖ>~݆vKXZtk(hYWP`]|-dOSg_,:?^'E@S N(BBCŶqvKWKfsJ[]bSiżQ_u/(&š2knVk*l~ozyoOX19&+D4Sj q6}PHB3nBV<՘DFh>53ܷi[3tϧsH4_6FhߡgjGC(?k5緑MkI+B5HP\wBj> *˫TmոKvWx\$bHD+s+>]jD+Y+g.Sb2; ؚ/vɒ#+]ug^ ]ӹ<þUĩK +myENoxfx]09:nkGZ/o51̜zeϭ/(dՕ]pKn^M#&!,|J$-$77/T<09W{r2і\+_gms}H;~kg\D(ʅZ) f   3UwȪOhLAkxTe&_fPi95OGk2JOm W >;fNXW@ ~6܂Oc>⑘MLiue/X37 ;(`*TRcz譱M$sCbp/T2~,S$ VPc4a6P,wBr[vw#YܓK='#~}q仏/'^9ZeTx2>QfiN.os45luK2z/`ɠ{4ы.u8749;9l>DX0ů%sR}_9uN+ySl l781WhV3چ>C@4t!hzUfk%u0M2u`4 0 K8Wdeql$1xz+frJZ2/~`"o_t}Qv^]f$NE7n؛~8#dPq5{r}}?g>R` U2V5&4Lf(\ #o 8?o/yrsKT\J=H #,]CCY/į"wћY:[6 /6KaɸRk^kNX2XoҰFϢe`K+SKld;nԖZHPtLblJ[[{̌E`ӏ%Kogڍ \ɳIГZN4X(y*,O0@?_,G^zh O=ib&?{͌`!soeiYi< ) 4}J83ijy܌SeR6+ezĄ "L, 39G2CJX'eiRUԃ"\"X@qIEJxQt׷tdZug 7S7kuNj {Y(iF*6E9|V$* &ek3% XO8EnHD^[m| yx>m+q|lxޕggΕTT:銎Tw\%5g`T6;~>GXr4@x@W+ [4¹t.h&J!jsZm40Q&-9 )0Lt)Mf> mt*Li>FQm Xdg 9k [\6 VR9C&uysno|:^~mGSy^~dӶ8^p6?"dSjd ,? nPC8YD>G!PnC`,L{ڼ jDx2H!vW'7pKS"q@*z^(+ƒ+wœҿn QEE $%I"Ut /IMC*߆m",'ӽhyF: E#Ar=͞LQ:aq2r0`b 떿DJkFj6wx͝\[Mgq[`co0r ֙Xes8,4e |LU)ͩV䜜IsafQ&*썲ԦdQ-7lOg=Z6ߌ?Xvyn.W [Ċ>oӧD}:A'}^CH(~\'7 -eI${VXa(ڧo:*-ަߦw,ucr§?V.WX(4 )4W xz%nl"|L9]>M=&gn*`_]h(6Б%Цu)_igYgz߬,IlxHL# !MM POmpZlvyl>歱0\ `"Q;a~1; ٳLl^ 'LWAv`rA[k 2-dwSA^8PiyDʪr 3Q.$^ҏ2nX4uVw,&뮟ٽovN@E y KN:[|*i8$կNj,q,WMܻ~}k%N\xײ_:Ɩ7x{uh> t0ּK7 6!b=+򜅑/x`|>;98W1{Dr}8VdH*%Fg 4&_hIyB4t.zBV Y'Tlڠ6|0bftLũlN֠| FW)X s<(7ʍg(gY,P;_)&gqr{u(3 u';{ÉK?q=O-[KI~qMOcxsǎG3ByFJH7_2Zw9-,T:+΁11iipSmǗ7>%jR%Id@W/ W IVp^kU6ld,fԳ@3ac Dؘ"ekA2Xby|5I2AH,!y҆o:^8bgj~NԈ8xLᢨji*n]c/~j'Kے>u׏]ǎշ}j@W*vٿ̉ J~?/E.+bq d1@R,c9/Ng=N[Eш .(νrgI#qf}VMukxm=XDLo:&Xإsj/+Ƿ7^! :ަP:Q(|+r20|ތU]mO9-}(ހ[>]$1za7YLV'kɖ\e:Wϵ[ m4 3w$^^$$)EWS}=EYK%QW¯g{zihi3:K!a"`@B`,;6H{m|6vf8؁ /6Y]'|$qb{W=B|HޫWUunK)X]LY*,DqJ8N#8)(X]vN//el>||W9ݐ2v`T,z;`gO⫘ ~jf O47籑]1TE=|`i&,.2Lѓ)VpYv5}|ģjj*r]z& Lb t2!7唊LRX`mQK&,62or+Goc#bHA T-bcg)eǵ[Xj'|YI:{[{?z mueWl?{Ka(:uEUڭ˗INGB!HĽ~?tDj*2݂CQs!,b/LΜ hr9y-1]kL<lN~cN͌Yx7 Ssi%S^oU8xu x\SO]1Lf?Gm÷z_;'\S=|++i$_J:Iׁް/-'|W)ߖU6w$#ܠ7w33O\L#Dɘli<@% Gv n?m?kS}t0we͕3_f}-E \3`jlDv).B1s[͂ o ӷq\) = MpΛhg.>>ȰJ K6bUJc5"J+\Owڎ {A2ʰgT@!|i W m+, Y\ -/!KhԾq)n!l&FSaxt>e$<$?o9 ) >x,\vkLVXTn{f66`UJ P& ƧL*ܕZNSz/Ax%JJGͫdQv9nA4lh [e,\&vIR,3A2ƬVjE*fi:;V> /" *}EOGRVtg{s޴rBpӑNKMl/QgeھϿf ~+TťM>۩E\J6+ ѮpmsJ;-&p8f[`͌uam@Y^yo>,pP?R- 0/f\gYD$r=f8eUszGV37Z@`jWMrs`jowDL> =UP@r?\|{ /gOQ«dn ,WBS#7d~E9li1M1ni4^J2|TDa.L_쓅+D/P2Ct5˧8 IIJnP+LmҚҚŵxZ|&5׌uVִ低c3 #T9N^hMmS8U+qOOK kr:Z'va`9;l,AZ<!:Ƙc*F!2BraV̼bs),p"3K ~ Sߊ# + ç?g_$S?!U4Y2ρ'9Α11פZέvc+;8cdnbe9 VC˥M20CyץO?uN'bu o{P.^ZAɲ^ݷ}&hZf9M\D5Rfx5fGLoD-դZ|~Oޠ.'QZf_v"_Kzk/yvIgIQ{Zau\.Å4T08Q.((QnvM>G2" cjٶ߬u=&Wݟ\?y{AF> Ƿڛú hsQQƯNU?%G\Ҝjgkn~Oi,"mғ,LLUM?h'6X„`gV%olr6Q͗]#;JbcGh8U\Pyx hWq, ߉{~!(~nv(t4UMUq-kcwvs*(WuujO39drΡ]"ծ M^3>z\?f2j$2 3î]w5pAz>E,5`Jm6̩%z[$:M)֖Wɷ^oA$2oԮ^ڳ*(m}.1yK#oH꛳zkMO]/@O>G6o>>)}Νdu6<{}s윺JW)S_U~ÂbwU_NɉV;0ÉӆL5* 60M߆bl&72lP O E|XzJ",An3;aa-OBX& a]2rkG!ˇV 8m{v?[ ߏ􃈗#aS CǸ@7FBFPg9X:GO`Z6 BB!}p4W`#lƯ؄ߡA8M4.Pb+A8p> |> @}s@z|'2#  ~ ,$s/{D 40Y2nJj@M# {`54|+p1w} ߰E`q>NWЄ\j*3kn ܆6>Љq$0Lхiu統S>#Td\A 5)xke |4i5i§&-aW6i;L>AFMѶezLh,᱂Za6Iºؤ%a=7h;̲&MEc&rs9$K8mk9%)vsZ9m7ehІ ڐA24hCmР !C6dhІ -ɿN;Ǹ9U7)N!Os:} 8ϫqs:YcxBc|_.f$s2N-ɿ4&-wg,e( 0Fh6p݉ [D[7lF8(AZ?: =ֆ 7يH1l[}H57Ӫé[L_JyLBcC &?k1Ƣ1qҍ9ٌԊ1ol@7],NJ$bH]Ky :M2$ĝ<_q]9hx6ס˂^ƥ5fsvta2趀竛ĹLsh[Pu xt.-s6lt-k/wKݻxz[FKK7SYN.co2LIq #%0B=׍Vq OÐfo&.ag-ZH+ߔ B/Bj3wG/:y}I=TkʘgJb,~貙<[? ͗<63"_ri60Guql„zc{>/љզLtw%{C__ۣ/jiZRoXԶ;;k͒ WL΋t'zk{8׼F9ޣ7ͭm7艵m>xދ~Wv{ZŽͽm4ѭ'Ч[oIuvzJF#hdF]wx:axK~(coiOt44cxO\֔76oz0eDgޛ[=]聉]qtlA6=zW[x/-<f'=Xܵ;J32&ΖVDc^/6pw9{++}w[+% qM%*c*mjkbsgGR!4EG?׫mbbFK%TjfX{1 ZQp_xF8pD8*<9&f޻G4.u'ld[&Z--Y}IL~>mmYICA f)B*{l$C89 wc3nhp}G6+u&[h+ mb\2 ]e'j ɦk]h,(@A 6%&h=  `h@\Z@~bOݞ=s>w==\G29aq>CѳO+=X8g"}M7=wT;XwT3ˎp"ZjIdd-kT4֨cB.Lr!w <14$CCA=zv}:CSE FB!RoA?@H"`-CSE)ނ 1== "3B^*}2P9~>K98)@vjFE".E+|-4RQv!4K#4 B؉`i@kHH) tXd&V@ˑBc'Bcw@oEk#ŌH&i]3"V!ŌHC#Rh 6VQJQJQJB7?v@q1JX8?MHF%鏒 &1LFQ؁K1?E|үY ֲFi(4%u>h0m1ds f6ù {IMYv=Oc8  Xjt#9(hNGXp3>Ō䦂f)tU!|` B>R3 FO_.МXTag(٤!{$V׋=Хl//!!v;Ʒ'V|ΓC #O8yp34 "Kv9K8˒,&ˎQ<%\ <)YOm3Q28eYf!N޲ݗ_["\qs[).ْW;3)yuaƥĦkk꒴vU;"["`iͮ*=UҪbi͎i `F̜^kSr|2le/8MIgތ y]V{Y-6ż謘^mSr2Ξ߬x߃?tc7hCYXs]O/@}xq}reK"fEJ֤YC#' ta0ܦ27d31O X6酞&!]H+h\e]lQKᡧ C'Iʜ>2ekb#$IdDŽX/FI endstream endobj 151 0 obj 26669 endobj 35 0 obj <> endobj 152 0 obj <> endobj 153 0 obj <> stream x| xTEhUݽ[zҷI鄄$dHİ0"  2Tqw\gљQg6bߩ8{ܪSNmNnB&q]-k}<8`~.8ڻWYtjMBRoX+B*Bmͭ_!T }erM}1WBGjiFBMP{Mnn>& eyMcM dݵ/Dh"Z=sƚهxp!,GȏQpޏq4 k [p>p;^7'1~ 4fy rK`xW(Z=}3f[lGsP=jqtE{pN؍xsq%xÛ߃y_ீ3fb$V'$ dYA= r< ߷;w#%qNrLn6w)m6qWq?_>y?+gOopppDUH'w%N/KWIWKJe$'8a>R3k,zq<<΃Vq?!ԠIZ둋{Cq“ޏ"y+}xAgt?OhZ~JuBzTT(D,7s).G9 }gx3bBux|}]T5^g= RWR cՒЃ Gs ŵ9/: ' t1  BH{:Wp+a fF4厢gA8q'-V5ԈOr">)Zav^GWx/+qhhH(- .m j\Wpb.L4UdNzc1z;xÉEM\ZR< b^PqiԀOINJy=aVd4($ eWHFSΜCf@4B4E4@UhMLKPu%V2TUAm/_͕-r 3X @ZhUZ7iU+wV5UB`E!'64qcT⮚| UoN!¥W5FͯL r#%<##AlX0Z]I;}z-o Z͗G:-VFܛx.s{Eѵ*OF;wn"׏ д$ig5 rѓ ӧK˵\&Z)p >D*m` RlhL:D;l5ؚêMa5̣:1r ,a'3 1h-̤> )I[ Rdi* Q*v)jP5mXLs#_# R0#P$+ʅT sʓr`ACY\y @w0ZzYCpn!BhbZufyS(\9cUMpT Mu^_0X3IV)ۚEcJz}H]8*DH"jA/!zSO"IQdUGԦz` ľXvY|ɡ)ccg RhΝ1uՠwvj;v6Ķ.jjp y,HO0d ?'k`L--!O37gPىy‴,dc,`oGI&<#CSm.v^Nz9wd&'efF!mё04t23ǍC|bR7e$%9iG;K w͖,67)mk6NIV0FJRE\7U{BPm~1KRiYΝքPYy6{in:T]R}AR CwSbE 32._<U_lnܰn>sMh~ͱ.My&nk.6Ej*ؑO d_2v > -[Jk̶BEM4 yC2j5QU3UR˭F\ޞc97-< JX*LT$VX=S{V=Kt,:tV CBljn5dSE|-O4I9 _?it_G_׶}f?F Y z<\~>Q "1F΋ + eI,I32*H~U~ <<0yU҇1Vu6U򄨰7qsgTiqj?p=q| jiupG^dJ- vòUƙMF$%UU6CU?&1 9fsDD` =ì.!f l߅}&-6D{ULJN HAp8.XErfb0`$7volH=M-İU7}嬆"/Qo+b[ҽ,/c~~B&|̖L(#Pna#!E"f׊ GGOE|>z{s5tB81O>6"wwۀ'czȏ ƑL#I< 7Mh̊Q-L6$CIJp$&xq K+)dyb*0­^lYy炰j@-j&ju3rj:* pJ(4RL&>SI"vpɴz<~psY˟5~}~Ҏw?ۧn|hAm^u  F, VC? qldFǍvޢբZRjSǬd7OS]Yb8Olŭ(v$q&#3tѵCZwQZj6ڌ|XX"9{۷rvOD^W<}otpbΥOoj |;@̥!؂=;,/Fla{0i&[a߄kǓ"H. pJie!TC!$=(v#g5' KP)NNNxR0's&)(Rlj)/Q&R0P_N5%ѢY%%ܤ>LMˡ~ йY](VQPS{bTth(tyT8.~3&0.JR Crғ_ e{N9G N-]tgE-PY2?-W76"~^{[JKj2ݳxW*.E f/-Z<>:s]M^|z-1@$/\H4XH(IqIH&$mA K z4R sQ ~|݃`Ƈ]ݫF޸8!*vLQ 8[ m0~)8y仳t%Ѹ7ŽJ\IE ĺ!4Av 0N!t-r vC  o F-Ot*5j(H`'3Z.B}0lw~vӝ./⧢qhz.<iN7x6sR_es33̜3CleB3/sBߍ ~asFw5' _Sr51Ȫz5$XJf/D)jJW 42Rg7ji?FXCQ/?;xfeBWûFOA !H($I}qQZ1;TQGO8w0  Szٓ-CExlׄM{O}ŵ)I OY/ʸNh^r5?pBɒ<{byZ~[ӃUw/⏭b ]VzeQ[ <>v^h MuGm6q-7<}70gwR0I;Ɖ~!A` Xr.%G&2xV˓0JM*OyD ~93:s;|@:C˰귗JZV&CEGx*ђ& =k[ \:uRZkquZO=Zzw}N%hRzTTQ~&y>r':'S,h:IHM"tW9*Re7Ӝz7XF7NCtX-s)y2blVGz[pnw纷rM GV8hGyQ(7@< n62#:5v~6ˢe_CŒ îvpvCn#=ţNtqg!: ZB&?ER'yhfn}?{]=i~}}R*"k~Ū&ԩťv}gғc>r dWbqu?5UBo3a3$7D,\-_mߴI+f'674Bd=x zv]ۓ^vݱ3+iZo-sfrݮ+_^$ ! p/qp_sBsK *[ί*C)%Hy+2$y줘[QL\N^Q@=Vma_G{>θ8B=!"prL)(SY&CZ̄ԫ<)WqRIIDZo<4/{WT4=;*Q)ԃ $(pUh(Zoqg qs 2 3D)y`4`'a\4ff͠ G|'©!l-]jB5 s N1821C](nis퇺GPՄhf־]}ABb aRRy?8q^w[5pdwWub_BM K{I᱕ r?3|d t(swop~TT '@ċ22f$z~D* _Um-gypbE6㍄D|`pO1AI['h6ơ{%1S@ p XU4 gF &XG稍T?y=ݱ ×mBvczT>zyjq֖z' -"֥-yc0QCܻ(tҤI 4TuS;$o=f;N/Wm. ʁ#n7۫Z*XUqܿp4l#& u@5B87vQHt9SW]J+ܧwnmN9 I~^@hP8'eT[⤵m" T +s2 i 5DOOo~~:kr*o]=mS^;۴eF=۟F;> ©U:2*05_Zgt~5*ˬ:Vlgo܈B ^O+ԕQ`pnbէZuTt-F[&(oiG4J㭋I)J5>ur8ZRK}qRܱA4nZkl x0p#JNul[ѹAMޫ9|@~/;N | ."3&|#,V:ˢ1>nz0ņiMpš:٤q٨e)aD3757Xsnbr,?. qo*| B<|Ȗ#?g -YJ>-L}'z6ZGm8w+}u̘ebh}Rf;L F]mM|5ɸe\2X*yNKX@ioL?Qp6Qp?[/d $1[B&psӏtO\ЙF{ς:[Wk67x2/S rH _}X|,ңʬ|+淮leNʕo5}k*iYY[f^ut.SSw]~~hI s^t){*D>#5n]onr%t:/0)C^+m&Μ ~G$;IMAXL2enSĒ~æй3P o߆m쒄JO9^89z-&OS]:fwI9ŝUvIUH.,\jб-ַj=V(^畽q'<\\ -乸CmsU~M=`!tG $wٍL_"'yOԭnϚqގ@Brӱ9+$mC s*f_UWF xj@k8Tmnv([MQ"g(A`(e&ZI4@hQdU& 8 uݘeY$vQLj;*Bjp#/'#K q˩|SMJfo1g|֤x  V k<[}w)q~%B:b#KYھd ?tM>ꊡ;Adž@jVl ;MqְmݺI&(gL)&:"$!^p9&b5,VlQD[eI8" ],ZU,ck [$O%*yLE]o!s;3pkKMI&`)st./HCjɱoMľ. Pr[gqoFʒLtlzPH\ތw }2UG>Tt>%ԉ/aS8aAPLFs6dK̢,+fEB؅X欪Z Yd1[ ʙehAe9P-Y >AnE.`z&l.:vkrjaA.cVeGImdRqjvGyl -]~wKy1X?ɾ}%k# KWN[f-ZC}_Za@:۩ETax[`% t1DJY~ -P2:/(>*gcGh <Bs%BIO !q48(B ܀P{{ emɸBeh *xavאZFrEs9K9V0A&*=8#[~:( qXaaKVN^6HiN,# q Q9T$̉<2 aqXDaOP8,# a3^,gs0E#'=`៉:E8 9:ΑY-;IP+̸c7ȏA/SmH+;+?mA@?r*Q;~֑e2rc+-c5eѕkc K<__k+`6wSIB]oKrֱtGYRN&u}ֶ@muXMS.nm֬bЍY5տRC3 NrOp wx4~*Z`t{o ^WCo 0N7} \l5sGW9)nXe#54M5_otL ˪TcPnfʰ[W}of~Fi46_=9($#r_uDWO<A:epݔe,3?+/gL=7\yPd5Q/*y9KS0Cd%[OAh aTs%b)d,]r+Xz,-g\v|?__vXp6 VH6  >< 6~xdȪcD/}1n~vv3Rp<pE $,X!<~>g?g5q P{?jymC*+hzCťzvOenN}8)2"18{`( J=%*AFm9^3-gU_īIaI*73bu@Q$Ǎ%N8>7bBCh-L,j endstream endobj 154 0 obj 13455 endobj 36 0 obj <> endobj 155 0 obj <> endobj 156 0 obj <> stream x9kxTյkuΙ33{0 !! !< (0@ $!!ȋ$<"R τ*F \)Ek_j׵QZ~H⣘l:g&h;'g{O^QWx2X9=+'+0 $V׶sQRPUygKopq!B4M /Y~/6(,P|C!Z3ԗUurKߡ9rHPMUGQ ((ߥ^$IAXZ`4-V=tEcb<|˒ $E6F|(biahd Q£z1!XDj0'Hphzn nQ) +B'dC'i8 G癏eA'H?{Y>T+=fyuSX$}CL5XtKĥW 2Ho\ 0 h s+xU5a*ips=kdبHIRtbL^89$_YHo78 ~% kU_y;&ㆮǪBawja'J䁿G1{fFA댲-,&P3 T2i䣿Ye!N ;U6c6 ޒ>vu[$<Zˈxf231K!38ijӳsVNLOVDY'н,V(>gg qXJ@ h)cS  J^ό3Žg %%4|MRznqGdX\D^(ٹ3K 7"D7doH&{IΒۦfI-J n1$ؠQ|gVD s]Ȋym>aĻ5$.zYL!q,1ZIWx0z_sl.TCG!q|Z1iW#ڍ F]=6Fy$Z/_p|fW-%<1EWl \@99D#^#GաA~uLPmdYK Qr-&kOD1Mb Fİ^b#dESڬ) !&Z t tK>ȇ⇗gKL6Ah' r юTHUCdܗ"OlOh6u F>iTjFZuF1:OҞwlY4VF%#X&9v؜Jb#RRm4IIeLwUV7-ܺq9k{um(#t.:}7\\8e~v^n.Z䦪%SOV (tg J,I$V $!Nrkgj_Re Ѥ| ƪ4ER*hVgzDQKǼ%y5}!w%Q4S|tZLM!=+[rzsW? ^(ۂ~ 1IflhږDq.:y)z&ː.GZ iUX/Y19YIYZ֡owzzGG=WOtUT&3͛K[dDJn8XyT;g߽dnKK_]\rΒtjtko?} WFOI  F ctB&ˎpnJP6n@3 ꦉ(Ty²6۬ @ j/_u.TugwHa̡CԄq<\Q~!#|H,v[!%'bIDJT'ج\L'Ff#;{Μ{7K:ass¿]8Z^rųRnl8m8L6:M]4BЊnLN3ͮ8O](6/*S]ƳγqR5 U#EvԈV[?o/ƢtU6FfcX)M~yֻ'Le5-7!1 r`jY;-:%JU.^vPo#Zl֋yYu'K{`"s8oOKU10؎,5TbZGbc TԅviQY0#˲/!-ֺ1`]42VؗKkء7,yML̮stJY>Yztcwܵ.}3lYw: ӻ8uSOGgǧwcQe;~ɂN Ȇ~ՆA٦C:l;-z& OGeG{t k jVKwg+\eIݫ:$1&o 4Yv .]ُ:zm'tBYDsIט)^SwYQ4WRPjVXŲ x8_wb\@yx%UD} Y2D3,:Zy0ѬSܒs\ekD>O\!o3_[h%X.O/juZIi% ZoY\r&=yռ#7JF̫lyOP_Vbv?_oˎl_64]0"e%4L]-m^kЉ.Ȭ~ +|ՍE˟Vۢ(c5,[#V-FnE'j !N8!늱jfwOlN'[&ؒ(5A٦fdځb^EIbŀTRw`GH٣h=:c;.کƩQSSqjprx]^uDw>M F}2*HFx즢mZϝ?OH( R2cfcdt}F9lUvr7;k`hXvL(XC19CNYv(5˞.cwkNp*`kTslPjÆ.E? JPuzwMHV{ZIۙݑT*S>YL)<})t-S9d%r T`KSܾPq],B˘7DX0aK{JZ#r eQucB#,f5f:%'@C뷅% gB3nDJqG1I91mJJmРXv&!>iӜp$8d̆DN}:7$&̹=bGUD!)NS\<1" I;D'Gy=+MKӧҌi4sFwfӒ<#SlJボ|3Ƒ WTW+qY{;&N 9 Hy?MNf7aRI#):J"4?onɬ`'XW8$*nvp$Pd:#QH)dyE_ D ~KG3nMzeTD 5V WBXZ|V两{kz~¶ ov@uҕhBҳ攡& !LIG, Nˌ](-=HQ^pX"k霤%o>K˧b=qUs*d_$N: jHLVC2ӓZˠ5:mCA)cVs8w =K$$$a.NoH29UfgպAVj{;}l_ӭߘH1潼/??&m C/ᒯ{COyKC:=lAFБ |zD-tIM![+@)[=]'zA FV<'(T?8;ȷOˆ>cDn$ƙT',>8$ y%lh"d6H :+g6tY&^'#h-%*尪uxjJQ\*Y:S^W#~IQ/C |rZ{or$q%7 Y]Фo{ge琤U?%Ư<_tlaM-f0!:w>{W!DF蹟RjxXF1jK"*=F3ND "{c\jy&Fd)\9' e$89i)aҎhhҫ7X/H4@4 `%6-uӡ@UC4 H*O_,Q/ ]! "zx(KG#L4Ÿn:x'3Oč:>:3Mֳ[XL6<CM M5աϣ@VVgZccmgVL48S)*_W3v>];R&ܻ!uViw[qDiWwqGiiǎRih㓶xmHbptۉ_{6GIm9 Ѝ*񮅸8n 4q!6Tz84f6ɔ8F6n7ם9ՖJuMIXWUYukW}wBXMJ\I3L*+Vr\c&,㸬ᐖrÁKX2.؅].X YqwI q~UB+qJi^7έ9gsuVtk7Ί[Wp&Q%؄Qxqjp$4㤉i'pB~4hop|Pp 7΍9n)w6uH9n@[ Tb6ݘw]RVݘIDaqL ČtaÌ>>,[0hY/6>]L,:SF裇o6$ӌtcG;zr$ޓIq))1$0ށqQR=cclRlƆeZ(2.=]Ս> endobj 158 0 obj <> endobj 159 0 obj <> stream x{{\UUgsͽ!E"|T|9(NcN:֗13|DQSjJsEfZ)lks!l7>q]w?k\ %IK=V4{!ڦ/ZƈOg,ylvb!gY2c%DAH7pj&'$7Yׅ\lakQɂ!e7"ΐ9ӧl!IvL}LALH9;:l$ZJ/L@ԗxټ²vl%D}*G%h:c2[6_uO$(8$4pNB\];!nIcHq I)=R{֧ozsg$BǧqA@*z;I+~ S=Z#>'lS/B8B.S־i E WFlrh<NK Xk',Q]b0KpOzp^}EVp'+?rfW4+ؕLb8Ki6uÊEł,ד5kVb͚5oE%x; b2T ҙk[d#|4)bb!GHQrLPBIBŖ$br%겺]VWHZCpgVcyr O&`@铈=HebqՖ@HB a-'&+D?o{50?9/_eBk/ D@Z|$ uY;F."OؙOdC6Q,/II0rH ň " /z,9,5Xp xC!)vT4RoO>b]vh{?1Fc;4a<=t=G:V@qUu'Ŝ@qQϢ% S L?y›cy~qFI3?e;J3z:@Z z96Ad۲:0 2RNb/&!a, E+jv"@x}I$Vn#aH&=]0&WqA4NrP a7AS"' А@ !$ :]0ΐq3dD-#jQˈZF2eD-#jkMqSḩpT8n*7 'I ȍpF8r#'pm8Ҁ B2zx  3IRJ 0$D"kzLIw(2%FQg6xUJCV`]*~h9Ç^հʳ0..U 4cĬÇϙЪ 2*Nc=TgVDbx)K?¡Esa%^,mܣSZ},vMRnFT9 99@,d9 Yrh#@rFegsDD =l`\7mܸI^t3'WhSBD+3]b1څǀc@1Px (< ǀc@1Px H$ҥi+f4=m=:Qi;R'/jaW/۟^os}$[ŃJtIީ XZtS?PkQxkHո̤8KXVE5lr} ̡;jyX<}nߣ{9ŭ3W:NWF$Le'Xŷ)ewqR-,{7˦wxnX=-e:d,wsYAK<9Ôb5E\߬xvNLťg]].V΁V3n,:??h%¶Ӎl~ }?j " #BJĭDkIc7JpfOa?_WT[ Et! {TYfV e.fQ3ʨeԌ2jF5QF(fQ3ʨeԌ2jF="#`wΗtN:P'Iuҁ:@tN:P'IGN:P'm%̷>~*ϒmVEZlXE}砑Bѷo[>֏uZn/}yÖ𳔮ʻinFK=1$-R@`8ݲ,eZ/l&XՇ9XkQd-ɷZn1"}cu‘ōK$p4%Y>DBօi@jAΆ 'fm%j/ݼgϞ4M-{:s;Iߘrt9U(Oh2dׯ$u Q+w Ap?]x ҋ_lAPN[!-%xp] RTKSCDv6Ϝm޲egV7-y##*UAxߞב]O]TΥ%ˣ9^+Ao\G6 K-OF'hv'哕8c :`s!6bs!6bs!6bs!6bs!6bs!6bscs!6͈z1 OCKA7G~J [JjjpX'hTWp%좩bgϮ^^1 k3wt 4|iE6>N\˷n]֭Ҍ>_ƶFd֊%Fwv5ډ2G-$ߨ#6e3~*:TgBgjq&q&q&q&q&q&q&q&q&q&q&q&q&aC'y8v8%)X,ABC؍p‡>x.!o~B|6o䙳h#֢OB$W>Mqe|$IN v!=эTgcFzIwL`WqAC'>dMM'vZZFҺ<{S x=vyn5dYdc&̒hCBZ[B)VK;銰*P+dJKyC[,%#g-9v^ hjg X6Fxmfby:C:wu(m(m=іi3~jBCjgLP/[vERT ;b^5 'pTOa F5O!̙p&!nmUY\rW1 H%ZK}pF8Z 5mx!D7Zn6ku$SN('F"mRmPjKݪUu[V]m?i. bi`@_F}*Z*P1_ ,fkL}z[I.ŏ{$wwa"bJkul NK mg7VVn饏նK=+cCpQ~>FdpiuFEj鹿MV*yI䮵E fJӤuIF0ֺVAQ1M4sVtG!@#IdU_(JFnM<8fgɳ;~l-8{Eu{>3selݾ镏M/HzO>ͪ*/[ Lh~(xm$W=Y:Q#^`n nQj5#1R71f% EwCIoMojߴƢR?) *2!@Ǚ09p}$ { %)tM܆HcR>R_m]CO2`8V OЌҎ&gjK`DS_Fsao͉+o9ڽ,zYl [/n^E=:zn*HAK H"1] #FO(ji Bg>wMaΈΡ?d.%†Smӄ{c8ƩO9wj/H I|_PɯZ[gj[!Yds#/o*gz)w0!NnaՕkVVZ֍Gbf1]|vzS;;$k}@) 6kG,C5 7|ҨB%NiT+yGKO`GyϬܫ˟:*R#nZ~r^hOrB2&[M1!:I1,ӛR'+q r#9eCiǭO3ĨӇLcw*=ne!.^BG.ߠ #9-_c+'~1^k .E]B u -b5k##BeGXn 7Zo3! w~kzpƦ_g<D)QN$juDC## #0#(#8#$#4#* BTh+t C&&&&&&&,NR @?k]^R_U}}Rԙ+vPɣj6Dg3g?@qP?Q=t.U__nu;wG7_G{_(WhB<_?xB:cc)^S" ./OϨ7WqĪumd}qm PB Ul..Vb#i4<D20LSg/M4 [UYYUUYJ+!UZ}`#c>:=~?>CD-y8"15uz~E` RyC]L$+==tȤVz:\!yL 36y³Wᡉ;VӶiv5X cFC(ߪzW}щ:Fo]Ԛv?w Waɽ\UϳX"N~G?OL<<&*$[+Fʸ/Jd/ EIp $:I%# ޤ4M6{s|HlQN~s|$K4;$ߡ&NIJovf>Rnsʫ :Ni!b $Rv7 =49MM7fksu9!Ʊ<8CqP 3biаHX*=}B7g !P ׇcX_Jg R\xOK'Oow 8;`w_W \,d5BսŒ-C^V"/ dg0F%cQ IrLC0葻:6S35!W+ȥ\Kv,haA5Hޮ#Џ굸Gш$dVJY;LX;4FSھlko afgս/Y{lɇAyfu0 t-V0|2->ĤZ-f~erMپ<WC*fͽ*dJC Ѳ"hZ[1'im͵}LU^| %~č%O:NAi7ُ}F2IѺ{=ߡ0Cr HZi.ܶz/vʉrR=6hAfiR~Tږ +Z +ڞj\ Zt%1܅"~cX7hǻ[++NHy|ҥJwɩ~dcNY%լ|o4U$ر/k>,T\_( +B%C/E٪NReLhXyDYGsp3.]^I[s/+Kq5>fOy ؚ)KM-!_㷦ry꾯ox_#B# d#x tW 39ϙU8pޢ‚s甎*pyJmuO,H*L{>0;=xss̼%Sv贙a3.X8pҒҹΎ6$d0DUXB`|2b{$p|-BR#sa<=JhY+3y :Xúa_☆#'ؚ,;Ky~,Ώ;{ p㝇BD3~Cw j8LS1 .nৌ! Y|' ^ı]MlxΗG qeX/ž '8g?yyR^B樺ߡ=(TP!@g`XU1"oR(fMJg׃nCaJ$^SfiE(uY#)uQGPz'cж Zcp7~: ?.TK?0xvtToEJG >A]>cpp$AK׃Wpd >\ 2aIt.|Wj >fp]>a>duv`.2^==gp5VlS]™n N- m'HM 38-GQ?xoqdaxBp0 B! T!A { v?d? <_?6Vܹ5, wfQ2䣗LF0Ay_4eh`ǝAk Q $?pHpEb@ *kB ߱ endstream endobj 160 0 obj 10778 endobj 38 0 obj <> endobj 161 0 obj <> endobj 162 0 obj <> stream xz{|TyΜ{~msfBnBVDI@-!"-RiE\"*z+RGb[F^닾H& ~l3sfg oTnk !A6Vh#!a&G)4RO@Jy\ c~#qb&6k\ W8!V&,n9KZPg$dXq~BYKsR-$S4iЗi0 y+`.,}Jt ^ {,}[ Ӧ-$R$'gyCL6MCyBcn8$ &ޅr7 uA0-ƺ!ź`'iup+!Y:+EO`zy!r;i! 9"1J2=^?782oVw%{M=饢^zEO̩K=(zGEfbQ!we95DtKA鶲"E /a.㹣V`E^,);q;g<='l驯Aj7 JY\ k8AG\#,PN̩^H^:w]7XTz=w^{-+^kbٌ9Ċʒ)3H͍r9%9$E_^Vzџ7*zC{7W>Vx³ u|xbя"_ė-HnНWuQmZOXbc-zd^qե~3% SrlK$Qm޿o] ?>5=m1t|G?nƬ6՟j LQPRcb1C@j2CW-ޯ ^ֶN= FI5jY땽I{K.OzJvP_iE~.!?z2+czG~ȏ^G?ȏxNERy+CxZh-j4ck4.=,uۆM# LFl%&%ؒ!1I5Υ16,aJ-S⶛e{0m NP(_0Z&1FPMblIiB#ݙJ* @PPE%4VFaw]1d -q8K\%Q 4|z'Ql&$FMGԋؖ6y߯ZGajҫj t Ue쾵K>?gYY1<رYG>LDi84p"ũp|& Pj(P>}Ul.n +gY6כ8D(C"L"f BU+ $0hȽt6fY_Fȣ\($;~}E_Q$ÛH6R]Wyi}o^ᴴ}=a߂/Fd[.U S F7c)SGH2_\v$YJ/}t$ֺ6lIN%gO 1) U h WCի5-hj*0aܘ'7e,ՙ7"WIw_S!9%xݺ%6m%?^ܲK&QxkI*Gq㠣iѴ˗_F frބ!.(r9XH >;shtq-.3"ٝђ+)RխpQzvu ^h* ҍ#G1rL㡖?r߶15GsҲn]y霿-[,}]%r7.^jjU:}T27L:9eSV#j6-\O|rGiYZ]'M6 MФomkr77%(몍ww{hfcI'$NrnypjwT\_Y,j@7قnb0+5:%A.lrÊ~Л$'1A~R4Sr79.|͡G (^Hz~E񵯄 4ݚ1YWstW'qEN@X% >%d'% B,b%; +3`X/o$dkNT,v,)>!"f پmEGvœad@&v]ވ%w.=G4`_''?6G1g>2}Ҕjw%Cˋ?^rn`edƻdf]>C[caُSk= :<h+(jH w3DّdCLv @F35[-$fX٭4)}?woU3t/k^^SFl]AļP,}9֩UmmO^i3=!9UVmsv` }(O``bFAAÊtIB-2THfB14z fU3'ח;$HP-H-:4χ:qژpuIm|vBb՜n ƧKJtދ+vf< j4.?O,}Er^I;;7OK .NKIy9P U;4S'i:u6X FI/[F'N݊w6&-*]Y({?Hz(zOgCӳ1@F g X\Qhclbv#+zS} '},9ƸBRSJ#6t%G))1(d4`7wEYⓒ3$)Q*֝hmk.*&a.ؿ~5RnyqU0X\+9p &?11eڑډr>.Y`w=nwdM-h?匜2#ใ̦Թphrћ]3~ +FXiZb8~\v77MqpP 70(V@RHz q6Qo!&q}MlaJM MBhfLO9?8̩|Ci խ_wqŊtPU?yX|8ЏN/ bfw_PATF[-]4էq' Vb{~u6P߾B4+j>ϝS߽36fN-ߒ/Yqstҋ6ymuԃM=dDIh!4&#X XP^ Hh.w$dMUU mk\hQX[S{V޵BBn?1ebU}d;yM'b6 #ztzp  FW"shT9QbGF{pk)-2&&V؇ޘ ^D#+N"$Ң I!L&"WQT)eBYzi BCjZ]Qw =$WR;:xHWNT>ɧD"ڢ*ё[Qik^M|G/XI[ǗfVŬ OڕׯKrV{R>篜[=Jw݂CoyQ ԰I,i)!,66ƠAddj$T .$Ѵiq9LЁQ?̂g(:v]{/ƣKT&ȭx~JIV^GO?ӯgi88'1/jBE9BE7H'bXl07$z:#;ݕaVRـѦBYk]LF F-N3M^^' FZ~ct:dݼk{m/!|C{fU;Hy8ʩMWIj7ɂWC^BK"C0l=nx~ݔ#A1b=nկw_Bǰ^'] |FQqS38u2Cft:YHȇ1 @"]Qcih)GPn 5SI(I$&)Õ)JЭG99ņ(sC! "C9 NWTV*ZSYg1` X*ق[`M{RQfarZiZtReX`Z<8^3Q78liX[2d"P{gY’TjlQ]F! GH3V 7QzD(M+~IgT%rγ۪#RUb77Ϡ^kmK4>i:SorҖk Em_Si+" sވrh |~"rFHX~89|w,3'3#N9f8]pxÛ~op8\x'^Np8qB|x{e+N> endobj xref 0 165 0000000000 65535 f 0000000016 00000 n 0000001205 00000 n 0000004932 00000 n 0000014630 00000 n 0000021496 00000 n 0000024842 00000 n 0000028301 00000 n 0000031242 00000 n 0000034950 00000 n 0000040624 00000 n 0000044515 00000 n 0000048977 00000 n 0000053190 00000 n 0000056723 00000 n 0000061358 00000 n 0000065960 00000 n 0000070445 00000 n 0000075279 00000 n 0000079559 00000 n 0000084469 00000 n 0000088928 00000 n 0000092327 00000 n 0000001141 00000 n 0000001003 00000 n 0000000081 00000 n 0000000171 00000 n 0000000287 00000 n 0000000394 00000 n 0000000504 00000 n 0000000652 00000 n 0000000786 00000 n 0000000907 00000 n 0000092518 00000 n 0000113478 00000 n 0000141222 00000 n 0000155682 00000 n 0000162691 00000 n 0000174528 00000 n 0000001389 00000 n 0000004394 00000 n 0000005934 00000 n 0000006070 00000 n 0000006206 00000 n 0000006342 00000 n 0000006478 00000 n 0000006614 00000 n 0000006751 00000 n 0000006888 00000 n 0000007024 00000 n 0000007160 00000 n 0000007296 00000 n 0000007432 00000 n 0000007568 00000 n 0000007704 00000 n 0000007840 00000 n 0000007976 00000 n 0000008112 00000 n 0000008248 00000 n 0000008384 00000 n 0000008520 00000 n 0000008656 00000 n 0000008792 00000 n 0000008928 00000 n 0000009065 00000 n 0000009202 00000 n 0000009339 00000 n 0000009476 00000 n 0000009613 00000 n 0000009750 00000 n 0000009887 00000 n 0000010024 00000 n 0000010161 00000 n 0000010298 00000 n 0000010435 00000 n 0000010572 00000 n 0000010709 00000 n 0000010846 00000 n 0000010983 00000 n 0000011120 00000 n 0000011257 00000 n 0000011394 00000 n 0000011530 00000 n 0000005417 00000 n 0000005764 00000 n 0000004416 00000 n 0000004911 00000 n 0000011665 00000 n 0000014608 00000 n 0000014922 00000 n 0000015059 00000 n 0000015196 00000 n 0000015333 00000 n 0000015470 00000 n 0000015607 00000 n 0000015744 00000 n 0000015881 00000 n 0000016018 00000 n 0000016155 00000 n 0000016292 00000 n 0000016429 00000 n 0000016567 00000 n 0000016705 00000 n 0000021473 00000 n 0000021686 00000 n 0000024819 00000 n 0000025043 00000 n 0000028278 00000 n 0000028491 00000 n 0000031219 00000 n 0000031432 00000 n 0000034927 00000 n 0000035140 00000 n 0000040601 00000 n 0000040815 00000 n 0000044492 00000 n 0000044706 00000 n 0000048954 00000 n 0000049168 00000 n 0000053167 00000 n 0000053392 00000 n 0000056700 00000 n 0000056914 00000 n 0000061335 00000 n 0000061560 00000 n 0000065937 00000 n 0000066151 00000 n 0000070422 00000 n 0000070647 00000 n 0000075256 00000 n 0000075470 00000 n 0000079536 00000 n 0000079803 00000 n 0000079940 00000 n 0000080077 00000 n 0000080214 00000 n 0000080351 00000 n 0000084446 00000 n 0000084671 00000 n 0000088905 00000 n 0000089172 00000 n 0000089309 00000 n 0000089446 00000 n 0000089583 00000 n 0000089720 00000 n 0000092304 00000 n 0000093255 00000 n 0000093448 00000 n 0000113454 00000 n 0000114249 00000 n 0000114437 00000 n 0000141198 00000 n 0000141915 00000 n 0000142111 00000 n 0000155658 00000 n 0000156365 00000 n 0000156557 00000 n 0000162668 00000 n 0000163447 00000 n 0000163634 00000 n 0000174504 00000 n 0000175223 00000 n 0000175419 00000 n 0000183449 00000 n 0000183472 00000 n trailer < <24764DD405714760C25ABCABFABF55A4>]>> startxref 183567 %%EOF ./nsf2.4.0/doc/soccerClub-xotcl.html000644 000766 000024 00000002224 12161565464 020050 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/scripts/soccerClub.xotcl

    ./apps/scripts/soccerClub.xotcl ./apps/scripts/soccerClub.xotcl


    Package/File Information

    No package provided/required

    Filename:
    ./apps/scripts/soccerClub.xotcl

    Description: This is a simple introductory example for the language XOTcl. It demonstrates the basic language constructs on the example of a soccer club.



    Back to index page.

    ./nsf2.4.0/doc/varresolutiontest-xotcl.html000644 000766 000024 00000001527 12161565464 021605 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./tests/varresolutiontest.xotcl

    ./tests/varresolutiontest.xotcl ./tests/varresolutiontest.xotcl


    Package/File Information

    No package provided/required

    Filename: ./tests/varresolutiontest.xotcl




    Back to index page.

    ./nsf2.4.0/doc/version.inc.in000644 000766 000024 00000000040 12776662115 016531 0ustar00neumannstaff000000 000000 [vset VERSION @PACKAGE_VERSION@]./nsf2.4.0/doc/Announce2.1.0000644 000766 000024 00000032720 13317120773 016015 0ustar00neumannstaff000000 000000 Dear Community, We are pleased to announce the availability of the Next Scripting Framework (NSF) 2.1.0. This is a maintenance release. Since the release of 2.0.0, there have been more than 450 commits to our code repository. The Next Scripting Framework was tested in 192 build configurations with Tcl 8.5.19 and Tcl 8.6.6 on Linux and macOS (both using recent gcc and clang). Common build configurations have been tested under Windows (Windows 2012 Server: VS15 & MSVC 19, MinGW). Diff stats since 2.0.0: 186 files changed, 26475 insertions(+), 15671 deletions(-) Major changes relative to 2.0.0 are: - Improved debugging/tracing/profiling support (NSF) - Deprecated and debug modes for NSF procs and methods (NSF, NX, XOTcl2) - Script-level access to NSF parameter/argument parser (NSF). - Slot-trace reform (NX, XOTcl2) - Updated MongoDB interface to the newest C-driver - Improved scripted shells (e.g., nxsh, xotclsh) New Features - NSF: * Improved debugging/tracing/profiling support: + NSF procs and methods can be marked "deprecated" and/or "debug-enabled". For this, all NSF proc and method definitions in NX and XOTcl2 now accept the new flags "-debug" and "-deprecated". The low-level interface (nsf::method::property) enables introspection and selective enabling during runtime. nsf::proc ... ?-debug? ?-deprecated? ... /name/ /argspec/ /body/ nsf::method::property /obj/ /method/ deprecated ?0|1? nsf::method::property /obj/ /method/ debug ?0|1? A debug-enabled NSF proc or method will be reported on entering and exiting the proc and method (similar to a traced proc/ method incl. a time probe; see above): % nsf::proc -debug foo {} {return 123} % foo Debug: call(1) - foo Debug: exit(1) - ::nsf::procs::foo 72 usec -> 123 The enter and exit messages can be indirected at the script level by (re-)defining "::nsf::debug::call" and "::nsf::debug::exit", respectively. To actively manage API evolution, NSF procs and methods can be marked "deprecated". Using deprecated procs/ methods will result in a warning: % nsf::proc -deprecated foo {} {;} % foo Warning: *** proc foo is deprecated. The warning can be indirected at the script level by (re-)defining a proc "::nsf::deprecated". + NSF procs and methods can be profiled (and optionally traced) when profiling support is configured during compilation ./configure --enable-profile (default: disabled) This can be controlled via nsf::__profile_trace -enable /bool/ ?-verbose /bool/? nsf::__profile_get nsf::__profile_clear When profiling is enabled, the profiling data is kept in memory and can be obtained via "nsf::__profile_get" in form of a list structure containing the wall clock time since start of profiling, the aggregated ms and lists containing object times (what time was spent in which object/classes), method times (what time was spent in which methods) and proc data (what time was used in which procs) followed by trace data (showing calls and exits of methods/procs/cmds). When "nsf::__profile_trace" is called with the "-verbose" flag, the trace is printed via "nsf::log". * Add script-level access to the NSF argument parser to conveniently process, e.g., non-positional parameters/arguments and value checkers. See https://next-scripting.org/xowiki/docs/nx/tutorial/index1#_parameters for the details. The command ::nsf::parseargs /paramspec/ /arglist/ can be used to parse arglist based on the paramspec to set the parsed arguments in the local context. For example, the command % nsf::parseargs {{-x:integer 1} y} {123} % set x 1 % set y 123 will define variables x holding "1" and y holding "123" for the current Tcl scope. * Minor logging reform (NsfLog, interp): "nsf::configure debugLevel /severity/" will print error messages at a level equal or greater than the given severity (0, 1, 2, 3). For example, "nsf::configure debugLevel 0" will print any "nsf::log" message, and "nsf::configure debugLevel 3" will print just "nsf::log" level 3 (error) messages while omitting warnings etc. This does not entail changed logging semantics, but helped remove some confusion at the NSF/C level. * Improved NSF/C code generator (gentclAPI.tcl): Allows for specifying and generating enum types. * Misc: + New flag "-notrace" for "nsf::var::set" and "nsf::var::get" to implement ability to use these low-level commands for accessing variables without firing Tcl traces. + New cmd "nsf::method::forward::property" for reading for writing introspection of forwarders. This is important for the serializer to map the per-object forwarder when different target objects are specified. + New option for call-stack introspection: "nsf::current level". It returns the stack level of the currently executing NSF method (like "info level"), or an empty string outside of an NSF context. - NX: * NX method definitions ("alias", "forward", and "method") now accept the optional flags "-deprecated" and "-debug". See NSF section above for usage details. /cls/ public alias ?-deprecated? ?-debug? /method/ ... /cls/ public forward ?-deprecated? ?-debug? /method/ ... /cls/ public method ?-deprecated? ?-debug? /method/ ... /obj/ public object alias ?-deprecated? ?-debug? /method/ ... /obj/ public object forward ?-deprecated? ?-debug? /method/ ... /obj/ public object method ?-deprecated? ?-debug? /method/ ... * Improved object and method introspection: Newly added introspection subcommands complete the set of introspection commands and reflect the newly introduced method options. /cls/ info method callprotection /cls/ info method debug /cls/ info method deprecated /obj/ info baseclass /obj/ info object method callprotection /obj/ info object method debug /obj/ info object method deprecated * Reform of traces on slot-managed object variables: Revised the interface and semantics for the interaction of variable traces and slots. It is now possible to specify in the definition of a "property" or "variable" whether the slot-accessor methods ("value=get", "value=set") should be fired whenever a variable is read/written or when it is initialized to a default value for the first time ("value=default"). /obj/ object property|variable ?-trace set|get|default? ... /cls/ property|variable ?-trace set|get|default? ... See the Object and Class manpages for details. This supersedes the experimental interface available in XOTcl: "initcmd", "valuecmd" and "valuechangedcmd". * Documentation (API and examples): + Added Rosetta implementations: Inheritance/ single, add object variable dynamically, tree traversal, and tokenizer. + Updated Object.man: Added missing description on "info lookup parameters" and "info lookup syntax"; corrected description of "copy"; added "info baseclass" {alias|forward|method}.man.inc: Added documentation of "-debug" and "-deprecated" switches. current.man: Added description of 'level' option. Rosetta implementations: Inheritance/multiple, polymorphic copy, multiple distinct objects - XOTcl2: * XOTcl2 method definitions ("proc", "instproc", "forward", and "instforward") now accept the optional flags "-deprecated" and "-debug". See NSF section above for usage details. /cls/ instforward -deprecated|-debug /method/ ... /cls/ instproc -deprecated|-debug /method/ ... /obj/ forward -deprecated|-debug /method/ ... /obj/ proc -deprecated|-debug /method/ ... * New -return flag: XOTcl2 method definitions can now specify a return-value checker, similar to NX methods. /cls/ instproc -returns /method/ ... /obj/ proc -returns /method/ ... - Shells: * There is now an improved and packaged shell implementation: nx::shell2. It is used by all four shell scripts. nx::shell2 builds on Tcl's event loop, rather than while + update. This avoids blocking the Tk main window (update). In addition, nx::shell2's behavior is more akin to Tcl's native shells (e.g., no extra lines on enter, catches EOF). The Tcl package can be conveniently sourced, e.g., in Tclkit main scripts. * The new shells accept script input now via stdin or as provided via "-c" in the command line. * They are more robust: Don't quit due to inner [return] calls, [exit] is handled gracefully. * Added tests for the shells to the regression test suite (shells.test). - Traits: * The namespace "nx::traits::XXX" was renamed to "nx::trait::XXX" in order to improve naming orthogonality with the trait management package "nx::trait". - MongoDB interface upgrade: * Upgraded MongoDB and drivers to mongodb-c-driver 1.5.1, libbson 1.5.1 and MongoDB v3.4.0. * The upstream mongodb-c-driver has deprecated the old OP_QUERY syntax with $-modifiers and old names like $orderby and $query, which will be removed from the driver. The new interface is more in the mongodb style, many former parameters (e.g. -limit, -skip, -project, -sort) went to the new "-opts" argument. mongo::collection::query /collection/ /filter/ ?-opts /opts/? mongo::cursor::find /collection/ /filter/ ?-opts /opts/? See the begin of nsf-mongo.test file for examples for queries with the old and new interface. The high-level interface for nx::Object is unchanged. * Support for new binary type "decimal128" - Maintenance & bug fixes: * Tcl command resolvers and command literals: Between Tcl 8.6.0 and (including) Tcl 8.6.6, there was a problem in the interaction between Tcl 8.6 and the command resolvers of NSF in certain corner cases and Tcl's command literals. The issue and patches were reported upstream to the Tcl core team, was recognized and will enter an upcoming patch release (8.6.7). Our regression test-suite was extended accordingly to track the issue. See Tcl Fossil tickets d4e7780ca1 and 3418547. * Finalizing NSF and NSF object systems: In this release, the finalization procedures of NSF (on process exits, thread exits, and interp teardowns) has been revised. For example, NSF's ExitHandler is guaranteed to be called just once in the above scenarios (e.g., to avoid double frees of NSF structures). * Fixed a long-standing and not easy reproducible bug when deleting classes in multiple nested diamond inheritance structures. * UnsetTracedVars: Provide for a two-pass deletion logic during object shutdown, to account for unset traces possibly reviving an object variable under deletion. This corresponds to a recent memory leak fix to Tcl itself. See also Tcl Fossil ticket 4dbdd9af144dbdd9af14. * Serializer: The combined NX and XOTcl2 serializer has been extended to cover newly added features (esp., NSF procs, method flags) and has been improved based on experiences from multi-threaded NSF/Tcl applications (NaviServer). Improvements and fixes relate to "info" methods and forwarders. * Tcl 8.7: Preliminary support for a future Tcl 8.7 (as of Dec 2, 2016; commit 71fa1f9c91). NSF compiles under 8.7a0 and its regression tests execute successfully. * Misc (esp. NSF/C): + Refactoring: There is now a common infrastructure for hash-tables using function pointers as keys (as required for NSF/C command definitions and enumerations). + Removed all implicit type-conversions, signed/unsigned comparisons as flagged by the following gcc/clang flags (ensure cleanness on 64bit) -Wconversion -Wsign-conversion -Wfloat-conversion -Wsign-compare. + Reduced variable scopes. + Guarded against potential Tcl_Obj leaks, esp. when using "NsfMethodNamePath", as indicated by valgrind. + Refactored functions for topological sorting ("TopoSort") to avoid code redundancies. + Addressed more than 18 code-quality issues as indicated by Coverity Scan, incl. control-flow issues (risking NULL dereferencing), dead code branches, etc. + Removed uses of deprecated functions, e.g. "Tcl_AppendResult". + Based on the improve NSF/C code generator (see above), proper enum types are used in generated function signatures and the respective control structures (switch). * Extended regression test suite: The test suite contains (for Tcl 8.6.6) now 5852 tests. - Packaging & distribution: * Updated TEA to 3.10 * Support for MSVC 1900 (VS 2015; win/makefile.vc) * Debian package: https://packages.qa.debian.org/n/nsf.html * MacPorts port: https://trac.macports.org/browser/trunk/dports/lang/nsf/Portfile * Part of the KitCreator battery: https://kitcreator.rkeene.org/fossil/ * Part of the kbskit battery: https://sourceforge.net/projects/kbskit/ The detailed changelog is available at https://next-scripting.org/xowiki/download/file/ChangeLog-2.0.0-2.1.0.log The Next Scripting Framework 2.1.0 (containing NX 2.1.0 and XOTcl 2.1.0) can be obtained from https://next-scripting.org/. Please report issues and wishes by opening a ticket at https://sourceforge.net/p/next-scripting/tickets/. Best regards - Gustaf Neumann - Stefan Sobernig./nsf2.4.0/doc/example-scripts/rosetta-multiple-inheritance.html000644 000766 000024 00000052050 13217207455 025554 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-multiple-inheritance.tcl

    Rosetta example: Inheritance/Multiple

    Write two classes (or interfaces) Camera and MobilePhone, then write a class CameraPhone which is both a Camera and a MobilePhone.

    package req nx

    NX offers class-based and mixin-based multiple inheritance. The search order of features (methods, properties) along the class hierarchy is computed using a scheme equivalent with C3 linearization.

    a) Class-based multiple inheritance

    nx::Class create Camera
    nx::Class create MobilePhone
    
    nx::Class create CameraPhone -superclasses {Camera MobilePhone}

    Show the resulting class search order:

    % CameraPhone info superclasses -closure
    ::Camera ::MobilePhone ::nx::Object
    % [CameraPhone new] info precedence
    ::CameraPhone ::Camera ::MobilePhone ::nx::Object

    b) Mixin-based multiple inheritance

    nx::Class create CameraPhone -mixins {Camera MobilePhone}
    % CameraPhone info mixins
    ::Camera ::MobilePhone

    Show the resulting class search order:

    % [CameraPhone new] info precedence
    ::Camera ::MobilePhone ::CameraPhone ::nx::Object

    ./nsf2.4.0/doc/example-scripts/per-object-mixins.html000644 000766 000024 00000071043 13523353475 023321 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/per-object-mixins.tcl

    NX supports "open class definitions", object specific behavior and mixin classes (among other things) to achieve dynamic behavior extensions. The so-called per-object mixins are actually an implementation of the decorator pattern.

    package req nx

    Here is the original example: a method from a derived class extends the behavior of the baseclass; the primitive "next" calls other same-named methods. In the example below, the baseclass method "speak" is called at the beginning of the derived-class method. The primitive "next" can be placed at arbitrary places, or it can be omitted when the baseclass method should not be called.

    nx::Class create BaseClass {
      :public method speak {} {
        puts "Hello from BC."
      }
    }
    
    nx::Class create DerivedClass -superclass BaseClass {
      :public method speak {} {
        next
        puts "Hello from DC."
      }
    }
    
    DerivedClass create o1
    o1 speak

    The output is:

       Hello from BC.
       Hello from DC.

    There are many ways to extend the behavior NX classes at runtime. The easiest thing is to add methods dynamically to classes. E.g. we can extend the BaseClass with the method unknown, which is called whenever an unknown method is called.

    BaseClass method unknown {m args} {
      puts "What? $m? I don't understand."
    }
    o1 sing

    The output is:

        What? sing? I don't understand.

    Often, you do not want to extend the class, but to modify the behavior of a single object. In NX, an object can have individual methods:

    o1 public object method sing {} {
      puts "Ok, here it goes: Lala Lala!"
    }
    o1 sing

    The output is:

        Ok, here it goes: Lala Lala!

    In many situations, it is desired to add/remove a set of methods dynamically to objects or classes. The mechanisms above allow this, but they are rather cumbersome and do support a systematic behavior engineering. One can add so-called "mixin classes" to objects and/or classes. For example, we can define a class M for a more verbose methods:

    nx::Class create M {
      :public method sing {} {
        puts -nonewline "[self] sings: "
        next
      }
      :method unknown args {
        puts -nonewline "[self] is confused: "
        next
      }
    }

    The behavior of M can be mixed into the behavior of o1 through per object mixins …

    o1 object mixins set M
    1. and we call the methods again:

    o1 sing
    o1 read

    The output is:

       ::o1 sings: Ok, here it goes: Lala Lala!
       ::o1 is confused: What? read? I don't understand.

    We can remove the new behavior easily by unregistering the mixin class …

    o1 object mixins set ""; # implicit: overwrite using empty string
    o1 object mixins clear; # explicit
    1. and we call the methods again:

    o1 sing
    o1 read

    The output is:

       Ok, here it goes: Lala Lala!
       What? read? I don't understand.

    Mixin classes can be used to extend the behavior of classes as well.

    BaseClass mixins set M
    
    o1 sing
    o1 read
    
    DerivedClass create o2
    o2 read

    The output is:

       ::o1 sings: Ok, here it goes: Lala Lala!
       ::o1 is confused: What? read? I don't understand.
       ::o2 is confused: What? read? I don't understand.

    ./nsf2.4.0/doc/example-scripts/rosetta-multiple-distinct.html000644 000766 000024 00000051672 13217207455 025115 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-multiple-distinct.tcl

    Rosetta example: Multiple distinct objects

    Create a sequence (array, list, whatever) consisting of n distinct, initialized items of the same type. n should be determined at runtime.

    package req nx

    The class Klass defines and implements the item type. It can also be used to query its population of instances.

    nx::Class create Klass
    set n 100; # runtime parameter

    Wrong: Only a single item (object) is created, its (command) name is replicated n times.

    % llength [Klass info instances]
    0;
    
    set theList [lrepeat $n [Klass new]]
    
    % llength [Klass info instances]
    1;
    % llength [lsort -unique $theList]
    1;
    
    [lindex $theList 0] destroy

    Correct: n items (objects) having distinct (command) names are created and stored in the list.

    % llength [Klass info instances]
    0;
    
    set theList {}
    
    for {set i 0} {$i<$n} {incr i} {
        lappend theList [Klass new]
    }
    
    % llength [Klass info instances]
    100;
    % llength [lsort -unique $theList]
    100;

    ./nsf2.4.0/doc/example-scripts/bagel.html000644 000766 000024 00000110564 13443231442 021024 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/bagel.tcl

    This example is a straight translation of the OTcl Tutorial http://www.isi.edu/nsnam/otcl/doc/tutorial.html to NX. It serves as a very short intro to the basic elements of scripting with NX and provides a comparison study to OTcl.

    package req nx
    nx::test configure -count 1

    Suppose we need to work with many bagels in our application. We might start by creating a Bagel class.

    % nx::Class create Bagel
    ::Bagel

    We can now create bagels and keep track of them using the info method.

    % Bagel create abagel
    ::abagel
    
    % abagel info class
    ::Bagel
    
    % Bagel info instances
    ::abagel

    Of course, bagels don’t do much yet. They should remember whether they’ve been toasted. We can create and access an instance variable by defining a property for the class. All instance variables are per default public in the sense of C++.

    % Bagel property {toasted 0}

    Since abagel was created before the definition of the property we have to set the default value for it using the setter method. Again, the info method helps us keep track of things.

    % abagel info vars
    
    % abagel configure -toasted 0
    
    % abagel info vars
    toasted
    
    % abagel cget -toasted
    0

    But we really want them to begin in an untoasted state to start with.

    % Bagel create bagel2
    ::bagel2
    
    % bagel2 info vars
    toasted
    
    % bagel2 cget -toasted
    0

    Our bagels now remember whether they’ve been toasted. Let is recreate the first one.

    % lsort [Bagel info instances]
    ::abagel ::bagel2
    
    % ::abagel destroy
    
    % Bagel info instances
    ::bagel2
    
    % Bagel create abagel
    ::abagel

    Now we’re ready to add a method to bagels so that we can toast them. Methods have an argument list and body like regular Tcl procs. Here’s the toast method.

    % Bagel public method toast {} {
          if {[incr :toasted] > 1} then {
            error "something's burning!"
          }
    }
    ::nsf::classes::Bagel::toast

    The defined methods can be queried with info. We see as well the setter method for the variable toasted.

    % Bagel info methods
    toast

    Aside from setting the toasted variable, the body of the toast method demonstrates how to access instance variables by using a leading colon in the name.

    We invoke the toast method on bagels in the same way we use the info and destroy methods that were provided by the system. That is, there is no distinction between user and system methods.

    % abagel toast
    % abagel toast
    something's burning!

    Now we can add spreads to the bagels and start tasting them. If we have bagels that aren’t topped, as well as bagels that are, we may want to make toppable bagels a separate class. Let explore inheritance with these two classes, starting by making a new class SpreadableBagel that inherits from Bagel. A SpreadableBagel has a property toppings which might have multiple values. Initially, toppings are empty.

    % nx::Class create SpreadableBagel -superclass Bagel {
        :property -incremental {toppings:0..n ""}
    }
    ::SpreadableBagel
    
    % SpreadableBagel cget -superclass
    ::Bagel
    % SpreadableBagel info superclasses
    ::Bagel
    
    % SpreadableBagel info heritage
    ::Bagel ::nx::Object

    Let’s add a taste method to bagels, splitting its functionality between the two classes and combining it with next.

    % Bagel public method taste {} {
        if {${:toasted} == 0} then {
        return raw!
      } elseif {${:toasted} == 1} then {
        return toasty
      } else {
        return burnt!
      }
    }
    ::nsf::classes::Bagel::taste
    
    % SpreadableBagel public method taste {} {
        set t [next]
        foreach i ${:toppings} {
           lappend t $i
        }
        return $t
    }
    ::nsf::classes::SpreadableBagel::taste
    
    % SpreadableBagel create abagel
    ::abagel
    
    % abagel toast
    % abagel toppings add jam
    jam
    % abagel toppings add m&m
    m&m jam
    
    % abagel taste
    toasty m&m jam

    Of course, along come sesame, onion, poppy, and a host of other bagels, requiring us to expand our scheme. We could keep track of flavor with an instance variable, but this may not be appropriate. Flavor is an innate property of the bagels, and one that can affect other behavior - you wouldn’t put jam on an onion bagel, would you? Instead of making a class hierarchy, let’s use multiple inheritance to make the flavor classes mixins that add a their taste independent trait to bagels or whatever other food they are mixed with.

    % nx::Class create Sesame {
        :public method taste {} {concat [next] "sesame"}
    }
    ::Sesame
    
    % nx::Class create Onion {
        :public method taste {} {concat [next] "onion"}
    }
    ::Onion
    
    % nx::Class create Poppy {
        :public method taste {} {concat [next] "poppy"}
    }
    ::Poppy

    Well, they don’t appear to do much, but the use of next allows them to be freely mixed.

    % nx::Class create SesameOnionBagel -superclass SpreadableBagel -mixin {Sesame Onion}
    ::SesameOnionBagel
    
    % SesameOnionBagel create abagel -toppings butter
    ::abagel
    
    % abagel taste
    raw! butter onion sesame

    For multiple inheritance, the system determines a linear inheritance ordering that respects all of the local superclass orderings. You can examine this ordering with an info option. next follows this ordering when it combines behavior.

    % SesameOnionBagel info heritage
    ::Sesame ::Onion ::SpreadableBagel ::Bagel ::nx::Object
    
    % abagel info precedence
    ::Sesame ::Onion ::SesameOnionBagel ::SpreadableBagel ::Bagel ::nx::Object

    We can also combine our mixins with other classes, classes that need have nothing to do with bagels, leading to a family of chips.

    % nx::Class create Chips {
        :public method taste {} {return "crunchy"}
    }
    ::Chips
    
    % nx::Class create OnionChips -superclass Chips -mixin Onion
    ::OnionChips
    
    % OnionChips create abag
    ::abag
    
    % abag taste
    crunchy onion

    ./nsf2.4.0/doc/example-scripts/rosetta-constraint-genericity.html000644 000766 000024 00000055457 13523353475 026000 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-constraint-genericity.tcl

    Rosetta Example: Constrained genericity

    package req nx

    Define the two classes Eatable and Fish. Eatable is a class for all eatable things, a Fish is a subclass ant therefore eatable.

    nx::Class create Eatable
    nx::Class create Fish -superclass Eatable {
      :property name
    }

    A FoodBax may only contain eatable items. Therefore with we define items as a property of type Eatable" which has a multiplicity of +0..n (might contain 0 to n eatable items). Furthermore, we define items as incremental, such we can add / remove items with item add or item remove.

    nx::Class create FoodBox {
      :property -incremental item:object,type=::Eatable
      :public method print {} {
        set string "Foodbox contains:\n"
        foreach i ${:item} {append string "   [$i cget -name]\n"}
        return $string
      }
    }

    Demonstrating the behavior in a shell:

    Create two fishes, Wanda and Nemo:

    % set f1 [Fish new -name "Wanda"]
    % set f2 [Fish new -name "Nemo"]

    Create a Foodbox and add the two fishes:

    % set fb [FoodBox new]
    % $fb item add $f1
    % $fb item add $f2

    Return the print string of the contents:

    % $fb print
    Foodbox contains:
       Nemo
       Wanda

    ./nsf2.4.0/doc/example-scripts/rosetta-unknown-method.tcl000644 000766 000024 00000001621 13454166031 024220 0ustar00neumannstaff000000 000000 # # == Rosetta Example: Respond to an unknown method call # For details see https://rosettacode.org/wiki/Respond_to_an_unknown_method_call # package req nx package req nx::test # # Define a class Example modelled after the # Python version of Rosetta: # nx::Class create Example { :public method foo {} {return "This is foo."} :public method bar {} {return "This is bar."} :method unknown {method args} { set result "Tried to handle unknown method '$method'." if {[llength $args] > 0} { append result " It had arguments '$args'." } return $result } } # === Demonstrating the behavior in a shell: # # Create an instance of the class Example: ? {set e [Example new]} "::nsf::__#0" ? {$e foo} "This is foo." ? {$e bar} "This is bar." ? {$e grill} "Tried to handle unknown method 'grill'." ? {$e ding dong} "Tried to handle unknown method 'ding'. It had arguments 'dong'." ./nsf2.4.0/doc/example-scripts/traits-composite.tcl000644 000766 000024 00000005330 12501766547 023105 0ustar00neumannstaff000000 000000 # Implementation study based on # # S. Ducasse, O. Nierstrasz, N. Schärli, R. Wuyts, A. Black: # Traits: A Mechanism for Fine-grained Reuse, # ACM transactions on Programming Language Systems, Vol 28, No 2, March 2006 # # Fig 13: tReadStream and tWriteStream as composite traits # # In this example, traits are used to extend classes and other traits # (called then _composite traits_). # package req nx::test package req nx::trait # # Create a Trait called +tPositionableStream+ # nx::Trait create tPositionableStream { # # Define the methods provided by this trait: # :public method atStart {} {expr {[:position get] == [:minPosition]}} :public method atEnd {} {expr {[:position get] == [:maxPosition]}} :public method setToStart {} {set :position [:minPosition]} :public method setToEnd {} {set :position [:maxPosition]} :public method maxPosition {} {llength ${:collection}} :public method minPosition {} {return 0} :public method nextPosition {} {incr :position 1} # The trait requires a method "position" and a variable "collection" # from the base class or other traits. The definition is incomplete # in these regards :requiredMethods position :requiredVariables collection } # # Create a composite trait called +tReadStream+ based on the trait # +tPositionableStream+: # nx::Trait create tReadStream { # # Methods provided by this trait: # :public method on {collection} {set :collection $collection; :setToStart} :public method next {} { if {[:atEnd]} {return ""} else { set r [lindex ${:collection} ${:position}] :nextPosition return $r } } # This trait requires these methods: :requiredMethods {setToStart atEnd nextPosition} # Require the trait "tPositionableStream" :require trait tPositionableStream } # # Create a composite trait called +tWriteStream+ based on the trait # +tPositionableStream+: # nx::Trait create tWriteStream { # # Methods provided by this trait: # :public method on {collection} {set :collection $collection; :setToEnd} :public method nextPut {element} { lappend :collection $element :nextPosition return "" } # This trait requires these methods: :requiredMethods {setToEnd nextPosition} # Require the trait "tPositionableStream" :require trait tPositionableStream } # Define a class +ReadStream+ with properties +position+ and # +collection+ that uses the composite trait +tReadStream+: nx::Class create ReadStream { :property {collection ""} :property -accessor public {position 0} :require trait tReadStream } # Create an instance of +ReadStream+: ReadStream create r1 -collection {a b c d e} # Test the behavior of the composed class: ? {r1 atStart} 1 ? {r1 atEnd} 0 ? {r1 next} a ? {r1 next} b ./nsf2.4.0/doc/example-scripts/rosetta-classes.html000644 000766 000024 00000046770 13523353476 023110 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-classes.tcl

    Rosetta Example: Classes

    package req nx
    
    nx::Class create summation {
      :method init {} {set :v 0}
      :public method add {x} {incr :v $x}
      :public method value {} {return ${:v}}
      :public method destroy {} {puts "ended with value [:value]"; next}
    }

    Demonstrating the behavior in a shell:

    % set sum [summation new]
    % $sum value
    0
    % $sum add 1
    1
    % $sum add 2
    3
    % $sum add 3
    6
    % $sum add 4
    10
    % $sum value
    10

    During the destroy of the object, ended with value 10 is printed

    % $sum destroy

    ./nsf2.4.0/doc/example-scripts/traits-simple.tcl000644 000766 000024 00000004035 12501766547 022375 0ustar00neumannstaff000000 000000 # Implementation study based on # # S. Ducasse, O. Nierstrasz, N. Schärli, R. Wuyts, A. Black: # Traits: A Mechanism for Fine-grained Reuse, # ACM transactions on Programming Language Systems, Vol 28, No 2, March 2006 # # Example in Fig 12: ReadStream and Trait tReadStream # # In this example, traits are used to extend classes and other traits. package require nx::test package require nx::trait # # Create a simple trait called +tReadStream+ which provides the # interface to a stream. In contrary to a composite trait, a simple # trait does not inherit from another trait. # nx::Trait create tReadStream { # # Define the methods provided by this trait: # :public method atStart {} {expr {[:position get] == [:minPosition]}} :public method atEnd {} {expr {[:position get] == [:maxPosition]}} :public method setToStart {} {set :position [:minPosition]} :public method setToEnd {} {set :position [:maxPosition]} :public method maxPosition {} {llength ${:collection}} :public method on {collection} {set :collection $collection; :setToStart} :public method next {} { if {[:atEnd]} {return ""} else { set r [lindex ${:collection} ${:position}] :nextPosition return $r } } :public method minPosition {} {return 0} :public method nextPosition {} {incr :position 1} # This trait requires a method "position" and a variable # "collection" from the base class. The definition is incomplete in # these regards. :requiredMethods position :requiredVariables collection } # Define the class +ReadStream+ with properties +position+ and # +collection+ that uses the trait. The method +require trait+ checks the # requirements of the trait and imports the methods into +ReadStream+. nx::Class create ReadStream { :property {collection ""} :property -accessor public {position 0} :require trait tReadStream } # Create an instance of the class +ReadStream+: ReadStream create r1 -collection {a b c d e} # Test the behavior of the composed class: ? {r1 atStart} 1 ? {r1 atEnd} 0 ? {r1 next} a ? {r1 next} b ./nsf2.4.0/doc/example-scripts/tk-mini.png000644 000766 000024 00000031615 12501766547 021156 0ustar00neumannstaff000000 000000 PNG  IHDR'qHYiCCPICC ProfilexXeTU]^{y..i0@BBQJJQ@PDDBPQEE{?wy\~s"аH#]   cee׶ @㒻sno72[^BF!`D\ }l$OH;%>'0 z45<}`G|$BCpxkaOOszzȍC<م wGzRX]n5o7=kihG [} ijccGv__{`{0,'?MAv$[J"'#+;힯l@#E!Tm9cy$lq g>d+@@H9ԁ60gA HI dӠrP k <1x ^)|`lB@8$@d@ΐA1P"tʂr"T݀nC]P?4 =yh ڀQ0 f`!XVu`3p< * wSx bF$Q*(=%凊DAe QzT5B-~h4-VGt6}݌Aы_2#QØ`04L!2 ӋyYbXa2 &`ױQ vñq8K'.+]uppx"/7ĻB|-?oRR RQYRPʡj@I#4v BPO%",D>*њH> A8CC/F,0 cc5aE&z&&8R{LS(f!fFg,\,:,,,,c,kڬYnQ ؂ΰfG[d?˾ȡ͑L\2 *ϵ̭ĝ=ȓDѡP(=E^N^cދü||||^Ux,^R \rJjf6~%By"U ='X S +ŕωJ`$T%$*$&$I:uRRRR-R_]HIQ y)K/k*,&$'&-W*D,o(TUyIEE tnm%eHzyee2 F+lU]գwU)E5}STVU#wO՞ > OSM SZZZZ}/k\+ۤwXSo?l@o`oPbƐ߰pH(clf|x„ۤdTi֬읹yylajgjް-2򵕰UkuGYD>[[wZU;]"145kSNNٝ[]p..]V+U5~qBӸ{x8zzlyZzVxxxy-zy3;7?PX=8#v}XpXqF§"" "#"/GAQZDf(F$&5f:V34vqtqaqCe7NNNMLJ>sבGS~8ftJ!)8QLrnRR̤֥QEM@<1!Q+'s K&0k+;{ɢ;N (?=v3Wrrsg,)?  Ɯ*2/j-(>]UPTzgYF9scחsgo\0ybsPEa%2cCU%K5/g]ޮbsF6z5k3_j 1 nxxh}Sf-[eM MPŖVۦۚHݩ{ӽvB{JNG|JgxBL{NX >|`~N_Cwo * 6)5=R|44<t ׉Iɹ!Ͽ}+̫״ px+Խiw^x|~~CGYٚ9?sͅ/t_ʾ|MТwٖ(^Zyζ~Ͼ Ǎ̓[m_f^{FzPHT { 1CN \К!jA*hBi0|fffa{aIi]P2QU疠DKIIkTULV WޯbƭUgBSVD;G'S7C/K? 0(߸4)',S[I=nbt9%n_k@7wo_`$S~7 ][ GEG FF[>x&P[ptQcId|)T4t4Ltvjss^<4wWn"^"b>~2A2!H= i{C+lGD*K2MPNw"ck%O%JWkjmU=!ƌ.6]k:rE̝/wA>o`>ʃC kh>37~b̈́ݤs^r{f[)iw*3il\|ҧϖ J_~d{Rr앤صu[ۂvH8 XP DIim1h3d`bceX+T@JhXxDuz2Wd.ȗ*UUT>BC[Sa_[SKˀbH1sp1Z,a-M ---MǟNK._ͻ3 ޯ}}g>ῠΆ GG (Śz(1>;,p M &'ҘZV~DjF\fpl˓:sOsa%Qc PpϢŒϥʦν8?^>ra@@`Х#WFjFj=:xmzG7zye/mwҾֱֵֹ޽~gwj }zqxfdɱ'v?;4YEˢW9~5?dF\|çi _\}SXβDLAX!넟TMv J\Fjt&̑1H *' h;o :Rm 0C (Mp`C4Tt=`:XvQ3H恮@Hbb0Xv9n!a*yphDl$q2Hd_uM<-:%; SaN3 2eq`YfeS`{~Cc3k;grW5_NG0E@'/%j!F+6.^,))!.PX&TV_KnC} b|\<{iTkўYC#{[(8ˤt^}HJ [j;cd{. \ w5X&U5$@Аp3?}bŵK%T8RuL0qi23'O)<#;Qt^q`)Gٓy+*\zP]V[g{M:KNmw;g{$-#x"}ų׌omsg?̹]fjygmsSxy(DWň ؂h ~HxD Aa 8n(({ITA'{1D 3UĦb'pxU|~ʝAPF$IdUr= u9 'M)-m(-zm7Gh*UGYBX ll˜vx(̔!4>~%*h&(VN䠨AlLD7}E2:rlr?G*S>EC3@+Z;Y'OZ]`Ɉl,fblhe~%J=S> nkGz}h|]Յ`B3GDE>9zA\bƣIP㛩Q'Nfg՞8th.U^MYs/KV__oi̽Ӭr{½ݨj]'G ZO&n=_z%g]Yʼ/6T$Itٮ?31Lf Qp 4^o 1AJd AI&t `,[p /Ql}6Zh4uLˀu^npp[xM*zhI&L%NHQDMNޠY]K3%̘ۘ2ǰPԲγdgɑ)+[=O!ŌǯS9LH}_)(&-*!)(%,!="sY"JiSyCeK V'aTӲIխ՟56k1KT yado̙e߾D=z]}^AAt\ASD%QT "}'K;U_՝:[vҷ*0%{"H%t}zoi`tdn!pm5#hHzCI@d]. 83iO}y371nak WSԋa#,󱱱:AZ{<VfFhhZҥK'''x8L3͵h(:eL3Lʁk "jjjнTu49@D͘-&& C[CCF7,eӉGZҠCIZ8eXz ˒V  aKrhR8ưO?_,dh-iY'$H$A2*/1[T`85Szj􌶘Ӳ"dɖǧ%2ҸO?Խ{wpT0MNBh4={6++z$@}v82dRsA̱(wU}})ܓcZ㓓SS/s.Z!1vnKtLtj)532;c̽e~-ښ x겊 {cXƸӎ%I0wL k؎ ֭Θ17 n=%mp;o 36KNrtN%&{ H6nT/Mh\qڛOPL:3?p4]1F ]3v:le:sKW6̧KˇZ\\ga?d?I/q3gRSS[q]96W~Ryh`gt+L'Hcפ_L>bZx!낵u9=|?MjrZ\Ga<˅&3 9Y}1$).3)]sF?,:gt|Sٗ;k2)T>Kb6[zwMnF[ҷ~[VV8F <ЩP+\:s_{QaE]%eV<sXܡȁO3{<S< jJ x6ܤ)Ѭ:»gxHp[?s|3neK;L3f̨Q>XӲK9?A֥{mE\{Syb[3`>yܼs;67_wxK_C&7D:4ڻ`UKјED1 t=qĚZA[asZօf .sb[BTh8rFNox(M&N$dS_鬝~|?zO>;SnhnƋf#>/w^\0W8޺Z։k5nEQЂ0*)1Nl C?{ka,v bhL,7N#Tnp 8._#}^n[آMftvFzcJ^=IYf7t^}|ZAP naLLYfQϊ(a p.pk+)Ftx=Jg裏zQW_}ֽO<~B@{nyV#:a/[ZrՓ^^}Aw *^^pAF0&A,'?0G)"A%\'c}Wy{&:[ *qm 6Eې!1LmTfc 1΋JͫeR;ن nh~e8v9ֆ!إWaxxuޒRCК0u=3S=)E[a[ûOi~7vOdo9fǽJ":}O0}؏7iN:ʚ_/[8_ _0)rQA,\}=L$r>P!ܧ"u'i&M=|߫/nɊzWgY~3־VD%r&gb[IQѣ*~:(Ug(}Xl#Gr.Ɛqoqg|%A~-- u)$. Np*K1MzxwEu[;5EsW!W'O"xc!M&#u 6tIP`ʩvQ\q49kj+.k3{z1cjb5u6CFߴj!iC$0%(TYU^ }pa׾@aa_&rTTT _ҦnLa}3lɝy!h\OK+l^#~z7&K K[5WL] ВZ9-ΑCV2Mn0ط:CP2l0,\lvZ''Nwa;vMMMO= c[|9I9mܸë>͛2>""yaO; "bS$EgxYDPTYbU;:|h֬Y'OtRɧG. "({#G$\dB)(q=H"&J "n}/wCB&1Jr0jJ HD7"W+ksf۷o'>{ ~qxȑ;w2,iV8q߇&>qf͚@K,Y`:̱cLj//Lٳ''', _|xE!ց \2DD҂aO_"}]vv6N {Ed5,*%yܹ(^iEUVIDH/%e?Aa: L pE ġ]R?XPXĭ.Uܤ:Zɣ@\B!MC`h~g~XnP<|g Z*(޽;##  xAFcot2gIJȆwgϞ}=s#?1wuoM^p.E T_CSPPQ^xZTb.IFCzz:QS0VB%KNuVǏ [EQdI`WYP^8g,`Ac&c+ _Eȡ+VoB$,yQ~" m^ [&`HH/A@3E w&L ^Cm'|ߓ(*9DD ْI(d["Ws?d7RP-;h䥎tJ1(|J%} @D9bh~@9|ÇX,D L&I†G)&N&!`{ɓ'IS .D/s%>㑁~8mYG]cJ!KCa?` +`Aco#n~V(Q³ r6iL\^M(o|ʔ) }]t01Em#qFjts"`oli6S瘙ăf|j٬zߨh܎@:N+~EH-,Ȇ˱G0RINZaw)-Bl b sn*̵TC4@$!@YIW֥c JS"I'I3lKUN:< ~A87%%%NQ0Ã3BhA *Qƒe]xpQ(-Pֵ`A%@x 4 Eʺ,DuF @Yׂ(A.<8((ZE <Pօg"Ђe] TʺLPZkJ @Yi@ u-XP""Vh@ Y#vԉ=L_#a!@YiWGP֩ # ʺH>GN׈fiPEQ?uF4HC.Ү(S5FuvEi}ԏe0+J~(he]]QZ#@YkD34(":_#a!@YiWGP֩ # ʺH>GHgff?Idx̙g$IYzSN 4& (F.܈x:zPe](uʺp#NQ(=@7uFjjMmV\u5[P['NاOQ;v9i'J ͛7p}Κ57|sȑ>]y@AN=ׂYdɂ ?m۶cǎ!ӧO= ϝ;wƌ_}Çuj*0|I%ARJ0Ur!4 CEEEuuujj+3۵k)ŋG--]466V:B åik 6}!C FÀ(yfy &L"/r"7}}!UVgSrsslقghZZxPf֩ L" 9uAe@!駟J׵E Y;X8F̒S(׀(y/r999(UjB^}UB?au@OP(W| o$ʡŃe U\[K(#jmݺUX)6Zq 1>hi!o3Ir~4%ׯ?~AsV%W^FC_QmmX懭ɷ\., Ćede uPj*lbXƋՎ.)HwKyF%qyPVӁ`L KR??gIENDB`./nsf2.4.0/doc/example-scripts/rosetta-classes.tcl000755 000766 000024 00000001151 13454166031 022701 0ustar00neumannstaff000000 000000 # == Rosetta Example: Classes # For details see https://rosettacode.org/wiki/Classes # package req nx package req nx::test nx::Class create summation { :method init {} {set :v 0} :public method add {x} {incr :v $x} :public method value {} {return ${:v}} :public method destroy {} {puts "ended with value [:value]"; next} } # === Demonstrating the behavior in a shell: ? {set sum [summation new]} "::nsf::__#0" ? {$sum value} 0 ? {$sum add 1} 1 ? {$sum add 2} 3 ? {$sum add 3} 6 ? {$sum add 4} 10 ? {$sum value} 10 # During the destroy of the object, +ended with value 10+ is printed ? {$sum destroy} "" ./nsf2.4.0/doc/example-scripts/tk-horse-race.html000644 000766 000024 00000102746 13217207455 022427 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/tk-horse-race.tcl

    A small Horse Race game, originally developed by Richard Suchenwirth in plain Tcl (see http://wiki.tcl.tk/3467). The game was rewritten as a design study in NX by Gustaf Neumann in May 2011.

    tk-horse-race.png
    package require Tk
    package require nx::trait
    
     ##############################################################################
     # Trait ListUtils
     #
     # Some list utilities, not part of a package we can require here.
     ##############################################################################
    
     nx::Trait create ::nx::trait::listUtils {
    
       :protected method lpick {list} {
         # return a random entry from a given list
         lindex $list [expr {int(rand()*[llength $list])}]
       }
       :protected method lremove {listName what} {
         # remove a list element referenced by the elements value
         :upvar $listName list
         set pos  [lsearch $list $what]
         set list [lreplace $list $pos $pos]
       }
     }
    
     ##############################################################################
     # Class Horse
     #
     # This class defines the logic, how and where a single horse and
     # jockey are drawn. The painting of the horse happens just at startup
     # time, later the horses are moved via their tags.
     ##############################################################################
    
     nx::Class create Horse {
       :property name:required      ;# name is the external name of the horse
       :property tag:required       ;# tag is an internal id
       :property canvas:required    ;# the canvas, on which the horse is drawn
       :property n:integer,required ;# the position on the canvas
    
       :require trait nx::trait::callback
       :require trait nx::trait::listUtils
    
       :method draw {x y} {
         set hide [:lpick {black brown white gray brown3 brown4}]
         set c1 [:lpick {red yellow blue purple pink green}]
         set c2 [:lpick {red yellow blue purple pink green}]
         ${:canvas} create oval 0 -1 18 4 -fill $hide -outline $hide -tag ${:tag}
         ${:canvas} create line 1 12 3 0 5 12 -fill $hide -tag ${:tag} -width 2
         ${:canvas} create line 15 12 17 0 19 12 -fill $hide -tag ${:tag} -width 2
         ${:canvas} create line 16 0 20 -7 24 -5 -fill $hide -tag ${:tag} -width 3
         # Jockey:
         ${:canvas} create line 9 4 11 1 7 -1 -fill $c1 -width 2 -tag ${:tag}
         ${:canvas} create line 7 -2 10 -6 15 -3 -fill $c2 -width 2 -tag ${:tag}
         ${:canvas} create oval 9 -7 12 -10 -fill orange -outline orange -tag ${:tag}
         ${:canvas} move ${:tag} $x $y
       }
    
       :method init {} {
         set w [entry ${:canvas}.e${:n} -textvar [:bindvar name] -width 7 -bg green3]
         ${:canvas} create window 5 [expr {${:n}*30+5}] -window $w -anchor nw
         :draw 70 [expr {${:n}*30+14}]
       }
     }
    
     ##############################################################################
     # Class HorseGame
     #
     # Defines the main canvas of the Game and contains the logic of
     # starting, resetting etc.
     ##############################################################################
    
     nx::Class create HorseGame {
       :property {bg1 green4}   ;# background color of the canvas
       :property {bg2 green3}   ;# background color of the result label
       :property {width 750}    ;# width of the canvas
       :property {height 330}   ;# height of the canvas
       :property {horses}       ;# a list of horse names participating in the game
    
       :require trait nx::trait::callback
       :require trait nx::trait::listUtils
    
       :method init {} {
         #
         # create the canvas
         #
         set :canvas [canvas .c -bg ${:bg1} -width ${:width} -height ${:height}]
         pack ${:canvas}
         #
         # create the Horses
         #
         set n 0
         foreach name ${:horses} {
           set h [::Horse create horse$n -name $name -canvas ${:canvas} -n $n -tag horse$n]
           lappend :tags horse$n
           incr n
         }
    
         # finish line
         set w [expr {${:width} - 20}]
         ${:canvas} create line $w 0 $w ${:height} -fill white -tag finish
    
         # start button
         button ${:canvas}.button -text Start -pady 0 -width 0 \
             -command [:callback start ${:tags}]
         ${:canvas} create window 5 [expr {$n*30}] -window ${:canvas}.button -anchor nw
    
         # label for the results
         label ${:canvas}.winners -textvar [:bindvar winners] -bg ${:bg2} -width 80
         ${:canvas} create window 70 [expr {$n*30}] -window ${:canvas}.winners -anchor nw
       }
    
       :public method start {running} {
         #
         # When the "Start" button is pressed, we turn this button into a
         # "Reset" button and the horse race starts. We stop, when more
         # than two horses pass the finish line.
         #
         ${:canvas}.button config -text Reset -command [:callback reset]
         set :winners {}
         set finish [expr {[lindex [${:canvas} bbox finish] 2]+10}]
         while {[llength ${:winners}]<3} {
           set this [:lpick $running]
           ${:canvas} move $this [:lpick {0 1 2 3}] 0
           update
           if {[lindex [${:canvas} bbox $this] 2] > $finish} {
             lappend :winners [expr {[llength ${:winners}]+1}]:[$this cget -name]
             :lremove running $this
           }
         }
       }
    
       :public method reset {} {
         #
         # When the "Reset" button is pressed, we switch back to the start
         # configuration, the horses come back to the start.
         #
         ${:canvas}.button config -text Start -command [:callback start ${:tags}]
         foreach tag ${:tags} {
           set x [lindex [${:canvas} bbox $tag] 0]
           ${:canvas} move $tag [expr {70-$x}] 0
         }
       }
     }
    
     #
     # everything is defined, create the game
     #
     bind . <space> {exec wish $argv0 &; exit}
     HorseGame new -horses {Blaise NX Animal Ada Alan XOTcl Grace itcl John Linus}

    ./nsf2.4.0/doc/example-scripts/rosetta-multiple-distinct.tcl000644 000766 000024 00000002064 13677316541 024731 0ustar00neumannstaff000000 000000 # # == Rosetta example: Multiple distinct objects # # # Create a sequence (array, list, whatever) consisting of "n" # distinct, initialized items of the same type. The value of "n" # should be determined at run time. # # https://rosettacode.org/wiki/Multiple_distinct_objects # package req nx package req nx::test # # The class +Foo+ defines and implements the item type. It can also # be used to query its population of instances. # nx::Class create Foo set n 100; # run time parameter # # Wrong: Only a single item (object) is created, its (command) name is # replicated +n+ times. # ? {llength [Foo info instances]} 0; set theList [lrepeat $n [Foo new]] ? {llength [Foo info instances]} 1; ? {llength [lsort -unique $theList]} 1; [lindex $theList 0] destroy # # Correct: +n+ items (objects) having distinct (command) names are # created and stored in the list. # ? {llength [Foo info instances]} 0; set theList {} for {set i 0} {$i<$n} {incr i} { lappend theList [Foo new] } ? {llength [Foo info instances]} 100; ? {llength [lsort -unique $theList]} 100; ./nsf2.4.0/doc/example-scripts/rosetta-single-inheritance.html000644 000766 000024 00000044367 13217207455 025216 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-single-inheritance.tcl

    Rosetta example: Inheritance/Single

    Show a tree of types which inherit from each other. The top of the tree should be a class called Animal. The second level should have Dog and Cat. Under Dog should be Lab and Collie.

    package req nx
    
    nx::Class create Animal
    nx::Class create Dog -superclasses Animal
    nx::Class create Cat -superclasses Animal
    nx::Class create Collie -superclasses Dog
    nx::Class create Lab -superclasses Dog

    Show the resulting class search order:

    % Lab info superclasses -closure
    ::Dog ::Animal ::nx::Object
    % [Collie new] info precedence
    ::Collie ::Dog ::Animal ::nx::Object

    ./nsf2.4.0/doc/example-scripts/tk-mini.html000644 000766 000024 00000044451 13217207455 021331 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/tk-mini.tcl

    Tiny Tk example scriped based on NX.

    tk-mini.png
    package require Tk
    package require nx::trait
    
    nx::Class create MyClass {
      #
      # A sample application class that creates a text entry field bound
      # to an instance variable. When the provided button is pressed, the
      # content of the variable is placed into an additional output label.
    
      #
      # The callback trait imports methods "callback" and "bindvar":
      #
      :require trait nx::trait::callback
    
      :public method button-pressed {} {
        # When this method is invoked, the content of the ".label" widget
        # is updated with the content of the instance variable "myvar".
        .label configure -text ${:myvar}
      }
    
      :method init {} {
        wm geometry . -500+500
        pack [label .title -text "Type something and press the start button ..."]
        pack [entry .text -textvariable [:bindvar myvar]]
        pack [label .label]
        pack [button .button -text start -command [:callback button-pressed]]
      }
    }
    
    MyClass new
    

    ./nsf2.4.0/doc/example-scripts/rosetta-delegates.tcl000644 000766 000024 00000002266 13565500370 023207 0ustar00neumannstaff000000 000000 # # == Rosetta Example: Delegates # For details see https://rosettacode.org/wiki/Delegates # package req nx package req nx::test nx::Class create Delegator { # The class Delegator has a property named "delegatee" which is an # object: :property delegatee:object # The method "operation" decides, whether it deletates the action to # another object, or it performs the action itself. :public method operation {} { if {[info exists :delegatee]} { ${:delegatee} operation } else { return "default implementatiton" } } } nx::Class create Delegatee { # The class "Delgatee" might receice invocations from the class # "Delegator" :public method operation {} { return "delegatee implementatiton" } } # === Demonstrating the behavior in a shell: # # Create a +Delegator+, which has no +delegatee+ defined. Therefore, # delegator performs the action by itself, the default implementation. # ? {set a [Delegator new]} "::nsf::__#0" ? {$a operation} "default implementatiton" # # Now, we set the +delegatee+; therefore, the delegatee will perform # the action. # ? {$a configure -delegatee [Delegatee new]} "" ? {$a operation} "delegatee implementatiton"./nsf2.4.0/doc/example-scripts/rosetta-abstract-type.tcl000644 000766 000024 00000002355 13454166031 024032 0ustar00neumannstaff000000 000000 # # == Rosetta Example: Abstract type # # Define a class without instances and without implemented methods. # For detailed description of this example # see https://rosettacode.org/wiki/Abstract_type # package req nx package req nx::test # # Define a class AbstractQueue nx::Class create AbstractQueue { :public method enqueue {item} {error "not implemented"} :public method dequeue {} {error "not implemented"} :public object method create {args} { error "Cannot instantiate abstract class [self]" } } # # Define a concrete queue (named ListQueue) based # on the Abstract Queue nx::Class create ListQueue -superclass AbstractQueue { :variable list {} :public method enqueue {item} { lappend :list $item } :public method dequeue {} { set item [lindex ${:list} 0] set :list [lrange ${:list} 1 end] return $item } } # === Demonstrating the behavior in a shell: # # Trying to create an instance of the AbstraceQueue returns an error message: ? {AbstractQueue new} {Cannot instantiate abstract class ::AbstractQueue} # Create an instance of the concrete queue: ? {set q [ListQueue new]} "::nsf::__#1" # Enqueue and dequeue items ? {$q enqueue 100} 100 ? {$q enqueue 101} "100 101" ? {$q dequeue} 100 ./nsf2.4.0/doc/example-scripts/rosetta-multiple-inheritance.tcl000644 000766 000024 00000002170 12776662115 025377 0ustar00neumannstaff000000 000000 # # == Rosetta example: Inheritance/Multiple # # Write two classes (or interfaces) Camera and MobilePhone, then write # a class CameraPhone which is both a Camera and a MobilePhone. # # https://rosettacode.org/wiki/Inheritance/Multiple # package req nx package req nx::test # # NX offers class-based and mixin-based multiple inheritance. The # search order of features (methods, properties) along the class # hierarchy is computed using a scheme equivalent with C3 # linearization. # # # a) Class-based multiple inheritance # nx::Class create Camera nx::Class create MobilePhone nx::Class create CameraPhone -superclasses {Camera MobilePhone} # Show the resulting class search order: ? {CameraPhone info superclasses -closure} {::Camera ::MobilePhone ::nx::Object} ? {[CameraPhone new] info precedence} {::CameraPhone ::Camera ::MobilePhone ::nx::Object} # b) Mixin-based multiple inheritance nx::Class create CameraPhone -mixins {Camera MobilePhone} ? {CameraPhone info mixins} {::Camera ::MobilePhone} # Show the resulting class search order: ? {[CameraPhone new] info precedence} {::Camera ::MobilePhone ::CameraPhone ::nx::Object} ./nsf2.4.0/doc/example-scripts/tk-locomotive.tcl000644 000766 000024 00000015150 13454166031 022362 0ustar00neumannstaff000000 000000 # # Example by # https://wiki.tcl-lang.org/1329 # # - translated from Tcl to XOTcl by gustaf neumann in 2001 # - translated from XOTcl to NX by gustaf neumann in 2010 # # image::tk-locomotive.png[] # # Left mousebutton starts, middle slows down, right stops # package require Tk package require nx package require nx::trait nx::Class create Wheel { :property x :property y :property r :property {spokes 24} :property {pivot 0} :property {color red} :property {tag ""} :public method drawSpokes {} { ::nx::var import [:info parent] c alpha set delta [expr {360.0 / ${:spokes}}] set deg2arc [expr {atan(1.0)*8/360.}] for {set i 0} {$i < ${:spokes}} {incr i} { set x1 [expr {${:x} + cos($deg2arc*$alpha) * ${:r}}] set y1 [expr {${:y} + sin($deg2arc*$alpha) * ${:r}}] $c create line ${:x} ${:y} $x1 $y1 -fill ${:color} -tag spoke set alpha [expr {$alpha + $delta}] } if {[info exists :act_pivot]} { lassign [set :act_pivot] item perc set rp [expr {${:r} * $perc}] set xp [expr {${:x} - $rp * cos($deg2arc * $alpha)}] set yp [expr {${:y} - $rp * sin($deg2arc * $alpha)}] $c coords $item $xp $yp [expr {$xp + 1}] [expr {$yp + 1}] } } :method init {} { ::nx::var import [:info parent] c alpha set alpha 0. set :y [expr {${:y} - ${:r}}] $c create oval \ [expr {${:x} - ${:r}}] [expr {${:y} - ${:r}}] \ [expr {${:x} + ${:r}}] [expr {${:y} + ${:r}}] \ -outline white set r1 [expr {${:r}-2}] set W [$c create oval \ [expr {${:x} - $r1}] [expr {${:y} - $r1}] \ [expr {${:x} + $r1}] [expr {${:y} + $r1}] \ -outline ${:color} -width 2] :drawSpokes if {${:pivot}} { set deg2arc [expr {atan(1.0) * 8 / 360.0}] set rp [expr {$r1*${:pivot}}] set xp [expr {${:x} - $rp * cos($deg2arc * $alpha)}] set yp [expr {${:y} - $rp * sin($deg2arc * $alpha)}] set new_pivot [$c create rect $xp $yp [expr {$xp + 1}] [expr {$yp + 1}] \ -fill ${:color} -tag [list ${:tag} pivot]] set :act_pivot [list $new_pivot ${:pivot}] $c create arc [expr {${:x} - $r1}] [expr {${:y} - $r1}]\ [expr {${:x} + $r1}] [expr {${:y} + $r1}] \ -style chord -fill ${:color} -start 310 \ -extent 80 -tag counterweight set :pivot $new_pivot } set rh [expr {${:r} / 12.0}] $c create oval \ [expr {${:x} - $rh}] [expr {${:y} - $rh}] \ [expr {${:x} + $rh}] [expr {${:y} + $rh}] \ -fill white -tag hub set :r $r1 } } nx::Class create Locomotive { :property {speed 4} :require trait nx::trait::callback :method turn {} { set :alpha [expr {round(${:alpha} + 360 - ${:speed}) % 360}] foreach i [${:c} find withtag counterweight] { ${:c} itemconfig $i -start [expr {310 - ${:alpha}}] } ${:c} delete spoke foreach wheel [:info children] { $wheel drawSpokes } ${:c} raise hub set xp0 [expr {105 + 15 * sin((${:alpha} - 90) * atan(1.0) * 8 / 360)}] ${:c} delete piston ${:c} coords p0 $xp0 120 [expr {$xp0+2}] 122 ;#CW ${:c} create line 90 121 $xp0 121 -width 2 -fill white -tag piston ;#CW :drawRod p0 p1 p2 p3 ${:c} raise p0 foreach i [${:c} find withtag smoke] { if {[lindex [${:c} bbox $i] 3]<0} { ${:c} delete $i } else { ${:c} move $i [expr {rand() * ${:speed} / 3.0}] [expr {rand() * 2 - 2}] } } set t [${:c} create oval [${:c} bbox chimney] -fill white -outline white -tag smoke] ${:c} move $t 0 -10 ${:c} lower smoke } :method drawRod {p0 p1 p2 p3} { ${:c} delete rod ${:c} create rect [${:c} bbox $p1 $p3] -fill white -tag rod ${:c} create line {*}[lrange [${:c} bbox $p0] 0 1] \ {*}[lrange [${:c} bbox $p2] 0 1] -width 3 -fill white -tag rod ${:c} raise rod ${:c} raise pivot } :public method tick {} { :turn foreach i [after info] {after cancel $i} after 10 [self] tick } :public method throttle {} { incr :speed 2 :tick } :public method break {} { incr :speed -2 if {${:speed}<0} {set :speed 0} :tick } :public method emergencyBreak {} { set :speed 0 :tick } :method init {} { set :c [canvas .c -width 600 -height 160 -background lightblue] pack ${:c} bind ${:c} <1> [:callback throttle] bind ${:c} <2> [:callback break] bind ${:c} <3> [:callback emergencyBreak] ${:c} delete all ${:c} create rect 32 115 360 125 -fill black ;# frame ${:c} create rect 22 118 32 122 -fill grey30 ;# buffer ${:c} create line 22 115 22 125 ${:c} create poly 60 95 40 115 50 115 70 95 -fill black ${:c} create rect 60 45 310 95 -fill grey25 ;# boiler ${:c} create oval 55 50 65 90 -fill black ;# smokebox ${:c} create rect 70 32 85 50 -fill black -tag chimney ${:c} create rect 40 52 90 75 -fill black ;# wind diverter ${:c} create oval 130 36 150 52 -fill black ;# dome ${:c} create rect 195 35 215 50 -fill black ;# sandbox ${:c} create oval 260 36 280 52 -fill black ;# dome ${:c} create rect 65 100 90 135 -fill black ;# cylinder ${:c} create rect 90 120 92 122 -fill red -tag p0 ;# crossbar ${:c} create rect 72 87 82 100 -fill black ;# steam tube ${:c} create rect 310 40 370 115 -fill black ;# cab ${:c} create rect 310 32 390 42 -fill grey30 ;# cab roof ${:c} create text 338 82 -text "01 234" -fill gold -font {Times 7} ${:c} create rect 318 48 333 66 -fill white ;# cab window #1 ${:c} create rect 338 48 355 66 -fill white ;# cab window #2 Wheel new -childof [self] -x 50 -y 150 -r 13 -spokes 12 Wheel new -childof [self] -x 105 -y 150 -r 13 -spokes 12 Wheel new -childof [self] -x 150 -y 150 -r 30 -pivot 0.5 -tag p1 Wheel new -childof [self] -x 215 -y 150 -r 30 -pivot 0.5 -tag p2 Wheel new -childof [self] -x 280 -y 150 -r 30 -pivot 0.5 -tag p3 :drawRod p0 p1 p2 p3 Wheel new -childof [self] -x 340 -y 150 -r 16 -spokes 12 ${:c} create rect 360 110 380 118 -fill black ${:c} create rect 380 65 560 125 -fill black -tag tender ${:c} create rect 560 118 570 122 -fill grey30 ;# buffer ${:c} create line 571 116 571 125 ${:c} create rect 390 45 525 65 -fill black -tag tender Wheel new -childof [self] -x 395 -y 150 -r 13 -spokes 12 Wheel new -childof [self] -x 440 -y 150 -r 13 -spokes 12 ${:c} create rect 380 132 456 142 -fill red Wheel new -childof [self] -x 495 -y 150 -r 13 -spokes 12 Wheel new -childof [self] -x 540 -y 150 -r 13 -spokes 12 ${:c} create rect 480 132 556 142 -fill red -outline red ${:c} create rect 0 150 600 160 -fill brown ;# earth ${:c} create line 0 150 600 150 -fill grey -width 2 ;# rail :tick } } Locomotive new ./nsf2.4.0/doc/example-scripts/rosetta-single-inheritance.tcl000644 000766 000024 00000001270 12776662115 025025 0ustar00neumannstaff000000 000000 # # == Rosetta example: Inheritance/Single # # Show a tree of types which inherit from each other. The top of the # tree should be a class called Animal. The second level should have # Dog and Cat. Under Dog should be Lab and Collie. # # https://rosettacode.org/wiki/Inheritance/Single # package req nx package req nx::test nx::Class create Animal nx::Class create Dog -superclasses Animal nx::Class create Cat -superclasses Animal nx::Class create Collie -superclasses Dog nx::Class create Lab -superclasses Dog # Show the resulting class search order: ? {Lab info superclasses -closure} {::Dog ::Animal ::nx::Object} ? {[Collie new] info precedence} {::Collie ::Dog ::Animal ::nx::Object} ./nsf2.4.0/doc/example-scripts/traits-composite.html000644 000766 000024 00000064604 13217207455 023271 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/traits-composite.tcl

    Implementation study based on

    1. Ducasse, O. Nierstrasz, N. Schärli, R. Wuyts, A. Black: Traits: A Mechanism for Fine-grained Reuse, ACM transactions on Programming Language Systems, Vol 28, No 2, March 2006

    Fig 13: tReadStream and tWriteStream as composite traits

    In this example, traits are used to extend classes and other traits (called then composite traits).

    package req nx::trait

    Create a Trait called tPositionableStream

    nx::Trait create tPositionableStream {
      #
      # Define the methods provided by this trait:
      #
      :public method atStart {} {expr {[:position] == [:minPosition]}}
      :public method atEnd {} {expr {[:position] == [:maxPosition]}}
      :public method setToStart {} {set :position [:minPosition]}
      :public method setToEnd {} {set :position [:maxPosition]}
      :public method maxPosition {} {llength ${:collection}}
      :public method minPosition {} {return 0}
      :public method nextPosition {} {incr :position 1}
    
      # The trait requires a method "position" and a variable "collection"
      # from the base class or other traits. The definition is incomplete
      # in these regards
    
      :requiredMethods position
      :requiredVariables collection
    }

    Create a composite trait called tReadStream based on the trait tPositionableStream:

    nx::Trait create tReadStream {
      #
      # Methods provided by this trait:
      #
      :public method on {collection} {set :collection $collection; :setToStart}
      :public method next {} {
        if {[:atEnd]} {return ""} else {
          set r [lindex ${:collection} ${:position}]
          :nextPosition
          return $r
        }
      }
    
      # This trait requires these methods:
      :requiredMethods {setToStart atEnd nextPosition}
    
      # Require the trait "tPositionableStream"
      :require trait tPositionableStream
    }

    Create a composite trait called tWriteStream based on the trait tPositionableStream:

    nx::Trait create tWriteStream {
      #
      # Methods provided by this trait:
      #
      :public method on {collection} {set :collection $collection; :setToEnd}
      :public method nextPut {element} {
        lappend :collection $element
        :nextPosition
        return ""
      }
    
      # This trait requires these methods:
      :requiredMethods {setToEnd nextPosition}
    
      # Require the trait "tPositionableStream"
      :require trait tPositionableStream
    }

    Define a class ReadStream with properties position and collection that uses the composite trait tReadStream:

    nx::Class create ReadStream {
      :property {collection ""}
      :property -accessor public {position 0}
      :require trait tReadStream
    }

    Create an instance of ReadStream:

    ReadStream create r1 -collection {a b c d e}

    Test the behavior of the composed class:

    % r1 atStart
    1
    % r1 atEnd
    0
    % r1 next
    a
    % r1 next
    b

    ./nsf2.4.0/doc/example-scripts/tk-ludo.tcl000644 000766 000024 00000036554 13523353522 021160 0ustar00neumannstaff000000 000000 # A small Ludo/Mensch ärgere Dich nicht/Pachisie game, originally # developed by Richard Suchenwirth in plain Tcl (see # https://wiki.tcl-lang.org/956). The game was rewritten as a design study in # NX by Gustaf Neumann in July 2013. # # Major changes: # # - object-oriented design (no global variables) # # - knowledge about the paths of the figures # # - animated moves # # - knowledge about the basic rules (e.g. need 6 to move out of the # nest, have to move figures from starting position) # # - throw opponents out # # - sanity checks # # - user feedback # # image::tk-ludo.png[width=400] # # Short Instructions # # - The active player (marked with the button) has to dice (click on # the die, or press somewhere on the board "d"). # # - If all figures are in the nest (start position), the player needs # to dice a 6. The player is allowed to try three times, then the # player is done (press "done" button, or type "n") and the turn # moves to the next player. # # - When a player got 6 eyes, he can move out of the nest. This is # done by clicking on the figure the player wants to move. # # - After dicing 6, the player can dice again and move the player on # the field (always by clicking on the figure). # # == Implementation # package require Tk package require nx::trait # # Define an application specific converter "expr" that passes the # scalar result of the expression. Since the converter is defined on # nx::Slot, it is applicable to all method and configure arguments. # ::nx::Slot method type=expr {name value} {return [expr $value]} # # Class Figure # nx::Class create Figure { :property canvas:required :property x:double :property y:double :property size:double :property position:integer :property color :property no:integer :property board:object,required :variable tag "" :require trait nx::trait::callback :method init {} { # # Draw figure and define interactions # set d [expr {${:size}/6.}] set s [expr {${:size}/1.5}] set y [expr {${:y}-$d*2.5}] set :tag ${:color}${:no} set id [${:canvas} create arc [expr {${:x}-$s}] [expr {${:y}-$s}] \ [expr {${:x}+$s}] [expr {${:y}+$s}] -outline grey \ -start 250 -extent 40 -fill ${:color} \ -tags [list mv ${:tag}]] ${:canvas} create oval \ [expr {${:x}-$d}] [expr {${:y}-$d}] \ [expr {${:x}+$d}] [expr {${:y}+$d}] \ -fill ${:color} -outline grey -tags [list mv ${:tag}] #${:board} figure set $id [self] ${:canvas} bind ${:tag} [:callback go] } :public method go {} { # # Start moving the figure if the draw is permitted. # The board knows the die and the rules. # if {![${:board} moveFigure [self]]} { # stay at old position :gotoNr ${:position} } } :public method gotoNr {nr {-path ""} {-afterCmd ""}} { # # Move figure to the numbered position. If a path is given it # moves stepwise from position to position. # set oldPos ${:position} set :position $nr if {$path eq ""} {set path $nr} return [:move {*}[${:board} getPointCenter $oldPos] $path \ -afterCmd $afterCmd] } :protected method move {x0 y0 path:integer,1..n {-afterCmd ""}} { # # Move figure from old position (x0 y0) stepwise along the # path using animation. At the end of the move, 'afterCmd' is # issued. # set t 0 foreach pos $path { lassign [${:board} getPointCenter $pos] x y set stepx [expr {($x-$x0)/50.0}] set stepy [expr {($y-$y0)/50.0}] for {set i 0} {$i < 50} {incr i} { after [incr t 8] ${:canvas} move ${:tag} $stepx $stepy } lassign [list $x $y] x0 y0 incr t 100 } after $t ${:canvas} raise ${:tag} after $t $afterCmd set :x $x; set :y $y } :public object method lookup {position} { # # Return the figure at the provided position. This function # could be made faster, but is efficient enough as it is. # foreach f [Figure info instances] { if {[$f cget -position] == $position} { return $f } } return "" } } # # Helper functions for the die # proc random:select L {lindex $L [expr int(rand()*[llength $L].)]} proc lexpr {term L} { # map an expr term to each element \$i of a list set res [list] foreach i $L {lappend res [eval expr $term]} set res } # # Class Die # nx::Class create Die { :property canvas:required :property x:double :property y:double :property {size:double 25} :property {fg gold} :property {bg red} :property {eyes 0} :require trait nx::trait::callback :method set {n} { # # Set the eyes of the die. # ${:canvas} itemconfig ${:grouptag} -fill ${:bg} -outline ${:bg} foreach i [lindex [list \ {} {d5} [random:select {{d3 d7} {d1 d9}}] \ [random:select {{d1 d5 d9} {d3 d5 d7}}] \ {d1 d3 d7 d9} {d1 d3 d5 d7 d9} \ [random:select {{d1 d3 d4 d6 d7 d9} {d1 d2 d3 d7 d8 d9}}] \ ] $n] { ${:canvas} itemconfig ${:id}$i -fill ${:fg} -outline ${:fg} } set :eyes $n } :public method invalidate {} { # # Invalidate the eyes to avoid double uses of the eyes. # set :eyes 0 } :public method roll {} { # # Roll the dice and animate rolling # # wiggle: amount, pick one of eight wiggle directions set dwig [expr {${:size}/5}] for {set i 10} {$i<100} {incr i 10} { :set [expr {int(rand() * 6) + 1}] set wig [random:select {0,1 0,-1 1,0 -1,0 1,1 -1,1 1,-1 -1,-1}] set wig [lexpr \$i*$dwig [split $wig ,]] ${:canvas} move group${:id} {*}$wig update set wig [lexpr \$i*-1 $wig] ;# wiggle back ${:canvas} move group${:id} {*}$wig after $i } } :method init {} { # # initialize the widgets with tags interactions # set x [expr {${:x} - ${:size}/2.0}] set y [expr {${:y} - ${:size}/2.0}] set :id [${:canvas} create rect $x $y \ [expr {$x+${:size}}] [expr {$y+${:size}}] \ -fill ${:bg} -tags mvg] set :grouptag group${:id} ${:canvas} addtag ${:grouptag} withtag ${:id} set ex [expr {$x+${:size}/10.}] set ey [expr {$y+${:size}/10.}] set d [expr {${:size}/5.}];# dot diameter set dotno 1 ;# dot counter foreach y [list $ey [expr {$ey+$d*1.5}] [expr {$ey+$d*3}]] { foreach x [list $ex [expr {$ex+$d*1.5}] [expr {$ex+$d*3}]] { ${:canvas} create oval $x $y [expr {$x+$d}] [expr {$y+$d}] \ -fill ${:bg} -outline ${:bg} \ -tags [list mvg ${:grouptag} ${:id}d$dotno] incr dotno } } :set [expr {int(rand()*6)+1}] :invalidate # # To dice, let people click on the die, or press on the # board # ${:canvas} bind mvg <1> [:callback roll] bind . [:callback roll] } } # # Class Board # nx::Class create Board { :property canvas:required :property {size:integer 25} :property {bg LightBlue1} :property {fg white} :property {colors:1..n {red green yellow blue}} :require trait nx::trait::callback :method lookup {var idx} { # # Convenience lookup function for arbitrary instance # variables. # set key "${var}($idx)" if {[info exists $key]} {return [set $key]} return "" } :public method getPointCenter {nr} {:lookup :pointCenter $nr} :public method getPointId {nr} {:lookup :pointId $nr} :method line { x0:expr,convert y0:expr,convert x1:expr,convert y1:expr,convert {-width 1} {-arrow none} } { # # Convenience function for line drawing, evaluates passed # expressions. # ${:canvas} create line $x0 $y0 $x1 $y1 -width $width -arrow $arrow } :method point {x:expr,convert y:expr,convert d {-number:switch false} -fill} { # # Draw a point (a position on the game board) and keep its # basic data in instance variables. We could as well turn the # positions into objects. # if {![info exists fill]} {set fill ${:fg}} incr :pointCounter set id [${:canvas} create oval \ [expr {$x-$d/2.}] [expr {$y-$d/2.}] \ [expr {$x+$d/2.}] [expr {$y+$d/2.}] \ -fill $fill -tags [list point] -outline brown -width 2] #${:canvas} create text $x $y -text ${:pointCounter} -fill grey set :pointNr($id) ${:pointCounter} set :pointCenter(${:pointCounter}) [list $x $y] set :pointId(${:pointCounter}) $id return ${:pointCounter} } :method fpoint {x:expr,convert y:expr,convert psize fsize color no} { # # Draw a point with a figure, note the position in the board # in the figure # set nr [:point $x $y $psize -fill $color] Figure new -board [self] -canvas ${:canvas} \ -x $x -y [expr {$y-$fsize/2.0}] \ -size $fsize -color $color -no $no -position $nr return $nr } :method pnest {x:expr,convert y:expr,convert d colorNr xf yf} { # # Draw the nest with the figures in it # set fsize [expr {$d/0.75}] set color [lindex ${:colors} $colorNr] lappend :nest($colorNr) [:fpoint $x-$d $y-$d $d $fsize $color 0] lappend :nest($colorNr) [:fpoint $x-$d $y+$d $d $fsize $color 1] lappend :nest($colorNr) [:fpoint $x+$d $y-$d $d $fsize $color 2] lappend :nest($colorNr) [:fpoint $x+$d $y+$d $d $fsize $color 3] set :buttonPos($colorNr) [list [expr $x+($xf*$d)] [expr $y+($yf*$d)]] } :method pline { x0:expr,convert y0:expr,convert x1:expr,convert y1:expr,convert d {-width 1} {-arrow none} } { # # Draw a path of the play-field with points (potential player # positions) on it. # set id [${:canvas} create line $x0 $y0 $x1 $y1 \ -width $width -arrow $arrow -fill brown] if {$x0 eq $x1} { # vertical set f [expr {$y1<$y0 ? -1.25 : 1.25}] for {set i 0} {$i < int(abs($y1-$y0)/($d*1.25))} {incr i} { :point $x0 $y0+$i*$d*$f $d } } else { # horizontal set f [expr {$x1<$x0 ? -1.25 : 1.25}] for {set i 0} {$i < int(abs($x1-$x0)/($d*1.25))} {incr i} { :point $x0+$i*$d*$f $y0 $d -number } } ${:canvas} lower $id } :method draw {m} { # # Draw board and create figures # set d ${:size} set u [expr {$d * 1.25}] # # Major positions: p0 .. p1 ..m.. p2 .. p3 # set p0 [expr {$u-$d/2.0}] set p1 [expr {$m-$u}] set p2 [expr {$m+$u}] set p3 [expr {2*$m-$u+$d/2}] :pline $p0 $p1 $p1 $p1 $d -width 4 :pline $p1 $p1 $p1 $p0 $d -width 4 :pline $p1 $p0 $p2 $p0 $d -width 4 ;# horizontal short line :pline $p2 $p0 $p2 $p1 $d -width 4 :pline $p2 $p1 $p3 $p1 $d -width 4 :pline $p3 $p1 $p3 $p2 $d -width 4 ;# vertical short line :pline $p3 $p2 $p2 $p2 $d -width 4 :pline $p2 $p2 $p2 $p3 $d -width 4 :pline $p2 $p3 $p1 $p3 $d -width 4 ;# horizontal short line :pline $p1 $p3 $p1 $p2 $d -width 4 :pline $p1 $p2 $p0 $p2 $d -width 4 :pline $p0 $p2 $p0 $p1 $d -width 4 ;# vertical short line :line $m+5*$d $m+2*$d $m+6*$d $m+2*$d -arrow first :line $m-2*$d $m+5*$d $m-2*$d $m+6*$d -arrow first :line $m-5*$d $m-2*$d $m-6*$d $m-2*$d -arrow first :line $m+2*$d $m-5*$d $m+2*$d $m-6*$d -arrow first set d2 [expr {$d*0.75}] set d15 $d2*2 set o [expr {$u*5}] :pnest $m+$o-$d $m-$o+$d $d2 0 -1 3 :pnest $m+$o-$d $m+$o-$d $d2 1 -1 -2.5 :pnest $d15 $m+$o-$d $d2 2 1 -2.5 :pnest $d15 $m-$o+$d $d2 3 1 3 for {set i 0; set y [expr $d*2]} {$i<4} {incr i;set y [expr {$y+$d}]} { lappend p(0) [:point $m $y $d2 -fill [lindex ${:colors} 0]] lappend p(1) [:point $m*2-$y $m $d2 -fill [lindex ${:colors} 1]] lappend p(2) [:point $m $m*2-$y $d2 -fill [lindex ${:colors} 2]] lappend p(3) [:point $y $m $d2 -fill [lindex ${:colors} 3]] } # # Setup the path per player and color the starting points # for {set i 1} {$i < 41} {incr i} {lappend path $i} foreach c {0 1 2 3} pos {11 21 31 1} o {11 21 31 1} { ${:canvas} itemconfig [:getPointId $pos] -fill [lindex ${:colors} $c] set :path($c) [concat [lrange $path $o-1 end] [lrange $path 0 $o-2] $p($c)] } } :public method msg {text} { # # Report a message to the user. # ${:canvas} itemconfig ${:msgId} -text $text return 0 } :public method wannaGo {obj pos {-path ""}} { # # We know that we can move the figure in principle. We have # to check, whether the target position is free. If the target # is occupied by our own player, we give up, otherwise we # through the opponent out. # if {$pos eq ""} {return [:msg "beyond path"]} set other [Figure lookup $pos] set afterCmd "" if {$other ne ""} { if {[$obj cget -color] eq [$other cget -color]} { # On player can't have two figure at the same place. return [:msg "My player is already at pos $pos"] } else { # Opponent is at the target position. Find a free # position in the opponents nest and though her out. set opponent [$other cget -color] foreach p [set :nest([lsearch ${:colors} $opponent])] { if {[Figure lookup $p] eq ""} { set afterCmd [list $other gotoNr $p] break } } } } :msg "[$obj cget -color]-[$obj cget -no] went to $pos" $obj gotoNr $pos -path $path -afterCmd $afterCmd ${:die} invalidate } :public method moveFigure {obj} { # # Move the provided figure by the diced eyes according to the # rules. First we check, if we are allowed to move this # figure, which might be in the nest or on the run. # set currentColor [lindex ${:colors} ${:player}] if {[$obj cget -color] ne $currentColor} { return [:msg "figure is not from the current player"] } set eyes [${:die} cget -eyes] if {$eyes == 0} { return [:msg "Must dice first"] } set position [$obj cget -position] if {$position in [set :nest(${:player})]} { # Figure is in the nest, just accept eyes == 6 if {$eyes == 6} { :wannaGo $obj [lindex [set :path(${:player})] 0] } else { return [:msg "Need 6 to move this figure"] } } else { # # Check, if we have still figures in the nest # set inNest "" foreach p [set :nest(${:player})] { set inNest [Figure lookup $p] if {$inNest ne ""} break } # # Check, if the actual figure is at the start position. # set startPos [lindex [set :path(${:player})] 0] set atStart [Figure lookup $startPos] if {$eyes == 6} { if {$inNest ne ""} { # Move a figure out from the nest, if we can if {$atStart ne ""} { if {[$atStart cget -color] eq $currentColor} { set path [set :path(${:player})] set current [lsearch $path $position] set targetPos [expr {$current + [${:die} cget -eyes]}] :wannaGo $obj [lindex $path $targetPos] \ -path [lrange $path $current+1 $targetPos] return 1 } } return [:msg "You have to move the figures from your nest first"] } } if {$atStart ne "" && $inNest ne "" && $obj ne $atStart} { return [:msg "You have to move the figures from the start first"] } set path [set :path(${:player})] set current [lsearch $path $position] set targetPos [expr {$current + [${:die} cget -eyes]}] :wannaGo $obj [lindex $path $targetPos] \ -path [lrange $path $current+1 $targetPos] } return 1 } :public method nextPlayer {} { # # Switch to the next player. # set :player [expr {(${:player}+1) % 4}] ${:canvas} coords ${:buttonWindow} {*}[set :buttonPos(${:player})] } :method init {} { set hw [expr {14 * ${:size}}] set center [expr {$hw / 2}] canvas ${:canvas} -bg ${:bg} -height $hw -width $hw :draw $center set :die [Die new -canvas ${:canvas} -x $center -y $center -size ${:size}] set :msgId [${:canvas} create text [expr {${:size}*4}] 10 -text ""] # # Player management (signal which player is next, etc.) # set :player 2 button .b1 -text "Done" -command [:callback nextPlayer] set :buttonWindow [.p create window 22 14 -window .b1] :nextPlayer bind . [:callback nextPlayer] } } # # Finally, create the board and pack it # Board new -canvas .p -bg beige -size 40 pack .p ./nsf2.4.0/doc/example-scripts/bagel.tcl000644 000766 000024 00000013335 13454166031 020643 0ustar00neumannstaff000000 000000 # # This example is a straight translation of the OTcl Tutorial # https://www.isi.edu/nsnam/otcl/doc/tutorial.html to NX. It serves as # a very short intro to the basic elements of scripting with NX and # provides a comparison study to OTcl. # package req nx package req nx::test nx::test configure -count 1 # Suppose we need to work with many bagels in our application. We # might start by creating a Bagel class. ? {nx::Class create Bagel} ::Bagel # We can now create bagels and keep track of them using the info # method. ? {Bagel create abagel} ::abagel ? {abagel info class} ::Bagel ? {Bagel info instances} ::abagel # Of course, bagels don't do much yet. They should remember whether # they've been toasted. We can create and access an instance variable # by defining a property for the class. All instance variables are # per default public in the sense of C++. ? {Bagel property {toasted 0}} "" # Since abagel was created before the definition of the property we # have to set the default value for it using the setter method. Again, # the info method helps us keep track of things. ? {abagel info vars} "" ? {abagel configure -toasted 0} "" ? {abagel info vars} toasted ? {abagel cget -toasted} 0 # But we really want them to begin in an untoasted state to start # with. ? {Bagel create bagel2} ::bagel2 ? {bagel2 info vars} toasted ? {bagel2 cget -toasted} 0 # # Our bagels now remember whether they've been toasted. Let is # recreate the first one. ? {lsort [Bagel info instances]} {::abagel ::bagel2} ? {::abagel destroy} "" ? {Bagel info instances} ::bagel2 ? {Bagel create abagel} ::abagel # Now we're ready to add a method to bagels so that we can toast # them. Methods have an argument list and body like regular # Tcl procs. Here's the toast method. ? {Bagel public method toast {} { if {[incr :toasted] > 1} then { error "something's burning!" } }} "::nsf::classes::Bagel::toast" # The defined methods can be queried with info. We see as well the # setter method for the variable toasted. ? {Bagel info methods} {toast} # Aside from setting the toasted variable, the body of the toast # method demonstrates how to access instance variables by using a # leading colon in the name. # We invoke the toast method on bagels in the same way we use the # info and destroy methods that were provided by the system. That # is, there is no distinction between user and system methods. ? {abagel toast} "" ? {abagel toast} "something's burning!" # Now we can add spreads to the bagels and start tasting them. If we # have bagels that aren't topped, as well as bagels that are, we may # want to make toppable bagels a separate class. Let explore # inheritance with these two classes, starting by making a new class # SpreadableBagel that inherits from Bagel. A SpreadableBagel has an # property toppings which might have multiple values. Initially, # toppings are empty. ? {nx::Class create SpreadableBagel -superclass Bagel { :property -incremental {toppings:0..n ""} }} ::SpreadableBagel ? {SpreadableBagel cget -superclass} ::Bagel ? {SpreadableBagel info superclasses} ::Bagel ? {SpreadableBagel info heritage} {::Bagel ::nx::Object} # Let's add a taste method to bagels, splitting its functionality # between the two classes and combining it with next. ? {Bagel public method taste {} { if {${:toasted} == 0} then { return raw! } elseif {${:toasted} == 1} then { return toasty } else { return burnt! } }} "::nsf::classes::Bagel::taste" ? {SpreadableBagel public method taste {} { set t [next] foreach i ${:toppings} { lappend t $i } return $t }} "::nsf::classes::SpreadableBagel::taste" ? {SpreadableBagel create abagel} ::abagel ? {abagel toast} "" ? {abagel toppings add jam} jam ? {abagel toppings add m&m} "m&m jam" ? {abagel taste} "toasty m&m jam" # Of course, along come sesame, onion, poppy, and a host of other # bagels, requiring us to expand our scheme. We could keep track of # flavor with an instance variable, but this may not be # appropriate. Flavor is an innate property of the bagels, and one # that can affect other behavior - you wouldn't put jam on an onion # bagel, would you? Instead of making a class hierarchy, let's use # multiple inheritance to make the flavor classes mixins that add a # their taste independent trait to bagels or whatever other food they # are mixed with. ? {nx::Class create Sesame { :public method taste {} {concat [next] "sesame"} }} ::Sesame ? {nx::Class create Onion { :public method taste {} {concat [next] "onion"} }} "::Onion" ? {nx::Class create Poppy { :public method taste {} {concat [next] "poppy"} }} "::Poppy" # Well, they don't appear to do much, but the use of next allows them # to be freely mixed. ? {nx::Class create SesameOnionBagel -superclass SpreadableBagel -mixin {Sesame Onion}} ::SesameOnionBagel ? {SesameOnionBagel create abagel -toppings butter} "::abagel" ? {abagel taste} "raw! butter onion sesame" # For multiple inheritance, the system determines a linear inheritance # ordering that respects all of the local superclass orderings. You # can examine this ordering with an info option. This ordering # determines the method resolution, when e.g. "next" is called. ? {SesameOnionBagel info heritage} {::Sesame ::Onion ::SpreadableBagel ::Bagel ::nx::Object} ? {abagel info precedence} {::Sesame ::Onion ::SesameOnionBagel ::SpreadableBagel ::Bagel ::nx::Object} # We can also combine our mixins with other classes, classes that need # have nothing to do with bagels, leading to a family of chips. ? {nx::Class create Chips { :public method taste {} {return "crunchy"} }} "::Chips" ? {nx::Class create OnionChips -superclass Chips -mixin Onion} ::OnionChips ? {OnionChips create abag} ::abag ? {abag taste} "crunchy onion" ./nsf2.4.0/doc/example-scripts/tk-geo2.png000644 000766 000024 00001221577 12501766547 021067 0ustar00neumannstaff000000 000000 PNG  IHDRp iCCPICC ProfileH WgXSS@HhPޑ^ l$$"bwQVtUDŵ]Y{XPPł ;ݻywo3 l8 U [/ g%%(P6lN/::&@k6./ Ӹyl5rĒ|H=bXMx'#i#mX52hlQAl' EO؛#`s!.:;;{ 6Of}fᑱq0OŞ50_Ïiÿ́y+䰃b!քx9nj8ՠ@?~@~03'q~4']5it,tI0!ϼ q1c8BLj avI+^Ӱ/'y08''rH\v [ll <D@$5 "q@ȂERk!=#und;c9Bx! *yõqo/,>;Gcþ6G/fJho=S0x 3S >br9J&[`Kyvk ;5bmq5 "+D@"HDc%7ŨEKEg{@&l~0VP=f@mķ 7uq/gck fs ؀l %<õrij$B wK5+Lıf9;b%4ew.RP63sFoo`D/%Wh=`aF  (t F<U`=[@h9pt.`A BG Vx#AH$$#!RY!kJd;RCN!NA Q j.jGP?4C|4-B+ ֣݇ TD1)`Lܰ, K1 6+ʱj5Lbp2Y P<\|9^35އ%I:$+)DfJH]"'Ldry6y9y3B$?!S(-ŋEaS)%}.G99}9`9Brr'=W7ϒ_)SI|UjFQ3 ԳԷ  **\PxJЦҤݴ[:nJ+5 E[0E<*zūL+)+Vԫ,lV\|Lr C^%J%[e^*ݪUS UbU00#a,bdet2;'WW11)3\<ļXq@q;Nm8θqAu,ubtfi n=۫[wBG/_RKbUΰ t B   >03j537h\l\k|DD`S3D% ffafEff>-n-:,QKgKe+Jh٪Ӛdn-eC)yd˴]h`jǟ.n={UpMo,8U_;Y98vf8Ot^Er5u-75hnIܛ?yx{3sg ;'<2b{mySy| |>>}||Ye{o/?!#`N@K XT00\2;%:Vn'&/5|NZDlDeHHIdDtbĵO2$¢F=6΍m2yrbcc2bg}2^y45A)ajBM‡5Is.'k' S() )RMY?kԒ7M+vqg(`8JJMLݛ:ȎbW6q88/uo yWn-G#( [3>dFeJ̪˖N>&Ret%bYG>IdW7-1_ rۤҟ >LyPPT6rֲYϋ~n-6(^Phߜsis[[1tdԓN'~fg/ >w.4_xۥ.ۜێv+W;;:'tsԵk箇]|cҍΛ7oߚzKv{N֝w ܛt:N";(Qp|tk3k{{:^LyRrO?72u/߿^K^YVwNZ~?=>A`/M_#%k4=7(:*܍}bd`/l` ,&8[ ;: &GCCou4E244yhNx@KȝP9~./O|#`l+ pHYs%%IR$iTXtXML:com.adobe.xmp 1194 1458 _@IDATxwŵ튈 *6. 6b,[,4v1&b[5Dc{oOEQnGdw6;ww9k=E@PE@PE@PLuwPSE@PE@PE@ i("("("-¬N*"("("?E@PE@PE@PEIE@PE@PE@Pt9("("(@[ ÿ:("("(4E@PE@PE@h taV'E@PE@PE@"("("(m""("("(:PE@PE@PE-_[YTE@PE@PE@"("(":k0"("("Os@PE@PE@P@@mfuRPE@PE@Pi("("("-¬N*"("("?E@PE@PE@PEIE@PE@PE@Pt9("("(@[ ÿ:("("(4E@PE@PE@h taV'E@PE@PE@"("("(m""("("(:PE@PE@PE-_[YTE@PE@PE@"("(":k0"("("Os@PE@PE@P@@mfuRPE@PE@Pi("("("-¬N*"("("0B:u{7N<_~}?!L?fyYgu;vG.]v࿏[l iן"#|eTrP*n_'m?okO?xw}=g800dؽ{^zDz.RK4vUT IMT(_i"x<P}'=?Ͽ/>Yd󦎷v~7/^fmO?tW2e rgwoꫯ!Ϻ3 ]"w„ 6F߫W+7|" 8pK/ԣG{+w q)_85EݧC9{1blE]DIWbZo:s|!?2 y˛7޶-K.ߌ3*A?l;/Yu ~zH@Jb*Zk}B"TB꣏>Zyţ|?X`)_H (@q|5jԨ=?W\6ۀ7߼% /|WoFP+_wuW`@`Ge3]wLiRwzn^!g?cE#yꩧBB^!|`ꪫ2߿?BF斞(@pW "/@O*hZE"E)r)gq]\{ݺu3@ѣt 2`Z(_YUb:CCu]w}7oόKxi&#V[W|d 7|<|puQ{lpgn$|'r38妛nfzG5DPD1_ bnN*5tZQg| رc鹝p 'xb"|Rxꩧ6^kquױnBДW:p^y{x_'s=w~q0O7 oa*'1n~ ң21c>sQ4sq A)HUtW-x- sR2P"P!ȑ#'@=Au"(^92~9@W*%%KLĿ73زXוҒ@)+a3Ss;3m/~ JTF*\+m&,hd+B =z鄤|4χ(d.bv ݈#ZہUvq[Eq!㻀 ܻwo`חꪎ|-!W*U" _$'N74DG WJ0ߥKiVBB[qؖ(+L[RjW^xᅕW^sHxpTu(ƥȫWEle A}ggZk%,fXVN1+B1 S6ݗjv@RҽQH|-wIn,|Ո^Q!_Dgi,r"GP 64uDp/?8p|ˆulJbOM-i"(L*Z+) 9xST"UACfUv UB&O:yt8cg_u0+_|^] 1ߞ9|p*O+Z4eP*T|kU@q *ի|U P|@^?|ѣG/bt'XvFGxQ@ɉ` :6l'|N}6M fIPTOZИ +ի@%́,!Vʂ֭ )Ȕ~[eAj 1aeY^_B~;,ԹsgF_|E!:fD1ovR T"n a"X&#%ڣgT ̜)JbiŪ#!_5q 2+d bX\+_g:i:Km_~y뭷!s}I'}g(BRk&.`|:HuU:lj,'pABI@m*jETK D`lI;8kWX8lÿ I wk{ƯN;dfzE8*>G$)Q&?x@uہŧU<>z|W_}uV'3,ХAgpwp pЇ R' Mcܼ`ϕhoWW_}|RK ,NчA"*ߺW)tUf>\VyZz)Sv \ѱXEūTd % Ik*V*1٭| ^,;wNׁ!>|o_2<$FI?蠃r9̚bJ<_"(*NEYI C2T'eazB|UaUL UY">Kr߼ӟT"JT㠼ewR%P6tg馛d$\~ jVkƛ+677n\qV#(B]qZJLzT)UݶT*7v|DCKA[⻸38C[}i 7q8^}ߨ| V:mԩ￿a'ZU`-7omGPW$f; *nT*::ڍ%gb[ buQ~?m Ⲭn @QF{WX5+ÿf:KٓϺ\pnN:9ߢECiC$ K E C|UAT'% k*8oҥ Z{vWq(+wC-cBsMk-JW+gv- Ƀ$N-%|UVuڇ.J[ꫯ9js 8F]:V% h hLHU:ks*/~Qh,\lO:nZ yH!%H*`u_5૪LV+J=)矗G>[ B7pBѸ}o1gsNt]e[Y[nqRo)H$|"JAUՇL;Wϼ.^c{C`D[O嫤/zj'Y(QK2a 6pJܫvtAI0̽~Ԁj0Xj̫8|VoA[oMoc}/3zZ8py [*Q/ ׭ڱcGo߾^t64/"ofy{.?Pj :U.GRZ$iFU|jW5&5˃|,z=#E];_µD\t|e V|~t{n).|e(I'132^Re=:ƶՀj0@O8|bk|wߝp ߿;cN(n '(_YB"q2ǩj _ 4yGIR[ #ͦ $.SVUTo=C#W62xWoLa ҉'XE#C"pѓF"-ߺW-O1ym!gmk%j)=z?\030U%H9'MVnT{U_cPd3pV2Z,|5rH֫{ST`7*_ŀÿ{o#eZj_~92S. Q4Rp H?|'IRlP@|UPW)BߞU'|resy饗gh0`PBU3zo,$k޽ˠA}7oc &a{j$HB|'!IrQ~"P(u} >=q:+jWYe^z}S Xdp7z(_EӾ?XdEH~g}V[1-("[$!HBm3lk|UOtWӠ=?p7/, AY# eYԫ|DCtO/d4wE6[?#SN2&R6OgpHEINR4G*ԃ1%U.P?!՝wٵkWzs<dc;`U( 83fl30p*H;oɾIym!!IK'EITUԃ11UU)QQ ! U v?i"#Y0Qռ,4r%^`AZ"Z$Lԃ1=E*Ĩ@e?V]uU|vgx)Zurvؒ@r/|e msnֶ{~+-y&SHQ ]uh[>l=`\r<8W9DuEWW^yeǎ32ˌ;Vr'pQoe.2V)X|ԩpԨQ`0Sv)*IZ] 2mT|UMyU M{W;҅Aj{UyMD *<+ok:|X՞s>4mݶܶg#1m ײ *D-C̩zU=6bz|cJTKW|裏.t{kZHZAP "L:|?XV=zfF34lklc$b?ژoU%uG|VZ=CgIR%?+^zhO>ԟ$1BC"d6q#T=X,FL`NWHZ4&z zU=3bTz|UPz)zwYg: <2wZEha"XI;U͇ӦM[s5I޽{>۸Gȑ#a2eJkT lU. $3)]?#A|UaL)9Y蔯JIJosC=1)I>"p/i˷-_y?l60[kh{@òK-c6Ʒ:Hi;Zԃ1)1aU)F'|E[~GnW- XLbGK'_ywGX(xTˋ/\Ȃ@ Į;BU=.YgK>ճ> +зc9. p Jؤrڐj; '=zt}f$xL$AFp˲D4 RJQ|U+2s"ÇOUy뭷jVY=OHQ]@CRQi `WʘT/x≥^?ps?UizY͑d %\SoYgsᳮc=|62m8k8zjBNGU BR+5_*&vWo;묳wpZ9$i@2$m5: o?ҢW^VZ~S=n2UHړD|fsÏ[C|U tW&Lp w Gq.W)ZҀd %H ҃$)HQHl? !8~P'&caÆ\#踩II~>H|s޼B>tWv26뮻u_)!+ޑ$W}7Lq\veҽ{iӦom: q qgI_-hU>G /+JoO_}aWcM68qȨa%"@b'$ iZULhH6A+bʔ)ho[% Nm$zBjV&4 3kaqT>(.%JzPJLՋ/+kf;OXs҃$!UH҆qFÿs9GȤQG&7Wj|851k4psS|UaҡQ*%g,/C5_nƍgiksH!yHѨ_Uu3o/:UkL3&88^m'6HѺT=J0Tݒ򕟉猯&Ov7c=o"aHt*ԚU%}8蠃 vo4骖YEp<եQ4I\;J-*-)̮tRD*^lk5<\wu:kC HIUuJN;4"5^$iw}`ҩS 㸟QV4X-*WTT+C[[`)_e~'<ׯ[o * H$҉"H_Uo_P+'\_qI:rg4qk-t_&4-=!'BLʟ,uWok_(:tR'D"H*R# r6|U 0>b/B0ᝏ5pe xeX@H .Vb *WHkTW7pW>by睗Mݺu{衇|Zm$Ef-_O6[pijB(d[nBfh*A  4`ѭ &OWB+>+rP/[}*m6|. C"H3RzUlB*w7=K zZ0&3aUcM  U0 嫧~GfSi&x_׀4~*@VW ]2,|sU׋> @F&CqN_Ut\R.PNǗ裪n+H6Y# s|U|m9\smnu Py$Kcɐ!4rtg+W0ho b@JjҤIm8W_mOH9" #Uj XQ6;s ^Evm4_~GU% ߔKvi@!Ih>2V8Tp*bX[A|u=,B]}4Uc#,ABR_4_͈۴OϏK/K.K/>['o&貳 /k9>coY{17l6;vio,@K;]jsL ?pz?:kq*$oYa%\rVZ- /\`<))\*_9Ȋ9н[E]4T -Wl%*2>m}73Wbs\ԣ^g?Sdލ7L& u|7֙n2,Ckɫ# E8*P@!ߗN+-n 4"R* Au*HA?+b嫂2!Rl|ꫯjS|:?C޶|UVIE$9IQ5KWx7x;oc8rx~gwq3qĻ{я=k&ڙ7x /_+ÆW_/JN|If`N: ~hQcxlO7{2QJwrwn؀ ,y{n\͝ U^ X+)/r!?/0ӧOPW۞+&x{@[zꩼt*U> 農:(fw|8!L33r D2h?!CW|Ld;nȑ̢d"G=K~pϘŒXEaf` &H%a )&eh>4" M\. U^ ,|732[U/RCb|5ez}]wg"KjY85_1Da s=7h~r[hDN|]WHNRTr͞+ߗ~aXA+L}_B۟裏^|ť/m|F-5Bx mU'䢥% ,QRT 0㖥P1`0BSРo镼 _Uk0" U|o%7_I)_%E,Ej̘12\ʈ#RXR*Y fR>Kc^믿D\FdPu :^9*뢓$pFU+ $HtZk0^]8g"_RK-' uvG{LJ* ۷/r*u9'Y)R``ƿY%"Pbʴ-nD _Ue_s+>x]9Mo6XR*u\XPbdSTbvy>2Œ`aF"/s0EQW FS1IJ r䫖,!U|f7_c)_nvb3zo VSdaF*Z=zĚ~{< B㫠E IfR:? VOy^G8,,oc*Ma_0>#l$޵^,ODŽ1S1Ɂ#S6r*h6ۡ MI>q.}_yϝ,,N*^xws7_")_E’|5ۘU_ kK?e,G 0*RB| +H`G%NcLq<餓EdID4[oT~6MEuQ,|~c"(.x pp iֲpAN=* 'O:ݶ@ 9g+vcyOpaU_{묳H2#mv" SEƍAeR w'uIXV $7IBTйsgHZVavV 5G=ܳkPOD8FAfc9y.4M}p/@sEXx]"*)U Vĭ|-Bd*_l?~3ۯ%5+:!gw2fmRk_EZYyWv ,U39]"T|u)>>0駟0W" IO9Nu kl\^& N'X!qw=5E~YJW1xzP^[wsC͠ RI(?4C"#c4. -vǦzg[_(_oB ܒB,\WF$+և >ꚟ|['h*BUy#PcRA)%_v<O<9FfnW;$8: f4[!2!J$^|oԩ]t]w@m\+ds{\/f/@ TUpIZ7]y`^\F&i:EC#44:^+#?ʷ{|ߢU4㫢mu嫖+^veRsc .V|/䒀iʨ y[%FZ|㫌$NW24+A;ak1cG~m|dt 'p~첏1 /p ƻ]A)MF\؂VNbsyWw|ߢEUk/h- T b%_`96*/ A|JmV_}ҿf D1/K|,KӠ&%Lʣߪ _Rģ~Uhk&xxv;3?geΥfvצKE,O7zLQjpOHY. @hz^YU c|+ʱ5U )SJT+gdM[q衇ʟԺ*W1_hBӯ_C&*R!ו]i)$|S9 4^o|Ug_!*97WI|uwvڕ? ,ߞNEukW<1o>$ #_e%Eu&͇F(se7h @3[2c'ޕ#wshd0q}RK-En{4v6ͮZ6sQf*.d_eq$u]ME u+/שJ_GJ{=zl-s=Ex^2<X^4=Р]󄯼$h_UoWXQ2Wl&b{)DQ8/ٳ ̦>k2 #.ګα$РO]?l(1g Kߐ́ 7^Qj$˴&9J"<s+q`ߔ)S{Q:1q7)ҹMf-J7PZh!}CۓQF%N9P4$J|fh{m<5miAL-K+O:hf ΅W6KoF9"Dju>FS޷r+&0;tpe15MMW|΅\jdq_<;cȳC9$+-䨣 f]@EʗC 1s?A8Į W,}@!P$+g3+AO8B7j CtoKZBbP9r-LDU.CD6R8!W|U FGw+i} .yK#<2~BlYf s=%?bXxᅿ@8*Pⴴ -ߏy Mұ +|p#uM71GS_os57iˋwG*|f /lY28}21* 'Y2?Q:4I+sӖ]t_y_:0|M22kgs A.@31 ޞD*B-yA|囿!t` 8\W[W@r%Iu]W{8+-62iSa#a/d7Bauf⛿?bVF۬Y6E(θd EW|UbhO?5_؛mrcЮ-, Y*9/GПUiÿ_~ 6_sРAOj)Dm昱~ Pr?`G.+*HgE](RĎu3o҃SXChG_6!񖸹[ͼPj|'93߬]OW<:-P@8_%2>4@1 Jw_[Q!/a})I\Z:\.6"pƻs& 4qS|UV:?Pwy1tH!SAPؙWݢmfU$2?p=sNW:餓̎m~$mx(@ho|8|f8+*m&JqD^zi@ҥKՉf=z`ɹ_(E5-! XBPp*2eIgU vcc*3oOxs+?GB"p)P\PDѣIVX!X/,#z)ޥ{W.ErӦMc9x 1J\@Bp{vgcFY03Črq 2C;/MaXguumĉO4SO1\4IhmtSyia4/U㒯wmCs]tMy2~ko˒:H8h*HBJ8Cj3)_ qӔ8V5'׀1\Cx!4=2JW =P`p8pɮh+|UthzdPW Yf3fLѸ)upxD[/|zi8m[~X`+3pEnQbM̶dS2.)bmQ,(ҢN}DX iYfHی =+5_٣'%s:a^YU+_0 _-zPZLW#GpZj|\$+N}b_FlYOjiv4:f(B8p3<>HN /vҷo_,2dH 'Ov.rNqPAT"@8&XBb-f|`ˡ{57|岻4^U3J cq.f)I/ߐWA@"jw/ڙg,YsKb;}W3lM>eʔR:0`W6K_0cm6OJLq2bXxٗQ>oym(& 6ࠃ:^x Ldz pO.r $:q/f` %1WL\G,׶ုu~Y1`eŊ׆yYRq~r1_t@/jT]ʕmE`W%aKz{ &:t zNZՍ7(Y 88"Rv  xcyW16%_<2-7M9=-7Kfu5ׄ?^ Tfmgq;W"TFN*@*R! Q5pو4$П`[4OASBgWκ^guVꍵrגBzC?Բ?i^BdID_! |5uT!0a)Y _eZr%i<= Na:( DD,LshžU ÿW_pɹ駟.e­_~$;vH8VYes9'f[a :>\lX" a &q" IȚS4OܧGK +7cKO.iB HUȋAZUyKLID!3=9)ߐkWf|;loJ%_"hiBdWt#z*2 ?%XU"BSjH3_%70͍FG \HVC'mu" PfcNJ%LEݜsΉy[l<YVbK.uRT領bdK9 LGB$[RO<Q(_9g_uUiL4"D|71 ?k/`2(_ 1|Ż#cu V|J |E3kFEnQTit!wjT%Ee|25Oa2oO` dС 1ܠc : +pcgl̸(lw'29[6Pjg̐ZA6F) a"XGdY [; 58*C;֭Y,MW-,`nW@{b "dβb2^ @bO?:qz+F1Ԋvߒ(fzpz*F/_EUkhh2!Xr=;SԆ3}Ҙ .=$I>0vˌs$,s- X:5j(N0S-T`a˥\Ġ$b ⫢¹`tKߤ|eײWIF "dΦ2tA 4JfܔI0R7+μRߠ<#-{ɳf6)&/Hf=ƪ`p#E|%9 Ǜ͆\ኂr@C E%$Ys}7e93-٣j/J2OC"~'ˉƠdQL0.L5Bm˱$R&|9(YA[ k 2*ƍ2?zyMTRÞHoK-K_K)A@#J5qy3z_ %_Y"m7Wf_ $Uڤ粼'.|z'+0"E%̻;g-êo] gNm4ڮ]"o"iMG̐#1CܨB).Fiz.w*/n?ꨣ2_fHW)&,;.$BF_|qD ( y'|e94*}Kf9͋ 3%c" MFsEV􁯜 _N:ymzd.8;3r&N(φYWSӻfK3?cpkVu1O&`nV~_8uTqߊ:w*ґ>ӕs"J7i _adRMzMJ'Wrx|eWl_}4UxÁ6|931r`%2 1\DIfJU ibĂ֬|t'%3Djy'd)KRau) 3z%\t ΐ[S,?$`*cv !9V!p=2GM8}Y-̗ftYuYzM7mVz^wy4=%_eԛ+LA&L rH%s|EW_|1ezkZ NB|+԰ˢs/1/<[@#M=GC|UDg8W\qE➅U.zS1|P !HNs^+K|ޣ ;浓g|D5|+ȑ#eZ ޱA b 1*P̅\/*W~Ҹdl[ztr:/ 5)X`,Oy2Էo_/uUWGA;1"^dAėlv#eF Y3]  -\V.M!%yUW=A_pSU^2 䫼U QWX[,PGb |(d cQ"-Wk6D? 2|/Wj,)ВؕQ?']2(>4)T UB4)_КkA?.wvX~1b?VV =Sl|ꨒ1'`2O uznMiz7ʷ꣏>櫼e1XU^z ) _av+_J㎷')pn-ejy睛XW(X=ݻВ={|Tu(Eu\*REdJk4.. ~ybY,lN^z#u.kDʴBoPޞg|e9~F3g2%|/s1WjUpOG瑊R\D]pi8JaBX& rT'4+5jR._y着4BP++.{G#XٸqҰO>G"=9[*j,GJDPhg-`[KbWyugc,,֐!CUE063 ̖ROK /|E@C׽_K&Æ 6}.#|/1˜m _1 ɨF(ڒfQ-;~EΌ͋iN@B|/Ě^/ .@g}R)}i>}Se̛د wbz $%4Xzb33U.Ygꪄ;)_l1lUz 4'U7MI7h ^BOSMWF (s+WA7iPB ^9/ VZi%pI\ |ݚ:u ^{~)FxhȲ 9˶2⩧bJYHKTAϸmw-pH %Vipb3 יFO,VNW;aޮӾx4 _AD14en Oq ך Hi\I:N24 2?"O*.fJV7q->쳍|?a饗Fr-'򓋍|EfY eU=\k&z""J㕯#(پW% _~4޽{4/WT&5_8\1A8"W1|i@j|7"/Xi5Ь"݌X._9c0ޟK[f]zrǎÕtq]vA;3 7eBE鍉( $=)rfҺBQ"Npě]!+MC 2)_dv|U<-:Cl * *Wu#/ Qv|w^+|TW,eyjv՟wyn4|'s<'B5>i+G$jkW``̞nR/_5k2>Ri)K%,;`=3x'<{YwY6'4i \̬"590f:BˁXDN)koP\'2Чv4[\θn-Ӡ"- Y l˖,⫘nB b#Ԭn6bOK"-W}+_W ƍO_ YgW[m5FҒF cfz7hWͤc4{TNQ|L\'d#||E#TTJ+Gÿ/@z.!mFʬrYaOӠȉf+ӭ$f(ȃ%"&F!!j,P+}L: j^o!HLH%_u]fF/!b ([ :`DgD( 'P6|#TK-X'9U38'eWBfK+G?YCiAկ_~4ʹiylc^C /0pD'X![nw}(ɞS=Ak! ӭKWpM,.[ʥlk&nJ  ق6MC 2ɆuI 3G-8n;_em݂|eS C Yf _fjfsHEBw+_'ܒ,\)$V&^vLƙ,C_g+~;B[nO-҄1hK*Y17(Nj*8ALc]R t:L),-+ njӉ%sn _ᲹI3*_5W*i,d7& &XVF2ȳZ+`rذaFo<ҿx+>o2tNdKW!f[J4` IBr|E1Q/6WJ+G?yx賔袋K/_lܺ;C׋{'yHi)03nS^R˒Ps F|NÌsy$F<#i,Q,:;Vl&! -#t?i8EUf">3C|H/kr!ƺtz/HgW_ $*׀TR.T;wFu|4RU|,w#6,<UM&Mn)C|kż _vmh~f/٬R[;@;+2b`]șD\QU"Gw0k"$Z̾\B S_dxܺѣ+%ߤ#ǃ[]72 rsLv>h)Ȓl3iTөmT˄.]Df~|·f9`OwKx ( DTl%!ꨒnbL/0"|/g<H BRɌp)KQ.f)V4W. URL1KȺ-(ȱH1ye:%SE^ ćp4 U|,wUEm*]\fKUfU_Y?E1|ţ^"4!U?t6dB1syͺL(&ج}_ɚ:sv#+Y,-W Z"VڥmvoF/>6zXPIUGm65j7',?2!W& 4H D>芬b.&uq+})]zPP ꨶ hnl.WS1o;U\s5|LjU4|)_^؀;RZ+.w^@̹L.d"p ρ 3ۓӦMc矟UbbF=ԢzXȻqisq|EhB JJ{4H_l.WԩSmK/$Z]J?ۗtq hB|TbPe 'Oevh\qw溼 NnQ,HjFN HNbEVHc`҃$,P4[ W _Í3S ʱW>h Cd]O'xOk79( QXzi e7X5٩k|lWLx_-8!_e_x&~΢ZQ|jС$N߬bf0hYwu]Ox9WS@Wڤ;`,*'ʨzH?Q$?n,;8k\ 2a)RN|*JYi,4Y{,%% Uȥˇ*2[y.>&#1CuLcENh䑒QBC"Y^3◬@Ø\9T\#*2긋j c'!MILfbIF*!KT&쿩yYe^2}#<"f+f MozTd|H0f[&5P1^ދX>x2Mq;*Kow_Ro$3>Cx"$R78H_= `>˪?hZ]WH`nH&6f(:yY2q,tw Ս(9A`TFDܵDʉ(,PxRܥXhz4MW3MO>)yWʪ.3 .BtLB'BƝw ۂo?b<)9|pY "שD! ``|enAW̽$A* RU hZTEci ˉG7#֔),Eb#3Kl׸ >|e*ViOn;7;KV[mj o`NeFn1el@/BV-3IF&*(,zŘ\boIP$@٥(fBckIhIzf ZI. Fl#;#$4I\D^!I.{rdrBp'LڔOY =qM d'e)kOTD0l6IX9"RNҋ6CU Ll|觵X%M:rba.*efGM:S)϶R?D0Q= ȫ%k3)jϡjtHTDj;`\wuuWP~5\WDF!BQAaQg3(;Fe?ǔ9d jVte.+bdn+G$|GsYMh!mYK&_ fB++U/28 8,_14IC*O2 yJʧɘ!1"uR`瞛[e#'iOIhFReM,#@+_+ޓ`IJt~aZdK+a-NoKonh4c?I6+%F2"K@cg#'bZҒShap_#-)|1x`_ٓ[R%B|hꖞJ wLf+S 0BS׾#[4Y~f&ؿr4')o!'Z_>LwG[be< z)YH,KzY'D^1cZ2\ҷƍ &,c0oB׉T2 c 21L5:y/Skodw҂)%?ʖJ $d/".!H׾%kr].}}4y{33g|{,3sѝ Tޙ,&ld!a~mpb⦀^iᇪ^q]~YfeRS"vhᇪ]ߏe]]ro˛ʦ[k<{}`}ow}>%]_<:xlWR\{Fm]Ůx~w\+&́Se[6| ^_[KIgK3)cq̾.(ӫWn^o^^yoި^Qa41bz=ʶ5(q"Uf^_y*oMdaH,zX6lNdw~ߧ2h3vgeЙ,Ǯ(^ҡzԅ 1M@C4JSbOA[n e3l'VlAL92sTc"ww]wq3pFg:9m& DhX۝|e2u_*M I>IIn۰!= ep9v(l3KQ@*Bhᴥ8lzr3X/W5W58NyzgؓΞ=ݓ&^BTAEʡNьzɻѯ^)Wyk?}ҫ,w9M>dQeOԫĺzk|93ݙWrGP -fs4!YEBz1pw ֒^qRB&٠^.\ m2c6kg>&X{!rK,^NGZjD30#SqMv.vܠY!@*g'l(0̲IOR.:"I*{Rq^!؝VeV[z7%eF-3˞z^LTtWvIS2%ӫ2:,Ny?^zr\,2;2b 6*- AYlSFHy+suc~ \JN^ˋiPj}/Y PS?:}emo7acqOz=e'ѤCu,Hl6"gFwX,=hm{&NI{FNUѐp!׶JkFmUӫ" ': 1/o#3=:GcY+;݄^i ,)z/5bvRZ1kFm+*{/R*V™%KOl:b&nჅY^Q2a#WeeR@qXQ~ ؏I^qRp9r %vzUS:Ii6uX*{/!y3&7-8%E!I/~]O{ȲbH[{Cnܬ3֖Ġc J _v`pb6pS_o^fs-^c^Uo^e7Q2捒%^ϮW.KRHab@i+*(+`(P(!]b5n~wyž+Bn9<+fIo.{HY,;lկ^&!zm^^iPjLG{l?? ٱcǦw-gey/ᦑhfƴZΏ~DN؂3j*o+6(bK6* SIٱ93qn\Yf͕K%$'<"94 U* ́zU S"6witv4dQzf+%MzUS#Xm)B8lQ]wݵIv(}|d=7P`C4V%ۭny(YHvfg1wz^EC; XٿZ<NhA#%ԹVfʥWy/Ou_ z,ӫļ;3UbD Ubi^*ђzvW˒ry~~pe=z G9ZEWCQ7&66_= ^";Y4W5uHCp7&-L1?,nQ)N=Ucw߽馛Qx2Co+fRx=QA:F|ҨҸng B# i s/봼L]yEjțKիObyc_4^gsI^Kbf5&:W_}5UaWl>Iux1^ٍN;-{-j` *(`!_^GDb;+"fvUM?=h |:`G]Q-u닭fO̷vf‘qw̘1Ef[p&Нկ~~ڌ|eAd%fdGK˻@i-)BSfu (`# RCFNX䭡ȫW.UcrwMvyt,Mԫ3W6]믟D #ܣ^YWtK4U}?ȥd?icu2eJysOJ+0e ~i{)\+: f͛7=f3krG KpcR=Ыbz_WYnmzyӟ|͗EIFW ]w+C^Gϣ^2(/I6{A f[Er?8bߚW?,X'_ .G2A pg Yl|NFzU_o뭷&~_xVE!ܗ?Oq^n0 +̴1V '@9Tv)b %a4kbywf4{ ykϘތ͘3ɊU+^1Rh\Rڍ7ț;Ê+H7K>l"JmYyl4UJ U+Mcy\Σyyj7(MM+:Q c f W; k>lҫ~0S]*WLPS ݞT,9CU}ݿbeT0N eWuQ묪a#^߼zޘGWY^^*f ʮL~ok%ҫ Zkӫ~+Xib]ދ^%ZdP_qGc;C+G\%Ɯq <禛nȥ6 K,1u*=Cᅱ\|V9rH,9S&$b0f_s5UںFO/xДɊ%?<-3]XsqbUӾ[uiţ,dԫ~E7^U@/zU^gۨT\-^6kH*>lJ|ͽBr0׃_3bzkCަZʗf`̣(/zhxq~&vW=p l.qO} ʃU/ b+l*3Ve9v7|3v}e ){MOv;od#_Kx0Z Fw>S&h>є~kw~O(ngXi۸%K<^!^߼z^+P*Poo[ԠW_W ʍ =^SO=Յ^ǽW$U?K- ?d"ܸ^sXZ7nK_"L[oJXeUK.WI'DNHiI*g0B\Ǜ&npXB#Fwz&^ro?L sηNeQ^fwXʁz5X_+/(ċ^7!ѫĪs寫Tz\Wt}&P ]yȥW\p0c89O|+n̫JuGB+"H4U?$wu͋6L3twVTkod=N^止dzNgvvKA#+=;AH(f&(_G9Uqbzb:z^_իE ۯ!ѫ~g_W 3Πvg#^ٲUj̘1z/V`}鋐 *Bqσrf*h-sÞ*ZY /p2pJ$8 HvX2Jdҧ*3*l9THm D^4\E1WuwX[WA7%ؔ;.lyiKVg7h#|N1b.¯*uMa}{%OuQ5z4 ѷmJK K̨b6X2 eI+ҫ.=ի…7^e7c2sW~bK_W2+ TWƙ ?Li7:ܽ۹j 6?{Ǫ]QʕR7%;^v6>w{AٻGz~bK/͕d+J]tQs&7JVQ,;.hx.VN\Tdo0#o ~z4m4ߊK#,%PSVzV.jQ*q`Uʒ WYo.X)z^g@FSzn;_WmHP^d[;0/^l1G̯J+ի,W@"BЫL9ˌϔ)S޺o3è5XsfOm(XN=W6vmkqR8UX]TJ)\Uoڼ4Yt8h6X'pz뭅_ﵶ=U%dido.J7P_zި ԫUoRѨT"-^^{h UK]2L.WHHU?Hf3￟ZF~-l%\~B -t2B:qUO|W_Sb%W\59Q{I?U/y@w,d$;PpUV__(~ *I휪Ҋ«֫.p6ַUh^fԫXª_΀b4'lzU'r@+e}WcP8exS*UUUF3,=1\YNx@G%D]xᅐ|͋++ѣG7`]lSz֜(F ]vN;drLI/,x„ &MFć C$ mLNQH! 쇅F \ ( mz*rzRus|WoJ5U=)>2%xLIPfѫo=yŒ|egmzU㐧XAJ KzTWG}4'?Ơ6}݇#܉ҥ~Uh 3XrfDM8 OizioꩧK,}'@3U  "hk-sbZS5a8Z^v\l6ORLOw\i45Z7Tҫ(ꮻ"ؘWnlg+ djҪ>^uܦa39uF8z@/< r뭷zd:SN9J뿘5D 4ޝ wÂu;kĤi8IkUԣW].eΉ0rHFns=y󦤯_.y*s 7ܐX`g{WvrY"qE~GsO&&Κ 4g>MSs)1ΥJ8%919=9ISC5UYZ: ,LԵRiS*Fj2rwƪkF'~x8r>b(@EMHM-'(jDs-t` v΄fm4 As.Uו|˛0Λ@zNI pz,u뿌vUfaRԫJYzHjY)@vfѫn߻,Tf$:g^zh*!M<N:JUv!SY#jJv6{kXz`vPzUm*֫^{zMO;Q{ש{jW3,\f@=(ٖ& fB:1AɝaU?.rPzyO:u%̳:+o=\m\q>^ ,xP{_KEB`crg?Nn|d`<-]Jֶ<0Zm)F&!N=4̘~ȓyԫ2$ùNj*(k0&(*;+RVWo9?g}v.MWk4kpVJr"t `8W쉃ի ?O_~2nIy}3hX-ŵ|5:Oؗ,^74,YΐdWquQ^^o fW5\^U^?m뭷eU{j Ei> ҫ]0Λ1c`*ߔ)S{n7:}u${T6 JZ=X1T۠^ Fɚ/3y)'' aEvvX/zIP5U`@PzUU.\$Z}JgMozkk6{!ÙDWy^K͛%}zDfhb",ұXN- `bӧF`'nQB'9–sQ'`0cy- Ak:(߼'*/1WWyWfpj֪k^FH d YB wO6-eC^~檲,S~54nO @0)|׃Ӎ83֨d(Wu^^5o W5D^%f֫|;.k6WTl!;~zf ve~}Ep׫P_c5hbYuQ-9 U&#mEx:}r.t줳n3@92y2zU.kЫ ҫ,Kzޚ{ [`ƨ^-&oО+5wU@ݿ387n\68FުLυ>z1scc\MK.y5ίaUVf#N7‰S ú]faKP5UmV]QhzUOUatUͼp饗ٌQ7qo֞kp B"ځU@?~njCcz뭹f}sjib՞Jz0 P]vYb$7z'hӭPX ԕ=KhUU V]EhzUك9Rzkzu'k{*ըQpD+7 *0| GΝw9{c]:{ dW^mN=n? p@\ۛY9{N;بt8eFhUUVZxzU%_zU`ziί|o}:-~{lIꫯ\^f=䓝q#@ @T6fwNN,sqqqeI4Uo  "jߊFP*dKJ${zꪫtW7֫f+V{zU@%\ ZF+*{o6MK,1u,;7ͿĢm2^w 8ґK|''$#1[Jӏ@.WHT@aUu:lHsy+ի~ᆴVoTW-"^HmzKh^0a2^e//_BEwy6q-x{i/,e{gY6'F:LN.N1N4N:N ^S/++z,*ֲaUu/UzU[oJX;vlgDWW0<(B@%\A-z\vr-iLoC=d疞l-=33(a7q 0xɩjғh*KQӄyY_^yK!M^Uo/{WfT]vY~ozۻ: Iz!J^J w0{WbXׇ~xYg;ɓ'tA#Gݼo}bq qgqq[I v68l̰6)5^+K0/ӫ̞d!U&B(SzU]bJGL;ӫWp*@WN*!FێӛK.l{{Yhtls)\A>81CnMy?>ԫez%~EzU5Vz~^:;]-z۾" KzM@z,ӊj^feM|L1/zD5\D|[lN:i`)rpdE5p7-(38)lN^8lcNޣS@^+o/ЫȒF_SP9$*C_L7oW{WW3 _<""8iҫ@oL s1V뭷VYeUVc~Xc @aC9'h;=ёlx9M8YbrB+__KW%=}z\zt%JJ엽:nX]?_]J[W~T7D]zn[n~Kl ͎ kV6ʍ6b|x+l-KZ0+Fb*cُ#M-Sce'KN%EsrEk<~zUd%~]21YzCHNQTWǏgVHK;UpZWޱ(U?Kw/?4I f}Yt|[tJaaMˋ'KC4 dq;9ih#^XZqQ;0A:UIi=*3VZEzŐX*ԏWzUG+@lyBwlTɺZWAw?!"F4i5+еba͉N;͆6kmQ*`؛fb0fws/| ƁS VCN"{Jۖ/J7P:UaiTqTzUh~WhuWUj^U$8 QQcsan|z*]vzGf=k[:Lk[jճ>ޅpG` qYj^zi.25\<7)SyBuZc=h/> 6؀.[/@eLFlSN9L;ՆnhL`{&L+cӠ=٫.Wy睹Wz/5w[ZЄ7(~FNY^}/~6ba󺑱^{{q9x,zՂ\챵T t칁2lӫ/F͵筮u^q[o_hgn>裾i2$)ujƍkQفj]!e]W+ݨH.wquֱ5*u]Kl|,x;찃/3ګW-H??j-#CH?Bkvuۭنյ{ԩSeFF C﫯2HBh1rQ6L8F:0!Nrzam]4+"EWETzkсO>έ6R@UFZuX*mzj%c9x_/u[2mm6r7Ѭ%]ESӇ]U^ ko`lyUzUsP]Ez#\~zڭ~T  H²P=֫Ч~qrr ?vjCD ' 'OJ2NuzƮVRmlPUSX^M9zE JP$ 2m׫ъE" sp0XF@8Y8e8ql ZW/L0Πiyں1ҫB jdrU:!H@ngɍUoy~iM /jU'#_ ui0zGF.W~ oiU+(1J/~ "Ukr,9o/$99)ÉF;+%F3JC[OzUClWQ^NT_:j XZ@#z+\O9o6kx{W=5h#NNNN6 [W-}|ԍ)E{NzU}WL833%|rD / $ ȼywCWD&n@IDATZ3k|ٺl6D J4dvZWHā&^B]6dXe;eɰE E/wF4 +s1l~*3c/N N ppKZWl䭽c>qSz+M]4RYx)7|sW?\ pRpjppnꐘ^j! -s$ -VĉG*ۯjhʞa @~!X.UZ}݌2+(ߢ*AAӁSuËUt/Z@ҫm_7nJ]tQSa&@~ayӫ !pN`c4iҌ}#CMx|q|{J@C-'ҫxsݯ^,]r%'Ca;W;M,Un)͹[6epp"p:pRhpYjj#&h{HBHzc4~[o Q D ͆+\`݃?EiVZ qu] 2@K ?'BK]*ۮWm~::_zծW+"S]w]ܗ%@r^:WI5jԥ^^x)b;W'Lr}l^ihS1p^5&Taf xht^05G,O=۩ $P' N:yڮW萴%:ZzՖ`ggyZj[U"aFr TomM~P+ zj› ' x¾6U%F k K&׫C9߬>8oJ/y f!7#D:ٞ%\Vk @+9N`HzՁIbxWSI3J=YzK"0a5RGCW]90 % 5ֹa;Wc+ 0 TFxkK\+caFxtx?/iMjzf l› oͲ3@fh7Jj+Wg:ꨣjSU -0#*f&?iYguy#@E L3!M`aZ(^uRLze)@ Ȍ` [dr?By{ S& 3!M`g̢d-"FFUT73f bw_%@h`ULT;,̤IǁR@h`˜`&5ghŞnU7.^X!(*-UXl^;E R"̲=l6Иa֫M_=*vmw_y%+AK~]jD_W\G~ ĉj#Ѝ5l+.ʷf׿Jr6TXߐUb-ƥ",;Ţ*T•%t `¸pQ"+\7~ҫ-ޥjv%\%%T`H:_t/]v孷ފҶF%P/V:5 l6w7I* ϥWc9FO,l ‰"tWv@xo_|{ɼUtT"@p*J"6Mz! 3s?Uz+\z5jԨ7ߜ K/tzNE(_8]5*G+oFGm'@Xs?pm; nU7piļ"Jlܙ]9A7d% @8TVJ+g:Q(%[mkkC'@@'!_Ыntukm.PU c xAH(eV^ 3n<^R>j7z^d?iӦ]y啵[ ;E"'**}X uYnrh!5 < ${ [E7j8{Iګ[>P{.Jkgösԩ;fus=wܗM 9#2C@7 3FN7^eln%Hѫ'|uYM?QbE౅hFUFPBtuGi[ @Yx_U̮^uS40ƺj`C+A?)zŰ~m~ٵ_R<M#HV߰~ ]q- R 8Ə\E0\YYd`H>J+D>L]58R;†!wvTEzS'"WU*WJ}Ri$ `>J3h8`}l-|g3eS!&@*3q,zm),U}@n;_K;'S;??h+"GN%2 I'`!^AzպT ƨ*JCxy_E!xԨ_F8q"7)~vԩ+u EBtc.VU:T-25ҫ}m@AnSc[&wN:${tes %@0D7:mrzՊnU+L YU"l@AnPo+Ww߽jC_,Xu@X<G'ܒ!^ syWzՏ@z M+N7:UdT,X-` =SeKTݔevhO -ի;Z40W)APZWA1l1ҫJN?xhy8\s}x="&@47Nz/iGzTw+(cioIё TfqҫH?ojwǀK/_h&5g`#sh^ ČmN ;$ڨWmeݴҫzZ@?ϜM j |.YGCM[E8U] ҫ\8pӫyfQ?z?n: 34~7i$ըz Ј4% JҸ41 ] Mh^5k /KL[Auz ) K//~qȑFuᇿ UUr$@|4"MIҬ4nl@nX#Uh.ҫvZU]u9l<o=>313yJjRh2ZA+GE@ZW5wjX4HqSh^pfK*;pu";b- 1|wqrUDeh ƲVhjS"Um]**ҫ蔱ڢWm~GR0o喍7غBث4MFU_jBjPE^! ŽH Q?Hx 7z s98Gyd@ As(:4UKͪD%^U=M.* PٻG |I2-x-1b= &d[oRKOج4 MjįB'^UI-*P%t@zaI4Sݿ&o{=lq]pӦMkҦa!heWJ dU^`VIYv*VUzg<1cX'>￿y˺kx^>M@Ctcy&~W;l]z BUBzՊU/f2egkX'{|ԩ~; R%v9y Stۼ%W^0S:.ҫv5ןo~λBӃ%`Q/AdJ 4*y+K#I`T!"K 4군u{Wk23Xݿ@U?O>Zw ->o:J洛@PzU W8Ɠ^yBD` ja&^.٭ARwe 2m袋~#u]?dݠI.hĉfr-O|+rj6@h&LΓX` Y%* %*WUVQҫ_3/X]w_^OǏ0zۇf|:jԨxWyˌǗ_~}7`:[l{{)Ekѫ] J6$@eF4WxTzmuоڍ70z?siYfaa }c$#Ѷlz*9yg]r/ms1ۯ 0 ԬW)CI SF@zU3UéNݿp%O?u)*jw~jZɓ޿_yWCOKvEq!".Ub7/qgzҫДEHR-*\ݿ5VnSYIztyX/8Ox*r/zr 1e&cƌ9}k.z_|i9묳,n'Ffp>,&⋓f|X_ߓO>9mڴ^(SJ6d#"aj￟w6z衇V\qūW$&5WՆ ui+ yG䍮ZmPR.||x2 䥵VE"jҫV7" nժut}Y񬎿<{d;o&f =naرyRzWV{W^I{ӟw뭷~OzoxںO \wu}1c\zgWvr>SYCI@O=9׿u1bĽK*c.S *FD@xܷ P۩ge*̤կ~NR=[SOLEGAJͶh#/=KLӧ33>K-hN _ Q" KGЇ>o|cgk>#_!d>(F@OqSw]r%LE5|^z_x&bV=1f 9\=tL!"P3;oWZj)]wnO|OD-+;9D~m@l%"qk&53ϼ w^w4ed$& _RE!}Lg]aSlI,Kim馌Ix衇r @ {hc %?ꨣ)?|. Ņ?qc_L3NCEQ2tM^?ߎ;pvr$+_J\\G.egozD{D@ Oof&[o} _]b}?l##)(b) Uf_rwg0ar-X#<…?ډiSD@(sfzhCD#+Y}ر?7|s/_s5*, JnbUHW _W[*: V9C$ C劀p\e`E@<` ݯ*W`^zJ+hC=s(1kvGNH$c,dP@ V_r=ж@IgusZoWgv+W]u;e';P}?p@R.Sv#,p&ӧOϒd$& W(@!5e@ Y\<d4)" )^|ŝvu! q#/{キҹ ^+h]d!#)(*Uͨmx@?sN䦛nʒҐ,d|ꩧRJHUF]tQtf)b)|Ey3d" "/}8X>Q曳s#1Y,/PT4/QVwaDh{ h;;F N}IUZw,d2BlBETG,Ihc yWg!2#F}ٟx,iBFSHtE@D :f7:믿mtIeʌ(Vp`Fu"Ҷ@/.{ƍ2 <&.o9 '!Eb$&fj p`X h F;Vo:sLjHv b%(D 㶷]WB[6{vu)SD&;PR,Sյbҋ@+m;\s"_F|]vŤ}⋣Dd$Mp&aFסa 0r)ӟRd*e2YܺLs\~6)1=n 2( ty|Yfm.uw_S J֝wޙ/ =ˌ ppzEj !H@ݿ% \ύe:s2}2+@g}/z‡b~=vt~B2R2Pon2=R0G_E` 枭C a֨7xC?M/+;9T3DVgO&1\m'_[Zm|%mBP0 b."]*ƬǐxU~{Ԇr ^#;R:*K1"6\ް3ό2z=^ょHˠx7NsԨQNP7xc^>V[mE |]uUVCH-c0&11mGjJ>X4 |De|BQV&*S刀tٵK!_'e~`1)3cGIEMbȮhyw}'?I{gk D/Sȑ#o۱|e> 2XEy|ĵe*AׁF=!Sw+ ¯/6@E@H2QHyp~)`Q3I=P:$#C\ %ST^xu.f[9裟z) =4{H{7٣ "UM2:*yhc0)Z2+V5֨NPZ)!hq?e %gL&1TQ@\~s=7Z=^Q e~%SP7JEK9[C DX=.9Ho}E'>;# UZk-?q*Nr=U[0#,ll[Dފ2pQ#=uMzp;sٴ曣 niṡHv (wi'"˸(@k  ,h0J3e^rc E[o` cG<c|UD+}c7FiͭmfK[oG>c묳\؄zw^z!G( X 3zTJս{0Γ 6#pViQPVc }ه 'N8&7BL:\t2R <k%X%"yg7(?3.bvqF~yb g0# PE#ل<;?J쳰`ܓiB̯4SN-Ɓdl3q *eyGv\A{΁=یU(Yh EmƙrW" ;Όdc(ep "s;!" F[n9>K C K. _eRFb*!hެce<{pacǎLk<3y=:smԀH(ns=y˱d$ز)*#c% n,_q^ElvtA_arxCbQ(j~mN-bCX?4d40T`"%`[ 8CX6}M6لiryŽkr)[opL dzƎHL3B()T@aD*P--U/_,n.RCvF3IiT))uHDm0 E 1erveSU@ sC`xzNEA?};]p@Fz'ftꪌ-O}S1Kμ]/v]PLuvp; X(Rm$ٻh>_hÑa/ibŶh4 ނ&rB=xWPhTTPs-i+` (PK56pVmW&s<㜵^k\kι{m\zԻToYNX+ $xQ**WI_u:;VsqHb]lIcy7` HUE,g4.SO%e/c u~(Yk8h]?+h3zUH,Km<)gmBx-Ni%j~,1T`ZA$Qy2sgQGd6s%)͒ӫTZ -;@~V!*l*9y]oSIm4! J-Ҵ 8Ul]w}sԑګ^*Q?N:묺}z%t']zףJQ6Lm0Jn_^IPe}ycّV| ќ[5Z'%p@$;J0sժ!ſUMگ8O-`v9V<ߤ\8_l2%QBTtiu{@ԵWæ''pDI 7/Q:-mO!4J %^BG` | .鰋R.]'lNjT+#U 5)OzVN܍p靪Ɨ$O.9W!Rdb 1ٵ>?g oid~p t $G ][N5#w~w=Hdʡk|#H8,gq/zOzғF7pc\p!*'7Ssy}C24h"2@-Ge `L<`:toub)15jhL^&ML{ x\38AH9Nc:@+Q]us6 j ])*j2B*oɔFv.N#;g?94+pEx71IW_]sw9s_Kg'V FE˜QڒUT itQ4$)5M'R X$f2 z ſͦ|1o܋5C].LWtb6Gv:Vqń}j])!Z dgi&_QeCVѓuVvZ3/)ٵ÷2L2Hi>YJ~Px˜4 }-wSEҖR?HG(JQªTjYhN-LKT-tuo3H dPolU9 7Pe~sC훇+3EmO?=s'+D$! _†;D`bkzd[~z#d/dQַb>0gѴlk .΀_u,L{Ԟ@md|UW "N#;AĞ~zЃ%˚^M $د 9eA5eW1ti=P|q?R]ǭ(=\+$y5״{HjE{Vr,y\7д}6Ux%de,Bv\u*e 4P3Cӝځ-8 vW.B/l6 GRN8ez_DG x\r\BYz@G`[ PO~~vغ@ޑs9 /h.PR4޽dɣdGIvcߞ 8YHL{5c%E#`/[7MinqnML%~6G+0"rFyLFtVuJ3#Ys%e|FicmARUg5.S@gy .=؃p뜸 /26}r;R4$":ysH89(+K.y]FqJwѭf[O<ѥ|Uz ^I 3s|d ] I 9i~8 TJ]v̀ 3uw5hc\][\>6oͿy'hE@"7O y;9Y|HC1AT-i3&OxJ"`r& ye+lOJz@H7$C,u@ j(]@XwDו+C lwMZP{E6G{Ua5ÈaC~Sxͼ=AG#j8jX zM%iIDD3.2ڞ3,wj!2/UD@G`x zCQD+LJVx@p=q ItW]uU[#=%s^{.\KSl/+/wU9thfOh@2eI6:u9). ќTs@-( u@R.E$x0{|]#WlE|۴}nz׻aFƨ7(ƣH$XH m!+tRn43-g1헔vN9M-Ʊ.ڞ3-CLz)_8ZTt6^Q>~!r!w#5ٔۆɦU5MqWgj)?`sldʪ7FN9gu;PJLңHZSF+lU"%aC$R윋J#F)gɉK h^]( KpaGKwA香ZM@T"uax]x6x0 + $[oɈ4D~za;[@+Y|_m.VN/t[c׼5-V4sڞ@²+?c (fd($u p=#0*G9r$U"8RdXqMI}mYn}[]VuqwO}jL2/+ʓr}L;CPw_\I?y:@ &54AC`P)#A"@h` j]SrZ.58`T*]۫V5=\2CbttOŭ(8I&rȈ=Nc:Ed{jbOGIdV'n~у"1RFRKyt8:|3X?j&k%);A1TT.:oExq]䖈.FpWqaIHo[5WT;E'K0+=8J / ]X+ xY/+^*Rݺ`QSG!>3kI @0Fv1 5:(".[UH>]} G bٻi K\9N&*$L0D@Ԩ0U 2Ƹl%)jbJ~x.NH{acEn=XZ^-ʵ|P78L͏<%%0%);~]e3:}=_8a b6Ӊ33lb(8N<1hXxRmIY`:0#Y$@2eQv(J*frT&;M Ǐ.8 Ym׽,\¤5x& {.UxWpew@5 m=2>ȑe%HɲTEUE$!,SyHE)c,*w:@~rre|@o>3yxjђڰ_E=[]E~Ar ) 3io4p0&5~}SϹP^ɰm!(h\4<* (B@*\*R] 1HBؒW4VAIJ,lr|1Jgq:.mWEx6wfwo} _TB|VI"YdIRUK9!5dkL!UG#pT=>:+?˔Et:{+_ dtEw׿~Q_Йb'_!o ќ@~V0v p65~:E&9Fܮu(-)9昘RlJ]vob6=7(dw;4-H{Ȩ_.QWH&qom! BESE"Lmk~)8 j -bt .&];<*- K]C z^B{ *w: MUc]DO~IۤYfm9eMJhU/ЌHrD "PB.L0Cgf [Č23Yj2pƪ^3&^Eȸfmu3]Ԩ6qE-+%tf[z#PqeǛEBС*]۫Dѫ(?gWIU#ȹ}I8/UgR5 5d?v:@+v* 5gqhMq0HA,xbU&=,۳}FLM-9̖UWk70\D0@ 8G "z;,yܱ{]۫n}T;[&CԜ)s.u '0xǦkzjGYQ qTRU:H`khΠl-%>$]hť۳~b8GQo߯-:_r9Y,6bZ'%Y@`R]Cc)야e/0afƱp syƯayko}+B/KDᅒ{LF1_WGo<9;6Vo}I}[ و ќA{Aɀ"@ hq)10AZ/K[Pݪsu^cOq^jl+Q[_"3VNOt^M Om2>aCR3U7C)F e9眙,UG#ip~jӗ {eOz|)co< (=QjuAEf)`|*@`ae2>^zLB"8ꪫ$CoJv%WL?"o:O>nzZEX4P3#]!hWE7Z+V S7[u.N_mſ%Ns%.Q+)34 QV.pw7] Tlƿf l "QEEĒ瘮VQQҍE0̠RH.ZW93j*,P6o X>`J?JDA%EON_veiiZO8-EqLE:q:ꨣڛD~djJ*u/}ٻ ڎ \" 0GPܝ%OtV{|?ukѺ[^]#z+NsV6Nss#:[,qCo2%:ܗҧ4ɻ(M)CRF&hkZ;MF #gfeog)eGIn=\ɮE!U6l2o 0zBQw w6F͓ >uI5o|6^2KLנv`=|8XVy?/x-<@@ t#0AZe!YyKL.q!?KLw&#ſ1&;!ƈDd: !ı~;vV i7JJdQ Ҵ2,'t%e?''v(0-K.ƾ=sb۟V Qm]K,_}.2~A'EhQ@S`$=r!@(up.|'?5f E?k#<λk}3k!gB/ J{8DLLz ^ vQ8ݧuLPrX~7@6۪2\;`@@m.t=ck8nw"wNos$E[$5@=)Q tx{[=#0AU`.5u.+]ZVb Ӄ=0!{_.;gľ$EnZ_|Ozg>%K$1ӷXBEs\&E{|G#GmrVnNmfl>4R=>y8y'S낶;WN<] `~ZսA?Gs̱RT ,!J Z8kb'FR綥~vru@@.U|ݡ tK!R鸒 uhXGnO+vk Wv7!2yo,Lyk=3@;YcdɖBjipUhpˢr,#˰.;=@~Qz+_~uTSy;=k3\3{ =gmeݷdQluAAQ -rGtD[dzx"n8OW-٧?~m~5+rzxo#pf 8ݧ+F֟;6 Xcԑ/ك6V~VGvQo(8pirO8crv됗G?Z</}KK%Q[o-YZiNG=Uc5yz@G`cgN^z;mQُ;蠃ڭw~%|ckY==y1N>/4GBꂮTc5Y'9.A` vEMGdV࠯CRwkF%fǀM5m6:2X0{(,P7Gn]#tG̶]_t:z$Imֵ(pv^.>}ы^dH~Ke|\mfU LĶ%u%'آZ*RJuM>jBR)F'Ȏ@G` ~Qi6>ƲX>}~:3c 4XgBalG+$cqibjΌ 8pHQhFH1:U;%5],pz`!c<drچ}_\`)5^u S2U%0Dn>ŏI `,%֕vo[w-׾fIy>7BҺE[>cwӝg^r7?{O~_w*m2H $X'HNAMBJ35V5|?v:{0rǃ WY[n6$ c?0`#<Kbeg|{Vkִ3, \qfB&L6M5\20R {ѪPHuP[<{x[ `37E>Bw%8e[^["I (ꪫBzxu5Y:.YۡѺ D m#4v)*h; U*[QQ13,8<o.x]TW$,HuhV4m|UqKBD~%S%8A'uu*7Ez\Ed+ Q懲蚻Nʜ<{^j`c{HE6s;K-C.Q1+qKnk# JZvߢ/107E\ UC UdûgSf}!ſT BereeaLS9e_I8e"ƉEz4$'hcT]p~i%FӬՌ#;u!PBE~;2 c-VkTڞmN H>-3Ԃcyyςو;L{G<в @V"Npݑ>ຘ'8`qoN1vPe \`ַ^gv䄟[Ү^H2ݧWzS?& &a2b!$SaĒ$ɺ:[ oxrJEMk_z`J%k[/ uS "p|x!J qt6@(jZ 3WSGgoNjvڳ-Vo~ߢ>@Ѡ6N9dpXBE7 uO3g5iBQm.`a+7M.򗿼D5l/W^# [vU؃U\(1+k"tV_+Z],6Z6T1v `0lV$]eE:47">?5jmUO"3XsTj&GB7-z#1J~D/C ((r)j߮qyeBmxzqK,h N= {UxڛGrj־(L.,% BNiK` Ko9?яbVNl]ysu~饗 [*-Jdܵ'@g աƕ5N_̀%zb!00[}*e}w{a?\c@lTnd;/"~[kS;r2fM~4 18d"PfF `ht:K"PXSBP8jD%%i{ѯ= kZg4Ey ,Ϲe"?a-$A8wݣ."nY[p?=OnZ곎YM'=I{h~r'%J–ׅ.d=ԭO@ >,1GLkSa- R2kJENſݿdwfsieTg" HrJny(|_I\ㆋV7jgPgM$L@%(aRSH䰝q/.d֫qe}ǼW~o~ 1@7 l`u:cث+8l&(Q/"zzoar۲P~ "\qc/&{kO$v:.]o?:Wh:]׫ dCdT!_Ԯfr^a?Lr;.mN{c;O|zֳB Wї0JCZkgm@q_V6HX Ͷb _6 ; F˳lv.UȨJ3_PygJƆd`:.rhp xܝY1A^Ql+\C4GLN;tZJT/.ɑAW?pmz=!5"2)9|)/]Ӌ׫ Z N]խ],Lz` XQXoۙD;,Mk<.6.l+jKtභ,8lSV.rߪ[Q[ϴE`1jw01 9L!veoſ*ߊ*oy['4R7.0xի^%# 6#mw١XLS&(D"P-RXui0@!w# PB#v(]wF /U|9Id|&yio׾JwfaǻM&:1[unzYw,T1U0Y:UhRgDLDbξDfvi,{" e>{'|iHf̹y<7y'De DR]/:kh [pմj&kG H8Ttq업¾K`ߜ滠0hE`|Y;1Iٓ;l17ѽB$WF@WPݪsu9e]6 {` {y-Z ɂE1j7]ۖn#.ҀI.g\rɠm,ws 7-gcT;dVXFM3LMp@,W;d"LlCow]m.sҺφ:\p~s)S1P?+F65hYj@l2pI]PP+ mkFRv pOC/g>o}ʋ }UW GAIg<cgϟX-Sz +ztNϖTLUT}%Y\XCb,1*vdܧ-|&~s_nbK@U8SB'GQהlv$ xEbj@HJx8ct@~J~'H҈Z.Ae|{*6l+-Yg5//yoШcAKQ~>)K;A[_ :"隙$KGw pЕq 1 ۲5Ƅ!=qMJ?ݝG 09g4f %Ģ)bm nſp Sb&_|ꖅ8w;{^1y̘2 L{3Y;qʙmʷ8*+gBLLO H7 NEK{Hct*VgIm }W%}DgO 㐉# ǃ~ӟr4:x]'~1X,=f" ] %05b1+XCpa0' S>pq=& >/H].<:Ȏ̸~=P)ٿM'< n\rugɌ,*q֋iH 1~C"c6e(e;Z88c[( GݔǵZkIok&Е!lg܉.'vjw{,4/ VAa` Lj!ePg1my+Kcz>3븏Eoۇ<(-V$ٿ6 x$D09dRC`l2c_|q&`aoBi`5*1ƓHl9T|cc<(|g?vo/',nH׾&&˥(2ZOBZVl6Hl e8x5(eYQ١AL+X"5B L$E'Id}Jq7 nҎN{!$3v4bf=wqn}['Wwa{ض8ǒ56KaW< p'8벱Qwҧb.=1|׬By܏`O|«?iWk3;oX}{Acйz\Gn0ClFA ejTO^L1䮒n<9/fn;E ~񫀀͏܀>i PW`#M9QO~2HG#0Ӯ} *3wӨN AWkr&D2krǨ@G`AF_ڼ|K_*+LŹG㱶'&Z:G~kxyEr.i `F` pxݡSAz_1],Lz`]8'1k'G>>6q , Z_znl怑#~ ^ h6ҿz`?n_tn]wG)j a,ct!ebTiKN9Xc#ǀ^=8Ơ.kU&K~䘴Ri| D {|eіL8 GٳWfQPjjQ0￿B@Q(@Ԣ d[`&H2S+0Ն,0I2Lm))ō,3  p@]E)``6ӵ7/iTRkRZKC1C[Xzxl`%>/| WQ%~S~(QLr=؛ &׫ؑHͯx 3 A4SS06 2` sbLb ^b ?;1; 㼨K{L~VqWPD|rX+Mfp7 Z׵O}*[{ˇeTB\ WEjN\T8_5So4YV! *l過@-Dz&~Ԁ\|^K+-]b n ~qz~ |w=CA!>ue"S€b.3\{WTV^lY֧gqysˁGnaQgq`$H:09ˎR g(v8N '6RUc*%[ `xcc̜1.mewP|GcV{$7)s6>Ac=6Aݨikdu=.a2FF(*VUd w{M {+ eǎB~6e2=:O3s J{)zKcݷZjMk`i6G]!o=BK] yKcpz;"Ƅq|`,Y]$O~˛:F/?A<~"k%d=r#ś W8%&IG,T X Ɉٰ\N1$ f΂9~v-s>fSwzz^.seJ+NΊa:4k˾KO| qcdWb:S`?4=LH A cG` PKE~%|܇-ooM`M#1H=99 l 5?۟e:NU|u$a]ħG|;a?wj9x%΍Fc˗%m8/HG.??/nnCLvEoutu:%MIt. `3x7u m~x0o"ỏxeɚ&9s[ Ynj% 㥐\Z! /ϥK "FUs4VG8@f ?vv<`䦧~M|຤}{l mOYL%E]tQvmP0 z39Öa:x\qx_EP;NuJ֭ao` =0H8:sG4F4<&O>hfTL?4> tGfT}t:ѭOіb.k&g MhNZQ}sׄ $00 /گ)^\]v(f=A@wWcl ` &oip,.K1?uløſU;qQzv}րV;H87tIykGM/\EŬt6x+5 U\ U%M+ M d|2vKRғuVZGkEƈOiSN9|xOѭ0$tYlf{5aV, V'm1<1"_Ҝ'O2.:~yЃ?4yfP4?u۝@tap&G@lyFl~>c5u;nb{o 俺 Bw.G/"1o z[Ifiʑ%({w(Xϗ/, Ҧb3U@~C^@U\|F%ݖ'2~[ 6jhor7pj;m.k֭/e_͕=ɱz!g:޶Yo+w4>묳ib{S̡n/,QnYr({e6TգeH7 թr-(MCI|_NXƢ2%fŗlG~6Gp{܏>g.)ۭ>'=uxd 0i6La\}u)рH7UD]EGgA1@): (%]7Ra -h?f%´,i.lb6KFkOb@Lbl9!Fekh hl@nQ[ſB~z[׼5̢-Z1)UTʥjeG8HQsLW)JbY&eEUd*@Ԝ,Դ4Ycg01$^I ~ mNBT:M{m 5?wQ52nŒaQyYHdƻ^:1[)& Wԡ5]uNAK|I5k#aV\R9W"|+) F $1RQK.'`[6lO|m-2+LS9ha~]1? ZQL(ſ/|9#O6c\*g~30;}`~wR9u$n~9<$&Y]EU ڀrLnh j5V5Sscm+0 q)ı??HO}SĹXQn4(74p-Ճz gNѮ<1~i  z!sE'u83,Be.W!R2}cu{b[֗U$a?b4giBU)b}4CCRx .XŪ.J/K5Y Kp tchc {LG%QC-2vXhfpCOO~>e^2HÉ6_i!Ȏx:H2tStN dK ް,X(]^lNGxshF1'7\DW^y!v\d&L ~AxTgPZ34>rxc-sQk fcmp0(r I[JRq31sƊn 'R^ɏHxff0o%_ogy[ʾ2"Z^dRiljAE oߛ?& EC ^L55#yZ2h{eDg.\b{`?:Nt\ҕ:TN Րlab.8;2v58=fĒd/|VՎDڼ5ʗDZ? 6@\b &iqk0xLFbS`af)1vr64 )2d 1]dO66'pFm6ꎤwWŇ?cs;N~&(aUx{9S Su>?YfضKT*'Qq 8mpG`;"Pt5šPX~Js|uqm__ʖ6l۵:EGt_q_cl4e 󖨁kIWNز`#1WLMRQT8lHd|n|oT9.R9HqX](h JȄڣb!a' &0jNn{{r1׉2LcJ:,v3#o̊{]3DM1:]J=67aᖑJz\f~/WHmq,#P)cM$- ڼi8hrs+*#%h@G`"P Ґ|77H1`>H$=B7_-&7qr!Kj8I7t_}~::y3`E0K%Sm,`a3[͗/cvd{ )L`e|0*&) cXPcJ00Lk8OmL [O >vp%CI>txOG 1Qą~8|'Ed;QE <eID/=8~J`b0 rihNե8US[S9;Zd?MȚ>q{k8BB'te_2}qrN,juNc `+Pl%mvv^ ʖ>4c0Hsa=-fb^>(E?Ö :4="xs>0F0U b`<1al6b3K†ĆLDڰZ|QɛſMzي=yƗE{y rXTZn{f0ĸ['<DR}Yꪫ,lXO [ ^I|i1gyD0o5J4. k g6u|606ǃKny=XjQ>y{N#Y)0uOZ;*I uef؋Rb 4 Iek]Z"P#HIiEFw䌦neB ;3?ЪGuL:ģ 68x@$Rsԩ@Mixʑ ;Ppz[j-o* {`!PGk\Yd?pbh"zF@# =q1*0/{ԤyUHB&$Eo !3!^qZ 4 +uod. l~پ"cg*uv:_ʓXd}87J!e3W8ɬt_V?:տ-K{`#a-G1^[$Eg LvX/.磹HZzUϼ3d7s&u{<&`mb\@G"9LyӞm`f1x9E?>bl]M \mL5ۆA+.MvD2cRV:<-Cbw-i$&{9p1p–U8MHIYԄV5EW_L @qȄ`//⨧={Ѓ= zι9m, %qtd0A^l3a$6'a1`@u p*?R>^Ü$8p=6o}[ܘLJhVBf=>#* _QUfxrQDY a$\ &eKtRq ,aD2e_ab~%X@Vnߡ04'rg{vLjCr#kJVU&%I\%cXdH$UdW Gթ>$F4q6K @6p=W#;_6^ГP}'z7ߎە%xhj**zF@7utbI̐{;1ʶcrXL%1+s秗s3E [rd_E)$ΧUkb%ކuB/B*rz۝ƈJ a`j{~߾J)xs87@$0XFa8N1]Zo=WMpDvvi*w~6?n.equ\g٦ H.~/%# kDZ@[dX 2YT*T7A2Yz'-eH\]i3.Qෑ=XAeyL|ҁG\w\uǻ6"7zƈ_r1vN:laLn:g%H )X+JVb9~mC']H.zֳ~x9KK/nw8 :*<`w 'VZqg>}x[yC7v(0{#"Ä  Fʖe3a0ySRl616ηǘ]Q2}[fߠc>Q#ߕ}c=Hqg|0>4H?~Hb,xd_$e`a{/PHY-ja[w2<)-+c_WkG-Z &dZ6' a'‚rgs54N^LPl 0YRN^0+uſ[,ey?IALz:.0'sUlrV@h=Oo 0$V_QpUh~0D"[MlꌛK s+E`E 1U@K ]iդ-22mEݽ/_Q3˶^tV6t_1ֿ3F "%!X+b6,ߍssv>w^z衺hMyq?MWV|p [BooV|O|gAp>A Ia0Sb'5HÐYRbc ZCX=;\r:9!7L*2P27''as(b /(f ],s; `ɮ2lSWHe9[ V448LՒI,KJPTԵ͔P/̻d~PZ"X#Es;[s f?WG䣛1n|a%Mnp蛧unKG근u! WF=970uS b,X1ucvT"+=ya`h%T|tOQcI9!s8 GT71X]fSxPZ$mB DZr5-'9sĀQ1|dB@^>v/ Co$[͕:SN9[r;qevԊN-nd?q{a.^w`ͭ\7zEuJQv(ʒ", o&zA(GQ= UXG T){LG`3(O!Gptx:ɹMw/^ͫ~d%7f 'Ti=-eRZ3MUdئMJ4̆_`r2D2` ݖ__Y%9W|330 p߫:jn[,oʹqsF#Ѵ+˗ %VɔyF֪/hDG+'a!bc%2q6 Q;po1N1]L'S;DUXCnDcpjYҜ~YZݏ$HӵGqDPb=?syi[$%JۺUu*]< QFe&l4), &*@r& P_oM:QǴْw/_Tx"]믿"{`[ vJBCvbtdIi J0a`K1a.pG֜x,bNWwa|L}qyfr^Wa +lU JV*9QLdB*>0^X`0X7@XC{EXWxp0(\dL4.`\f;Yވ@u2#/&WgBJiU|zf,A/y\\<VU1ܞɍ 8GŊoWQx%%ޡ\F@KdXCb0icJ , Tɢ0WOdt"\=#(ϒkFG=QhڞE 5{g.tUi*>oN.݋N`t<"ĖbT],V!w|.O ո[ֺ2>ӓr u]*r}D('KT۞`EX(hdZp3 e{pGE@֫k,mS"6ſ?7:PY!"Ws.#c:1e /ãh#+5#D:.'>= yEz0-DXu!|k%fJ\X@m diu'hpG`o#~ª]g_e$ $1I0KZoA܍yi dӉuq&b"Odꉅ0Ҹ9 e!1-v-1t[s%oa&3ddz]JSkJSG4E$nj,W`B9XTrbYZEϳv(&7)Y16וko'Fxab/| Șhܸ6Wn̗V5 댭{ߋ3roY]-Ct܇@I kN*S4 IHFŐW3QZ p@(p$FĝQ2ꔱ`9OR؃~ bs=) g!kR7Q\;k=*_U9=jnۤu{>`cEJدuY-5Y5v$=a~J_q軟9~k^SYbZ\7hS?>Rm땽:nB0U;lVRndؕXbRLu0YRQГ0\2L{U,(-~Z&a? 0i]q<`poϠd.wC.rge>$jS0dE$EFuPS$mmX4P[#\r{?@E~t1mim8[G!.#Qˍ[P.0pA+/iW2̲4d X>t̬G_y2( 1Nyc*ij'":JpWK*16owDۄ0Ę %೧92')B>|XzƜUd,\Q0/yvo18QI_,=>-ٶEx+ 㤡vUD|rc1gh__WAG)A2r% dQBKF(JvMW!o^|$r`m$@Y h;tf=Nc:{v]aq4nV# gA/6M P\ bڍq]=feq/0տ[X:7~_^,t#'MGT[*j֖XpmU /;k6O9c-f,kE _BiN;4Er6c-KgYI/1@.H Sa- , b F(9w{!{H7d&zj7 Uwo zvnGoFn؇lŒq2L|^׻·lZ g0m|΂Ї1}ȌDG> GJ_a"I$>L1$ĜX4`Z2s[7??[Hc "ƫ;W">mJ_6=E1w~-}X*Q6L*$:s UEt<^C0 a9c8( Q3 fh7Lr`h̏,o.cP^}^wp7K2izlG`O#.u]? >Vɳ _^Ye{T|<8*Y;j_{`!]͂oZ>`ˠo LԌKbTu106@xncoܘjwɭ(wR[^6W ?O=y,@a} =#<]lnbhc<@LK$Ȗ8M1XrcU6`".mvGP/ח2_V)%Qs.UINwK r*[ t, ܲUYfa6c=)5/@*<ߛTjȨ"{F![(8BrkI]>d딸M3=#1Z$1`ڪDyklR15p2 #kP_*YꊁDZ=Jh+ӭfTi{n`_[;mcvƘKH1z\;/>9dorS@M&%]!P|;W:Ty;mPEʴ06lϰV,C5〭3АS h[Gd[y'akwjkflky^~\ib';#/\ac= Αwq;ܡ3s>Gj߳UHuQAR!^!~-ip@2V3]F"M:HgU JQ^pm lUٟY3vRYP[R2(2 3=-o2ݪrjb/,I70OXq̟6va*,~|fOS^j&1w.;0ԃhɼ?| ',Jv衇J,z*LUE{|G`IbdV\TT`T,(xAX8W2'QJqf[ 7+EW- IB"j7"HQng[¾)s}eG֓ dEcdNsetVi;Φ}V BTXEh$%A1 Ii_ iQE$;k9{LG`]g! Z-Z]B"K|)+\_lD=LYg;ff/큕E@P]YzM[j1 KRx&8HGafݴ.Nµ99kwu_:k$8%H 6m"RG6~vG#Z,çWXqQb(fؓ Lk=2TvVyâSZ63ͬx߬+5*9hfu=7%}YSG w73<|'FW\"6@ :"وCNl#!1XD=i0@ŝ:"tbsU(AJ$Nò<>њ0!L YOhiH(൉d@>Xpݔ5Bz# d(Ņ-ֳHB8qQF|vYPNǗJ:K{Yl@th0&$ΌɓQ 1G=;0ǃm/xs1m뮻.7=Ə"wʜԑqZKP~ݲẔa[iwA x- ْ Ð{){-ɱz[ MپaU 4^Z`⓰j$ z<؊"qIo8͌z'&* q3 c6o|zi;E m'%׽U>ęId&Q4Zi*_ |ʻg?iX\~Êr\ ccoX]6" qArBE,[ſ̀ VB[ib _;~m#;J{AYdB}{EV9ip&kgS "99p179[@G@I0$=ƣP7c7&l0UP[c1~4]Sp\HY5CukwҠKx=*-u4Ä &#DŽApi 'o\:2[$=T٭^WDX+soo|e6S ^TZ1Z#0@\b$~"Ės1۩%aoL. !` nP N>vi!àL ]ی^xSZm.?m[t;jG[?&Qp&rsG mE;)wi;@%oĊ7@7n;dbpU'N%(ٯNp2~mƇ/ Y8mo~v/ciL,ҭzv^omZ@dѴ= j1T_@7rd9+6k:s;T,bJDk/xALz"<w,ILOX/[.VĐRXcVgq{$CLzmDvow1;.RӢA76[bS]M34?2^oޖVm`q'w^.&4@]t"e I|KoJs1Q< 5Ko>Wcv,h8 ھnœ9 {Sm /.V\7 w p^}t}nr [V2cP U`Z~I._rNNR{ Qի,=#DV9~Y b쀴a7/(V 7YtSr+|1 =voC}+6Ոؠ9Ux_6?s?'`}!Fó .݉IYzdb=ӕo{dG`l cyoXδ-ئ?C#cħ }iR]ve݃1N9i ialp0,2+60Vgw pb{j&ze.Q?S^}ſ e;h `N.n/N:$?3l" .:ڻ[5A` RIWɢlep4?%,ecij/Ys řϘO>o;fۿ΂L_ؽ~_ (/:7?~_r01G0̢c3`1a,W<N<^C}Yu p{<>kna¯p 8irOC$J&=gج5!N'>7&ӴU, 6~]ۋm{߽rEV`C4]Y){챭ZnE_TV'PʰiVuvuBth} ލ!Ps蟔5wC,-})3;Il=f3>,KdH多tem@y엎ٻӠ풲>JUʤ0$CRdemP,hl 8a`d * ;";(&9`شp:5V1c%V繟}羟?}t_}-7Jbӯ9(븁 VTlɁV9xֳq6y󞷪0{er̒Kl"ҊݩS2"#3x Ҳ2p6Jf:/:*MU ;y9&*02 hjt-0_ p Y'V_bD"r!Z-1+d TbuG c@b`LЪ<X乼*w/] 蝵ҁh=!Ig,/IQr*3MVF`^P96VɔI;o 8W&`R;"ΉK~f1}W >Y<`+HS`ehk558.Cf/`Ux^%+y3w@z>u`(>B!Zmy )`M#nQ/3bUPqҢsgկV2/ٞăZ[z??V\,Eֺ`\D^&SXv%UcrlNG O8!F+3QC^Fpdϲ#k0h 6xkOoe|3g{`7I{z|iDˀÏZg QmˏS ad'aA}i8f9,K.]3v򪫮B|XL]1>%\veob[dђV;҃{eSo^@]5 .iD0L m IVU7rlWTEy[SxdgB9ϧ(IA}NN<я(,UQ\ u$-_.F> j4űx|:ʌKDӭ-үu2%rTg5o߲ #S abw}iG1? L+yy<fd&v$:sqKhVNf;|&"DL&n|9KƑy(/hl^SDP4INՊ&We+wV'ˣ8f\v2m!:s8K[8gA۷8KKI `u Nq`P$ǗLX 5v -ѐ7?i':uO}Sj3u%ߔStIOzR-| AE0KD@t h N^h{|H -zH;PrcwL ({s6/})ء:Ӗgf7nw;쳃(]wz?:]D! 2jH*H-숏90faD8LV̍_}88|E>Y&}{_N9Y(Arb7iځ: j}9iO2{AHpWiH\ pZ%oWy|i+viDV%芍P :l0M#d~oۻfPf!m~S*f9Ē_rTo2rPQ z^~.؀(O>D|f t4M2_Lӧevԕ?cw`L!l2;:4B$.+%L^җ:8WY(c dT&7Inu6mAB$)wH蟈.A9-wYbooqfGvyWW,&U{C|DleJ^OLL,YYPkI>0 b+P?uGt>[,pjZ+:XsG$ew/fkN)lQ<8}, ʻ]ʜ&] Zӻ 9 @ V4eMu HqTOYx\pF %Rx8ݵ3#)͍v[ _L'?lH 8-(A#XZ Q *t SFLL+ݮۿE@aV~ttD&)~-3B*G'ځEH##^1Kyþ#Q`Q0-l00@IDAT֟|;vpdcH[:6^ziU|5?NGZ$]VSG'ÍU"`9A"Gk.,%o)U$Ian rtTg#>%Z`fͺY_jYЧ Ur33[Fk\ ‚8} `_Xk@.\ٯ,  u<M[-E/S? Ġ ȁ7@eYcy(ʯ3vY-|RPUܬXcw0{+_>x9/x ^PMS/C Z%v]~yc3Z ufnNs4ʏ EFf_-ÔR2þְs]lV9ж9[O4G>-P1=lGj"??JkЂxJYF$L|暴YZ 6y' @bvh HT61B㼇{XiBJ&ierӭdUr$Fěet&\8hؓ搤fdL>?s@]Nivk'گFr"P҄ ˱;|ߌ6fo>Vߪ/oI&Cە뮻(.sL;:TtL# l-đ#&* q0v Xتrt]r[).F3=yANg]ܽw5wWx|@QlZ g,Qf)~Ǒc`JXBPq7Kr@ &QUnH-6n,VWֻ1߸ t]rD&*+0<FP|@d$p7zf./> ԹkD_OP8`,1f/nN<gmGoxK&ޛNwSdBu9qCV,Yr֗/tw>E1"j ՒOVf}pDD Hleh2Z.wvˣ&+w/" R \BhǗ*[{7 AAV9Acz N>(` c:̄2>`,ngZ>9n-@:؞Ijɞ=PRzU Ux}pzׯ*y[BbvPP"uMcšBUO@r ` i9=6b@WdcLU%g/9۶ɑ X$T#ڜ ʿ袋*m:2C~GV??-/|a[(AD,sth6"򔏭jVmsD7YSo@9yNKeEw.w{jӕ]rk(puv/aA>%эxȳ)y\[W,ayk1qm0-;{KƝZ/_CР8Im1/n9 c ȾS+/H  uEph^Q1Tt~U'M4c**y8'|d msڗ 73 *I ;YoT+{XrL&%i G3'Ȃ8(PsFIB^D^E(G)e}YuDVFz (.={ VI&:n`3^f{ ЧǗX& z-},5OEδ%` Avz ~>_ >`hV%"X LܽDU$Nñ숳K_7/ijA{[:-^h{I_ŤVO뎜AG88% Aw ӻIlJJ_՜s, *V;L=IVE}CPL;2/`סVZr;YŎx"W%'~\tQLԊy\a\ma%N5d G ?E窽_F,w/CS 8s^C._/Ql'~'VPv`lMv,D ,M`G-}cZ.N[Ř`(PjC5EL+,EEpx]x|$\[u QX0g,ܽTic89 roZ7F:+=刡T4k)|,U-uGΠ2#pӁ<]ԍVW4q/uѕȕњ )M]9{kt 㓿G'?z׻&/9A>Jiۂ]`JK¥)bE__JKD@1(8DaYZpdAؤ0.Db ʻ5<\wvxr2KY0[sSN_x(m-qOt1`Ftjΐj U_6 ]肻.ٵs/cYϳ:Bw '{@1GwܪiWU8q: d@* G[G)wދՇ{nh~B$HΎ=}K_2ބf]A( 1Нv7 _|4٦Tf,Ĩ8NK)"\ krfa\vbtJ aLR`Y70 ^fiU,0K y//uw$ya:KKyKW7n`vt2T29IZ>:7WDENE>%~l^W*6'~ӟ>яxhGKpq4ezix~%M35rlhdgL[89㓿}~vwVvSFbIۖĐi{7g6*;~l'1Vl"Q%_,BYw1k&̒lC[S) i#g(p yY>`z|*fHw% 8Ps-D٩vUM>`b:H'bK[S70k{fNoy _>?}w}_y߯O2'+ JĠ @&,Y*t+O~RN̡Mibsufv8㓿D3?3]e{lѐy2Q=qUM>QFxv؏ T0e'G~<.L>"  KȮrhԝ&v`[)2'9p4 ͢.([70eP&vVS/]-h䤺T:{; ~uk$o1zj..P:}Q>`@qG/]\aW^f[KN؅lF޺U~wWϑHK ď 'sMozS[~N&E,]n zl:L"L_mS9=>N¤Z]wumeӜ!-p FRR@UdWLSqpg-{gVԧbG-m&d"u[ b- kjNjabV*NXyƅms1?(}W.0yz|&Q*SQX-K <$Ŧ U(rMukD$b];ioz(v>, Yb"v`*|RH| d}XPa{ eAMͤ3MLL'w*+)S< (HF=Mڶ9iGRir袋.u{ i@S1+KG2AqDUtI~?bJ[˲DYbQZЮCU1GR/}i U-XUYiSzռz+^)+xuklܖo6lX?YfӗJ ݭ5/sS,֬ ISxU?Kǔh"㯐ۗW򕸸_zŭ'9ie3ہ9(p(~ҥY ȹkDĩ8 u֧'R Ĉ%䚥@$7X؁)my,/LP\,ht0 Di#Hqi:-xhaS~9(lQ ,X.M|贑sP`+i̝ ǹE=w41k2Z SdwD)#0ZUe$N&ZznD @+*g^ށzD( `?|\ETMJxߚ(>1TrC׉=peŵYjA|@T_h$)/QrTmq駫<_!gL/R DeA ,d%aRlp$D *S%GCE"{=toPzJ6\Mmk G2}L[9A+Fc}7.L`+V ` d.DkN=t`ӫ/Q=K|jh6e!biOu0'@eq&AIJDե"Jq늫._VJџO>k( -@Tq ټ9&(Nck,'V /0vc:k$0DL#,a\JfFsҺأGK]txB-ZS~qk)-.P(X"@j8;[w/+.8  4lΏ4ڥt9ņ~DD4? W#zֳnct@< \<K }25LD1S}Uoe֡8!ĂĐO)Ȼog2oU;wMKXAg<eCհ-ytnIkD%"sX2OaxYXI0-(xBg[tdد6`g:TX2!0'C9SSVɾQL9N9 ˭.nh *njbu%]F/eW}6&B2ZM\?q SumqRxcPj}k!GrđfY}#Q F+uozӛBE,%TGzPSA/Q@u :s饗J3H[Jw22S@F&>ql%f^¾L~Ǹv$rb>T<1>6KyJ3RCa?Oy[2[e3 Cx{'/h": qL\=0 %@%'\sY).PD?!ķÚ/.0z&1~K1T<"E:#e86:[5`DF * EQA{lM?Vh!L5YLU^I٣kkAy. (i0g?ZV"FL~~/ME8U ,/@t)Ѽ@:^{dfL#5YNpc1RxU"'?1`׽l4QU`!Τ܁Unۃ`mrzcX_xmɣ6P)j9GI©]Ս)pWD%1b7x 8CKP yq '{S GE:bm/,,獬իLiYǀuw$@F魂I,.U~Eh2W%^Oj$<=F`9]ShW96"/|h$1MX̔2T8¬2&T*Ц` @^ݫXL*ۙkd.wɧ} Lw+}nw~]$gqUb77Qhe^{m I[ #)j9@ʑ@̈Ζ/tJr= `($ BVMqbؽ2}̔ 42[|aL`6XWAtvg^_FH2lfULvVO4d}70{玜 8n~b9q.o:iVk\  5^Td` ̛+]!.%'gx} :1-29iYBw+^uUU@ou[o-={m蹶 q;HA"UcGFĔ:d)B]z C)1ITܭ#}j)ۅf6`j4Q[ˇtj?*kVS<#JiVK'|_{D_84|L,.b{d 6m4W!}sXxܤ-S@mW|>@a[Lחՙ[% le1 >w+v}ϜS'Ȏt_~TʼAWFj@x g#dRѣ)M~ZerV>`5vSR ;(﷪#)ݘ.Q_ugtǗ)AfUpnu S&s$nOƶHCD}.0``? 6Ŕ|Lj&H(wmˌ('X@?]kQu)a;9L`Rd%iT MO;s3K)i%>PkOKKW+X)%b֠OlWeNc?9Щ! ѐ.;U Q ֡R[f?i`wGhl'`i2,:gݽβ˴Y0-:^4=@~w~Dkˏ6Q9|vW4~uҎw<\[Mc?9ۦwt4lR o}[-K&U/~A:Ʀ-6҃G\cU: 5n~MB*ۿ%9#ly jshtAQ\DRj->e D8\FI>PUHl"V-@ #-70%, w\eHsҖ/0dzm@^G95xGӗvȭU_I *~ޮ*nJjuGz!b^BS0㻾뻊J&ڻ2_׾uBXA]Q ` |m5 | ~&'Uَ5DQ-ߛ_WDfCO'?IFf$G0Ds,gP];NKa֐re$ mj$pg/5(ӱ>ﺧ`vt)ZG6B,=71svUaEf˴õlM2銢8L*#g;(~uT'K[>[Ęh˴LNUG~(]'t%<dկ~u|>Աc=-E/zQ=hU?ȲLm݁*fϓقx^` m"݁BhG *f1xDGApZu)-FKyG#@m82fQztYwӡL^V_җ Hl0ׯ{e`:}iG B%T֞%t)-q` ]5/9M5[LXDɍhNBJIpYgA^<˸ŧPܥߚB=sTX9hIr i:' ?q ejC^l|_?v+::<='=)6y6B;nEw9tu駟>mlٍ44x;d![k #mjU:EU0@X*F4N@%V5>7$eME ַ5lDΑƎU@|ߎ8P[rFb(~ &Z2U| `0 ?"\t]qy"((~(޼/._AUzs":?R^Q?KYZKySc& ,?'^l&̲LYU<mo{[m gkEG.|(ZwU&lYbَD[낸Z' :^`FC=,AE< n `:ej3yX^SuZnsөӗ*#aj%Fz(U3즀aaN NA0u{c Ih^83Nj=ϐh~OL-gm=|T(p"p- r{kPe[Nxa&pp,Z.yc 3do͙iy9Aٻ]&'1r؞=n^p-ǕW^Iz1wlA:3Xc%Aq(F!ڎCg O c&b%b+F'Jg5/2@ZEiA` | ހm󴂣3E-[\uU äbK؉NBqk)Pl-Fc}ފêA8h*6]^yZl*2SD+#eCG*#|^WEt}{~n#岭$}?=uEQm+Ђ.>01`}&I)nPmFCg>ZSu㓓X̳4-nzq5UW|vSbZ֔s"s6/\_tx-ͪ67?44,_ bȋh 62ha.wUK JZHbzֳ\F!q!X¦  א%EFuFѻÔ&*!P !'ƊFg)%\Wx\n"& zvǗr;VT 5ҐtU(t^o6xvFP q>:=a9P]"nl)"5=Z^LQG,\>ɵPx:AM*x+G"}deB>"=A Ihom`\V&6O;-/M5kv'<=S-2>2Tm3#GN~vzַDq5Ȝ%:܈.*6J(ulF#ښ㍮ ` e7lmSUO[Yk d WeFb)T,HGP V <"k| LRl 4V ~ gAHl"ӱƭ&Ѐ'p fc |=6M!ل^Zt p1B彄5183)g>#I#Nrf)c2WWl ؠoTk:}!ۿ0VN&w-Dz4 qF3$$cTRg|t7Yb.Mqrb[\flvaHzth)"YX6mrbNU =5T#TS \9ovtӣ2+袋fT&~q3B5Y=9)H-ճFb(Pye@D&*Pk*Lr`*_K~׻ޅQ,w+׼&\7'Gh:dL'㉃-@8@4~/֭Q07==`_Ey^m΂ShE4+u]8,!MHV~Ed5o|q͝R\ݴqy[ꬆi~n:0Xik0fl3;|=liKJGYS4+WW~\n",X%~(HjR%'UƝFfX??0V$eivD;{52.79 uJ|@(BYWQ@NM44ཎɢVk)|J4h"BiY΍>Z_)x@GPRPU@Giuo}e>K.XI }S5hr饗.`L81}oJS ^L#8TnYR6$3tJ0:(XԐtkOіrwv~i>QGuXH06`')2wmx'Zu5E]~{ ew=:imS*` SN>Q`.Lj'>Ś*@IO%?,^D(#b 5&N_y;0 x78]LЅqaY?%}@0' &AI&7f̱;ƻDrKVZ9ݑxn;l F(*TNx9-=(Q f'n`Zo Od/~S`Q ۿcU긬wa:x8zԨve/|ڨ^pq|Dy&!ݵ pN" l"8k#_SaN?t nɸc5ɉ%,\b"i6S;a-4݊}<ʴ>\"ۦF0Svy:uzHFWn`g]v B9jsXeFb)0Ԉ:/Ǘ**[w/]\:6"w{Y=A|ǘQp4st ;w]эnt;?:0(Pg@+~4xG]Sٚ]ڈg]IdQEN{L(M$+^g>wZyK_S/2,_'괵mZw5Z veHގH=m2`} ӻ991/aFAq\ )`hxban`:/]L}b|iҝUP xO[%K 2RŒ:Yˈ/5 on!3>:.~48ʟq/0aP ;0TpM96`~>o(F*Y4m}o[P&NItbMu/*,v{Mk_O}jW_n|1#P# CHKVo~sS /_'0,fr(d@}T|SnA`#(70  NiZqN|ߗz~YP @bwi+/"_Qw`ˎɴ ;tJk:j뮻HX3kU.g=Ya=yO9@Fg8P4Tp n-.AM#Qcgabk]98vzCfŜhR_Wwwp sQpMKG8J9s {ʎ=$ⷦ:o qihh~x\fz#CÔ|vuR 9=̎OQrkz]QPv{lq#ٺu5Uknߗ*++5ڳ*0K:-cw;/u4זtoGw/UMٯT:Ū=_ƘWzԣ$nvDT@89ѫIΜ`3+F̥xg̻= ݅]D *Ǜrie+:ߴ4_}k]\ [?W; -#uT<1ֹ\,"eC$ʱJ܁2&Nk.鑺I2@ gm~]]$B(B kKԧ>6X+=L])p\N@Q-J!ø< .@ȑ~L6,-ש5%~ y0_֡F)/ l~oc%N$ӡG3~0 wL\ 7c,ie]uZx?0(Ӽ[\V"9|9ӎS Pwk͏&nxP%+-tk?WY*Ի.rOfWezZDUQ-+A~Tv WVoVONBǖٮfc]v)hMW\~% ;> @.Bzp.8UFF;`,6 0.>oHji-ݪ=WS#qx(P~_5~Ԁ!HX)M[[`^7?X7 ]mbF(FQQyYMUWe+H&]z%twwwE??1(gk9kgqJhFgud:SxAQIꢷeڱdW 0`< TK_KĠ2sk|\n }u)O 8 ̊V}j@\}_-=Ot9bkۍ 0+^X^P o@[c8k#rn㠯vyoV,1@VS`l F@GQ=O3<31 QsRm){v9h>HNaQ(Ή@IDAT>딯2<#ʙ&+(F,X8RM1N2PaIH%N4bkxA2[Meӻ 9%PSu* ]#@czNU+3.9+dV˦qDy3@6t^=BkFP ;04!:o3kصYeWπ|61!ykEA(|c#k9 QI7ϛKD. JANpwǞ?y$!2 3@/׏؏q@œoVr5y"LrDX'GӞ4*:Q) 8ёU#i^7.C0rd۫z!`嬙(,[<0D>Q G @fGoUuQث-b0ւiŪ[Ҕζa,;҇9ʨm?@&0Ď``VqVSa| F{g>6o4?36|[q4%u}>|rZ? k?;rۿH:G8f,Sg5Gww?Ar^mIIME>k6-\xmBX2h6^<}H.m>%k>E7tFuu:ek " D-DS w,yg,ݻ[htO_*%i ZG̭@)Y:V7L)7he}s0TX& =Oom&OB{$*#Ÿ\@{ʰ<`@0"GŨUfPtޯ~eu]`K~򝸰(\Ro /~k[XPAk,qWV&Iuzߍ$2;^f '7q_zVR6*o7kw@ëYh/k'֔o=zz"=$|Fvuফ:\qb8h2nX9k&< =Pl\,b~` {^i?  :ЮQlC)P;@ӐB*V;b;VK_XmG7yVDY;0Pbn@{:) y *Pr`)QbV , /xGE9~ӛt{ݫ`"*w-A}R ѕk% A)v'w[vy>uyxڽ6B3<}raUɳ:K׾c" ľS+ɟIu ?4O}So:'MAQxh %뢷!( Hi00+y6ӱLlf`e 0YAvHYHG9yN7j+Un`[0y__Q[bYPqy8)^Pl V@PAjA4; `<~ḘI'+Phַ50#>t`w~w#=(pr(xpX$jҠ!@[[>B?vYMpwg{XޱP-oya  7ܰVN~zkU#4kŋAEB[v2ȉRЪ$##!GEO$z{=1C)ܱd[) aFVbnti Q~W!TPUtHl+e}owrcv C6ٳm+9P+JG Zw/ShH <hAP }ѝB {~( 'R!hCG=KM 69aFN~>P ,tlF.so@-(I#{ i_A'DZ#u̗ !_BnŊcWx;R'5{`%)]ىsj'TJgJtRWpaW4]#S^2DiٜCV=pV7} LTJ٦㥉gnZn`K[ s| #H5[mSH0qX߽Z_^#N509Jo}[??7 *wW$j`ķ;q|M7lS̅];Q@ ]q.}y{2YPiCT9I{)O![/lM:h腿eR2#=UѬ*MSL!Ƈ>!#J=H w/^o  J*N-q ] ߔaGb'P8_L%K@綇P'"zHfz6h jw%'mە4"N0A(%zի.r)=ƒ<δ`l-?қB CK"Ǘv8*w/my+,tۊ#9Kd)RyF$LlOHC|m˵b R kgElv8s  ҁ4xmvh1۱#;xPQ%Ď c6}sB2_P Vy3~PDhӑiU+Pi]z3qfj+Ӯl|j#Cu`y㧝vRͮdDL$mm fτLvemX],|q<M2:v1c ?ƥ _hҺ,LLy 9ϙ529rVe5z|i,{Qb՜6($OA۶?Dz1@m'5xːI^5Qsj!/D1Fa+ ]q10G ۈNDS>NwE5~_Z)L+&Xl#ͶCѿPuw] |w֝f&3.=yGO dJB70yhP |4aAMo T~{<a7Dٺe`_T*>,fup 2`^(hW]uT pňTp؂Ϙ*W=ț8 ᯿ FQ`@'f4H(A&F\/vuQ/ q99ȩ_^`5\Pc8'`6r.r `y-(ל᜸'~q [d/Sr=1}{{g%H.#]³llҽLJQVex=۲j1lefYɲȖVdgۓ%{vZN>5m=ƒu9X5^zԵ2TW_]#əz|$Lq֭09Dޯ%o˙ EÌA`-'md Uwݧo1N4ZxkCg!bo8Μ!vKmŔR ڮuJih?|'cS琢zny\~z^_Sa \ [wmDZܷ܍wP #RPȅh ]5/05wtAޕ^&E#g[)P;@xU+u>`PNtA~<8%/y}FI)fY3=7nP `Vb_fK I1i[mπ ] {n[jǀ5G epuyiW//}KH *[+ D5&H.`HO#ۼg}!Q[vq}@G?6sk^GtdqVY 8^o5LG>k>+ *mxM{: *pjK\U:ӼA$4L5vˇ F+" ciSׯҖ]X@wUwh   D̷Ls YTF :.(9Z\>y[޲rFb#(e}x|9U2Tf `րbQ,NSLxV|ы^$~D-)E _APu^JVklPmE:͂Vdg4ҽw|,Uro>c)nt- X"%d֡6}x52wijb]yI[5Tk2-wxIAYpjO*q+WYKg.*e}fGG:U? O¼6<Q HM)1,PoL_Ŵ9°/=ҷ_g8m=A+*rW 8Ĭ8 OqlHݭRRi勬$/28L R90,8l5@ FC ulp2;JۿO|b{}݆z.˟YPT˿|'?Xg=N=l`Ե U5ˑL[YVeg&ʴQWu3"4L5RZZ]"А_< ׯ _d>M\ ᑏ|d&soI^WJnw΂T7(wm4N磼kx Ut{a %&*ipJRi0BPos8VvЇϱIZ&dz"ş8ESɡ@-h[=+q`X>HWOl i+PAOތo~ : ._׮;a+f7 /ho|guYI3sV:r-Њ~X9󓨍)u =lup vetZ@ ؕ>-`eeV~iHwGvSvsIMnHR#פe*+eHl }#M<1.݋ ˜3HFܽD?@ʊ *2Rd]0\s'Rn^) ]lU.^5)Pr sbX*В3 ? he0K׶~۹KlG$Eluxۼ@SYvѹcbwnv*»n~?яGiaG,SbHsvhҞn.U#::cEG;$Z'0+1t2 d8{@>}n 0n+v"}Q9Yi*0g ?i9Njk:ŵVf1X}lH*+P06@8mv  @D++Lbވ&nk_goĉ%{ZrAwyٽEg>=U!v,x j2"6L:_J088tLՊӘm,vtWX'5{vn I) *:=e7h 92 J}+;J 9VkD|HI[9:u8 ->ݨ =b( ̴0_R= Maq``l9? E%PM | ]ڔFp5Hxu6'{@Qg+yuFb>眣$l~d6sr!=i 痺2ZuH3uFDW@j71}dܱBL ](|k!t+s$V-U ZB: Q)3"!@*2-&P>湠ooe{)m?B|1' ^(/x c0f0r 92rƲ(mkQԧ>f6螻 ϵ'?2S>`W _>]pY1W%x]r|qzk@5/Nud\l1]'BZhAACPYnp ,,IO-'|Y| hZ:(㗜82$_`Zrt7aKm xDȘN@-@dtPk_Z+"}$5 /{"؜<'C" y

    x" h% ނ_Ρ(c`̣ض_<4/'v)?$/Z۫KYGuW~6 HY#pg8> OFk`'vUWl^QV ~eR@%KŋWDՈf5[qd m> qWn :Բ-<BPHD@Mlb?eێQ`y9YnS֚dn!d.9^p㐒@SN0K8_0{۸FH&HpAxA-+<.bEn.j>ȈiEc(4?Hp v&j1~heS8Pum$]e@?~ODw,i# #{j% 4Wr:B>ؖg N:!YYwS-d'>7iG. $ =yK!*k$ʼ혎iJBsXx@䑈9{wL4V̹fE!'-3`%WѪM'")104`A]S`f7F-¢<[HD-E͙OfJpэnm58'yQMXV__.ud $LTU8W[%ύ)¦}1[(Z#1(#@%1odX~$\Z]wmygt9?Yb^{сhvZj !+ =&>DʍSo w] 4дUر@7zU8UiQsf3V'e-.PLaU\xܪ[ 0UvG@@K.J` 0` ڿ x` :}V债~XyD0&rByJ"Oif[KO ġ,˒: 1{o{;`($0S\*0Ge~}{jd##+&X9b^r%q bZ}k8kGZD $eTV<4 _`M#~`: 9B){o*f,⣡_J5ܬ'tqH.>?ԾAM+-e`eG;ٖ@F/XAeR@%xTL8~ js$B6BobHu< aj!Jwy]w]􌢐b$% |.UJ(&/g%=qS.dw`HB7pEm?ϧ1lWs{~X`&q9b.C] 5ۆs.iذۉR*}.9qk>Mc}sO¥)[Ydh~rt[\li1Lax0nG3<` d>m>]Q[Gߪ/$}{ h5[};*{ݵqHL78᜴`PmTX1ĭ4@dd{/Yӂ)UVύI2:k;K0 DK> Mr~@X\4#H-%DՁhPtwYepCTng+=_esf,<Ј5u0p3ȿ/o qEq/>mP[R5fҠf5xН= 9۰ a^z)A:]nZr69g} /BR[ۿ;lhUH~sRMFe[oFFFVR +0@%g3{x 7ݭ$ݎ߇>!st _A`ڑU Ҭ'=ID|( mBU?rvkl93mqw\ktrN'Sݷm+q) #4R5q(1I]`i-'Ĭ>9i5?4cmiyi0;r#"m_ "`k  ΂(ogS!'F8i7 #‘Y eZد{Qӈ 4t> 7^)``Q>/л+:Zt -%Uba4f2 `7W` QPx %jpZ>OQ˛2IqPs4ȯ ̱O#lS18獜 Y-g^7w48̔_nbEJMbǙRi!{b6i ٞf*QL`Jzyz!d۷ٴ hxk1C3<LOf8]՚ Mo!'/Ga?J{xr)`3j@AJf従[ GrP Ca2qG} vqqj`h1= ;Rp:BY3ʧN){|uq'h/Jp?ǿ[~  `tLVKLl?ؼ*CdWi”#NC4=IM9qZfx:3ƾk^FzP`UeA`J]tcgXL`ng>ɡ|gIʼh;Ŀ;v,`(Ӄ L)h00їS` 1Fj%6xA98@[ا!̚*#5ʀ uwR͇ X#V" ao: 4^.䖮qSd Skn;:Fz{9v2"2 k}ښֳHl(\DL7'!uWF}Ȏ ^IfU=\$A@|a/*P5/ke}''p UaOL>ؚFcwV uV2P @ZS Ԉ_`'ȉnrkuq}f`˿% Z0׾K. <" >y9o*6{ԦFKը bN Em%*f^Q#G {ɽ'y'>u'}:գc~|r!$P26̗JR]plKm1/HD$TLŔ**n4Ds49p< ÌG"nQ9(D%PFN襴!:kwg҂Æ CϤnM<뛥=mu[K7>[7q䘗 Fƛ2}@5qw44S'Ŕ1qzLkaYiyzPC!ɓ:˒u}9LFUV'1ӂO:l;uT&Wn>8Y$,=RxXBa%xlVY! 3K4ҝREiSyxrȎaȒŝ#SPZ WGyw!;xv  &DߥOZcx3Rx6fpG> @|3'U2d 0(@B2dN@@Ic tX]jwvT0^='*Kw|M:BW]0 f/SL٫)|:'\?'f+-͑>0)jE>1L2U*Ӎ% Cw a{c[&-{Wq' OJz +P?mEIUh&=|Y1"fuòI 2r2K hɲ,Tk*jΧa(F,:jtbC o/6^ B8qgdH]rI?yPfȾhxs+ ^(ŋdl<0|$zUg4MK0{tR[t;:R(Pʐf˨9SLLw&ՠo|M螋4}}bAFj4u]r)$1W}1q(U[|R M^yh‰ (@G80L L2YKYhDbHŜ6rG_scHs#yinwygOWKؤ{8kbiTK4}ٰ>Lidң,Y]X$,YwY`H ɲdFͭ|gQ_:Ƴ>KPW"2^mjJB!F]X@.R!ES,c/kg;:m#1TMHknp 4,Ms(t##FWná ndF_"@e"$@ p?tKjI)\-+g.T!,ՒRHQ`np+d_:+x gST^$O4\Sb\@PI3pP_l- jFw!0AL 3qe 0v뮻ްC0GO>$PkC"ifHEn!XۙJ|2$2L?eAƤ3 z`a Ģbiel- ,%TVU+w2Ov&dBV&)f)EaXǮC5$xO'Vt۷:#ş?G2" Kk/"gc*3xˢ( U'FM7{1pK( l2 D@xe&3e)vut~1$ 7Fҙ+ eZahIAe aVf,?Y,H-VL2d:0P#, 6:9@_7l^zcڊOo`>?1'-xvqCKKUi ùu3ry.ĭK?(Rt%:),vpMCNZ-g h{SMzˀ`aRdžg|MዓiȨZXxo%$Cx[!k^֦=[|z3%![d֑~:6X140}[{ ||#1MHH&3q Xe˸4A"d we!Ú袋UKJאaB~R$~w^ʴ)NibN>&dBarb&ZwzcIG2VFFLjU'K4#ӂIw t,7}?NCz88wG?2?p c! L>0_LӇ0SɄ2r-t^cX NjDUbcɥ1$¤\D[1i?ߙZyz(3:gPRέ |ۈx'176xy}_|~w쏳y}QG{y:s؞W]H=N>kf>L(ILEU'pu* \Q #H+dn1YLev'b&f^vQ er"d9Q[x@H/M 4@V@X'ܔYcϞ=kڂFf %|8 Nj=+ }m:HlJTl3@5t̝u _N":>Dx"lqc 3h 2]Cja:\o:1~O|h˷&&^3eeS;vfRezcQX`,K8$Ӄ@R ]T7@ @[ i; 2`[ו;~ knAz;<}GQ`7]pfda'q[OJ%q Iz5@qA0)g,J`V&7uE;AXBDXr(RdA@ϑ]j[FП&`m%S5~:u)jvǎs<|#Pp[ FW5KrNl~8ߚS6GD0/&iE k)&4cA&XUxgT>Y`,3MRdA,YzΤu t.V+ 2Ҥ?:S6mAU'Ϝ <3Ois\4u'e@IDAT] ದ='RyVKt,sW3h$L)_@}r -&o`nǰ9Sz'sTO&9|/'@, bPԙb!2#RaDHjf9XZ!C-8>YVN[kML+ 1/(wyλ~ΐ"8APj͔-<.TABzH^v_=: Lj}O=t}*|{b,x`~D@V0D=N@y#6 >ِ7Wt (nH? 5NWxQ8YT+^ :g^2L S3M\ad܁R$0X,yBb9G[Z,˼LkXkyML`56]` ɘ1cxՕ\5.Dvldw>?|[0:SjnoOaվ= 9V5.0/Us*EcK]kpgEbύĪ yֻ0,4{%偏 ~9笸Im)YSt0)Ýɒnb6S]C Kòba@8\< eo5s{&`&%P6Sk,$0A'{W'gk,mĈx6]Ed3xTnrNVs3qaB`I*3tL04{F2s j![Č/M`P80na[<ijqG>w?\r<,_ Baw&K,$=zH¸A&Q`:t1MLL\%:L:SUDj%KN-j ӻ- 70*t!~J1QВDO,Ʒu!HgxDmdM{ΰE"Q\ ry/l[=,03@&@] U*/u&} bǪF7F1ؿڍ.*{i/zHDRYdx81Y!a|05Ld!sLz,K#%i%Z,nML`*D?9m$ؑS( *-h-hR!x&`9Wң/Ë U壿(2{eUړƔ*A-U`'~7x㉉/S/C BD쇨ieruzˀbJ``ڊ,B" 2SC+_ZkML@"!/28~D7.O4/( [N8! #3ߚ#&^3iEΣ cDTK4AC(3֞ 0ueQ ɼV05pB(.CKٔU&0I D5 @Y[A`5,Ojk_c4s86CB|q`ҙC5馛.C>STr~Id*Phn&/ B*:b)ӚVZs=j0"PN-**~qM l|ٯj#ڂV[_ns<Vrޙgt_(t^@0AMw2io7(%P9ӡJu>zǣ~y\s0ߋ#"ZL+N%ǫ lQaeEi ET .1(,xjt6?Mi6)H@^{&[\ݨV`8Y`L)( b,ꃩdB)Λzf$&,6 GeBVZm=^0@F9 70ڞ6馛NlXҢVS}/0D[zePz vsv_-ړA M6"m tzS`%:#nLP8a B@p 7<փi_\.ho T 裏II'$'i02HNkШA *ӡLP3qLHsL(*ERAeiHErV LLJ dP<e(-998ȁ9lৗpOlga0)' 8kSp3t_ [O}{fX7$=" hrVF=,xMp"IC8Ge59a!On3axWdg̸_~RB5[ hO!ot)`"s}LŔ)ɭIEB, I ҥ , ּe5ݣ60z jF^5̈́úLiz2롇+gK=4NExB(RvwlFK2?`u>]c yKR4B5P^W K,\&Bǜd&Px9D+M >^$!٭[QfD]6?)}19nw}4ʉ_596lذ6*=F6t?qajIhyM5|(R&Iөv@, 5$z&`&0i ;t='9l)ŧ Hl6^ZD3F|Z}#`3Ѐ&º_:N7 1cƤ]cGvm_{iw.e!`On?2@2wӶN D_(( : :.2LkSIԛ>576J4Xf,L%5`&`&P@h Amd 矏tQ %l]Q0T)Cc~tb^Y{VJfU@K]/L|[K:ݰgX$0^zk/"Ki:,V]u40 iV(@&RW<}Xfe8 DK" {P *";^` h )`|( O&"|ʜ0K%d!XT,nRIEW @]qj?푐r뮻ԓKo9w#PQ@t #p>l8Qj[Pn6olUɭf ũ0 Nb: D@'@5E)ph|cfW2V>Q~Vl q 7 wDEYeUYkt&M)R3a(NAX1VgT @ X`')H]d1}P0dIhES?ˉEba^@ꟗ @x9A_)tA*gy8ZfhR򶠅}zkլanNZg Jz%,ـ&ׅ`t{͡Y,<ܲ= ĥ^_<$A*``L\SFULT2S|b1;Nn{!KZZkMLԒ_FfhGy[9N/ *r“_42! t pq R:  2'ef.2MLjL94/25P<̄(7n\t  A14M9`1OH^ S ފ4d Me?b. #*)KTKLVLLIP9ACח<('fWv_qwaEE#H4Ds'+a+a(B0J/(BQ Drvkv (cX&|1ȱO>$jxwdYz4O\s9C .B<0405F>>@僨bD !D_~-)(NBf,40-S zΒ+p&y @^EAS&n\"vRȐ\uK|5F|Ʒ'U4HѼP@@/B$\,<( t:jYi`+h :WKr0(廆r#'=15+EQmgy&b: ",B8;%^E|fPy?>t?Tt 2^viRmL\@s,Tv:I'p\iÑB0h-yEE6T1J# U8 m^-+;5B'ũ~`AgRXF1j Ak~:B'FKYUf:wߝ]wUr[ouMI `|=n+m q:QEJP2m Kή6ۙpf'L@C@!*瓉H&21V,Y,-5buN(00h'=?!~9QVQ@68:BYVmU5%zERzcHf d&_6 f`f :)tavi5@Ky9W*5 4d^O +(]Ɣ4@kKP!P :Fb$] Lh KiO`E6& L3TXp0Y)| Z]$6o %{ɾߤc<ڢlge?6NN:C{$0ݖB@No 1P, (@Z3Ξv*TLz!s𒥅0ˬ3տ@  Gy晇_bQ"sӟTl쌑')t_(Dv+؉Nh;= {®6C8@iWauBl7x -dŸ80,e\%o-]Χ=?䣍_N;994MtNU#!d"2L+."@CtYh[M]Z]:2Ge{&`&B[[ۼۦ}he$( +M|/Q?x$":WDcP -n65 r˺DN72O?T6}z\Y=’a7o~tk?"$y璞LTʼnA뉁81X:=5  ڨ',c{l aŦNs֊^ޢZ*xϥ{K6X|*Ő8/lKz̾h05tzScQ!K+qտB,40(&v_ac (pYL  z;c~P$85l0T78h#ꫯ9j^>r%,Bhr$q[BU7t|4l?Vxb.c!;cJA~:Xy R|fN(`jY3"8WQjK .* 45XCO'Zs̱2lƻq'J" # I7ha|AYN5";2E>b bc:4ԡ\q.Nc8*VITC=6V uI4Ds4J!C=*-"y?=hjW_?V'PPxT/3+2nܸn-8S:Za)˔K vm-dgP iDB JNR(vJQ=Ma P& ":Q:` z)cT2L+3SB>]}Ͼg00'Q{е'['^PPHRo4 {elU&CA,6%fߟV!%EeLEsjI\xᅸHy'MXW+pM-_zد՟S$j\/hF .LX FJ}Gy] W.hPhaP0FP!"-@!?+tI~V$]En`^TI (pp@NJuDΧ=.%\eXBtTV8LL`H5A˭Z{5\9 8~TNz*;MS3I2L~pL83j!ovik\o(6כoYO[f䜑78KZ/u e뮻"@]Fy-^ +N2ÌT*9 &h(dR` ᄟ)?+q1Ϥ$)ZO*&1ifu%DS460R ~eYXQJdN2hQ:P} 4(ho'54*V'Qj+P "4(HxL~1<'21 ?3,{Զ!b yTU0N g*/2Qzd bSz.BX tpPi&t*,i~EZ$^!ńtc&:0#,BgWř&`&`@h<ȝςqpx)޻wt#QCuT~Tڣꉊn@B@7􆞡1@J2估sLe ,|5\?UVY"guVEd3j|%djihW)5|p9;ヒ/M^ᕤk׮Tվ?_Rݠ3tI'je Hba) g %3L+ 1řKEXH2'`/9&`&`@hzf f,n`QjF9$*TPOehhj·@ @-ٝ](PwwyGV߸-!h2_Z(`7'+DY"zԼPRmq!m~G'j Hn>y!;E[CALqXj2&` LBIe?u1g7i_h\mz(^ .@݋AY Uwf+7Kh~T[TܟV㎶B1".hgzуpa=3u*xd;ȄiGK2eOM%҆t[1XN3"KPQaEBG48pX![,ocXl Xkᛀ &  $ Vud)BLf_ne~C!0=Y+L&Z@@Ѕrzd;4ōp7ʾfxkO-Ҝ|:gsŵ$QۈQ ^7|?aP -6#7Cǎa2@`r#feCPMI dX &j/̡ 4~ݫ+9*0gzK8Ι{OSNL:Q1V>t0)L 41YLa~<ZϲL*T[jS3$9LL܋c?SOq_( 0OwM}A]w=X:#婅gUzE4C͸,QFaCsR[ ~xkzHࡇR 1 @g" =P3Č=wh}z鉪mR߾}'F? X{k̑˶&Yp[su sne Zk٩MLq Y!Pn&3LLQϰ/ P-vG:: p yx{ֺ_I d#`ovC&`&`m ܨp.#1yhC-ߊ`~3mEW^yM}+Ն{΢&`&`S+\7ܲ L@sC(Zx'Bu\,1ǿ#%XƋ |Q{ƣqLL XkqLL wMǍ9.mzs ą ^#%h@J:@7pNCu^ t>6|s @K+Pv⮳~70c= ;+"t{Ŀb믯(ܽ3Zj)z&`&5$z&`&Bd\ACCnLL`_7yfĭ 4 2 @GGב] @g `3̒h&`&vuu 00NO_BLL@hݯML_~esУ30hqezzꩧZh!C"8LLuXkHMLu 8Cg׺#70&`'C70V" J3ﱚ '`o< LLo}2޽{泹ڣ30($`3MLLLLLgͨc&`&`&`&`&`bq 46 Wř&`&`&`&`&`&l5یz<&`&`&`&`&`&PH_!g @l3 @!Xi&`&`&`&`&`F_ͨc&`&`&`&`&`bq 46 Wř&`&`&`&`&`&l5یz<&`&`&`&`&`&PH_!g @l3 @!Xi&`&`&`&`&`F_ͨc&`&`&`&`&`bq 46 Wř&`&`&`&`&`&l5یz<&`&`&`&`&`&PH_!g @l3 @!Xi&`&`&`&`&`F_ͨc&`&`&`&`&`bq 46 Wř&`&`&`&`&`&l5یz<&`&`&`&`&`&PH_!g @l3 @!Xi&`&`&`&`&`F_ͨc&`&`&`&`&`bq 46 Wř&`&`&`&`&`&l5یz<&`&`&`&`&`&PH`\g @;tPƵ;izD&`&`&PM||LLyqk~GyF员 @/ tVGod]v}쬃qMLL].l.d&`&va~G6LL&w&˛ 4>zjO<^h tuIc&`&иo?{{f&`&`w&TWi&`&H޽{A6lFb&`&`w&!\Wm&`&0 |:w'\7n!0; !`opv+&`&`SsO{%B wLL?xr=40huo>o}kw҅ 6[/MLLx#20A馛u?$ ,{&`&Њ.2L3 QzQO~<ȒK.Y(L00hk@LL& >cgLC[ }a&`&`H8 <.췿-'}fǘ1c~sJK/vm+$}LL:;utMLƍwGWjOuLLտ&LLLkY޺$ÇG` ꑷ tRV:Ĺ&`&`^{O?{[n%>]^xaʸ &400!`y#10' ||5瞟}_unXLLLN:q @VZi1tӍ9ry獜L/~Xgu4hfm 4M0 We]vذa9׵kWw7;v ,/)VX >`zR400KƟws00 =cN9gnK00l٩ϝ70^׿i^|E}'?VYeBD<KFϏ'ۀoF t^s瞛 LugI=#]im]y 馛1rZy'?o&`&`&Q @+xo>44OwB8TP>|8*?v֭Z*%z#j[LLw|=00RgGө?+jygiE?q8S[E;e&`&`տ2S xd\rbGvl;.J^cǎe+瞓agyl-d]}4G t66l3 L5 'qSOˡc=KOx)]v}g([l͆%֬&`&`&88sម E`ܸqzjWMT#I$Pw?n6ݺuC) tvYf40rYgE>kzq>V[mСF?/ov3DxQ#3\}}WvۺK>o~|瘀 @_Og&`&0\F[tE7l3C'DU5xѩ y{[} ^ZJiBr嬳:D'M0O9&`&`w:4&`&`SE ؎Ç 4faԨQ>2O:$馛.O_ׂ .'~R$o,cƌb|ǗXb . [o7":a&`&`@0 @myY(ɭ>}ž;s's3(5ss1$cIJ ۼ]|wqGt#s+sLLwvj100^z%p'91{^u0KN;_z[lşT,FdCG}QG]l$r&Xy6 w8/"錀/MLL XkqLL!7|p}gyf {6_>Ì9RJc^8rnL;(@İꫯN=0;NYd|600'`'308,9{B_sL30@qk~ƈ#PT?O :aY?]c"@ǖ]v2I盀 @h3 d pH^cO?%;]^Lvl~{_9?D@"l37|.v s I200"`/ 5 @^=EeYJ$O?=QȘzqВܩJ+ B8vm_a U 41 @ህ;lyꩧH8r~ZQTBPg^|F:/00h(6lpgLL& rݎwmM 7ܰ&p8khP9K{aÆ-rܦ ٳTJ+$b>~cu500)NS| 00b1'f!=PO94bQCa>w}wP22v%400hdVyv70hi_OF.~ '. + "A]wu%T l\![&`&`& l n L@=z3rg?\ຓMk :W^ݨ'M<3Dχ s/dz  P&JS/~ !~a M>a6瘀 $ݿIm K`- ݏ|#{]X~}A#C~tAvvFUiq2b6<1%GUmGy/Vf9䐴rMLL x']20V'pwM8b}Ib7'bdOo0oV~xzt8B8<38ceՎӀ-RO?|PqB2RI L"ݨ @)T)v6jݻwPz\=:w׷o_. D;sHtI $KRݏZ>3~ '4 ߤ{lzX1 :a&`&` B_La&`& ѽ+@1HjY殻ؾ{QR1;ˎ;Ѧ\-.Vo[$#<2p@峑q)itl^Zv6_[IM7kM^xFvvʁ?yŔB%!o&`&`տ- Xwuo6c=V('Ol>9]duY(fKƍ#}<{Q&(L2sZeU01z ŔI #F^y I200)B_v7j&`&%Y~c-+5VXa8hY/i۸ GC*BպbJ Gi @8sម @  N>2@ L^߯Hd2Nxa&tDF[nVR~Ǡ2100)HML!p'>s`hpI?"7soСG}tpzJv?.VYhk&\p7`<^z╔AUH L~>7E00 b>S;|yM \ȇ'?&o<>7_"M.r,z*: N3V4-\ >W.h8b*O9眯:TΆ!A#2100)BS50Oٳ{>~wYgX♓ /t\?GK2 Ļ b$88<=ܓJK#ΙZV-00<7y800bl-=b+TZQ^z~XXƌ?O6<@K䓭xټOL3 E)/_[n!_,T`ԫJ8 /P4Aya瘀 'ݿ- '~ 6|hkuN81d 38,SKv va_\⚅[mCa_JsQ!"_hSNLGm:=*zf0`;a&`&`S300)Du駟{aiI&fN)C>#8".(]QGŭ룏>JoqI&HC$J.rkuߒ'g +*_sLLL`R?LL`T^y5' Mvu8'pdcǎE{vm7.7,9#_l6uΫ̵^;'s1aN=ܼ*yrQt?tBN}7_2bʥ~t?LK%)x|dp8:)kUba:DBI00)G`Ro/~00Yf2)ev؁+R؝7nwqIg-rbO?=Aɓ^tTb$3oz*:,CַLLL`2j2&LLL C`-@)?gҥ h:Twp\=BA#[oễ_~yF,sbl* $rˌ@GE fAA)Jmwǐ100IgY&`&`>Vgy7bF@?-sdr.~>3t7W]uUF&?'ڵk^&>A1rHG/0Hʹ(ĩ_~3400Fg&j7d&`&T>t'AbG݉}:'B=q P +O3we].֣!LYguذa~;S$[<K '`o3w&`&GH~УGl!޳>-vW(DSlƎA۷2g /gqF"sI(# . I:LL&570OoRܲ?^`C?_Qy gT G sꩧ>_/qJZA{߿0a"ЊRe&`&`M LLQp)h^^*lߡ;o&pBTp}c-#}9W+BE8RK3[oe =TG Qg>."o桇/PN3.2yI|')_򗄈@]700&400IM.ӟnQԤMq+: P^đGD(Ԡ)B }#_9__y睗 ɤ"d ]⒝=0hY Go 7-00M LL KST!}M7eƴR^&u]G)||AB>bsʇz(* J (C IoQLB WIg 7@p9hd.hJW_}5/00t%-vLL`S9C&w}ѿ7l$PNrN ƍKoɑ?N -"Z!6Cd`x ]-SITޢQt#VF1?pOoo908p` LrNt&`&`& ?TB88d{.a[piDyK֤bd_"~zܒ<1'ȐIUA,Q2HIsqnf/QbիweJ٥K٩fj L"6D`] 7imgfS8D10bmG?.믿^şyՏLKsfi=aۉ}W(O&UQj\24GMӁR гgϼFn!e\zWH.ڜi&`&`տIAu '뮻 ^_>)p ^_ݗ_1N&_֛{w*IwȚk:蠌L )BqYEB#(Ҫ8Äē O3'%#Ti00MRLZQgC ܺp N2swYiI%2뭷UaQy)uY9.X&L>G0P +ETK4!M.B,x+(TQ/5\LT}LL X@LL K@zZGyD?&lUU])Ю" 򗿨Npj)&hFKgf"8!K.$oqH`ʑ?ף$*`D)'LLLCLM- t,a4(bHIuk󁫮*#G޽{=x:묃$&h5`P%9k.".ХEX Bk]믿 Hof(?}Qml8u0jC| 00Dau&`&p!BjgXDWG+#i$95W0~\T9#toiGQ!u-܄1XvSݏ[;H2s*Й&`&`&Ёu LWe&`&0yt ](f-59".ƗL}~8"xR{Q)U<>3xHviUZ* E)|ls9-%~}Wi#2b400'`ÑB00}O<G@I+sU@u.(KLʭފe]v GPxz#lqtm^Yj&hhB>n6?.[y#?M1;82N @&`&`&бPfn|+[ldW3=_E^ap&gvB~饗ˏ?XzO'v_Oc%gϞkܒ[N*L+iN@F>.n\PB^xᅤq3f̘I "&`&`&Ёu LWe&`&eƹt,;#:u.E,2d`r瘀 @!] WtH`H4 m{&3'oZchBH!(E@h&&--*M@ta+'yoP&$ysgs>fyw[xU^!D HD#D GfJD#0l0LԵvnb9!v)C>tPQ]S!=.|G! Y4gm6'tRT@fyҬ-())\9YCXLُ}N~x@'F?2)=@"$?@ҿԐ$@"0 o\z@\r ԧVA$wi'YQP`wvЗ^zwP2pVgD[la=$ fÒ|J=DڔּNTo>ec LT=@"$@$HD &6|siLYpJQڨQlZS'ύ6~(ܲ.**/e\ګD9J/^>mm `I,''$i%}_|),(]p dD H $Ha{bJKp袋Fk<,,gՈGn8`C#g@SC1OvMgXC9D3#^ѹJ+1E5@NL.5/l$@"$ I>SI"$`K-ń.$ʼn Fʬ̫Y!xW2 ʱc~򓟤M\%zkq[eN3.գ^Y K~WI3s= X :hWv{vϘOD H&IdO"$C?9ԥ)zOxk&G2neȘ1cЏpt^wu`DN^zgwSI0]6F",(h _[)D HDA ?^MD ?aI@όG h(ꫯvHt)] w)xbwyʓ54z5y"CN?^be?ޞs5n-@Jj) `TD HDA ?^MD h{%{9sJt>hW>Ն}w@{EŵZ<'W^yej^t4hr&4W b^k ONia(!CNMO2ldt}V`l|͕f+ "6F@$6HD HᖣD H&vmY H Y7+tts=x 1 ]b7EtC((Vs 7y;tPTF{CèB5lȯG/ D.WF< s lĈj bi S$6HD ;HwCD H&o,e]w}Lw/Ҟ[r>;+l _|qfF@:- Q I^>_S&F'JUX>*$-Y$Ke ,/l6a}p?n.]te{䃻j$@"|(}(R8HD` :d0<%]!TcJK.h&Lhzwc^Cc=V>o~^b~De]O$iN0 ƒtW~A!կ~}2%Nt4YgICG$)xW`/wyg,xBBCfWRW^4М4.߸lND H>,I>,b)$@G4VbЀhw}h(efIV`Y8^~{cvsYXBykCnXUgd iV T,ųJ[c:ٚ"|\5 K!_Jf;HD P$Ppp"$DU>0駟N'Y~B7* d Q_/yqDv ӻ<6u4\aX~6v]dE[67"}(F"$@"0$vR2HD`W_ !1iR@_dwFovm믿>?1jRK #qt:-˶z^moe `/a^ w>ӊs=Ԛ5hk:D HDD H_j$K/ i^Oer-77S{H}Ѝk%yPԧ>Fk7G~%` _- :n\Gyd=n؂k7m&O9u"L1TE#` Q"$@" D Hc9o|CޘzhΊ8XVjuŽEޱzEwKb1#@IYC{N}=CQ+bȑhXhW-hcSd~r̈'gyOBW^ye9RCD HiD 4b@"wH~6rW[<;0T&8O>y]@os=7a}p?v}Y)S&-y@s+LCjy]v٥)\x[+j[!X&E"͌ե)(3R@"$@@ҿ MD hGP^{'R;|'Lq1g]lI &N|Hz'~ӟ6Ga#A(O~S:y@eӣBxHH&M.3lWB P "t(E]_D HiD 4b@"kpęNIʧc/bG2Ԯ2,`rk!q↌VA_ rʷ6f#HD#D H AA<~_xFl wɔ…ccƌA o }/>Vel3tM&aTwߍbۉ]ўk6l?\pAְ6Teall!63bd [l DxLbvۍ[%d#HD M J)$@FK.l| _ "N̠"4: ѹa&X~nܚkI ^a|s)eN:$:!NeVj,"3g6c=Tl#t3_^qMIz0Y"Oc2=_dk(gG$;<W\5#8jq48rl'@"$$'&@" <+0 jh<lF8E*@Bi Icɜ5/' 2U7ߔi8Apyԑ|/(^S*й:`,4 l$@"$$'&@" &V曉+m+a>U{@Nd$HO8^b̓L26FxΥ|ZLȴ68=ǒEX.ӇTܪNrڀybH?c8E9n ȮE?9=#Y%/OD $/@n?Hr- @tb,Fm5zh@) Oѹ t G\0jR2WrU(%gu֜RQ6,lPzK"æ<@^xax驮UW]5pXM=ٓ$@"T$D H)Sa_E?&L('AOGਣB"gNĥ lj6pNY3??[N*-7`# K1K/XYllei;~f?~[/ԐD HDdg"$D-o" 0Oۿx?DdY|ZyxBxu~g阂GW]uƍO~6CxjʅĞRGTud1eԨQ>*^x~1 fx3us@pXQ"$@" IMHD hA ~%M~bv%H8`>=3!c1Tn! Z/s+&Y ?n1+EsxoRΞ[.Qe/hٲ.0LDƱVg !\U͉^j?HD?#?~=Hv *X`(X'L1׿7ސ\s5튊^tj'DԱxa\QܱF8\9)+"򫯾ztd|!s((UReX.,نܖZG}4j =\LUA?8XB%Jk[[OR]v"$@?D _?j7a[֊v,2jAwҗ믿IٓO>^zK_+_u} _a"${W %QUA10DFBrGSGՋuWF3I_I[oe7s)0KmZS]w];9V=ٙ$@"@ҿ|D HBVM FA%hOG_|q=nQORבĘP^E(xPNB2 A~LmP-au%hͽ)DmUmZ ,ńBLA^p2;#%4d2~0X6qH[aIJ'HD $@"L 0e87Z!Ȇ zaک.\.˲@5h#~=8OD $/@n?Hڶ""d2& jA2 Zm-&. wa2]vYtY5 Q2nviрrV2[JH*%+oبHbrBVIY@xT9 I.i {um=8i8 mHD $ϧ{OD`*dSik NUW]U{Oedt\pO&y0Z馛CZ֔1z`k:t([ã@{D H~@ҿ~{D HBvAo|4s0lPN5rȩM1;(=ҟ4҃>;$gyfd)oXy,+uccCG&L@<A\HQjկP׿`܎r袋*dMٓ$@"H=$@yV  Xz饃c`Ĩ|GIPqv=?٬' ,/VCAG$dF.KeUڿM*DTOF]~} \0`ϤDZi@_RKfN+R1tf#HD_!_wn6Hv./&)Y%-ԬӾt뭷VZ=\M% %Wz{; l#”k!oӢW|f!^ndfmF%=S~;eSh35 X4"8~ B@2uSI;n!b^¹)1Q6D H$@"Я4`%u~F#kmx^xtI3sYhh[k묳Σ>j=5#Vy7nv́'x"CW&m^s5!QEy0+lKAy" {衇҆sNKiDBЀif[5 Y7@IDAT{,^pzKpd}Z_+y$@"0 #o>Z"$}#pqI/La'^wk<ꨣ痂uˣIX[nTUtD /RCYc)aO3JsL?_VBV㣪 ~G$=o}y P0P MH)|1aeZ{wcl6D H9I O~eu'uY2(P H5'5ӧ%g]uecc *;y N;ecر¦w 7OΐO)mMޕiWa!Y6Xc1<VXa:0Cw(l /6lT*q6l'* sЕMD $瞻ND`Fipbzŭ&Opz4d(!L!HJ5C4H;0ﵪՅy>ѿk2<Ee<}1U2̒D+r%)s?zTVJ :˧6ks9>Noa:r+b9{D Hfm盻KD'8mlhu]{**?e%"dk 6ӄ*nrK[)=gUPj5db"X֗_~9 @I VS@I7c,%0L.k'nEA`7o>L h6K8*$[d>N4f#HD"}n<H;("Cm 3qak%iؾ67nt=6͆=We0LĘ$d1Pb%قA{:̏1 .@9F2R@|d,4TfOK mɆMD 5H7kc"HiEgM7V/,qkxG>y3[E$Hl^}Z!Q輒neM1?yK痿N!,$k4{,0LRYp)l3Q{WNSD`OO;4qq4<% ɴI$ /`7=}im*ϞD HYD m5ǿoH z$ЭnY.B $ L),Wov Ċhx>84 Vy;O>dd oZ.I, CN}zUW‚5UfF٦9o8~CQGK[IA&L"tF9E$@"$O0ן$4!@ 9'iXtB:B,ZXKQ]{NY=)2Qe`f AL0o~#Z悔ʹ4W{7bdT Lu˲Yq.p+sѼ*3]>K9ԇ^3%+M%PNWLӢ`j&lK\UrTG}4%(θ8n+z6|>TWzݲun xuס_ԆpeG;l፱f-TY_Yzxh*ɞD HYD "$5 /' 4mРA lP8Lm҆#I+cಖ` kI9@ʵGJZPM-Z`j䟗M$[~*Ϛ_~yONوx56غ ;0u|wBJHelf߳1RwOWףObQ"$̅@ҿr@"|88 }2bK#v?aByԑS'y2f foI+78XPS CԣD㶃:BO~ VJZMeU%z~=}ه[h͔C`_gE'O>G\mլ%#^ c>yI:VD Hf%J{ID`*!:wY2%3Z޿ΩTL}#ĢU@55KkT*'L (BjԨQh^s5rnLc;(Y$Y!CQ3u9㏫Ct4e֠g}l[oq.X#믿^v-DipS<8p 66/jBC6D HfUͪ'JD`"'$XĒ[Ӏ[]Ѓ^0Ly&2 7`p 37߬]wE+oӪX!3+yYdTemHC[)yfO=Բllp6J R>&+v]>Dt;@I_ ZP[,&ͼte9鲝$@"0!o;N"$S  4 |.JOJ[S^&-wqMh|d^Z[֣>K~ %PX>cz)Sߓw;vۍ _hiTb pX499ʇY6X6lofKɪ\jY k8~n98^y{qdc9/P̌4xIx=24&iN=@"$3Ifʥ&@"!Xwuc\Mڟ/G}~^ I@)>et8d3 \q24^W\qEvdX)= >43p1 RpnvY6୵Z,wGBhBl•eG 0>N)ۺ2yA~,=h('ٚ)dl%TGᐷ"!L#̗-[iPX^u%(V Xa9{D HfjǗOD+ (fmw/Rrw]]ƍH: p}{5<RMܵ^+%_1YL*g>!M%}V㥮:6Xb 䡚!lP[MpL9vQ宙C1fc" 8>e3.wt5ְ %q66HD`C ,vD H&bV i,vw?`6JFܚ^ġ\&, Oh9'/JՑزZJb6vئz ["5QgBnP7tivJVyo_#Xp/' KP/pM9p5Q&@",$YN*י$4!@9sHI7믿&oCijXY)I[od%s'Ԉ@3ROGSaÆ[ubp Ç[]AbXûj0fUbZ_l܊r)|}c S3U_tn gyZ&@"$51w$$-?|_feDD)rI:,oV]vEIgy:W^y%b# hiJ!5WR9LRU:¶qDX;R>q Vҗsy k6:';JAٲfL۠cj`(U-T= ,q(+?(Axfg"$IfC-$@"0e颋.@ʧ)Gu/A2FBєǏIW3q%fV=DvXQsȗTet$q^C,Lz420TS?>MYLkzJy-~2trpFn#^ rLV6pLjӢt->~njZptٙ$@"0#o?\^"$[a@;{AIV6(aTƉQn$%嚬&3 &gCSd 6Ć(8KCza5JjChaLt^}#}/Qad d/C q_h9n\*q ʥVDꦨXu>-mEGKL$@"0 o9H"w"?+' n+2IZؠX_;Y0 Rx㍟B_pCً/TRf0"mҐls3S5RƂTڴnI>xVڦ, -l0KG-g?Ӷ&CGДt!.G\zq[ ~硣~h?/US[$@"$/$$IdY|3<|I6_'pOII V|1ܭj+b)=؀4,T:+~;!mLٸ ьe<+?y]w1d6v^J+EjqB4N5 :m4=0)=ςq3fL( /26ی1`e5e_9vyG .X<O?Ib &A?{D Hf,'LD'Ԏcu3HzeJ)% v1ok2OQeRRj%w0o~󛌅lR֐mmȡC{Vf'cEf(ISc9~0=Y"j N-Uh9줍mD=>춵MzKH k8^*F2VSm"$L@ҿr@"D6,~^ ~}y| ?zA3YWmCTo}LkQ^>dD)K-Laz9Rޫfl޾[ q}'U^{D- kT2(7 1iLtB2%Ƥ<fC PL e 2IZ/ۣ98݀K"^: o$$iUdID IH7\.;HINƗ:Z9~K!zg !cD)Ci40@I0rx=uF,_ Ƽs9gBtBr4@rI1iՀ)InudTd#-n(1f=*MU!cWҧ$BOQsA 瘽|c,;(1oemTU\gTk4 cRӪ9 `̦twG Dѥ"c]bpRBP #Y烗ID H7Y.8HI\DIMFdԔ£42&Ô#|RpqƵQ-]#_* 8 ~3'+U.ώG(SOd}h` 见-`-#Y(mMTLӒe܂c~=PC{~\@jxpwF?Az\Kh#&> 0"~a ԺJKIC jcj&[Bx9H?E-Aj+0Y.ԱSI0uy5ʌ ljBaLmnOةl:蠦"Xc{=|[>NÆ . s'>cҢKބh3^Di4RnKf+f=|0YaI.$N:q|I;3rY,Zy첋֋jb=C-eU A3'IS KGT'Fg}6VαtFM-GۥFB%^3dA g#HD`C LwdD @DLJ8KbȐ!~St$}ѸOfČGwe/wz2F/A ؚR1dVfAO5Jֶݞ11ў{ .vlUW]͈,@\lH0Y(2z>! RkL Foɡ"@"$3Ifʥ&@"0qܚ ;f@nm/s`sv0m  БS!]YF Z7h'F*(W_~yDgu! jv$b]7NKsu |4svP( #RTOAE3"ڳUN[C+:-/3؃1?pBL_<^^se"$ @ҿry@"|xAQ`|}ϧ2y afǒ+f"Zf4hPkMG%̙*KIj!f|_\QD]2uY !~bTTd*zZWIZin% .8Һ)`LV]+mb#^40ߒ E(Z;ScI~ _hƶ&y䑱0Ua=ٴQAWB zcULJVE).@v}G HDoSYY2 $5s3i*%?vqGWĐt{N͊xe2X@ܒFBvu<=N O-Kh= ^jMD H7P./H|k1v'Hn#M~ǓOE3T07s=Xhbx92<:餓 'J᪁R~LvQM(ɡD/l& bPٍ6%xTvxM7ig(nlN=ˈC0`״@X4Bt`qk([K6FF6.t-آUItz?!y`aF"xykM8cl$@" $A"$@OLBD"9!BCbCqF,qhq}CGC]Ч) 1S_ WALUwDfK;tZ0-or*,iRf(ܶ k"+Lٶ8[R֤l X$X umNjg*TC/=/~QE׌CHFrvLD Hf4h'ID`*|IHMI> u衜v3=baY1M57-%WyBhGzY 'QP=j޲l1(f/ +vdUi YT<`^i1ea *WU9zY=)(­򚑷&hVh^H^B^3HD`D x(D H>@zkC [)?Ç3]G/f+ěяx>qA`-烾̄Yp{PBvM{1~,tOE$G; KXcMO[\"ʷ,^v@)lmotvyKysHv|UUVYծMۅJ)E%0C%}jf^6_!ĠYo9]$@"̘$1%W$$>gz'K.whϦS_|/TA`ß'tAq'=L@@vmKj5z .㏯UD鿊Z-URtG̎gX SOEL$6t6%G =zu*1۸4]tE#L[P4[q)D'G DG k!B,_^yGoRrip>H(F"$@ҿtrm@"Я_{ n R_u.0䁯pMH2m_PL7|˸|EYwS)"5UE:y&V2c=:,Qߣ_lĥ|ԠӲMKȏcY( 5Kɲ 94X9:{X &`կ~U*ڑ2(+po3`N?G EFT#1xY2 >""QmL_9B'2娱l$@"̘$1%W$j{ENcZ,|<KB@B*C.i0;u%Ed4+UW]inx>K֢*< #qea ]̨DUVZ#~L4%/De6q[6 }^@tjvI5ѪN^2b6R^sx}ݣߗ_GyD̐[^׎%D H3A2D  wD @b ͋t)EnOh㎩&| çQ{GS&zaC;o~Av 8/Z Dz{eHJłfиKQcǎd<95X̐4+͚UX0dX-fܖ$ZȳXkzf'WH!IbiAdwqIcv^ \\ˋku1ZHP dCy h?cGj 6 Ld"Jk;z%QUe  SzlhmcH(J*J8nr̲f1u+)K,2g=,Uقlʼ)lC J- Ue1nm1KL O;Ӌ5)^V6HD`FC ߌv"D H&B18Rj<3N.RA@s9S2LGLDGOyfy "~fY7d:B`3̥ڦ9n?L~F^x9iφ$֝*xmv Uۚ@ay:fz&og{6\(9_WCW2L d.l8ʖy1f}vLc0;'哱8_@_\Yv`]Īߍ7ޘvE4G#v+¼R6HD`B uD H&g4삀:*kӶ\ M[l_mOc Xe *!6r-28OK2j -lk|;ҴJe w}M E*%nqt$%SNnRQa KnI<K]*J@#kvNqp( 1qXcCTtTy_Pah/EF9dᔥ6HDcG ~D H>@, $T{Ϧ봵/>'7!^7|?<#+@S3%s{<56+t?d5L%boLM lmA0!íbe'̔9O,TqtȖZj)P7OXd)ڶ`#gPYaea,Es3 ٫!Gq1: xwItsuC4> mAU'dLhd#ƦK 7ZfWwfQr4M a ,U&YvN QlJ+?[o SO qH>=#$d5EiI&ifբ +C=z^]Dy$@""?gOD6tS>]Ǩ0?б)r ˁP!/RU5 ?ƶs1V~M>{! KtkxK*ΈCm ڔwH*r,b/vkLH$nl:{750%BaIZlYLDcv5g 4t'D1|zU.6G@ b9*C`nhW+mkT~}gWS* 0zU:\9/s5Q&@"$N!א$D+/3j{dp +{N~pw~9UZᨕ<3 ul3?Nޙ= r`LgY5Q;! wA8NCR9nzx n()o&/6@"$#I>FsD H&Rϯ!NĔY7O pTiS_(+p@bu;GiI1Qˮ[+=j5b}]Vk\gLsH~I'5%amVԀgeOp{{'psύ4'|&?z35(~O:̎(n#bbmZDY~nQ"[FTe$H+Ǵb̫IOk[3c$&,9a6 G*Qfa%Pǩv [#RÑ6*Tu\ I"oBHH/5S%farHSa"$=A:~A0HM4Uc'[07hăiYH#%XʥK 4!',eh,S AeY%ǒ I?\ɔ2ĆGx6ꉇ0DB.zX/I>@QE8$*>DH'2~Q!X҃z q兼Nt4TjFZE[ȹj{g6cƌ8hzЉ-ƂK?do !% X M^+4$jjGYc2G(36dԲ ]pkʦ0=hdr~7&;Ylj\\Ag7>́P ȨXx=kV5 ۘ t| =~NjРA6#^+?ԉuT1|q ne`S~VeKʞD H _:D hA[/aw3B@@c2:0d[4.R*e ,#n(s9ǧP r8B0`\GydS=YVLHoe]S@vӘ2d;LJ*J4$ K᪍l%p3n/tvƺLpzdbG4dl9;Tva@4bp#Sd<:K18t N^o&hRh@y"i׏גTbS'/=ini(meg#HD#D GfJD'r./rw%cS_C~*nAN |[n~'8ෘ<6^ Zpt Bl2W knSro)oua2O<)\0pwXni FgނovƖ cYdZ0FTB !BR%IHh$)$BƪURbhf3{~'K;ξs1X3^>B#$=%ҋ3|S6 oxC@/S# U35nx\I) 'M(Bcx\ML%Z? U0lAAXkWQy“2:'Bipe9casރ.ՕV{r{ M얹?[?:8Vm\KRTxnm>3|;xtA8vyK`K`K`KfI`ÿ%=Ζy R⃔OLqBw5TO~S#yS6a-pQD¬ *@%?8}:5Q&;lNC.#/|apڄ`w+$WMn! rjE.5ClL_c48Jp"db-Oc掳ӂ1Uc6kPN"fi_JwqAVcơ;z ϕ8-mָ- ,*' C?C us|t #&ؗ,in6)b܃l l l r1'Ts2~Yu2 yxk?5q"d}9gփBxq,B;*:cEfpEt4{Aϣ( 5aSh"S?:r\E9Po([_HX-_@ÕvJuR-زQi_m6}n,?gEg : 핯|78Rї0Sl4;dwOҶ?}q~-U2>3J r6qG[[[[6E;n l l |h '|jʨ,CTA\kkQʒ΅5F<ϫ(vwQuȟôиjk{e R1Tg ( 1ƙDl~7|T hdbU&dXi?i4& v8]*hHLCK_U(-2Zt5#_h+wNæNCأ8g"NZZOZn]Y@dֿ [[[[9 lyK`KKOB`# =8;0&8W̌ttl=Hß9a%\%h1?; ddYifj&k)Hy1,kS1g%0r?CO ӂ=6Tt*1\!׹]3BIDZ!Vs=Mz ;m9 S!&=ZlW\-H4Dqi OoFYXnFWð^|,wyK`K`K`K#! >Rcn l l ܡg~& xx9f+ˍ_=ˇyӫ} uP 4)ۄ|<+q'o}[6Pw# .i4JQ%SzCb:g<̈́^Pa F%M?D% gK5ڷVov0y vfD[q\l3 @&9CREԼ g0ۑOUUb]=mSĀ9:^P"Jt[e Ǫ7̕,K2 vaK`K`K`K&J`ÿ(=Ԗ% 75E܊ 2{#8%F+z a'驯kE/徤;>i>˺k S9ˉ;nOz1'q{@\よl gԛ(WN"-ۀ K#Op"2a}8N,,d5-'FZ$YrC]b·v w<[Mm_LK˂sJD?LHaʯf/Qt=tqU:M*kJj3Bzg_bWAek? ze_n6"n l l &w#OaV9) PqSjS.M(Sq z>a4ɵ79G=Jrp}AG/z N!Lwv [[[[6{m l l \)5";{BdNjtwe )K_]~I~Saʍ>."D<}:5"F3 lPHeQX,JF4XL ]~sx+h"m*+D{{OO^Ox6J`0 *6\g$XJ֗3"C $'`1B,WM" Z;p4új(6®\F}Yg;dnc6m l l l %Q]$P HgEא-MlIo2]y,3.cE7Ȥdk5O-lU)ivg"|d/߯ Z)ПO(L|cvؼ?`g`jASQ[BGNӂȢiWi1ԫOi˵LjZU0&2 o]B ']Gkk JJzR2EmumE:w.,C6F5?z7 sjW(!\a⍍gXP/WF_v]%%%%pS$MdK`K`K 8$E9#d|t`!GjT,ƄߨǓaT+?=5iti u%/GR2nϘWǵ-58XL}LGoh0b?t|ްYX($m: JCa$QdWGtU Q'LF'c\!98` 8y O{6Ƴ<2N}^rExPqn6Yl l \w |73uV\$2a 1/wO JY_ԅv.d:w*]T_iOx)ǯvQ Ie!s}4=iDI0$'_BZPɜq*bH6, C FH4a%oFQt'1vLZ˰> *{ 4&_OdRJMA\#sb,ш9L汉[Uw;PfF$0s~>0e&-%b4".Gd^`O઻s5ٯ>^"}P]YfIr%%p%@ p *!Qgy{:zpI0y*iRF*N*'3aBNH N[-ma2R$d?,++!8LS<В+-di pc.ƗD"__d$ 2QL5օ{kL﫡&0eӬpjਈPa43dlyu%""%ر J'48ׂ+coiXR K=%lg(TV#?xZ<[5fOq53ԝL/zыP %2k5Kڅ----" n [[]iS{"Z/m/57,ax OoL=~ (6__0@ӱz!//i@fd82I| sC+_+[ۿw䫿J,!FK*)iQU=z:u|]- 9}^ x Ιoo) F,5PdB68Əo9uF??I 餆3>DmIHa?}NڸZ-C,P_/;g_0xkK5M{EtcˁDd`쵚–M7E{--k-RSy'&$ @ʀbwc ʓ+C5E)c{<5s00I髐! dm UIꌁĒ]8llpPV.q??8S 4/p!\͌ gx$ c\ehI·Ӌh L} _8 Y &pBn &WIZ, jg>f?TUj/,]' .1C΀ !I[B#k]cUu(< L?5U/W5sK`K`K`KH`ÿ"=ȖM:'H x-d]2-< NS!B ]X0 Jglx1 ke&]9$ mw- J w{d5]4XH6+1 r:$=y'=Iy xF%-0\hk3 (k̕.,Xuԉ*Tf7]5|3; 1y!=2gϻTavs[9NuUJWt" ĮG٬2Ru\Wrn\ݸv---3`bG=(@NnNykOX+ǺzxMM^%\4__<;BwD)W*!:*':S0A&O.m؞Vnנt8"e S>jU;;~f| 1 rPf Xu ق қ7ZUۙ]c&AA$ItamM\q.Vbab1ы_ Z h.ǂs\"ǨbG_a<7ߋ)D)HBVbW vo l l l g%Vb%/z ZjՁbr&mo{JeCt=φEdMjPidtOqG_-2L#5]\NYTikrv0_P3 8djā̍N?qD.%i01$nW6eU6׾vVlDCj c/SXKDEFjI*P(.qa4_,_V9-^68$@OO: bI{d6vm~*ԋ0yA4G񍳗 6.Or.؄+Rz_] l8.td9i R\};+ryhM.l l l l \峟n l l \)S5M-ʋmpDD1 dXfzc+8jB4fbWmNv!08 z&=:}ܚY-sGءT#H| 4td߂sm^5zWMm upw4dڴewp63ZB_YciȍX8r 15+,f %qWy'_Es\$ɥ{8-g  rrIrc_4 +dKo2Gkءw>< lm\17Zw~S%3g ρE|)-!!}]Q͡;sĥM` g|]!M_̋1~4S.ZaJ&񐶳zpQޱn@cŃ 57 i0-قN1h.rw紷\o"%zgeܺqgoi;6 b<͞'ty{N@>ԋ$//j HSyxW]f7k沍׿Bu:\9TW\K/E#jp:KXʩ܅----O}xr۽(`8/])ʿ9+JG^W*}CST 9x*׽2SW(tY: pb\/ωwrʢߌg$mPՒvY R"[Y2m^-+sk $}jNZA:hEL9x @e}@p0$` |2;\l6huv \{d1+ S'LƢA<Y[)2T])hnd\n ;tF_W翚,Wg] .g?8#k)NfëʘIVWrx3n l l l \峟n l l |Ptt?Z M}#Lm"stQ6)*!o47 pSO "¤q__)ھګ f:=B^m;Ltv=o|4 J |/{db1ɜ5X ?@opXbxe܆Fz(O bu2]{/dfꇀ1$LFi|:nu:g? yJ7)iq ?Zudd[,93Ѭ|ð+P&'Ic5[[[[ lw%%%p^R=٧E Y+ u@IDAT z:}i*scG,|koLo&>gN 1Ƅ !9{2l ggQ)S\L"q>~ RN\6|ӛjބooO@w"bĒ@T@8ysfg1@N4`QX}ZU56[[7D lJ)^^Pr !NI-vp ;r( Ne87/UW0{|>6##~ 1f(CԑTcH 0K^----7"fK`K`K}w%/!m|0 hFrگ8 s!SQ{DaX٘rW4pDZS ȚPaBqS^EJp1A14{^SW. B`/]Gu":%l@YPv@1MjI$)@hw#uSI^ܸ0s}$~۞<J/9˨`]N;:<[zڸ~-Y>¹>DnJ8=V_=ZObF^Q3/ 3څ----7(lK`KK@\DJXj;̞iH$Z5J{&{ޚF+ez2ۋKU?ɰZ"8*PS;,zp*7N_XR;;uHHcu̪,u-KQkWY1b =Ç)~0jŠ,C},_Q{ >=! HX6uѝrZ.%O/Ob27jo .YYeX :{!}&3 ւ-ў2ůQ|6vq@$6|sb}b"B]KrTKIgɖfۙmsCEѪ+cr:,^Y.l l l l ܠ6AAf[[Z@+N _z2%Q !ºH^H[O5^+Bl| ,`m!ufgLh: xFld6}.tz- *YtDJU-h++eÆȤ> [w匆{=|< BF#iɖv:iqtdPKyD]CGU^kUdZ=yz4DMP? I ;פD2V#鼒^:----7(lK`KZK!XU QRGxDfPRTq* Q@Bጃ TLM'*GѭPFP,F6[.[78S@M SR_źWhG{t\ Fŝ pH?X WJ*GM-q9s{UX n hU&̓񰞾Z(#xgsgd&BnjKӽ?*X(|fىHSb`3o5 + h[U {5ҋy6:^.Mh%%%%p#Fl l \k bGd`yaƅ SjWZ2YL^g䓦RHɂC|feg?>O4>ԭsNj$ Cd½Eߺ5eK)=&U ̸bWSX0J3 :ؾg>>-1nuB@,F\7{6zyȰmoJu/>vWΤ*-2,f]S`KF2XfE\}-\AppS^Cڬ? ACj2BjƮ ּ5zGjW[TKB0јJ^ӳX[[[[6[[[[G 4TLˊI09_v0FKXC5B~S+}zBWhf>1!븚Ta 9 Yb6d"qgY)rk]A!:>+B ,B­\@51@K)q}7}yM4s&Oӂ'#mXΤ1ZdBn( |N!""&F$U2,qLe3H3Pm1ic< a?a8yqBq`6.`\uʄiJbے[dxk_뫿D{KJ4!{SYW;%], .g?NāPWAЕZ!0*TX#N|R=Jm8} Ì]$&kPRiϵK\fh5C\(N3P -`̸}W|pH8ɂ$f?|b&m=cZ9K%f"viXn0am4" ^`A&A~"c+ZI0|%"2 $5ߞka5s)[Ɣ=QSGbMG~GX~NG?+ 9k 2 ܕk:Ͱ £NV{sb7*u %%%%@k%%%pʯMD0JRqx#Ə_[c"4ʶ-c׼F/bd %6ݚQNS2NA#0_DۏlkFk"Қ}|ʬjƜ,)LJyWP4q<>z HQ&Z0;.[94ӖƉմ5dڒ*HivHD:.؉u>eGC<1(a w؅«fw3Ϧ aٕCƝ}?whY?vt2^RhV^7`硊j0S^/W-Ԭg [[[[$G[[ZV]6MgZ WDVqPFp}]@gfsSƨg8?NF0 +:uǸBrEUx,w t#:bȉK'ufI({(a/icX]-a^r0G`0Z(K3u<;5X`*435fY&XG b!azGhĸ.2Uq?WfNFj ݲ]-qGyur" ia)g.62%ؼ{묽5^syF,zֳף;i 6Ƨ5[[[V]ۣ("]SF1r>GeGPe@Enzϑ˓**Cn1]OuFefh跌C-?S@1! `XwTX VyE0<<$g"ʅ9,$&ANGt8Y:&QXLncn=U#1}@9'E"#q1Z`j( >k.kLSF;zO3YqńsU H);Lѯv`X5 $${ZV)zgd~ue E\f j=%*?~Ѽ^;6/aWIfo l \k Sw $TUvC.'8OO4.>` bZZLcWe5D䔸Eaiy0s6YG vւU(c}WMCu{]%9`~@= B¥,MMtgb0*Wk+{C18>^g-",q2G] VNĨui+xu|?=\KwbLTH;ǾtrFCSĿi}iհLn]%o"ٖw߻`GL@,ҏ ^:޺]H훰%%%p?)T[FHVN4K!MUyURŎ6X8#}EafQfӒЀ/)|8.05 ~46>>J%Z bq M9OНѲ[V7JTD}?kfa 'P:nrx/Ʋ_ҘӋDNWuXm+\fC;=Z" X %IhVj@QT($F56rr 0Osu#{T >>J[_T*Mr|xS3(o*"6Uk;|V [[[[6[[[[wH {,т-۱6lBwX?({ ZÀj=j|#x7|<8V> A6^Spu|Y5'ZOKJ^6ӁsT+V3al&Q6^ϒj8-3.l l l l l]$@SD"ߦ<)/Qr_y2ek6H9V1no@YpV;oo4, w6""p@53fZ 9=E;W9 -L#Tp~4od!=AE13kO 62IoDp&gJe3-i){P OtCk#.K`>[;˚(M8Hۀ\u]~ԧԅ%u4{MZ H?3dد  3]7%hf\/Wt#fK`K`K`K lo–% UY)u?Ҵ ;|HgI??2ǼFČ UdmاWPS ("\9+D"i*? Bt~~iE7a"$3sFɊHGk/~qD .f9􎾌;3KQ <И t(С{x'S=8&Mip(@PDQ{o1riux[ ٠mCVw|U< Dqf '6~UZF;tGp,n0 j]<%n]2de>R܋0WYV0ZJ'q͆r^.N7k6%%pB,|4h.pbYbjE/zl8C1oģ%2<\*)ւ'',C\Ĥ?6H~0D5SAn4`$ZN/#L;2py= PS8J1Ժ``[`˶i|aӆޣƱ0ix-~@ [ ir05)H7ѯ6&JtA4Kj A:鵔]Пk M1/ḁV %9O8^zbQ^׾v0=zE8H`ÿ@--+Mj@| (r"N#?48󝖜Է5 5c[D 0׸),3!( 6;"6n ŒAus{lTa}c1 *<f0#`ɸS9*ěA5d8N uԽ hHmLmARn6epN 2 E$hϒILyE#p3~W@T8XewWWϧ59 "ga .ѹ5ߴqy"cxŞFGO|gIRj\^1/^a/'{ѕ|H{Fޅ----o_---;$ }~t(j(HOf5pJ+5x+4($]3$u?)>A jnIg߰!| kO?`2NDBdRL,8Vw ֈ~_Y !$yaI5kAP  հ, Z-o~סpP9tTھAJenXGns[%,u AzRumf' \W 1N\+OQsd5n$&w@ѼO<9\A It%|') ;j h!G9dvN4O0B|Qb2B5dmy m+<(а,ʦg%<gGY& .jYtg}|]m`SІPjAnYV0ffi8y]y#ຝc\4ѸX׏~^ÕΝb~0Q@ыṷU07#4z܅----$߾ [[[( Vf\(_P隒eۆԢ+#c@t|zCqr|DYhQbƥi>mh1;Qs6x@ F1+@//o^SQ΄==xfadF˚Ɲ".(Vfj Jǒ1#O 10žt׽@aNE6AJa03Pu Z8:8bИҲE Uzv(G֝eGDa4h5( Uhuj%b%$ 欇r..h.ײ :Ը4QTg`! T{ׯvwΛu3f^rc>k^xUzW ~m l l l lc(=@L0U% xr%(cY LJ?L{ӼPy |jDOI8kFL9BZt+F倷 ٪p,Jl)DŽo֦ ,{*hFm59æe/{ kG%9`J6P NG eXD,b=Vp~Tc<)0PTd #9wbcpFG9&[Cw.k\!ԃQ.^?L k,B^`#cwc[I/H .Kiy9A{)ffc?c>eaM q]%%%p %5<--H@ 2)ZpKoj(tPI+ ~6s|NKˠ )1#mo%7YC;-i!xfI|,0bPw}w"IfP.٠(RX3H`hm_s-;C03MjdDA&7 ̮w1=u$шtCdJ4puveuix3M2t\t `[|8v*+@r_C'YE(TKs]{_Gޚ_n~6}C} DQ.)ئC8E*!vdq$7#p H>1SDad6##_iխYӧzZ<MC'LDs 5Hi@0̉S5ЌMQ0 DB!iyPָؙBANB;"yU0qY0&e98q@^GvX+ך\ c>E==M iļX\]ucRm@+ } Yx!!;Xgػx9O5dlj6`oKZKw'V_rpa9=[ 2ڼRE\;%'|V^ eVP61]KPSYItmHtڭ3;=f>`-)ÿ04:<|.Qc@AuYZլmW+T$Q@{ v8u]|Uje ,s~` h!!Em9D\t&VcLV_ N7k6%%p^X/:"o%$+DpBS*l:NGcxOi2ShL^ M)mp Ew6~%olMYd1DKE(!Ba]4}Ht[6ct5 X Ӣ [vJeO]>]$Oje'{ha̘2^}I >Ht́O04=o{;Y5?98ahk7.┲c@jq[IۣڭOFA8%!\ɟIaoXY5 `TPSu7 0 [$6Nu!k+ +2Jc(IUm9a9H{p PGy˾lpG&+5&ʺ0#hdv} Œ9$pxk.Vˢ9S0u]VO @,PKdK$k_դ0!JNR!=C'>MCN'Jϯ:zGL 2i [[[V]ۣ@wQ\uћ=vF@ߢ\JGLf)%:(~=!૿br+3O|Gg}Ri/~hJX=ZCjc(B肁a[zs㑐6ZB&WU®=NFBe`qǛfp2d6YXy$OX1!P3Z[.A 6l!f+P\ 3<$wLm02ؼhm6m֖g Ԏ![1G;ugn o=cK,oAgarf a-i%9af iӕV@]ek8r+`_HœW #UOA T;,k.o l l \C lw }oyKK %b7ݑ ; \/CFiyQ8ʅL զh.676'jql uX3b@p,+EAl kD?k<'){iBybvc[ApobHYJ%ape"~ - |tD@f\V($ VJ3SG-P|جV2=0P#AzE] @G&2IM $,XcFlG9fmyԁ4$}*kFX]ubz ɒq`^Œv](&ԃ E WqI. y`pGJ1 Q^=7rsvtڟz./6%%%p$u8--H Y;y{3 O|5a-A5W_2n݀a %ltt4fR}EYL`iS52Vhk.wi_kc ah 2`G|(JTW^l;e[ xK2vL P|a|vtmj hR?(i 6JN[eײ+`{/Ntr=4;-(8RCa&XUTGѫ9J)3UZFz]nﺝuX@RP 0 ACMh:ylJMeT&'@0ᨦ_sET6 o :&ҸX5AB HE+#$^#H8(8 ߢeޥ4}O2AM=!C'c `x' vN5lhw_T4&aDו{]`---# Yn l /+5Ay#ӀSF]XaRo5sM42 ) Kaeau3TIBх #(ntV: (ֲE_2 gW)$Pĸ aM:E T19 2:_?+a%˟h nP^8LnzUw RX~U+3chmנx٭DA LDE\#Gre4~cBeqmX-[ŏie]\md]CO vEۈ3@T/ kF8>'J&N5t@(1Jv]"=r(Y\9`jvaK`K`KZI`ÿku{[Zh%(ȖPy)[P~-sdRQxpMƉ3\?sʷV;=Fs UrR}k}Q&Fm% [ZAi?+hS@E)Q=V9,$C]P @A ڝ]3 "NMOza!,ċlCZN5'yt`dms LTC1k6ۈ+_8w#(b&m$OdHϧL$0Cq4+y A51]5D "$\6V8e[^ \ȂLp&3,-m*O :,l^/WW27hLCU 6; G|V瑣3zN.l l l \ sK`K`K%rUom l ܠ!lm l l o=-l l l |H ![[[Dkr{[[6[[[س47сLyL&lFR8yMG}PöM=KXoZ^ OYK_ d$ .C6{y];_辚1,ůB0B7ahʋze^dQ,HRb zFzDhd8"b&=aS[w;w˟Ƅh0a),$AvY o|I$H$: 8Yd6~HتLGFtH[f Jb\f hPƑ9#OvM=olG5n\"jhwc!FFsVQ}rʤ7.˖as/Ԅfa;)tzMdԋ&jK2ղٟ)@Sov---[_.l l l ܪPeG6ۄ_~sh(>U[krUTÜO5KPR4 }LaW-rEh"D,LAX"d(T']v'J]ͪ&$EyLvƋ/j|@;@DnN? Ch'QX(#_ 7C–urNyqKZK KrBr^FYG ^$lc"KV OTE,IE6]*iI 46΄M/Ho>)6QIclC+-oi^n%0nmO- fFDTs2TcB:!&v% -niԧP ~LT0.岥Z#a4NO?xх 3e "lq']*A ;Ed|t1UD-f7^Pnښ(뱮#Q-,QE=LF4vK;Z686Wx.98Pwn= lwі]$Ww)h$ .Jwk07~7ip?*şTL@UcˇQٚ6h=.٣,MTPT(}5q8YsFcE)^?gh^3E]D\ys5z<ۀ nگ@nIai;6ekb== u=•ٯ81Ȋ<3³$HÍ5l 3}f;r)~[A<8:kKj\}-xuPRJsuhC08@IDAT/^u~ȵH+P.* nՓC%ue-Px*n:%9e P &`=p60 ;tҚ' yq:2η,QzcrN.+KX5O/E5m$@rӠW%춸Ek[䵭W`*+|wws<-,g%%%aH`ÿCh˖ HQz:+fV AN N=nH9JǤM TdZð6zy.p"FQdiy q@S`'G/c|eVKx}w}Jn`l"uX-HZ"Ra58ѧ4hA`sB&cO8߅S xZܥnUAPo@p/~̽ t o=7S7__`rz/_N?kob[M`h#ߪ W^?~ /%"Z1CΫ'rھ_X* nՓx{ޓ=P-Tǫ2zOԵR~_Pg=J;7_lA|_/urD9TF}Vdeƹ`]9}E 9K4lE O2fBQu!9'0I ΰ 88bƴu+cvYajXnq;.kL ^5SXV$.yUy W/RwD.+".-L{G^+/tҍ0,ژSY+sYLx GPii%%%pKJ`ÿ[XGҭa2Cz$OS&ҝiPCOG; .doMPQRB"=H i#E`p9\(XqB\ FeHo_\I Ez~pB++ 0äfBt}jkuЧѤ#]Y׹Zw". Xz"ʃsAVJ ZӲ=t g#{G0=x{[yz# <tavJ7VYuSe7H?񸴇8C?i [[[6UOvkKZK@P+IO8/GŇr^IḭApcK#˞rk1AU{tmg5O"LLhMM~DfܴrUT}>fR{{8S{?5*ЀYvDT3.|D% *{{k9tp gAE<^k; @~U&.dP O+(b5D{5P1{^|qV/b́pj[W{|k^~X? 4ױ' n3;xEcBQ7%p͠nӞwy++ŝYIra*FMiծϪq{[ g>!1bj|+gꃺޕ6O OYwDpVOqB6bf=k·q{$Fv޳|` :2\ .+bp=?7t]~~zU"5n~q B瘤M, dj(l^  /&vf{&_9Y$[[) uFQ=˙Q ZrfnZq;O1lF,;+jbLCYv^~gKP1}"|FL%!48w*[GhURyNͰAzPcX!̬Ay8!6KڅA 8ÌGV CGGc_:*\ۻخ|[szڽBMP%&hc'!1 \{OJ >_.X0ѬJ*]˽oދm٬7hsи>C#So l l |$$GB{--1 %dža) u,ԋ CxAb[UX5GlȷX`V2p7PA:1FT A0oјe!l'n>Uj4Ip@Pʎ87_.1ur\.ʵ}=X?ڷrMoaHlkg?٥x*n=ӑyBz zV`uWpEksr Ի%%%pH`ÿ[(F"Z- |'i*3 'T@0wo'2Ĥys=0*3@-8Ѓ_T@|]U՞X.8+g*w<-՜ըCm1yL0`]W.VM;ĺ7Hg\d{ .sո$ A U8ʹxK(kLWZi6 @}ҏ&Ue4{5TB#{/]t{TOcU 93z>??̡ypz;>[[[6NseKK@K;dQd pBVP26ci2MTAR\H̭~]LW)RG ,<}1(YGg;T~6Y&7')A4WZ嬗" ʫ&J`uLr{Epznp}{D͉ҭ$;q/{oRw2IURĒT%eʀ"%сap%$ 8&p( A0HD 2 Aܐͻ8a^<~g^]kZ,3m]*+^qmQ%% P/ڗ1;&fdu1{N\Ə)zWFȩWp0ԣ&i3Y_ l̿rȦ%15qPw{ߛZԤ _ GճPk APcN_ s9kZomfS5Tf"yQb"L[s k#;NLs %fqpj#N(Vzj. P 2J1xc>At&Y>fKuS`S`SW?gSRFhYF#jaLp(fIˡTM k (R)(q{XIcZJ'ZOOy9EIɟhd?TRK3u@F?Ss8p d5VEX,Y0j(]֣h^e)Z?h!jh|;b9qAW\Jp2vr,99~/]Y ֞,Obi[꿛&~Mo~^)))pS`pS`S2 P:/PMg_ɽmMk&HozӛH$EBɀ:{Jѧ>%oG%w0ZdTK M]3*S9 MR'ן`Q-oy%b z0[=? %OU/݃Ő:aӹ H嗥΂ "i9Sڙ=]Ţɚbs"e1NV@LK)anoiNw+S9SʮJ:/څMMMӚ[;}{_@jFJ:RA0|-ɏh *&XH%!O-A"f)%n^}rI+!RT xU LP>KF!я|#v$Z>/6oYmS_Nou|(knWDIϩx,5oͿaF Բ8x R2`}BG3əO&6TKbڟ{SY FH[1^ ud t.o l l ,]/{"qL* ֢"|ID*5)= I b1x1$~8=˚ xj #p87@!Ib4<^}^b|;{S{J[&+ _B-jEqOKYyU;qkL ޲WP樺X/WL0XXx; jKbOL^7N 5\_rf k@(ng31e)))pR`n|S`SUgRp饗uN⾕I91/xD TXj סhy˛( O//GXVrܰdXcs1-'=IskgHOJD&eZFsb@l1Ĥb2foX|dΛzc^]8)տ?)p)E 0rO|tFe 0yF-8KF Zwaws6NI Wd7,3<% D @Ѯ PTɲ/Jڦ1e|J~ 3[Xwq|lMz|0hKn3.l l l 8Oyr%Dy<{V fKi$,kG:   X<$љ4PlQ)Ҕvw|uJ!m $Rf7ht,{-WK)0$GD>+q 5Ը11cڛ5 :ztz8kf~OG?1S(GA")'MfMMMӚ[;}{'aA?6l-)T~EqOSJA1^W-}Ϋ]4]zW*GGBiC%VI5/-9eA6 j"8S/ej¦_)P2`m ԧ_ To8XJ6i `5RDqnX91#2A&`׾l+ninq l,9]jr666Nk lo h PrLGZ@$% =*邤Bԇg :_ZR,ؐ6)]n!(6qBxի^E1>ɱ)pKoa41v?s.Œ(<3piɃ;t؅Mo{Vf7A@c|Z2QᠶLuЇiJJLJ?kwn^XaOLcncE]1,n \W9eEK[M=G)))p:R`myS`S2 I[˒GdL  w~`*rL s)3ɟCCW~EeP.h_*YO@3Vymo{۵>W\FJ)d[eeq]ܛBKvt>p R e #1]4pTH6F aQ<=@>.a# *eVJ.O*6WC gĦM9*4%0bnʘ"?& QS CubsdQ?sǪMkY +`~X"<=N( D2|pl;W7W7wuSx))pP jcY;*GOdQO?*=ѐZ~n ( 0H ~?>S2bj q;Ƥ1,S贙V*juSSq'Z) D j@[R gƣ}uK[.ٷKҀ:a )m0?_]w㴥/0mzTXl/6&WLdS`S`SVNӞJh%&52|B>`zhLW-.k! e^WOh-J]&) dΐ&S Zlys^K,c)uV"+TIJ1,.b<+7ME v6$p¼^m@@bjѷW}㚤~צUN]$n l \(;;g=Ys)`P;w}wiywPF?(.4m Yp!/8T_' RQ+9YƳ x)QSBG&Ɗ2iW; 6瀣:-?U)ˍDzд= x`X1/N4λRtƶ`[Ąo,|Gm,;C 766N l?Yn l Jڐ%#*$3G}4~G~D342fqMn))!SpDG?ѧ2}c뛬l-PSm}8pvVfyOB̅):QAI'/o~3=.G=+(o7fdI);'Gj[F1$& ^9pM]8(տ_')p)/|g>RTwϵ ,Qsf4On=ys%]z饉}?-~`·o|ʉ'ٟ>aL Gɦ=_^xaaJVV⧞:15;Oى^$)Ng+8"-N4+w_bɜuYLta#=k>n~$>ܿMcNk~x-/qq\)V jBj b^M:nVK@;9x# XYǙ=6b<7jt4G666["MMcGOzI = A'p£W<3NF/| i" \}{'1WL)ݥ2~NATcOuH&g¦1=| *Lm"ӆ%?pN-a)=^-iw }t3G>rSVRI?2":Y d Hb11GHz֫y0 Dp,a _0Z׹4E)p)ЁŮȠ=&gC"ùYxH*g'M, 1YX0>lƒgXh&D%f[MKQX_0i(SZE^=MK%d]*8'1dOc!Vzr)t@l9_Y J,6*Ȧf $&Qb*U,o*'i`- f@h{waSR-LMO~(nm[/z}9a$o3LTRy dQb62{1G?zlJS  w<7N:ݤ[Bj嶷GsWr y:Gc]Y ԏCQWIGK,hԹG%r㋆p) ABcdVr 3VC&=)ʪ$ynx3auP rNv^cձqXx28jh/Mi^  w<7N4^Ҙ!w_!g=qɋ_/K/(a.hD=WmƠGHэqp-oyKm@ je:'eoPVcZ3v8NcHK0zt`MRtH7M߫4̃CQi*waS`S`SഠVNӞ$l!W>veOvg2aG>Q. gP׻t'z]&L@ٌh38C/r;SӰj+kl0GTmw69 'yb/tJ`-bAHc.,?'`-`vL: }ƾ1Mk׽ }C$QuLo[ښlP]8n t xI;ȐϤ0!$U_\=[_4jfcRl'>.ysj捹& S}.92))G`mLɘ`>ox ˾f 㧺vlzջ)p)0ֿp ;j|PL"2f>5~GtYLbXly'#Z̉C@[MNxB]{@/xB%m}81m t XR& !>υrppTkEtwzD+fAƌuhvmaPax/M .RXsg=sIg8ӛ3.l l l C lS66.! lbxG೛)!B !GӉ "Ʃ]׼ۿ۽E_Q7Mܒ>*CtT9S^Г>Ssow#_ӂP^җZ1W?gL=8'!o|c݁H1sɾn l s l6N.ք+r{B=> <]//X*@qWvf**#zEvE\X~[}]wݔRI{uaL/jWd H`$Υ\49lӍ|g*Ⱥb <δ5vO X\SyAl%N=~R-ޏNXC A6ۈ7vd{1ՁڤE/7}^s=MJMcNVaQh\Z^8E]D#)QA8ǒҒ,ɚ'"h$Bb_2e޽u[8?ԧ({8066]MoS͍8Tl$ _Bqt܅McN8kɢi[a&lSx\iw j A*pz6:o/`gÕ3uѶg](u9][X&c[5(SA'uM{z[k`S`S8R ^` U1ulO+U}l 9m>a#_dD&;;e-k(4??ZAw pP?maz<7&_м¶QO&ea9͞Ӧ(P?XqIq-{K==P͆ᙩoحS^a;N9mNpu6Gm(7"Fl&gcqK0 fQ](;]Tx*MMMBĞǦP*&Y1,+]H029t}`9jltyw֨!O p%TA׍U ^_ ?˛^Q2}Np$6ɗeuE77d69ʃҵͶPI8"=a8eZF*oj0c|DPQ(`9(𾟝"lΕzQG0yrX:Q՘mP> ufHm6@}?kOoS`S$S`'}SR 34?9V:`` _j0 6T Mo2fRhDa4yKeK1ES A4+gj/}}b8q9m d E'.:ˤvH)dv;;e2(;CqGc1#g=Y*rLk\x-ɣ~]>eߥJj !)^.C!}^8pv)p)0,fZ&YO`ޚCZ_ Qk?W6UU1r=[o K-dq"lTkK66j#zٲlbuMMMcHʞҦɥ<)CE䭜*sL GM$3;q4:B==:@|&4"b Ob]g@SY.d'W:.l g  OŴ˷i#9ysw<1NߨEцƒq40lZZ-D=l^Ygհ^l2`FY[x?61[qgm l d l$o ; }ل'pz6W*9pe`OPsͦǿS3<ӐVVjh5[*zP mC :K/ѫOBL%րL# @aY1 a%je%L7HTAR_~:,cK[߳QjW{WB{bb:Z:FgITؼi۸2MMMCŞɦIX-Jmo{Y-ktY]~]yК8LmY&HM@?]ribTiDk햫9zL?Fw|ַb6--"xe'oV홸yS U~0Z&j(Gmyfu@f ]dؘ4IKR5G>eBsWo|ؾbC]8>_l t HEl ->v.5WqzO%=yϫoT2 03J'h={Q 'Ւ##lj`Kݪo&\p^ַU% UU0ǹ#z kNlź;FZ=e>*V>jR`-:2ȟ{W,ȰI=Lo۩L f:i4oZ4<s,:g܅MMM@žæѻHTF(%ih\bR# MS^TCyɈ\@SGc`ɣ38]@&$>P%'5)%B5x$׾1 h~مMcKYg[žۂzvsGC4`-§ w^Xz Y^#I.sCskyh0 (T$h%|sMha[ۅMMMcBĞƦI@P)#DQyK  %J >}Lwbb86,ͭ; D#P o{Â֋|jRceO~#~wX^h)p(׊uo];iZ&_8fnη`#0Q*JPfxf);Qphұr?/UO uKM5QyV?):l k $; n<`oNuv&ַuS`S`S8P`῰)p)P̛ &82‘$K(v^9!\L'GkOJױd铆aAj ā@xma= 8wgj'ywVY|h׬kܼt6Z΢v JK=?g1 YLwhlVҴx )׹ʴ^-/(ߘSՎwyќ M.OZ{1$/pG)))pS``O`SSayB*QPWAMNZHu#C++@&R1J`BB//d4Z60hUB fsS:nx6mzAd,uݒqvySxR X 8*nHC%ԑGiEoa.#^qK}c Y+/2ѱ>\j%L%w,p5 DU]Kg]8oYEq4[0jǘsB,J|px{z0Be~myzp[Cfub6%L`<'`v?*\QMhS] ջGleMW}8q/9l \ |ӟF2!׬le}C[ ^SX9yx_s)W"zDTFh9< F!Zh3%n ߢzɦUM*a=A,Z3.l O 0^Ԯunp-6=POHE z'wn2Xq5 \썼:GiPzŴ7վNڈڑd̅+iyDζ -4)))p-R`"76gKOxqR$nH6V 3šj6,%#kհ~- JS! ?4h:᚛~6#R=e=124[j&< Ǔ _b=;KZ^hc/%ܣeT֏G;L:'_;%rRfVBٚh^g??F<ltq666] lڥ~m*/f\HrK\aCBOIZ@~]z$6v vWX ӃS?B}_L2{J;MrP4SRȸQ@Ӟ7%IF4XR*e`64be7LZn XkαC9S7fg%1W3Z>-S&JjiTƽ@6l 6 g–'p'>A#QYvT>z+lk67 n涻e_766] lڥ~@p=.Y)8xӛ-O˴՝r1 I+ * u+3HfIt?g_ntZԿǠAԤBYV D(A!uԧ>j\җm/T(80f![U?S Lku2.8 쳊Y J 0| CG/LZҕ ט=ka ǩP 4lw8;͙a} oxCX!i}w^cOŹq܅MMk[v߾)pr)ȏK fR"+pd>ޒ?8Â,{ ㉃iP jsfI>K2(U/W"fu9稡ο ~|DɅjMxcj&$6Nn4K:؅McHqb-i ,ăzҬq| &2H}4,ʕaҩ*]eNs"eحA9Z j&|}p,oCEMcҬlq6:Omz3](տk'N$<jyN(қ| Y>Y pvYCz1_@IDATT>OWӯ V㌮S܈ >_aSn/jDٰyJ??zݬ@&GN]8(E;z,췽m9ISJ˚N0 8>-e~ZaLܲnҾC/:fEG%`+r/F Ox8.y!R}[>HeRe?D!C4ô>IeSj]߾˛NJA_Zi}Xd66NwrK7} e щnetwI py{ު/"|'"RcX@ ze4v`QtEM}4xDF__||OC$pg `|{߫%A Vvs ]ױ4vaSPm-`A_:X}hs. v4>r˪W/뗶]GG36B;>QcZU.7ު@ۂf 7f=5'~'G Sͅ6xtwyS`S`S>v WheF@wErvBjVGGEأ%d8Z=u.n>D)Wf&rS= z(|A5)XSx8BidYDc1njpL,B#8pʻ)p(`>YUqY+ݬvXK#ʩ^ ͬcbXb۵WJ$#چE| $wܠ$1/ K|lAs e9ysc*ա#d3a`GTLvyS`S`SէY766V BYN+Rɹ<}l]pbT 5Y~}u{_pżk LdOKYv S_G5؆YBxSZ*\PJl:J.g3.l + sul4idJ̱fV>}oތ1 ImƕCIZgihԗB=/42sʆ36͸",P,/xpr4F)?n 76L,~7эQF"Akx^J+8Ӹ-w빅C?C:üh?;yTe<˯q>FĶ884gR, s+(ɌUj|~evq@p&-9h[ҿ `1"Q^\T>iOS#Wysa:vӎ%ž4vök,o41\WP֟KKSI: F;v7wٸ: *؆W~W H'dؗp]yk_766I l~צɥxd#PbJXsx(E[]G/|a8X I tۓ 4=u,ɋ'&7- F#ַ$=խd;p BY;"it۞]8s;vL-cVXˍ;ֶ3[Ѱa aj9`2aKS)iV`OO[\yƕ.NtX.eH6YQ6'c6N+emJ@oq7O /vl l l \J=)@LȺ e2VWD7N24$9fF03'S/NixzcKS?ZmiJ]rGggk9W-O T}lӌ[ʭZL}i)]yi@L(>\ `~vaSP%zn=M%T~n;AHAt>siѪ)208(=Ŷ [(]0e%fp1 Uޤi~SښF#chS>H4AwjdRg {'\P=49ԝWr_^ (er?[ s۷~LR le pXXZu[4@sѰ[JZ-p]6VN~9 Vu/9zc4vb`8M=%ՄݩӫLz=?Vy!vS`S`SjV&a76$1ɉ| rڄ4;sk#S%{Ly2Y*Q)7 ȝ&20dw󝍟 tIG&&Y&kjK 8U?s;po7u v|Zoa7I)[ЀFDÝE ݰ^Om/dy;ļegi qh=傾VVI wqB|mJ4\C=v;G<ʬM}YMMM[I2?Sm`}.ɉԧ>ՑyX/"GdpY/z8A"T伯}K_ң yp?XBE~6'2N.r[HytL9/)#=69eTIh@RMWy.l \+ 3d+p.C}3M^jJణ8yS"sb(Vcy0nPeޭ+V2MK6!e,h 0;ntBJOgjwC$:쳛F^6̣5W9wt))piq`?ِsJ2bGθhc섞z׻[DAMLwZ moK(c<ɾJ@1+*IxR /cl@`$E f K rg3_Qڏ/6+ cptkBVѲιfW͛9~#`oNZ9?&w@7xJo/IM2*{0})))pP`W  _C]ruBc $J^&8#uK$69!Lo}[לWKW;YWu饗3 xFՆP`I qrzJ܂Hu93M,W21dd^D\'˛.F qr-J%cSM"s9ic6T/| Ui]$|ZtSIqʛTmC¬54ButRJ^zTߢ<֗e5 bo)SHHQm-3]j)տ{MM( Fd#ρ:~|RDP<єrp#݃:r@U'֌'QD̀)pS fk5r-pW.g[&oF<OMuWb&_zqNbtӲB"[o'h >hRFEsn MGvKv~~ l5vAyh6I[eJ(տ{MMR@KU#Zes#%'ٮA_ J24yG;z= >gzT лڙAvBS&JY,t4)&d%hqqAؘ=ml0{^¤Ʌ)u\a 4v/чA |9K m:&ZY:^x-]ooQz|HaO|`.Ojp>%mWl%ݏ[fCad!m!3lLc[w!kPK۝~G~~:9D`|3  -(տ{MHVv#YclkI$FQ MJFs:~VeW"S~S3x*&v3~уG7tӣ$f47ګ'cDқfF |]<=oQ/ np5$Ka9,˜{.o \[[sJ*YY-lR/&FhS/ Wt^FnO"RK(i|gtw尪M(56sԳzav5t3Av6*1[M틞̯4 f#HO'¦V4vMMC Ь_Hx[<ά? ۏ~d&mwAPS*AfcИXcx[4]??$ޘn*Kx` ϔl*leOPNBf l|5o#+ "EF``xzJk53.l \+(Ƶe]US{_ezT,dF:b(l5cQƫQھM cs8h`1-GlM*f*5a3i1QWΫ~+xӶi)o766w%l l R'px;gJ@asN g?!y={ =:ң&sz/W;k`XBkX{݁m|p"]Z/kszMs&f di5(zMPpާ}y6E pNf%.o&ۤ=ob51Ath^xh_vLjg~7I΀S(g-ej`WWp7.kNlhg7*Jګۈ|{e°m<v:o߅MMM[ 8ܒ ^Y|x w,{t Be83'q}J;RbM|fsb͡wEVzAa@ 4O =/AY8,pLD7'> " me-A 4т,g BgqIm&a4D5 #mrQ>r;;Sjiq=Ze)0M\aSX9b])t+i[jNo766 l[))U j'0]tEp2o\WǒƳqmn04YD9MAK.d^=#QC"c @-4q{԰I?}E1BγkB p&0h&J>mvmF-n1}Lʑ3c%Qt+,pz¦H2+XR Ĥ,J凯-㱷[͓ heVP;b:oĀ2:dC1|W1X գ^hc1R p: U/a67J ),8(F踊B稴y7 0f)))S`: _"%e" _8mnwsKdD'wTR9/X++;}O+&mRIĈeF8z^@k_>8˯|zR~w Ok KX/ư Gp}W>$H>`j&ĈWMk؏h%]0]9Z-;d&ӆp>Eq0﫷Մ9Y9fM@ܼl&S}\ÌfI7]k}1^ٮD?OZJ6$syv֙.l l l \%UB=ȦIsw0D!ށ(,1H=qDIg#yJk :Q'9Xh~??#Ok^X@[ߕ Zj@GL }cF( !;tZm"ul)3.l \p43 2\3)6 tKZ҅R 2#8-0ݼ4(e?e26c3oSL:/%MP}pG5@{6aj:r?LlM&͙.l l l \9 lm*o}~S,xL%qS8V0ځ:,Љ#]"x[ F WRcR)cxLE_%]h+ #(؞u*؋{fX0raW Ӗs#bftJMks4=toebm+ŜgyszQLkK1; "8<=>7 "o򔧨_J답f/:c)t}\N/,/yPWH^1اZmt\:ç|6ƺpV͜lF4؅MMM+A] ._/JjK,`'[zPP\ O$gTOK"}h?`f''_WJebzԷSRH%; 4m!7|oXUU2duK[+CĤ[R< })pMQ`RYDb ;"kY̖+g3OjbjWCA4,X/4d}GZSwlP3`lnkpv/;[6"<:qgԧ>U{[vvK6rNAy ޷W[Ҥ76.@86ޒnAq0 \/-QXؒ)kvz/| cyU60"ucF.>RpDGG]% 3ޮh^"BKSuўgr⦨+vyS8>,W3w+[Ҟe+i`կl_:et'–=fIƕ<عwh5/ѸVs>=)]>H7XM &W|-4gaL3AўYؕ) l/ExS`Sk(@Kh $>)o)Eg,{#(M˵~-ݗpI_XjkkqS4U-{mWeJKK3]f(UaMEۣNj,n1$Ke SL(AWR}(򖷤֊@ș 1C&K|_tKIKmv{xojv:DKYBXӬ0̡QL0^y.A| MMM+A] ._@yޝt9猸C~hs[塢eD^JtSFb8^hͯpy-pO3)O汜F !=I1 DMI]}ɻ,$dv^A ࠆW{y)iY0z5OR5]-bV-J)M,L&++2nWGX:;3 3핝SLy`(tVZΛru^Mo|cpo1fq>,mJ2!ɬWptJfS`S`SS`_>R@Cq&2S,p/s9Ě{Dh|{[D 9ؾ(6+^Y[mEwG[C>lt\ M e+,ݏn6O)Ōx 7 baWlGZ]d }Ed4[L`^piF޳n]c޶*hv*jC5k 8qvyS`S`S/Ke)o l |ex ׵+E0[65ypG7`ȅtSzo•ц }KNCP`4L!C bO|bo't ' ЗB[_!PNU+DHOӧӑØʜ?Sk?Y%t߅MklS-[|b@`uS)reo_ְO1`î1:bY-۞s62y3uS&*uSCPDO^(9eJ5@*-֯׳l/MSiъaSuj|dUh|s9_}(VѰL6YFh`vPr$SZ\S)n=\Oy>aP>T;ꪍͳWP|M: \!jI7I}66JM:W,h3L)c~P0YϿ m6f茟Dw7)2@n:/?`h9v+C^FʹWLJcɣ,u#LK.aո'iLԀQ"G=U03.l \con/UkZAa҆?vJ 20Pobn1!@}~]ƉZv$p/]"xzÉWOTmT\gtt;MO q}`'A kgR*y{WmNl“ܑ.|`z{t2fS`S`SR`ߐD!I!6@\ʬ#4( JXK5D"ྸ&H lݢMEQcvRpQ3Fe܂ϯHz%}b{ t%12,>bN+ϵWUW ҵM nY}SvY!=ӜImRdjj0%r < f]߲˛<j8|&59Z#(<eG԰md9KFQo˝,K[*9q`Ft@N+| ] 8z#y?QұXcN-ȱd}=dmkz>o/?>iF ))^"pغzf\f)p5Q`bʱ>3Ő? ml^0t7ULV `m o~z0c#k ;^I9joJl23l;ڂlDh@'b)lDd5 UJvȹ4>߬.l l l \wE_CAS-׋+^֧S&'5:~ q&cVPSS&Mu{]e_|^3Mut f~c',9D0RQgSe- B5R: W,1; j,3b_Ε[1š1!NSiY-i~7鰞[ls8Y//iȉfnyzez{ףpQ^CpmJ(,`kNLc6@65C^ j^J}M}g_ `vS`S`S`VVjR@JhpH9#LA9&498ku|Μ@PPQ' ZxP`R 3F$~XWN0 !=S2kPXz//4U^$!> bk`Z4cBG@ t}.o \xOK^rV2|f[9{{4- ?B=+Ec O[;0{ISA/\ 6c /46َ5g؃>Jln&}ٟɟpiiL3]ק~))p7o;A$tN<琾#rZ1Xo!6TB55k^P;) eFAEwtWG tQ`pЋqcpV}@ӵKD}oW8TNA 2[ノ~n_YG\y o7r Ki)筀-˰tsG?h1[ҵcH܊&Kfu?]*dlW׽uTPlSwᶚNdp}+Vp/e_+9m"\^wek9% zPL*y})))pJ ldٕ_C3G H4rM3`uY "a-6b ߦD,i V djE~0;N ;̞bGQ#L֡bj[+21<~\*vkY5pqk*ێ&;,8y\߃_!oyzp7u ,ެ8";D~]-l],rK}f⸤y=-LKlH 5tSHN/~Qm5` .gRf)<яLAȚހ'wƘ z:W,BO 2ڢg]7$n)p)P `F{#.w]"/P"n.ό3xwGi\q^}SOLSΩ򔮒F|5I%C]h 4W9]ӁWySHp C5 K0o:GG=WH[l^r;ߙu/wQؒN&K' ȀPC׹aا JDkӻ40fM=\a<ٍ9:rVMm밶ɯۦVN٬r(XwCmkdsjD\*:Ѡ6[}'ې%cW¦7V!vMM,7T"K^ed&#WH V%\`օ C{Cj+`L{ғt0rm8B2*h(Gq$gfAAp_ rT%nd__9p$S9`YNԌqh8#Ws6B XZ-ԼYx}c; BD_l1v5ս11V _sv?.%2ĉ1U/LBpZW&`[X++@|NZÝx؈RlMGGPFaF@8yj6ߔC}B`xr̮X)տ))5 uѯ3xRfq%x9w+#А&7~*kfRm_%$7/µť^JrnN4C A;R|~7 1x HFa\3@IDATr4-+phfB׭29Zo-Ϻ].4=Ow?o* keS8(ҵTf~=s93k>r0b1V.liYi{jGzW*9񨓧d63#}U4~t-d5S'o|E~WFYOt_ޠmaosFռ}666um t D",EN?t aը%AlEհ%ɕJ :tJQC@ S'b+HZ, Oߐz* XTy2[ls2`ijj7k3Ƃ)}l26swLi/u̎M5EvaӰu6b_{ߗy L buԬ+:Qz}}LwmXZ/:.o l l \wE'^,(EʅE*bz׻ޥ/hALc"PGCY򡏝0p5CJ~ a\"4H"uI\ -q0`S*-5@u.h[;/imJy}T M&yDSIV 3Ł`)\*DKu)pP`ŘmYx)V]X֧2uqUb16_KNu]ZK<dm1Fe3)w~XنbQY^A&+:[)nV3Wzj'6X!Zi6T_*.֑BQtiF6[ :.o l l [;%YvpA@6ޏDat9֙Fw͠5D/#ܢNi33us 53Dg>a&g1E/ Ʋw'^ڦ4:FJ#ȎZr$fad=Mx@OZl$ؒ͵63])0SZrw,R^E I38cޞ[%뜠52&f.4M|wխTg-)i@) fl[EkxMI/8`G 렜}8M$9ؒ74V>V89N`'Xʯ@–GQz?qyw|YB#Kim.=\&39 ٻחۻ|P0X4bMVZZQ FkXhQDVV!h)"ڀJ! x@o[ku5sαylI*?OυWW8- 7yA$~[V->τ ǞQWBA" sl l_I.X|` 'v$ML@!j_P| 7!pؿ`9O"~(Ry֡6V$ ]#H4xk35%) ?6Ԍh":ȏȵ ZH78@NGk nzkR`b[jfcPb`KkBo3'+H/}C3)@MF4z?^UeXV$ޝlT`mp:m+ʸ8 rkeoMTU/.UKo'm*{Y)fL?ǵ~P Cb#%_#Ȑj%>}++X9:6m%VV u_\3)a188!W :Zo;kfO-$@ъ.fǵM- GDC+,RC T7n5=^z5!C%xd:+3ܡ$u8ϥVYGkfbx# O{~@..  )$t16 +jVFkC=Q7kq{1c4(мR>p~285Myrgz2ĀEkNiƵƤ\D}򓟜ư% * 1.YIAA5Y ^m@1JIҡwYr954[Ͳ1,c+SJOG}cW5,+X>a\U\m(x.~żISBB7;bbWq$ sqTi0=sLg2GeyfynVo)WD|jJ-_*Q$S1g?0-huUsNc"sO77͸pV#w24!p3%|Vb!6q<]@X_{& 22N|oQL?'T9^^w dM{ߥ{{@ӹd*ML5zQtMU|}۷ z3%k;Bs1(סY־ʉum+wSr{M;8UεXw\}BR9ŚNb@'c6l&4m|s C!?`,³+'@nޞZ46 wN*,pB0<) ( a$#%tW/c9Kh OMQ5#@bJſ1.FnT4hcEJ( Z h"-|=AIglR_%_uYPХñrN؏7ߘV4.Rh-zU(IYߴvU6MO^4U?*[*#si*Wb&js8_3C85B E//ͰXnG`:ũ988cp p JU]TEKh2 ;GĽ[j_EtЗRsѺ<|h+FM8楍> O:5 6N7nh-W}Aqۀ}M&FшrUoDhӺA3̽j`Ĵ3Hp5hбFtN@( p$H9t;hcXi̼/ iY%r5\(61udt1ɕrݸ8W;.O橳*"պ(;sXBSӫB;0!v+@`Lx_P1ɅX-ۈm@@@ CTrd#&GO`H ey $Nj6I dlP&OD}/WA%#BT7 BWZTڴA<Ή1"NjG FW Dз/řB0Pb)+R)!L d BWU-~g[ %f7mXvp+ +"'1 #C{X2+%qtw1qשz{"--,fE3ag`_gG iS2?=>y@xO{! q<>(|h5KC }eRCX<,._ɧE=/*rsTzqT%m+$) Ѭ#_'l^`]y&7Y:ƈ'Omʎ~f%yV+N},N_똧| !PУnCl;ltΎ(CMqwZG5/.Τ#\hԷ#Ԯ)45S(c[$5~ UAhV+kB !l+y*C//W>W6+7g]?K:'=M?| C<F8C,BP0<#/g#ih.H(TZBp)5i5F#"|Ѿho| *(rPjdB5_5bw~{;S]5WUތ_аx _aFv::s{*ĨGz6!Waf1Z~v.W6/ԥ7+VUc91^chCbSfA2#E _Wz֏ȧP4t=fOտ;t:G.D6]`Ky@$l#hZkfq\͸ zW(A;cXY~"|: Q+Y[AOh V!sl're,6N@&wt`Hc6w~LxE^S8ҙR7M]*+[n1$WZWKǕzݵX6r<SSG_I!,:4ZyT2$vBwXi#2EB UÂm]ֿT&!H@n(}[z p d!pؿ'AH8v$d(=b`B2_dc[$S]_ƕy*bt+47㎖c!W @2K Zf Of:V4{bX ua0V/4D֋nDȖvSe#5{?}SN8~O3S@g5|/s +tix;t_;PScGw50v iO)ԦMƛ:ާw1G:]yX [G+9#zeI /~PŠ^8ACհqx[9MWEֆ6=ӝav=!PTO2sBe_R"!)'PC6T^Mo`)_ &~]\{o_%=?054uHL*ƌX)+)/pČNWgWX w)jsictj(A55ƽH,<P'pIÓMY4 K̮ WY?Ԍ !+=so\`$k RJu\r5Z̰]ih)IaX bif̣ ЗAWhj;HʝrCM8iؙz㥎(Ah텲[}3:)@#)?yHQ {-+st2Ch@ױ-^[GkrzY֫4lVEQW0hjuag>Ԍt-m܁|= @4\t*_0lXG?ZXZ2M :MTz@/skҭYzҟ̂]›p0m _#?}p;\pPGne+wK: ,3@qӠBjFV[:M3 VO3 _?VYv@1' a֟ JU|73#a 72cH\VNh=)Nf3N;\ߛ)itA%2ݰ|{R jsaʶ:ͧ׼G$Qz u|~xBWҐ)hE`7[/p XkY`n<.b&UrTI%:s׃jF_p qbC\]tFo@)7ZH:5iM" adh;ul)[ +(+>@q^ nLQŘȴA_}˷|KƴS?GMt<)Imy/@y9D~-f\eQ n* ba7~d5L!fNSS~tY}omhbϖ($1ޘ`j@)%`ֹwvLxRd)c =[8|)N@`VdUL3B&58jWͧw4Gp̥^+{KG)t[ ˥Es:.ףooߺ5Uyz Aa2(0N=N{y{Dj\][ &7PGa ՛B,A ]*Dsnq<'<92wӅ3H !J"G2r>r6DF5hv+ur+dk=#X/Ds6SU,umF>R wĤ=Yu­|-=^L"ݔG #^}&"" Hk)$C9 KDkyW\2,]MGuS~/V>1i* |XMp9*{:$,n۫leЮ5Biry\=0;mάd+8f0;H|l^}@2WIW<'Tf:nC#AeU&_f![@^-56w_b CY`@@)@Oa; 3W>b{N&>#%{gTg& Pܙ/N}5&˳n{D?Yi!eWByyȚPcb\+ղT{~+!DA\ u]kSOO "5fVl[ڣ\*~8֞a9QP^V#Ӭ q)Eu-`-mZj̡Ωë <]t'QՠZ}*!Y,͑0T}șB93E+OOT+.Vj{:nMGڪ M̜ Zsw[yDl7Ř^0e^۠T a|=8xj8S P@P@E*?(0Ң'R4)񁁡SЉLpD 9h<[#'8MAQ8`ĸ'їLLg&RŜP%S^y=chAz2JC?`kQbOTeqdZ_9v4F@7B MX~eMyOBqpveG{W1KVX#qQ2^ŏf>B|\1mn Y޼֌SZrR Ji1_ Hro @nu`[~ \4}Ж(9렑^sr9pfG}}ӟn#n٦>_^aj7 Vi%уmd~ʥ1^؀]f{ 9d: Y~8H]~1݁#*=98`)g)sJ,KuŦ^zzM6C/n}1kzM!˅k*@#oHiRnƼPQ5{LD6_6_Go̮7G;`fq6?8u| p BΞ: H:NP l2"~Gt2% 1QA&MQ.˅pL^uNd4fi-JF`sc߬B ӀcN[(T~>[b@cj" ^]]f=#Un*Bq59hʨdJMt/ ,JgOعib%ܑ` yܵd9ܱy8O܎ Zf=8ؚpӧqʽsaB21{ݕR3[΀V(n PfdxD㶇R˦&kے`>i k^>2hp;2k8=?!(!p&2AÇ ulp %Sܣ~ IQܦy)*ʢ ƊҼÐC.,1d"q&I6nLck3tSS2|Ch8Ez5eߐzd"e$|uS>#GNf݌T"XwiLxe:(;%ߧӔ2J?aמ2>Y<,VМc0qg{ UGс֯A;ўi0K/qԯ/BzKTZwpDc*Ij4͒hsOTLݛC]y/d1Ҟ50O89{MZ5& ^\)C@e]hz 3O2+!0Pm@@@OdkFޯ> #TI \L `Ku$FyF%BhIp3^{V14MNڻY/P`}7LwoOYLW@㲉UStc֑-i2Cx-GKIwP8֒W\`ŲA,UF9ǢƐSmuSH5t15$4(Ip+Ԣt:+hh0w9F \%|00uX۸\݌ 5P׎7/ļ $d'z)WI+J2 4^6a0FWsfkGa|=8x 8S1E /*z:%n@#quVWbe4.w}݌ '{hy֥ʭ7:X#I[ Ym/ߧuXbf!kʉo&w3 ^|=rm}MY!pmUBN]-Z6fIde&8*q蔟΃WDJZ`6__uBr }%1N$Q5RP. 5ҐM7Lx՜..l14z ?IJZzkmj(t+jiu|L,C`v[Be_J`|lp~QجܷW{%ԁPDl QEF.K|h}^hai#S3Vp~|-'Ϯ ŤҤLx{kv@kBDR?{1~R2EPVk53DvYcրx3]{ƢFG,cTuĴE>U{zySx!'q*ҍSu+lo?MU@q8|rmL0GWh0KCj1#E+smSᄦګ(FtR<,PDGjg`]h R}Mt=`>TogmJ̹8헟3y8d ysʼnR9ip3V$VAg;GA '$J,1ED'yaĩT→:bEۺ=E㒤29dؔkG OvZp;NqA@̽ ae + |S1qtH|ɥ%:x p uf쨫tuwpA LrӄEm O) #^YBu}LFӫXF 54%o G7 f/2 JZc:} Ȇ6:Mqyk|&UcOm߈֡N@@a^=v y~ I]?-Z|/,xT~>nb(!D])l$:2buHw3fxXfQV= wy8(%f*޺cзx34둀|۷}[Om4c_ltiŸKڼB"mxv3Qp<vl/> gtDzx V$=\F-n.\IRvЛa:f (YJYqнw]|k@Wfo'.b1̈́3 Y!>v*hޱ&5@imY9;?Z :Z+ u{j1· ++k>Ɖ,rSa.w|BaQ8~ 7כQ,4_W&ڗM\^梭b16ʩu(5@`un2`ׇʉ񴆂!*rL3Wf߈`e1=!zyTq"ui\7bh8ZH>??ɫC1={qdh3A`Nk N H٣n. /Mf>7Ssy7ݣT^i q*)un)Fr-F"SA7rvԿwi $)pO3F.Dan 3^[eiy{:_K CS7Nl¼*ƫE:)8+iLEᓡT Tu#(6DXOB ȼdGly)[1bBE)Ї>ts*Sl&/%}i.3s1R5*O0ccaFqDwj2JǑ3aN XoFrLCӫ(U'PGi.,yoћNd LT1kZ[A v ʃ[HrNX-:~r J0c`ULQ;YvPNUg²$úi*Q qyom;GֱvPM xTMe5p'@sߓ5; z\ BPM ڬ`+ؕ'98x5 pؿWc[܀exd_T}3jÅ%JACN&+;ޔՙlop~o;K̰T&pxC&e'Π"҇V<9N VwՀϪꨧ3"NxZn|;i\ t5q\+gM0ŬWƕyBO_v_ːf73N3aHYHk-CP4D=;Cc4 ))tG3Lc&9<8x!pؿzAHNR~$U5c,4FR I,6'u}9n[2+0uF@vaBaXey$Ӹ 1d#5_<OorpIّh!,>],f-jX|)zK(6x4W^+Q,_ B¤ӌΤwAI(":2Mwb`S=>A/h6XbZ ݤo&ٱiWp?LdQw 𯍧Ws,6Br L 7uOhXyNud1 -m*(!=Pi5I$hY-ᯍbkv5, u'%#^Mճ㍃}Ss p B/Ɲe<쎲Z ~ #&A5axn$5nN?FC=،ּ}nb͋..qgM -tdw fANw/^,ЮA,r+i`+@I4 6wTأuɸx@`Yuh輑bJT5 <~tDp 6+˳j8]x"Xc4t!^2{-o|GY畕z]C拧|7+X# ˞N`hh 'ڝ]m\9ةڪk: 4)8R^Lrܧ3(p ]vʯ8喖M.,Rt+ȱqxȠޮeovo=Om6KK͎~A/xJ@u!z] jg UmGb_EK~ID8+v`Qe߈ K`j5@.z B *xfn$3Ɍ\1hG~mZH1XN~ U)zh+kC1\rjLT`.Wظ_shR]jF[=xXi.\XӼ"MGĈW ̶S[.4p$:c-EUXc oL ޔm X;#l)ȇxe,Uh+l=y ׯVS2cwB) b-eK֯v Vi\G|m^1: 'RZ] DQLJ~Ǹ ;^XU΍:"u\)b0h{mԣl5Λq@E ȳQiSݴҝb$8z|{Q=g8̵GY͡qԲ2C6ٌЩ,cnYp:Q8jwݽ~Oe5F3L(!^΀S]JQݲ},O68::u8E!~Ȅ$^TwQgMfk.\_Z[r!K0O?ϸVKiOGÿzL4ӾBHW!^la?wFdv͹$Sɾ13/ 1ݍсK w pV!D}@L4耑H"$7C,RiE?H/̙,b5Zss*%x/4KR{D/A#XMTCrt80g5Bl[fr/IIko6tN7b9Nq}{;uYw/\9 ح@IDAT?OxG"* `ibWL:n̶1?= S^}-<̏жLW9o\lٔ{L"'n1LhGP WW vm l^ߘ!RV`N|=8x pؿWi7ϻD)_)]ȭg˛+sUCd5j\O!A#PuzJd̛sUY}5+ "%]g)$fQ7?`f9-%g3nv ^S +( ;eEJ5gWDOO F7l^TIZdvgS88x pؿWlC0HvvPA~"9# b9oW_އr`zǰ9_3uZ>X![@5=X p`Ylm|:b' yB)qƄ-+Liќ_Yq mbnknN {wV~ C%4~[a6IBn0Nm->AP6a܊ʴqZVhdQ5q5 Ӽ8ZdArjrLdkxV^ Ʈ TzXhkhLlMTڪȜf_ʊ--vvP$ 0Ä7$&f?__:isa-01O32LO.L!hSt*//Vsְ(e5b1H! ׸)679͑UzAW[wYԐH\byd=4uo{mtf4{p0$J\V2懴Oך˛}RQz^ @ASrbHT`iS$ ˁ5 Ok DM;WFRνX(!MgaPIWpݣk$$I s2:!ۻK! CWF\5ZQ }S橞h`5Z=F*o2CoRم`P͘ J7 2:_R2wqOo[[8 M7AJXC0KP-`4Ɏ9+~#ivB wۓg[/_=RN#JtnqnJm\Z(֦YRƆP1P*S(z:xo8ҵY0h+t:2I.˅z p j@>8x g~+m'B^kvON?^W+%jġ1>E%UPx +j9s)p)L.K nf_i>IE>#R9eJSZO~3ZG<}+֝96JEt2cN2qk5iCCcn`71]G` e^_L` j4u ։1ۄJkvmFC^%jQ ,T!ṵ"qPDCaΐ]mND!{T\?zx`^ /;w}+EG}ӟ~ 4fdEx0>)k@/ 1!YyHk]g)ZHrXЁ*ޏBAtPB, #$<:xI!pؿtβ@N8T^~rGRc=gA _V(kMszKbdu?m}Gf<8!h-w+dWSȘۣ"׈fd8 ƊY %T,K>]7<~sʑ곗ݻ?;(P%u"~a]<5d6F}L#T͚t1&_%J7Yy=$'+eTy'+G!~LtF37u0c!&!>ܔ{M{dmN0-PYW`j*&퓄~Kg{rnf](#s el)/]I>l5 YAY ܖqbA]!(wJCHrn%8=`P tq8z+Bw?.7 yO@@a^:="|,5< rH(DD:D:bh$Jj,ǍɖeE&f/<8*pK[*P#Ž-.̅>Tl_) /U!4CM ׅ\K3ҜYf`#ܴ/3DXM30S:`(HT{gf_3]|j^ n&JJۦ# [@Vg ea{yI<7#NUk1 8BV{^cENnj&gcmRBM_ Rҧ=\)rp-Py8Xݎ{g Z^E"0v| G!@w9U)Ҋ y1d.crJg+ 8U.x!v`|kP^I`ʩ Ň(fP60 (6Y޺56|;5qhD kJ"CU3%^B+vWB;G(uOQyYsUnN@k.n }Qc3ݘS*=JQ6tx,fR }UňqlcX?n]|M (_2~rVUl>ɟUэez.~sd=סw,@4ik9ɋ5CVPĵhn#_GU>0ȇDɼxo$t"K1?^nDWE_"T^юψ SDJ2xdύ6 >D'#44lY6YS+]lT9ԏ6 yŌ"BY%uP<$ ]O1Wƈ k]vim5.3ol-_iSXqP0Z:_Q^? ,yF\9ͺ_'/ƫِH-RqJ֮fQ,A/AwM\++;zc$j h4^Vd:"暴$BԤl;Mt4\AYÕC6CKw|4{56 @}} 񱽲=r7 |'3ÜNKDuz C$l#N1jHo2r3(ðg#" jBK 8Qg-$^ "kRJ@vʥ7m}EWk/ͅ-|}''@SP$RkYs]#㙚9aѯvqQ{?3?cF]^fe(R؏XrD9V0jnکΰB?mc,3vgo 9$}8B sU3Fw VS)gc}]bӱguL(ՀN5e;?oo›I2XC2P 3LoFnc}0ch$MBU@k܇*񙋼j35PtYHzHWo ,苲5J+9<8x!pؿ B~hi*5wzAa؎$|1J0`M@m<*46 (WE%I+fݽbA ͵F|p_&?||€G:8"+>b|54yltm.rm&˙/qNe]c8f%(f݇dgC!BfJW3Jw}S"@`;{] =TA06lP@ZƧOsdukՐS]a7k_o}//UԤFNSNB?eLPPD`.i̲ksڠyD~Wc~3o?7|Wzc/ETX"vgz /mYA@?>d^/ VE<>Ml̇?aeQ4>1Ir tV9 f7lpk,c*>,R^tؿUY7r1JZ &vMFq̫Zf)|ef,謜BӜi/pY(+=>,Q t<Ì8 J@>_JpkmF^LdCZ[8ÐgGe S7~ <ê/#g#k+pU D_εhvO?.ĺc6ٽN;*wrg:R5]0 n2N4;Sg?gtjAi:,uyoz7m/xAg5}v;A%=f%ufy);$)7i7pbQTy3eu[suq[=<e'tEKqY#0QQo`#2WCqHՎ~o{L͸cBGC8DSs-PE#{e~^f:ZyWBkLU75ȥPDhj^@ܔ@& LFj7;?,?kPj=b` SasE@#Wݏ%בqQI z;cdSR F!C:]c\sʿH`SnYIp'%o75cCOqjv3ť閭n.5{{czZiC3W o *!_h)u@ 5+T K`7o-ȅoam Or965-y tPF._ q= 8:FL3n^g  !=ײc^4Eۑ@oC π3D03,)w!H^lB ϰ [_$*iqd+$?̢)J^GSk@ԍGa;W ].~դͻJ! -( t0 2ͦ@S|S3PоKL{j'Xf*3QS#{(Zg3.[چx3ǖ j3m^OCU(N~ hX}&1]P5{QEoF,M1u84:upG&!rG5@S; W{ߢX쮼饚_hr$S3&}#`Bh7_fen[@zgR,8,Ȯ8KO^j:H^Ꝗ v/:-Mxӝo-~ :1[_Da)F_'åkK5qk"F4J|D [*+0Nb ceXHGScT[rJ6*t{8LNǭ3MkU%R5 /Ftms i_U_e; }RTrߞ>@7 PzN 1|̆sk[m->`'1nFf1\ #UqPב4öv+GDW2g?a{\TD*׾ո{{ 0t]p|%9)t9Mꎘ xHth㇏̇ln|-~RDtUA& f!R' ۿ/B^dEޝۈ212' zۈBB_Ғ~`#ښdem~k5C2Ó e@wBCkDHe%M.t׎lҼZ勷b3\ քDs QFb?wŖZĺXh Z#` KGqF|^_Z #c7mGVqb6vYzxR֣2GmC8hxޞ4aM+?ě *`S@5ՓoPGp%G}I?&ps*KS'AVnkنgG, {0Gzg6Nկk #ůQ5gh^"%ڬԧ߯1p/ ( 6QG\h"[_Uzge0G욐b6[$TG"=ePN:\#L]rJQVBVNᨳ ^zyA*bf0 ]<7)@JŧX X-(r a, J;QL*qe03/0]}q}ڎ.$))[llynk̤o4l]A 4욽njBoMS=֋g׼s85#`RVd5k~u tm]x;__A2rƟ8L+kiإ ](-8]74S\ +~mڱ<~}sGOØh(qz*Ð){+u=\ϩ<8x!pؿ| ,oYNKAw~= f)+,_O}SF௲fz!n"O4ֲ*ˋLlwQF[e"ؽ,WCz^>E7TB!r$cHl*bF}jl[mngn*Qp GS14c氍!,y=pjtwbV-N4]^$h JV]U'!ܻq3#QHF$8hdoa?9H`Z^+$M8:%'zgjiCm,#4ZA]e8(XN{范rms?mPsگQ#<|ws".Q.k_V8pS֖ pML0 S_ͨ0ZDWS6VxSJ2Xh/P}몺m-;}Fk2lLפX@}uK SLSs~t*ˉJt55 8 Cr_hpO;$\S#zwcuS>8x) pؿb":\B?W,7sU xHfqWZDZsnݩ<8xk!pؿgC]~w H %%dy~0tQ9Lla6`(E O=Bag2&aZٙJ!Nm+ 8j8ӘhQ=4`:)QH5g+iXeﶻ7k0H cgb|rS:N V~-i]1-]ìW:r (b.jPa'6RC\Gk ~rS/ ]U!{b 8̡UGh}YHQ9-,# z4(rKQ.xmBɏgzJ Q=cKjvėmJXYV@j7vf|WRGrlxfr!3cƧ}S0Tf<@e p[![uzੲ6vxI+) !GBWoȑe8~eojlc{d L ;1~`_0"A܆Ԏ!'6{ºEu-N=/YCgib`6 xߛ ?ς' ώӚJ:(:*M֠Wˆq+6lۺjr"0[ŕqqVSrmJ z sv')#۽a-8L\q,f9Ja{J:TYj^}fq7!?FqnSO,) heڟ rVu ~MWff~t#;瞑4}M݃ ͘Óԗ߇Ku'>[& lS%eGq^G[k=\<"Hnj2QеCriRvV,du5A [{ֶk!X+o1`uƽYA" S{K~&=xSXB%@Qq/32HwdM.hU籟Z$. QղJjZJyNmK(Nm7Z@&;_e$&w )(1[T<^,ͨz!4j[}ujnޞUbBdW_>6{otSO2 '_<"#z>8QIG?aJ<|h1-Lq  0,`qziu7ꞹ:{Ok˒;PmS8(D>G"╾ofq2?!Olhf-qQc.\dc8`oG\_DƯ.~=%옷~FؘXdhʅyE"<Pp hP0Mo]l S-qqkMp*![X(n7~: { =x<3Q_ ?M7#@ѬI>%~쭇t›5k@}Aej5c^ ꭮6jy@.FA&2³9K1G%Y:OVa>g,,fjւ()ɭJV|V> F8_^@ܔgQIWX\L_}3ʛfTZ.:7[Ox o6^+LJ ++b6#9MOQq-Dr ӲRÈ5D[YXQت K4-MGf5D+{ۭjS (°!u&>BsIpV%XOT3"=_,Gv`m%v̀W sYryn)e;W/ \ Z"嫷 k`SY;WȷojE5vn @^;VpXtqe;j RiMޕR݀ cEk~O}(w-|M!V{cRɾXX'2Ic 2kȀLUR_L7N25 EgSL &!>hWp S'{غS.3nt\"h2r^P [L{tjFRT(qox_˸6p#yj! :X7yj^(ڎgZ U֒'J~/T9}E+,"lke_eɗ_Iy!kzyH J\ǩ&/T2s]5Es i 1~cc?]0cEb_PFJ'iT{/RƋ؈݂\׎ 4??~ކhXim4 zao4{0KzR5@W_//rj_;B։ɋmR9Zmdos*)){ 9^;vŁ>&eQw{ x{A6n%f?WCd+voN791ќqi9w͂ ҃nfhudh8PZy-g1K|}f\5,= gk@T {ϛ>-|=8xK pؿgGAa̯o9qJ)"t;;hv `zQQ,;౹ xluvLHUZ` sBDy8&g:RĖ#Lg ofD@q!Ę3"L3bxͪϯKQz*&̓rga=]#ˢ+)+4Wɢ2o* (&^Ր[㍑1' :6~WZ  O ?';xH3t/MvW C`;>uke0FSk葖d 1skMK4kb\S4YMPVAkwu{1rfl)t*;97{mo#8H>-xfR\o4&4ҍ ۧBn2N@@-aIB7AuGe ;}mڊ؛+q{HGp{w^D @IDATq!^y\Ch^G&?Z#rgXj(uzt6 D|⮽N>Jr͌EhKИqLWtjg\\?RϤ'L0Au M68鍟<5Ye:T5ߣNx:̀7 ~Ą}Q7nC%x\E=6rmFʐSA_@ M{L{ 5S157 ɳ .;,~g1xm}}G&+c<Bh@@୅aZv+t|{guC"zh[vH)O |øyOglN|[f6 nj/g1OH:YmކFʮU:$mW}AƭK`#eF%LqZcYXQAVp@:IPc]FWN}5ͧUb24C9w:" .= t |. ƄpU٪hJG(+6lWbipۗZOjm+d ݂l(`w/Io]H1SAL4cQ1@ QM3#3E @#Ql{Ι̬nӧU]`eVY/~|:0+A =ë&gC RR+_1ou' DMq{w[#`/deq$ce"a0|3ɘsM%χP\>m"d8U·B Y}+97 ǫK`WSi!X,Qkݏ5%%pt3 .H7%i8;\Q­u9酣4IcVjOoQz*A`Cn`ejH 9&?9 FU2>掮#.Ȩ=_y2&F);Ez{0\vkEhzUmhbQʣx1Le]T.n %PAq%atz> eī( ϻ_*R{>F4rX>5,8sWctYC3:q~d]:-=QϟH[ ( ?S?Uh͚@U/z/?P91xeZdC9aW(3a ++9Ts~P2,SFCCMEQhk鰀 Ť( ? e[ d%`5R"|.9QZ/" ̻Z |nKXYbx<q\Vvv42oRR૧_=ok ݼl=ok#' ) m/RRR!0"%ir)d(rs21e+5_NsydEcH_JG(C%ĚhUCmҜeW$YXtY)]DBp(S#s_,}◺V'*t GE:%^z%=*IPqR棅"@M0`PH{n) ~!nItR-5ʤ֠YΪϔZ)@M+ƨΐe4YU&ĐeCȃOΪ|ŔCcԤ1^ZfF˷"Ba}@XX E tYhM4][*-1oMס`^]aci %̏(磷dDdy`˼!6s)p)S¿}n.>?lkL+FqPnT[FuxxZXQcU]zW-rva۬x=XA2:cnAavV{EK\#V Zƽ()C(b6D?ob`藗r4SJuah`5Uϥ'Ek`)kZ$(+v X ,`o=g1!7qlAӰxHz^ՙR;Q謒4|naPU%N[}L?nG]Q7RR_o@g׬W'X8'@ 8H#1Sfv4a%$9?xr|i6gUfiϮKD%tqZN S@jt}FLgJW.uhb'cXe"~ ⾿ .U\(%/<@TD^nDgx29H"kQW8':Xp!,%x3p_IնKO#` "z͐nd kTX/zg~S`ΘiFa^`ދ4Y&}#t_']V4,;nz*T QQE ,Z-PX.b!PmE$,XcC(SHoٌS1;ߎO]Kt14g J5$G^5is|* N  v]D~c5.M.{|KN7ɦ ]$d\"[· =+IbHJ.W8>w@yIS uԃ-5~88+(qF0y姜ipn륏f„|#:]C:ȈIA/!ΉL{9>&{ߪJ1&I]f=d2 C&YHLgZidtֹ(11 ˿D*RE1MdU^ƘE`7񳔖*m "Up{!S!g(BPRJ3&<5!nzC]W~eRIcZcԒq!OϽʼ_%.*}XP Z³(z\=87vB6PLrq6  "  #m%vu^yp0BS i<yB6bh#>i g(͂J&ӷw({=3sKTc 6k4cBv?)YTP*DPIQ1@>uIrbšMLuc:-#=ržɲ|HdM^x3-*q}xc:W񴴛˕=>o,L^@u-ÇݗhCydOc[s#/. \Vz)m 0dt*<Јă'!Y}W7`It?oH4o0. b !FSxL=#yъx5 I3b'2h,׫:M b$~84nRK>.j!HVCiMu).)dOPv +zU.#{ykXB7K)x ؒ>XkEiVþػ>Ǘ~K/!J6!A(*=*2"fZ@88ƮO59ot1@*̆IJZh΁nb~JXfN*LPWCfJj عKzSX Mgl(x];hzc٧L ~8ѲL\,f7X-,U2˷Cd\4>Q s]]m|bGzܘKK/}I^ @ 60$o'|"#HyEsX. *D)4)3Ĩo~c|$$]LfV>);(<<٬+\J{RQDXE9$8,?j b762qИ1 y1:X7YX|a5%@E"(kaW;9tSOqdBzr`g8$ädm3jnvi:(eW~"bon+U׾أcf]C,шD%FczbY.J%ik*+kU}3ʎ%>dSރ#'PYa J/YF2֖z̅GU>SM=\LXVO.TE!reUc3V0-s_] *|!ҹ|u6SHx8<.|iPIm!L\6,|E$#;+͞7{h qxJifrNV^V#SC#(5rCLUj.E"s[2sp)'q0C±i$(aB ż[<3RW ē-ftŁ# jB&첐DFtX2 #Zfsz9Ǩ^ٯV.`) X> h:X>h m=6 ېoVBwCxl3w]_6.)|˿R KCAt O;Lw"pUY+mLeo^TP?uYN'uU#/E%@s^PؤpD 4e8fu?m&MZt"l|%u5Z쒒!Aݯc?ZFB^p<.(@"H d+?~'~"|tWu9:d( !H7QB4zg{ag3F գ1R{РeD%%ſ:!1[~yůLVpkg@$ ,V9nE  gL14/0MCoKIezv7@ =ZGuCi#ߍp2dI(7PC~9\NgTơS6V -Fctz+V*meyWTVJ#?ýa7|)p)uQ¿u _F VS[ qD!s]B\fEI6K1MO#LCb0@CٿHAubD FVd%pʐ+Fhssf~5?b)yfjӆ#F!S`${e%IoX"ϵFU#vw +98])Urs;KtSHwoԠl⩭le$4[,xÚ*npӄ80AdA$Ѱ l P_ }2[bX5ĕL ٩yc Kgx}#fxeaJе~`ʘ8QB( 0v?zZ%ChqPaER;މ9kD$C`둹ajgʡv' 4C@9A]^U23α نlFT1@^NFΉd̏9卹)pWL[ݥGpKE7wѮ{+;=!K$1kMR]闫N)${O|~ DpppL6IA );2D#m4Uu>lX"㚂Crёb'1u)"U"vq2J  ĻrDz;mR; 3 %(IEfæWRZyS8K^˲|2Ը3AˬMրl63 XoڡV^;-@Cj//. \ePy)@Ɩlci X^%~ )si^2n p"DZ"NWCL\~zC'W=qrp`A@cmlnLN~i Kc?bynLY*1{W<^::Eu*SxA7hs9gRK%D9c pJ|WΥUeY,Ez2i-HY(dsC7ʛ锰ۤW P*WO z)NKFM<=ؒjRV*>)Fl3!͇b/mD("JR1@=*@4!idrCh?B @ ͡'!!}R| dng uf~crɵ0s`]X-ШU8zPo?LǮ$u*g~gh\THnv䑙vvvLDϜԵ(. S^g32q:5ZJ! D#nZVDI;ؘ%qYrWzQ"d Csc'^޿=$#Bk遣O)miH`N):Kv *& ) Qxe +90F(<,vi6/ԧ=䌟#ºF}_&љł.X`ROOG>0pZ i!Z0X"u0˜3$_@4o  3}M*V!p-UL(G!ĿkJ6;{P$K:1є_ }ś&Btơ.2wf<ʼ6mx ' YK3;,J\YyKKY1@?]kZ_XrJ+)b-ԖkɊק(o l+U! Xb:\ȬֳΡRRCQ¿E[Υ+ @ ]j̦r%]'<+*{,#Ѥ\8?D^> ^G)-m H|6/Uz554BS s\tqi:V/!u, #Ko'.ۙ(@,ˉoxe\&i(C4^27vZv7)$33#7(";2œ#N (s8 SH͔vނR[FskqýiOЄ"N!3ֲy Djz^r"ֱ3g@'ҝ*jeO@t~%bXv 1 .˩H3ڔS`Y|yXiƅuoY Ҽ9}::}zUccSX#WzjKdr&bnI!Ù "eM,gꝵi&C?7XLHz ݌\7RRK_aok aSۥ'~Yx>X[??9rgTR!wydn*|= ?vq\<,.] (׾28Y dՍc$8ix$ڰ#>^_"d/el*q*.I6O`L1Yr\':`ae\M}b}ܕ$HdCsh< b1SúGJː6d"B8"7d& Nu)0ȲKYbBCk(̔Q*(?6oo.;6sڦhhT:,Qagrw`0 a"J0YԂ n] #LFE;Y !'ruc?m3v[b΢ p51PK ]H<šیQĤ%H9TOoB-*S ޤ8s8UX<ަދaK9%:dѮrVY|1ue?#K˗ey)p))p$-RDHf",K _Gԗ'N.RDo %=xnվMݡeߖU@P S%͏?MA]h6A@ B5>؃?_c[EJ]uY!{F )"UX*oI 1]2-wB]"B)i2I+F Sow~pUNbZWДGwucٓȢUH4B_!i<;XJXPǁj_˟G)3iNٰ `!~OLAvSc:~;e";-j D๐ف%Eʻ +ڹKX+X-J f2kEa 已WYFd:p>Bh%6`ul=W* \ \ |( \(y˹x@> / J3Tnhj A~6gJ.dq#bq:[TRbK 2+IvEQv *zxo)qA#X ޺t+^ZSHI=\N0QY 8'B]Z[ه@=RNjY^zKmnJnX4=1IT -4a7j΢} xpPS|[Y|_qWxzyn`ʹ_}ݼo)=>s_yy=#`,4hBSW].B־<}$7zilx@+L1&A4>Ux |#ЛE9mDmɾҐP ` "t0͊mD0/R4LeY4F2zQCSI3[ ]!eƭ eF_(و&'K>kr"CPFj7qrî*/t TY(OXJ/d1D&2n≳ah"x/hW!HA(BtY miR3{@ 1BsbWcfi2)X%-aⲐ =,52MbhG{hE̗U`5k LY,)9ITvN<-[,tM:eaI#ǟ֣|G|4Yשf+3x_]Tvwr×_6.)|˿W9# חNj oHr'iיRp(gxyj~tr"uY3r}8$DZrP=8ĠH!~bϞ3cD J =+3É>ᏓYX,{d*B* r0# u$3(.Zq*;2)^}*VCmƼۺYO{q HVg#&q ˷+}ԒžG"iNJ hNtD݀؃{C]XEȂ8岈Gn ZdC% U`MAY X%>]թ@`LRH<~-}ʧ2 dCYJʻ <» ǣ`a̡?3) Y# rű9& Z b ;9Q>0Ϝ /}2- .\ckVE&Ä,3\1_}Ad?uYUvv~*eBqj~$Iv61$΅1.Id$ H0v}^ ʼl @ !J]o0@qaŠKS c$p6E境SÕ9XJsPQ=rS(-Dj٢xڵpCR㑅OdM,P!t_ҕԫNT(P;.Se'Y^|DPf*pRJY8:졛G*L@ov@qT4O>U btmxĊ΃fU5 h:F_ɽ6$b=c #H \*ٰ^]oz : OrɉԌީΠR >T5mD튙ʃfre1X,Mr> e %-q9l1ZXK>PK oΙ#'}xƹNu_}q.(.YOe]B>|ď_GQ@n{|18.$^ |YD;He@NRX,*igyb81aO}H>} 6/A.q>A"E @,Tͥg< ,'wmd"$;H:){ME.vJk5:<*R5JNs c*xiChX E8'c`s;A8D3E`cМO} vͬR)WJ&@P -u,SH{ ri@!j0iY*tP7uVY{V/Rg HU0[#OϐbY ` =(7KM{HKCkVc Уx%t^ZL9X@G%ES;rdQ4YP# &-Ƥ3#l=~8ܘ.TW1s2cȧ?5[ 9. C *NPCQs)`9sY'0fS';RfhJ݋\!VyYoSvyvSD.] M:D$Sw %QQɤ #"^0Y1LNb'Ys&W_ 1o) i E .n)6 GW:j[&0[ &aF7`7 CSK> 2#KKM} >a1֔M¤+X)o7׬~JB$_,5W}E ta/[u}蔮e',x:`ΉC)6dF4['q{_6k 5՗o06* 6)zzbz*lVifuhF&#`)IVExzxϸ6ɽdkދ8xPhEx,䪿 ~ݤ19>6J3mtKl?ɫҔ:%6trapwjHAO[+/[<#u|waZ 8Uv) }vM]I}I6EL :nqng U&Ρ>a1lKLMEHW: Jf40 YL΃ !2#&_OHB?F+?%~(^*UE{t_5,]NUTF0d\Qk8qz>:(GiF&,Q8ܨ AA]FTvcBGCWC3p=rj^Hu$ֱ 4A*fH8\)rm'l4{!Y@,#X^Gsis }PX%$]؎=0#TƴZ12@1%ҌO!8pf6S^8,.] |JHon8ϴCS)m01b0Cy:o"K_l$zN2L%Zvɛ)Jȅ(*]i'̄2mN^4$v I|s>,,6K1,n)߳adPȢ G qT4de `DvR#*,kP(@W"lXj#qf 2|-**jU< _!"u:^xp4id\\HBtCpGS42 _DU]?0-]}&J-O@IDATvvmC ЪP3|imS@ xur/-&PWNͨ {94!:;L.m kb)MYbl14]xIlT50E}A]G~~d)%/oPwp {;J AZg19v|>1RrQ㥃%'< EA 4Yj(?6i'doUwJ$)f5.+:FSzC઎OtDIL.dIB!&W4 Y00#}b0R@  =IGXuA)䯪Q_d0TT"w)E(sf>nZc1,0<6D<Gvį R 42 UN\tHbM]{9¸WL!$2L(<`r yBcJcԣCѸ9OjXl٩]?cT^N1hlZrg4)gy9IwVFtuJ$9 &ڜ\ \ |@ \yԻ -B,v|[>UιQ s.:[}q?-<33askpj g2icw%:&ܞ*[9AP)AG,$vKx8%;`0er@Gv?` ]jwJ7.g" .??jJqA"yI)C![~_Hb2բGӛY 0ֿc ʪ 3FX^˓F14 ™q t)VPQЂI..Cf43>:b͹bG@"/r}ڦ 66Ze QLITL9R1],79 txhk1=ܔz1M%vod&>6c]`W),<1Ke lk@X),-&=~8`q~g$E9ؿDG9'&U5pשYͨ9[3)YrѳwL c݌k DoT#hEl4o/8w׀7V:q:Gvm_(+XQ Qam>Rt7n5%(UMWl$~KQ *&sQT7DI @Aߺ;3` PmK RQPGHh*?ҐOzhCcxJ#q5x1@N!9SPUOޔpC4508O$Yއѡ^!C%F=NNu[AhHȈH*;C Eě ihy/oGcV‒(Y2xGa'v_ 11ӅÇxo IQmT2L+3ryyCr'鍯Jٗ|xzVhF%GW7v8תrj@lmQ폏77BfђVm(#7E "xKKKK >,=oi`T3cxyKKbkhIջ!Mg}]2]cU1 38o&n9a!gp); 2dVH~6#O4LwCK1qBPG〰]5 ~ƫ7{o d(1qܜsCya*qrRvz !vXKF$ӻΗ.S4o$95REћJh`?:`ȸ)u>"ug)NIբ겎Kߋl4b[٬b"S7)S =HK"{^'b[1ˀ^H o{dtkVZ8 R&9p Y3֤:=m@IewoUi[FEoi,8[|@W LDÂQ&At Zmy*Yms^ېْ1wآ+~}XzҾ),pPc݃c[ʰL(~q#O9M-!=w |)rͭYbcjmstxGX"t㮧7& kr5ؑ*wCqw; 1msDUfYnQs #|kQ@ͧ?yk.T9=D3tt SCӰޙq1nOPמ^kϧ'~dPpT(S3:mW<^cNb\Có>,CqL} DhsuWb -u_ \ | \Ew^ |rp 9:e0wNL_ 6р X&葼\Wt*o8]\Y 2n\pG$`A @fls*ϲ :{ĩRӡQ(=D*bf)%s̭!)Ŀ>xJgPRT˥oLP`Q/h @`\ X+TDL  )(WQ\3]X^׵TaB]qG|fBi1+,>/q }v P"^R[ Xu)ÄbH4XbNNDޚ^THVGmeao.pԻ%Z]9UẹG;ʉB..BΆmF)gG)ѧbs!jwC^-Chyy~;J9XL@mH[NHI,F^ \ |A \ x_ |u5'QзpBz}Qݔ풮 ~Nm5|~;ǰrAWs aDyAb"vLhmF hGCK׎.qc؝: c.ռCtvhq|GtkҠ2J0G%a|1$)d&Hu$_|*y0 ÇD3<>-܁h}jϮu%fS- c$0@@pdD˿2"錚$eF?jb?M4U蔮n7 YVwzKUq[oӞŀ9] w-AG9q1nb< ƺb 6M HC>cLdcv;e4"#sxH1a,I8N-t=*XÖ畦{S"wg%\p.oHM_pD_ i[y#/.."Իy/>@>}L >ƹRMNH-IJs;!wsW+?DE=%#1eT8YMqc34U3eJr'_d3 8 %PF#, ȜXRC c`ڝ a0h;]3=e>nui)vѻ\C' ҫXnO1 "a|˦`Sd%i-ݎ ]%ÅL AcG;:Uz@bi\c,h?Hɽ=h ]e2‡j]ëz ƍ#vTaa5CbK̉E1*v튝(y2SCQm٤ԗ Jp|ᠼWKː9T`>O]=Z|5_:)_=Ԛam[)rD"[ʆe۲yOS9lWvFpW)pwLRS zD69@$dq-67n9rIi~~ܚE?%wQV|濳>ey?FG^g7GT)7bĬع%#p)$ɑ%Rѓϓ$ája( 5$+pEbr!W@ZгiO7C<BB_]ؔyD?4U GiMn5cm =Qe9j%U(p0Ɓ:R?&<"}bCG ʵ4^ɗC2%!.JfV#5U5[uA*XlObA*̣>_S-ɸChSB96g4 q-DŽXl3  <_ lp03FvQ:ZgҰ:bB,[=MUM]Y\o{LOIeJVS>=X.U/Qz9ͧ VL%{t'_UoICms^@"{zlbA+85 1ް2D+W8fprZ[o &iؠX#N9Nmn e Ё0YdGM])tUu4kT 0c N ki36KwJ1a PI L$^48$J 예GnIn,U'Gr|ngFo:I\y-ԂNu>Ya*[іIJ Pl+6yضl^p)̽A,CO-V1G$wl7_}Aߊs䊗SIӿQ>SZ;Ѷven8q I=DniL\>ЙQ -xl)(mbzJ9@$q9]cKcoڂ[T&#ް]8G0@o|%Tsy > ^!Meiߛr6Þ?HwA0-4>UadLM+6|nxWz]P鈷A1 nI>&6-I76 -h^3oI5vj_ӌ8&qRFľIfZ;`gpEX~9JO,_Bίo e;\m}Mx,-}h[l :n86teۍMcٌlI6X۪UϑԆʴ>̯Rѿ>^ \ (pߎ27R-c3{$]H2 .F@*Ч1tҰ_±&ny9&+zmsʼn졃Ut)g߅Rx .]fl $"j Դ E9rp;A9]E"G%~'TN6zo@p;$`>])%e\ipޚL[p&UԘ G"o\A)x'.Kw_ô]G@7~ >I?E(0Lixk 4u4j!6@y,1Y\{$\l4C.5;mrH0OfB0|X9%etd0F MͣG7>j:Ʋl쑇p>1mK2n1b˻EO_l6R¢ҝl4s|Y]ta}E..ey)p)Q¿n7ץ)٢ra|~!/Lm. ْUliHKNo]J)"#et0'ersF uN<LEdeCd;*G.hPJJ E[G*u@ݢOzS>k-S+ʡyL$YVZz2\J99-ty)~n<$L#?#Ɲ.  ƻzFnB04ԋh*pt^ ǻr#yģ0;UF.iTd0dųg4TTo!M pQu1h df2Lːi A74nihZ/RuF&%]u->B2ohcu)?:. |QtV=4`~|'LX+Xr@bFCbKegx5/./>SUml$ǻpTHA6u$bvEJ2 n8gBFMԝ$ouFuKDij 9&ܻTC8U8ٗX|=@&7lQj4!v^N)^Mʉ&e7(1{}Cr+TY2+r#3:yB9cev ݃s(ӻ/l 451H|0' $x ĄN Kͳ4~ Yb\~^bkt~L\&)%(ּ.9WL}Z8)- ԢjiZf-mmm[-v˻ERohC^:7yLV6%f,veRT%K(p@x)9(OKeީ;8r9R蜬Fx0*@-3#pLdxBKzEn)%;ZJ 7sK{hdvfPw]{3c#q2/ j$2%9}wf=O-™lhHR_dzd6ɎwX\ "QL4s(2+ i!L5A xx%an*H̅%Id`U4k,U, ;KbCNsaDS5F˪UҪ(Cc 'V PQ>m1a/PgKTsnFqŐޕi"xxHܿ^.$FG?){Ǜ17wUx.v>N[磷\c ±/}crU_mU9]uQ#v0a|.xI ^&)@dMz1&ַqJs'Y'߂?x/|UQC >-/$Vg$ңOBW o4Ė^ŗ q1p;Tf(Irz<ȸcFOPa">EdgwGĄ1Z`-[5,ڹBZRxh5Lv x[`zx|3`e#TzvoRR`I d0Fݗ/1H!Y¡$EXEd.R g8J-*+LyQhр+ #x;15+&0UQ0磟 Ɨ&93+.Ӊ][$6,JvbeɲpY#zf1nY6%Csm`Ŋ9,ʷyKc#: ezy2#o3I`?ru_] \ (pߎ27RD\vx?>@  F U%0Ҙ7N\]XRIENUw@D^Id8Qz |\X͗'ry]qh{Q9\2c$SȠ؃NJ B.?WH/-; P!M^ ]Jv}-niqE"y*Kܫʴ+\cGW@ Ql"~Gdlp{dWT龶Ȉ;:$XêpC+0o9 s0~؈P\|3GUCk+>0J)@RߕJངe80ZR,,Gw,A18VJ$zdKi;Z61%_̦=Y-I 8pk25L ??C}:1}.rėQv؊]mq)g98lj89xo?GoŰx:6{C3:"l(oIQ}ZȝEu)ͭ*qxWFLvBDızyE^[YL]r6?J>)YL;K!0HF??憘ᣎ&r^^}dWcdB  2RL*g/UV8'[`|B V,[2JO1|Q;]YU,D|"L!&0ayv-UZ(RhtҤv,F b%8ӌXTay ` 0tv5R˷"jXhԶX=,& (Y,P)gɲpYJIE1tD]!>g c,W8D1ͮ!_!-l=:72[)j(peKMڄHsD:j㭞*06Ѷbv,xR#aZO =&SJFvgOWA2[ -r3DrP #(>N}]fk|&Ji/)߸^̷huA4J0j\~D# Sj"ˣ+ Y` @hw d0@7:& -\>qރ]l$w. TOZL ~#cXp,;HdYz| U@ǃҝGdc 0>/Wcl[JFk1Эƕ>$dy-C!RRsQ¿ER[#.0;S%˱sz˜Ot+g}coN eO2sO`xDʉ-K#.hΡ #g)2|_ɀ(^ŰM!R1_x*{vegy iXnD& AȌB}Bt\UT:p6Qf Q@rTvtw{@IK]VP5O>ʇV43aYm$r-:ZZmsqS~JDCyd{LsGmm(Wg^f±s#.i5E-c q,U dƪW&L$0:TԀ"oC)eXvK ATKKy$]OyHr G7uA Yjxga?~ ` H,R!I,;+zEK/y;2Utc!+%D+i8qO @0Dкbnd$A!S8Y~ WC *8 UJ% ?,0[p(R*Y Ո0_k֏8#x(6cJeG%~O2YTfy2MC)8ZN jNaS/0o:mpCY_E|XeGޓ C b,gHtpCgtliT!g_b,JT`_,,f-Cc4ëpoTsc l?Ƣ=~vg*_6M=|gtl5p.&+@M9bZf-D}Ѯ=`0xI2Mv)=N`lˀ5Mmv5%/;Btr.kG<͒HdnP@8__9&N z9F40yIFҒ%@NUGX-SyPע mVv%>28SCL(L0$-Ӳ i*qwXpH_s1f&ddX,A/9ǎeb:HI%E]@¡KO T1KMi/9K!N( `*5+ug;0E[(ȊRB": eZ܅$ܐ 9U0ʑjO49` E25 R4iGO$PvdPF%i0倞&ƭHAHy˰~ xLHȄaIBhPCQB cPXT',B '4N2'q/nfR%byҩQ H=7:L&6UF BPX2L[ek,vsXZZ (ʜYQ;Q0^ؚ-LLn&FJYn,gJxQ e5AE.FĺapNnXab~Ȼdb'Gb8ZTF]im%cW^ gD.,T9\n x3 xgX9x4eE(6- !IKL:4:c _^@w~Il2<'h\@Y7v]*_JFgkET;:mi y!M5rfr[b Vl\m5uU%T|TզRH8d?ՃOэ|0wd_K[X *\V--B %mA#7D {?w`7橲NLYihu\=(0u.mDyKUSK2aJKKg XRRL2M(9 y1qƒ;!IWT\Höggᱴq)e :H\֘D%,m˒-vsMEzpqǓ$&CDz!M 3Lz2J&w.ΑO2ZDZuO+,c2!9h!Ĝ *0FW$FFѭGa`IuC0Z[bhC]#C20̈Saax~*#I&ZVV (y\J"1$r3~tdj̪n(ҖP,??hiZk<0P`~42U`B ;a*f{u!3br{-LbxXzdd]]!JowѡN#;g[N ݖl/ 'VZaX1vlv xw2<rvNVo{Rw3ʊ(6.ٍXRjv 鍿 _<|~brj*;Hr=3o?'2{2lsI\ kX-$7S.rwϾ BqT*w?R} #V$ QV H.)!vwuOS)% V3Ĕ 0`[f\j)I%tJ)1nysp_X4.,y1 TlΈL)7,"rU1@% zfZ( Y$<\oQaJroݵ0ղԒU.`0'SS,%0ե)I mrVc\?E3?0['dt5G`]7RR`7\ ||jSD$*eϼ!L;ҶsO$T9)J"^=H~zN >r 8k3?FvOr@q@d<79oty}hE>v~F&En |&w;'$q_ KV#iL+~|9jRȜć30KTy91=UO, h!"yuAA~,HieiY5/9W<}#"KP)3`ΊFZ K'pA1NCơM^D&l 7a1Ն(Fx $WlTm ʞpwʶX;+xG{D׹2S뜪Z{4V*OΡ9i}f..2[؞^ELP/_N޸.Iƭ2/#Z 3cWH!xWb10tO;Grsg]Tm4"7n a#摥 &VQ?!CtέnF!W&9,c΍H!z%3s@!@IDAT)VHvlWb7(VC۲Ԛ$킖?OY>0ޮ"~TCL 1w?yEe@(k(;|}Qw6 |M}i]#JFr<&"!l tE2K+Ԗ_u[.5-u*#n1l,T_MADJ7Ezϑ.ߴ7H(:zA}ry %*yI@vWTIbd/ٜC?5}ytzKsRQ4(g&"ȴY@X*;,kRA/d X `t~dru#<*4IJ '9مK=XM:(p(T 7fY=@P#U{ ˡ%jlqLr&}WP(UFΣSʕP%!lH4P/)ql;H  ;LJ#U]1UVS+!h>1wLX JON!/iA°':(U0W2sqgN?1[̓РIOG9f>X04"7!T鑕1b +Jtl7`nn GE `U7e:YX aA#fƎtxJa1눼 Py}G)t+%>' >`>ge-üFàvJCbo mM X ( +V 6)nY,>,u& $g]'|3CaI9YA@ë b1K?3z0׬Wkhͭ50" #*_X1ICɤ 81Ę'8 v?ov[M.́0|8 XPC2(?xU9r@l6ǟc:82|i+ :>ǧKG`ytu&iV> ڒ\M8NV72y(n%#E~O^œrG`1l=zmiq(`HaоO3V{ZxΠ MUA]g\4'05驧}ԦARLTԼK@s|"< !$11JrTm. OV<= 4LlȜwԟIMLF0d0G#'/e@7@BsNb\H\%lܖGWظF83˜!Wi~Iy$сߑ|04})$ ^䜑|D^>sF+"0#P7pUNuEE^4hje`g-Os^蜊 l볋2EfktV[Qt&a(m0Ҋ„(2(#A!8pKopMZPpo$#y3>|zmyOdļ{UgN¯^D?{]| BLwZCWSG3pA$.$ E(| XF0?*1 ?2H[R5| j 2;1O23ЎfDVG10!FOi'fN 1qD^h)_hK5dL1j2ޢEkk.l?NFqiL PӧȜeЦgjUr1nWK<4{T(1aq gEĘ]zz;D6Dѯ(Z^?)iB׮C(TQӥ[$qӘs, F^ۀǐuUw6Ҹ>LUxHRXWyn1-2Hl ld(ӓΩ"cm07#?%Bf8 vt[^a'.s G3IU-k:no6Hk#.U~i%jI\Wm*9V Y7@b6*8)mfoǑDGSrCqeWmi"0 D %+cLVܲ0d:fuvɆSfO)%CvZ%HFukʒA#bc @f+"0(P4P 0Bg:Dykf_DJCPt7kE;"EcY_y'*V 3uf !z}}&ˏ]G#A(!~NdhQ hXM (Y)QkY;T]u pUEK*U<[_\uV2*3D?ePPe۲ENh+)5zץWocOFcAZ;S>I=| :FzK+hvV$¹l鑒ʪ2Kih!Yxu+pxܡ_O.=Suxc$k'8 &<%ǁq$]-2DF*de2JXkd+GƂf[{H!xX"0#Г?M/#'xuGR}~!OULɰ7^r`$ZpCots剺Àp+aV~1p89>]bvZKR1P=iO~7/>@g!DDx]8' dOwUhQ"E<٧1?Z@^c#~ƆtόȇFg+|#¢H=܎29ؼ #c3}Yh[#=6f̍Jiӂq\PEo9yRg+)slu&p3 ZU;: nI@d$Ӭ &3aPgc!pN_g6 Z%7 |4R )>X2 5:pNX.+ F ٍxh::ddC1ˣ["\y }*k>ZH$4*FKK;gu [bv|z,VmBNeH ˢH4rֵs*DŸӊqc]|[T9nj+\zA-n~iE Pyں5} T+҈.R -[y.! >~KSڏK kyzź̷es쪲&}~aFI KL'oω>ބ ͑.7n9aAQKh8Z"ev́–EbvhGX!~8f #7PP5Y)  *m%Vشbg#M=}@X.2AneG)-6=ԑiw5Qt%[-»H)>GY-IR4!#[ Q%s|AU>DBh2GaxoI%ɑˉ4OK5sO⭪ߌ~q {j$iV8F-T&CԻ7ydðh<[aFni210(^iObJoQSC:\xWtMlsGf9u 0xE`d8qF7G @߇oV[@qt%;bј}g|K=*g3 0 QG8buG~WNWSC$ )ˆb<݈/[yL:3t8&ΚJ=e~ݹeRzns&Qmy2+j 1c f8b! |`{02ފޒUF^ fŝŦgP\0d:"dKX6Ip3gj} AF1Q)wRVPvyTRxdΓS`AZæl&h*]9~ a U %L0a Kب Oa8O &(tz 2ic9ߐ\N3ct}b'%оuvMywQӀv;nNHVZzϴ5N.Yorp0Ns&*l]'rL EӏݬHί!y; M?d*7$ Q7FX8+͞W5|lNl>v["pjEOc6oP; /j r"46?>}ɪ3O P14D.gSɰJFRYpy|Ji9{4nuHˈ #Nd'] gCĄ.g g"'E݄slQ ߚi/n"1ppGY71u Cc`T"TJöj|J>O[˦|jϺ4\|F3,s`%F̬&z=o3wtEF)/[K<}׷y/u_?V HR4iEthZcGWraPR+%9֧t.uk1pѕOw]n+ӕneҷf`ξ,HG*m5ANaJn .t_G8|udޞ$vg8jǔ рg@D'~1?p$3eQ:ظ哼 gC$蔼xD$' ^e;yͰ dk\ßu%:, "le,Φ 'ưXa7T>pFmrY Hj FY!m2?bZdhn ݘ"0Rgd\oCxNܬia&I0LWܴԘ|ؔ$tyKb# Y}L7#Y": S߆.ىo1ƒoM}z"\dd7%91E pyߚzgV-e-e K:!-[BL |~HL7r \b(>\(q1Pq {_tIKpKmGc"ФUZUf/XVop'jDcS=*P#~@٩[kjZVS ((='^`GeNbo\<:8`Bt qy.R)I0rbAEiX /=Smިdl˽\79$ٺd_19s!%(W;#N(f(C̚HEB0YuZJʞ:]mJ*^{h3[x%Hhfu(CΪ3grNS:lيs@aTBc8䪦яOOcxSdf X#yzKPmE/O[8,PUjoߘ̸cȁ^Ƭ^$xƑw UbO֧E"PQ[P ;^>~ՍOmTg+|llL`dzSՓT}IQ'aY\ڡִy(vH}tn wh3C>2ZiQPh0AnrЊ8k1mYꎣ\O1tM<%[v#b#svyɐO etcBaA؋?&ʙ:zђC#ti^42- 5P 8 SK՘30GWV%g1`txtܲу܌K/d\H,|#5l◴On=XC|d;|e& , t_$P{Y3 v-0mi|Zadb|L2P}޵_Rl[@*`ѥ:yc3 Qo%- -OYͷ:`1 ^0Ϲ}CX,73lw"[&eLX3^J$30ёtd{x~¬#rHGn5P~bUWZWxTQ4OvncUE|naIj>~$@wJP 6T"#y6̫М$>B1ttfJB'ꔊդŸ(Wւ2t^: UM%8p)N)8jP̡7^$dm`BYgiC{tKDMs lxʺ5)ʯTyGH M]Z0R7R-:M#(83:ǒ\OE- FXkHBCd¥ \1EV!tP 3VSրD+/.%]t+GeJq\\:$©DZGmm_/5K>^T* "WiGR:jM#y_~LxgƜ[0&`}z|>ƋN'0EJ*sKBathF[!)}=?:.#V4| =xt]ʯl:yYSzEBֿOܭaɳaIlϡ)ha HO|[SQQ){qqeʇΨܶmpg;R p aMJc"3#o`!ԁi SnDFeny1GH7v0P7O)mTX$J;ŦGޢ d2Ӵј6XV Hzg.Ŕg?뙿s,~Uc#C. '09t_LUѷY|NdR S]QWa|R H5=5yJj_^[B>i79*3#P I([ޢWهez'VYN?7BF vO]/K]n#oxBY%Liѽ: :н|r!oӠÜȓ1OZ2Z13î2l|`}mu/z1S&4F>d)/}~ ݱKL~; Y[A5eTl<\'gQO~kš_~ $Ҹ|O94HTG[#ɟ!$֡ f ʈ0:ؗ>j}QfjIyb;bRrݭf+O)Iz{# 4`<'«AMd*s#~bVa]EsiOcHs;ίt =SZ Ju#L^Op~q~S(H,078>LKsU<@97َG=OZzG3ýs"r2}iA77\jN;#'6}4"Ue ~߼[4|PQ.C @vFRn|9phT w1[I4c# Oɰ$ oIRnOBŤ[o+( xqL#0@̲=~a Q-~HШH5vZ @:`ÉUa(^ Iq>2Y;ւǬ)1L@@QګO4r+s-2(Z^9,xy Ig>ܰTA+ Nc| G{KMlDgE >i38$c,⨾G QXLN!& l`&P͡Q$@)GESVC'џ$ga N$GZTHGQl@VihBad!_PU D^iF,?۸ӭHbS_$Жl$? $<'Zsm*Wq5AۀMޢ[Z>64߁@TFޫ|rh?Qrl4|"EyB/GQ+-TMVFГOc*԰yyD![Oo:8NF^FE>8F*"q=:>: #GW14uI{xz$C*ҫ]\ωY:bpy2w+EY<“2RJ;pT0HqQU"Hbatxr4Q ;bVy慀rk.]zB,^ F 2aDoi\T?4Ȳh{m"F@Rϕ \<"iZ"͡A5N>N,EQ~ęK6 eYeK-)ǀ>=K  fDf3 /[_-}7b# [9*l>za]<1&tՄu?Ә"(xm@{sPFOM<|,`?On#ȓT2{j#;hƳ&)^:ndG%fN5`ZY:&Hv-IS|lgհH F/;GM4r&Kt2QM2^%HF޴8:h7BJiX؄+QUCT9`ϒ=rFA~-36(ɤr%0[IC 3i}%qڇ+Kb\췶Bw-,p}FoBP>_=O'^1Ƀ]ZF;<x" Ws.v讷iU*K>Fb6?*"|J$ID82>2)D>OpÂ-,Xܮ7sA{fj" /;gnp>R ȓqrO#7B+뷩xw+hH^$AaX#aڧb$LN8{yOqQ*={zqTvzNnrSrjK-h-.}Q`-:&yJA1bU8F?_G:=4+~BLC<$92Y2.=_x󐤳*Lf!#KɟGꓚe"ptp']T@ሙ/Nz *]:rVsw f4Q߽t8]IXg*yqϫy*t$\=[H m33 HD91k}0dt!-$⚂ɍkofb$9+7bHjǾzd xRCSY4&j @Ӱ -5-7WbWr=6!Ie2:\Ғs6#ƑF94leCyzQRQPX k)9xk&V7oa, ҿWoqbd6}ō/.囚BMBenWq }Hm/|q8ӡ/~`Fu!_tygaĚMrӃ{0Kӓ &Jk'B?F3ևl{%9LJ j. z@K2Q"R%CDc ⺆b{w kp9رW\Ez5*%+M-Zh ynuxv g-xDũf5mD) ](ih,X@RM1$)ĠRѤOCz)$sQ1LV0@X+s7ZE2[.Dci)Mzd=)Kl>!z8RmtЪ;kH~dk,'ocVv/(& CR {W# J&7/!uxb׀YvF 9{v9% _OOG X cM;5[QdM3'(in#+忹q/+ϤO@cck-P\/.4!JENi@$!:^>Ov6Y=ʟnJ_ZAΖӒ,V[<¹kyteNK5|D-#Cb^OHTs%8 al8VgӰ^PQ[j$lo%'B*~/d<;R㔨(|CZn9 #?Ȍ{Z'?bV^mٲf-W:O) 2 xȘ{-+Z*4u5ȥ-cR=Ya—3}R6Vk^sdw pfIa=]dp\ɊïOWNr*}Y< _xxJ'W]Xk.|8rM§@0 _%g&@1gFz{`Mm ɜKv%W&104x\b"9u؟7<PlE"/*\_r4@hk7[B tȋ1;X!hY&RVAV~:6 l}4_<'Z1BSy y~ i}&nmʇ1c K7e` Ok[tB΍ie>EMvb-STlA?m+X~uw PYhlꂺ0 `*8 01@Xa(OnI"JB]!HLlݱN!+Z6oltܸa;?>TOf~49Uj+nF R_Ka5811>n|!K0})8XbR;|؅r!p"Cr,`xfD- wz4H᫷`1ض\&7gPu\Vb2l23@zez1pbh[r`\wWAxI^!܌FKXKЈl\ݒx3e9^,  =]yEX1އ ,"ubHXoTbt|8Ƙ`q9}GBQ4tgjtP^,Y9ͰE Pyں55f<]cIQ /hn0L(9a}|vO(g13/q)8/r_Of~_SGhjDrJʜH$Aop*6TI^ @.a_zC}Do( )pze(LI,@?O j pЦ Z|\k8%~䑷7:)2{Wh*YTz^a'gN7f_MU10X9T-/^@Vt] )H(n oh%uNBR"rvSx«&]XX.]8ZKȈsPJAi] Z\bDik85pWJ)[3WqKELq{PGȍ5K>)&9y Fr~qT1mÁq[ߘل9Vp]CslpΏNP22HD4cǧ1Z煩!>#4f?-,Wl8xIiW5rO#cӋ$.ySŴha,?'*0<G*z$rӒC,%5@l!z- 9*L 19=^s8TS0-33xvc|_ }4?m?Geg*[a0Ա,J{>-ҿܸ T= :'_Gcj뇗w!f>{#Yj(J/dn5}q0hfPn#]%jY"酾. :xhiT̍,B4m7bW!DmveP$2bH~l$OmS g]6aկh4qG2k$){n;!B 03G/O!3Py6y,E^i.ZN:"S~)n gj=*"_jWb, }R ȅbBtBn&a܌ELwnc$6Z!ZV04("AfLoq XeOOO'afMZ؋y)m"1zՐc`<{,) oЩ೼BPe }\7UӈR%IsgDKvP542E{`$AT^d6@Y9!q"My5!$!ew&ϓ>|Y*f9*uZS>p%늖4CxxsoHq=7|HJ>dR8G+ xIDATުoo?%R,?ND|_OEc!Lv%Z:2N޾C7F*:QJ Pd26y& GcF0hx6kW16,2 Ņ iJoUϋ U RrUH<fO p9uwK1K9&W y+qa *X1|$D}X/-gT`#2^P# ׌F\^M"zOQ;HKc "-%U.¿fK]^!5`z,T֧43HbD4:x*GV+gk剞%0g2n+b $gYrɗpg;rp(s}d$-nefV6iD%w˃@My3]7tf>sN!^FFo}hb#ޢ^Z,8ߐC uaePە1WYŶ=#k#ϧb#R-5rbheKO͞#siXS SF@߇oV Dk(5/.BCt˄ 5:YNY_?矽PaVvF]F-Ca,.d'([> BRjϻ.r4叺(mE<9eKTQ*'V$%R9'v4x#WzjLNbg "%%#O̖f)TϸIB\Ƒl!s^|47⤱rYټWZP~v' "b\52*=ڱ'ɐׂz5Y]2i+[Qj~ }G[# "`zILwiy>D 0@+ &̐2s DS{h'I+ HJ) U8ߓ7dUL>v2Q~C8H o1Ya'+ (`u0F[Miѷ5-1KE׌g|\ҫT`KOq'[Ga~Y& MO5Q4dkUQ=TftMfp π@gh)Bx$O#c+oϫ|辨nSكAǥM)0Kux`RDz/G,JEcEVz2ZiC?Q=|J1"F tAIuߒU4$2yETTGDcu|<:`֥5L I ?Lʣq Db)Sq $=]|`Hr $p"L n's4d+#Lr1"e`Ǭz|\Ua8@$cPkYi\ڛ.US!66A"9nlb^AKnjA'xK@alh;~xuNT|@fqd)]ًpXOq&.Ԉ@pGHzA^j5#93Z 9.LIY]5L Xk31,hTJ y.+0IčXK tS54ptrY <~̀ѭ-4("{"x$R6kh9~^S74B!|+n p 39 3bes> W P|hNxR( d|d,+#h괫bcz$_FGvEDž2_Bzќh tלb-~ͷ?Xh*&H:E;DcX%tБ!eHo hLǑt t$AV5hL<"X9ϽӾEPvqe_a1})=uS9iө*~)gNVTSy. [G/Rͫ$s_}e w"{+ 'G] 'ƯT:+}4Z3"^DJM&[r]ɋ' B @0^R94  S[pe^b6^( ià8 zl~9g񧸺v[gɠV*RNY z0C%Y˰KtZ~n_eKWFENtunEaY'aFnhVZф-f9m<{qilM?)c2!} ~ f9~6ՄMK)5 |eCw>NB V(W2s|tJ̑0,z>Vc,F Z %:rd}Wב΁SMhR\jAЊ]PiKiնYW ,~4 j֥CHlXK5 xE?)_稈s(_+?`_ N̺$05E><1SX:[4M;&шB+YXEb<ʋa FtXXz?rR |Y#!C` a(El]d_@"3Qlv+c2aJ8 ,İEx(Qfa3dow"3*6aU%S KBrm+1>y FISIXnxA` u+y:$[6~CǻJe`Ex"a#!ab2†SbJVKZzYB2E:ɭnfuÏ=-5#Ɍ.bMEG( )2.?u-*u~4MKd i:# \yT >d>g\e;P|Lp%s!z|tEci#FcokP,|R(sO@G2-}&*eBN_kxПPbht>ݧZUa#K;K}}J1p9 klt&ncУ%f)*<Wⵚ1;Qfyi իT$?w&l-3-̩+ &(^W̜%9LJQ @2 sV[䠯:"ռdpLYʴx֭ O,[)NwB# Nh&WNp؟i5};c"Gj#1f :Uؗ=o\4|T??ٳ3d,@(E`FGSQn(? cԨ)E"PI޴E({Vk@(E"P@(/#^NE"P@(E"aE"P@(E({(E"P@(E!oh-r(E"P@(EuJ^Ǭ)@(E"P@(o@6Z\@(E"P@xҿ1k"P@(E"P"P""P@(E"P^Gu̚"P@(E"aE"P@(E({(E"P@(E!oh-r(E"P@(EuJ^Ǭ)@(E"P@(o@6Z\@(E"P@xҿ1k"P@(E"P"P""P@(E"P^Gu̚"P@(E"aE"P@(E({(E"P@(E!oh-r(E"P@(EuJ^Ǭ)@(E"P@(o@6Z\@(E"P@xҿ1k"P@(E"P"P""P@(E"P^Gu̚"P@(E"aE"P@(E({(E"P@(E!oh-r(E"P@(EuJ^Ǭ)@(E"P@(o@6Z\@(E"P@xҿ1k"P@(E"P"P""P@(E"P^Gu̚"P@(E"aE"P@(E({(E"P@(E!oh-r(E"P@(EuJ^Ǭ)@(E"P@(o@6Z\@(E"P@xҿ1k"P@(E"P"P""P@(E"P^Gu̚"P@(E"aE"P@(E({(E"P@(E!oh-r(E"P@(EuJ^Ǭ)@(E"P@(o@6Z\@(E"P@xҿ1k"P@(E"P"P""P@(E"P^Gu̚"P@(E"aE"P@(E({(E"P@(E!oh-r(E"P@(EuJ^Ǭ)@(E"P@(o@6Z\@(E"P@xҿ1k"P@(E"P"P""P@(E"P^Gu̚"P@(E"aE"P@(E({(E"P@(E! IENDB`./nsf2.4.0/doc/example-scripts/tk-spread.png000644 000766 000024 00000040004 12501766547 021470 0ustar00neumannstaff000000 000000 PNG  IHDRbmTYiCCPICC ProfilexXeTU]^{y..i0@BBQJJQ@PDDBPQEE{?wy\~s"аH#]   cee׶ @㒻sno72[^BF!`D\ }l$OH;%>'0 z45<}`G|$BCpxkaOOszzȍC<م wGzRX]n5o7=kihG [} ijccGv__{`{0,'?MAv$[J"'#+;힯l@#E!Tm9cy$lq g>d+@@H9ԁ60gA HI dӠrP k <1x ^)|`lB@8$@d@ΐA1P"tʂr"T݀nC]P?4 =yh ڀQ0 f`!XVu`3p< * wSx bF$Q*(=%凊DAe QzT5B-~h4-VGt6}݌Aы_2#QØ`04L!2 ӋyYbXa2 &`ױQ vñq8K'.+]uppx"/7ĻB|-?oRR RQYRPʡj@I#4v BPO%",D>*њH> A8CC/F,0 cc5aE&z&&8R{LS(f!fFg,\,:,,,,c,kڬYnQ ؂ΰfG[d?˾ȡ͑L\2 *ϵ̭ĝ=ȓDѡP(=E^N^cދü||||^Ux,^R \rJjf6~%By"U ='X S +ŕωJ`$T%$*$&$I:uRRRR-R_]HIQ y)K/k*,&$'&-W*D,o(TUyIEE tnm%eHzyee2 F+lU]գwU)E5}STVU#wO՞ > OSM SZZZZ}/k\+ۤwXSo?l@o`oPbƐ߰pH(clf|x„ۤdTi֬읹yylajgjް-2򵕰UkuGYD>[[wZU;]"145kSNNٝ[]p..]V+U5~qBӸ{x8zzlyZzVxxxy-zy3;7?PX=8#v}XpXqF§"" "#"/GAQZDf(F$&5f:V34vqtqaqCe7NNNMLJ>sבGS~8ftJ!)8QLrnRR̤֥QEM@<1!Q+'s K&0k+;{ɢ;N (?=v3Wrrsg,)?  Ɯ*2/j-(>]UPTzgYF9scחsgo\0ybsPEa%2cCU%K5/g]ޮbsF6z5k3_j 1 nxxh}Sf-[eM MPŖVۦۚHݩ{ӽvB{JNG|JgxBL{NX >|`~N_Cwo * 6)5=R|44<t ׉Iɹ!Ͽ}+̫״ px+Խiw^x|~~CGYٚ9?sͅ/t_ʾ|MТwٖ(^Zyζ~Ͼ Ǎ̓[m_f^{FzPHT { 1CN \К!jA*hBi0|fffa{aIi]P2QU疠DKIIkTULV WޯbƭUgBSVD;G'S7C/K? 0(߸4)',S[I=nbt9%n_k@7wo_`$S~7 ][ GEG FF[>x&P[ptQcId|)T4t4Ltvjss^<4wWn"^"b>~2A2!H= i{C+lGD*K2MPNw"ck%O%JWkjmU=!ƌ.6]k:rE̝/wA>o`>ʃC kh>37~b̈́ݤs^r{f[)iw*3il\|ҧϖ J_~d{Rr앤صu[ۂvH8 XP DIim1h3d`bceX+T@JhXxDuz2Wd.ȗ*UUT>BC[Sa_[SKˀbH1sp1Z,a-M ---MǟNK._ͻ3 ޯ}}g>ῠΆ GG (Śz(1>;,p M &'ҘZV~DjF\fpl˓:sOsa%Qc PpϢŒϥʦν8?^>ra@@`Х#WFjFj=:xmzG7zye/mwҾֱֵֹ޽~gwj }zqxfdɱ'v?;4YEˢW9~5?dF\|çi _\}SXβDLAX!넟TMv J\Fjt&̑1H *' h;o :Rm 0C (Mp`C4Tt=`:XvQ3H恮@Hbb0Xv9n!a*yphDl$q2Hd_uM<-:%; SaN3 2eq`YfeS`{~Cc3k;grW5_NG0E@'/%j!F+6.^,))!.PX&TV_KnC} b|\<{iTkўYC#{[(8ˤt^}HJ [j;cd{. \ w5X&U5$@Аp3?}bŵK%T8RuL0qi23'O)<#;Qt^q`)Gٓy+*\zP]V[g{M:KNmw;g{$-#x"}ų׌omsg?̹]fjygmsSxy(DWň ؂h ~HxD Aa 8n(({ITA'{1D 3UĦb'pxU|~ʝAPF$IdUr= u9 'M)-m(-zm7Gh*UGYBX ll˜vx(̔!4>~%*h&(VN䠨AlLD7}E2:rlr?G*S>EC3@+Z;Y'OZ]`Ɉl,fblhe~%J=S> nkGz}h|]Յ`B3GDE>9zA\bƣIP㛩Q'Nfg՞8th.U^MYs/KV__oi̽Ӭr{½ݨj]'G ZO&n=_z%g]Yʼ/6T$Itٮ?31Lf Qp 4^o 1AJd AI&t `,[p /Ql}6Zh4uLˀu^npp[xM*zhI&L%NHQDMNޠY]K3%̘ۘ2ǰPԲγdgɑ)+[=O!ŌǯS9LH}_)(&-*!)(%,!="sY"JiSyCeK V'aTӲIխ՟56k1KT yado̙e߾D=z]}^A/<{c=>;;5l6>~͹)b0:3U&:Ȣ<-8.ʏ ^V\|l[]p3jKf7MJMO7X߼tMIeqԩRyz8)!=r)+{d[yc jR-㮸Wj{y5Y8qD߾}At5Y;yiilNףENW>o1^Ew|vi-),/ohu!7ހO2yᮭ=-q=z{N-+-i9fbo;IɉqI`J[ctMkVIIv}xӦ;JnQkTCn_[|E=;_~>0>i؄ѓUjuכ*^t^ZMu75g_Ӛvu cLt4>?_-J}GRx qqqvBdq]w ~ ~Vjj*>G‡[^rD*tBC_~og\ͻn6b 6 U;vf􃵚&뵜.j&U`s%RҵzS"kpGq&:}SMrl~zXRzGEEk*6\tѫ| *KKb`cG7$uVѬ:V<&ǫv7g]]=fVSsLZ1j1kMFAǨh<.dPiu16w&`sɕ#.&ڪitpWzN+?y[}$%)VOo>oSDXM}?!6sb߸d-@atzw^2r櫷 аos?#]E>UK=G]q-t&,sv,Z󖭙7/Tۜm|gh1dWkg9wuۦ! dɼ5{]{62 r .6٫L‚;+Jv7Rʀ@lsp*5`2~Xp5vs8 L]X͆X.ڬ1z-mq[<*NQuNQoDXa1up;FgP5yNJ^Ai06e4wX3f 6r-X*:MS&,M0?}s.2SU\nh2MMI048{:pz}mї|loMS~˝3]lE\ccweYoqx٠_' ЄǍ́yZ;UQSEEh+cZ:zQkkt9Ĕ=qG5fڨW5pL?*bD9ZQ`ԲmIjj򸝌db~qg{ 6mڒ%KnzWc8pln!hvz,>8q9\xʿj#o[7^y=޻5xļs7.g'fƤz}v]+kh{_9ٮey}(99.z{G;iUZCwʏ@\{$POt0S 4eP؁^,KPOb8 -qVUU1>d1Joh5e܋'3r!ѵ=D kt Zf;OcMZ}dаF1Xsu!詫r& 8zkG.!ؼys~o4׿uܹ%4ۗ8[%w0̿~^?̟lņZa✏&hȧ7?lါ6ܙ 11GAdor 7;@̬ޞQ 8U&.o52B j\_ _/4e&yC|*5#ΛXoV`H.ԡ]p Q֓wÇ3̠8uLjeLš|ꂺ:GOaQ;-wd[ FxXSa5teG5xteI㑊~9iXXQÛp.[VXiқ&m^A7x#ܹs\,bo8dҫ[v:FswS+&x؁z&дޖ:j?_uӄZ Qw1o5i+O1Ԗz[Ρ3?XF7>eԿV֔{bQb+ߏV5sG|ߌ\30%ԫETEAGpX`cUP0Gixklrz5=\13c-iYF5 硬vL'f'"M>駳[- ^qN KFUI}][P-`cڡQw}ܳU` 9rM0;~qs_Xl 6񺼖ϬY̅?c~iJGxWս ʶ?z9cٞl}~r݊^߻;gO 3m֯^;׫pG^*(GPY Z;U传d!9ΚפÛ}&. `]$EpںkOG~蓁*%&&Nʊ1eMsu 9|)UUUدl۞kWb5[`U]V_~7Fطuʼϒf׋ᬮ L1F$ּ>:t;'^k@C XÇꪫ>aÆir4$Ū=.CX-=O$[7464ڣ1Y.gO

    ,+<2 :@II :\ $S|K<$/}ᢇfΜ#؅ QE 2Avs+;HaBR&^P %`O62A =܃$HZ3nܸM6EXwDdt>CSNE~JK/zŭFdhVC_`AJJ 5@&T W_}?L|Lj8o(+7o^RRNBz'e͓\@qҥ> B lCHwu[-sB /W@R& =xb2VVVG&mu2s>䓜矇}㏻v!@`h⣏>jll;v,{x%uٲe&pn:^}"ʕ+\}S_ٸq#'?vAXl۶[xWOLBj=zV/--=}tff&2/Zfeeqe/G|dp^6EFi>@y,"7b\" B?|}!@`h (.\򒂂 ra{L ݓG}SuHy '/!@t9 $?|DlXP:'xbƌ՟5kFH9rV1jQ<,jOpE>IH]@04瞳Z~a 222-Z˅g}հ F@)Spg}] &~ۆo/◻̽ŝBle7!@~؉Aەm~uޢjՙx: %@GwMN]Ԅ L!wIB )D2* pQZFFug'U@+M`B)"e Y!;BtxR .VoBy fg(!B@+MN>7rP, jEt ::%DbHB3Mt=jKt .ZHXC\{_ȑ ]4?Y5j0$/RC@64vZx.6/ D ZxGx@f_+#8w2bMs1_yJE!NxȄ_fh'v0<(E@4 =Xnnn@+RQ3Yd$CT 8\mm-"gz$82:IVZ%%~+!YPH*6VX+KRZ!@݀mٲI77Y7~* ~=H~9~'v7+*.^" ;rg ;Vl`3JJ.qg}0qdPbBRAlW+ZrEb3\gyF.vO=J'튱ZAkg9~@xR@@Y@a(H 7Ԅ :DG@ChM9Lt&`Vyut>!yZiBy fgQz @ @&@B՛P^YYԽMV2TR^YY$+FPэ&L%Ch"8ܨ!Ѝ FM!pDp]P"e{EEL_OB<҈AΠd[ApɃ&~ .&j4T !l&=d! BP PyX25DF#ф⦔ "B=7jD/?o/W៏ 樘<Dh: ~I+ ~W#@A'#"D4 $ф'#"EkK0<"ɐVP^YYOXP!i %)#MHYKҍC 77W1P)B4!)Vݥ$t5"DiVB (& 9M?~M/F3bY9o \Fsv9F-Kffh9ZIe6ZUUf-Bۚ&Aiwk<`'R ɓqqq}}6G<"lEe 3(h~V|@ 8ڪoBs֖,fwDRҁ4DR2[dՁD9:ф]8ڂt!%h&v}9P,)uyк9sfI!3œ>dtEHh2t(c B P;|&_@]l9"MQ.ۉ # M =܃LDxgܸq6m[n0a%m￿""jР&N$ V _zիWG_駟F5mڴAG ؿ ɯ͛7s0!xW>MMM7\C.#dHm4y䨨(8)n{@qҥl߾}ҤIx=#Bw^B C#G}0aٞ={=lȏ /~7-^U񵲲7ܹsjv?D}'9? D];w} ;v3fPBeBG}4cǎ{*ym-[8PXn/G;\Ett%K6nɑ[u Dm۶qru ob||~P B@04tfՑ9 :(p9hAe*A~D |po>,"*=VpMm۟U6lؐAB!?<&/\O92)sg ʀt@ Y< BK ,an7 d&_ 9*#:6lo'1c/f͚g:v9rY5q Ynw B 3gΜ;wbR B@04瞳Z~ja?َXf EIDATh"^.,<쳨e0v1L}wA.XKA_|YeB\z ^p±LG@;8tp=w kܫ"h&kE(Y4takQF @?+ƛ~4 !@H LAHP҄""MEࢴ4dkH`ɢHI9ѥ&^# YʛK, :dh>LF@k5*beR{,t)uy@AsA(M;dQW >=GGj=P!!}!@4!)!!@4!!}! b*<(e *#W IM)* hBBhAeB}%`Z2t>|!C4 m?t=-e Rr!RJY[ҍ&bH(t HRVOxmn+m1! !Q_m+{1\\>./!@\>vw. eMQKJ+Q*A N8rm˛&(en% !QjjjN< q7w e.wOoih0M N{'A\ȑ2 v=T <49ȑ㞯T࿢ yA7brj  ~hɅ. *!!@4AW!@\KD B@[ٛ򒗒Eҿĕ7G59"Z0,!R57GBKǥK % MPY)'B=#ϑ5 ZV@`6h*ҋ!"SiPB@NMiHWB "MDvDr-*XL.YCXj\1 !Tb f@@,5\8E;T&.bj >{_j\1p\&hP9/`Hꢃ7Az/Rɡy]2ݳSbRdK+&%)gtbrX.KRy(ࡠB/? Ըbr8DB4$bAC:Xj\1p( !Tb f@@,5\8jR 3 OP (0J K @4q 4!@\6d/q͑1暴4dQGW0HAG@!y#MP:V)$̕pqs$}=а&XyKɢ 04Qv0!(34! ?&7g1!f& 8 G iL0NChB~sFaFh"̀p ߜƄ@ 34! ?&7g1!fQi8B Py,R$DD&dф,$"D$ѧ Y @4!i"% H"pQZ%/%"yq]ʛ˳[NZiByK"_ʛ#ct5!D%ܮ8qMD}RwJRD@ dф' &[QF !Ö{ccJt Tbs!&b4@mm-6}t^Nk}q\4Oaeeeiii$??Y*S7C%@dt`%6&&FVÉHOO[$$ͅ<$R'B`qqqZm0iBQ}}}TTPBH! 6bHI㶏kWP[M*AcneeeQy,6br/}suG[@`}5e6UbnG\#gwNh_~#µ x|4x ȑ##G aC@l.aSExhDyp7n8kO=WAgpkKbbrj5 ͅ< *~ķ~B#,Y[A4[BB 8bÆ O8PF銱OB>c |x„ T"# pիW:Ta%\rZ-^_ųQ~IHD>P+8z@rf<TvIENDB`./nsf2.4.0/doc/example-scripts/tk-geo1.png000644 000766 000024 00001642043 12501766547 021061 0ustar00neumannstaff000000 000000 PNG  IHDR- iCCPICC ProfileH WgXSS@HhPޑ^ l$$"bwQVtUDŵ]Y{XPPł ;ݻywo3 l8 U [/ g%%(P6lN/::&@k6./ Ӹyl5rĒ|H=bXMx'#i#mX52hlQAl' EO؛#`s!.:;;{ 6Of}fᑱq0OŞ50_Ïiÿ́y+䰃b!քx9nj8ՠ@?~@~03'q~4']5it,tI0!ϼ q1c8BLj avI+^Ӱ/'y08''rH\v [ll <D@$5 "q@ȂERk!=#und;c9Bx! *yõqo/,>;Gcþ6G/fJho=S0x 3S >br9J&[`Kyvk ;5bmq5 "+D@"HDc%7ŨEKEg{@&l~0VP=f@mķ 7uq/gck fs ؀l %<õrij$B wK5+Lıf9;b%4ew.RP63sFoo`D/%Wh=`aF  (t F<U`=[@h9pt.`A BG Vx#AH$$#!RY!kJd;RCN!NA Q j.jGP?4C|4-B+ ֣݇ TD1)`Lܰ, K1 6+ʱj5Lbp2Y P<\|9^35އ%I:$+)DfJH]"'Ldry6y9y3B$?!S(-ŋEaS)%}.G99}9`9Brr'=W7ϒ_)SI|UjFQ3 ԳԷ  **\PxJЦҤݴ[:nJ+5 E[0E<*zūL+)+Vԫ,lV\|Lr C^%J%[e^*ݪUS UbU00#a,bdet2;'WW11)3\<ļXq@q;Nm8θqAu,ubtfi n=۫[wBG/_RKbUΰ t B   >03j537h\l\k|DD`S3D% ffafEff>-n-:,QKgKe+Jh٪Ӛdn-eC)yd˴]h`jǟ.n={UpMo,8U_;Y98vf8Ot^Er5u-75hnIܛ?yx{3sg ;'<2b{mySy| |>>}||Ye{o/?!#`N@K XT00\2;%:Vn'&/5|NZDlDeHHIdDtbĵO2$¢F=6΍m2yrbcc2bg}2^y45A)ajBM‡5Is.'k' S() )RMY?kԒ7M+vqg(`8JJMLݛ:ȎbW6q88/uo yWn-G#( [3>dFeJ̪˖N>&Ret%bYG>IdW7-1_ rۤҟ >LyPPT6rֲYϋ~n-6(^Phߜsis[[1tdԓN'~fg/ >w.4_xۥ.ۜێv+W;;:'tsԵk箇]|cҍΛ7oߚzKv{N֝w ܛt:N";(Qp|tk3k{{:^LyRrO?72u/߿^K^YVwNZ~?=>A`/M_#%k4=7(:*܍}bd`/l` ,&8[ ;: &GCCou4E244yhNx@KȝP9~./O|#`l+ pHYs%%IR$iTXtXML:com.adobe.xmp 1200 1180 U:@IDATxu+TR-n ! nJP44[qB  )nAHi )Ϸ޽{oy3g|f2=3|ر?000000A B00000)5xwLLLLLlz @M &`&`&`&`&`&`sLLLLLjJaM600000&`&`&`&`&`&PS6k: 000000AXӁwMLLLLL Ԕ šm&`&`&`&`&`6=LLLLLLltm00000A9`&`&`&`&`&`5%`n B00000)5xwLLLLLlz @M &`&`&`&`&`&`sLLLLLjJaM600000&`&`&`&`&`&PS6k: 000000AXӁwMLLLLL Ԕ šm&`&`&`&`&`6=LLLLLLltm00000A9`&`&`&`&`&`5%`n B00000)5xwLLLLL&100 ^z/nsQ^&`&`&PBcǎ-yG&`&`&9\r%}O~gݻstͽ000 l+ L>^[>}SL1 ki&`&`Ni&`&a9K.XM6م^8\<@Q֊ Mo30`/\xᅯ+~6pQFM2${V[m|a&`&`!`a}=503f+[c nf?pj (Faj&`&`_LLxGW[m{Wd.mFt[n%LL:{;ـ;&`&Pk_|E~]tQ VZ驧*EQ*T:Bj ѝ70{4 tjvk? $DžMLL`""`p",j&`&А 7UW]a8F %MϞ=00 e3`&`u& XO<ў5C*R!B bS}70:AXQvML8[l~?<>:B"&G뚀 @G&-yt @CJL9\_wucǎńK3I&J7|sQ|_o㎏?"-ij۔ @ `a+a&`&GyXbk뮻fe9Г% D! *MLLAꙀ d xݻwOyg<L2 zO W]uշz+[;(L*R! bN4Ds4JE|LL&V2:60W\q#Fi9#~+8TS]tEkfL4hЖ[n<]wx/w};\?tI/LLL`%`;vLEHyBku'ifZk&pMQ S" ќb LtlNtCfML?eY>8`vrSnnfO1W^y% $ V+7yDQ*i54 q2c&`&`oښ @sSOMdg:o?Usσ> >=X.Zj/\\W+w# v:l0bVb&`&`& h#b}LL&@^'r-(C%*\92U<=z49$k/'pWӟt$ @#` 20/?{ZDj!裏rPp̘1awu6>IS?A M:s@500o~ݢ @dgyd Rtv` )}wT +7K+5yJ(B$*DanRǏMLLAꘀ @ N{f'$fq'p",4L!cf ˍ\<@a(J(z30Q?WS00Plv2&`&PkuYO?t(`h{o>8?K/Hx㍕W^O>Bh,?.MQbej *sΑӅ,՛pI00 ᷆ ;_PZs=* Z_~%!F;=z 7ܰ['m @ ftM$ .W^Cd#F'dw#8av>~#߬Jy c&`&`=j8 ԔNb-c0A`tr)#G\x1VXaO>>~d*{ u# Pn!ɤ9i@ A¸ H5;t4700Bg&`&`vW7|?E|n%`hKPfL3t} ӡg~@(Tz hP#_&Ѕ{J`< t42 MώPlɆNJe/C=DIΟ|l1>t߉'5G/"p]߫[*i~='s%y=egij6cq?O~L\ |l~ݴ ԗ19?:HtBOU$BC9_FI/2ICbl$,MEi*Ɵl;#<_1fbI'e(Vb6T>-i&`&`&6msE006 (gn>6dam6EaI2\ iSOmreY=%'a ŵxwhi깢 |l~<-LL 7h(8Ȯ&u?&* [~m?+^{+=A7ޘT!CX`J5 z뭨x9A$*fQA300~ݤ ԓ&i8'kGnxYgu kpg&'Yg/هm@"(";4AC4׆@AIgt6Z&`&`& A ´(00pg#J3 +>x ҷo_q̏03?I')D 9+P*T:B@"&hhZ[teZR %`pt00\s5{嗃1Bw}wy'T@B -4l0 oCJ8gyP.tYW]uՊ&(LEA 9zFIIgU7_z%'-LL?00@H9׵k?aSO=W_]w}W^jºE2Ŧb ,2q2T ќEFUJ;Br Ea_ L{r{nLL>H7ӧ^-HleРAb:Sݻ:묤f}vU\(Y]|ʼn?.X;6Q5P (z)kt0S@_.}&| t}LL&Ś @M :T*7jԨrlpH'!"O",Re[iV_?|fM *!PUqđЩr9=l͆:S00 81}_&`&`E?gR)XM]ivGs1~)Q^c믿'Ău]>h܌QxgϞ_2nVerrVO'pkw̦B80!9C>%Qᩧ}_ 7N7ML6pg}6zG OL\[[owܡ234bgIŒGXnmϗ_~#cƌQG9v>\4%*Pov8ӛ;/I3ӛ600o~H-LjG+֭[ӧϵ^ے5x ~BƝV/Fe" +7yDVeFyCt! T"%U=AhtRU RV2&`&`&>opE ԍO<1|e'K.i8!mfwi'劣vځ*Ӿ͹+ܤ- P­G%CJ* 6_B>hHo/Tw00hʴULLK cr/VsškK3<2 +W7sS ِYhqG3cIC2jeEIFm}CJ>zFB􉆠.,&`&`&0l'@W70:0ގ;-q-Aۧf$.%SOMw?|g~~ 4 I!*Tz_4 Q ek%w@Ft(r`/G&`&`&m@s05W_}U-g/\ J@J+4zFdqF%s#F$9muv8_aMQXy䩎L}Q(n|a:BwTV`H4UO?|sc&`&`mA6:W40:2dHa $´<裑aEmd \$pY%dWyIlE|~|"TLBEI@C8 ќ@ͥtJgSOgCZP|Wg|LL#`=ne&`#^JBƉxi8:8׷o7|3}5/8m"f@W4M6?⋱InVR@"&hhQD#&KfWH$it.̊@omMLLJ ,G&`&`G`ԨQDym1a'? OY r-8Z!vN.tkF|(B"akAtK%8h(pxÇկ~ Gjb&`&`"`3LL rH OT~WH.3fg'',Q3Op/%蠃0DL7y6[^Q4AC>ttP%^~eAT{=J#00AXwMLꫯ.%K𴊬[.?Gʼ;믿N?2 gqBwe#!#QG,l@TOx@,R>i U* @ ?MLL `,BrK܉ aÆne2qѣGL+|l^ 4ٵ^;S&}_zV[ Ty*R!B bN4DP$S.qٮ|XSE >}Lɔ>`e T"P7 50hJ^[s5_k*! `P bu?D2뉘B`(Y,F)zF-!P 9'$TQPP !Csȇɉte} L@TX&J `~tP,RX7MLL C[F3@LN;T_8ʪO9ZcƌY{%^y@1ң"  P&}TrMTt_"D*yt뭷N9oeLy5006K Ԏ9#3#olAƙ޽{ ZuU.믿>z*IP)Sdn馨 /Dm|UƿZ*krWݧŢъ(JBkyh @ i Qzv<$ҫW/Wt`X600<y&c&`"pMkb-#`kn8L 裏$IرjxE]TV {S>lxf)yW({?&Z)bڨ¨v&1bD|WpMiaP\m 鐌 rMLL2lf Ԉn8&cL *q2` {w9P1)j 3 bv%l5>hT}o=クH"{˸#mjTTF5H$(xt(fpfW00JagYL;H1*ӂ Cm$s9v巿-XYm]펍D ޅsRnGѣG:igʹL{רL<]#I({#=:knTMLLaG}7)̕:*c3\LM"!~3U Q^xaI[c5b%αOzC5hΡ67y$/\uiI  ڵ+IKz 0vS=_uY!ҊAK. DAD1LVL1P֭,̧-Uvi)T؞{4'D'īgH$ܛgy$Tڨy>l$j߅ J2.8AH.(OLwTȥ(7i ,LUO>!==S1ǪзA'LLA=20bXAo.E~#]@T}Qxe[y?OX,lM&zJ|\ܽq~{챇 ,0RܔF1 S%}蚮e:l$*sɠc ,xiLJwY5tn2 600'wLvy.d``4մ&".~;z"Aa\tE8,G>=xy̅ NX#JyȖnA#1vec<;P1tFiZQF[Z ;MJfdc~Õcߩ%> LTa_ ԓ z{m&P/d`4]:4Hb*'(BN>B^Xh$Yg[ >|wܱ$o{T'K/-l},4 {=zr-׿5\PªEu \lE*)]XPjt,,pCP%B]w5TS!6z!2}LLAYG20#p ' Hfc4CJK. Ac,*!#GFO?4S3{L3$l}|7T3{_NTl*TD2B6*MАZih**-@3x "JFs; ģ ,fA&Lºi&`&P6k2 @ o[veJ_Ԗ8fb5)8wt$ z&}#lmVvw6l~)m$C oٰa";";9FuSB@"&Cs4+O7KC !|l>C Q J eiUh5FV$aD00nwLF `$E:믏 t3Ɲ%X".裏- T {js"<9ZD p4,GjCO/t!kUN<]! H?4dh4 `X܏> 7j7^_cb0U}43^j&`5!`&n Ԉ?< LX 2q&, &dz>袋"ŠAgC6A{eʴ_;]C,9O*'_!q4ACyiq.0 x(4 `1dud(t{G3I'>Ӧ=mʻ @!`㌅510oȊC5=K/4k~ =ܓ/\7\:#ɡl\qG}T* JI7>[F.hDl9L1Ig!\i[[Zah&LA,Lq7jNZH' | DDD4XVL8pV/FX駟eYZzi;?mݦ$ ''_\~z|N33c )ۆ&r"Q݁&hi mD8tMˇ};"@S"֬1X WR/NuflBI a 1J @g"`3b&P_X) %,W^)tCl5׌kq4f̘[O `RKFFR IgQak%R18){衇2~Xzަ!ChT)A:K38\@(JXqcK*[r &[2}KZ#00LaGf&` p2$8M3420򟫬JnjZ2N;гgϼiW#Ic;W_}uD+I/Gl1iP ^z.p$ 3@a,|w}o߾2(k7|MF5ꪫM{^M6OI1 sBaKg $LYryw"_t|phʥb(,(VkUv \@0r{ꩧrKc8&Syɀ#XRt"1lf t&6;h/&`"*M} R})T%4Pm],I+>Z>jzyH:BXv6Rm;Õ;4@Ⱥ뮫l z# b5j_!Q (ɘ2y 4#0ؙC!` J2 z2ĩ/.*/]cq \h::Lz&Be|LLcA1Z @1wE w񫯾e6ZX>Ѳ{`-(ʃ]v٥%ghtm}|  mf+9T6oC[q3s*h(iVٟ LIȠnU3 ̠GU&SB))DWck t@6;X%0(&@:0 쩧AOj|u SS\LLcA1Z 2묳 M3k\ O n%_|qI'Ig9tߔEm37lX#iUo\I7% ?U|_}&$T)phF'UP2C#t-otej$i:">CP؝3С&Qv[nE+OeIP&`&` Ž<:Lp~rq:7nGy$TuzW98駟^r{.Q:cO%9;kr _a`L( R@:]FMY#dˤ__WԗADɈ"3fh代iS4#'JG*:H7 o<R95#=QMʰ2 ƚAg8eb!hq_K @'`3);niՊmٓ+R'ѣnf E O9^xaE;+L3DF8xQG].V1g//|>V .|C=$eЁЗƴJzM4UVYEqjc?avmiH޽$c9Vwy%E`41ZUL8L iEi8JfdhT AT(3 q)Ġ *3n 1 !=2LT_ t|6;YC0z?CwްOXs&]oV {8d`LK0_ eSFFvb-49蠃 <@Zk7& 4kIT0a}vLK_[L40݌ء1vQs 4aBm? (t:Ȅ_4"G+CH"SGLi_ML&4囀 @ y_Z[K.eIȹր2CHYql}QB؎82h+B0taŊ_ ٭[/1FVG"*KNE *  x @Q1iI C# N9"AW™$j˴a䷡^uU:çLTn2%j @"`C 15>: . Vجqʰ/݄J[Я_*bɁPgϞi?vG Dm߿?5Y| x[NBd+fl$^K"AqthF3]kH0t$q7xHHdT| F%Sa#W 4teҪ ӸQTML:a @ \sYXG0-xpa`89#]vL1%rS3#c-| b\y=S(7qtGg 4 "1|r3g+)"C5vqǘrqӕ 4~Ll&yI M00o o 20q60IZaǦXpsAT^{m`_!@E #TJOCl(ȑ#OELMu9(^K/M7ݔBhzF^ W~/|<@S!iB1)]PX):BwZ% ~{G31_3B*2Ǖ 0hm;tɖjuYgi⥟"Ml0 d2}m&`&A`w&`u'0l0m}ĄP9XT)<41(OK/I|/ql-кvd hc(pW͉XYdQm\5*p5_نg/lWd0j6.:T&Hl۴ U I#N2a6}L!K=j%>55Lu=b򷱥iO]LLm6F&`&2zj`e[dkf,S[q  q2 O8gHmWºP.A|m~Q| -whQV~_86Kݻ B9De]~WwygI_ ,<@ui* efe^,TYIM˧PzQ`0N&T)1h&L4F￟NPtJ3ՙr "00 5#+B>X>nVx"ٝ<*&ISث6p 8XG^A76􂝓'xМ>UbRWgapϘhcnTkl s뭷\5Q…B27ѥKC=ʠ* !ӅԆH( 4j JH 6,!:|tLm% &ӣ;)m"RM[ 4fb`3eG^TC_ |Wl~Wݮ @`~Ds?hʺ#$n&͍ڟɾ=ܳE`DCE6.:J[2th(tSzzF{lKZ4sSs8HP+ MaNXcB7y$T ; 4 QP,J0jkݩ~P._ 씠x-sN S"տL&Oz2!=ᄏ$3&3[ӧaWieLL&e ^ym/3O?t!س=+W^c`N:0vTPa7TqٻwoE(bTg6IѾFEPjOi5czu)Ű{iɸ@P"2i(52eBaE:t-p@$hzM og}F.\8·2: QŒ,Hcr /Pen2ejjG&`&` MMKI'$ \+{Rke}R&2`]D?JPִ4'BUW]Eu^:Q(=1c44)>*[h+#{[eg*rȐ!Mu*eBPy0-‹R> Y)ExȤQDU:AM`Fb jm>CKwPUQd!p3[4P&FϙJ(f*2!5pLѰ{DT짍L15BD?20h ¶ѹ "-τhK$K7Xa'Z:#sbo/k3G INyecfqBCL^xlk\b%$ihThOP-?O.:d h /טm*UP#zנ!7nYta|R _PUGJd;.PjdB@IDATΘ Mc0U -ɴT&*ӕIˠ7@}f3u3jȩ2'ZUS00Fl6"&`&>?X.㍑FBĬ}u5ֻYauT>%3 r4/Vˣ"!"e!- _ITf"(g*fNϷ‘}7"wBZ,3bD2Ė.02^p0(i<cP4ʰATa´KƤk~ʴP0/ ʠ^I10lNPn&P;lӧV.,Nk2r#EaX%1#?lV/y09`1K0MCWElQF{B|0 zAV=|k|@8/^;j h2II(O7 @`L#Jga YXabb-P2%BӃIaڴB.p2#bL`1i׮]%>jy Bt^F6FGw|a&`&*sy0hH]|:oFT}-Sw ]7r{%;$=e}LV[哆gTu 'h KpҎg 4qGĶIyQ[nĽlZ1ԻxP?tSgF2(5R˨Jᰢ("9iFi:S+]1qPɑ#G2(1|mLlL#TdBƮT&*5:2^Ґ8ȵ^ / Rnl-&`&`A*170b^zi,g|I E73 bm(Zx&cxI\mikZKg+=X.]$`.irh}oy!;N;M90h{뭷R 1T8U={$y#"&Mw}i5l$I>A4$4M%Z;t*_Ƶ^e0/NI* |l~H-Lvi9p(aN/蔠5FD10T`X87u#!ffD6lΟZH wz꫇)vJLxnf\kFGȇ9M(X5x"` IFJ5?4Ө/xTnƑ6 S<9D&jx__(L3#PH7(UiL5u#GUm=e:1̻NN&0Ә1Ls=WS^8FK/(?^"*WOMLƓ &`u'@8Ea馛U/=@/a'[(<& ^B~)N ۮĤ)d㮻e:VA6e{;*O<Ħ`Z{IBgsTO1H馛nJ7<@E6|yL:(@1 7ާiF(/kЩ*@$iq pǞXA 9AlunS`jJf%Vk&*Y`z39(|EЧnk‹7WIyxB/LLq6qh&Pz')\h%Em֡)qUgacp$:89 õ@}%K^{2p:adɔ!ʩC1HHi>Xq@f<#3JBvΞ THNUW]BHl%CĊ Q{kQ5>d&<O{׈ h * dP04 'w.2h SdF.F™;/uSa-ǫ!2(Mc2o&`&Д ¦\L qe+G9pto)UX$S"[_M{ (2+9a8nq6=pX%lVKx׎-NHq{W[:"]{h' lj6(IieP)҇HUF%A(:EWQ/N<2 nIGS1LH2蚦 irrFCUC&/]^a10O6 ԑ<\Kl8tǝń K : V)ؔ(a%#zS:묳J gPq[]3ça_3*F798תo0⪊ptVEO=3Q A%SDan{&KF`FM 5d(x q[)A&ɔcPEg&B2Q܂Fs׊G|U_ۘpI00r6 Cfx~ei}UK94»:GdLVg‚X1Z؆*+rR{W>Fīlϒ rHlkD ǡV v L M$ӝ.(rSxp&ߒ,| Gk P2"ʢ<]b]mc nFR.l1d0ԢL6eaхy7E*ZrQMp @ 50!șֽ{wDݐCCFt}k=r$T%N;$9.2[w >IFE$\g&", aA[+Mm**Ig%\wNH`v r1RNʑHT8U19)(S#v(**dzdPQ/'-C`%H ~L‘ezu4Ģ'/1Ӊj6k00H LiLؘz:,vª7P=>Xk /tZIp:A,mHF^:Deׯc=V.drJ^q o]v 9昒%*vms1`ɰCh }L>}M#i\g}"",R^)&H 1!4P[q)Yt0R`8t&+v*CɀV/:9H6Lr5~LJ[LQ&*ӕI+Lr92K.|ƻ^X<% 73u0!5twL+]eeYJ&USWbاLi$/q禵xqx}xd:N8< Vw΋yogڢMLlz Ԛqn:֎L4hEXz-PXzrl1B=P]z&%JUoۡtqv+fŌWdГCh!y~B9m@V[U4q!.R~%J(f{뮫 䂯{> DFFV#P@03m4D)AP2_*9Fs&SHB4`L3&[Zu,=tϖpG(¨E*Bla`ͺ[p`O> U/:R(P0{"i 8&$2,z?Sai"K!0AJC\>5 jr2si&mTg:150٢pKLHɴO} Hg^^"^%ZS/`d/)^^^d^g^jmvtm.l&`#Yg0%@Hd`Þ\: %&;( Mf&BY^,c{+CfC '$DtN3]ֳn`2+7)9, 0$y]a61w1ˁș?ϥ~aY]CJܙE-9Zh'=rN;8xY.l btaN?',:*T/[zZE2Ml?>01.*Feze J_>a9gM[57y$B|1ݡ9(J=6CZ7K[r )b@u#g@Vٮ 4LSL4`1tʑkƄWjA;|Rj8&jTd$/,-/ok\ 㢝ռ ԓ z{mu$9/<~[b~kɲX9`;X"OÇd)uŠ0"wZk-@]vFoh}}HN>e]VD½aX=$)WN>0_|/\!/90Ԇ Ű^4I:(樎h4a6iP# /\:X"O E1G .C 3Q=3=$LrL6:$n3L0>%ׁiҊ-]ɋ 3xm)+ Ֆ8Sৠ|L&^6'ޱ&`Xc5ҥ$)Y|O,Ma5tVgyZqML:ٓTa0?N9a2f۹['XZ$\A2Y /l#c^kǎ%Pz%˟0ԈN*|M`Z5ՓHʓM&YUӵkW)SW;9ZڛAвܡ9r9)Kg1.\UY)DDs1U(nXqZ$y7t*СC#T Ss%`tAps=v;qm,4pmx≊H 6୷*iQCD1ݻwo;M{(Z9rdS PԒLWb)MIg% K%H|RA):2*ft * 01 GD=b*ef\Lff;K!WOȫp^ۘO^ ̏@8oqg; @ `s{a&PLb++sO+f|/6-"cGb)b K.<5P_I4C/{|n&dJ .":^E8K.$rkvr).?;5 nrKae[*2!Q QDlhFi2tY4F.B ęFa/ e80 RbGLK@=ⓩ[z &E^j#0"Wz͡0-0TژF}0lvuLXŞ՞W$}֩ TLfN:)|)xb_̶<_V:E9l/#'z;U`y $DHKFƅa;[U)&#vQ`f`^a 1EBNlYO F2qA5 fKp 1Ao 'FyDpZR4!gi8HA 38#pkVizLE3 VAd(.͌L$tnGu&!S O͙VOJ& Tij5;Ju^^ᚗW\/c(I~.2fs&`&й ޙ@M Zvx8a}%'X1Bv<ꫯ~糥!sd9W6=Sm'+{ mBpE o8E4w!lvvGe |}Y.|6.FL!FJl6/0d/i=\C;sfDpR*%;{iNs&ўN5Pj,O" (B=h kAah¼D1| bФOiIL9&^zid2QC&pT`-LHyy /b~ 0*mh~F150Ma_HrՙZ ? q2óAH֋ dE8ݕ.1)L8Dv}lou LjZ``hlos4DzB&YS:w}q.2\">a'Xږ|VG_93vT3B G{CI1ɟ0Ķ)9Q_)ޛo3 lv3AGXSQ*P1=I]hU\ G)Bh2|%,(&"ۘ %`LoLB"23E 02 [Oo"GB߈zhh+]e Ǿh|E楖>5/hǁZPh}~@R|m&` N? ԈWhQسgOrB3Whu 7פCqZC5\Q'KO$<ƅ^2Y\*pOR< e, i#5HL'ɔc1JF# S]VM^"^h4C ]V^855@S~q#~.}~Fe, DDD4XVLC= ,9\GX*K8;>hֲK^z+5Bnjgr'>BcP{_>A+u2nCm|#TUM!y~_@CV^<,;\FtZseICWG!A*rb^%|F+[( Ŋliwe*ktN3ڣp't$% (p!G AȠ pC2p 62 k˼ôadidkT+i].LO^^^"1yKأ|zѰ\@q'\O0|lv1uL^p!a%m8]M'^xa`AkX,T k0. Z ~Yg "\dD&a7tK/|7ިp&hY񷺽5GFH%-MSvrj۰iu:NHEI$QP bl)LPхK*A%Kj<5juB /<J?O?,jYY Z&y,| ED8H怼r>*+(F8a!LT'8d{ ! /̏~\Izjl?>t0? B21lz#~Ĕ* z# &I*R!¹Kaqġ|]R:aƫԊax Ta0m2gjEj *Lo&rAkF^F>@^4^7 Xo1Uŗ? ?Ï WLL: f(6pZ.aB7|_'흙Lq . )-4p>|q4tVZDXo$g&D l .ƢX涪ͱ0XPc8p7"'!A&o P\ aHtL~ F)(LQB͸QP,-k@G莤AE ,xþo, :f`Lbb0=$^wfv|͙Ӧ(KOT 0a +M{GM O7`$%p0 G@ K4`K^2d(b#_ ";XrK++pP,LcƌaZѶU]c-ۗMh®vaeS1IFi3 1/aK^|h'xb׮])ڦBIHp *Єe:8[Z_P9bq @ݡSt?-@V. t@uo9Z !f3`20%X t@[9LŦO46?}KѴL^+7eyy c 5ǁ~(W!?#.?/awFI_ DJD:pVKk O˾Xɐzl?ρ KW%+R,ɨ9F*H t6@|B!-Tl5.`ZjȼJ/c)OJn%|)<"/.J:H#<2s(1_{w쟄9>'nC9}!B [Zp܋Έ#6Nq9, RKO$YfC/ Ha2CtC=k(СC OCN*)Y+ah'@=lŪ,Bs4iI,/ `NKrD,R J1| bmcS,c2 ӃIT0LN(ՙLڈDLla‹  mDye䕔 qk+;TO:y?2Ps!Q-~RB1~j.! s:740Iake&%TyXP5:cy4mx!CgHp6|9"rJY,P !$K!xK~gIK}t? cYy?|ogyf38q gbVK,jsp - @_)-x8GJ b`DLzƔ#m?{s]R?Nȉ j$$D z Q6 75J&l@@$1#QLƸ`kpƈu_rQܬuw7Mwu\5F1j<טcԘ}IhpL)A"!S#`[hLK@LUhtu \M"lJGgL%Q sY> QRg> &6K56f=D)-uc"p0 Wyqd|ҟ9ә]ŁŁŁGCH¢aq`q*%<K /yKr 􍉥Oߋ^X "M#0 z_LP:<*+_A,+5ex0 <-KCẕh8ŗjN)E\qd|֕81e130LS7 {&گMݷ0Ww!AwmȉP$! ylO[X-b' kB[b<8>p^ĵEuDuT"M=)["cZRN*Z +m-BMgQ?Zaڪ#Xa ȹtgerb\kaL\gX^av\d"(ƄJıuq`q`q>Z$\P1 O%'?'D4O!z(WOeܿ˿ pؠ=!g?INdx5vˆΞ%'Px  q~wwExixՂzr<A뤓cT';6S2#OOe)d""cE)n[E]8KKUoE2!^%e/xXz8b}}. t<1 _"vC#s62S HE0r,'ӦseL }cj 1eSX$I c =&G(բ`9:̩k}{jL/ Kf6U Lh1[Ƭ3fڶ῍l;gRԆ2[< !Z^ ͻ4LE=&EgedAb|ܒ45Nn׈cYXXx8‡kŁŁq@d:OTbHQ>fdKl> l`J>я&W܍1C$:J`sɋ%I[Fp*~w71(fxkɐYia瞋N>yse$C^ㄕMzf[x#w(l"zck_|l (5S dLE[&V9t:׸0#R)i?g雼A_+^jy8x#u xUC-D4s[V'ͶMO t8mLP 0MΣ(ߨn\tZ888r"X,vo|`. -{aW W\o ԄH\T^|Q dLj4z@du0ɋEi;3 4r o-8܃}[r/t#f{As?$iQ˻ߧđwz 5(\b8pi^ DP$7۷mJ8 ez&2IoX6dᖏ X11 N<=Uy D6¹eNP91rNezO~-`#>m@pbD6-oR1wb0SEfɆ{dB *!v^|uXXXx8‡kŁŁCHʳv(JD$@J= ~~kFQܢޠ<njf(i8ե?>OR[p:yף֫_jx!bv!nMhwV>D~~J. z>tq%7$=$6ި- BҾcʯQ#lWnnt{OT,I-b*4sτv3BX( ttȉЉP__NR?JXSN*楺VJ3~Kɩ:z};j >іޮ.p@ ro~)5d/(&u 0zIZ?xV>#$AW>cIHazD%tʖ"Nw}5HwC,D6М*[8B6ԜS2L{uo518“NJY/>dxũ+Dp]h }N q!BbqWM1EPwn)9bih-cs>TKF@y=Td!bٔJD3Tsv+TBf"PT=H)6êhUO[\u[!lIh^[vÀc [ÒٙFtq>yҸd&J̍ZP2S 1ȩt`_q:ݲ4#k{I$|&I >2fP pe N|K q0i$dyʍdApv{ye9sKjcMP$3o x@,8d%"hp5 j3'N \,Vokqy{v袟t_dntAkX'د輲$XEE XKp~&`E"®Iο4Š숒@("}k4RE I-so&FR`j|!QDΒmr_ f̤zTԶ n7k'QNc^2)Sr9ri23wb\!ƍ,nH:Á><|^,,|γ%m V͢?>6)@TI9Z n_^+mȲ&R! R~]4@^XA`҈%z͎xe*Xbas ҝHF'JD$慁(tμab2w]e{(Wj+ MCp:|g#2BS?6j4yu-n'M[~Q:F4 LFlieQ´§ Ps#8DqD XA*GL.3JΦ52r,drbQnڰk ӫ,bm۟` ɷ]K1qq٩(QTer dj g袊, E-ש*8uY1㻩wyGYRIZi((*2 򙀵B'd4mǙ84e*G_Y;ǐz.n&Ki*8&3y^邖 W"ijxtF ޻H'MwN՟T٪]/kjo~{7‘IHpd-ӓc'Q~aюD*-XXÇE-u}a z01NTB@BOHW.+0&1dP'.+բ`Ԭ *Ru95=عƆ "C6΍4ڞa [ mk9,mngHLJ$Sc41PB: Wqe׼o-1W!Jq~ͻ8p8Fx({^p39eCz\ITBA+{L+.̉kxmL`_qP?\8rIgg,cl͢OivD3\n A5i hѓ328B9.j7ӟPd:MK 4jp<soX!c5 Pو؅iU]RT% ~ ^L_)6xo׹8T*vۯ }l6mh3ڒBHmdS_d"z{y11fdE L0_&̚2q sG 27ط|[W,!adq`qDJB4xtEugƄVZ@W{W$UBWЅ˽}򓟼@X//ǝsQ(oHsTIYfXa_Ās2ӶIwT_l 8Ö-Jە(;a ?MwZ .en|S jM/$;.+-[az^yw!A!F: x-w%ctU U~AIݐ3_@2!وow:elfO(s 7S CmuQWbLԸi`582-fn6T{ Diڪ6lZ|1.=Pl&%IE1>ɖI$1V a><*?`0ڋ3C03|M8p8 r]w%ED%(sK?I`8qgt&M:E ã2EӰWL: bg"b:jQ0#XQ A=TȍԉRQ@EA-L٢_ۧ)5eڀhK98iڼ!XjkL>j3g+ $)4,4>1} g#:ŁŁŁ!|Y\X";pO`ܟ6}? 0>ۜifϺ(߱l7?/괅Sźlm575 ~~yqTBf-bĘ2^t̠$kÁ><|^,F** 6R/  ~ukՈ^/\;\YP*<SLG.V~z $a U`IOzB.PL?:NR.ujG$Y,}5T>=(loFѭ+Z_LT>8j( ]4t;"=' ŮA\sJk SgU_UpbHnIُȀ-]1IM}Zc`Kr3[2*gbu:"*vDL]7Q A=^0F٨\n<*ڔ\ŝ܋@xhS bH\LhۍCŖi7{mtL\FFbJsOIF,YkdL $2ɾFex&ŁŁŁɁ>Hv8C `S`C<9zCbI<Q)3Q?<`%'ՄQ1T!:uV!r-&dɣh(CwMa)vqu7`hᖏ cFَgñj@rT( X w\ rJ[⏮PF3Nj,MPF;mџGb8Mԓ6-%pojS܋mms0_LwIvToj"aЬq3N L_DC׭lNMv)\Z,mq`qJ'QG  Ω$e 'Ҹ+3 W=2j)KR:=a_$Ubےe.N`.ܙ׽uhE!Wp%/yooiCLQaWq^Y_e@*©Bo##yqmNɪr1go"Iɘu&8쓀ۧW})4 IE)АP4lt&5XZv40[4ϫLk)DC@'"#8#>[1>M܄NQ(~<9a8ET>hT}[.69zql4-|ovM<2LgO,1 sh$4MGLh7 x|Ffq2w1 3Øl0yF@L.3ŁŁŁ/Cebvqro{` VXG |C]tHW*&=ZɕﶏVƗ8bꂄ HDoԄHl (kʔ|qJ<4{  o G>o *r80Ů'(+S a8`nOzȒ`W=zGDK;w E IuJl)tꢟF7ҍn70Q,].FH{KR}{XヨntL[0M#87|7l1YxwnDSPZWC 9u.Te@=]s8 fm,D6y $9!= h38#oWI5=6%"1_EA\Nl?[m\^ٌiB 9p\tM~X&'k|!ӯж%5碟 ǧ"〈D*ޘr,vW{$`퓻N4DLUBzt7ڣBc1ei5l5O[l>=mҮ浅md٦*D%aScqsʎ`ĒP<2} 3qbq^|K QiF8j/,,\Ɂ^ɨmq`q`ALv:+_E*ky/ ;Kl5u2GԷk,ٛRzԪU 9wJƯXr11- *Cm  krktHA8S#=ж%;RQHQ.y :`~]r?C[ G)'8ۋAȈ $& ؋ɣcCA2M58I(iv +Ԇd!-D٨ţ~<=RZ\g5L@mbP%Жlڰcؐmv[7pt`Fr?ڢdΑS+fܘOe eƒMƓ eHSt2[֕ŁŁŁ!|8Y5qO:u;ccR#9&:(sM2g|g erL(ఓ /[Y^X|'!6ƚ#%5=!YyX!p)q ,- '{qfT,xDj* ;z78;>.cӰ7pj"Ȟ@A1;4!D*`Wh]꦳[751>G@$R`!cQG_1 `#f#Rީa1?Lr#bީTUa&UԒrpBjnVALJ 'd2JL@6mh3<ə5l;' .=*2$2673%3_x +fHC&1Wygdf֭ C`]P7"8)MozӟٟyR.@ QѧD%LάKgѕѥW w_+⢟tpv7ět&"$!`D0,,d ӚA0{1/2u Pbm+q[´jӧC r&S܏{pikmesb6fӍU=m#˴wG^dh shl4٤LД%KLt&oЁcʈ,1@wмx2 )sʨ2䭋!| \/FHmLAfi7}?"JP`H;:6O?P&t5@Iz#"Wx;'oHU%Lmrz5# #aMzu}4IB?ptB+/ n~G@k L5L2DҐ!s8|ౖ#L gncdqOQ5^ Zq&0ו)j hX7pgxh"ciۖ`!uQe;l1ب3b#fգBӝ )@7ŠU'Z O:؝C8dZR@ h-9𧾽l;sFe]25/3 LVgQ$_%M #3l6f]k.v5X'r| =7ʡgbMu]x+nLRpy\#L)MI0+|pDLaa+CC+0?7sRDXo\Y7X#Yia;u>8`k>Ɉ_gmlO YԸ 4TX-񐞧P]/}Td#oS4A,ent˅rA&ZFiX lᖏ ]6<cǰ$cy^e$m&>((@%&ڴQ `#%;Ѷ%5-fAlŖJf>N䊹lqۦ=[zg΀0#c N('%Ycbs_Ί1^5##h٘V1ne=ᒽ!|<\#,"xrX'^%>7\? ] yG 5m*=@~&T d|p7M՛[  n] #{=EtU <_{K1/ΖZ ֑S xt'ߒ!؅:b pa+/w3&$WD3(Bi7#~y?GD؂LJ ҦEJ43 Jp&*XG2{.1 ˱Y\Yb \ "Q(n\e(( U2jg[rRQZ MkM+ck 6YNIb8*v׼5nƒ I}l0OU^җOh{/KMP&TnG2[އq"THQ͏eؓn8_4JP$hjsM RE YRTJi.Ɣyt}C 6&uCqmPf%/'mf6~Fv&°5)i.avKOI`1 Wqf.c2;3L"Hv@Ɠ sȨ2 lo&7!"f]^s`9j\EozU:8 XS|B.h NxOM#^" _A7>Qp#򆞽"ީԧQ@'_£T8"~B#0I |lTbIb`D>B&O W µʓAk}ܪq5#EiO{ZXm,đx 1+;jd 7[0'G܅iXynԉPvn*p/rPC(HGH TԌhS>0Ho(^ ؝ecڞuqGڶ|<mNڮ}p`@ƄIA|08 k|5֯nF33,1$S(:`HITef )Ne)h]ŁŁŁr`978p8ztw`rg~g/卂+QE;XUr`CEs_`޲ .؏X\JBxާÏ菊W6d~Z-N1Ux^&h}N w'N=kPS۞ZUNZy*TPtf"WpSiy/@jb ʓLp/B~*yD ^pu6!EvR(NPf1Ԃx,%-*`'T's,c'Ixcul[ pWǹ5@o<[LUt.M@on'!4{/KJlp0=u'DBgAYtVxU77W~(r3.:%H`4 :ii ǖkVS0DaLpYGpЍh|ط έrEę36@=)4U!np7#2Lj!]YqF!aV'1{16| 1\(MKs* jF:r RTJinיJ_|fiH #u=Yݳa"=U7Ahd"?!&ER' ϒkw1a##-l<2*s 20SL2L_v9]B=G`q__0QT2^fOԓ %lD՝] V犒 JNB M*9=? o̾`gO"(4}HV>8ve ˍ} q^9*\Q %#qA sϮ4HP{daQ,h*"Z"2SHs:ELIGyx}2ޘi@f#I"%oD'١c>ʻ~2c]=y4}m3$MRF6 uYeZl@l_P؎D`29ػ{!6 Q$pfrQBk?Dn3I3m&xFnl4ͦl@۰ㇶ~ڼl;Զe%F YpM$ NyۈBӆ1th c$yd$< ccFaB V\|".S\ bPJBUayJ:+O(\](3Y@"/lF-aƴƴ=mRll[FǑ6S ĤX&Cq͢ sy,pC :5w2iUa0GAm 'Afg&'gƧ'X sOQ%hX;R x ^8Ze.Gmq! F^QG!fJ>? g ]RwalAzE޿ۿMEZ8I Fjj!IpJD@% xO[[bG!6-86!rA/x@aL΢vB>-V'(,{p4KgJgCHȣ01 \s8t-[:0QEq>msh Cs&@lL7&Ig!(4oNC ^Mɧ Bi S38*ˀkQ)6nV'ݦ5lז6R5l=6 ڶ ?ʦVF1 CvLO' &!,>SJ0kTޮs]o`ӪmƖP1| u1bW1?Yiq`q`q`rGnl':"(X@#Ip:. "%IÔj+N.csȩ5g3CPO˸þ*LriJ#uknWB((!+Kh5"Ǣ,$>+]*ȸ$4;x/^Av6dCVn_;8q$96UDYa$7ykmȤ կVF|ݲ›ǥ4 3T \s\oqGw]G`8uÀEÁZqHd<%Hİy0omtGD^_k!N._=Is>IMtz:BLW^B&Gx_N LJ7BLtvˑj"әtIXYɬ+h.LE┄8LG|h^YM܄NI=(֟1z~1}̠[`LOϯ ,3Ks)+ EĀ[cw?4vēu}q`qp`9Dk;UO> Cw"-Y`9N AOsxt <D 4+ian 6/˝/Gu=_Un""+jϯ(BdwY Je47vGUSZ)a %w܉g?'Ǩ E^詿mHP,1m3Tɑ9M"/{7z!zb;D ({X[ Gj߃@ŭ@=:(:Fȶʯ PC;a󊠙KWTJu==Î @c6G޵p%`uM?~TVWi4pj1vePOlGҝ圄)Tث|658ې45|)F֍yqBRqQ6R fIpcY"\yOnIi|؂|W" #:[ͽ|?/(7|uOsvjW֦F2F&9mQf@l؋~艆)G|HpJлLۀ!ER>RTO$v6HFelgdnhl< /[lgbmpS죢f`4rU3>SKxɚbc*ugdTu2&ᵺ,3ΙͤO־2yϩZXXX(CXVmnIeǞv6X1p^I ~MnU42D{ywsHU=_OhiL RA,j1nŪ9#$}2P.f J/8'  jT pqGBf9EB4ƣY'!fRF  LsQ@IDAT3@t JӦ~pKTm9rBLrfK~]w+"Ap11~cQOGg;)#%Dʛ/:c: NNa n Τ y 5>-v#2-֒8Q؅iXr4.JJեX7O4AzؕA45e+g9 P#hb(6#m۶mba}l"[iۭWlCі1mA&87e\Bsuɲp&&`u")AީNP#OR4 ?Ozmwye[s"m[$16k5/鹸;> cR=Ivr>y8.6tv>&Eb4h˴ؓE.LKp1s ñ+zw %8SX zAR AI 60;a/CĹe:gW1ID0ƦlNrwq=gvݤL=outOaѢŁŁ*Vh j,U&*QZRƨP&2;` ɔ!TIh'EKD#yR4,95ݘjȝC?ohf~4pp)OPПl"%?k'Dr5yu ֦j`^(-'P8L RH8 KcOFIhWfg(xBޖ:K"m.ƁG O]H5ʏ`oɜ7M᧋kی}{U*F`9f?o=tТdr/| ~C{qo|#2^O.+6//[L-Mek)FY2k#X 6ò Kxûj/,"`4bm,1aR)Ƈ "r-̔1Y Gme2: 7t{QՄ[lodcdާU/;@sF&=Z_X)aᮥv 1&(u'BJ{a|K*݊B%IB M꺬Y5AS[EQ 2~6,NL( *](%!"r8d] ¢Xw<_M#_}KGc]ٯ{_BQt䆠Q"lA#I\ 2BI,EqzHR0#J#S-20Ж*4g}qdMd·XFRi).Q=15#(bSb-nt{U=#D30ғ6RK%,2-֒'j9XQ؅iXwT`8c>q ь'8#>@ Ǟ66S*EI)-եE4}bb#{mŖR+Mgі<^[bp6`cLIK̀gRȚyduɻ FYcu F4TEL_wDpWj1ƻHp|!˘8.,fcr, j¬) l"%}2",'mr 7=)/qZg968X/A.6ہOuJ͞o|1 L%IZz3~0Pn,2WApFTL 'e -ƑR%~O\ky  mW=yX rA07eM*Ii+T[^4Ȕj5+>2Ai}yMD DZl jfRKɤMO: TkM oA:>86ׅ, .(GXؕ~Ҍ ڜ^IB[$5SҰIpT'ŵ4s>z) kv W̷Yc08AK$jNNǦk1rQ'#3; d &uʽG} OA`O٪Kw229fG#˙$=Yi:+JKerAPmzj62_GGZŁŁ[e.0_Lyd wI+ag+tHv_#P+-yU~û %{Os#\295 8<u؃tf!<4}B{\F3VL|H9B=89o6R6L - Lj)E R=9AeH"!lrą97^˽TpwTJ%,v:f E?dP4lt@ۑ0!F6k!i[ _1 0-í@s1_̜ :>al*eooibPJBU( NMe]*rzt[Sm,h47l+Ѯ_T贛lj[mv[Ʒa>%yi1>\dj2:֞ ݤ\S#2f Ei>5n 2l &ZkϼLz`` DP"_.O%y,1/+@›Ȫ UϏ;=]̳j8e%MTg'j3XR5{H6H?3`JΌ RtT"9so( +NwʅH(d6 \vBԊ„`TchKe4utETFLID/ Hc)FoOx+T$;@MDpG( UT6+r^a*7 =p9$snd.!џ lx.w/R@3v\GnÌsȊC'yr7$ |験}l蠛nqۑg(0el[\LQ؅iS|FB!$/a@5zձ Cxߦ~*2(*uS`jLGz,cD2l0:n6Ueڶ)ݶ!X8q8^G阣16Έ1e20zӪG8 w1lLpfLtl#tcn$󣙩 Θς迏9JKWڋ^2q^_e@?D<18u38<wd"D9@{j ż*򔜁a[#s˯=P <.8A\ W0>"j*.Uh!gx D'm:fFbpwFuhCQ/ B,!OO[e+`%}Ev @)ͱ"mIno4/W% ֕z0Z 4œgOץD :Kt}J,%'Pwg{qox8VXsq_ <ǩ6M7xjrWL/q!?pNmXm*ʁ/ƄPd䝆~0M:cq8~x 1K 々&[9>δ_+rW  R7Η8<v`GbDg&?A^b .i+ EVdIE۵SĻxGɎX9:VErwˇnk:X?a&Y^s.+FpmA`@EЅ< `9:sFQ0j`nm5JMqup0B^Snsq<=yv+oVFRoNB([zg"\Erhc-|3I])gFP!UòH*1%]V7syp化ϰ]1O.z<˰}Lfq`;Ut4x{Pqi{4$4]5vmLż2`8:lxHbG 8o}0Wp7KQ!yj0Y Ε͈3~ 坚2c]H +11אpn,etW5Tl(QgF j3;>uTD!i5XcCk|0P@"5!5C}~Bbb0YI|τT#TA) 5 MPMІ ( vuRW1_ĭ̻rc?noWd NUz1~+7K:8~DW+h>hjyo3 _Ws!ۑ|eAФ`#vq8%IUtȩ-#K(EX۳ t ndy@x&BOpD{@s]٠NX!:-1üiM ~Bw`1Q.%ՓnsQ."6MX*شf) fRyUJq 1tPPޒƥrfo@s.nW4@|{^MVEzWvƺPh4Zt_#wz!x;4^X)Ci-9Iy>K^e|2=(?mH>e()vI'S@cppL(2LdVH Uh #"=xr2eЁiIcE-"_2?".Ḹd'S 91ƣևYGucd0nRd2n0pe%aSɠ]Um=ObKsAQ5c-SYŁŁG5C"qR[E)sT tdpy'OZfA`PA>q2rR~>A805D.4iST%)iLh}L}rϘ#|좔Yx3|ϕmvAovE*SeBBpR.9 v 0L0$>m|Qo2H=r|+a -ȭLE?O{}ڶs}MjFJ{W󾧟Ygwe&AA!W((a e )'~]XmW ҝ 'q#ž wˇ+ZK%[~㒫:ԻVWMLTMlj,r֚zˠ!zz{~~ kT`l%B[ ,suiO{)^R#oW̋uKX[KۭC-^s/W~2|"态`# [4(g[;s;WazW{4#Xֻ OM:#Ub|= ?ˬ&40b[_6'5(j__B*)I) Nz+A>EB䤁.+!ŒHD:hN kxq9K6܄Qv9kV }]r#9)r!(5t> |"de瘗d/U֒Q;-IZ`,1B<6)"Hd[cMn jnLM@- d_>%(nƼmNnHc}K#ӞO=bgA HȮ=ؚmb\,PTTn1K2^, Ⱦv9W c7VB9^KD.AH6HȎy(1MQzwx0<&ʡSGOh2~~~!O^ w{&ueԯ]^( ,;^m/xif]`5[YpzY4Jan1"iI4,'WUEaY#V_o7 31=hF"Q%="XT3]h 46,Z!ܰ'0-_? U$" 4U'B(_hDsDW[a>f,LD2E1FbSbՒ 7̜tI/ا?2qMlO." ײ;ItKa[VZ-i,6 l7Mn ÑGY9xjd~R`k6$'^gx <ac6|$I~ݬ"E]^5 ?IDύ>%7svD`N`/ Ǎj6o6`ٻϩ4-"  QmOMZ",N68<<,̃2vGoIRz3=yoL6cJc/ס6j&^˧Wl]܌ CȂXhO `HAKcSš\YW%mR̥a~'V!c˥7Z|#4C`~'55Hyb b ܸY3ϔ<5l 4v. tR+;L{2yM@S)X#8¶w@S`P`AJ2GS`%) #='WMJ@ŝu =JR•|J xEםѻLI[`3?COj׿.HOeYJr9f%IIw1HW#N yҦ|RKf([ /KH%&'Ys铋|921KӞ79CJgd-SN J]ϊocL-ȕ4(06堕";Qph,Hז'H!iy ^;Ę+O#W4 PMnEissf( ['?!1ʖlᖏH Ȃ8HPȅhH*mlxɏO ƬTn4m?T?W?Z?]?`?c!oգKћKUB@^7/W/S2^R/׶X(ծN& [ Lc9,hjqa_ǀ%*1Ll7Po4Zyh0g,6rƑKWɳ7ɥ0|l?@! LXࣖ4i zZ艌Y҅@S`S`צ@S`PL#(P1 xW\1V8is7X B'8ؽR zlU{VI2!e@H !Tѝ,H6%A<.&ոE2$ bլ(*3$pIEyK5-F (?&uRV%\"Fޚdf"jK d'O ʫßf DI t۹V$0mZA~ۨxu~ ؏9j?Qp/^+Sof^(k ^=/ ^RjCD2n2☀,GᄅD 0VVk1[nc1Ll(LbSbe,ƮT2;i]Zh)%3L@3\rnаtB]h l( tR 8z2+J c<(%礇1k\EҒRU`0e !GY ߑ{Dw8cQi8I;zz.*{l5OSw$1-͟@NF^xP=Gէ}H5'A^6"l,شE+LlHNO Bd)XHRVKh{~Li_ƧV ټ CN; /E׸ayd!z~<5،mObGg'%cgz^4Ϋzi/"{ѡX+ֆ!F]D69>t J;IYZLoD(LoL &Y0O*bѤf\,V3Ʈcu{*~z F7,nQ" }4N*d-~Y,;LK&-kS)(IeFg$Ix f#`IFp9CkB47tVmx$jO ܎bT)N;BIǭN{^^{mmyMhe-FXUNEXVwף?T*]Ñ^KOVa ھ ?i ķ͟=Q wa FB?g6xAp~64.^7p΄xsR?l,Fw;%DF1ҌJ/nyau INn7g~mHV.nT_R5N{;{HG;ʡ6Bvg-}k6}CKNf+vG p*{]XkShI2^TIN |ƒF4q{ڠz) v59̖Bd>uo,jsU# ]ѱ6E~#Qt)hhp= Qfg[3.`2{! +|BP(hzp&yO4Q& P8;+E| :=>N8ᄒ-vwC{qA5t.Id>&[ xL5|Y6z?r!G(Fj`Hs :P[z ]|ŨJ&,BrPʮnv~f]t*ewJQory=4"ar[~tL~7if/^+W2ۏNqvզۙF? 5&=.@tT=`YP>tl܍fH4< `j772PXl-;QWd>h{GUmpXS-mTNIJ0́|Ȏ k.%瑩at`)~͇~[t)8hpHd  X>CM(I1 HአŸl<8 1e|6v@S`SzHP3~!S '~K^"{ e]P."0L -$Ըtg( @6"}sS ؗAPÁdc>&T @IDAT,B{ɾ7= kL͍YĴLe 37kF:fhCv#II0e Ȕ4þ. Q~Yu9X$5GoJ.%bߏ8FZ)) xa^`Ԣ+Qr_";WcYu&4ZYXsl{ ΃`&NdD !J0[ѱV)jYKb E69yi3 'x?EW_d "ßq!> 6-X9PGFgdFq߾efĚz8eY1!!;:ץ.4nsX! PQdF6*6UnXV{HTҗFu >$ ͤWqFxH|1d4b$y{ tsdfU32 ؛3lr|3= Vmy#d؞iLXEj^z2͍5ܒBjoPp \Bɀdsci l 8>YO[[^X/+W=G|/{!`˲K(`o [pnBiG bc(_W?3*gc=7~jrB8x(`Y)i Yw]ݒkcNda3 %m Iib^̪m 4 Z!*dNUkMvuúji;'vk.RAb]V.袜HIԉt01UEXUFΪ1yED ۼJX):(J>60Kݎ"Bȇ[?j!q"1&0d}&6+kCY_W4۟@Z @/RIlgǨLUs^A"рVF<| %̖!Uɾ, LA{՛ KL<* "dh jK%$2JQژ]zT7<䗓rtH_bk4X {^[_X K 8-`-ufFԇɸ`;g07,(nAK<} <44vyb.xa.a:@ P( p h Vpu) |,6>m`:Yp.7۟}0yZ6ɖ Xc6'/6쩹P:jn.6}'_%;u? RNj|Ͻl:-8g'7݉;)1,حպj% [{N406WekĮ'M "ՒhMx8EIzPe 猆5yka#'pdWWMRx5 ^/4S^]c}뼭m&5n(j`&X R%sv0,#Ž0% ¦0b/Z.YKR*1LlB+3仁b8Zuo 5v86WL A"P,. J+ifQ\mՔ ^sf)f]h l7 BHƈ- |r%k4ɪ:pXT\pKDh@%5$ 5RF#-En`fJ54c6C^Q1LwyK<ҭ Ȭ#49E(H1lͻ`) `5a ;¸ C07,0=`'VUoӭ8f>27>@$4P9&BXPP[LS^ < A 807VmJ`8%c.7ۍn7R@E6J `i#!n7bb6ʄwP&#mlD*|U@. РptA5F!/!$ν\4z k1qdD$:T"1|,%ڇ %<KF ߔ%_ <{&0$B ^R>6U DPMͣy݊K\`Ya¨`1/5aP ʷs0 f%+L0M HS'Y5i]Ch+ @XuGI pi inJ{sn(t5 2hظM@+ۚ*R4 ?'c]J!$y\ !_$iwUH^`@X^ӌ G'í$ `̴sdJd,У̤t @oA)J+嗢|ٺB[HDkSK{2@ B ,k7K?e.M_MK/W 52.|)6^a/D9"tEۆF0 cU5^R¾01ZXu鍑X"X&960Xl6UT1ZڒَDx&[Wv3y`UcQDG^ ʿysj rS)( v rB`϶thX͎[2r>7Ds."dqdQqVf84 3XF͸k}VB-˷CƆ ?QAcrOm9++7Dzzrk|#=ɬ=/,/S4?Xl o+#TIr @$jȜGmv\oMH/KU-Mn fc^01"S0j0/5XhΘ!1b$V'~BUrRź]8Q*g2Wͼf|'=H$- `fH7ڱhC0>E.4Z!D!V]vYO3a@0L.7* NX(UQ R dzb]J GQOS2斝[+;LϽn8z"OC4~<״1D)jf.I$$7T{WI3K&PQV}kU;Ylm 46 ^^y=Z.1|:ֺ[E1Rǚ0(l+Vak.a>.af\;"5kuաACսkIR1$Zhep J\O@ gڃl{M V:hn.7ێ}a.46|.»ʆz!t'(%1 m}*h*B7G}I*1L{s="X_!E7H!ۍ39,_׉zz6M-5PRr 5Oja7D7ȱBMx<eHHNq1b.'U訰ƒՀRT_XN6 |xpqF ULsyLP'"ЄI9UCu3喌R,اE7 |:pt) S{zI^ & UaGNF6aqi bIb&yb)vTb% \+>ǙS\8U;+xr5P #8 ;7V5^^`bRMNg_Bզ@S`!.>6\ivꡇaIk*-l3i3H):ԛn6 `)Oyʗσ+9E?z`euX03&M褓Nങ3%ECc<׽?' 1 7OzғP?ĈN<(%[Ӹ>g8=[r%K@Lrw?R]BS)O|cq@'?MD~ x2 i#>@ 9SN)>I-W`6Ic 9,1ۍjDa~w~#d U#w<+W_mQtla_&m.@*PJZ:X(H3#\`Ї}6[[]+Bxġy-| Ν&V{}jLG=1pvY^#${n8-PP'|Y3ay&5\Bn Em/QLx#\%UkRq㒨b%,풡S/t%d\ݼhè, Ӧz4]h 4֢F]`X: v䯸fea\&V[Ve0_1{צ~ѓf1[w*V!cȮraƔXhb\b (ae{P'` x k2ae7CfD;^rS)(Ie%բ< ',@pžMAJұki /a*3<|[APBB7im7gW z"i\y&>iƃ#mG+ HPNk~I3%5QjJ6n9M #HFw-k7UzYQ#h 4O Lѯ~-Al İ2 |J1劢6)b,fbV![T\?g}M>Y3٤gDTZ{ X. &QG57A`OK/vp2 Z@sl X](lT#ah 4Lp/Nak*,X1ևW{$J  b/[mL sڃ_#D̍5j4Wdx2h} ,L7Y) @.slT7jظ xl@S`) Ӱ{X! g-2q13ŋ O}j@$jZm'<!Dx %pDa'9sc_$\dV4-voG'PRLM°_@Ni*Cp |+zv)h l `;aGkqy=F'0V\ bX%+ ,#N1yWWEXwÍA 9 # zKu^-煴[8+% zR`lڌۉp qӅ@S` ) o_! @ks9'+}F0}^qP_ Ǟ[<|Xp$qbDVЈo,H8)4=Ya=L)uoaT&j^q"Kmd (+ H x[IVr5\q9  )h l `JXMbSkIadc\lB:Lkyr1^Ɗî磤UJ08rȐp-&hi=u2V=D˃? Xx/)Q n[Dڃc~=.@VwK`vRjȤbQ2q3 ߘKş8d AS 'psyd.$7O}E-RS'W^ŅCUIid!'k.DƐ%BC j*GN|a=WXq}h 46,0+, ¾Ɲ\nae1L0zY5aX1-c.ͭ{ +P `#GR6 [ɍ6دRYԶqı7-bl2ᚠjiV W_Am=z 4HQ Mͦ@+MqU(qXlB/ʮ)ݙ_>#Mʲ8J*O=TJmQ} ŝWBu91:b=@nicyb='qqTLd93/| N( }|hnB*U)KS+а5mESZ1ؐ x` [$F]gFC 1(`XX fE %d 6WҲ`JP p+( !,ӻhpة) v3fS1n,RIg ]X] Kr6g~N~π%S{ګ>`.%roS&+ mk 9uUW>5zGW&%DP+%ғo 4FazbX.ƋbXqzh0 C{>p v'f`Z7eՎƍ50%fc ] c|?+,Lup&M7h 4P4S@4?s4;z0FuөqG{2cFqc$&1]wm揩s G"ٜ\]t-4aZiiqɔV@ȘT`1)h Ap4ɅSrL+Ɛƴj d,n3Y݂d100@ 9_A^l@ĀT \ЄZ1*5@vrt?^VS`RmHz祀jw\\=a<Dju2!t2e@+|e<җQgvciqXLxr{2Ӗwf W <蠃H ;gh 40FCsԬW3_78@a >HTz' d: 2p!sn1 ?+ .+>S^c{5= |e +C)IuM]ϷW9W`}w-'I>Iz1TcftIYCB;=m`@?gɧ0٨-# FLi  WFja2D}u#Ք1WIA)@O M@S`- `{.92 _|Őe̹xA}{AC)rk >Ld$u@gy`32  EQ@j1Vj|WؠM B8}i(s\IF.Zwy FcuSpa 2oJ<@e'^{{itRTR_u.U=[+30)NcSX<5d啒|2tuDك9t~ҸB&J',mo< :WRT@ j Fzz{+9v rQXkwB3 ]تYMhp!Yr(=-QД4z7ZH&ވspQm$* .MhA'ge'?X>a $j+ Aʡh{OݕpzԣVx.d~+ڦ@S)#(bBj̱q< Rn\v`Q1pt@OALU6 Y@sn=j-̖A*`@v\|< opo m Axb=fS`g@+;n L"s K҈̟~7Yg-+Z g^̙Q2}&Ug7c48da;4QGy (:.07nџ2Pog}6Mr `0V@E<|l ؼ2((<zL T"V%gI= ࠻_A!XT9fc0= cWA3oePLFhM%hp qҮO6:1ɲs.gyAES@8ۖ__ P.=_z,R bU4͞<-WUwO:3<ɳt;,Km.ü~?6@+ۜ=Sb`'g6`ػ3VT1)R~W FS6ӟ:0WbF0U5_cwNO<-;XʵѲ>KzXxI:[z7)5MZ/Blr,dkUJb|UtD%T ,q@ BAf`Q9J,,20M d˦ |bC GF  kQ+KVWѯW/ʫ.R+A)a *p-]vYMozSQsSBT.wY1c=a8xxu3ZdZ9?bk~Z\č7X Gu/FDhz'&O\7ׇrHmA~$z>mM&b*|`>]c&M,9q.{yM@S)ȈANʠHVHk&܅@S)XA `G#D'7o H-T@@" ~2S:> Lp A3y-=ЏR1`#J`HR"S1it)KR]:=(P|B>WJ#S3̘y1gV-cm֣y՞1HŗwJ]Maר6:5|gΩ4?Q Yצ@S)XA  > pUptzTт9ZQ'pX;xʦXGjAs=; K-@:J${S 6V$q"'Nצ.IVwǺS gΫ_>­ƭnud" l /$IKM:Ut[3 Ɵ9>&6e  DkXr0o|6YWm 4MP#(g\@Lw- V-JVW܀/@Oਵw %v DCʼnI)Q]܊?wzGqss֟6|K$(C]Di<?g\-SsQF)~]mHsݮ*[UT;N~5Dܹ~2 u=M A|~1`< "A" s M]quWQNsOz:]!!!p8__||s $d$ AO9枯 Bޞ䩧`s^r/ѪIWMNP!Sr pԿ|R2wI'V|du%@S)XDPjUgf )yK^|I٬R&j At}ӽV.7; dgHց{3`DA/$``-)Sw Oӥ /9㯾jmXCB WkxbF:Cܿ%~'Ń=9qQҗW[`6B~P{y(-3}T, }G)h 4s 1Q AI]\4@'@r`N&>2#U@ܰFO|F 87|q=9g!ĀăbA N$M msuMS`נ@+s\UHBͩ#0~]R B?}3ʹe9>wyq)KaOL*97Q^'Tc 'C#tl3D4ɛMHp+!hGf]I'ZH1\QAL+7M:( *Jxܛ@pF `/PKK P]`4UO|nj@4h0]-X Wd Z P @Z")1#<ƃAn9( z#:ÝY O?trD[wPEipQGE`ȉ^P#TMѱځEׁcIPҳRJuLƄoFFJ-[S + Rj5؉#h 4M`bL)L1\'"0I <B0@Ζ#lT 470Uj`jfu 7o40`@<@ -DEH𕀡a#"!d^Z! -A~3*fD;cOmp>Wl7p8V38#@8+r8Z]&\{&Sefg H\z/$^qUuY+6MfQXG!T`xB <TUΖPmn X 9Y-ǂ4 ; MlIBB&Ll A8A0rAP*Q ;W)SSYc2"Crνw !2S9g| ~OЂn\Lw]&+ئ3k|=#D8?C$|~cK28<ƞh 4M(2Dy p !`O@Jo*8 K,b.@'sف +` w<x@>ۤ b Z~@2jօNGVwG~{ߛ(`G*;(c+a&~9G?۝$t!mjoNFPĈ1x*W D T㚛5/)E|A׏LG<"}2jBVʲ[=LFM@S)PdL)!#GӚwW>K?py{ޓ{gj` Dz"1c]n 4Mr _LPܸ+0I@Uz^i*#@^(\g!xh:YL'kK8Y%@21bCu[SU f6u/QDJ]BS`g@+;S[9_wu3җT:׾2}@k^Qu{77h'\CYGcLCuq.4".٨@5vSRo{w=wѣz~\'Mm\Gէ^Z{KP4_3j+_J'`~Z*Ȍb#U`l M@S`P yc@0K G .͠yh 4M()gQ#x> zCI H`/` ^7B DJ큦(NdG]X; c ?X Ā:)bqVO Z(3L5F !N( B" 1(مNAVwǴ*\GBۙgYg@5ax/| {\:-D~b]&0Q;eaCe鬧=0*QO~"vB3#Y[T9M Pv;^9KFΌkFBS)h 46Q b I>sDɥhh-hv"NXzP 5[`Zے5Ia p b310Pޤ.xnrČL,@B,I}ZL@{b aZTnGr~'Ӆh}osGFQ?CiĦ_r%}s+NKش\v~& ظB){`ED9WZoeLz #?z$1~k_+mrN?t W,etT$_ .Œ_,rh 4ۀ6&M093Pbd=\鄀Ѭ}hZ H O3埴SP^Q ~v :Z@x B$&&aABQ]‰T|%]0&fD;.46&Z!ܘefuyT{ԉ |ᰏ{M$r|qި\s5V0Z >PX:U@2>6!i o*w?cXFVF9ljB/Q9Um>ϧ"`o|c@M@S)%+Exxx*è+66&沣!@@d)fs0`ݘS3\>]9G*BzbC@ T$x B!D#T!dĘ8{7㊺ؘhpc>u`g`fabxF54H{n!Pj-\ J :JөaGf%0 W=0sˋ^h@~_T `L&蘜7 ѥuI3g(]h 4MVp 䳠ŋ<)n/ 3`J7AĚ! #/4Yv/N8\+Ճ~D"D F'ZDKWڌ[`ݥVD!.BQ.u)) |(+4k6~&+^񊬜|R =YϒvsOWu^7d7ˍ OЇ>/d~Ռp|f$"9P 3O ,EԠb-Yldyp 5tm*'&AFBS)h 4"@LB,HJQ x0@VCyO3  "Xy@mX␙bp Gm- 6I(jOH TC.?!DɨdDLntNBxjE]h l4 Bў o}kLp;|ӟv-PaQh;qg%e;w+Oij'E|rIX~헮bꫯγaLj<&&,jR d~) '?I%h9쳵-ST$"dg(gZG:w)h 4"@Lrz*L@ T4aFgї|_9z`qggw g-G\^9٥jD[嘚y"QSN!6RhAОA["b ᄈ/tC!l7Lơ@+YLs8;2=] ͩG)85cׂ'~#@^ ->W++ZEcunw[7$EGwqȔ(p39P[v&ct__W%3X8N>a6M@S`RД.C2b\Pb+$ij<. .N*6\3S3oTS&<!}A xd]"df$QuK!DTIEw)) $=߄qK0-mf\%Ez);!v԰pXʉ5.R]k_c,qF.ܸs??iO{n$ љTۀReyC?8[{=`̨^~{K$:^79)cXt%M@S`{Q;@[qdP}Q +pM-(Uu_6.^1V;XV -ф"9J~)DK%,Dq B.46Z!OaU!XoP8Q:8:nQ:%^wӝRELz_W S_lK ~61yZn>!F5̌&՘ AйcuQHI(B9` 6BQgJPÚy;(ʯܸWEeOZLa,Xxq9hv1n>!jK”;rt+?7N,VIR˨]vٹD8'=ɸ/yK+X jfntm&LwhG3J!#"zzBS)h 4)NDU>Se|X` x6 v DN:Us#HU@*,Ch|N%PزD F!x?!D&ԜZA!D0Z5SZ E}^u@+;+7յVw _h}./||6&C`tCƶ~ CqO lBRjn Gu"xQA KMPJREspD>6g>^0=OaB2L&zPikW?Ӗ{jM@S))z Rp}rH(u3\ >I|QWAjA j•5gdϗsubNʹ/,B!KrB}ݥ[ 10CZ%Qg<\F}ju@+۟5"0t2 kXps<Υ;oU3Ջ_&N;nkR]0aA-ӐU95ӆOs3y[-^ɲK_ook9*LHٸ7ןt՟M@S)؞H# [ 2php ?*b&˽2:a$`66J4ȮKcAV'Oă? $Q7Zx?'#骂DIjvۓnOjXxߝ|g\?bqYg) B`l`KxwZ`:Of;.[jiS`wN@*G#&ϏU2ڬO:餺,K.6HLf6tM?Sm]$ 0O39J|iӸ֠]h 4M ꨣ"VkI Gf9mM@S)FL)0@w4> d%24GDLbnsd=F롌I^S+9a ă8r8_@%WM(B !L=-f J!u m]HW$RF!>W`/.W rGk1{IbAae4Ak_A>'7R*u:O6JF8|t#Ha9j" A4^r7 %8dFACAWhțt4!)ee>KϓkS)h 4v6X`+hrt/N#|AĺE"ՃKhV#bݎ@WO}JhF!ɡ N,-L !N9^͍e&$q1DdJh !(5οMmMV5Wc 0C B0V|{8?OjFIW_}''Cz_ [7) e&YcuBNb{_QҎ)Qzt3-s5P_cu)h 4;,plERg|  S} zNVm`pjpgR'zؑnI0 \͙լpBD!d\Lĕr<5QC.(&5&Jo- MNV:IWCvߟpOɻ&^Rcե>]8O2O9Z$s#_g+S1!$mngHUO2e!fP=ý}ˬ$R6>19CK^EbZ]#}XhZi3:gS)h l Oxjl]y?  3 .(|/9k`71~b\9s^QD:XϽs/<9A!0I // 1039Ğ@y_#<)pUBS`QmG91ᕌa5đ;\/ Pd|39 v#e^$>S*WpHC<@jf'>(qhs8-!Y@NE.[[}4z5Z`U~6sNdE]Y(&ٸpp]n 4MF@䡘V ,phs (VlY-H2g\ޡJo <`Qؕ#* 8L㱏}l Qd`4,pP BjEDtEX"2BEĚL6:Z!$]r:viqI"stYqd*hx\9"`j* ᐢnqƸNI<^H /d8r{ bdzĬg2જd⪚/T`z9Dzg?iTZo2ٍ6M@S`P<%"#3 \ 8Tƛ44u z@ cf\OA9@x@~iE+zQ>5νu)1#LT[ 6ě:Ğ4 P ^B8!D)NQq5&hE8̭6Z!Z\~*W2nU$^,Hn${'hh J=bSN&i#_67?/\y> O(w J}7&3)p dܤwD*F4 ױ" e9>4a]z|]h 4M@ U@ UnWĀ,Ƞ<Ь 618ʑ4.1@)Ss^Nhe@(12%b̨5~TK9O"H.4.Z!ܺ\Xg}@p=ˢPL,1ӌc f jK' c-Gm|W ==Ax44#<! BHH!i"BT %՞!Ѩ.n'J%A2"kNu)hpir=x=. BKUf3>{gL3r7&f\?y@<"_AVjctu]"¹T=y.n`.wK6ėKU&*"kLUϺB4<0_":C!|ӟ&|W$d@E(A+:!Ev2 B%[{vPWNBy8Ըs?sxO"(Ѹ8i(%E{. ®qs(LMc-gC 'x('(& X|; TxL}(uI5sZ[̭6M@S`R`` ŏe G\^ FՀԸh2_%8."T7K)H)?Az"0-̜81$l1H,ILfxC!gu҆hLTΥiɃ@-1BQt)hpIr7r?#(7^\Nw-QĉC/Sb]Q;${}1@X?WDB0Q&B%;SZ$C[B0Dqby_c6^xaط{jg7A} :V{MYD}5M@S`R`!vg}K34 S58|Ap4LF  ^UCb@W!_ƒUHȞ6 <}(11g ?TĞ6Ѩ$8P(UiL"tYL aHF0it)%hpKBb0FE.gFؒa&+4(il0-o|cNh:nȲ-x(tP?p\zrWv8ݺ*{3DG0Ü8uTUukSw|l` YmF:p4. cOkM@S)(m>z&`Ԩ@D%@)HjnX0 sPW z2gQhrWRQDx6toLW=T+n_E:DJĪXf0bX fѥk&]h lZ!<]sN<$භm1(WĘYCַê `s}~rp6d0` ⣯~Ue'~zkG=ʠ ,uI TZ9z-В)|" ʚȲ3-{Yg'sM@S)Z Ws =&^H1 @yB ]˸}r7a`jH`ȔrIQGJI\!_1:~ZIDX"JRb$t%2wE$#M&+M[JVo)V/~|#e ؀{ rfiK<:gqFis{n,mPΐUù4-jCυ:ҠAE iG|K檫kM@S))j>hW`@*E"s hF&Y5=-:ہg2t>*}KbۉA%jx995&C5V !I__Pk_gƜk9g93;OTOM7M߄VMk/y"YV gA O|7r0ߋ0!+׳f`$i=M;"kRNe khhКxG?zv"ۣ֠TX7k)dRTa-l"gj4IR`S?lB>T9>9Km~ f!`!xF?6s Di AoШ!@NaH!U3 (8Ɂ <ɖSSp92[&rqFQy*}{sw$rB?̥ YXHd%?=Oþ[ZE|#I^oo߂J\zvWXAeG[du^w$01}cQYG`p؄w WNl8@B&ʫ>%B%in@)S*5Wizv|3M0BWg9u @C_ᵯ}mЃ%)f o\Uҭ@r.E<.JT.+<1 x[s\AxIF]!2 ȬوNiLXG0"@~w~gbBH5}:@ʞ[fЌسސ.;1Y{"'_??FhJ9 'wກS1^S:^*#h>"c9}[CnG2 rO9u5(}x؄wGNrLURsZLyEA6!]:V0'g}{[?&N` 0Sx|djRN* r3Zެ[v?Q 2\B4s[I^W*J';.J/X[&O:Z~ޠ~xw9xe/{=QR5hJ '< ʤ_j]e+0J6[Ŗ| #D%/yt23Fb=wBy_E_仏Mj(88p90`FNw{4<8pp$(JAʣFvw%AuVIR:g앏¥vqlm#bV/!կgb]b?D")|u<~ЀUz 9xj.r%r'8 pÐ{)^,CE:Tr<ګ{;w/Wdt =ebT"o}밾 {f "r%aW04 =hrmoNd-Vwv5Xp@ypvAq7}ֳ5܄r^e*&j+pp]Id]yYz̘BIQN[ z*JJjvߥW,zT|I (}_W2l!k(P YV]!OpМxܫ]v@k`8jT\f0 'ُ98AxƁ-RGw뱏}j`W0iBm2΁p{m(ʷ-"֟iO{#WmyqB>뿾ce筴_ +R$i ׌(88ppw裓W)tevTO UH!R]A)PjT=Jr|'dt6T6ōGI)o XJ\Í8(_!y2?髺G` {nCz 5OA_(=.HRC,hୃ9Nr0OjU:)h~Z$z Cn2 F䭛\|o@|lYm[9?X?S?5W$;ZpZQrPAmKv梜]FQ*eÍ?g mm:)E/݊i"]ɦþ_CviT6fˁk|$' (zq1B;C.!5ZTm7\Ƹ6QtЅ⦾uESI&@sІ=m;pC2$c \N֑.:c6mA-\-0ia<n] U`V0.nsqyp`Á 0j]C}C,k~#mN#_k!ͥνt$r<9Zjut鄢l3^\k22# \M]&FEkn{ukP'%_caCG$Cr:vT~/Mtk>|3Q88pps%x\APm*PO)Djr"ݢ.WHPzꕒj)\j -&;byJQ ?*. `T"($4t!]FQK Ӥq\=ⶕ) +ˁ ?̚ (! 2#禲ֲɪ0F 8u+6&ej7#ԧziRAfEC@~P@ra{}cKCe蜴A,?co:ΐն Tg9$5w̻.kG?ʣB5"&Pݥ4')MRTmb7:FL5k[JR*vIDŽZ+P=n&;8O7Z dz뉀 P10f\? 8- |xrѷ+6k&VM);A8*>5UCqDg(wpZɦy7deB !8YXNRf}_Zz4_q 9::v)Q ᭅ_YF[ʯ?GHVˌ$y.} ^j2b#ڦ#{P}N<8ppNpNxwɝ;eJpNߥ!nJU3|/\$*܊5c)n[or3q `!()]@فi|W|ť235X=PjI԰om)A5Uo*5dP*(kJ2gޗ6̝@MGYRYa1qtޫNCI#&:~6z6t)S| _薧A-A'=I*ltEՐ>du_u9dr׭>Q88pp.rNvw] ρLT^TaW#IQVOuR1$+ZP 7uLS)}9u<MCj}JZh[HN9q5tao \\ܗK 8Ɩ0p\63hs6Az_M2{ȑdsG&D]Ҕ1b!_+s)9~{nEWSJ:,mslQ G>Rf-׼5 >XOz&(P z#%jQA8 z+ VE*7~7fGhweGۃ70QyB 2IQ*z(nP*W,.nif4,e= ĩ:ܧ~ mP7H[l0  5@E&C 2SMN\3'8C0iL3}*WfcY εyeUz((:WAxUld"Jw{sB0IsZw~#9$i e(Vo__1Jn„ ĦCM=YW22"R29cM3l;008DpMӎH\H)eDe=7[|qyp%9pswK'AvppWQbe2GjL:%Kբ,[;)hze&U}dq  <ZlBc_Z>ˁݗZH~D h[ŦƱ[`9 u]{ԃ~`Ga^]Lyi3Ɉ, 9ڙ-\I!я~ttZ+uFߛ +wӒ9y\V osK[uŽG[t ˿- []8__>Cn=U1,6sװoqs@МHE7kX—+$Q}܁.}t\}.܍uA|pe74 H!%YPʔJXlf ܿ)2BAT& @TQOp<}eg ̬ @A&iV &Mo~m[:<ue a?:X_ F0YnUT&d^_wwW~d_Uw 7__xC)sw.gwW6hM+;[FI3mn[x TJ Y@ԕOJ{}}Id|D̘[9OM?$ˁ݄;7:xxK^j@e卢:)Tj>Qi9"PuiSO(&-bLuCG%wd3 M'#Q{ 63}(B j( 0e@kmeLx(b{Ӗ^@A|nҋo볎a?47̼L*b x \*a2خ=PjNm'k[n%Vٖg9nC沘vxr>O9/C򐼆lH۔>NI zQEݲ S832{ݒB$L2\o=?PGgx u{hup׶US)M mِb^gYQxP'3vmT\i@O1P`P(g%"] b9I2CԑZZQ=־lO}9tHc5A]AA5Wyaް<]M#=ٵJ9dgN)pm쮕kWZ0 9!>ȑ,6u{(K >)OC4gE8Eɯsdz<7vvP|ݶAQpR  MU"s̵hU_dh&1zֳG0c; 5c2swMtM[IO\ߨ H$*ӊA3:QZt ):՟MI[ B<E/t4"0[E9Pgli045 S>e r`V҈g`Z`!p"@Y;?WAxϣ$l e kަXPViQ%ZQ^O|N M6$oih cw,S@z +ѐ92g dnօ^8ե!>)Ϊg<3ppXI mxbF;4<٨CNBD\2P,OAAx#e͠2y/D7ו&F]^@IDATDףy{j@MMY?*IWտKYuYk5V ΓUv IǬC2Q,kژrJ lĻN.5xM0x<,(/B2|}ԤiM["[=tCs\88pP{,lGJ+*50^:_jFIMɌ)r:@rG@Ϩ&  \/$ܚ-Js=Yj~,iRadQyp8%Tg:l߬|]R(eV剙T)wwE<0`ϬbF^HK=# +. A e \yud1+汴o]S(Ě$ڍ [G{?w9pm!Uǚ8tݷ-$dF@(z{wEΤdJIyk'>-d_=7 Ů l"BPooDJa5r}7|&ddp'4R ּ֠mHv1u_γHf ]iWWnyr|88py5H:?E[Yg82kQt`vaaqy|kI5XWzʗ VC#)LT6s)Q(raIsX4{ѧ@K2AlR0[8ϓ*|n`uZ d3v±o!Ǧתث<}u>9p?ȁ!ԫ^2[p&q65' Hb,fG=xJ/g>䓛d6g!d@lC?qv|W}z}Co#_BP{.VΤЗZ<=`Qz#M=@V|hq`A2!]D<$ UJ!du<`$ʃ8GQ*Ph\R9)Ȩ`S:퉚Nѧ˃`zH}\HPڂ  p3{u6dmk^T X]|3ld!KؐUiTT.s&+Nɗ,nF:l<>(q0?~OkrjM&*/Vy73YaV%j9g?<<"(`ו)>i4}W~WzH??LӞ4Vzk'7'ؗ}ٗ!UfncD|۸Q)L.ɩTYM lKQ< pQhdX!62; X$@ى]2(6t>ylBאm_>9`Ks؄1?8pb(%Eyڼ5Zhj)\)_:vI5zbP)y.^~*0V ʅ f1?G`4+,MHL]/ q ^ 4`l9 2W?ci_?@v2A3AKuG΁ @1pHO1"[o] ɾxmb#1*o'ݱ n"0m·$`]hz&ͫyK_Z<}TƦCd9䣲Y;JΪ3?3j[u NIf!ZWSIeZ+0Z")\."(h0I7._R#Xr _3t_6i]aku35ե4~S==y`^2DeıL_mI'wT~q0?7~,1ɜ@yLV-"ٚO蛿هݚJZ,Mo[ Bj!l. jj.wb}:nD^gHVzq&ӧ׳n0s RATl<߶.B/(F;fyV뵷|pe80 e">A 56p\s8p‘Ssφ0+Fdvԕ*XÉ.|7yjPA)Gm#|@+ہp-s6P>YK%fq_2My 9N*#M([HBv fzyn魻EIlqh;A򘮎XHw+f%$Gh']'H62 O<8pMde3ebdZ5.@%o""qqk,>Dx(*/}8bz~.X%n椏;J$`tü0;6i65'q8Hқ^ GԻ(7#<.?+8 ۯ??AAͽf#I'a]'~]&.8_ģkpڰu;{mE>gOg+"J8ZI ֝),R;V- 86߉kɰz0#,^T'z6oIk\ ٬=*혞'9`Kzlrʲ ouϨ4{s:8pe9Щ fPth,U[R搜Z;o5rjrvQhOL>lQP0?8,Q.@H ,+ л+uJYpSBKDgf|W8p_D&$ae* ׿o{LmW_䙸2z#mo{2""g仾U%#SV9ŨÐ-U[,.-ܢm!5j@kR qR ۾2JYs;HD!#{_>5|'%iQ88p'SKs2mL6%X.sla ~L;p4GFjSo:VC5GCYOpЩuTRLE6l Vģ9 gL^$/k}*f3V3E%_%b3/"6ًlNFދəWPd3^'̋_bdBOOfh=O5]2wF$~K 3ͺ>nB-{//pD @GQP?UHz լi/#97lo0S _"9sgw77 e"H\oRnxs~h9lq8ÁLT0bTvj<V@J\ NSA=!ӁxPf(s8e^?PA ;,ō 5vmA -Xԛ7]`'>{~;h 8sԖԺ|di|=_-ė3 ikj %/t=8r@3(+Ng6 _ լmO*ċ뙢oMUz 0576aAem@ 4f%0 G= T`ӱ,In^]r0?kfYלZN Uʞ$MZs5_pyN]M6@2S KYS=2#4rN\:7ڇv %ozKu(}e,mУ|pc P&hsux[ Fǀp8"oMYzpßEF'^WUKSԱfj:@EqSijQeD O<F#N~RC Y ֻkBn/ y(0dmkee~ :ٓmj/J278Wpt7<7}N=A-$k,;3eB'"(sȣ@^nQ5aC9ݏ|#F1\2&eӼK#cU{Sd%]vtN8ruȘ@y-7 ` +ek($^ 'WϥWhQ>8pp`ρ)* >,3A\Nr}  4xCaZ`6^h[`1AotʚIit]|P.I{ނ Č@ܞ=@(5aL0fz(-/<%h0 M"Or`/3NNE`%` ^hJAlT?po`/zQaEs[^]_3E׹lLcS [K-M^Sobh*|k8I<ŰT4kMֻS?ӌ:8IƫNRI]EBg?=Ș/)gt1廄x+jl1q`0S*VzvjFV)aMiK!0Οv@L\5gޚhxyꡟ[⾒ x7B?AۥPR/BpAܭL7T;{ n*zH斏m-X"pCT]GLm_x3N<8pp`80`Wl°m{l)ZmDfEmdr5}mgz&<ë-i:(ɔ.4*/?kկ LܸR6&rfLG#74@RkWq)@NOtC2 9 P)CԃjhZ}CCN_(K*`9'l @\A/Vw>8 ¿8s9l1e ͢A%Ny TB+rh8yw4 _µr-ܳB91M9**GKCG =et^PH D`H"í99z(3P@S!ֻSX"&,k@,(,jhˀ;cOD Xw R: 1$5O㧚 `/{C9ֱȁ Ts!׭ ؚqt3ӆ$U֘\)OkzAN.RR\pz%ROgNo Dӷ{-w+?A~[ozӛ +7*>vOf2iXi;(6Τ}s|A DYWCԳdue`p%VD? }dZ|p`ρ͛UoO|>MCd{r6 JyC&<+ˁvUSHiʺJ}OfbJ袙 ū 2_9 +PNOooOKs [keexiOW@ (Oly敽oJQp X. ĶZ}o>uͪ}518 8MP|fHs2a:u6%C\.5[**R}׌s_G̃Bι7 Sɕ (Eg+,4r@gKВ9戞I)ORZp77Yl%P@ma]A?2KÊppp`A88Ay?ė/L0-qzS /zly6 9YOI&<ɥpbfKծ7uL5rIYSJj4PR A'-SIN 氊!,ϼ]2K^O\4>X҉Mu@ [3YmtxʅfRKkC1]O`}v~$8 \ePSG|cw[!Ѷ 5DC"GPf-5ZKrZ{v>Fu\M5h)/7|`;͓$Ĺ}&j4ȁ=|yE Ӫk<8p8@g¬R)[2Sq)sKIW%<(pIka/PQCO%wSmx}COg^rٕ7;'by5d);o%+ JK&X28 iah>3X/MgNDfwf}_HÙ):zhi27VO;*ϣ-l0OKJO"fG[!Sk0鿞Y"Y /W2/]ÐKe֦mBj%Se9IO>zX}X90`ys/i`V6LlIm_O)Ic/mPB]Avp r 5=B8լ)4U޾lz~ p 76 ,F AwxZ43ulͪD%*gcŝx߬m m Ҫ< L) nq63|}GgAa,ߨu2 ]'|6lVN=y1e+v2q=)֞:ʟa5IƲ$qRYDR+םzɾݾSTjo(v/k~ԭ "ts$`G֒>pۣۥ]IsdY[؋P~Cu_(X90`uH SZ۞)?yϫ#P碐Md lC1m[dY@a^%ʩcy|ʥECS딻2E+'v^ 3 EI@"[GSQ;Z@3sX@hr, (_ ŕf-jFXwrz&;l?б/ `>dN݂I@wPn>+H7k';<*vR)ӿf:9;a?͐VI=ͦFA ɑKcm\&$"2#Hy}<"~$lVDØ|DjH>6hVLXݡӰ|ΪگEeXR M؏Ek*Q88pp`XX ML`{&87eES??~=$ ar2kBmJ du-|lI^6_ 7J0EMxiGXը;h mB%ooЀ+o'&OGVF@M \o֧?m26צsWJ*hA[n` ^V,=ŁMsbyzH02&uJM|=Igal>+`sfEw#ncIO0HN'S)ɟQ'Y|3g촹@EG$>BZNɻh&g:Eru f[uZ{71!O~e%%uC;$o\bYpJتv 6%Z$XȄB!Uد֦;vBQ>80k&SI&qARp0!溎u&a^d_c fjBAB;`aQypf|JMS7MSŅR{S~) Blҁ繀VE+لL6!HQOQaFe`C V9P?z )uimD '%<#VneX/`dCLS~}W67re P,gAx7wp^"̿)Ve4YJ_m_s{qM}r(@r#<5i+;}hUnO#O #}'`2#4fք`}{߫"mp9ؘZVR!:RB^xjda2r5]jf?  Vkp1kL5JB mdy_3IpfKMɂ`Hvf*Z+^vrZL" iGu͔QĩfVyS{GrIGy;戯m% rU\%ddl<8AQơ&a \jzxU{4h*I$sABehx-\ȃ]Hcݢo+BVKzQ옹{9pw?[kYf[DyLgpzJEK?9t6RDaNZ?퇱^t!]oִJ,+Yq_e_f7|3bk !?jgv!%lo"o/5q?m Kܜ)\VW$,1,-Mc".rynm?Dp8Z27M5qBĠR~s0!½8V|svz>[ M'0 E3^K%vLΛOgf?lkr pA7_RǬ~-WЩu*ז(&+`DnX]bRh)+wM(AquhF,h: l bS*V}H,C@@ ֮ LQ}y`QLp0*WMԁ;>FV7dr/|0c7B"1 vfiYzJȌ>m\A:w"EOGq䆸)Di[Afw"Ϻy2]%2*M$цcun$#j,.BT~P?<)XM>{ Vkd*fEXhwx{|IHO l)c<&e6 y6 _HpǫyAޭ 066QG(+A*8ulYaSPz)R~lь0X 6HGt ԃ@}P$y L?cLsL%;#!CrS HlCTC6yLoܔH//rxicsKp;T X'L'JA/7<.^]^՟ѿ؇.+;tJ|$o-ٌVx^x꣟}$\DO}SK9 Bo5̓sl%W=,kpK]a|uE2treZOS٥9F`Q/)ټBd]9Ma76VkP9isr Sƕy'S*0gR_lxfEė?yl{ڛk F廰&\YtjRjXk:SYe(@jrOhE׏Zd9ހQ H=)j5 +͔K*i*VB6zn6?]Mئ,sP%fC L)Q@Zx{~泇jo=: wAx'y( G)a9m !,bU -Q]s"x@QfiwdLh1&5gы 6tu8W{kpHw&E|'j նM NɊI. . v%ɀh^̚~}u؄'uT^qPt~T3eMe@;(5f$PM9 TzfʆYŦU<$!,X~Qy'8pbēut?*ߛm]ysROxj[)}C8&WP\Ai- 4\ʲNhyo|%uK(ڗlJO)O9]8ؒ#Wɉ~#ukogY AW{kP`R3cexoʑV~3R\-+te`TٝRHm$¨ƣ7E4$(e-Ksei)cXkJ~BoYxک-k[e0XLET?s~wQ}F l-՚?$z\9ʗa^Kr 0 hcZUqԿlfB;7 xm&Q>Oc?O48k^hgS?2??[gt%oCo'_v(Mbhu[74L_>E÷o42֙ qMhNN撬k:C?gNt+xx);yuC]h&ciLa9((=iNYQUs P" Hԃ &l5 Q(4dž%Mpk+ `uZ~6&# U [@\0+"vM0 ǀ}.0ҰA\2(C0uOw κmm|>x>5ox\^BvLC} ]c(@IDAT*|s5Ө8O{j \lg^d xexbZKC^ I %J/wރrLSww P0%Tq_C/ȩ1odO8f*(dkU>[^GCPKnh :&$) #ؚ{S+9yMAv.yݏf}6mu/%P(e\թ#Rks(zwg6 g$Mk 뙃%HFW;z#ځPDaa^ķq)2'5&Ʒ[,srmo =5a BS  DQ\]Jc3Eio{C+`U+y @Z 06g@`p (F]4G 8uȶj8&KV#VU. uluPƴgeI6K|Kθ7ȩѭe6|9nH&0Nj΁mz.R P^l-?Mol)O5S#x nx3o<}aGdG4[*LWSEOSTz"&^~@M}ICGf@J D#ȸ3 !0I <=:/ TӃ&tXkp7 \/5%9PC1 Xcr- OdɄ:d=wpw!%Q[a  !nK\"~/ odUEJݧ,"Ԙ:ݠ^%$M= (XApi2.8+mo~+ɶNt39 4xϩ\npEϝ' ^*$57>==:G aYw\McR4SRܔxAFGS~`0кbĤ> -yhcf:C<6!PMx&# p^M!l܆^8׻hlup2PU\dͮЎa3=?cI (Qxz?VcwSG˿9!tQ$ά[KKN[Y<ϗ:A氨-O(x3gJpA8x^atkm59 SQQD[oM8G[r^Ќyl7Wl՛3)$@azQ88pu80`xng) 3.S`DI.ODmPA'2+u-BX'[]Rs䙭5'j{Y| FfVɧ$ʫjq1*OOS@ :rЭv KA C}f PAv`Fm6 TW8W:C@N ֵǕ&lz#pn/~/sru_ }#`j\CN&C~Ic$.r8֘ OG+`~!+ϸ?y^Kv/@?kK]/_funmT<dJeaB=g_Jkz-k"k. %Dd\s%` `SN[2S$0IoJ_Bh]ePݎCX7 z Fc8O>˪V[_{صa.AAh@M@'c٦p>|DR$A1k<8 Oⵯ}mbbr}f~tmYܤY RZm8OjՊ+^}'kM3ŻD*}v_Ĕ\ԹR2;;XpAג jQTt8ԧW ΙNbN6{Ք6:baSهdğypp r`AS)6Tl^Hdl"H9smiZk< ;>N"tNos/jŮ=cQ٨^96)nB3!RT  xu%Z M34 ~Y#3)bPA=灢l`ȴ@WXwE % WOn0{E=|*fjx(P kHn'Jέy3I4`ޟixxZ"O~ï3Pf̈́LLwOLZѕ#VO}{J1u!XUzUV`SW?~ye_hs[|7}AH TPe{\EȐ;NڴO|bHO=p AY_v(jk狁' 2o֘b'-1!=R\EBNs6 ^e#ïy(%G*L;n^ WoX| qVRF`C9\6IWmJ#5{uO 5io.J%P:=Z,,[ @5=mS fPiut(7YZ;jR:=} @fsUE9a$ ֮r_\n~Cjod(b{G!0E \?DX0Uw !ڹr̞M\h_?uC"pU~/![X-KL8e!f=) Zk9c!xFs4g0 g-'N>ٜ~JC'^}Fm".fGUj &Ha]kr9I]č5/:eDE}po6 ]C@I=ϖ‹vz/15/V' tx؄q쨿RwcP⭘)Ssb$1OK?S`F@HN'TSl:뭵 eLkZ.SY9!f% KzByAJBU^tT' =A(6l0ڿoy5Z_lgZ5(Zo/ -'Q錊3=jq K)>)I0ވmzYkAcFg~UWlK ޚjuwQ0l0"ꃣDi>_y^QפG` WX.πr+OL[)+9U`J0eX&z;xqXnY=6s} E8)V=hY}E'' oW[nUu; Cd &tVç3*cHӹpЭmw&I 5ʹk%IV|8ˌ9璜?ؔ՝;~ηcG^ybD p/inQ{ҩNl~Me?MSԺK*+T1Hp+<  F4ԑK al޴H\$$C2lzpn?5Xݖ4dLY$ךVAIr~j Js NMT(k)Ӟi_AOtoWp Bnlf zS%'TR$5`NZ+;1|w|$SYi*\\&9G\/qU5%9{c^Î\ǻ[>AxPϵVMEd!si&`Ë&&x~m* vP2(913 "FMߗ\# LғM4uu%DUZ_W5}|&)Y8yvKtM(1a9)Q [I!x%*R&o$#}xf;/ݲazB~W+¤h|哂{3ǁ{ȆGsdy%h^ܽ40or'ɥB 5 C6Yύ!]aFojL6N.N?٦qyp瀹AմD4&oJd6X0Tv#afr:{gaޯ.'L#6.fuT>7}6B )NAGt^kf^l4?S*ɺMCƓtx5/Ah~问 gm j{=yOօ;a fuy}=5N `@SEK[s7oGƯc257͜ڊ)$0}71OliUmj#Ss-Ro G Hh 殏>7>.\M39b7A̾9ɜ3GG|3z>AJ\iC;YVNBU2y R^yӏ[* d:nFЩ jH'pLYpT lBNQFȆu1eTə:HVI 'ʖUyeү֜"(ިm;}z.軮aX/< JYbz{p}ܔ1_a\3㦟yk3~V^W?PCE/znti)ȣDүohA]J޽i4k?8jre] 2|s}{zkʭq@fؙ]x,ppk"ů*gRipFgs!.ŋU>¤W+,ϓXaA}tyqyp*p`oT -% DeBn.sPknBOe"o)_&F z3]5hrla)q )Ϸo{9@}'|SCHhZx8q8@|\Cf @'NGL !ks!YϜ+im%ȧ`US^>q"163LoEsR%`E՗fr.ZOWGu Nx>L\7AAyW'MwqsX)ϊ`qlG*HgN͜kKDߪewC\EʋU?KTlɌ-X71oxAn'szfTTe^<4EV̭l;\ht:r@Cx Z~TPâ  z%80t(?M`YMA.pk5NI|FyBi]l "p4/A\+a<WFػxcH UK6/2N  B~nK47Pl^*] Zo48WyӞ<ٰ"dZ_[Gc⭕\_횳 & l-+ݼ|dwp  4H+ CZMHTHt`:::D1F#I āw,kᄒ99}wwp]kWծvժzU|*wm ,b&+e:*cTk`ѐe>P-B[)\DVCN9?p[0W&MMmoz_x)0`C h]6e'έA4d\=H_8k?tnv;ac0gLk#[ZfKv[#ѭ+xiv>7tavfqg]ۿ7~#P>eqį SІLOD[H*f ZX"t`b MS#f Us4Nnnl$\@Aĵ/0fixT_˩qH1riebk+P牦zv"M  tvQ= i s~E"d>QdiJ@ᦜjܑ8S=^gL1Aϔ_uX`rRߑopQUy8 tԕrsB? Z]0nlö61!\SboMleDkR~zRk;Zdz}RNQ4F TإX/;}SཧH#VH)kB]VjR& G8z~ Puc,[`#J $:<#E-1VpEAoP+fh(?pbp¦(RXh0 xhPy)nNSFc ŷMUv4@YCŤ4>eҿKM:wDgB&G0=@ r@xV\D//%Gn LQ|)g Џn  t 6L`yeNf,1dDt`} [%RgkLj#കq"u[*p!FnmeF09`@[ڬkҽTt[o˔\$"ӏ\G׏XKo 0)"S7H!BGpӆ7X\$ȟܮZRW4at*hĕb+kfi}`1Z:XxrFs{O#ƆHUFޑZ?Q+籶2"¦\oŧV߆$[Xe~î}R~ALH<@HPǯ+̓J!)R` &BMŒ&;Pe6SV3҂>MV)_ s % TѤ#WfEpȤ+)qDu[c2'DA.Hn89O~qn^>yK @ܩ_eU-r" Ic5a:b6rTĕE 00f‰ZPl2* gpT+_dQwAxamC_~:;K&9\ x1̎O{-Q;c+^ uw@AXG hϷLߏ~ǔoK_RX;;|F?i6Y]=Z? G=u[Z+hQ2EΙyu"#eN t=-> kELTfI5P>1ّ#ymzq V&a;qSཤ& ZGϿѸ6a5SyZ_?EZsNB2Ǻo3"Y%~5G1%3!'ğZl[_t;3u'9 &ej*W=NZ&l[3`"`׮@<."; VcǦ$<.\y_B7Ur%c=[o}iB Փ~Ӧޡw[ dCO`3ʛ3@ msN83mzQ:/jL$4Te!zkS#]c1>^KK&q2rv2/%Uto=P4%z!SXASv<~:ѱ!UWR_OAlu5\Ǝ%2[/zMݿ% !$ sBNJRtm&h `smx /$b!޷h*@hnFٔ'ASS!kqFmVy6+:P'l[{1ݿ]EXLN9f L|?I_<d ׀T[1YXvH=(۾}<wfq@:2ҽ??>h})s2'O-&4qfг$ЦyН)^R@m[[52ţ_ih3߂UŸnz3-ߧӦ8ֺ΁.Hi\ =[mG52K4wD⎘I-<(&|xH;-"nP KVE~&F@PG9kn ZE>?@հ23]km$K&r[GeW; e[%\[DO_s-C7 ]o]$ PcV"0JVV t՗Cc+]KkPj \'l!xLPT\`;fҎA!d1xٷZa vZ#9|#Zڵ0g-)n`Gl)9_hwY|-O 5[9qqoP瘑7E3mL5oo[M 6qnCى{bq/lv:vB&=z>]G:.fHӄs{q[_ry2pʩx#@>}{ě^?kFS1Gra]&ڎc޹"13NJU*ؗPi:[ zH ]Wc뻛ۛe-ʳ'`zw,1:3@ W`R) N[L̡w2{.2fh2Mrܝ~/TGfx#ilo)U'p ۝&V@|n d`3[0  |}>EQV<]" DBzMv_ܜ;B \| 9 J"jARհ7KĘqDJ,*te?U PsY|(`@S#H"ޭ.P"<,2t Ƥk3^U?TĄ#x/UGPG2O;%T@P5_V6)@P@TMmvctuA} 2fA548;漚c-U6=8p}PbN1&kMNeӺ3U cGSw畬k椩s:1S Gpagi'J~2&`б)~>ijex(y?y,YWnfe[JVKf%|v.t2|&>.df꠆NfBޮABy&1bC`TX Jl?tx>}KhTgM4hvb88}ƿ_3HH*k#?,GA[rmġ lOl~уGtkgfhoŁBRxZ:Pa֒i|>j3npޝ~(0~fD0 <[iH 4M! @QVWƐ0-,ZAdi4,o~y?r=ꌿ ¤_809P 8Z#֚eP=jv|O͚u)9 DҏiӁ"@|[z"IlY [W*`mʶ#w l]͈"sɣSԵwtT-R?>;Ah-ŊW*Gmmhj7$hQYuzϺxHخSg=bagZ=︘4z5R~@TӇ̤4BC Aw$2\e~oq~.ˁr˄3 |S``@HHPx𲀄bLs)!y=J@e^y2A j$;K oŠVKPM- S>g8̗\C\q;όN V贰 k⯺SN{ڠL;3CIN5-r'è:Na#d^Ow"BN!n#qA85hLG ?yA4dYAlfNUt1}pn5 5ecBIeLŸŎ19%ѓMM<9JkmJ)B9ӣl0ca#ևH=ZE7n3E =zڝ))0Ҡ[ՖO˿)l?|u tދCM֑ABmc\ISD^,e+^n3]:A[k' hzm癴NY5b%ILا Z0T s˄P..R`M@H2b@ H 7O +*o L#gmA3*ԬE#\ΙVaA>-Ui "薹YȭeG@+o).ٮMy q/@Ǽ5;b@!&sK"&dՔɽ[;_W'ZҲԣin"Y٣2%[ҥÿw)(A{BWQyKIeQl*VOSdz}nKQk0>]{Vs4dǠ5nlZpߘ9`oXڨaFԷ:hd:2Uy3PxNw{@\l(f"@͋Cm-D: ^%&D;zzG#bGt&zv(ŋﵵP0@:>y9zAMq t.3V7ã5a#_ɇn + 6x!ҧź JdޞZ-5PQhX7v,L} ©'ﭯԳkDO< sBWd&ZtA0iW v=vke[< f?͜W$RHOt1-1bUk;RT`hJfS2“=xkW%M$~'~"Fa40 SdȮ-@6"kT8K^ƆgI"90I9AW[4;..E )[؟cL8NglWZ0eTkM4(nѩHtafMަ` $κi"n >VLg=蜹5^8]^㞵.XtQ \VSoPEi3 ZW)>> 1`!4}7 dj.T(؞[թQ$gA|g!dI ?p>]K&xWe;^7\)Ue6,P/0uN'D= oƔV.åh‘ XS3p/Of;%2d^"P<ӓj,u3v}Lй+6N}$c^2#!Jo˪tj?xB ]ڴ hSD;hM#7NM<-g1F-)3`)DT)Q*+_nxxڳM_XDE{~K?z8ؖ}&w>(BQQ4}7E lPRy_B>-MdL|ŲaAQd*yzJM叙( (|2t雸ru F/u/AZCu膫?7rk(>M}qK2JX rUnHHA&4T7luᄐ)NS`N0֭Ԡ NH- `#ӟL A%"]4AGaN(/A&&JZ25oƫ$Rms f Q0:F^ȄI("gbΣK`>ZKqݚKy!q}rT{/OkG[ňI׳wi+|$rD#?r^@h=Ao!(Ib 4bkk>7ؓ!NOooS~;ԅ^ߘ%&:gǩc@ ̍PIΞх&j7}q_BwVo)?/j<</{N/R.pS"1P8!1? Ż+0JPg`ϚOi RT-!PLi7&cӁI-'c=Xn'4u'xy* +,wK?/W {10 ?yrʯN&L&pV;ym@d|Wv#PΖ-e^Z9MQb7pSWƧ=I캰MISzB;)r̚7ix)Mi[z=f4ٵZRw &kf-p sflGWamxf[>y(4]mh\o bͺpuU_12âݸ7- ;dBZ]R$NyJ[`S9+?‡"-< h(ZƘm(ujc[>)^EߊUіSo3m [h0ar 7X"aSSA_xG)M - lS`!- KB#gZ sXI<֣e'+6F:|UG. Y{ڥ-MOEcxS3:o \k_ZQ&N5{)ظI{|4a KB1#$]{믧@$t?V:>ZGȆrzyb3A`Dl, y-Cw͔Vle^ @fV8Z+!.y^,UP < I=YtXVO;Yzn~ ,]"]Эw2 \ }479 f ^ɕoLXP$)h LSDc2O;׌{MbDS'n[O(ɍOwK#yG}ܺa}in"2RM洯Y}\XOV[,xw0sb˖qR Ck7Q CJI` ӌTB< ixrdTE䷸㞚i>teZ9 u;^]A9k GlmNx(P̼慿NH* 0#0: ,)@e-N{WwCCSi䲨DӉ) n;\f*o Hw*jMq~C˜<HdˢNɢO&dMbAٶS:Q`Oϋȏe! A{ [<+'\$rU7>.}ai (?O? 2 O ]_4}1!2,}Y)u"ϙ9~1 U7o4[.4#hlInSDmGWXty ڛ^#ϭfwVy pQZ _%`2Yw4և^^LXݸm //队5uPi7{>9rwBG`}YHMr`Sm^$TZ/v^fuU`0\t鑏uO^ }k֦GRNx $O_g>| .ǰyݛh]?{S5S K`AHK81 ?(Rɪh6y@l\2]#FOt<:r‚d=H%fVh9r8:&` 6%@eLɏ8k7Mk བྷu" 4O:\(2v(t]ӿi [@-/sQ}O52J(o8I2_lKEdbȩ2Vͼn=#u{^v$ظjXGBүդVƽS#i8T4S6|{4م)Z>zO/6gff(#N-mGr~:-g ~khx).R:-oO]>HXrMBiyDuӠzF_, !랊djqD_Ojу/.a:b9DyJOZi`@] ^x㤱Sn`[* p[Fd6!4)pTwî)@PP֒Χ40g&VTKG4Wq 3fvf41CvwkTc>Yk/vo tڐulꘓ" 9Գ0ӭU] vlmA >}/'BbRJx1; -.=(m=e `F}kBhbSEgZh4dޘ&I@)ĩ/GsJsq}`Z7m9#;]טM!OVoRrt`B6vS$z_ qC32Y *:ۂcI;zϺ7 \t3Ή-F՝꤉V`^bY=RM#nfcgGksNoz&Jh#z9)U75yr emg8IgC >Ŵ 03—p@lbȽܻMWH` T߁ CR8N9*}4C,]v&DRm{eX_eJɦ1Wl ˄.~$!?% pj5N:Mxe3X6uh7bq-3OZcq[mFvQ&(OsnM='PpFf?~!R- H wq4hU- 癬6oԚãi^ZlKiZAV(tKZҢ)ԬpL'R{Tx(($ZȉIQnόZߛFܠ%8. }d1:MV")kj1c5E;R=b@F:d|>`^6q l7i 29vf4ݣl\RAh [2 ]mek:w_?BJ30! Z(`̀OJENʼ2HҼ-#^&H#65t?OSQ1`O־!2x>BJg2vMŠNvi+e8;|B(־ȸM e GԽQ3҃n{篽"Q@}dBS?xfi9/B$YҠm+R*oŅwˤg1'TVҦI1S%z {L ֿZt,,p (?*Д:)+1V8t~td_z,8F]NǓB:Xgd`aϜ pp:#AlK_{59X3~Wq4iNx)`oN,QvZop9bL[%WˋI`֑ 䞺R F?pO2zGopË`C&Ӧ|${dV.Da $5:[A8)wMO0:<@A] $툚Zxl_~Վ,f^m5h%W,zzޕHR$pb>MuG'HkzMNZ_h N>٦ILv?"&gM: ٨M$>LHY] >F#Q&Ѣ|vi.hBŸ/kEFE쥢`(o4µ6|l1N*kI=:1RgN6UiuO9ʊr. ~:O(4e@Go6:zUIєO%}[OƸ PZt8]מ ,W Aaj):S,UzU] XUߛ4(q?v0ɦ@\|46w!O7 ^T9`B'/<ꓣB݋̭̭u=.ﴵc,:PZrqh1о2X=ivin׹ dXhSlM!IQ2@ һs1^<`f4JG,Lɇ*GWOwkU(?D] 1E:范'DB*yd|!im0\,:9'G%xTh}M?W~WFޏ؏ݜ7J,rrX͙mVŌņ.V HFl _wo 6 l`ZF^|PRcͲ_Ƿf˞Y׊c5H$71a `τT୾4qD_־I?_z[c f]m%|zz.;'8#3 %gNish 1X>pV{[oE:^3_a%SЧv r@b8Qo8?1GI&R`dYZ4y.Wf2X%@fFյC1swTЍ{G"S@qkݢ5gZ=C|X[8MCE=i`f$SœOo_ ~#r 0?6Ce`k'l4Ӻ_m94Q紷[$@W^g^\雾IIv: UMص S31zpY HwʪFݎp1͐kN#4We|/kxpOs6Cxrn2+W V'<(3ܿ"6i+sYvn?F5hbl<o/.2}+x$(pvP6 \tíuK)s#J_C(&`I%4p}k@d!9-I*3%2Ђ1ZͼoK]5R S[tMX252~$.zdU|2HdDQS6@N":" ϭ:̾ =[>#tEI1u"E_2*G)I0E(o5뻼Bp>Pεo%v׮S'&CF?M^0%K?t]liEej$i6JHʌʢ$y5*1/o3MaoK;MM 43Tә7Gڜ6%w[t(Wb1:f!o[x ױ$%^kur:Duο):)YeDj y9E 2e̬@KPfl͵M$&s[bViA6PV}\v<7 3[[:ub᢫E+Elu]Wq&>Lc eU*:~O·($!VOa!Y}ES I0II ,Ėc!ή8vjFմ&ޚ@c4=vWEb>6_YtHJMJٴ2hu?3jk!Qnq~ )zL2b΁+N6O;f@<4ĬmM#zҺ%蹵@FgcOa^s2ׄ:f g[]oGqj}S84\x4^{ ?;&ekgM;A ccQ0s2ǑL,*#(yPKuLܘN;yb4:V'8 Г>/v15dpy~^lS[趕Mjg=Tbg|Jo[Q_GץKXRv '9V ϵ>j)rk#ӣbo7^ i"ax) `Qr5=a'*@  0!tv ʬn[:2OfIPP x` 4 q)sͱ{;@Zi:ghOý&H +ӞҧU&3)%Gz$2Ux;b G06 DxYHr#g|6&ҟ ^oLĜplYr(nS SwMdJn?tY &|tiP, 7t!usۛƼ__J͙xj {5;_^eik0gppphlt?s?7 J sJܣ^KGG(G\CF WqwJה;}SS&?!|#Q/kfzzjZ;/)eA)y>N=V/fUQSk'd!%[Mu+kO~KdD]G~G =|\xUo3Mc(c 6ßcۃ˛@B;,8`oi-h*̌8 8tPjs-t&z.H&<3a+yl Y2{4 FNР2 @-t *,Lk5I ;x\gxf@֬kq$},S:֮wK jHp89ɯ`]K *s#紵̄-$iɷBHdxg,Z)ْm2lOlG^9q%eMmDroQ邊m3mD ?CmE[aфea,-6?UPz`OSt!Iy!q LOƳLyP4DD!5cS gɗy<;p~'RdRD!D\\to ~ \k ?R:49hLL\4eRn9K0Uĵr9eбpș/{H#JM6R `\w^7Mr}LʜaCx㥞lp!Es1@>SN(}ǘ~4uò yU(ҁK¬h;k`D;\32%ET^<c4YeǓ:1M QnHH{ ȬtDSÚ'Cѵ:Z) |3EYi#@a&k5 r[^\MdZ,կ4/1'is3[¥z~^';50:qJJ^G-*iaܩV SѼgB'nJJd"?UPM_V= =?rj]d FezaO ө ~klL-zɁ Mn&p:6aoff0~{$GjHM->Eê5b ՟cno5Tګ~a2k?Qf3 KPʣjk O0 IT!|%g|8D`{*ὴZ`S~"CwZ7^!>3`F R03sU2v\(٦#͑M#j`z47^T~|Gs Hv*ӎY՟փsj~aaKVzR~r.ĄX&>\1D$GiqfxT+~3x5a̡O8ޚ@UfyOLhX(2? ;\VȞ۴ɜ EF7M?[`\뉒W5SPz.qU8Rۗ׺Ψ"uft-V@sh 'yL G8._ɴbC[bË9 uP=ooʈgel+𜩥LM#^ԩTME(A&ͅrLm_ƷI̡ќp ~pV^lut4s_Aq LQMżgʟuTT^ܙB(7ߓȈ>c}::JxxĜAj鹵o8fS,U/iNxmĮ.PSOfX[*Il9L " ?hprT7FLJhOBe *#׶~4.MS.&SՓf=Zϩ-if87Ng8D5>){9aX< IȪ/ RЮXi 6zP18fOrTU$qknSZ)MWEgyOa_6~|YBKjUVk:o{caCqZofŭYvl׊VVRHunmmM֥L6JI{k~x P70l[oq)PzTe%J\lB$hgmp{Qkn'3hm [h4/ \TϦST)D#&c1u>U$|d^SܼM.#Nkfm fc]_g2& Zd!afMy(|$ڡHfZ}megG{ߕgw7+~~H>nZ,V+g"bK*m'V&xzj͟߉`tDnM"p( QK86yk: L` [5%,2T%hs;Q#>G!r;tkgқX8cIQǃ143g!=tqÂ>[te㉅Pw5ahnkL5, i;+-ь Z3}Rr&=R&GP GU~d'."ii̞4 e* z`[KveL y]ai@fl&IwV-ZVK'z/Pj0XWh9_[xnXXCzV$BM>q!ntk'~^fR?w|w~T:εzFD^3-`~n%@[GkG,:X+c o!%umM:!~]u=;T&f3Yԣ58FjOjgw?DGlzB7E/*5ni]W<]q\ MUn]x;qSuRhnlcr@6@Ic ؠbT:n4"Aj]@gEHGμU|tLS,{սc0Fz:Dޔh^jN)j[ ==ЋGq$7 QU->wku30'XHL8rtI_ ܒ*F+2}zj\K4b#(h -vwK^thA׊[:J DPf 0GR9G""{wkj{n$+q ~sZEfƤKbWuҁB,hVQ<{- cs틽 n[VKnᡴc@oCMV"'t(i4߅pǿ GBx??.eֲQawm'փh0WkiWR%à!T%g#"f0ҩ!H0-{ނrx/3X=Y}Ԕ. "wחr>F/#< { 7 IzK{{A E.]\{"Q+CCB0]j~C) @¢ˌ?6>*̤v5lA'e‹qz=!ꣵ]jI@tт V9< u521W!uJ$JpG#[FNO@ji-\)K8Not} ( F賶9iX~IJ`ެ2dtU o^"F}'J$!{" #s o)| [/۶hZ-߲@s^Yjv'r?V~7~cަ(5ikFaK q rvɹzWSP-= fGMtJsmYhЙV-I8rNq٬Fg?قEM% ReB[1q )xQtl2IEDy(KQϭØiX'g<#*boxhT.guѥgoY|ooFH 9|;^LQ1*UTh&04h0+@j[&܉LtZ [G7eLPRm`24\%]|<YSpJEs ZNR mc܊E=_mzbs|0d>yDR ~{2Y|9 t;! ;EkWp|ʑm4% rV.n=ol>\IQ|k5|>wz|a^L!NBkAJsFɬZǜh6_XHऊhi-~ -g)ªm{*ݙzJ93Hq[S@b52+׬B)mԺShi/@yGD]wu"HD=)>*mNꡱa$2Ytc*N#6A>3MWEUn0pmdPj93jԇv -6> ~@M X>ڦY*~^t8 -Q_'s(V2?Hv4҂g'12fܞ^~>Lue%i"JSSQ'!|P =*y-xwR6@h̟lq*{_]{97^ L6(DWn` 0$l9fhŤiDYŊӭn6-dk[ |@ޤƛK=r E @ĩ?ȅh=b7H%00f)Y"!D^苹ՃiݴͩF82ɟ"Jaxo~ ܉( rl2k^ί*Ȏ33zMG#O՟r}wxS7iu2s:u 8Ğ"XK "]f*և.WeV;|@E`ME\HG9:ovD2m#.DikPToֈ6s6 A}ebh%/wV.߾@h(Ӓ@l? mWA7uɜ$mMu@X7/ȱ;K)NawZRߥ+{>,:F]ydnV@\fTrumz0֦K0B~^hR9>7ْ;KC^d.䨍yw}XN>; ?|ʻ;vx%8¶Urx#pFv|GAka0P RB>%%.|1Vj0%ZU>%&aĄǡc= ߠ;?(#-W'.y/r냐(bHwEZFI6#R*a3@w[%oxqv{ Gnկ'Pǩv<yН)(`nl3ȓᢳ`yirzE@ZX_djϡ*zts]0lsdK\azu-Gwv)|8=:#+K<cm&]WV bL}k_۳rj#&>}$td_(w.Vx s[D!w`HǛ^nM˷/Y2U:[(<`e}`vt4+|J>ɵTM aMorZuNwG0o6)Swז_/a[aDtow)TQۜoE'~ewi!Q䳭=Y{*93/vez; 3y__J_Y1Lΐ{[e[!jM5~|sSPsxUkdA1fIYW1a.S!!rZVj} WQIs]'%PPס Rʁ r889. wW@mbv^Ky5/af rRF>j g=J Ch6Tz54د]zA*Qt cp^F[c8T3o |})0ϚMLh % ߓK΃41 g&N#(u@f )BS @&/4xE=^^|{gyBקzCw`00tW}]*6yuo0HC(/b0\v˚QXTkpe\٭'w<`{!x"v~+_xU#;=L$|/-|,'D[2(+lQ mY3LBU8K C$FӬ;:)vs6'-oJU hd'_1GJ$?Iqb"yq?S+GkGToL"w+#@kbpvjȀ[y+),UF^"{̦A^L+n]ȇ|ƴ%ĩZŴ~24QLD UΏN&FNw b㸜[=Ef01+AM9Q3&iO7 6D#1 ?ǕNzv=@aHexϳM)p'n  d4 #Ssx "y4rKd:cNߴ-d@hy&kT T+0/ꑼRIq{\vxuyBz X1U#YS\ =wQxF-)Mi"5;|mk*2*D;L.j:2*EY|dbEЭOD DLϭF&_jt[rm3/j͵2^[lIcYbsٷN"rkmɰ[qD~bQxbq_4WE̺Lm5IHi4V"7}Mk-Z\4;[k\1Q|e$z+|&ڱ;}S5P Fﰅ6X[c3Omb1ZqS$aypmSϟ]7k"3z:^$-`3#9#pnQ.?Ue Es|jtOH bQ<%Y xҬE3àhS>b"M/ڿmk%PWy06Pg^8³ s PY}*v.M:m O")@@oe[Pݘ3\=ꮗxWfҌf\ r!B:)gg  NA >+aD]?ѶT-Y1MDJoÃ?OD _}6mʣ{}rʱd!kF?KE&SVMVkV$;LV[}F/zZ˚l5ZOU̓\l1,AXsHk'KŔ72ۦ:j<Դ3&Z)d]h8}zkX}t,۵yq'n |NKmr'߮ie,<ٸY@\6Xl:FiSrmD N\|cUƢ4n>8raWQʂrt(sd bl\D: h.y۩P<ԣSz~H6լN>:;E^DFjGS poò>uBXgFɟIC1e6(cIrEâWUpMMOw(%b:Tr){vҒ*bS#Gtxh@CYcp*FOJ3#fi/Bn 7#K&2Y uqf%U'=hJTxPƱ'oÏ~nLb1.1tZtVbͱ mWB`3 q$8-Yf;?8(ut#H-|hiܻ{dcm ^ZҩOŒj^|jqN?c셽zD*W,]~Yha?,*ϐw|'n |:9`Q|n_L` RwԴ-6́XĠ=zeFgsI:` 1r>z1y sN*I٭_mPߛ/_b#q<<0AZY37 Z#= 4xM7:XS/5kL?4Dp(&v%Ѓ0d GU Nm&#Q<}C)‰.XCQ٠nҗtSXι)iR m$O1ХcI3uF<`Lu2R[b31Q@iZ5nRA>oU+бi LS@T% oHzgݴY BmɛgHXTsE4ka]YkB퐌ca9ʵvXW6['}_;r>0mΓ]O摢?ukAr5eRpj٧]L2#T93k|Od_c- JctH8s%_iЌ0@g6~L M-^jӑ&f@_ Ӡ<'UZ4 !gL~;z=HM=}ySӧ3IX2mllE?X CS*gM7|D^G>F>|#1i]b% E¡ނʷs4[Sj_=jC~o"<W "oN ݶDcU ϫu6Vo ɂ&< 2MOyo0C:)B im\:Y Jw`LUO[B̚uXk r tJـ4@F\=FG0Yώ_v5搢:< nHE+^]kiI4YW[:>v 7j+~'q".k*'"r>V-֒'J+డfE(X IȠ9}O=]gi?-e&YeAT%#\§#9l/~ZҌU@eZSQP+s[׊1&+m2dpP^)aZ=7$^ӄqEk:e[XtNs\OjFeeeve9 &CM;;] 6qXj[I& 7"}M陃%#xE>gN8M{K3] `#tիbωvJSx,]ȫ) jVqA"@0W$}h-Ot^g*aӯ8wC)&:&g^JeNe,-H_+*Y,4N4jݗ7> A!m%ce6HNgs{_sj^UvZURcryf%K4 Fny}bkZt&Jm{G '`GvYD8*XWJ9M%d•'tRa9&tvǪ!4BQPcxD凥6ȽQZH>'/C;V7魆L]r+%mJ;3O鷜$@&i#uWز{^!z~h%EYȚt(9FmWG Ed6դGGt68 M <}JO]|يB✹.*2,7qr@x4>;sq%#V{S5U&@s߭,mn[%h#m kecƖ՚ă'pCkd@D ǫpy3 H׻Mf3J@_KwKum.eʭU()800^=ѷf%?l(cwm49QN/-^-.dk2}~:Bӫuwp2 ~_#`LȀY.i ̻^2599`*@IwǙL.! ؀7.u- %ΙsER<%VWɜV,5mۭ.<\ nOY4#xi̞6ӧtMS2'_E}bgX^?RssV6v:qłp4|J6 p7BhN/-so'@Ҽvk  '<9"*^~p(qQqHG:dL`GF>4"WRө׶ZMEtZdB#$0Ds͸P57mJk$Fx]'o=EY續(x&cX}TFJz^ _kqY4Vu#*Tld1okk3[H$=R6OԳȥ~'û=2jxzH-OCK6r| LN`GiCk~7~cod/[ȑ9Yt Kpoh/=\z԰;XLŹzvfR{kl5?d Ed]+2u_ػA?и)9LPSYVIhXPvOKsR nA Ti IkfD+%,4cWFX3OӖ*?C_%%д ꧏxB\[oiPxbluxwb=wEԞLj-6gя&i0 ?znksAڈJ^T̀2V5}W„߬x5L4iUss\}H׉.J;=b|,HӦBsA߻a4h`7GI|*6S T`ݢ3K_uѮI*jVg^LK!HEH{44Sfbm8ʇ7(yiTA48=R[IGhi^cj@_yiq>ӓ>z^dfى2h[ MΆhJyG X#`L50/ߙM8|M Z\v^0!nɀh3Tۡ;ZJV77nKfL4n:hfGϩ(duڙt쥅Z=S|MicXi4A@gĈsԘ욘}>P~>cI@qIM5_4$}QTCQYbx#fcN0-kգ:-C^ܤ[ 4-4:=ePb̗MM%bqhNU[ 8/ Afz(F2d}+d`ΈLPYi.I gc{,.+m~죾d,]ҿ^gl6Pc rFyIOGIv]l#u?`[9Ah2 Zڂxa<9UU؁뽗?c8՞p$ 6 KPlsgWUB y:I)6+Gj=n{`5rSȎj 4V5Q:hyݵ4 %م ,oX_{8S`T7o @~x!r}[?| pD$\\ QPq'j`W{t=1sJ,>M+ DJ(jStdl;5sF<(1t:!b*Ӫʤ'c* ne:aBGQǀaZ2ەM)qZm`5Mz>0hh2iMU|֎=6 ˧K~0ɕ-?g55?@ORn78R%SeJXkzً6TP+ |XY}\xDuOԼך0x !p2|03ظ37qk\kJ/p ̋F.oU,pJrGRN 0B<-4m\E{QZh'V`𖴹ƨT=X(PZZT|ne6𵜖S 6{ďTWtKX0{(Qݽf_J <#J D /~us% _vD*ҬIRh,mw+ at!l7v,6NJqƽGG)!.,I>82u+֩ {~@c^uNA,V/^fș[ЧyK&S"6-Wr>fJ P _wxas al&4m0mG:)43Dү SVʶX-4PUxmH'JplbF c*<2 *.d4/b#B$\^/]muZIG5뼙!|gF ۥ` x35Zrx &GFCe-nTzUNqC}PC|'x=fd1D~ Q-L;ot9V=Q1QJ/XVݺ[i6i艳L4%^ q{\%Ղ& Z2?7p^x-[plm0lHtI0IZ]33 ^48&{b&ǹ%A8c)w6ӯ+!_Zfx U )Z)&xF$ӭ1 5(NTZ mC&aa\3K+boqM(ZizP7gbWS۴fM_џ&yl*\6]O~ LSK+L (~\$,<}3˿66'x[՘OiM`="~9'3ј 3?(OԪp01:4hyL=jL/7Pz9(ipM}pIPpѼ֛ uvju~He(2{~w}?.V>G?|Vpʀ1ln,l_ϵj[= kܶNFgUo6ۜ.ؘ;`c岦r@pU̟`[ M %6Ҭ[8% Be cA/5Tn-̧ [0jz-j$q:\t,굴U*VX9@GoJ,"K;4 $M.#+7[Й7N]1p JV]@hQ-MkӁEֆӈ=!צ}sJ"gZw;$Onn-sWh+PMXEv 6=J3:~6]LmtfvN^2 ]G-*Z<&,, Or=rU?F[]&Q_Im\0cXnkο{U{RN] }b- ;%7N%#@m\W3k`7Z_}Dt2,A.1kR x7qd"j^L-T ;}53(qS(ϫU~_:eK\{VChhiSC_ǒ'l+]:M=#>@>p>AChƴ _͵8 5 ob!bQv%iL:t/暹^I@%M%Ԫ);qJC I~)i+MfL t2Z2 o^CW=j2״;6r4ڨZ͞%YI4iF2 Ԁ7 sUoaa|TS!ETT^^{Qb zQ$ţ$ow/vGi~Z[i)̕O6>yGt㥧]FȖ43YrhIVa[&a)Tںɰ=6rlmӥ% ERzG+aռ^هf[1֞LӱW'7gUu1 ChS)L RC)Z-܉yEC3Jfɡ"ɓ2==.bHm/Ivq'{%l gbEƳiafE=T] G)HhݹW 1$s1L#Jl.]M#<>.qFiLXřf7M$y?Iq||KǮ~F>ИաTS5X5+xP|cP^)8Pl5׍v%|tz4l Sg㩟oިR2ȞRVoZkCPOQ+hK^*)J 4@MNkՖv,iuⷙxuP׷ xy?_|CjZľߑ*ւQ5{ !ǂBb8; _ L2eK@ ZJ|Ld*8&.s'h|cנ*R'Uzʬs崉_0̺?qFLJ3vG:-B7׮[GDRp+Q0[Ah\zrI>c.̻^] a)'fq-GrE0>/ѰJg,)k~0Tn5z2># ,V1u ]G!p1MSrsdPtkm&e, = \~8_!0;aH/v6I\XW^SO ]4O]uoG 5oTkz*BP PsLz8v|ϰ{`cg&%`ƥd.J!9HDɉyELmȀaGe r,29u8BG_t(KdaZlsIjA>E^;8*BoY9=3:Uj"6.[XoWSEUgnTJqhUXU4|8?>.wj?6 pyo#/j&5C<U2E e2BQ5!3=).[Fr~y2ĊMx#d' $ik|8WfXtڔՙesygƕN^鷧} iF{ 1qG$MwP)t`.+ylig8A0x p&Τͫe2jnmsk.7k.Ѵ̪&'AT06&wvNjTu5U7@t3SO`B)A`%x.rJLȩDJ$Y >\V5M ҫ։qy!S;_(Πdc;0$E]nnu݌> 15u{'`.#W 6_[kiP;#8 [s =VR )XԊc?hjr{hVༀZ=I2ip :)ՙ:+f~p9Һ=ԝsk4"`WNɓDfT*ֹՒ<׷r3"iEidlʉʽjj$VO(6\2şv?2䖵zsixt(^+-`k}$3h\H:y\LΚ.DӚQ~up0+2 T&gԝ{cc:r@e q?J=q!ASҦrS\GX%?jqGf l;}Y;Ũ sY e UEBpѻ P\'iT5o5x8%~돪][6#YK$I uu)w3ejm^ A;ߪHQ @5f*c7J 1?Ze1iT#8tV̋ [,uj{'C@[QCG_5nv?wm}?x 7x`~ax{(ϞB3gJeOl8+G3' xߺ{c wą?v+{w #,)Ϥ6G ި-Hd9'W'UF=X\b+vѮ]lm$xViE mCkqZ>&}9`$02OQVql{zY ī@HPzמB j7/B>GGE #I`B<)vLďtsޒ@' H @IDATkS4h>Lu]?賯*9 eVvQ?'",WmrAV|Hx8-2ح~&!~lƸE^# Ew.Q eG]oޕ]Y5u~Md0w@%&ij*S+nQ0L<5%/W4HE ^4N=vzn{S??\ Z%=0$8! K VW^[E]6 -ضwA>ײl-K Sְ7+%Cs6WҙO nYByae?Ǒ)왳?ərā?Md%\% QI[d~Dߒ@Y7 %ARi䟝qJ 1M7!B#OC >ޘCSԺ-]psIn%vpwM SP 2Ċ(JT4۳K u`ct9dLx;{4+Q[3ȀjOYJޫL9QaRy=3y4vk^U!R6K2)%:f.6+@ܝ>,Ps:vE{H39>Mދ*!|r61}h[)O%"v_1iNAi}9+n>?;PFݕqP6@MbiJ0xl+^!яrnX+)͖qnn%i9˜sK`;Ƿ. W lmjs,pMZL߶e"P}١kЭc>i0Ӻylf_=#o)R(;[J@VJL讇ڻ$n!O^ m/."YKQ,.ZkTKLIL5·p2{ڏқg&F{F~x &ub\Ɏi{y&.jƤ+7:&, ]o|DG͡t-:g!m:oz J CHS!|t16 WHN O|(zpUT- r@\+<(ZNUٶ#z]%ǷwM29㊵a+Jq%˙֚nscRkQ&TSgn̵*/`}Yo=JgK$|ZԜW O "67^Pư]o clV!+d-]O {p3X#Or<>o+< М>zʹ{FzlzMNN#L6}R{ uX)԰3d[Oɇ}2 הbwu+Qzff}; 3Cf3qH1LJ$̕Q;qk* J7/DG9h/X/'p\8FHi5Z*(*}kh$3< J.9Aǿc䐯CϹ^cHlڀ4,'RuWۀ_ӫ6 }m޽N0~h6\wj!&ơZ o`&}_I_VlăRЊ}`+}F@->YCKRʑ O.3/ Cd\5`(? 1kU&P=%G4a6g:@$VR/5W^tlhfBfpݮ [_$4֯ R﵍&moaĪ D?z=?,Sm'EBU#V\~6S=J$ S\o  Z[wL&# ?IX3uu,pDG]KG~5݇56P'.7LN~n2t_x电rTZT5)҆=[WZACp-Gi]%)f{">e"!w :Mw_S<6Z8zGp6av)cwXYؤme/(Ij^*m}̯b|'x8ӇykuAcx*ü:IYmU Q*4WjY0Ɯ*A-䣢{mDF^Iߑ&"6`aҺ$@Iy5-(BO-oJ}(^Q_[:G~{)}^>BPxN)f0Ƿ3&u H~2Dp%Z@-g­|w@11`9ޥ>|f2>hKC1 ]'<< 11$0imU5-p*?N `fzWvm6zLa(\KKh;l|C飞 OY 9L+ * Td )+Ѡ9/M7bϿ`K[L[ "wڃNV~ˤnAL=fpst6|AǗrh~fWI[֩B)rґxMD։󣨞zrxݿh7CSz8idލIhm'R`[N :f2㬯]U6kZݿ9]oLl雛JG(=K=uމ>x4L z⼻Nm5 #V54Z#1 lNGOG_5O{@|.m2V̖h@SQa^IVTFdʤf6Cޫ=$]vy^5~I2iN40P|WW'à_0H fu УH$P EBY_ˎ2ԄL9Ƽ xqGYzk50Y6e6eZs&ia=]*`f7iwVW8-G?J P` >KF͏4ͮ֡TpLv9Fš,a9GGsTuegf%QcOKk=e+[\&_L'E*& 0߉^eq}4>Mj☂dp#*iEdT1m XFao]e{#jB'S+2jAcn!&fΤxZĬŘiDm$[庛}ƸnFj_imzN|9oisԑmT[fKt*B8p8IOfJo+#ׂEl? [s|0~yw(p}bivKp*E0ўG48x_&4QB~>= @HHwkkӴUPh08 QpPM3ZX#%65a{ `Q"9wyz`Bc4&Ԋ I[j;څRJ[.z׫5kovؖuO£Idbo"/gU-q(i6:/ELHdnp.c*C]UMۘ<~hZ] rb/_ ,7Jp zng|Ftb&y;}OBƤ6GACV=%#l/W`4E7M`XC1Ѱ%1 ubB{*$x5RAA`k/>S6dAQdP4h|P0ĸj:՞&f(Zs)y|^= V[Ʋ]͏œGm3mk68-<0$q#큫4V}z4x&?jZŮWWcbm':x͞&v^xad$BN_ȄҌyo+7!>۶!>L VF%1!LSC^~yW@ ~A[WӎHh']Of?h=-h fxf_h*m>='\~ȬOL4VA ^,Qͯ`cE?)ڶp7myUK0т3D`y)Xpr8+-QsPf&>?bzӘ\ ah9w$F}q[[~x{yـĉGbۑߢk=;QW@xf<  1/joq=Q8_N"3ue wJlkM~R|f>O3-jbk)D `.H1}JeZ#GypxD `=ST#%B}qIP`s}Dv {DC{M}FFt&muizE&%ɰlPhg*r=^̒k |4ړooKb SлC'Hh#1{7 S(ܡ' *I`+0AHk4vSg:p1TrťॲU^,^X*DxYV0*m+GQ@vvlR%oKCԜr#{@ }ꄊ2@)ZL{Te %֏Q8J,cOn'"M^|Q@E:e[fF3eW`mnh2ޞP7/Gvay?95'YZҨ-O$\:.qL")YQL7xH /G_:ங0 چbċt$!r@=67>  AQJv&';Aa-32leWx?{DYy`0(1,%@JA 9@Q3UR H@)^/ʠکԦ' tDN1#g*_n\/9Ιr4bJgkĊ>eBhDL<93uN"˧"|F ,*NB<9M9ms0N&O5%Sd }%XQb!inpHY"@@~ V$y-a:0#6jk1^?L.VBkT -0ǁ D I:7B6h-t=sxXAC_/"^A[&HİY-̷ŭ=W1,Srƭ"$ƅX)DQXOp"^,o{mw"iωOc3=>_KR_ǺPzvi 0D Q_'nAgOU[lmQ"6nEPkb46fcƘ/Lx{`= Kf|IpVJy1,`RM0f2(J Z#VN=Wͧa Y8e߀CtL?.icǮ֠a7Jp=?AMl60 8?gLUؿJ&g!b`JI$Qn3nuv m`Օ3߹ ٯگ-V} j&-amܴ". ;;jHξJnGTe.( O.Gp佹&FNT ͆x L)b6㔒gMP}۷}S,r9X>[f=]20z}tQ-Fˎ@zu'Xz`A3JJhUC|D5J~ۤA8L nvΜs |mk?}3k儽K &lSȾB]/ (h|& ͩC bGkR? Hx&8徥)@aI? ['fl {m1/y0W;7,Ebdn0x=a?@P@&ͣsRG] #*4TUs k#Y&iP=)Ki s3<]U ^1m607GSQJRWweNMDp/KE(d>JdQazF<F cemym[i15.k@JtMSeUl͈xPٻZff#|CVk B-Ln4stY h==CaBԀ>`B@1[6Nݹ˛bTRY"˺h*Ϝ8-w|\=JҍSS'ZQigLmMU%p}{P6H;hr ~:[|-+z)4:"_~dst(mty!aJ*o8MNA2ub,*AYux|Ğf"4aQe;1@[#_0&NMci)=إh>e Pe.HS("6~gc{ _861N:dX dέ-eCˌ& oB5i| ."J kX?^ױ`RD]].h*fqDk cLğ! FE$Soj -1;5@\GQ/3<O/患4Gpdw6f}s:|''Qk9WOxX`%K6 ,HZ_s z[6UH$Z7r̀䰮W-Kph|#%ז^MDbTACtx<0oa;1m ;A0mߒϲ8 D"6(0,ꛤ: I0y0+AㅸI)oVۗz)IZkl'Tl Qՠ0u|~0^?ɇEb 96}@PXl.z~r0w~Hy˄wc쁁L N0&apPC'$µ^WB[3Z=@e3H{\N\*Ѭ '_MKpW4m\ë8r ͔w|~ų pZ̬G x'hC`R5o;>3O&D&|r| UX4X~e};GƳx^Ju^UJߞu_=bAErS9^r_ڥ{S |-ѭV>A;:v>' 5f-X"r!ˏz˒_gtq&|}y؏=Y+3 ,306ba"J~K Sݘ1C 4cY PU19 2F|_=f=`pnc;0 x? ٘c o-:7ob1@)չ)V>{@':JGZͳhx&5GM}ov g-0K BXӀw>nMlMų|BZ9]34ѣG'6.g }|!=z|/`P{Z0]˖f_~Sl5fBD7*H+3X<șTNԨs6z1U9FPog _'>m?:Lm6"LO˻>wi6r4St8J*F@[$i}ʝ{@!9M~KHi4gcR0Ex.Aś& z(V%1nKE|:hMlV곕Q:QQ/|+'g.j38G[BZf( ~,NN HM+KkD穸^-tuZ21 D+uKm.Tu'xW `d<:"m{Pؖ3k(; H{m ja+ÊT܅&q3V%H6S# oCu *DsؖfU$0EofBUx QE08"pbM{?a8%m9rS$V-ughSd)4Etm!OӮS`"I ?WxOs<,'Y x+LAX0۸\{XE5Y  VdV$gԷߦ?stj6&u껠VǩۿؗxtLJâxZHmvSq iܝD1s= EI=JefCMĖxx* S\gL"2; дb]oc鬐Yf"O9L!yhF}LΥ[u?Sϝ{#5g YVЖ4QnÁ(b0àg ^c@_F/:y-ɷSڙәNŲA}5[ٯK,@fJXD r ÂP-rLݵ*dn]ݾƀG불`{Wfpc4 vkMrܧPUIdK <*lđ ԷJ f biϚbޕMl7/EF[.OltׂLZ&$3bBH0w/)'׾$AKD:w,MV xO#r3YcfyIҎYbkжILЯtap)XB~M{As@?afN)LXyzr&`]#Cv*T(v2k!5pο\&K997ikCa\sQ$0^vXzl#_a5Dk$6kHgkb0IU;l/gqT4#͟&"u 'x'h 0^FI8I?H.*>ZϤ1#Ę4)Z3eVJ*S-^V;}=:CM% gcQX Z* Ɗ˒"> e V. & "^]LWjvwASŏ|6IUN5͛Dy`LN[ӻ2)48%i@1n"̌w!l;hz_DZ #Ivk O8"%m/̂R4b:Vj>'`ў&fia2s ]S>48 2'_~bⴃaʂd ڴ!`[uc2]Owɔ)GkA4 <@f >D"婗~qV nhkroฝ]^=: %7$"fJ\y[[ cL[ȷa5Nz/n#dCπSGe_t0A`Y LUS>_Ӯtjۖ…b='U!˰;C#f3_")K)1^Ϋ{ iiNEYf5}.,GV6?b[҅$q==$;5lf v $SVU/$1M c>XdݢVƝ]a*̤?f] ͍>_+wqYlIj2~~JVu Ca+\Vw4Sl^3X XȓZN=p8 oIhn0CU- GUl5W(Cn@ZJ1~rFidնăAA5H(UFE֌ fHm#hT:xIh@rF&ڇL{y.j 1d$8:P̈́:߇[^ \`-gAvT |Q.^g5Xmrx $I?p5K)r9ͪ9UGӱ*%Yw|߾&Mt,VWe4@>) oZ8g}zT8kc ďW-MLgcy[Kor1/P(3_p1o+XʹnM"6^#ke?lҝ5Zy}2Kt)My[)b]iL˿}o=`{`ܗgP0FK)K`OL)v.vVf/_LCs'x0c46(69/8 W n]aqKj# 4FZADph\ԪegARkڻz=K+1\wɱzkM' w{ 5e=by$ ШPNMx!7辁2n uc}tjq}-G/~ EdAZΪ$vG{9O>1/PȄ+̅0`jvrL.`UϨׇR #niwK{4@S&3:,4rUzqJ>p@W}l| N <`oU:g{1ĻE[ Ym-[y1or-G"J*P|7"D3TȚ&&$S1NmTϘ,UvB=2IqtvS"x x-[3C=2guZ|3[~q 4Tiq2#h)[zMD__oO7laԟDwA^Ǐws_IOf} _Pm?-n+TpN;SDys͘ӫ֫;R@mB`,lY3GNbd264!|'O~ Mv$ZAƐq?ݎ2pL+qʩYomi^#c|8Q}0S@oˏEhc iabM|؊C>Fӊ˞1c@:yex:a0u|X{t1 &e0rO]!(;2a R'@t.n; ^=3P==g xv%.MPWcĭO <'TSl\4u23%td9Sx`O(8*Ug'*eG=U`@IDAT@c3Kz80V09eƆSQs- 4;!Wi@Sg:h ToFEwSƉ30`=x%և bFOK"nsIxT(*^>aݧ0x쯌o =b^4|),d9[tͧuy^m#[/us9!#b%NV$[ڻ$҅@}@;bl@"Qf슬 f>q)%zK:wp-(dpo048[bsFЖ\nM=0`ؑhҬ-Vm0, Us9 |jAPI*k]@;Q{ÒNNP7ЩN#.Ԥ ɔtAQHO?FK4l=mgۢg|lRr*U S aҧ.meµcGf*`u[ 4  %~|RrX.+5) MAjQDȷAfk[ HTnDg\zY=ЂVX=W(Ae 8 {z]@|;T^#͚y%&Ӛ>pNi޷E S EgEbZZJMU[Jr4RAr'ؑ,qfov27$x'9GXlhTnI~-I1?{zU3okQAU-:'~'|DWvֿZo>:+nֶH\SpOKB7ov+yFaԈ/=Tn?. ׻VD*Zi8:;pܶzNw~)Edk5KD ~/YF%7a֍T9Փ-whv mKa&;Hy!x֯m#u˄k{i1 <-y]@&Ou!WIKU`#a ­!%[`V t GvZ48H&5K~WS PÜw^tRCm~}Ж -E+"F4_@6eͮ8G0}OjW?w (!-N>Ӕcۈ[?NlpkX.)ڄ3Sd•6 /cέ³ֿ񂛏4141iho\~Q_k ~:GYwnI4}(2*zLuQt)c[R۱ÑOY[WN{`yKTӆ1T7wȻ#àR\˚L,*Rcdm?_ڵ<&S]Q m}[{ U})u ţɊa6 \E羥2$qa̎Ar I,l FśD}*Uq;AXDS| m2?x~Z@# 2 .@n_io*ZrII5^,yc-UC,dkAS0uvrYUW6oeAFR;M |#.Az*Qol]By4?@"20u/EY'GEއE  Sy 5m0e+z(X RQʜRN+*T2xnØjۉSR6F]9 #+%ޝt{vӈn<%>r|D.>f*~c`ֺQSj5@a+<}oM&>ij N=pGXb[K%#+y(BZ3FavCр4nsQz%?Ԧ]y{8/޿(U<NH4O,y$wQE[=~ A01eʪ ])},Č-@?+ aCe8ΝyiXAf ?F`D)ު0F#F6-@jKBv!5x}9M5摘܂8gcuќu,Y>GyH\~21ara",y<ݷZ!_{y=ۻ@H3|uڡZxIof9pzmeT'"Fr<6_ k9)J!l46 s {R mگZĹ5ilY?Ƀrk<9iG5SaeRM6`3[a%SE~.m߻N{tkoĶ!瘪-fɴ$-F11W?w f LLN@X>Gx"&jQ,ɧ/ug^@[R{ (V|}Oͬ>m!{]{5Mq^L,UYLFo_)=Xɢ2;P->bsPbC6f#&b%ca$4!;ߟH )ԉέ  ZẺ1䩊 F~34 KZi*]@q_ kU-+Vk$iO \izl9@itnD!ѢTM j4.4DUu֎ZQmѩ)nuu^kw%2Tyf#2D:=(V;f CиZ]>-Rf|+3۳T4/Mp0?n^yވpk//igz  b,3xZ]Y/R/au" gJ000 b(7ư4_=yo9-_0cbAbMKl<. $_n_qp9o؂zx9O_਻)>5J )Li`W[f81( PoP~89aߋĔz@A.݃w]+` 98Ҡd h?= s>X2vpLifwd8{puxCjlq귣v3Րi|,xn88܎5@f?1W9*tM8HM.xkYcԌz1 B4[ERpZq1k((,A=~X噎U/̰K=[:׻fm$\HH7O} -:26lO| 2k|ߨ>ǞZ$[U2P3 !Li|=lEOip6xՀP:Lppj9Pԁv鰌j;0q: `&!hoda nF HܚHi"ڒfOidhC2Lx~_D&Gd~+U9׉]Nq IY`u0MsQ9d O1vWiP5V)E5z+У@C)&sgu8)^#P:}'Дv<`QL)newK Q3:7j(,/td2s&"+ Is|1t16i[ U1k@̀d/ -''G۝4^[G3AGd/Leui`< B @+%eNׂCH:xf^:qZgl~U*_DҠ:UYuK2_>^Fڶ??-gX,e;%Э8?=ԠlVǩB+?U+_U@r ~55d2j4m͞ܯnjUǚj= De]&lUr}JoJI `7u(ͼMR f XSϽm6[p>Lhң czz3\VpQ~2׿qaZ|EL-@J gwDO" RG2` $HKhX M 0~sk)7L*R"kuvIw@d&7%N5`n,1`%t{'SbdB"A@N>;4]KBg[sPiUm{'GWY!Vؔ;=G v^w1,cO;9=bmkǙ${mjV9RA+j6AN nAմaĶ:}J$.Xd+2#c+qRhdwuqf2GEX7n u:B%Cd.~ ._,Sg뷾~@:в=.A ]]@24).m#ѭZcJ H$ـyJ n,` ^[Y=Wij4X>eId>O Hw)et@xrāHq঻[`S 7]AܕY}\<3,,Σ '9@8#M2w0Vo@_"N("zҩ4Rl^!c&E{sJn&ƥCV'ضǽ)=Fvn؏^R6UGvQ2ןW-G/mA_g*/?9Fy\|klB`6U{{Q\25ٜBM%”l훡XB%ܙU[G[-4ɥg$5|$R3JL~Q iT+/[z w82m=,k @WX)P̮Ư :T:fFL&|vHXo.!pH"hdw`ip&X&]Qmo4`V8 gEN `񋌸x T02`gjq[ ŊGR 6?e L\l2$zAVi덞f$n?պge IF`Nz&D7&F#D E7$b`:B@66TZkZ5jTըQuݦ}K'DzDt՗1%uHrS(:2 / RsKvO^8vie HEX2bV3A,@˄ %^(jU`wk&_E]rDw-'僚& QK EvmIRP9=t,nv4_WÙ `=BUھ5Q~N^Әh7Ac-_"Cx =/Q.uwHusphXOZ! )5"C~r5H%S~}Aڇv#-4RQe!ը]meZu*pQwDŒ^aqZ?)**YYgifR8QCW58aKX i2.ci*Ais2l ֥n8'];nHE.{)J|87JOu+3U0Ǜr$ oi~$蚒Aس>1F"Da;ju[[wWCgL򝌯 x_??Q;HG81 9TApx:%F:^.Sk  fX]eV)bZ@蕠s X('l?`@XW<H֋vQ+ԣ _;ݓ5*{vLy_f۬AeOIq]b48dvf;$ÓX {—X_OK1`'lPz16ؼr|>3R&lnMMքcVk%# ]]plɴÚOyTdK9j^U#my˸=9sA¬t)CAQ=_^Mzp~oM^4  &_$PW,z k)<6oYzRaW-n&Vw@~%BC4R[ tcR ]2P4c9 6 L}~+- V_:ɴ$l^b$'$E^6Q=11r #J`28d0"DDA) bZqW}r`d]o8Lph,(?r',D>N rOg&Q@IQQkS@u,ppvmG$ܫmIm/0Kd ~hpq h׀B3Nöjv 9ܚ'ȏj)'_'v|4!<2 ql $ @/k| m-mR$>оrt BXp[ۀdo~SI?8nIh0$RTb'5W⣍p3s[jRb ?[yvk6V""h?.6Q%n#䇉t{d 迭WSj1uZ?3?˶MYyRujU3$ug >:ϓI؁"TQ̒M۫T`y 8U /lZ c 8 DP@,AVr6{)`tK~~O@| d&WQ@^N;L!< ZLhv+8"o ?)abpr³-z+_gt1D^6Vj) g_c`#$0pR]K H-[!&_Kwg6^ F0sfUņ('gTp{PxǼKZZ1u gh#1Xl0 XݍҘ >ԧGhP sx_(Cy2&24&ɰZI.9{ <*YMSblvV]zV5l?3Fhd #Ǐ@nd]Aܴ|?܈Pd\ AZݨ}vEOA: 5/Sr}>-'~WjH@vyKMA)s`̔^ u*3 g Yiab&:FzG׊@)hzܝ Z@ p*y/AV`{ZM/y(BL=lgfX)yMfG׺_TmdݏA/+C?Con0z6P(v}1G}"#Np)<+GUsR>DG4ΓV=n+֐kDj(S78{x!ݾ8razxUGIZ-LB.̣Aioy]~rFr&ΪBMļ0L5+FXk b U4K " ]3HSdt`gH0`GlkS$mO*@ۓy fR>I2n^ {`Sv9mXyp3eS<ЭM d#0"0?.8yXMO^>Mֈ@cB "`Y7a"֌m-нvujS `4e?a}:bqhqNs5[k\w/d%{TMiGi&rliWW[X]H0(%_ziKNhK#{›e$]\P;_j _#"Izq,p9v|n(φ5VHunz [m<ʸ,xw2Q @c6wCB??/'q`PWT+S% A;93gkㇶX8IO#6f}%><XZp,*ڳB}pi&nw tzкAm"&K mɔsaWLVBb>qĘAd⻡m߀5_Z f|G?$a|b1e JN9c#}s Tf-*PCK}L%xYku vGQv VGݬe ICfI[ӥ),d5l$Xn8+RsoKV!V6&r~~i% KIn'hn7G0rez+Og@vܣXd*?S8<=ӎS|Qx lbEU=&qaZm5llof%ѩ:-d<~F!5ф^y{JCK|Jxl !&##A6,᳛~j_s1Ĩ3Vc`#qH-qYkO+ؗl΄%I|=ȫU#Sx!iT 0~h: ⫩Efʤ7oU 2hdz4|>4!-_ x5H`c}کc%v: ˟׶{HVm,`&ъv"2HMpJJ 'k{?9M=.!LZ(e8X(5(R4ZJ>D=z,:jWK y0v%z]lm`:< g.E!. gTwL߷Jc0CJn<MWrB%@2ytsv<myAsr#3ٙx.0wB?dRә0,"O1,Y=%c1?wɵФ] ME/k_6a_s +U7Y'=lx~+Gr4#bsֈsin-fif&3,ag y>Ŷ"i?w'L1䴋/US1#y6_'#ƞa6m%rClk67?_+>yhTMdB4V^P)J<hPUћr1k,LkL6tb=hr|eq_ 5Rh|.qW@tl6&2ٞ$6u%Zd1RT+UTӍ ??J1c Jâ(M4e/} z >%+Zy0;0l?O>{Eo?- ؑT?z=%$ yn l._4CH4(y؆t{4_yܭ D S-#b|˲@NiJ’)s$xFϐ sT ģcP@#WHef?cB-;jXOþʯ|aܔnjC틤YH@ZG9DXks__G P*Ao4AqYops2&V}kj$Hfv1xGIc¶neN3q^9Wz@\b_n'ӁJReikҔE55n+ciFp_nk2Hben%Mؚ/zʢ^'zi@٪d7šw b,ZԵ:N]"8J*ȔGe_p33JEx`"}J1Pم)?IvHM[aEflEJ`pxr{&nx<-u [3Dp7~l`;KW{=1heT&,22ܕI\D|J$K}杆Erfй'om?XTa-- G0 ":6'[p9.abopOOiJ)S=U#~FK*} .g?v+Lpޢ)a]DAotg̮DǬݏFatMi"@SC*3-φ.,AҜHf/Jwtk膵PYCI~=z z^c-^>a?0~4Mąz|Y{D$]SB@F[ Z8zܾߙƹņ2,8-=%.)Є݅ T; ڱB)&cٞOku82 oUG6v$ͮPFA>2IhQJ :9[3<nfA5L(4/%F`jr n_[3H _LNBH=G0LOkr:  p^6X Qů2G/$_Z_謃$NHI&(m [wLSDv~LKzԉ?gϵVwk:&ʔT&q?w;fyQ9I?v;AyV#N,Z0Z1VjWhd _[HTw_6p_bƠ eř]QimcH|7Xg<$MHNh`m*OYA[5ZDQzDrG'iM;d£~ȗ۹Um}x{F`߂K'!S듉-*'A@>9 LQu9#Ūi;.GF% s+6'AZsk~)Xw2j>B%hQ#Ge PȗHYoD^MPMkRE+/aBRH&32]b@ H"fѶC^js6ICidq 3VKoL9)HԲigC6<$G̴3>zh,L;sXg,eG{.s3)8 oQ/Ies" +NG"V .jӂ߭_Tb(p O#ɕto=M{EO~)|m]73jLqgOZyer3+Eu9G} &&},?m'O΁A ΋:x4xms\Ti3:^y2Kf3rkd(@9 RQ\|kd=^՞xT Tjqi>SNBR,2[ HL+p 0Mvo/~2Bh5y ")!w+G LA`R)62X™D3.n_PMc`A}ff88uHUtIa2%h:c ĦK)39Uj(?c&L e eaV.#0uhhF\!IrmSaKXn G<!Tq8Q?iIl?ϲej I}+oέ; '9#<%GhYbI0&Xf)C&f)2խľH-e;z;$3=F`HP pe\N{> l;*ja*2 D_ &k rq}d f;vn::" %A壀KZOGtɾyܷt\U;&շ٧ 7>_ *)2~ s=FOE%hfs>)N:YHZEO)wht7YQ6]?ewzMf: Ǔ*RSGeiml 34_Pf_6c)j&{(p K1Gа'ۭ-픶f3Q㞮evN'@IDATiã&_Ӿ%g9Imj?]h$g}M~b5+b9gOg.e||b5u򤝏|kơ 4kn&d1?*,߮tv}!V@kdIۘ6x'oY5o"ZV N;MD+C 晖3S`k* Xt/M؅)PB NSG|Mne02 T165Ƒ6yR3JX&?;q}DĮFo!$IrNHGC_H笣{bD$D@Z DVi}C 4(.I1nt'rZVo:tO^8^ǘl扑ts |G0b0#[}Jn0+#)Y96Qm܈cܷGƖf2KLL>nyf̦mGu#AL3sůvs*5Qѫ # yмf5'۶%3/̂nokBܥdc?*([#S1[Le" Hm#'#\qĐ@" Xg{Ǩ~QGO%c4P@2 l-y 8)F(Ƭ"{T3xˤͧ,E'`7D #zԝ~+OIϭȞ+qۘC5ҘM| k?P*K ~'~.RԜȄlBPomd{ߞž5<2Iث\qgHrR T,PѷWųЗ|j/[8K'xF*e +F`An *_sloeס 5D.LIo6k(N3wX]/3`]w^ kabC5 DkO&p2Brg>j ^ɖQW1c_0:Fkr;w{b=&@,RzA˶iG %0)`uܴDL4C;DOOx>B&T78d:c] (KAs$O;5hٱt`VI}~\ %D-.ӼԘ?id2%ϠnT쒯d8~b\EYc0:ܶ(,!KXGh'Oxd[jf#kV ݎ49, zݗq]\@[ã&H\4;#!U0W+:Ni;@Q ]IP_nv,]<26Ʃn>[ q4XHd0GG $ _d$n5P~Rؐ(zx;hК?8^$)JTGTQ>z12LլYe<_`6_2`.eBTULu isBaLc@2M)[stcJ?" bnIԱP%*]啞2 (0vAh$7(e$Ywsf\R3sG4'=u\fD5YX_L+d~4n߱|_F¼Γ>_pW7L``FڌmY#? sdJI5:f%Wݏ@\sxm#KD8Wb[SFb$DaZ@>M@`\8T쀯 $.NjIW['jx.bqQ xMdo50Hך8@x$}OT{t|3 aH33I2ҶbF11inBAZgMf}; !qSs)shކa X Lti#ѩ;[z+FloEƻ *yDLƉ&?i=g)cCY&jo6MW##DزU3RSe6ΠUbeZpUo#' ȆBlVu5X0%q=}ꞀskԃM{t8#5?x8o?]b}<*3>qeVG+}ڗCFcnm]6̐VVL{'Ub$22PS"9œ3Vzh+[Cm—;@#bai62Ns~2ZdcG۶DXxecGvWg]wșEh-8{Tf _S  *1rdbbA3)N0Sl'lÕ[LO?q |)X)ѬVRĈx:b6.HkXc 3w,;>*ēL^GdN_1*堖+DNThce3;ZܭE_t^g¤Ҝ0q^;3[}sALM/*g#}nH޶LJ=@km9*3)ivi=lYhobd 7ʌ,O s4]d&FnϹ" mJfK^1cfr[2WḠ)Q~zc풳;.v_T nUm7QXNDZ^_6CAIIkgkD1)ok9)^7T ۚ%9kwkڶ]mr>G vG;U@YKUݴr`0|֔1ydQr]h&՚a8G1R*6{2 ěa?'3 u?CX62I2yGr(;;lAՈET&ȦLL׭P9v1Ǧ5Z?\ӭmFNK̵6gT/8@O4*㱕E~c9~S ,! ]Gt6p葛&f3]0QYVw鹘- {AZ_ nw>x6Ѹ;f3$Bz28! ΡK$˸}cG㚓:pڗ&p^͙] n+mrXhj"hNncE:Cd;AP<;ށEI;V[RYQD{DXvrh8}%l-SΙ! i^??2*>J{PΠB\ӌADT}gg#rVtCA6iD硓P&=i;-íPo&N` gY2dm> 8+1kؓ] CHh2ߠİ"7pE.>Au>\ؓ 1?&zhmyŏen.nc nȤSx|m짠ər̍gI7h[1|QIaVu5,I/t՝;;Z..pd1+F聊L1j4?D-F+h۳53M,+c'؆&0uS}cM]s"Dxm :d'iw0P(C#hY@ܖD{)G^jЕ̭ 4B@xSgVceaeh=6V~VcQ'flŗU\m$B2!~E%n<"Gr?IMEQ|߆81@,~WcY\VICh;`zT35ٚ2i$4 ^%UHbLW'ZȇMº /i[[87aoC- d衽;7˂ї<~IdfPYkkISxoDnj}V<` *W_NCLD>r93uVnqSwF#f8JrŒH#[$%IG6jNinN`~͇JS>MlcR뙟z_y{9ʷڧ"P{hJoɠ1 H2^+Z_V 5ruQ>4*]"F:HdZ?'5?(?}8.%H6^-LJCwW:|^~agivk*=V\'Yb"4QHy)36McW&V+#7꧿6t"2["y4|g#(L'9QX2[&p `!aU#lF@]T0l>k h켾p;4=NAУi{m]1zmq# (?:B؄'bnLK[|K 1Nh)256Tpfɵomãgɏ+onjFlMERdhTxR=Y1MpWEH+* ;.Te`$)Q=̦h'Ȕ69dm~N\z(B[Qm~B7_k'xU0RHLkuNŹ*媱EnavƯ9'SuZ6GS'ĻΔ 4_}ևl؞١[<ۻ xTa{{͈/HHG81i<>GҊC2z}~闶@FHrܝydw$)JVk n^&Z&Xxe?>ņy{$sӈ[9 G/@bQNp4a .|=D7+/:OlkXnA2]QXi ŎKB~O}Lw &^& Od$ e^/w+J ّHd{=Ξ9TpӈD϶@Mq)S#k9cyu^hUؠ2Bݹ‘H6yL8[2L,+ )*G|+GV]*l. n;Q+Aސ# Nkm @2GfD(t.8R,|Fq[) +G2VAeb 27bu T~ UsG}IP`yu%?IC}\.r/|-{Efv%,x2J?Ɣ֬;ûe)wҙU@ ʹGjU)YMLzB+r!hzdЋ$EO|`^$ 8RkrI%nK`}ɚf@>^(r`hap!7 p$G7E0/NR`ط;6>)$?yxD}LtDq1 J>A=꾕DRDc@Wي@O*@c1:lCy%yI!YxsNdv!Hbj0Ny-u)A66FYk1A ^WY^CpKIG>ܗ3?Ŧ>Oy%lntŦU³W,L KL4A"G:qe=.{-A&̔i&{) e2OdcՍFHisl)H| s sH%χ╣ʓ[WFN`8GVNLe׭Xj-FαLtDY܃ @נQfFFbn׊m|ꪅ;8sk1L"h'<]Q9}9'<\S-Ky,G 0dqJ.rw!r* 4-=tK@GRȫU$ D2iwk@V j0R Л@ vviy-WgכּɋVYG\өm1a-b*6sC?}sj|lǴ)5}'Fǚ=*svtHƭOǜ}fc۲NgZǀ:96@rBWB& ۚ+koai"R$PB&s7&l>^)~Wpx JXq{5$ԬĄOq+Zdv1p+-"*!WJXhs_3o"dq 4$rIJwi線7 N5cZu^4by?T+I|廿Y0FP.ؤvwAKHm1}kշsIʜf>I=4l2tơIܚ Ƀ^dvn2$|\SvJ&ڄk62\vW0%%qسrFb1jz |awE:ev: voM>Xr(6}X6hT<(|ȿePw$xQ0jz3ccL&zk 1,@Lxz{>:X;?VK=L cv-lyGVmtTX3 Ĭ &8aR6;KL=Hn]6T(׷m@>ٞ*՚~+F`-u0NW+j:s5s@3>9PGXI1ak;PRݙ 6'$_zmPIkߍ4tO,A,Nophk3v#:{tXu^9* |!+Q֦3_ˤ|؋kZ'g`v6aD`<|R* ”G;.фHDa+y?1X㶤P du@suC0 jkRX\XJ0+ M*lPL0ݲ~,LZlvM9 ~ॖAD]Y3'|}{ko ONȔ`W@iX=zXٹ!ROê.eolFyBa=6/pF/ChcB|B v9sH!U1_Tlġe}cҚ8!Uq냲x֢J|-1`sŔ8O#=>*u\S*GL9!zµFɉZ(m"plֶt#tx#0`r;;V>&KE谦4e+cQ%vU2 SyNmΎeP_Aw21AϮ-|g1(L8#-6vhN̟G:Og1Ԣ%0vPغSJ).Ndv N-k7ZtXt0:h>!?+E3ٳx&*ҙ!p,Bo 0>*CҗwsY怿KsldaA,pןk:;wFGy)a*:d0r:72>٩sHpA+.ڙ`Q^ݸJd_1c0Dhx6 c\(S$$COB!o> +& EHw$̜bP51&g{M7P$@꜖t~!|& BJ۵ # lj"UO 9S FBv+v/HZ>󼎸SvoMO~]12ό. DFgr,trDvJܠ4!m 0b&~$m$p"Ԏ2>sn)A)-Ƃ<*WzA"U`.<7oB>A+SGL )XJIB 0 )ZL/;+[?tLdc,`&vFji!ڟ^u`['n[=Nʯ:tėe%tf8ѨV!U Ox]A&8?}` p *U@ œ?d3Xmr$'kp(ߣG"֠gU qjкGA^ȻXH`MYf ,k᭑PWM ?쿭{Xyiikr\Iиgy4ѿ@4|H%Ƭet& 7N2K!>'Ab_O`B֓ 6's'Z҅?/U8d$.d||462y2㙬O ~9B/1aG)헗+G6@ 2uZvX7!sRpb|P,,q[T9jGe?iӲeivFٴ35,Bþ{hhV뒎^__w_,=ȵI 3M_sղ]/^k[+LӆbQHQ4;瓎CAmV@&`` m2 ehB+xO pߜ1,@W#6!b(KvV.@N ;iI4;;j8QX֤.ZzRkTAoƊay:J~ߜ;x>o!,B`iMӼ7t߭ʊRћO 6N{څSK02ԭͪM wx/8cw"Eh!PXr)|^C,XV-XA{~̞ 4҇ᡄ/Jr敩Ҝo2k ـw!Mi?"=(N &9hxQ4jЊ(Q`ge){cMmQCU?1v`o4"M cU/]a / 'XaP chLtcNz95Hbv?Gtt#\W&Rùhn+)Dr.,E[<0xVxy"P,]7lYS`amٙW;oJH}w TRe:rEP2?n͊&Υ=%~-c@UAéqhdfmk+^s1 5&2&j?=0ZM4eɿ0 S=%*CX޾Ss4H?Hp||5 Q'j $|?g7U1w3eN?I5"1s`ScrO Z3E PEN,scxp  }K~\@.)mTrb{ -t249SG @BkOpg/ זs< èVf{-Ee}_gpD$&^Mf;wNWC {W0 wD,j< <%X j+UI Jt} Mr]QB+mfi5I-[n ćF(?K94&ܒ(QHM K"_GRl$J)o3]~#EL DGNbUf `X9&xf%a)@Yg{dPSc͎]d:k3-+|mBc@el9w ~'EˣE3 \ 1Q~}ÀL)VB`hh_duL!NE4| <2LA L`>_=)!u >&*fezP`u'ŴJ4m|8ΌX[-hs0ڇ? :y=ԣjD &V8k_o ^i#0t*@K5fz0AS#&YB|VÛ@*r(F*N}v;҅ 8!Rul^ #=.{o|@@ĊuT:dh!@hTl&B? гPI@^mg@۪gfq}dyFZkI0?y$h`qum6b=f'8/4Sê$Qs}1߲WXӃf1L;?c?' ;.D#Pf /MBV=^#-.nY:՟\iA8I U7M`%5Rɳ2y4n|CH.;Q{9ʖϯ˷5Ɓ)BU>Iy>Kc!LkGVY%d[m]2labLI=8&IIu~oih"/x#(>:s'S$`naȠTtPZlB!+ڍnw)LIpxHfN(,LF#iOoNsFr"L웛_''ͭ'[* 2>B|nkى!wWG;B""2{Ttz[&Os;ٺ4X ]0RT`[2N4Hr4Q-f ǭ*ʐdgGT$e z.p]s5ぃ t@T5bXqXDRiM0ѾǕ뱛zO7 uu T,u8:CvuV9BVk@y[pVQ^,d fAZ*E &{K0nKN\Є0q1a5DcJ cKFaĥT 7qa`P2K2hw_/67h!(^VWq$\t[wv!@2ҵ}C0فB VGE!3,/4i/gԃc5Z8\r=*>lB 6sXKP\1;f9/e0}OdPR|DOL4kkyHpd?Y\X3ƭ9a*I>歄*: jٳ 2v4dꯒ;mg]#c#>~ 0p2I{Quf2Kp/6@5#@i?d}Ǡ+P&̙~@rWFK<e ȁsy'x Tnji1 =WO}ԔC?.KV *osG wW4 0wL1x |Œ;sF>Xl*XO]YGŷ{BAg .[ kB--TXKdžԎYWϩr R"YX:S~2/2;YN\G7 6HM~ Ҳ݊!$ j⼑]%2a=9~{'+]O'ot41/z,a51_I傏:ޗTfN}*(GVܝ@2;LLw1$zo{hB#o3AL@j"2c3*Ӡzu 0|Od͛^đƧhSG{neQ;l*JK}2_ #J1:.8ChZ!%ʹ8XS y~-mvF>9%$WDE,J)ncM2!SHZEIIFVF`A"Ei Y%:XbROnbn s5]fi \Čӽ gHsibStaa9MzЃ3)v2ӫhVR6B1ؠeŔ~ !Y#`ZϬ{-FC G<-VrՌz*&}HDK= o“6+bC%M˶bUQ~~n3CflK`#(>-FS71rNtַF PwkZPd?Kr{\x;a:r6fTh/7Ifc 'Ւ -4%\- V%@0-@J-? XA K^bjq*𾳽d?A[Wk\kw:zV> ~H2|o] 7sHl_~+#0 oD1lsGIVsk= -|$˗΄݂#]?Sx mA6$=if+ay} jdp\- [l9#>byAF*FMl) oRv/vd86?x:iA KIgDo%Ҹ(%#$W_MR2:5' )qӈd:l]/2וŮ]H(f PRڎ:qGIH^M&2ek|C#{_SQ3+tlɻgglOe+bʌzݯ^(Kg7L1@g|Wr.9[)P8@ƺe_z 2wBPQ6dAH'^j>MM[֤a剺%@Va}P9f)yKbƸ;Q}.G~D3`&u@iQUj:^&) >筷9.0QȬ@aBg;!aV4D4JU3=r<T<LoZ}-;l{׿nP |Wß;0n|wP kĵơv7þpm=yP`|DhJD6V$ rP|–N ci;iФ4'HmbmmݢȧJ d| Bʻ"__F$CvDP(”%Y&J+kѝiG(B$cF2hWWȟKڏ̟~WI}kBeL3̗A]-痹x58{_%a\dhqfJPԴ.v[W̬`:L:{F˾m'ؼե~l B_z'>v`U I@ W Te9G{?-mA|qZ)倗ι5 0HoέI NmdXՠ.Szer@?wk:ܛԚFmёזhΛgxO [?UFhSxi&D$٥yd*ħFvS_o)(Q x4kcJ<< 'NB@IDATs ^rx+-*ƏM4| 35MobZQp\>.'+9b!HmcL!r"щ>(]>7mOqjr}ѬD #VC60ZX}ק̀}^l>.d.$[J5mux{(b)A8b9 e-2A&ݦ 􂾓΂eҝ&gօnmTl"OBxt,i?a+tcw=xrm7H`,rX<ǐ!g;~8GItឡH,zz ۩%f(Kp H|y}!滢w_t9xe-^Pіdx6wspj?W,jsBG)(!M&2X ]ko p[\ș%@D{br}Ty]~# rQ!)cy҄Wxc(~YǀhNlg[bQiDgi8{O ҙazk7)''QO'2W=+{J0{OHGMn[{ ؟3f)Y]t&6 1W>㮪c[a@䑨__#٠ūS &ÀYQ9El_R{aocy W_eOė6Wx5 $<ޅgT| [X(<2(Le_+SQ"e]D달,^LB;[i@U-%mE+CJܸ789EyO** ziQ"JyT+ (Bka{k?]ȾlUҠOփs$mL+{y|$Vܻ!SK>ȕC"> Y9Fp2AXK|__ "b5m4Us kW;# ɣ':#>Yȧ@l@L)((n]eqGbBSqR;_ʖzd4ϽNbwO:nܾLs ۺ| ~m.y'eO?>%ڙx3(/ &5nki>:dO}(1_}UR?bMх@3[!t;Z]"QWsqI\0ՠWnT V1WΗ6W`L\99ޯQj&)2v#mHP7NY5[9 9#u4isQkCe|e\-D=U= WdslBKaB%k|ovH)XPAU'o C%\bS݊GUJ ~N32r4q#w>F7|*Ȉqk3hUJY&|3JL- E9p#-}kCB).Cm厘BkC51]G ͥ(kS1n^`u:g'?P@w-ѮGMz uyE Gl w<*vY `;iμmF0>&VѩI0Htc~X)!|a jɛ6Do˷[o$9mrZi{Fa-i+;,4_wx&4ݽU8H!e 'ȡLWӃhB Ef+ `~߇^4a>{dBP_\!М’#~N3b9ҵO* x2gL#ڣG{Dlr-(~!Lz2xhDfrh a}|.K`a0İ4qذ&C u8Id1nF;j0~n[>lTR|ŸD\ &GŢޅ%YlV25q -'Enæc5-1}lf_`,viŒ7!b33}@.#4D  by}fbzoq{42m[#[S%涿A`5!]JWsTo e;(P1@2sWWEY=v$;ZdRo+0v`Z2jJ3S' C81|*_7[0>dŭ(ߍ0Ľys˭͌ @7hA֤W+Z(@Ai%M{Qz{U 2ΫƱ`2뻾N-VJCjQ54KnՎK"e(ܚjp$/sn['.ba~"4liOnMf ̡5@SKoC$jQ`ǹI?TMK&ZN΢f4A)nӾUx|E9D]O!܌CnVP}Y;:A؆4ȭ1fdeY=qDg{|fEM p&+) dJC#*&=3 9d<{? beHW ~lu \b*x`j|qDhIZAϤ V#*.b&s۴!ktgm_ap2W#:KysA;ud\0xߕF,qe[r̟~n} |A3;_`b(J wINg^*sM IF )i$ P>3 jfn |&gmf/.{Hl+P摮CqShgjp\6+8N9ǷD棖%WT"Ĺ0l=Eu|u@Z攁0jgw!_[EW"x#RIV\[uX@.Aimi2ZK]Q ZI8BRni\U r~t}{8AtjJ60[WÒyHɜ#%!czMa-+]#(n9d6e+s"osۣ suD!`tןnÞG AqǞ5"ﱃa.aD]ţK*V%Gff5Ry4έA3A _+dv;$8fw? ninWkd4 -uSp8)aD% 7-{JsgN%ش< H#±,"0:$ /b3)٦ o[{]~9#AB):"t#-V'` sxerx[-(BS]mW8Bo:bC=} _ۙ9s bo m`Њ+>FV0]i\OOw*9u?(~[W^K$4cmE*. ۟HTߞ#V[sZ~[;(RuƟ6&2e|{PrKͰY:fK]Lx"&}\=.+> 0CSmit;S]WpS[]*HDVeVf$Ι._:=YCXȪs WzVJPr* 3qΡ)&/ՍֻyztצwW;;.0X`Ƴ6(qQV- NC3ĕ9q)&2{j' TJM3[i:ԵW64 \BX~Lп[QWpHX1[pca9y΀Si2m%[,p<~jz"p srk\.<6䄙,il]2.Wj-HDxDTTɘM iu ]$kb ']S4 峺r}.mC'M2]Z@c3d)ӕ`BI` kWf30r;Q48qN 0u$)/:ؤ=Iw׏Z!u dv -w0%)fgՆKr[yYE Œ^c,SFel%VߺWP7A>B(hLk˞5o9XMgVćG :^:0_zޤ$S2V+SkF>f,} S4>OQY-$0 ` PnodUeXBɁTSYX';QLwmFm aG'cVe#b-_z -cK،k-{ԥ>)ݙVu!6}}׿K>gul;tᖣ#`f,yoK(#UJBsdRY)L׻Q%vnc]1X?yUYl'W3-3!VO7i;lz }g2qMKu֯ND*fG,8-Y"B p2NJcd@nc-l"E8^-Y;hcG;29JW{ nagsKh*@ɔ=hLǺnVBZ5$FϨƙ(FϻjqincW"ƥ Sk9uۺFkP7;|։Vjo79{[iAh/ur|"C[8uc 1zlO tcZ9O[ roN-Ėh 4ՅF!SAaûh'g=eETP[4[ 4d HR.궍vaijs№)}ʪThxT[i%14K~[wWNKN{MĔ;` ARTd8%sPeq3O'rCEE&(3UP>v )@Eqr66%NsŠ[ed/!u%6QT>F8-K[d;d^Ot=7cu߱o}[Q\Gj>K(ұqb zp?D"/zRV[7q̀I@ca)7P,mrRVw)<:ӻx橸&:ˣ|\e4`ђ]t@0S_2l-] ^g>y Y-CH:rF -E2tMf 4!Vˉp& dKʺk 7}=FoŜs _߸l+hI]k, i/U!;BO|B_6O#Hᆴ_v)EKWo%O/nH"|Jm0Y47@p 42UfZ.Gm9e^H";%qԁ `ß\+MeLXM :p*,2o '>?*@S_gH%9R Z?4&ױ+A?[^ }$vYoOn<8'/!' Yʂ!1/:L5PuB*ozW:G^%H:UX n3Yǻ3 QoykRoU~.kG] U!:@1n(wWV&}\c!_5FcX( ځ5MHQEm2jtAKɪ(zH-!4՟vI8vsM <{\ђ&Gbfa D=(u~6*J{842K&Ɍs9o9NQ Z:uT}N)sYE$U..#h7-@|6'waFLe*o9gHuZOzuL []lWkӴsj3˓ vUL&->iU'L嬿Ǐ2M;NxeEY<$+R؇zm~|8%iiq%[&n}x302+@j@+.zh unbսˊVQ $(gS98AS0uZR Iw$k1[ x)mNRŚm В*Ro^:p?i:+(h=儈D3ʜq4͘Ihkjࣀ~ĘfIr{Eg`fc -3<-v`V؜'ʷ.'H ۩J姫nPvXp{[%:$[2寲1䙍)&~]3r 絅Nߡ@ɮ,DZfoa/8=4%fksW+= ڏayU^u5V]ϭ%Š".S~J,;Li6OI:vmlyU)Y.XS.*W{;30 Qp,{+$EuVN5_=$ y>yxY ;ھ/'?Z!G#*tnm&qfL { jz|~ ved2M Pyb8` h<ԁ&E8%6E8HO)JˊiH)蹧l-vKds˲]x#}N:Z/1FHxkI<z %C/alk+5^!^4>0  I]mcaK%%P{*Zb情ʌ&] /i2r&nwX `nMS,;'&@;Λ1cD[yu ,26)"Fq&Zk}U.FÝ(UzvXێV-2@ǻ-)Xu-$9tC%-Xt~L臒QK )=e1qtyG#SyT^, D)Ӓ[`j  3(JБ>cv]ZIw2XQ1 E)oM(qT9+o.49)#^LAm aǫsJ<r'7R 5AyTݨK7:j וL}6xI/ ̥]ìjKHL\^B򎂒dE9#*>$b|+:gU'u 'L*84KT:/T j4?0| B '?X6I[̽^kP\X ,ە'$'45mbjЫ!8c* #M11lo/N7N}~{pVx3@Pv\}9y~-Jgaqq^K0Wӊv&):v a&ǣ>-ޚ| o:2͗) 2S4qǻ di0aKRåv8>B߉R @?]{K\pyD5Zo}tBD@ g6<6נOZ+*2VNw)v ͧ]m'2tH $'[diA9ӑk?MyCg?cUk{FL( #*`:E=`-+ vw[k/7N[B~k_[}TU( ptȢW@dlu&,j{ʝ]F4.;pbVvx2!|2%J 6#*jǐku,-ێL9F^" RE}DSqѭ׎ëlDI)Đ2|v*Wg&*}͕o4nIc2S|t9RfIr{e.3 EsNN .yb;mzc^[.#U``9M+vQ e g-6@!THi2LԻ<"aN[r]0,-?`V}2e^HEDȯCADx>^W7b_]@)&Vow kVMQ;7 {6:8bC>UNbg'-p_PXh0q/LXp÷^ֺ/$}!g ( {v壢u#2'd~~LܯO.WuZǭ:k>s'5eAMFJ#tIK<.@9{ wh 1v.s xH&(&K}t=2?iNVOzo.swU`{]ܐb)mۆ[}t;DZ#~_n*03`qona1zz6 [8~IAi8;VtM;%{$oPD՚YuRr:YP~ M)76#[ -gd3k,˸1&&w0@|Ȅ}BFk ѹf6Gr H ڙ bnF[Jw Ⱥhn'}~OTMOg\(Wx]0lzA h1=6l-av7VCI\9BK~3CZlMSi9Iw5>WN_wJASKd^oY'N@yucWqOIǩ'.q vb>{dGCS౐7k\1WocXdԩdoFBj#\MXP|ȣ JEH7s߄t[\ pjJy*סSڮܨH3Q8'b;l+FOKvZh(3Me`YfۜAyc#SKkYK瀠3_u7uQo ḅ('Ch,:VX7֚A~j'!^8nCA,prlWiLs 7ri_vҎ/=D+\g#^aY]yjȧ rc]_ L:Y4fX $f#m\Z]ZJܭ@C{NU' }aWu e䝬%ζ,<*bmRiuarZۺ,&*قԱ5"wtXcYG1LsҲtIߑWe) Mm{lCx\~3@L{`ٛ`-4V"H}qXp[Ѹθ?ȱ@2&Vl͗` z+@Ycɬ%52:Ȳ/t{7Jz^_oI;y8ŲqbELhu/ Gm|He%~uj9rYɟpԄᧉ&'N;%=q 286d239lsOŦ qA;Z#k?i@5a D\..a+Ӡ ,,$Wb9k2'ItBG ;`2 `|ZZ48*j!Jގm47dpI_m/}X3$vzO&*Ca=2k5m):PT X}XV H9m6,/ݦh _ 2C5STl}{8_VS6I|CZ3Yx{\QO7$SVo#Jh;Q|}KH߭@IEt 41![ןDsZoIӵJS8ND5Q ;\/j|sZ&j&hMPc3g=wkE9昗"@jB|ʘ| =@'g9MxӶ<>^4 "ɂxae ֈ= o`pl!p.7!M b;ZF(Dho[USkZy2 rm f R@N+.a*#iS%ӌ2W&ebxps??*x;z*E8'. ^xq?X`4~B@MΰLQPei !BՕ1p'1rr lpLflCȴ8Vh9pJ" reNLIz11".dcLR˼Kf>x{botMΩWԕP}nC&\OoA,`V" %r(m _j&Xи6h^pn4}OE4b=onyإ88h+~L/}|6w{1W|u+.és5UpkTӂDl)[{i-ەG:Ϟ!?ؖhGoςAN8J/Wh 9 sXrʘ*&۪5ۋPf&1?ᅞT1L>Br!j Ch~&RJ(p]uISqXyiSH.E#,'up ً8NH V{B#gc5L;ݓdv{+"7 9"vJC!iKA=v?z$>0sG~GRrcsW>"ufϤQ jd*sz ʤWQ>_S/֪8{ZSqڜD?t..AyԤG>+kr d{ALW@!QOwR7Ĕy"΅YWZN9c]0W>7T[k ӥ.NRNG0j+$+f RI,:/qmңihkf95Tŋ-d t p&?-ӹ#{-Tӆ1Yk[b[(' PlʷKa6u[|33>M2-@~'0$&ztg;[=3O#=3s@i6G\Ѿ#.s8c0n\4l%m냤=Uvz6&`_uP}c&Q\1o˻9-0&PeIIwdă>C}eXNff@>Q]k13-o~5qQf'O~3s~ jtk}-Z&{}+/UHV/4,ry#Q΀lenj?Ϛg@IDAT [[ͭ.y EJ[S 2UdpR+Xďw*0daAhؽ&Y&`a1A`#3;pyQH}pI N/~u*m{GK]C_4ւb@tJw?эf:7$}q]Τ5Q@a@DW?BE=kbT9t$f2R8iNI!x)WT Xi>޲Ys3xsb⍘@L`Ev${I $׃v\+LfcޒYpTc[nӇ`AbT& Z`[kl=[]aPњݥ,U]g{yߙ,ZqNgjC #HSc/;^5ò;I~(RƚcOnGCOsx׼3xM|z@+dlA q+Wū'CYy2Y70ob?6I?]r_򗷡a ffQlK.K&Oˀ/nv 2J=]hC<M 7p Vd jT2@[9˙5׳9|“ê-[>F=} Fp|z]iaX7t˖1VCgoձ#i/+$FxѣL^38/ekC _ô*T8=TKt Lb"MذU8 qvtMJm=0MF|rHȟc^= _q~vXKwn]Z@+˄EOVBݝD DTΩQGɇ3.I 4Rtq9ֵ-@±Xa3)n(4o su5iє,r#9ŧ$:a-mSH֥@t*r0^79,gf\i#QxgˀiHS̃2 I-|CE@Qh ȼ˩.睖hpZFk[]v6 $S Ҫ]z-ַ+k\1^VW& Tu_ h(\a0}"6T׵Q[T#)Fb{uo1Ou Os[CA B  @xD44C&hiv3dUPM 1}H0G<~?iMԧ>p?(mm.]QoqzrKƨNLEPdNb0[vz4թ~ [R _b)= g0ODe&QRQ x23v2!j;xsg ӉwkRsg9h^/wu٨/z쒭c!?}L|+pzIV+wOK^B#7 ׫>e}Ȅ33Yb>O^nv4`K@Z/ku3WC(X4RQhpFXCև*jsIЦ.z칦ܼ`WC1{W/IPܒ˯v35bC RYoYg陦\ VV7/vGO_glB@Ym%e-pYp k1\ZGmq!14sR1o$C @ߊ1MwLHz 6K mlrg=o6# ڰb+Dvu͵5DY \OSe=)1RVヂشz2WIwdUGLhAt\ҥS\I>RםInܘ]VXuN|1?RNj(Nݫ@TAn;mynE7Ho׳ lڟUP;TA!d|3YuhϠmM@mFwVr|R>]HqyCv]<=1 l8 J֚ 4|q'Zx.ngl峃N[ΧֶBg)_Kz}]fS0bo pQ׺9crH/EY[bڑ+`,VN8>2@8SGMxc K2Xö2DkyȄ}餩/tu ']g@ڼ$y<9kX ⌥SGwq*N :WS.0<%:d,s6@i;g)$0 _8g'-s_ 4A}$""] "Uz ;ћ(WblQZH\@05t36-d!|˕Ơ<֨Z˵Ut#]j)YxØ zF~W[xq \H4Y3$<(?;tRd~%Sȼ.d1ftMhSFԳ0PNƩ9''?=|C=f6;$Y}:((yPy:iX<63KlJ CU뛚(mz7C3ѐ1Ld 'TK2ɥ̣&1qSU@ūlvn ;}z vkrRLvHl42{k6S2ΉQɟDBsԷ:0N`;[:{<(Dl.~X I.Cj<( [3 - q[5T d1ã갷iO)HO;Ke]+/`bʺ+1)j?8+Ѧk0:4؆Af&'3"n{<'&dA)r {5h-sǩLfدZ_32?+bUH3%bF~c2K\q39Yk9Z OeQ_"-Cl@t&?|*K\`@שU UWqE-O~!t@NN  5ٳ}|-־X]v5mFmȋJuDgWft5+yjE ,'7zYx^)kj 0';\c[x9/E ̯)k@?Pts9X3t#)̶̡Yە oHx$gw ܸ(d&CP> T)&/M@#v2/jG?o6# ƻRO @B KQ~  Gvy%L.;mBηM垺YtI#v[ݖ7iI8!쌜"$)af` de]@| lg'֥͛^(طqq6쎁 )nzhS8`C3d_c/LȄdb-p͙"{']ʳK4|i12mcWeL9g5c P,эSᔳ}݅3^QGS=X ә5QEY{ٰʥtAΑǪ"< $s6i=d+s;C-ϙoGVؖ vޤFfi=ధ&(?s[qsG 鹧=Y9R䤹%pL8@qMgwU+mwI ց>d C} 95A="œVDS~GA:)8Țe2w]ەm{5G6pQ GF g6XJy*7-Q9tuHZZ?=^ 0#wq)&\^'@2ǺrYXyWZ@,9a%֥ Oh+hV2Q9GLSW*$gh)E`T[5Q` g2 6չ+[Q-_ M-QWGM=ǹ5~2@L-m}eMjSدIHb_' >'${jumBooAf'ev4PpDڌPީ1]&' {Z?uNcɜVZ; n]ʡTvOdmY<4VO1dKzȄ)rڌ"dKNLnhko\ jj'?zʌۀAJX[0LE1V׃tL"Uc7Nn7&6;@6oOu݄xbCTW;cW|:NO&mQa(ud6fXu؞:~=q3VE~[A`L#2:ET{eNL{4V> Z}x: O9zleka\.( H(oBD}xϳ0`KN 0(A'cP1,lά>Д"2-f@.Gĭgey;(<>C#|3'-,}qsv;mY -Bg/ܩ']هx2s3}t0m@i@f`҉fYq|J1'{D#3'o@5vPvX8)y*8lc[ y',[w W̍?l% [sÜۀSr}۰|F0eq6Z,.~Ȩ8s1~/ɉ*) ͂=SaZf}cR~-iӋiǡJT>DזΡNU]x -#֎v^eu}\jqB JD)NIו3zq}4!t@ѪM9wq 4' TZA .3On~:/g$jmSHP#'9}eb8U`~ǒ{2D.!Jl%kHn m!&3rvF+{M +Fs&]K Nqun8q ښ/6%e=d6Dĥi S^"*Jcy@ h]6->d3Z=g+z\2q"#ި.wNZH 4RI ,m>OOv2y9z EA].+sdIxОmo'*yVZ^8 X`8 WZ9 .veUO.`XңOȼg#ѭ&d0ѥÙ!F UiQZ@Ohj#I[I xX4Й9|Z43֝(2]itx|xc pstZZ3V`'VD)9 ?sWNX4wjgQe;`*Ao}[=oX1mqOXBrG͍t"*ކϣKY\פB" D[/e kAOl/T!9jl *qDԺɄؽeya+E ؊G8^خL+Np!4:?HpƏ vV9uXhbt/(/ޱqf30`2UˢAS‹ek1A#Ԝzᖇ*3>0ORN4tZ8}l?"к*ǝ rUg2 0^CM2Gt ²6.cU7YJeOd2CdB33?`sLĊ/ لx|Lf7@BĈ/65N/qHS9&fZR^ FAGVd)@ޤK+7UlHqԻ'>y 6q뎩SkL1mJ ¢7*?o96;&x&f{DeBIOܝ2ЀXq-62oWE'Yy7\Ox]WQ0$GH[ Bwiϱ|RA:to6 ~x9 Vvme_@A2h5Lt,#q&m@=oYY"Pۏz)SLQfsLkrh8XooKSd'Jo4-'+.+鮦* JsOlsԍhK~SWZZ]`ПǍ>Ӭan]J;7哾1*O9=a6/^|3C]fP-NwZTt4cJa6@1r2|' DțOQZ 6ˆaWhpnz2oMT@ntzksp2wuF^MF-ZD :wT"1 %LjKBYϋ/6c_vV"c[t7FcŒᒚy_t۷-[6\5 $#!oo! yLH;"@ 3~2L -i!2>@#X[`7 %wMa/} crHflx3Zuu)˹|qa:thBTQ·J8|KF@R%N詂0˾qi8ZxZwϫ%7t䨫m$a\@D-Kh!r 晓U7[q=~f6iCJbOD +&^li;hK[lŮ\V-`-yH)qdz6[ؓ-< \ #6 J|<ŖStpqr?Oa XS"G6ڱ{w WEZ dfCyXG;J3xĄn͎ܱBQJ)/+*zZDsWk){A9v-Q9T)r$#428FɣN75*a:<+04Oe-㼿p~X~ $ĉҚ*Om ם+[)_Y{SB% yQ˜7˽$cJ6|栢>LSn&(FB\ǃjgM.텈~0qE~{!*f\ k7FjF5 ]bs3oC|xցw8^߀T2I@&!ě KL ֐eM 1-&ǔNxA\~;G}-?9{|q+|on~?:I Y9JZ[/׎bZGhNqqM'szO^ܶQOcZ)FO;–;Vrp(f-ꭑeVus?r6hV> #)ERd@]^1E a_z:/>tw)TwHH)NǀUO:=WIX׵4FDY~Z;7|B/OrgB1񆚓Ѫ~*X.(9>#]#OO/ZN;O USQw嗌*9ViGrm4~cjO idr-3&a#|Ce-X2pr 9m3[;l1W]澄՚*.Լd$q̉YAC7 3r}ۭSڽBAim[o%{Tkb_;/d\/A\ 4|RZH5Tѵcͧ)弴vOy!bZ1&*@y%ۃBM{ue95|'V\;g@|^a}|WCgYXSʫm鈄X; 77 Zi-,JcM/:2% v}?{@ D1du1e*+e vAP6R?@^], \\;b+ C#-XMN_$_G[#Z܎ 7e6Rc<%`ŊULs6/k-0ÙODoB+k p$~bOg2Խd=.V#sאU8mNXaiFb(8G5=CAYgq>UTjۙm/v7cTOO?VU8j`o vZK)QK3wK.tK"YH9ĝM~JI}!kH`2(1a;ji%lJ|ԚУaN/9aiHH]ZK6KcO3ȼe^k Ͱ\APP#b>J6|%Hf>#d :(P5_:u S=k-;bȤ v'+d,dœO¥٫̿61DXMwږ1)fR[\n4kj2E\ oN+IqʖQ{'Ձ7A>`% ?&䘢N& vIܙ4BIFloIJ}}9Nl;"mnl𪥳 Cu6(Xg;hDNo'S2%KǮ|/W!>/d PVKjA X<"FL-3LxmHo3ك^Yg*orr@]X<`OhW (*gSeS?@t\tv0N]TmNSeZ.@w?[?P4`k%_D /~QXꏁK>疭=ۑzuDi=BdA7e-{+ WMa7DFEJ T*z~8K|nAkl>GsE'y嵮 ?"SlBM暈ZNvQF4&DwKKǥxa*xhN"&9zr qFR-)+wV`Awv5-M;90'qUFkyl^il*T'.Z! DU PKٙ4H>oY1S%Nrq#u| 0Hfjm>&Amɑo]rW!Z͉kjARb^HBBFj!T@tc1{H73} 7TEV&J 8je Aᵰi}Ԉ?$!M0ii ȦO 'ld9Ưi&t<"r 0L554yc N1FI]&Kfr ȴbHdϠjw;V*'4(d9+v$EeWICϭСX.C`hV۰{yem.өrÏLK5Q:Ӟ[$6Aj b^VNw*l%Fy!g^2KxBNw1T/9X>;d.YEF% NV#&Up2k u`ҭ(yrf u]:VHe1-pr}~j3g__ Rniy%ؐgLȌD7iG\ *0Qb&Rkog3Ӎgh[Vk"d{t6xO:~ !iF֒3?3r `bXYSI iy;=8U&q 0ӆ _) ~ q'[o{-k?Ȣ$Tr6t8+4QŪZ"!r&=C DW@IDAT10Z-i6`Ʋ*C j,__kю*ӭ+su^@N~P5_ߟzp|k`T Bf!AS+f[_ eȕ˲)H4NYԬa֤JQܖO21}:chQ*6WT|$5:}qV0" du_ U¹%7+~pt<~2BxjJ%4|\e̅f)Jt>6󖤜cgKlgHt>m: D ~iJȦaY^TdIVшkpjhY?0xS4"V nQx!I~C,a搦S]j|^, q$$"u夐Re HLq^^Y9ڗMD{DN`Ɋ n֒ٷCV+l4;^G.Oo{Qg k= > ; w7_teOǬܵmҖ(uí"._ᐱi_v5f[éGߙB3z 'Sc8<]m ?53I#S둸2݅ yWidN?zW1Gdŵ@D zڮ.' ҇[1e6k)Ҵ| sZ2Q+ŕQQQ!]ŻO}ʈ6U#]#ZY}7C{4"ݩ:y0}5pDSaZYgӕb S} !4q5YQ̶ #z[yh̠__KK*=e<:!Q o,^6" pu؊uq =y`{\O^tcf` ׇۙYj' M[w}-Z7ux <۔A'ŊJ9y.(e!jP3`m Gl=ek`V nNu,4o{w'?MA)]9޴ImM :PԗǠp 0iJ;7I vNpyLz*5],=h}$·ͱ6" ‹n[Qko%^t1]wOsJ%}ZFf\\ l_8Rےgo.=ϧ)ֽHRly33əܕÉA5Ֆ"/3S ,(݈,T}Q#nMi 3eJ_͵pxBc.Ͱ }S UЃzsv'ݵ{/_Pbacl8Rq&V/jLNAk"L[ÿ?<η7^C4fpcc1_lǻK3bcׁ193-ԅ4mvN$p(ك&kܫ,xʔwEjA=wI夦GCȅ'm">u֗B" 5wأ'o|N7UƉ;[oT"Lz +92p*֧RjAdȌؒY aEYܓue|PsrLM.7n{z$>|/;kMq*|F׿utB5WZ΍ [6{Ob+FDP$"F/۪g>KӠHws0+/va$:"xnej< +Q I^C6s6@->30[3jm3Xz&t4SWOzQC9_ ec`g#u{ALmL;/+DUtr"G֞Q,EeK +zwKG:>b+r$ePHum)]f{+3hi63X`LPWSF"|0O??* j1|,QAxW[!v5sK[=Yqr f^R#H^T=i=+_H `/&9|of͔ŃI.s9ݏq_Ѹ[98Ƭ a lǢrlrNsE(8OE8{P'R`˿,arGt#}}{~S]/ݎxmw[;>oZh-zYKi> TkIg+=[H \vlOD&GfXLg(4;rrh[{w*[fr#%)%Ic|F]m03|<5L2]r=+ H:`g@2⋴ #E5yݳF:h޸.=cɏ2׳i&lNAa&B}+ԗg5dCֻOr\F/}R;E>Zl.=׾?Hh ,cw|]lS`, %ɜHreb!TwB1rl'緞g k>wXcsXNSku svGSبQiX,09m=oS¦@SX匔\O]9QcWFxBlH|"[M∙ &y $yݦ"]FVu>[\F^;=vb'%f'';DqV1<BQ7>Qk'M:i?:y<]?ڄ7i1E&(c#K wW}lDߟg<=KkvR`~D;x&s E\fXGA3HK#[c''tҭ4zhf׺rWJcb'e_'RxwNp.C<f*@W€@,,V=ٲ7tU|F֩.k{hu2#LU 'LN,(T0 7y^crk޿}:HCkcPz<={ofͤtiZ]-ڵzTD/'L Q{Fz( mn!o76{ڱGFGRPyn:s`'ȝcVaVk *ss/ ZNO:zP A4C}@1Zƪ&tlWs=,LURͬtx)'@ѦrfLJv3]4|XM)2Q4SW2:>J2 TLXtis#eË1^iD`XYko>J*'Й+4/..k'Y,0&6.%9r !Mbº++ر*3t0p=#t^I `*:7RnB{y3x9>&bLӱvӳQ]k=.o Cfh[_;mGu塙GŜBǸ2椀`YD{Z[ΡgspjNZiĖ;( r;ah{ꉦcD i///`,N4clQ?Љ5\w=g]h&VMchLbnنRa [ƞ~RzLC埱w vdu@qEďLD+ӂ]azREaf +O6S3¬ϒR|Y I+Zy/ݣQΚ_Kqkq_=OxnmeQ$ "rx)A$@``aŀ$=T uXdW~6 w-d͔tf C28'iymgk A!xg?H/\>=P53[B}L*O8!ΤUAo_4KtACSDOLiUP2+TP7nԳ; |&Z's%98-|K^!*zkŞ|YqUIՙ[SiaHܭ֘G8ܜ 6ۣwuUNGt'gr+E[g,B4LZάy( yϵ̤#& @x2͹@d һ_{Mbkg&O I.kGkSd<_t>Ǝ+M4"Nw?aҶW:5Kc'hIϪ؂M1{ǁCpTBV 6[$a|EL??s&Ǡzk҆iV16a*6U' !#VC6~J.=,Pu" $  gp9 ƺz?J 8XSa} yUbCJ^]\/2c\y3`qo$NDφH]71(f+]]`s.v!ݷO㡭U:{Fyۺ[}DgoZu[ڻ{sG0І؈EAрb:Ѡ1* $"CP!h?k>Jqyι^{}8g<ub 1(NBK3@@7nڧ ۨ;xfVv+gz$WZ /Q+#5)x[nbC+'k12Y565~* 3̛{,7dĄ>ajCf{!~vfjQ6E-gT.w[fvwΐ13dA#,>9[}1:؆2CkX"$>>3 xٷC>Ąwtܧ72GԪ7HI퀛< 8r"ǯ -Gz5ʐ4c8HP#noY^jL8:k-'Xma+(,ϟjl_aOK*,Dk b<_ k1 XcZ#4if -& ) glEe;JbĬuYgIQ 'J0[5iոaĚQ@ Mk{6xOO X0f iD,F*K3l[?f!'X7~7 ȚӣII>R,!0iMG| 4L[~IC$tʅD3~ᄣ,u\kw #-Cd EHy; @g2.Xa{ّno.2=]JR:,"̝V͹n<ں2))cR!7{Lij;*.&wgm۫I}G qJɏE964j^/ jz×C?S$??VǤY<а4Dk؉V{\bj ISoj$0 "}YEnQ/(lj6Fчvy6jᛜRPhX;OY&cY|ry)mE|&MǷ@u|U3oe{tT|&&@ =)^ 0Mr vk;pǬ# k?,fuK5 ԁv+OvAm[U:DAa&mQ:BEPbZ ,F"Y 2~ t'A nyFG0|3,M2jRYuIUKF"*Ҫ8BfUKY:j}N8$;$&?jd+M v^blSyK #VٌhG8K:oWm~V|Nc.x|+H4̘CEVTz9iĘHfoxSQId$-4)|2Zbo"yl&I#vs695Ul{0 kQ ˕\dCNJPY4E*kc>p3Juv5v2D湀-f!365oz4P,::K1d{&"Ys#p3$sR g_ύEd:?+H.$}䀡M]A%3|\ 8oQܻ:Fz{*L.Dg:8Akcشԝ63d*e`gCe.)$8⵵~'ٸ~G%LdS3BnOA!|-,8&hX3 fk" s@^NՃU2*mn8,>bNNryxN˭@T1n= 1_`hS}|Yљ=݋? Ǖ9ZA͠Ο_8Ƙn/œh( plkQVGS? ')ޖƉAqL Âhږ}>N3{hZcmNny`H o$SP0z)kĚ@]bb5-ѻBط,cvl^[+:rbXSV~MTlkx=Ro I)4&o̗M@ f=T :[c:v ( Z\Sc9k@-0ź TYV ΃H&wkmnÀ=*g!uD;l<# .*'mkÔ&`gjKNb͌H#-z6qw 7_΂X"_|1\<^WL^3B8RUo2/n@\@5҃=[GH9M"LeGoOlO2$Wv[z+7) JYNfMyw5dmHS`v±:Ft.0䴑uNt|B $tN >=LI@-k8܈MF ր)R@o]7 j ߆ce+'GHVc}VNz qL `;ۅ]16ϊ^/[6ߺ/YVњQ8|h/_u_X kR51L`!"YݗZ/fn%.x,4Ȭ: ZkWȚ[`dR[Iv{Ǘ]by@  oN/Vy3>6FO7/Wvvʹ<:#GJ6JKYT>5oB\w̯Lj7D`k|[0pzn0b63f}RATkgk\6sst0#V{cƋ$7*:Qы,7(X`l6h _ lŀ"A8C`r 9x5Ɵcp@^LTҋiUNOe[tɪZ@pj,%ƒAtڽ *ʵ;<#p3_ EN\LfpzЅHy^a3z$#Yɘfh,6-}5FessZoͿYf0:b%K62˺614c0u9 (ju6날P[Gh ě-;ԧ6h޸1VaE`̵zrbUnUZmo[+3Y|̲>vөM!cs)Qj[tC!wʠ)zU }Y [Cjבm]M(Kf1=7`7'{.J5BG9V5)8Yk¯dm&lȐs噙 금]8yrc6i\6W!~HXWƄ/G roIH ԩʵU]DVM)˱wG IFpy77TAR cf Mg^|fm^ FT1ݱ8HN9d  JގX6Fi9B2BYD*~{i+֟6{+C`2ۤu:nc\ߍCB<^؋ӎ'q|jZmoV2ykwsD+4 2Pf2ڎ2F7[cf1E *ͷEW! 1ϼb1ɵ[Sϔi}a&`j!NƼEX?1ǕT9  }mJgڐF)~mHs*tHـ1iN:LH:X.ӵɡRka_AV-Y}E9Fcn9Kj\ >n)_|`&>#w] PL8;q~5l^(6p=u3 –Ydi/W}\Tt"5G[}&S#Ymjݖ];-h2uZr\L@hQj}47Cfaब̙, a5sTVs3Eʓ?rNXWq]sR'q'R7WdQ6e dң-W4 &rOC8clNW> 6GI=hf}M+{.7fM١>5MxgbI:Œ\e"v %WZJZz ?(@ySH{Ϛid(:|&(IAzuGiUKP+̩r>5G(/!<'|D #%#"kjĥפY)q0 SGhchiۂVi;] s:=FMӷUei9 uOy:⏹\Bv.}2X0w#@[60L[ ]hV;% % kDJcVLk bLo7G&; с[|-mIvUg-K2| lUw$&pD|tVGY x;y0YqԬ%ʹlMHUB nbCvOy]M=(v <KrY19a=|@…lyR&2Z]99*ɜ;-@B-ئmoj5OSv2FBtW&HM9F1DV"ޡ|/:b F1ɂnqXL's'6@W`GsH+^x<@h55: jF`@1ǴCKRʼn/0L [@]M:N[k~Wm#bfn\>kcNGfװd^3Ggٌ̹MUf XZh?B8Eۭg[ fF2VopWT UULטkt-*Ui5#`n:ǒ,G~q`Myn~ꂎNM. -kO >#Ar 1VV8GCƼ!mf){ufiKqJ939 C #҄I`e^[.:s8z<c -܋v'^+ hDNÁL|9m4v#2Ђ-#3Z2=n~kLvj@\GW4/BUwf@UCQDh -ML}~QX2YN:>l"?_elt?r{hۛsFrQm#[0b4u'ʔ25VZ#`ӝD}+w.i5Gg&<*d#CXˢnR؉W-]_Ƶu[V8w25BI؍ϝ.Gv2[LOk߱,wa9>n/٭l0f% ~#ZLoId>U3&yΐ Xya;H 9!]n(JmX-KC/jGs q*jxo#L4rK_]ZU= gL5,Fh%=墳0+sa [=vG7>SrH  } ?GWMh̫64DrI 2gd>A_#l[8%lff ia2@ @(HMʩɽ:I4S'h;EJbAؗ+ldrH lE'>d]Ӂ?!ܿxbIYo9%bέcb1j*9GaSIL3Ͳ%b<0o^`8Tu~{HšlÂf$F,V=%=ޜV?Ìc1+YyK78( ^(/3&c-+%zR%MnLţ%dgW2kɮU/<;Vel*rւ>m哅!{ЖQcu򯛑PH[Ns e|n1w+ `e# f8ꜶF]->xڀt%5ȭ2s'x"V M!U@&?y:S~6U49O&k!פ1L@6״TLs"A@ᱽTUv%aKLt>5nQP6\ʖS4\777'xT l[g,*x%Ҟne-nK d)'Z6Cqm~)5nl1t˹o'G4 WN <-C5}!ܿKpg3%_,(YfVZozRV9$sRSqJ `awX jX$OgʒA`!J.kpj5~Flf:9H0 yTtՐ)Y)x^O˅]rmFq,}'XJP Z!`b2ٌB-j oiW\տWK,D6mvΪ,hE2mvϝ*"zqJTL-p4xdf"g2M]fXt';8N4 mL8<6vMo>}ւ}9 *MĂ鸫-4;lR꫻$ZF ǎpFjVǻG-pߤ;|17CNKʖQ~erXфnx;г%hG!ps}QH 3{-juFFi66'`YePV0'DZ HA_a8W{^M_HHSWh0;q“1oecܙk8Mq fovM g➂R+F+=L6HACLCoxhޣ(=2of3žTŐ%jݷ亠uX-a.%wx%|ߚ=h^ؕh2"c 61:+` G7ö#/73e!Ȼ^4]s'3MiJmPvS$qHxU ҾߐhvZ}~C@fvqo'v>)5B_ dml6QcwH-D̴ $]ZC1$+G#@(!5wzļtj?WM%b:dϰ%/0T9wc!I.r'3`Dr$@Fb+9͘\MR1@ 5#> HG4,9bC V4\)fcٞ6ysǦ1`L8fFZ[ b ث D^zW(l[Vf-cs~۔ѼO9 t;0;= :^ʠ\GfOƊ]E6(cԾ8NJJf奖m2ӷ):K(vst~^-Ѣ M|NjWK w J,їm5kwS-98bSh/ @IDAT(1W.377.Jaq 4ĩ7_2@5@%MCȭNfM)2j RL|QKҖ3]aUPD`uDeM0G&%383DCG 0[cDszWͿ7SK'*m%ʉ(3ɣ%} O~tSgK#B ]ao Z0 Z?ڞ\E8ݟiEogΪHi9_͉bZk#صٲe2{CpVmM_8yn'(AL/FwUg"tiڬ2Oxߚzs1Ic˗Q Җ{`vsȎȴߑUU.4(-LU)ȪN npڒ ǂS، wW9X.,akw“QBzsn"4GoSfJf͐o=@+?2fJ[;ӪKXƌKv5%&I;/~)[<KVz?qD>$@ dLHF?$˙OWcfLdy3vŬe2GI oM>X?x) 2h5 Xl:Shi8d[dfߣ9 ]7Oi|U$#F9ZTV]EfS?A؟nG 6," Q 4ɦDEd2C0:Jcb1V\1fMf,5i9֗Y #_2[!;O:Ub{-]&yhl1i ^l$>O6q E&0mushiRy]FG=0 lbt(8<^K8S{\{ Y9ݠ(VE jL/{Ah;UӣuFU[ޞT愜cauǧ^!Ca] z^K̳J7}@el5;By3f7yE8Ϊm ?;GIp pQ9 ??(]6d#_2BVT PNN8K_釽a;+ XUG"եW!ܰ$j? <ndDОB(ف_x NA_d̆5Ǣ-c'ҧ(_*x&k-::ϺӁpsC7Q$85\msdrErkǤ\#MLn*蜓h!2k}@ u'fHN-gs>6+yc,>b4Rs,yDpzfǻ̓daPggm Cg8ɉ {*-ZWs`ɀڌF v">% '}LUGr<-m|;ps2eIiM9.Wv ćHhgFfG)St w2S7 ʔ\1\ۑ0FCkzAd$IV vh>Ao? 优]364-{C~$`†ʴWZ.3ylIvH̡.hibMO2yt'RNJV쎓2i ǣLflF#Y퀾gKG?s?U#~ ʓ.)L@󤹚e5o_$h>V׿Z[ccB7ME'眕Gɂcou xx zRʹ]*Mq3ҍsRʇgbe)HNU{ `ǻC[d1fCDZ5-50)te?7ؤ@N9ÎΘ\~|5vzssQNb@/OO^G"2LpL.wKlKƅ/)vL3o]}QtfUziGC)$ ?ʑ7CxJLp6&=4'첫:m9t^>mӣ$L2LZ0ĥ)4^SǛh}t{ףּV`?xB5u=2.%Iq]uu9cϦ+4 -) %fF6& c1۪+Sa[!A&7WlW2ׅN(FUHdz%f/;*i^O8h\{D*(ٲ_;#Ae_WfEuSӆnt/~ IbA俤 ?^B&4ʮi66/ 2xӞ)K~4Hu )u9=A:(#})WUzm-M9s*Gg&y4ƶrO& e ՌH( GNʲ( pض.v. p*h =: JL* ȳQ6֣&*Bفs@IyUߑ/IIdf-9j˿1@6]_Vmrpsg)!GL? cGF5]~B?&  IVIڣ#Spy^5UoFNPo ͎Y,pmX| @P2BF:`.8: n]Y܀أEoyAe9 xᠸDWZ\nkx3@gM8k uG~o_4;șۄ1wש3o ".)C𬫱@UHxbwt>Ube"xn1j Kn ʹ,8}8vhMBB@ca=yC_2iG'x`-ɴR^֢*ղ Y) ٥6]t+xa5FSsIb\$EkG=aZP3v>25Noa'{E Nj+5M썤_DUYTj)cx:(fixzi~O"= if3:kqMq \/LGvX˛&1&52L'j1b%&\z7l")ⵄ1=@L.kMs4q$,Qَ;. y"!J_uL rx~^>ҵsGٜf4(?+mOf{`%apQLܣH dG $bj,5\ZcJgkn [S#Q 耺WhǛ!|QLYӋ hH(3Qe㣥0rwbG-NC[apeJfۿxXaekKZܤ,p2G]k$ky3%[)Ծi9AF zA.)'k_Nm^''<=J_c1#*VAkS &#v,%UY]ˌL4,[-#OQښ}L /539F`;Bد=ȟәd/8ӪJtyDS4mo-X@65fy*M lƟ蔮Xj3+ׁzNqէA}VKB`M6t_TO VGyoM_ṛ)cK-"7qw>Mk-_SNo,̆Ӿ?1k@b.PF/>ZES ?̐5ׄ(qU ` @9n$X/ ٿ_#Ui8dGjRIR*L˱:$砯7Hk_AKiـ7 $(ÏFfW9a~#ܝmO`E0c3n̴[*H=n[laص*v=@(8(d|>~6|e qiz1G';bO&" ڸ/s hzzadgHOQO%k2=NQ]$^:HF? HA@X 8|Xy }Uu~eH‘LJB%U5vEEGy?ʉjďuzW4^o`?"[4-|Ifh|q#Nj~ln}21}hGYG|^1&a`!ẑܩ`tn(,ao[VƄvtȨdk`I`Oqjm¸2nk][=VUavǚԵeQhɶ_ JjV;wNŽAKcu5xX$"d h6< [)Ut.h+xx=w#p3/X1{wC0L2\Xd74uF]jS4?m&.v ihy;))׶@6pǔ[?ɢM9݁*;nGJ90ZkL~Iu.&Gha䑃ņG=X-Tl=l̺!}RH2|ZVbkVY,Gnc×Q$Wݼ.c-.O^BbcQ@[l8`hdɋU/L y/T̑?ƌ9""@>3dXlyƢrArh$ 蔮`|j( smu`2Eр@>5+]>ic0TknW*LS6rޜ`A! U^ )&bBenP,q QZ.v"2фڔ O0i1|Td5w21;V]iZmc6܆}>`_?ppmekAG: KI:e8a,S惵McW#V0_39AVBw`G3]!|a:OܛFo\s嘅B*J ?w8gѮ(6o041מ/!8.Om&=rMJ0'E&.zve}7#)phr# ơUg9JFyɁQ6UIXz[c o)maӓ"֖0r;77Wl͓Ր,N÷=gk|Nƴ*&OI{ RHb@5uCݯ6{qV96 S^*#q8Si NZX34fejfk|‚`]64'!\p>vZT % Nø.3Lj"Wh>.PxIYӘ.^"!LycKfrYUqt-3їJ3A$VQ% i4tjҘ%n^˙Q[ ta@D)fok˲4[wV"gs]fXni=&̊uuLC;jsdC;3b'ak—+4ԉ"쾡<ĘM\/Es$>&X]볟IR:f+C):}i8ej&1C-/rC,2ҚmcHg$?$}fb r~#0<|>%Hd_ "4I.^%?:1SD;Z&w2ѻ ]%cieAQ4S&+**d[PJlKTVh]?'k[#x hV  Lx֘P&HFU+,EB+ '8e"tḶ\",>UOi4^tdNtO==sC(2=C"@`] U=noO3mC"i$HaiN)*[8 O8Y5͋a5J| \d-HYy-Kbas'eRѵ K)Isq=i唣mAwٺ9,_ZLo5u🬔vGަ CF}P<"Im5rY)X9NHZavoH=9K[a.ҫ5+ci[hRDR#LLG&.f085!5 OC1>f|&1Z)J|&c^%t?.|cD@A)[^YkwRA4ゎƮ] ȀBiǵ * C7Ihi6@c5F3vr7i+^_]</ݾۍ* 40 sy%ʈ3Epq$&6CS jv/֘ՊG.V Ƴ^xpUv)oŎo2w—~L~6 EWқKMY%I<+.ɍG Ӌ5D$ NiZW B^8elVłdyR%vBb$H& (~ O>&Z5 2[K/6m2j=VDu,:0Nfe.Ӷ3ldINՙI>WntfI^s}KᘢWN{:zW/LYeYǗ\;/gLj 3ՅWm+q~Wࣜźo-ԧ_r0={ȯ$J&q") EEjfh (ZUQ:h /Cm CHʟ_[Ip&cZ]^оC:f e+=ǶdC#WbL`njAC}1# =Ef筩(\}n{N|s3Ws(R <) u?0FR|WCPw5^['dTTsS fjW"`I9B0f(\9A%H7 ԧ;§ƭ>a/I=Ң|Xp_|8 )|H/."Oa#]iluMُE P^ecV$D{ѭ=8OJv2 `@[u|MSv'zg#0#`dʙ11:2 3N6`eY ӫ^lvZ&f236nqN]᣼BxWŢU%o s% {66vnlՖ#qK <|z*Nu3V~hƁGe ?' (f-\mnn<靔h=.-3 9[SԫugJ0 V éV홢O7O{^Nf2T>%1yٱ? j#wRo77E2(ҏqFJFئH0/ljp:YmoȲ˽Ev3O}6ʇ)hRrЌU6ey~W)]-b(h{! v9Kr]?LP>0 jC2is)mگcSb'<7BػDcc81QVvENl$7;jz?l Zwqst E'l'r}t66Qz^Q/>p/E֒=k؏1A%k36- 4Y'\"Py?0if:Uc_0Ս]fEp,UiرIJZ?V['0 M2t0LC:OO<=ڧ_#MEdH! ؄.Vo*/λ%32wi1dN&Y Ɯ4ȹ V|4VE<g{$:2_Y_R|& Epq@W[Uc%llyX 0uNamX  <RvT+0/# s;§{3^E1M4o3ۥ|*fTz Z'Uvq;+2ZGQZb[`] \NdUC[;y鳚cdwH;ãMt36GyWُ-٦q:ΣB9WERpN/~% 2E)<9bSZΘh˛BoSzo:r6p2~ M2M/2w2AeQbzgΕ[Bd'\߱yv\]i6?O߶# #;6dVx3'Iq,>IJEͩY2t8 :)G ;$}`BDHu*Uum4hqĺ#S8:a= j$85{47a:AxQe1hz}uHZKvl@AZSm|׍ ℯS۔9*5~J'u~8bX[7x=ڟYi"c3rh2([ ^XN4!wjm;Ly9^Ґ.^]qS- f#/rg%^j$p~y ᳃ %;[h-s4OAa7''tG6c]߀B oH(?ӔO@{yN8y0EdoSk۷2*H~m|G8hh|d^Ug33W֖'|~4gԋK0Q9#O{#r¤$T٬;P%FGǒ"-Yjݓ^aL0.Vk ,7 (}a@ m.@Ne{8~og4%LX<, S'9 $4V& )tZ *~AU[- rKY%én2ܭm#p3ϏtX,IIW1Y;,GU0:"ߴ1y,8KA/Ź54qf~$GCfɊ@QZռi׬Z~#"f&qs0s I_˂EK6x3Pu5' XS!Eֈ#4'mdX n0EŖCBܪxv5eo[}3GՋjNj)a 1*ٕb{)gXT|84`'wfmCazռSjp&=ƌꙘ,NsLc__~4ɦh|BG<>:U~W kI&b>w̛ZVO|Ӫl&nm8M {[z,ҊrO9FԖ!dac.D;b|kq>0/X36~tm}|¡cP Xag49y4Z E w1?lj&(zt1[ qL$#!@;k Ga<ٟT-jz%΂f> [&9$lO% U4ۖ̑D hB$wы"^/4"jZn!{3?SQtgVy7!mܗ-Cc9h3&x|6Zf]6Qdh-u6~]gRSt2g\rWGڨk3{U?3?Uİk 11ORy1è]@" ?TfP鲘5}~yl{TT.FERt8J0HMUH?-"2~|'jX|4.R^ӧt +24b[~1pjYQ=)aҤf|5 + lޢ(mtjnQIXZP LaqBaIͻKi .]XξUP7o@Q (8>E]ͷZSJ9" Yᵔ*RJcr|W1H:oxMX.8oUI7ߠpèV{ tmCh3عڷƝL6FGBJ-pYVISd7 Hk$cir_P$ eM54u?Osr*2Р-?nnpYx49!kbx`^l3aԹ{3&'FԬ͑/h*L*MܢUƖC;DjR6Փ`Ă+FKdhou߽3&%yhr^FřƜ%b]'K0'㥵Q͚XӺD8ޯU8நns5p8jJ߳v4 q*8U 6&R`u' s*WxHc::",;eS]7enjD!D-(l٪Qw 6`uÈN}8MD=6׀ӴEpvg43X#1/fѝ^gű C pa?,03\,2^27RUZ4Qtn5Dp _: db_x2}ӌ"cфV.]eʄuRa#cHaV@mv |{U[)kɸ)zŷ9'k;7R͗Z]"%9fm.W-A¾HZ΍-ޣkǷbV3 +:c%Ya\)Dc}eH@M2G^fS l`ro+a#2A0U Z2MX;U O 6CHPoGVk!g7ܠo!|Йٙ(oQS-9e ^{D M8–nBu`\[4c$>Q6 @[&إMůaC\j |> ,o:L6 cgtlWVRn1{@z,[$[6j@i b8ǻL"ҵv$aR(Q%npEj3NX@IDATb`1EIvR87`eNp@ Nv543 @"֘_?npQlQk4~k3 3i:2r$4cΧ8A(`(Տ{ڄ?Xb/f&`؞7ĴNj㘨J//U.B<}ɬiGL!aWD,#YcXE)<7k|XubZontľg9;nuEbV:! :>i,Ԭ.s(P* *pӲofoNc̚<[k@l[Ͱfo87CL*tT=0Y f Z.֒h31ۤ|goNd̜jhQN_[-QN5\sVdTկ;g5$a\ӣ?!|EIP‘XӃ[i%`NfZ$l5>Qa<ʬ,kגigMՠ|X ׆=6o%.:x#tϦBӷ.: /64S&.?Ms N1et{\@+< bnO5]sw8 []/>'-]^Lb̶.e1bz ԮuʴM#X֤lzURu\x|H洏c* MfLo*RsQus={Y2֌ e%8E@ h"NSyPK(YUqӡr%C!J0jPߠx޿kn#KIA^F)f4&b$&}a!YHRqg9U|ˁ[;\(H=T" D= Ϧ;}'23 ##@,4׺ȋħ( ?h_kuȖx$?%ړRvJ 7Ō:z1vDFy(t K5gVvQwdɶh0lO6xKyl31?c?fLzJ0c:AGԅr$gop ;՜,)Qmf4AG^+˂s[fFqt:c08k`2UsNdd7[ׄ>SZefS}4k m6wYl\$g zŤ mֈV鲵QzIh . 6ynnP/[b7:'2 -'~3Dc!,n0R[_U:hY!ȲU#H :ZTۭ1-sTz> ᫇~Iȁ6]VpU##N[(}pST%~I3Yϯ% ɈBYdY H7 Ɵ5˚IbP@lh eg][걻3|>#yhБ{CdaN2 J.EhNb۰6r]_)w3j=Cp-3t|8Iix>L:88.ҘH1"v1H)b{/i.2 *aeSj.y봧V)ٟ@"yK"K8*+*\U*}VOk椉G.>c|ejs2HhLK]flCVY}Ucb@#>iM$-ƐsZHr4:ߒ?d ⻷;XyMVX/"~HW[k}\+m^.f2Nl;{6S#JgɜKa.e)!*L&*vG[$Nـ* լ!D@2ɩ:HQ N§S#p3ov&s/a9ٜ+>7mlVL{6!MlU)eަf*?' ͙ض[mUJZ&~5L` 0Z[~?{%&[Y#s/. &{6K~|=tDǔ8يN]hlZ'2SM,**28[TXo y8"Ҙf"E}~u^hD Σ?t'8[_W9"e.jdb8̪QkʘEukmڥF#M<`M^X!R`Y*R%[.C?6  H+QHh=1& ] [ɜhū\Yop˧N]e)Y(tl46/ ذGxeϹGU`狃wLV ce00=0!8CjasGg#&G@.Rǁ5KAA`a|XD'|B*d&HFYL8U$Qmg=l&bZ{~· f̺Ӛ9rpsD Q7!Qo@kl-| H0z|b7 /<@*q+韖q6Qd#G:& ^v#0< +zF, &?"jSmK)}d3&Kܦ~m$}\ˈ sk2-PO-ʖ,D6tӓ%@"pib}8F㌷.46u#%++ܧ1寉Zb*|*Rc~ q|a{̞ C]) #8}0u %nE }'dp*z\[Lf2!fn`q'36 Ue|g#樊GQ`#&{N:<6{n6P?Ae1nnp})uEMV,l+َeVN>VDfB6W;`[(qy<[7Fdt!4·sN;-NGӴ-哝t{p@6#3<&2+i&vwَ%U$^QI0@%@W"<:%0Яگ%_[ì/??B#d$~6[L="(&0?۷8B8$E^6RU]3α)_;c1^5gFv5__^vի۫J(155.0r" U='PwEe$`Y8Ii9$C5K،]T-RGO-+%ii;)r;Gq,*_2rcbt9ާߪ8f]^~AyŘiAm/tEiRts#2yC7icģ BG#,%[$Br}î2IQtd[g-jv%70Rj?-*V ȭ(us5~| w:= x3%+grJ l~꧎Y+OaN0ۀnc,]+ͲtZ]z0&^^"QNT˱aw~@ޙ Z31(4(33䠵К9y&c~Al{LZǒZ#?o5BfK4ѐ6u6Uk3n;j)_إv+Ύ]^[Dgf5vDYǬ$o j$;S8r:Ї҆n x<ؒg ܸ܁-Y=*<נ]ۋ'3znn8&x2m62'ءF=qkL q -a_dMTN77ZD#H*PxqwjKШ1~v#lk'&0's&>YF=H6Ҷf;9fF#1Up4=ڪ;[䱍/O3-R- ]h1#p3r$-%K^wMkz[T"FnZ;W[- i=*ogFi%8sd$C'X"S7=WlP­ae!Z'>˕Zk~Z%`WZu?A@ssa^$ipɋC7-u<|yt5bYӇP[S~GWX읯[MWjHz'<_^l7m<_B)=lk ><oȎ% 'Nn:! C،[ u"zq()VvV\%9Fn{e%szacxmwW$bs@N'Uh=*4OfYumN{Y5F$~-WJk.ֲ#D iB3f$LFFŘoUXf>ЭGq_N?`[J4x2DEMWSZ$pM'e1'jcRʒ58kO* 4 t޿uڍ>Fm)0j$޶vL~̀dLµP,-L=Rw,iEW$mg%SB]V"g9t L}@ne)܍K=ܜr6!!)+vQb$H uVcnfҶK,?N<Ԕ[,9T=sahze^J5ajnMa߷/_Ӽ=՜璂mO[鿤bX^7]'I:k9 ].SːYC_#";WKHQ;Kژ6\[ٰr.c}w7f7l|gsZP:A[wUS9@쮞]ztCY?huWNO\FFԈ 8[B{lNӘ!9Z+ze!)(1{j3l^dƤmYW#d1,"p0ęQlx`d"CJ@p?r#K`YwW_՟ 1Ap($`ۦ8a_> S Qۄ&d7kM(aW-6Q=aYJs[H|t̺̃b։5`\դe)^B2 ^$Th7fj휚t %JvpS:[빟_Uʻ-T=tEE-;xEREGa.8 ]s(-^3oܙKMX)ǺHκwA!v ynHfxf==|5__ [r%eU_&~.oyǻ- ӶC3Fi A>WEU=6 :NfG"wvz0ivԳr*|S+Uk7ܼw^d& 48y|v:.5>+ jNxjyRRt MW>f%d]n25}v0v)7ObrSS$-&Gw:W"V1 qe:8Ou~O֊sc˱d͙QSDr7:ݩ^%:]~(0{B0aj/\R3N!:g~7~㴩`r4.* ,\d+q aHaT,a۬$ B"lA>jF)F"oi=19 9>[ՁaZ8Vh Z[z5R`o:1bd%%L&:` Nqא*}z|Pgg&:1ܯ Li?J9Mۋo `L@36c fO4 8E(;ɉ<8]2]d9ɐXyЎ+zQ Pn12ʌcL1H_p}qGF¾iAZNUƳ,gUe{]=>88:w^ eӞvW8۸OOvZʄ眆Z[-عجp4 {oyubZ*kz8-L vuF>KK֒rO {;kbfH`Vu2̳$"T moCV@8T 9@S"X{poc:WK\lu6C0hxvz)7DQ }3Y Jƴ.kPP^$G҃YF:ƫAߋ2OM dLBaSR!ݕrw.?fX {iL/L'v9e|Q)a:#(ރEtؗ\bۙO.cZ^WV3:"fo&Όr7&Uƌ k|P'y,B_OHB6Vdժ6tg]J-3PWZ0nh&Ze'SL$zdAFa'(ISd-fg⶞S Ng Z]1R`o MY R1;7t.10NsF>T`HwG)&c! 0*Ueoo Xq$q.I⿾eo=tdŞ*hq;MStˇD2dwXvojC}1 s>[7M{C1x _eӳ3#S. pIo >1iQK̈́f a[.KbyEՃ/ԩ FݻƢhJi >BAg9tMT2˸+[%,]s;)Ou x ȩ ڵ؂|*aG2t+t\+{<}GK^O=R Fam7P:рNg|@5>=_GE!'JƍR%r˦2Ԥ8NXOR#x?/i]3k{Zma 7, mzIG=^l)S^ 벿Z{[HS!*d¤iT9;y(ZWc`씶gp&)D3UZ{nW3c$y#Vv~(S6Wշ v6c0*K%5p"6`Is]Ss`cH'`3WƼy9A6&S K_dj|/q}\4~ ښlO86 m6i9KJxp E{Q{-[. уODb|TW+¦@8+vS#̙ ~8TrBv4Six'*fY{ƶ9۔]&,8}b|$2Wq$D[.F<ø۲=!q8O۷禙H|^sk6N Wd9KK{ea- \}a("gZzΰ+$gBPOUZ ̓%r_lvgj/zы|YV݊d Ϭjʍ,U.6l\99P*Yֈ/vwa]d  2Cv~찟94/GJa0ō"jwYmn)4!gmk^vX߀C"i6Cj v\"g]qs@n}Zf] 4CH& Zr֦rV~'oAD ݋rOAL^=~ZrZܮo4&i{*lE.:` uQ`ohSÐa!lD.QL^do`T9 Nu+c]LR R~=CrIo 0g$kwޮnM+)NNEyt.-;RkM0xrɃOY3[&p/Ō玑JV#dXa[iFq{znkծ+XqZ˅oWU~~P0+7J~6ukp\ѷֳHpd~AՃa=`hN {78݅S L<',t*㲌M96mfkiK*7$8Z"=8pU1ymTaZ;%H\}e B{C†.\ >XN^$v0QMClԯIՁ?aclw؇?1H^`e-!Ŧ_ hC9}~DK!ZґAQ٩Kupڹ"w+큳v";}]ԟD,jP84,JN`c[|>Oi2e6w7jZWJjֽ/ba5a1!]r5/<Pl V0)kyKuZ>RӧLH>" ?ull8~;pD@T"!*'A [ 3IpM껥g+vUi{* e>.>|`'+eB/=#uiY!oUeK ![.~e֚):ڙuEүKpҚt¦P`f ls:i) AAKiF7H00)X}ZrQg,>yAq ĥY @ecmf$-zXޏ7`)$2k&s_?RZaBWeЯPJ:RN"qTWji_MS 0+iQP͘DN>+[VjQ$߱Plm.y$娷\4 qL=n7g3TW8T 2UÀZ"l\~HS:46 . Z;ji>*v>NЁȗ-&5 s;8@`& W8 -`$ƘD&A(Ggdt0ؘ֓ʄE"h 'uNC L ezJe{5#geFL,u[)R`}Lll>AONcV*`Sbexdζ2+~V1"uum(Kd ؾo;vݺ e=my6 Cɟ<4`?[פ0RM|?uUm*ͺKh4ؠK?(ONϐMl V^is^wѯf+4Sx9tB>b(*[SPi,(I:p1 KcB^S-|hy9BYsl DbiLAdmJQB?"]-uO ,mpȵ g)3/mg֞ J)*)#wxMAGgNl7[%87듸x!H?\9| ]Jz{Cx/س2Qnb6Mn>d8jogr13Nn?D<"||évJ%7%v !̉{3״"̆Ц D۫gs!W5y`F8;av?}hM6H"Θ6{MZ$OBKdobk҆!wIT-!S׼5!rlÝ\w|0wr |d0"u|e= u϶Ywۍ:Aڟ6Xk8vZPzECg}k% 5MEI._ !) kzJK<~Z` H^+nM-"0Wg5}#KT@.U ,>?5sO]s 69 bU& !phCXNܕIV8䶗?x\z'f4lA.qའ20ܮ5`쌴vި李GhZا/5LtN:dݚ]K!.Yـr۸53=Ep9Z[4  4@Y+8QT$djgm,AF,N5$+Klۃ 48 Tk `cDezKbr,I)9D_\{",˧D 5ޛnZ'-/0SE uR{F3+F;R'vyS 4ܦMH> a7{enmǒd.yj{QvέC*TaCEDm؉$LĊ|.ifS`S`XJ -Vl $.92)OL6 RWY [kR+Uvyז2J!U\Yh}Z,zpYs*Vw)y Ե 1"(h*EuR3IuaZ \a@l=mU@[`pq Yr a*y4def,ѳ门y;Mq̐%4X 巤';UEڠ2g !i9Ìhբ˙gwaS`S*H]S-}N?سe[Hc`qK,Qԗh55rg>{ 9[ W yͩrOk.`6Ia`[@.P  9؜U)du̱c&Xu fP.J]+}wA|Yq/HWG\R;nI-oR^dc߇br'ZJqP=[Ɋ5?8%hI Ơ^}̛_xήYlĽo︿5R`~=faӔ%4$iD&#A;NbcuN?"EJ `Xcڧ8^j ;ϭ:T b]:X4~9bO*Kyg>s(p9SL^Qh2@ez)K~݆:xg2z]YdY$n𔪻*XMsrm`/sy@D@\4!&:_tégi f#FQN!X4:]k&L].ے7m-c2y!|{|X8aVI{o)dXZ<ːRemG;xԃ4e<*IipyFAS:ʹKV0C^+KYD.Өj6FP?Gi'.jwaS`S@1r B,&G(5tb0#4 &iAD2sBak=-RǑͧ5dMFnQ%qy7H"xۚl~`'Hj XN'8Ztr05Z }$fm=ibAef @d}^'yKkNs&>T9y4$VL.5xRt(|58~Cz<H hoY __:¦SEHXߤX #Lfcp6kߌ-+ߚ`f2L x-9YA˲4H:fsa2fsS`S`p|JH@ BjO d;ƀ)˃ǹjr*'xLi9]YuLh5`2L0!@<Z-]:@hy2ϻsW=.t s^0{^r+u*.k_X#qE!D$3]0cYNz}.h sXY\(1A}?Q Ihp*O9~I5MpF?캆SnwY܏lIYT\l`2&bLLeHcӷOyH0@C{Q=^sInjG5bhoHR$ai w@ ŰaW* Pd֞3X%E, 2߄Fуķ̊ƟLE N+RiT Np&W3 p}KOíTAJRMa=x4D=4__}wg``Xאt^&a9+H$X{CxSC 5t0K22p^ -DT8xFE4MoNS亨b1,-p,O UNqɅSU?yJI] ''1ILf#L?b>q5E؉/u9 Ύjs(>0-rez+F]zWz\wx.o l †qd۫YI)8Iޚr@˂w٫8l&whxِb~zի,nO.rrW} pϚ~Kp s<7 pޛSb湩 Lv x d>A\4VS뒉nݲ}q&3 BA^3B}lr`7e@vm6rk:؉j3[.v+>ƅZQŨ-W$#>Ō~_|S}͔b ̞0tCHaR*IPLg;_(Z`x(sxE }ڧ}d1 Ջ D5gm˛P &j6pvMV KmB0'fKhsp3F[7W@/<g\igûY <93lXK{^"mxG:Gzq%K x\IU:Vi-mbly.syk-%klI .Jeq\ ;~۟E]陪>EelDuhR5UQB f"$ )~[JJӟJ] uͮlA8pN]w@;0`ynPV@lЇ>R2<09B)7WU[$D P G*b%DiHI_M 5COVƕ=+Ҙ~'~B?5I)XjwM+SN,|]l%KJ LH.%Zf'j2zD}OOט³-%HJUy`k._ dN>gl l R Ƥt=ihx2v+8Y.jVevt-#Iv8BnYƑrj.龻)pu 4! ꂠ!=O(XÓ_ +ނUSTb t[m]p0t{ܧqZ(tBe(5όbdPK B4" N /<۬/PH-O{[o|}ta=?z|:|іQ|ķ9t mٯ+7'$qsnf#'IU2YrAOH}6.}fޒh0!m[?;ɾ8P/Re!·ePq$N:[6?Ij)(Ʃs$x3;LCu.cNd˗ER~rO]shN ԥ-uv,4=((F T:z5-IRJ-? cU0sTڽ]N!>Oگb.`%##xK oUݢ=fS(쪀OoOaDj'U%>l_MF]{؏m \' YZ{MMXG eLaH"n# =OO^: 4yp<7J$cA0]#:{NwvMhdY,_m߅MA il?@7$M`,4o536AG0rb!#8:!a qTST}^N!>O|%a@aD.%ޝt&bɇ|Pc@4ZT&ӿ80cZl:hlX:*}0)D@>uZ'7@SefCgA+"dA()i&&IʘK@dIK=Y)b))p@7OY KE}a:N'y”*˟sڔHc,%G}߻|Zj,8^$p$zEؼq6 437&LWe PcS {iHE݀U kۈwPD̀a|d sٟ{Cx Ff95-$fyCѢ yf%b'+Cʊ`-`׾w|w֧ؒ4=ڌA46':ߟHKTۿU>'x黝XMB-BD:N`?yԘ5Ӿe\s.o f O_W(8A0SnQIP'_SY@ԀI$3\vo~8h-2I:+̤K.l \;"epN=獙?5AĆ4h>[b17mtՀDnNJ8mJa-cm3`o.ŷue;3ws?rePG'䤵Û->+65;MD?Zs:` +PL!堊 U`8-1Au84Q< =`&]P#5~k˿2.@ɲt'91Op~waS`S`<<*/HO~63M5^ ˆIڊ`|^V,H:l"i NGn6]A9%u$@`>29O3̖$BaV(tH%8j4ډ;"z*2Qoodӳ=ÍcU|jȮ 57qܨgKXʌ*Y)9U3VpTK \k#*SG2y I1Gpҿ`I07A-9ӭv^$ETvAev< +/rKfh vsI4PPH6¨OV<$-2̆KuT)p?(тq*LcKbn5 &6p8AWx vIi Bs|e{ѸR`|f )7~c AtҌk(NuYQ6$dx`t0:Q;TTdp4.ێs $Y`}7}9%e[S۟$6xp4~j_WsB}"t5Li-X%E#aK;¦ ||g3O1l|Qm&1flOӜN"pI=xNO* [z jyt7D+7A,h¦}@`[.8v`)]2U+ gNpoP U_Aٺ. Vצdjj烧oš+nj}w)K}sIGMęf@p;= Ovj}`yu2c=Mg ~\įcc/R,*OXO[ggb"M|˷h32ySJ$CZ V ŋ_UJjIy<\ܛB|Z1H l3xN=rMbXO\ٱ.A͔"Xag< $ja`w#-FFxTN3=(ђ(6L9L"x)"g4Q촞]jeķĖxe.1!Mg90ƳV'oS~S'JQ楙 }Cm)e4LrP{Q{9y_KtJ9xMwy^'21t[ :'-_a vSKf6ep.yj|Pm2٭MmzRIt<D>LV\ t1iOĀzl'?s7 J/ÚO` "(8pjcqFu&M7fߗ2. wj [UKM~i ^?uvW'3!9i7j֓l`Td^G *`%=) Hm^1IeF]:?S?//vINMLN&V_^-+}q}P3ax{giS,j/c˦2}n#bcuڃ5YD Rγ +2Ä́ hPl&Rt7 롧~i>D&`Lxo3s`YEZ;qTz;DŽGƾRUl#уGW Si`Sb ̞0e4())97aK:g/%};@ 즎l O^B"M RRz~)." Yz}ݰ.DΠDݏ1ʽhu(ydf%.nwـts4؅M[KI'.gI5r8^-+.P MHU-SO }݂@vS~ǐ΋8m84ΚQxbpSx318ȍ4B@*i)/$)J9Y+n ER0nX*ԛ"~/ }Y pIV~2r&HGv33@.1rd2mSԈ hDm.Iܭq >N=_B3E@b .|ƛ4xJwGDزrv ;nj,msSS`iyr4XTЇ>d s#eNJͲX(te kےꃻ@J`.c|$G?o{[( ɯk.h%@ɈV?Gf6+n!&J# 1蓣}{I5I1|M{/x~ŦU(0f=2fՀr?1l`FD%M~dKǗnM*z׹5;e։ k]P@08) 5ʢqVC7[׿q}:bedpG0~]&ڔt˺R'%^rx]l iMZٴT.~5X}vR!^չw @Ŕ{1NS>Mk2 ~}6^P{ژ@O9O2 j_pgj#Y0w[?>3'k7sN@T>˛g , ,Fe1NHb߁y{:X{,Es-9}'>Hӓm})PF&A;0Bnef~\k8bԝM.ɨh-/S@w[`[7 $?%cC98}n2_r>Ncg/X;+gJnwF8L˵`-piQ wt8' U`([蒧Ya f6ͫ?W}vJ̌gܐAifS9he&?a}]2luV)/w3L'8۾\6(m/e ̑Sxvr7x )0d_b%el}?^PQ;L$RSKcQ`N62^_ ;;*%-` p/Bv%ֹsE}sy׻k&szXw'/z׾V)_DKBye$; UOJɪ<׼5IFnRr8yF'۞u(EBGAv<6VʩمM˛y~~*tn TILpų%ݪki#хW:Ը~J;A>LQ9'OKGy>])XRqn{ؤ\2NP>c(L.4=_G^(P Kl#yezl#(Q ҡ1TNvSo[2q ++;lX xG;@ur= sk=`-pq͗8HVt0AS>_& .<)dAY}9'$c~䁆<ˈ!}eo:. CeBUgβ2qhxIGw{)pL2plb x4,j :"}&e kyPPDid3Bzoo@~CTF`S=[אh0fF3_ Iگډï= \77z-s6M@.C^xK_є&c`V&gPQZrKKXW6q'3KQrm CZQr24/x&ex&(Bɞ HS=>`Ch8T^ћ 5"u,hys-Ս)nAҞ_9>/x$)`4ӌ` [㹅a)`F.?p'~՝n}f{ENYY/ZX.l <$& ހ:#)6$Κ[x5; ZTq t]QlW?o{C~6 oxCoӚ#bf?}s+=:c+e_ej.ũ]uiǧY8+ҐVF4.̓~Ӧ]R+sRJM!6qMy zuwzPn A`*!׼_*6 }2HOs?s k︳#OɌy>=W_gX?S mR&yKtISc#T=_cF4Ht<_Sut +> ә/k^4Pԃ%QkAM~0νYo7KOC9*׋qQ6E91Y`?HzDZ3F?ieU\f)#e8~©tOc<9ؤ1ah恒ilS)pp)P`;'$UÌi@Moq yƨvRr>$_{mo{j$$e['6m dayY R.^a)`:ι˅[H0q -__?A(VBI'bhS|PH.:>{*ڦ AG6% pNЬJдP@`dmߨ~0$f/f%gucMϣN/| c01ww/QI^݉wj_Gȍǩԫpg13ϙv^!Rgh `>[)Wįfڬi(6+mkl:!M^/-)k]x8) Grp]5F,j@%; pƹM&дC/Ogze{/*!z'dNzQ %6*_\̃$dfNU h0n}C2qp)./EmhCۼ)OlЃqzKПNQRc>ć}lLe@2Ljd(@镕iX!4e2ccļt l?ުX GconɽS̏ 7&LLdw DӞeF꒍bVM#yp:L׽uʶR ϳKDSg _ ˟Ӭwvj•RO`w,|7&;:}Ճlnd`ᒷ= +g N&6 ڙ#oSg[H׻r1fFn$/˱M.%=Ky0?,_&|̼A6"V"YIQh_ GqӹuӛJ',"qAD ͵d$,I5ƞ%q |{ޓTD05!-@AtqSI , \y:vhB& XN'xGG2p7)h ׁ2PQ`o78x菎M LEdksb'&85+N(G MOAϒ{=a}nܟK=ϷTr2D ԠwxڌI!WUу¶s5q(s+fr_ww)St2 &{U$1SHzPɖ(׾!5/|*^8OOjFuDjѰtL')HPUz*}@Rk'~cE>Qpkeszz-(~$h{{7B -zֳPe:|e2ܿT!d]7N"YǎQ>[k46;$.1p)(4ST`["֐BqRvRlUY';=Ի&9yjfG8BH__WV/4h0BlP"X ,BroS ᠸJ0UKs< bR|aճ@pTkR%bm˛3!]+~c9w9.)h 5'NSA֨Ī 7r3=o~*Pys\[m8sD/NnO2>u=o΍Q#OT,5bm^ոbWn Cgc'\edA4bP-C|qyG('9p5}|aŸK7n&)mb8g N|#EHG"P [;g/Utҹ\qq8݈V{<{CxsvlWܳH[S{ gXa$k'L x~}ˏP`4$Yet=_)po"e1فB |(o"S`w425ØX[T)|O9{o l̇^VS=;-5OZ(GzR,aфaR^_e_t$-(W\OM<"8@Sz DE-aX2wAPp4AX2kh-6w;.CHR`UK5b=6rz ]$W ~~N&Ҕ%qGdgwTd7~OJyx֝W<=*773K[CM+X'5/i$chȔBB|ptx0e6 iZ')`c |(Ti'0PGc8o@ʯ4v!Q⠬n˂ ]B??ܞr$A C]xx(IP$:iUƩ$ɏڶqJk鄅C֔&5~JW*qJJoM GFy"v˛aЉo\0%Hbz>APM=`5( j To=f:ҴAahE-EbiWc |GEJjZ[GS5 Zw'tJ, 7FMkEpP>Cs?s=}316͜e(%w fM5]&>`tv=wW aIw6o 7EaAD_Mf9$D Lf LWTK^`B{dzݿw%?wӓv E?waSQ@|eC9ͦ~aDA . ZYˑ5xGRʗ \jѳ*> c'n>mHb_6,;Q[5&hW_ hcM_SI< 8sc/V iXC7Xu{[1HmD YIJ0àYw]SR2#{=a= A׻Jxq i_kN^"N$f0&] frR'BRycZbIegF|1ٟV9k]xD)+sSd j91X9N>яjM5S -%O#8Ҍ&)ZILു|߯fwI'SwwsK N1ܝo#~})4%;GB.3(h:. FNkF%s$ ^w5R>E,rg|OF4CڅM R#~f;2jO\&i0mL'Pt̘-x+z#hӠ>]ʔ>HMKi[:Ե.o <ek֪ GW L"`98NOmOf! CR@nAߩ܅{Cxc?G&pz{<)bXW*mѾMiʹoVg knCÂ7jg>oؖ;@yool7 EMu&؏؄h\MHaP /w+ͷʳYHu/x 2@7<;C~}}.o B]sB22q !0g)53O1K]Wc1> ã_ЉW3 g<8!SR  D)=dDR &ഷ zyG1~ӱ9vikkD_׺K2{6jj f#_W?G~!>) gsIu9 :fnjp6 {4 g/pXi )>1T6-9{1WXعMƕwdn$.mT7b]o` wk6 \/@VϮ@$Sh/33`vQΖ0oo2Q90pzr :>?f|#Ob'__)I \hA ţ:;~ܽ ixS~R`&HVwiOLn{ȴ".=l2EC甯g:6Ɗk7`.l ( g"bU⛛@IDATW?5yS_49MQub M`q }-)F \G7 נiccdz:޶q3 7̟2u cTq{H ˶& ^ M#&Ze.TwW4؅{Cxc{D0GGv< uθ`1Wv{ǻ8-~VBkFa4CnqOvBB> d]~Zf)8Q`/z:"W'QN'<`__9H'Nqi:;-c=/`5vt}:pd<..heP|&$hͤ5uU&T TYF \Ʀ7<r5kV'1G ;Lx 6t{7x;gmq928@!8\-`, DN΁ƿu 0OCE!៣lЌO~exx(hP|TzPQ:n<5 '\Nw f6 sC0 um/SAi@*WpK﷽m&O)n6γ2>,z=u?_S܈3G_`ʖ(ﯚQ4.ҴD5]IpL1KbD(OO㳅"}Nks`QlOѫO`6YV8{!V& !($juKw8Jb-`m=N]x)77Z7,p_3<y/U2 VB~u_kSGn}13]x($wOD[+Se"ِO+ ƀ6V&ac|Ǒqț0tˮu??uL4x|MC5FQ1cCΖy{?g`3OL>⸥{F1EMԡ9YIz6ɳyS`0BfD<Ϝ6߻-v1H) k(`@p6yD q"_Y5@Lz2 jb(s UЂUƻR`ooGb(;&:D/qBD Pp_c( Ųo( 2XUG=>:]x(p9\aRYg0N-Ӕ7Mdy7CՃԩy]\ r;{xmkR&¶aZU3IL@);3$$\)`4j>3YPd=}ԘL{Nk/{˴f}cTij.g䋞@aCa4A;0ov@`>zJH e29^-\XP65e}{77;pv}EOIEeljǷrǵM[֞}_B zP7O=MC@808 2iж2\pcK;;s az4 c3ii=d]#$s*d|N_IMŸRO{԰az\FIAWaMG)ִ  }I 4j2)RIfdP L``m4ޅ{Cx F"R`J;#C1o .qļy[+b _BqV~qjldaTs׿WII&pE5;?h.m.{B)66!e9"ⴹzX[t"zӖc秿B;" ƽs6]&-,YCIofٵ>{(@=NY O RYE\@!%os?sur0)0x,֦Oƣ.]N xt)&1,]8 [kV je̓@fࣻG>#)5=Xδ܅{CP4b3YzaEҚX1"CfnMU#MΒQ;CQ :q^ .V$}'񆣱Ufg8^6\ۭ1U#[6x:if(YYZAY*{Wˑ2c5[(Naj؇N9 ي: wyvQчť/~SۛɫD cB3#z}ɔ5zYDz}Ab [!Oi׶7yD]c@q+0;pKhW}{Yʣ]?9C4sU|eݵh8ntzۅ{CP xyR&llzhK~"}YG<:15y"V)PF#nR_lHLs.s&X댊^7G)$2.0k'pR`oߥ|@FmXc< Q>Tz)=5-K0q?hԦ1iyZ[+Ȫ WG@39|YNRbtd]?Riّ0 aX MPBQbrFv ^ rLR|B!WAs-,-Eql[Az]3.l % ]grgYA<ǟE=~hWJ>APp(MbYT$Rܮ#cK->.G˯X.T8Vҕ௵whW WY0چY5~y0_(iN2hUf <6>>8ӫ /'[ rnqS8`a)e}qt_3~'~b\ s֞`!pICDu2v\2I{''tf)??JY|d3~\0j_IaEdo| M!̜MġCdolIx_9;k%q!E/AYDNA/q^Wޡ_?퉚mԠW-oo.)rn % ]~ .imZƀ8kKRo0*Q!׆¸zc6OB=MqRq,ۚxcLkk-KёJe8}im[7,G5:ՃԀ\ֳkYW3 $m\tMIvA> $\HHa  ),*Hr(fvC_')P;)rlߑؓw5(qGvJ7A-=k$NGTc]6C4 o=l^I$3Po-9;.tXsv6$Ұ ׇ_ߔȧVJV x`9lC+W :rUg]x)\?su:p!l^֘,?NoV%?msTq_ӿQ,A&^`=waSnP`-J,,.?sG_Z| v9F„%yJba2gJٵ̪4NxÃq[5%)pUhp< pF|aOd$^2ϛ&w*=z  Rb/<{6?VRkL|w>>Ķ;3#OtxjHh(PP+GTGq^j <]iF{ ou0sMۻ6nQ{Vh\m5cA˓o)-Ys'd}"pV|A+>Q}MoUH|n;@=}9ۧ܀[$R/$gvkQV# qc6u xLF [M;@ [@V{fZb ZkU]Q$1"ٙ\Ay 7 Xj0HX؂n h^dM2恿I}"8%bRW"ľqw '|5 {_E_I;$I?1x8#&A2 #Lz(QJߑXiVA~l)/O!L3L¬L՟[<%ή{H'Ei4*|v宯+ɓaaKS02H ^")CX])߰;pc^c䶮(W(森r0jTh,.RH:  W'5J ,B؟ï"ÉLj{* d2ه_R`K>G}(b*81 Hks3++SaPUAJ '@5ekrs l1z@??n`ՔG9 ?U-8섔T){tjxD9b@Kp3?ᗓϦrL>3]c2][cuMf xvl @h7q@b# F:/mԃ(8:r5픀k?ncD$F*3m=nxТcieFs?suAxXګoi,uD0ٙKG)ȄU%̒!gL e`xйڻq)w&pFEkYViS?+)n!vđO(.53Sr2R:H4`5 ˅i8B[HggB$OD.M^ig'+Q2e/oo]*|Mw3=4ճmq YYgŋ)fPQBUh\!Ng)|D^9{ tyfFgl4<(_*<ϒ(aoqj*qΚl `j5X q俍qKKX' 9xN9S}k(q3JЪS&xdP5}5_< _EQYzl>n׺~UK֎u$hӪnH(谮%\O #€Θhu|A0\ wטo|]+|h~WWD̩)` ͣIf+ɁMC\G,4EN\7m)O\A̍Xeut9DR6L`xt[C#Z_olԖttwG%&C" ڢ:%{k$]Trѝv555([^8x l P!XXX$0n !o̧=l@̏x l{F9 @H[G;!uƣb[ aJT{ Eh'V?/umTҸlJyAֱNr7cZ'8|epAPDX&&of "m8G?:C~'ij <ܔ&!$1ְ)I"T0.oacT[#'6prC3:'I`O>$y)fFV>Nrygײ>!1B?٫ġ>.q֊[n::2eϾW,0oҝBb';^ oQc{5k[ؕfeB9pemA6do,VFuAJrsuYGuS՘d:u.?chdVS?ʯ\g\-㷿>KrԞiֳU[~!r3MJ61Z D%PȮeg5ufAMH0 K#̥#vA@v] ?([\mb]i0XG0\yYBC,dp$#EKN |CJ}>4&_JKtr ^4iu1 TƆzPkAF66D|Ps{I0:s]ˆ7Yn_}D=k|Dz׻ޕbh01|v%گZ}YJk\GkDЄχk=pM;@Pjʭ+ thea_vԭ0O.= Lx+aꍙ!!@7nmˏ?@=#6wkɗ̬X_g< cpz4orjL٢Tvٟk&+g3*T=(:gw*4lX4F\]eZҍ܅\)d$Ȭ@an$̳PT9ltgg#JQ<;?#0FV3Ȅp jDbH(i MxKʇs .tV\Ҿ󹚻3JlKگZe#%FwG2 I%́eoF kzjlY )FZ 2JLAAg}φȢC5sާ(3%M;CLZ@թX,2\:njV uڃ;v8W `ǎH: vǍ[ |ܞS|Lvϳh oݝw?q,vy _BL ФbV(i,aT!Q}Ⱥ')eڗ),[7O" ҁm]_#[@Zila=HX`W}{i9‚H4b@ƫaGE :`Mb9];({lk\E/. ~g$/w '^Lg"|m֙e Is W&:!&/GӨ r郑|D֫DZlgiM2#+{J?--ۘ^rgaT!"#HbWKV] c9)7PF:L[@B, YAZN) |)Ub6x7N^?>q[b.e5ߵ2qS,f,1-0\gK- Y*-E C;8Vx~x*a 5O͘Dx-e F͑'r"Z lM# +HHD!bdl7PJUE?[XI=Vq@^f'LfKQB_@9?#?f^XVg+70Y pݜ5ngcr׬LpcP8OhSO`Y3o%o;e~۝M4bƻ|+(1qh\I) ,-5.$4N/`I/nZ1U;02lL>WĂ0&$.6)p)px->鱥M⮣A`&;=7i]6v-Qp,__XژpQD<tΤ ʥOOc?!ڛԔ,in~Paop+ <IzLY%eM o3E᳣MqSnm疯l\t#c%JMD"=aC(t(pZ2xȊdf~ȓy Bu >i=JH/W8GwHͯM͂7-ٕweś%!n w msX4h*p*4ʲEҁ8DAgXIX:3;wP` 㓂u%hh,&p6~J>ʿ4~(sˆyʚv0`B"g&/7 @T8RiS(pͿ7-֒RjZBRjܸNYAk2,^f ᯻rM_M?PåM[p#ܠtn h\)/6nK;6Zq5[/ ,r%. D|DIiy&G^ CQ ɐg wx0ykdha; 3qu X5+x`>@ (YDT.V F"τÖߧ!n3蔙hVȪ]}@>8YF+O/{V5=*@ǡKe2T Zِ2_/T,{ 8koc$6) ~۷}:Ö-RX/!پrϧ:>Red2Y#Tz\!Ik鵊L50%1Ä48/ʧB5lMߩ,$ ١&!#iuV$EOz4:G7H,R{&;]_o3h]\@U>4gh4wݤFqp a$1Lw7&i0&eODOde݇{CἁUf"}~S'}'PR_7'[_`70U GЪYMo-$Tv րEHnIsǃ*Rwa[cX%kjqf6__n@(@3^^BbPMՓQfW?a|@.sq0倌 ~!=$8P Ӏ\t|[X`&>;8ך 2t!bE"i0U0s z(؅6jC},3]wyQe4ߌ JZ?7SOބA<W#U>Y%RXQ(K_(T/RyOkS@U&,v7R3H›`,'j`caB󙟏t N-CZdqeqq!aRϢ^¶3_z.7ElNd$vknGwW ].d+9|t qh{(̚]뺦db;}FfCk,`51yXI1gM[bBxpݜfk;gƁoNpLЃ,- H24R~up ,dF xVqeV_@Q}֒svrȗm(L[uO'{Z7Yҷ6w5(qb%V~Q+ܿцň<9N)t'!8z K%j*s )p)02aQ^goTD{I`G}]MSDEXvdx9 &;@/Ϋg'V3%ZNse FL~86@2>rrầ,`v@̐ѭATozӛʚw6JЄMoʇ,MUk>DP<:}a/"OFr>^H8:P*uo*HJqb 0YA)+tTz^ìJ,f<0K~m \YΧ 2w|}S [ ||Wi-0`3K 0\%XEj63YK8 >QW8 Ӭ}u@̮,"Hfho%[G7]B`Z;RGwHzYW2/P_Y 1"|8}%8x,yBoomV2W(Rw9{Xzg# <4㵻z3sQocph2q%qdAz)pK)@&,|qMP o:H/ ?~;%K|^0-/u|uv?SkA5NE=SAN/\bz#,<#|6UӅzOfhXS|OnS#尐p&d4پc@xȾx*N;A5ʟjWxsx!&sam%$ +D e2L Y7NXYGq-=c0$2 !V,rY^In,KKiJ!zsAS*"2S@8yX3' @P""ZA Eُ]t,ȥ Y- ^xݦ8tHp̆*KI4 :FLyY!5xOn|M>tm qWgAM `DjrF l~jfm׷]ˆBȾR%ڄ_A}mʟ^PY&9Y.Nr IMBk"Uf(ʧǚ{rx M/ۢ. y#*6[_tk*c XT0v|Ca1y٢r{gfYN% 6@FܐDߝmy`Hz9$m'`#E)rS%,<0U-ǻz<^t7ɇս8<϶rT^-aE&S<e|]"^Kˮ3ȍk Ƃ P LK<[kS?6_Tbw>X5[N),Pw y:F@X?t ȂMyH,Onca++-UW#]%TJ57|7Dl}W4<~7sSry>įW44 fA+94sv`,l#!9a/c+=E;{+dנASo¤z>%\ p$?(W_q4ޟ //C})p(ZJƙo?Rʂk5>)XU0[k,E5Cy|^ ( $TJ`0wvQ` \4 rP~b9; :֪fVij$aʼrR>} ^P~?>Kd\Tq|nR8)>E9'̀~Mm < ._hӘscCTv81ׄ٩~`i]?THˑW]JH.;˳Ay{b -<c2hAa۟ Aq^DY^IZ=( A {O^ǝD}3ű,ZN1<464&-oU-Y".1T,Ja+xŜ‰h\R5&E¦iX=2ѬY(RaC ] B-Y xֺEI뤱K3d/$8URSdK#=>s>gxkICB@ !KKB{0 ^$i/HGfblBzl#*BaDܽ;gD= E¦tCCy$ŸٟQ4όpa!vySNR:0 XXO@T;jֲ:VHu+kXAz0اD Иia r4,Jll@?8.Tf 0 R%k?{q7L5912M9dR*I^׮*s1} w7AᒌPQ d'Xa6l\) a4*'8<5) ^,⚎kr&{ 88fH.N4k)aHb8ҝ5^6 h Lj-1u@4sr0z tiX(g/G> үGAc1t D4/4 N^!C0&z}q\NCoZ`60R-@ZV=-X/`X'! Y5A/@h֦ ϊSկ Edh@ӧ}~pֶ@x r8w\ZiWC9#0>FҲOAz:el]~Bɯ~~/ :F`rBT@{;q`awaSP, N8aZM>,5Vuj٭2}s $[zzC xj$T+ַ#_(s/\=H_W7ڟ=eb߰̄TCSAHYF¹l<;C%Y̍/ hS0<2*n/]C/F :za̅&̈^< $aYG-QáHuxk¦{F|*0\p \ZUQ!׊,@nWSk6mca7B&X jΘz0u& [ 3W2lpFlE8 kO6NA #hj䮘KT1/뻾K FbwLL3.l  SCJQ>̥L,rZUk^ClB[=fkc9 G %o$NU ׽ gAlozT^_`G\]Km{]#zyޓy l7c?<hzyUCbSCt* ]7cj:ٮwCV]-+-p+&ӺƆ> ؘ[ޡ9{jbȉ?,4,pMU3]-xp0?? ڣOЯT (Q:e,\W *c+V ||OGB<P0N4X|e˛pLx(isd,.X';0D I5+lrB ï|+[ԢV׳ĉ[ӋA󓾙;V֍m7 }W}W^zśBzҩYqNF}Ḿjp05?яj>d0 _O-'zHΰP >M/~\T1އ~¦=7 {4,!ŸzX5^W:!]u,õ^>.r,3W+ hJAS3]xpYsSjְU "/P9׭ZK sq(Ā^ C)APe),qa"a=t)xTήrPs]8@sעNS@IDATMZ/' .Y>~Ih> T0 H {z_n߹ĕ[g}rYi~{u_[ ;- d@-HQDNBm [-?`P$gjlz?NP]!Qa$/8KUE9f^Z<=SRM;O(fn>Hdzy$ 9ZGZY,>Tecp˼^r;h"H,X.tzzZ؄3CI=԰ 1 )f9\;aGk˳4'J̟/4S4īs sPm1wŴ\3}TW$1څMM Ҭ p!II%~2MȻ6鋓K[r뵦Lݮ D} _H8J@2IrDMC@qy o# 1UR_ަ‡(Swt/DZԾxᦖt^q*[ߺCj/6[ԻnSi֋ՔU0v(Rs:X?5o]WMk) pX<t)1v:>Dq!b*hp{)[g.Ch`ҝ$fIlJxnڧ-Oǭ FfvI.(x(W_:l029yp9ЯM@ - k)Y~dżwZeԺkj(M{] סf7*B|zv-8|DYV ٤5ķ4#}'~"\5v&˃5$kmWuyӳD_K#ʣxJ+>/yK9($Sƕbܴa^[ie $v/sJaP`(L=A pH4' 8%k JJ~WM4,C g0Xٵt3HfG&۱o||\2FlPp)[+T#Myi[c??~3ܩ~%ϭ~~iPkxaʜKn`ܐx>i mce3ls(Lr6Ȅ."^Ws,:`1+"I V# Y#fm_̜35q mVbɟB\uG1' S~@2pfah0HWA:L>hg@P3H0Rq'J@g [ 5EGgxSx> e\:;#gllSvos8Tu-WԀZTev7WΤf89L6yq6ʠ.qeoSlWĨIXQ0S|k70ŴZ-h\U%iƃR#k۰Yl_x }k#q/'E>XpIRU^2$xnm qL5S vfr7;V#8QY5~g++3^&=0 :&]he0^)*(SE;+ 'dײժwaSS2,&& S?bH zWZ{a9B/5*6< ~$HD,Yh :✴ _35}ڧ}Z/}]F{f{ W>pVB%eaY7.c<|0lqpv@»]a5'N͡Kfܴ8z:W߳.->мR`7 .CeB~\s-jjWs!P욐BYdp<}bZ5{+&˒(tċ礷vQ<\(ߖpe`\& b!x׼f쫶c^IC3`h>s`'+zgj"ɼE/"l 1%3MV0zMI۸Y)p) v xdր"LU0)p@ s^xu iNFZԁ5ak}d}:a]-{p o+7զ1a5,^0!lkr`-;+5|_KC@|\cA*q4 .Z3.l + \mʧ:Ϳ7ƪɉ6:] uH=ِBNB[(!_`*x3@<Vc MXsyr/7grG+qߵ؉atCY v67v!a䙕5A7n \Fys; u=๴y@м9˃f>=3v w$?@!pae%yhz```x%w\: f. ( . RvJ2Y̵*ݠos^'9C]o)_Xvmx2FҞ=RF4E#_(9`pQg:|k_g?30 7a fN7U)ԥmoM5՗ _ ZGƕ3BH u)^ `䏠?A: /ozq1t$bt#\pNe0415gF8~ʧ|pW[k\)Z̓O>) B)A^g.b^h&.m@d]iu.o y @Pɮ7K DE+ B}@fNr~OLT&eu=)PT4]|z^q!l;j2Ys7[Okr 7.)[:JQ|ى /q)nFW4jpPlÊAj¼&sNό 7] 8IGyP9KɚZ.PպRZryTO6fH/a^)biqt5 8\K $g#yO{yaYW*7^aax:2̙7&hM%i%S~u:)Q⁰8߈^3fSP\YW f+(oǡ= ,ŝ֍|in;2,i0n@{?PDNIO(6j)T>k;okPBȉn{Ma{G>n̝>L߾4FulA(D!L9DI/C@.s,//SE7Od HDi{~~ɳH:%à}0OoŁ=g_uV)p(X/LYw4ʫnix[rAU !x=^i{ Ʊce%g+76S4l0a؁"r!o2a} `0֚tpxu]*GoDPk_P4YWx߄[}w[ }/Qk'V nɔ7{Ak^Yzj0Q/ }Rix!041g@/~k&9j#cp~nV.oƙk\k6Fk'i|̀IQr" U(pk_%ZbdeY%FBJ IM.? HLc>4& QD/`lo<Y0Pzn,8\+]k V&fzUc|7@xIHZ{ػ{' ЈTܣY?>22AdĄGPg֞i4I:s 60mIMdLȅoPЪi0l0 hiﻐb]y\ w8P%X!5KQ.nV>Xn=,b;dFpչIj۞̜j3?%s0p:m8/Pl*i2ާ̇a NHB[_u_σ\ϪV>l.o + dBy'1 $c2*0kq(ɦDM)Rhk38 $x846 %Px5s.gCVܑJ}v&QSF`0J>%qTd|>3bT¯38/oz4P89 V+JxE")WO pjV2:;Fߑ0}K; A,K Ӎ\gw[ ϑ:ҥR*Oa1*VdQ 8qָw2; ҤOr!蔨X)2ܭlW2&׆b6Srߴ ڬ9n)p)ʄ, D roTykȗWВO$ס /琲zR|`S(I# \MB`H ہqq8yL.}\2f38;8VI~YCz7X6"T{wK S-PUCLpk|`Sco&9WeΤWRぎMt6F p m{([4YU:Nx4YMxl~|A5 :jtVO))v=w$bN? -јs}a:>+MXV@I?3WV>=M Lqjp \hE[SW ~(o!gT|ʻё;%?@^d*mo[˛#fۗX5A 71y2%H+P{B2 вq$.kReƒo Sf[C_^QlZi+}D/_g+>оЅ ѐrG<P.MP lHq]J M{B(ZiTZ2 M @8lVr.@;c0`6) t,0X." HYH5/HxoFۅA-(M~闺Ejchz&i4/K *h98_[Y"SF$lh 8 X4H 7N)Ev6|vySP`dBKw]qtbM&wԧנ]L 9C!Gm⃐ð(B~xa)b;no>8|^SDo"GG\_w`q vTƹ+yqEPQǹ².l F 㳬ZxQsK g9+2LY/| uiR㦐B $(Y=ՖM ^WxrG'._}DL>F8x N됒`0|A|;wRѤOS0QClO<ݦ8>pC *-dl{fAZRO]WAƞ8u 𔁽aB,/rN.@&Հj\gw[ ̒Fl{wZ~WSxDrWРIh0nŰb<|+^\ ‚SCUbR.Ͱ!/3"&}hdWP57RvaS>P@/:C#7SAi $0[<픘OH![$tv<i˳5D%0vУ~RGC?~GTFyY&g9TcDlE:\m.=r `ow,l3c{K#`@@%j`g7@.`e},|G(u qVʇj`c2Tvia |&ܤ"α@3;@-⇘ض,گUG;ŅUEFwRVMH.rR 'ad\b:TfΎD{K^/IFy2art7tŨNd+-ɧU?+Z-(VUoxָ2kuIaUԸzWjGmzR.rzyDe]&M8k GP+5Yx`!8__4yƍC7DKw9@YE,%e bN*ơۏ_A@}|SQ.謁ZQ +?_̼_*{~%q,X*&VyD-ii-zz.̗~闪kD/00; 6 3da4Zn~MC<╶Qa }F'eHv~',4U|&Gzﻼ)p(pXo)QBL,L| ZD| $LC؅$[vq:8|Ӗa2elsv*W {|xgWd^v:r%Cj=ws8͘;[v&7`\tc(Q$pWQod$=~wE+Fj`l85F^EvN|)5*.:=420>r@x|?mUmP/#[~!vU[9D?`gB6?%7%rʱM>T:cдq,Ͱxgg)p)ppE2|F*- N QXDg,!% ZS?SlS1js>kcNSO Q4#K_Ls!YE<9u].L "#ÛhB㜽,'s [N1< uպ*~SnS\\eyx5}? eOJ5ӗꁤ 6* eդ +檜}} @ @FG40cUFSi=[)n.%>*Sxֳ=(.Qm(}Ü]c-~mh~}]ts:w(\~2M"S?kʊU6F|M'xXÕB DH2jQDWk2jhU=Ca^z7N;K- WU%LD.p%$ w95 (A+mLOp%dZpB\.׏zR[~/'<Q [{kuՆ0mSx y#ג c}gc!oZ~Q9fÅ 4ޅMF0s=B -2o4 =O5mn-Hd<*}I}^ z`iA VtjlpN@> AD\]#Հdp8ooݸ-(T%>Oݡ%2T#1`|#/ױ?oUGtJ3\}\ *8wz? NM׾1L[J'ˆ٧G|]ym9Hk6@, R~ J5LlnIMӀmY qhtS@2~y^*h؁@|F`!>r1 C`n 88?=-'4 dK"UlEqPoD oU(ۿG8)ޒоKd%(V,͖WLcL/eF3C cFq3Stku2)p)pxJn%GdeNi, &ĤcԀ>rH! %cmD;?; da?c0Sⱬ2 65Lp`g1kz épp>#)P4>B\}*fTi tNp%:A<`f`,X3=hͰ-g`LJTK鸺vƲnFGRAS@xNAjXSlC"e9 -i009NF,)C}I3rb Yyw?څxH$ h-&j[`\}6V@O 0XhSԗ`]1X''뫤EC"yؐB__JfG>򶷽6=~S5#X=Hז[6H\ӣK@͂t_e_vp8\妠CˇY$oM%ܾG3BR&_/kwSEbV ]" 03XI+mܟsK+=A7&=!뫍9 ބƑ,P0`(Nu^:5ݣo3E,Yأemۿ P͐U㨾_U_唍WIMdV oA?2]hU-QxJ,p=z2c]v Wm]uP<ě ZdBE$HN:HG~y+6?BWI3AATk2is[[G]) .t| y[zh=p*8{-~~qghpZyQ"{{t޳T^5^oi{B@"aikTc!F9uD)В!q"1:UzJ0 XQ}jSޯ9ziU3*Wȁs*x`^e~}g~g||{Lc`ڿw[ O6nςad?C?D?mg ț׼*C1i)DcCL_Z1AhIeFk&+Ө/v.J5`+ 6`mZw|;ޱNl7F& *#pd M) ]Rȝ; oa\__kkg"& ^]]}Du=e8Ջ`RK DDns48N xE??|i|] JX ^5*[<%쮹o!RRqK''QJ IwfSFmr|u}i+<V l0DV䗥?Ф3O12BaBmRp2Rh :BqJe԰f\X&. )^h=; 82ZC3ݗ\3.l C LhQ7 /^FR[,T k@@oym8դ#:!6vEyDg+AD%2KLl_P˿C([dŐug%>w15q4dQkg 1A.IR5.@8 Ab+wmtP:(;Zr\Vz&l9W5fA̺;L-ޅKiN7W[ .:qdCEr@Ė8pI)V/*T#KF- m$7 xcZ=N7^XRiV=d dڼ׆~[iMaj=*]x6Lh%2YJ-Y8VbdUO8l1ɇ(s1Q3j@Ub͜ lJRZOn39msf8A} x,moY'#06,j܏p^{Fk|.z~ ^r:01YZ2xt+@֝L/{1I% %H`ҬD)CmhjL%:6m\ңz|`]chIwp)]̶&x[7`( -~k[ X6C7j,K*jE` & ur@G.ryǤf¸-(xO˒jHsʵM 9Lxn a ۂ%lw󝙪?bہ H>S>Vpk' % et8ӆA-pSNJ@6I̠f͠j!CFRf:IcI=@z0,L7 C:==@߂*݋;U?M)կvÔ]vlSO åI?MTD:;??^ GbdrN]#ej'LD"U^f-?>ϯᒏ mT3\Caubա pA}Ubͣ/¦GVj6'8991@. 3.J$&@$OkݕAA z:i_\T)OGfel6춶']3´1r~~nNIWX=\kn`ȅJ2$Iz=&ጼ Bj H8lt J5%?m0䏽n38A4 F@&)e}7Q_K04@jLsp>xOVܘVVu8 QO?9 ]Ue@ONRA*q;dv8,v]$ l}JQ\'JQBrx>CMf)p(0Y_rZ5AnE+3yް\vuiGc<4 7}ߝ܉#zP՟ U0ZZG;={4K?Mv<{﹬ʲ(=VLxXW*fSSHaUBe#!/HfS%q'-mPg%# K29Nꁨrq7.צAX(0vH c ov&Pl!R=0-:>i*)Dsh\:cxj}4ƛJهV 3Z6'$e&p+>5$@m㢖B1.JeK? NؒQ1+@NMn(~fZ)8XXwnS` wS-pFe<ݝl!B4_WzqLcM`[]k}m:["O69鸼^ɢ_~6ڰtrFl3ÎJLtS\FvySPTcA9V5Jq+~~,$&56b?\2%"qKהyH`` uelN6oHFy.䢫s5S r$Wb8dZW\ә3x-L)p(%c^ eHX2t!AD MA[sJpÂL7f.֠ϺG4 pEwUB*_6\wl#ϩ]zz]Y4P{/&?1.ye(3r)88W@ ]G"./d6+ Şp<*|P&ܩ^8upix=mn y  XL뀂|gi"J FU-F'd]u~Mg#=TH<:}7]B=df$^t^VR.t?: <4Ue%OzX/(mæu;}0< >35! ЂXG1Y=6 FGP'֊ݩ@j`I= ZA l6u}l!cD|[2S*bHǩم;O-ީGx 0Db=+190;G8;#O!j8v5y^[Ӳ "1a$BV\TtS}1fjd-Cǐ3w墦0n z-ۇHb G|HV.o3k )}J@0/FT;MW{̡fa E ]*q\wmOV7'G @IDAT:bk㯡lw:d:p_\^6!D˪2w0*ڔ 6@jD:%D6 3 `i u {@Il4s 9t6 %y |2LR&0@xn KZ3܊GEo2TXZkLTaaCA>yҨs=o4tX`q4n4YM;:)_Z~q4W 'P[j8 6:bXH.梻)p(p 3 )o\g+X٘$&#oo<nj<`»ڼgNUZqUAI욠7v<"NQOvLcscMbqTۀ8T( `c^35":)Nx hv\R(w `>VD&bͶ~3%\.uD_օG١>2\C<~RQ}o|Dr3 *ov;7k'8G8l4%^&7V L@ - Oxށ2Lgmߖҧf#Rȶ }VQ6fXͧ~꧚iS5<&0g=HBN nʭ}lr ܭV==/WyXn} >w;F~ yT`F@(m'ۡU MZzel(.|5g^`SlPl|+{I[D-ޢo؁AXs5qibmKlC{)x=Ƀ^bn2 eiX]'.$2ddYFS8X})07#`z!kWТ4 `u[^Ę6}s js6 ]]o۟& y&cuQ oT@45u~=ܛFZ#~ΜA@iZ` J&" 8Qp%ݞ@aZsG 2X5]jf&r-uk+s* @1F_֕ϳ?-g-OWAKOA;rKP&asFNi99?ǡs4LSS+.Mn^W1cXY-*5R㏎\+k_wO<:]Њ$:B@HK w*pR-H8͞yAq3 kz&>&ls nDbp*~);+h%1a 4x_i߮4eNjJM'3GP'P(.. DTQ LА{m0,Rsr0uasy~ݿOۈ礠*omy$, *q2I,#+fJ%I3?3륵쾉匔JB %p  ./)4J *ڐQ?"ԙ'^e;ih rz])( q/Tf@{uWFzS(B李pcm-Jri:#CD})+a>%H`/o_iO{:wM'WʔH|kLGdlQ4Sf*Der?M_½(DdEǸ#ԣhǿ%(b#wkV>Rm81ΜVؘ[uEl7σ͏NI9Jp)(*S.g%B7~!I;#Thr525zon=7R%4[E .94%3#7~k$SmE p%EkALŴO95)S]'5A6vXaTc"߂\ [#w핿z*l~NKӕꑤ,Nʶ':7EXc.]#4؅-WhsOvoͿy;2?MCGU֓YϞRx;3mU:VX/VȎ;MJ' zu6H!5Ӑʢ?8ðWm_@ u [3@q1*7 A\4X^Ќ ,Bw!jq#$Rov@-P/FfL' u]g 4 ivs9 f/(rVP.1#a:z4 ?^kˎ}dZ;UYL60T,-)z"Wo-k;k/&+mXt@9X[(ӥŗL=˪ۑ Mm4;`uG'rû[!tc0R_g3'< Sԫ֥3 Mt6#TR{m'Rȇu(axٚOdEI| eCg{"ST~̀h rBo*ܦj=]Eb8SQ) Ś1;(bk%,gn]!Y :wu݋Ѧ%#?#3Nyq2Gfڶ]\Fv)u$Hd:#–eJq;2G#-`𢡊55 )L/COIg8`h?Xh~i闵4S:msR!F2ׄvNi*Ml;sc]3¾%p zw~4 {4bк16 _<zYLGZFLAr:4})k^Zڧ?{!]~"l2'yYfaG 75iS?oAq½0Mַ|3>)+J|+jOny\XI5YoWuVk2shL{ %gʚpBa\|ò(^7]3x;l ~R0Ĺ.l \ 93D 5"js5>׌3!LCR^5e+PzrBΫF;#v1dXt$ J|Lk]@ ^p>5$UІp@0XOoGEFiAf5zLcr>H#K(ӼڨW{V@a >tϕuuѼqRfoDz9i˳>i7R{Ax#w>>/)*`VJόRkW'b3 bմ=&7G[%,":P|ZO )y3.-ؽ^PqÍĘ'/W. D|[@>`c!1 >v})c]Rlm.M0K)Zz_ny2#j Twn'UUҾ&#kyo.U|E[ :&ŀuz ١ל 4?^ ^>撁 "W%@ -S8`Hj1uD?V!ۂ+HK[vhLY+#?94Q~Fc!qvG[B:Q!f)D$QhބF[u_c?o&s6?CǗ8ZfRs+寐Ze:bl^ xLwUӣ)\ʉJ;&g$?lEJ˧ܟA\7*9PPJLChbZFR{.k.G뚰7uȬ לX8Ig++y+92#L._iv)s]Dt!y{WFkNbDW&3^EIXkA|@? [Tt :TDKЌlڬ=D] xGJKHQMBˊ.a$rȊE"cDnTՅv ^?GѣҔr{F5ğr!shtkql)g:bkQ1BړB3Q=J;ᅍ MFV4Ky9&,P?6RK=9u$/Z`]q4ϾknfM?Vs/ +ImkU_Um;󹠸OpJevzpp(Hx8kYl@*y{>զڞ`3~&?Aք4k]@ I=@J(3@3zUy]((uѠBMў:d&&!Kiq25p!r銨]rDm-l/LNY|%7ѱp˝dE YR?͹5:n^ٟqh/| y{3sr0i\KEvjZI^k,dם}.ڔS3v#𔨆٬^3kb5kFonuK(YZ==irCz1(ODLl 4(@h-X&o=V\h3%d j v'i,i@6J% WI*([$aB-"z$fhr`#@#Df\BT 5/iiPF5@^O9 xar`):AzވP.EfDѰk.v%7׽{>hӄ;˱RK lm>slyvJbW?s?wipUrgO=Da.u h*oi9)ܴ k?O "}y?߶.l |JK`ք>NcYZP1߇gGk:‡6)Kzp4g-9m ZSۊ\SJwYK whhDG MtT!^ ^@s_ŒMy'(4`֐}sGthìЉ{㝊\cTd *`SSᙛ %?TNDѶ2D:RAǎJAvp GG){3JCPy5,؊~g~F9}=}6o\j?b|0ثwO:bl,W g#髚]U%?Eľ~)QH9T/ÿ~*`~{?º0ZNŒްwh ZsD!Oi)/;6ӵiS2zesIeF?5EƤ5^K M_zYGQ{4o{sq^ܘƁvx$зwb%`YһObA]H:; i0tWW϶qNO{irv&OP=;atL5B297vE w4{^ ( ʽ}ܛwY`Ϛ xK`^4adGD hF,@?2ѕo 41vОKp8 ZOBf3f9T35{L*[.y- ߏ=w 9(JhqPɭ~+_J'󊚼(LHy7ӿ`:/JDN ,|Q%gj?*Mʇ^fg#wގ·<>LI}0sPa%C) `-)W뒏I?Nl.PVA౅^߲\ovV\O!.[t\rwW[L5]A]ִEL2eD[GV[mew/L*ڰ[qݾהZHҍQA6^q7X=Ah_Jf8qPPFEIDۚ3&3dAo:N՚ GܭѧV^IE-AtA'gR%D/qz.V{AxNYii*1e;?T!tGEN ƒ@nv@ї5:!W$cW[ZD]hOV_WFS*}; B*z*rF+ ,Hv&.q̰#ʙ_e}jIcv_'Ȕ[0 WƋcW:~.o \5oo g fHF(B؋?+c}!Sab?R8A.=Jt}"D6<$up׾ti-\c7'#h 8'QD]BO'k.P{Ax)]*b'>1P&qD<ґgo]Ȼ%pXׄk0!"r0R>}["$nـOf/GUwМ}+TO8m`{5x x1yztmֽM/| S**mP 8"#"e{2B]əKKw kT񑫵'?3?aDpg]4 ̚} =M*X8FqOySr:[]EH11šVs:NdFd߫SA `yG,b(Av ʉ :poe ?Iڐ8X;F0f dd]902 ?5:'*e|0'P7F\ r\G\_%F³wߕ( ?z9 OWhY#i٬f-k1l5~?JL#i/#so(*yӰ5׷ʔ{ FO[Xo!``JeuqCoy|`0Sh^z]5!杚D-&ۜ?úE %Vg9pm0A"11jd\֖wYf}g&As t!LN{5xwH hooJq58(裂!pL^# hC+CDb)@ ʇ?~S&[08er? J`քoz;[LĖG_K~_? .h];nn.ip6k ̾v9|!$@mLR{5xni| o[?1P]]|\ 4(gfY=OX6rPeHH႑(oAv7H,;]2E<BQ B:#DHl\luV!K$ Sm-v),N ~WN&u)C~~jB$xPTIv%#U tng)c.",oxf ~e7wLɍcwlu4ګ$#$P {gh(N&`r'QENf&%p5adW4҆o*ԧ>u^سB![l' R DnHPrs,#ES{Rn9L&㔱Wr5(ڊ$xsh{f|>Nls/f θ&ꥉTM@9?GY@236tݑTg[=Cՠ"TEBgkJ#fJՐ:H|mEN`W^ 1YVXbNi[A-Ɔ]sPϪ>wI1QY˜Ӳ N]vt&KH nuakƟdט<9\Ԍ')T (N ;b~ⲩ왿J_e['[7[&R ó(mK< N ~& >OCiN5[i!Ba8#L< Bu` 8IyEPiL+"~蟚'g2pi K~肯ʯܖFSpLN( =oSQЍ#rzM}?啜4&v#!~ Z3>2sgGyLk35.DNA4P)m4@JA sF%Gh8VB)o񛢘FLܛ~VaXU{4ֺηYN2UQY=͜%t@}F^:$q=O1OZ03$ct}qYTweA#CX(dckQnBqpn \ Ǟ{Ýpw%"|oNH3u1\9 L8WоEf ,H-xi XOn@@<4f=w ?--;o~zކR+HKfeo\F(K* ': Ah(SKY$jd5lHZ}[UzоT$2;Ι|C=52W5tw8z^6H};0sK$-λ֋>(PQww:bitT EWL @Gy/|4)\ %zd5uj?^i,aNH'~GE&(EiEJu]`pt )5Bʘѧr(Ls}FP=$~DzhגPp2%wB֋Q`r&sW{*P |(G븮sж\j=t!ݱFwU{kfT:EhX#,Z-q'ߗz8M (] 3*20^…(#Ӿ[dn96Hz) MCn}mB:Y80%}=qtXߩ@{ϦvEfcAftAOg%烔VkV77]5vu6-ѩW]KA}89UvU#g1]&/3/2?ULH-kįoy[&ߗx#F%p5VNYKf-y&dE )&̛۟di{5x-o8zP",.W6#P;N7 '~X ^%O@T!QQPa3݋A`f n66Q Dhj 8]4n9ݓz.E~ж6B:ܧQ>3Y–H`/GUlCM1(0%@{Ax >h-<9Se^IS+.Gqo ׃(غ9<,_ko-V[>au_us_P~ H(n):<̳a{RGvkU^{@#/ц1G#1gMKxpuw͖ G/o-t&4՝:}pxы^$pQ LQ^v-.-fV$^ {aO'>+@H#RYQNx]r%pS%0kBFz/ov;+kb)ӺM/ xFCSPR&psjTD$K^;Op9g_Q %W 1Pppy)X׫2Ghe`L D[Ze?OuA`?|MαUQ6hL3 hr^'͉6mrtΡv*1K@ \x,JɌ҉8k\e^~Wӫ^^%ot.YRgBڎ[OXmp`@V#%^=Iwi1M4i꯮]@EqXgޣ~HGˉ:@CNO4G?-qH:]ԕ {_,? z:iEbLoUo^C,d_sA>J_jBL0ky;8;2h(`}X95>%-}!@dt.Rh&fE50aNRA0Z0sp6[yBu`Ҙ<˿\xREÕƭux1 ٗ# μ7!gu:9 ab66^+8ƎoV=pe(ӇׄrJP{5xyip潨0s "(>)2;X5pnػGSC- D:&~ hrLC$vzxr- ^FcYA *3s%U"o95o\[pŕ#RTn Egi+r?ȎݜخEU 1$9}]FT6+Z'>ѥ d{iIYKmmL1ӸBq~w}%aKj<{j^Ϣ-9u0yĪ7:ϫdKߧ[7[N/y)ع]^W ^/^Ry1{ӋXVnr_KL&͊5Lמ5ܗ.Am¼@p̣ Ox\v6`ץ#$Z UR@4車䃀 &6Q;1Td֐"*su- 6\E^ʄ8B]V$=;Jr> WJI׹* \qqPaCcG*ַ4zϊ]Fx~~iݍ]MOjFQt̄s+;a dж. >ܑ-ֽ0<^eautVKpo(D#GSf:brDm|n5l陳Ι/K0p:8id-)|}_Ϫ {5xvH L  R׽uk~z@' uHOL8U߈Z h20 I:ٰI"G2%Ĵ=AtSwv(V("PФS uKӪ5 +C67ETsRUN%2+CpNIaKG٩)nȡɒ̱Om(~Z(>W.\q&3sR׳2&TcŎ?<*5,AGa7ɦGg]Vv/,5Ul]ׄׄMwaKK"h2}h'T+=v~6Y{0JL#=r$0lވR#+f9e*0> Tܑ h+- O~ ~"0S@-\B3 "IΙ(ʴ_ (ͨ/!D}u2U.C:n(sJ`/Wi\\zӟ1r?-WlXGs(֬ˤ:c;raəh]8]_.iƶӾj2b%!BI(iá:,2v|\MN{T<8Kb!΋lGJYgfٟwI]P1r$WyҀYi--txqNǏC,/կ~5\[i~}uKSK S{#<=(lL9~hf d/ <Yy2=wa @6hI(&$d"PhF*Џ2!#$%;uPjܚ: Ax1=;:&!4w<Ъ)'2\C6#eϵAYv^#­g:k}y{eY2Gɬ @hR:?ܬ w~:aaǽ#t}똹_8Wl7Hc$toVQ ǷDC^`*d#IK0GAl%ps%7BOֳ?{zdyz:+X6Ol8[r^s-f-xR9]@jdGwitVT|;[߉b k3A9֑;9kY QDRdkG j+烌95 h[dJSFVҲs^ ~cYGVSʂ] ~5̩)Oyʴy;6-D M@7ՙKBѻա~檂d$n\+aJqwkrBLĂ2 T)jꕲ*"b6!Iϴk<54M` FS-ˡ}lC>AQ %:k/>a.5!gp鹫`qtP0 L #;//8C uYWs((`;b`VHp5mQ}K:tA{:֨Ԝ*mP$5>XgjVR'A!uhy-U{AJB^?w C po`d+?2Ռ4*Ьey3q!m64gyʢۥl>B_[~M'=I1yLiPT{@`Cld"` ooifz1wyK$ &W-`H E]cA?( o_t͓ʹ˥AD`X, p|k?3@EW>$ajB>EdAZ.AuL2kBE&h}|F֣m^gwj6LvyK pvYF[ >v5OkUʎ~@:{_~چ?nW#oA݋v;:;%1C 4Qzu|<'[ι\5IvUPA93]-5_ׄy*T'Lcη6܍)vyK} kB_ ݹӦ:`y_凘W?85Ro_n協 mf5O;yԊUD 4{ @vԟfژOw@jh..%$L f ^Z$- -u( bs 5B)_o q5PHU†ECsHWn_|dٗ:wy|Wozӛ4q@ pU7Fkv,WqΎ@?}YSjf@SuC߁ɸr-(H mMG^+EM8x'"mm)KO)wΜQDt]dY?Pg&%p%`MPF a׸!\/ 'DeZ9ppCuq*i\(7x;BmnN@ۄZUd"*,1(48W\X#k [1Q8t.(psKT{Ax*KqD-#;%%˂D /FuPIRlqQJe3WUMjt{j??AcXh gw?y)ĸjC?C[ÒNJ|Ϭ3+;Ћ̇WFr#|4C31h7k$L%Gx9L` Xn_]hhe$KÞu{ьrpJcWnp%a8-0q{A[mNj4`{G jUֳ,5nѨ%(`%s .!a@8g!AKW4Oԥsᑙ(GFQe*Df~ @<6E9O滋-^(.@RJ#gm) )nUL"Z&bRC DnyFez*s֨mdҘ< [0W.tYMF`?5i&hWtаIGBکb1LuܑƠEm}? #1 -!AHӐA\`z>dOAbGCB'#03[p.!K(S P01,vXΔ]ygnn ^"Q\~~enpS(ܮsHD?AbEBF@,/%OFH~MNHw n^ef¤=go6n-9ʞa`mЅ#TqOяoNGkLM4oojIMLR]j:]Н!,\RL檂h2` 7JtK"ڒ 8# V{ Xf1Ь׈]/ ݹ@  u>t~wA: j(z(ʝH'chF@$4i}B: CIo2lMϐ4 yCln [K`/e]6F{Oa0Fz hTio|:І+< Õ+rz JߙxOh<:KWVW~W8aJ xz}̜.-oY{=Z^R! x p7+ QI3m l3aة[=O=#HޕRȭBLB7_ 4ayzӥLws{xɸ_g1J ̍XX;sBSq܅-KYD\&u$S>1[r1S (`@U k mn ,G5r]4jQ-@p<= B^ keΚ6NTD?tjJkHk8D -bUYWBA6-@3.l R{AxK]VObQwSſѕ.$IyN&͗9B_7!\ Ecc;,ۜ/DϞH f#/;8ʋc3Ǽ, *܆BIA鷊B. կ~5pZȬ׶=W۪/ˢIg h["[ves rO}"rvOdwKSQeWT' 悭62#(`O (Wњ@Xٷ*tg Yg)q.H؂= q8\(1HZYArU$k|֌V(bDb Մhέ# sqW+ZfL[]zRȺ>.o \(W܃B@@=d;n |*J >g}x*&0^ ,"SY|b#3G( ndМ_ٔkQ`'E&͵3)gBZF.BlzƤ^l!L>i3rU_HWO_\Jmj#Z-Gxa)3FT㎩VIPdSy{W$1N2>š, iYd+ȅ9Heɜidanf%~cnԆ%GGA&? L AkFDz\\{N, 2 %Yk d70A'q IƋ}?Y!˸YH,ߠ `Ndjțl. ql<H x<'A3ӑ=_ w1@Qi(ܒf -6l zcz2^wUЧuғڜ =D!ux.ߎvtYmlNu@qAN ʨ5`x[BVCF(I"\jW]y_|N f3[0Q*ў*5ڱM5`֜sp$KS?SĘD<}{nݔ XN ;sZ''k-[/o5AX4,yc2OepG*mPL*.Խ~5!b.|?\`eJ暱ͳ,53[i!)?ޅ- =X݃.""`}F\\8|Cb,?sT(vYFj3=f%p [ $ƥvRrVA()H`k6vkRPw\9] 6~!? hv0#yYA@0^UNzߎf (a"IkQ*ɹ*Ac A-P)>~OCZ}.E̒O yj2~K 5¹KA!`qloޝȜ ad]yD;*܂;c\}j$j1}ڴ׎k-NCj=++]WbBxvng(8t$I_T/'_u_')vgL/*BEY r$___dznnswn]@((-Qpt @Rz٣#O@V,hp`nFビAhYсAdP{gbb`2Ra{'ug,@0ƌx ^bcHΡHA:~# NӜ{VU{V,Y 5,v@ ?JkfT(1Or0xX*)n~-oѝ=lߛq*6Nbz0r _.l a?éw}w>#֢&r6Ew E /(νX@ |?1^,t,%ovWB= x8(Tn.o x rw7^D/Y@au"}ȜY 7 0Zip8W8T?I~0\ Xg !l܅P~'F2"W rՎWyv(M>SHBС[ K(!0&0t+П2Y knS{AxfłD}J9;Puɉbw }Y'c Z9WĔPpiCȬ@4_yЃd-rz˶4#xoNiY&>Tt{Jܥ fYbjLm#9#l$z$&0,ןr%p$p͒K7#l \/pv`DDtCNVS/xRs/UQm2p^i]94ʀ_gBm`Xn)uGtD <\##gN"%8t7h3&YRZQڣ&HV#w.#IfVa<\'j8M~ԣ5<;u\R? _x0ە!IƯ>a+&\(y[ ?@;FGtj{ȧB\MyxsK&I;IOeK 19PYCel$Q4X`kFg@m6 ȫ1M P8:j.؝ŏ MU/2аQho) ZLyWiXjlk3~6\ Q1B;׼5ueWQXQ.!f?vn - %6Pԧ>54*vU2j0ןmơ}/jh/?)tX x6N9_BgJ /i^jO8юMU4cCk$eUGlz깞'RajdhM3آƁRn haU[Rӷϲn l l l t^h{OP;c5Y pg@`OValnAK(LO{gl pXU^M_sRڠ%!\wϡ AE(ʄ 0Afώ֡٫**{sh%zU-ۑ^ގ.M9Ҋ2;%cjm`1N<uӃ፥+@IDATo0pu2WU³3 W_ {|SUB5 :n^h%@!<Ɲ28 A!4 #?QX>^ LHIcU4e 7*ʵP5 A줁x@UϻvY˼dy8  w=ٝ_ Z qu[f̵rnvS@ZW˗4–mJ`/oSPی/gPeJk8zJ11qZw-oF΄m?jg#<,a3)CЇ>-2J&,^1ſ̀e-=0))~gGĺ*b,ul=\=rfB`V{%#f F0cB;\{;5&,4o~<.l l l l |JԮiHhxAԾ @A@*A @A,N@$R `-}p&A#D8v^p~uTi|O/i9Yfw[gDy84@0Ќ֢="g׍ 2sg鯣 R4A]E'$A]-+Y[# )]z}=J"V0xH}:kLx#~;W?^%*̺5g+MD3:2Qc*~AŰ́o{+7!p{v|ަV^Wl>Oo4Ħl|TZ~瑩~K>9!VL |<,d`cKag}g͟:ۅ----O Pb2hSA`2: VKIAo ꎁ ; yڀ? 8G (Ki jP p L{w@9 vͮ= 0<RQ`fќK>-RT=,L+]"ꅀE̐ݕ^]]bo9[u2E1Ca-E`GIM.ͳ;{JiР"[LeMˋ_b\5ΜGtH)NV 4f1gPr5J=R8[u`hrVky?񉝭BvLE]22J63*+KgFn l l l ,;_ /G3i *%eŗC0IO l/ %`i=@EOYnIU>pxcD$hc4( AfA 6HPl[Ai) 6 ;Y]u;֮]U{>ϪUk2\xu7kn1Z?7PY^Qʃ9$$}LA٠rx:^Ө1U3@Q(ET# 5)cK}Dey\ zje,ٜRut, K`-峮_gͳV)+rKt9.3`H։=Yϼ]i#6i0r`Mmù,|IӞ4.*%Cf6 ?fVf9V̴Pa\p[C,4`^E+ԛ,>bw5XMaKKKK_ڠP޾|oԐÇq$A1C\*I* j=Dޣz9*fb[ÆQ0nf4,&{KJBjC1Ti 3 MN3` ~)8AlJSm^M|hڀ}/|Da=ck 6ikJ,cQv&:$ gVnX^=l^T1$@'AV-җpړO߮Q`z),^nK'jRh 15C]VyI`I`I`IkD:k*a<>O6o|c&Ԡ Q4PNɠzLԃ2SeDX:Qª=jCp@KitY v+*E7J򘨹ΚozR EZ"oGP||P{(?V3i޺˽(S}͙%YkA8dlHA@'f_(gsL!^9 W6?Y1h y\~R3XJ-sI~mC9QD{5):7 ‹/SL0CWؼ=B!>ߦQе^chsT=-";.'}sڪoAX54CÉwՋPAA4'}m*SvtVaI`I`I`I"]@_DP2&P@"$D\PDdyQJ- !5jݒr"]"WD2jN"޼=Qv~Jd0h#+TBidǵ.鐒Cթ΋m+xBDUf?]%* ;Avv3u,` 26 96VrS\N꟡QW"f.־a rPT7_j.(5ys`42+fiLA"Gؽa_s` ^o/*Q:/}7"Ӭ7Rf/V9č =y]_.`a8<5cɗ>y_uUz)񸐐Zx7C6wӝՈUpjӓ&$W2eRx9d'< dv $T0M,l\'Yy/oOv袋) u3|RnR©}~p궭j6uq ]ԒK/@htp9xa 2q.$+ix#H7e07g>V"졿_J\xQ_'{XQ2k%_.,(j"YIz"U:I8lDЪ;uψs]AWaI`I`I`IIqDm *`@^ w/ϡ|iP_b<]E=m%! ajCgI6o"%D542}nގ}<{h5=t4ͨ $LCKcG!dXd,zhΑoIS@;sس>ȇj Z+B+BFe4DR aUW VGm[ PacEu"P4Lifbγ w34(gAj.d/$U$ Jb e32Rx=?h申aԪ|A&v (ffI4$!cz ]pD>W̔eW|/&nys,NFG: э<.5 L lU@,^<7 -pޚ :;kђ⨮n酷mxb6z2Cc)h2yF`Qtr׽.)#Cq"u/˪kb)"~1fka9|d|6)?1qΫV[@?YaJ;2y_dlsatHlnqazvb^ GQy~U$$$$pѱ q! f Ԑ(d^S2BLňzW)?$X`n(Q=e eԬr\iRVޭ)@1/U B 5#KL[T rԕqԦͫUӪ ԏh՚UX8 i?P/[#c挠k# tI^6cނWU \\21\W&}"Ք8'T8? b^5ԧ_Y(]DF$]rkN&qAyc;lAQQ_,^2I/?@2T}\U ZIPütWO'j\6@n&,P8U0; tPۅ&PމVpQ[Z" 4dPnPQYϏP^ҕ"Z]{)Jݔ :.!xLd@k'J`su`A~L.ʉK1[W\hF2 -LWP6;YK7UkAxS%vۣQf97Te2G?}a9$WKfCCI.qȸjsS_!uLSWq,v=Z㍚46IY&"FueJ!oP]]B> U% \5J<88- ȘZ^.̺W4$zZlx".Xݢ !rMcNC@5[a KaW,:V޷{P (gԐ!PP ѹYeO %b,W+6Pi:RXsB}ͬP]B;K/j6TlJ*DV3ejơDIc]yUYjOl(Ny.ˉWRTwU$pS%7UbǺ=i Q*@&Ut(w!MVQ !s:mJÀxlC ZˈLfn6~7~V3S {1,) lX\'2U0]Ildk\S|ErsT k$Kg?ChwDWtr9ĝu*.WmTc\-Gu\loLɉqR\;&Pgo"Oo)`߾K- P]!2z(#ƃŬʕō|rA N*, , , ,  P@ZZurBPxhƻQ˸DBMdb̸COԣ ms&7Y!2!;܎74pJJP57C[3$7PS 'et/c>Tu; ³EriG$W* [̦Hd򖷔Yq] ̗z;XxkVḁzoPNY[K"Aw]xN9|d:*-vLOaQ7q! <|\im#:a(j#zd6X6Q1:K*m;]:88 l*ffتh'cjIxn[R*$p B;v( ndͦ+4,Gud- S ujCpi!!4OFi9"YTkP F}QvW}F C9a&E $ңW{~w#Rxze/?eʤ)EҀo_%3Z ]B ,{`]AXmH%b| _ؽ#5ɲ= 徻K|^#nD]fhO!NwoM<(+݋^OGcShJ#=n.dr.ʯ%10Z)ii6^ X\]=+ayC8"䠤RYm 3zʪZ}Yd[FoyBHŷޑ'MP=Ea!2(C'nW?YbPl|?'~>z=>U^XXX( j^fYK 6`3j$ R(F(q$ HtcSTS֠ks0ꑫ"e=NFAW*ui4uU\]=+ wD:P$:uiCB֖;gY.w@ wՇԗ5[/"\M9U$p&X 37˳=&*4; n'b=S =QA?ʾ4; +'f{&I#!wvohY4YPUut$pc$7FJ(pna|, ᡟ΀'я~tϮeZG4jb|3Y5s!qX#ʳl3ˋ#Fjw]9{^βO9Bҩ߮ԧ>#=DA8]57x$:@ 2D"UbtPI"&E wU1'ynDG(2坥Nnu h:3G;GdK @w(S<EbfZ249xJܨ@r e)(ZzmqWyI4$!u TɬrV$Qͳ ZN>q-#,hj] VWS@oKśN?&`=_EDCK;b=,- &a~~@H$20)=+ʼ?,t{׻޵{-3'>1&[r aSXDik/;9,ߞ9T@w[. , , g CXCȩ, gUm z k,PGjD& !'wCNc<-C|"hh9ʗtͽ$1%C([(:ZGi`BN\+ܕɻ?_ooMzd,;Ic#j ܗ޿Trl%+ʃ+K'į}k]ʨs>ZDuL(SW јة-cfkx^![gI`I`IUX5dp TM|#3]/Н0O.-Y#g4,4CA%%]Ѡ/W}IUeR+ C|($q(?^r-MlDt>e#y='R_s!k??/h,b|SGDHEގQꉪ@Ţh!OoNCkAxB[|Ea@rldM;i stY>Qf<[7ej͗^š`%cO*!"m85Y-R"@t%UzU¢Y\@7) `dMr3kZ֖58zIgxuo ;aUuگZ=WMr-jn$$$ )quHTX x*r [ xs^Ib@;wuN,âDLx(c$ٌԈ=uC^( /x.4z_AP!_P$*Eh'D[9ΖzLJ;m( &CtYujI tPZ.w L9U)H$ROU)*VRZWN[kAxڢ[7~998 xup.7Y% wQcS^"+6{NL}{ͫtQ֫|4*W<#חŲjlq>Qd DyˢcʜHeK 3~V#Q89uoRnIFf'bȳWH$G]K$#KKKtH𰃡o}kb*jLu`&_e_%iAzN*]eԐ@Jr-rÍH =ڪ90W2*M=#btQit͹+ +܃+r7(3_b9g(K}_OXY{A=%3Z o o2_pd.BlZ'?ɇB@!r;tvIXy?|i95_.4&NS~_ B} T+Z DC y@L I%gz@a j5@"SM"2#"@u"_QTRЗvA"@w@{XP}ncC"ٙD+]zEI<$ +Pa2!ǪGvIASjnAf)e3D "A. *È~f915ͫUI5 露CL^]’H`-Dz^li똱Sg<YEpoE嚉 v]1.@j&wI 苴|ӛޤs }3Go:w__:<4 J@'lsߛ݌%bϭRfp8os//?H+ اKlW0DnZ9d)j\J?@_jYyJ31,,$$$u-`A"`lOڷ, @0 vHPy)@>Pzo)lPH UQHm!5нhW(ewAy.ىɪu'=f'$dGmOs$6-nm֜;3YzF򗿜#,OqĻ%n3mM+uS|zL@$^ awCѷ)WN&J=4iugyMҒWW+s RKe=;cIP 0 )8̓܂nP AZB) ddgb:D%L mF%QlخbL[%IZQdj&nDiT8߫L P Q,s5qYinoqh(!TzpH[K~4)0z WP6 Ω?FVQR%+ <+^%N{˿}biGvrc^ve(k\aXؼ7V'̯Z(>RdX_7Ez@9\xntYNnӇ!VD:o#=p0ܘ䢞]K.9ƥ`,A2MI?ƣ(QJ?*+ۿ 3Y_%Ce\ `S%H 1t /U(>_B1} BoA7Y"jq+W nO:w/tЍQgɟI +C)282k^kߏBtunDLGo ovVc|^] r&8S Uu{ W +96;ײ?Ke=Ɍ`8ȡWh3gFԤ\v~ūw5s}ũJ;G*/ , , |$j]w N[eQB!a P@Z``lq~vLH}NJhY5:BA+YFjQOB^( 3VkXB;ĝ̐SA<4PQӘMʆffņQl.:ƔzcDW) M<JZEkU. E Y*XeY_G<{äIP)6C\JIA3dGt>AZxd'A`2u`'r: Z uFeIdP@rbk1 Z^(R3T" 6-- PV6@D^Ķ*#zM)Kvx mo *³,3{P`Sg9ZN%aAWE)99;d)Z[ 0l^L <; x^1$рVFC ~rDEd/Dو}*(;G&ЃPoWB(m6ST7 ҠP(B!#|}z"Cí%% <[<d$(&(tshJ$]+3x! z:b9;F/C|as m*{uE;NB3P_x] c퉰9Q 3G^HW oRճ!xdЬT*C}S)+CT`QGoq!d I[z@3wR׍A3djΫ$$$p% ' i I*:pcTA`c,e2C\Qo҃b s֓ndxN,|m? @ K̑N &YtR+WQH3B@`TfWj32B84N?sP)#Y1:PG{Y]^.5fK t-W`zYgJiL //ժۡOgMӄ]9y, , , 7 , @֜ 8@X@bP2ʀM B5waP\H PkwM P*=5$j<$ggE7xM11]9KDC;YL0&<B%Φ $õ;5ՍngiFE!*F{9weզbYLz?s&ػVyI`I`IJD 3ׂԃ;`:P 0cCF10[{  cA4*`577c%R\Z;/QF:Ƈ2yήNm:׎\Xnjzu.:cVN\.'&FP~y=*RPQL_ !#^CpY!ʰFDBvqEn $|kcŚRA0)!T I-(R\\.>.G =ò䐑ſcgan x d`ծ"0r |?\ сlOZ%7s/@nƁ9Hw|N9RluqsfadDC tS)6C 9ݢȚyTĚqQJ9H|k5JJJUPyz2(pޛ2E-+̡% D,l7:J3 KHkAx{e5@%!BI$_~bzqdˠcUYm ">N"JC̔^z-*f YviL]>&l}š563%ghV]>sWrIxzԏ̪~p*aMy5 {Eb8R}SW2I@Kza3vOW^wu5*, , , @0jOl p/ RMx*>16l*l`/p.<ڠq` yuA dQ@"&d[={Ue !NHua`L˂J BNl!^@ $gWh6ܫFtPCtE#nm߶ydBtSMl( 5m\ژ C(%zW$ ݼZ([3]5C|P<:%@aщԉd` _I;A)ɏ\-ԧhJýZ;Ǟ@?6=/v)CJj&fH2wp+TݲQf8`paߙd?bYy\iG\|8>"W"b4g?^˯~aFMbd/R2v &մd6%ڤ"?A G2%_yt/\JXy>+5}8rI`I`IKh@v &j)X%Ё;c>+$Bd@hҊU `%hzOU`ҫwGD;} y:DCGpiC>">C*QNl 5PN$:Zb o!nԀSI/P'B蕛,+W{eL@Ȋ!Kg]kAxEz;d Aa2a),>3i~cV~N^W-1&\Nvh4sgܝsʁ2,X4 9P!zO,+Sټ֛ҧ)΢Eg[վRep>OnS$"$%z-d b#Ig>AHdۏh y!Fph١>U(2bՉso2&%@FI9S,5`$Iq&eʉ(*isCH)Y95fI\H`-υTulzفɹcSpY^}C{\FB-M{R2Ml5Ә ҂өf,XaQ^2A0 Āǹ l>7fhRcoK |S~J G"\LiQ]"])'˹e,X5L ff0NHKD1UL!OĎhO ~fyVfI`IKD$H;x@ C,cK`jk dN(Kj@w3A,y 4fko.Tv"80q̸|ha\zbCFBX%Pۡě!2}Q)fNϠ*7֑{뫫ԥ@ȤhIQzRxFjJ"n~RsfII`-ϝli̊ S 6E#63*7w }CZ \]K+XvIX{8e]f@B#7W'CT5j/=DGpv0;C!3dshwEk\D`f,ZNԝCEbז/(Ňԙ5d!<9(f%I)gW9(.6չ3˄^:KxS ’X : H5PpNըJ)w 4k8"m}0f_ Zk)J-5x-Vށ<7s7_1dߨz􉆐JBLL( UyD]9WSRCV|Q0"FǑde#n}h{3oC# $g8*EhP0'C?ĺ$pX ݺb례bYC7h#{J_e8klϜjmj0#za &D5̣TM6 "Nbh}ơx!êN,Wm˿ Cċ9̾:1}Lڬ? CRh!Q/Uθ˔W%=26g=8bU}ye3k}]X81~=:\  TYW(8@^ <ɾY)8/$CkA4&0H:1DszBcs1͐6h` E*Rk^@B%~5:z"\_Pskvtמm }Ы%DTDC|Ce7VaIH`-ϊW'7@rs1&GhG=6g<mLd8@,zp o0֗+RK^=[oP=N#uM3Kw@PetG6,cd2ӘaSi_^2b^2;,Xuo.>Y)@wqrVէu|޲;!=^FMsR-Vȅ͔A+XusC3m8fZo/E퓟d*/ , 7 <&Q`B x>'>bS8!\ =  0`׊^lU }ν ;Veƭ{MĵqQ A7} AIiX[; }"lR}EdXkO#bt1RMԺ}.P[fj@ؼ+%CEC(3T!dTc"52Q|̗އX%. <"]~OF Ǘf@8:h+X-߂aJB4d3 J)êcsc2&qeAsmyZWi'9d  ?Qv d|K$ÐPGxơ/| 1#ᒯyCn&5 I;QT=G_j%_^ T*g z#R?I` XU'@ u?@`06DG `s0 р\W/ :wz?wA mkoP r) F yu2O}EucP'E}P@r3,?r7/YgMpA2( :WJUGSc _]2yjPRZ& ^%Q⒜+`2בr&~B-EG&~^ep OvKX+4 Gah;ov6KLbV2`59WM}{pL".]%M\tzRSRù+WˈOOrÈj|/y H>I)X*ҥ 1{ga5CYD'3͓Pvb>|VyI`IC~7OT#8ӗ[Ol%ДU6,ĺ@\^\732H1! Nv_P` ro 98 gEɫ d2@"ăbMnvX*6SV3gJ[RBo<롘I[tY@&7IR$z\&PNcӦ$^,.eԧyU$p%ZǴD;\hVGqyZ"$T^W_}ާ>)mXv{kx߮OP^6L|>KQQI9xL}tW"Jι%s (;|43!3Ē"yd#cqh#zԗ,)&/zыu\Xgg$$"˥J8=yOoU2IҘVhYzq|a]Ү'VMyI*/ , |=J<ϿzAJVS@&v*O ŠYj s` ʜ TK``sƭ.Y [@5 4,H}j ^5MOo^}Jyƭ " ^{f=t۲JU4_ Sك;rI)SWIB`ů&E̙] Ox|% ozV;v} &,"r y?x~)դD@L5b(̑UԞ<gDNh%uyP q*P* jƐ(.6&*@ X>&Lng$QQHvXg8[ͩ?L 5._:PNVaI\K`-ϵuQYx%AwྡྷqdUÙH2W~qpbE$"B b?u g< 8*ŎO4܅WyC"J2nVF:#BUxP@o-n2oJ'F>:V8yߔЉ xJˮ}C! "Dh)}zY++dKKK\L1s| y̬_t$$)?۾Y8('$pa"'$7D1P d.U̹I@_̠u{A%txzpM9awa@7wTȃz_!PX%_h5m0sgpA%<=RVXdWdJ$eeAr;O8/ Qc:sSޛ?v#CT ۯimX.ɻ4?YX8#틓]Qŀ~`8t0QȀ{G@ی@ 7Ifn?xu<0M{z&=xjK8ŃDnS$3ԉ:X)$%gٜvo=Lx q{.$#zoߛ[#^e6RE6+|JAӶ KNkAxdz>!u(JKGTyW֐~u(ǥ Ws΁Adb`+@#SDtt28#i 8]!^93ynVogĈ5O7GN}LI ajx7spk(j(?٧&?IoKYkAx~ąww~G0ٱ-9$UsH^j{4i FAV'13Q`~~ֳ%&$^MOK~8$sITHA)5x}.q.I cm<Ѱ,r40Ԯ7.@rfuݳAMTDg۔|z; $ӔSgV?a46]L#P2Ҡ{F/Q6WyI`IIr֥ @ȢъKWEF( 1PFmpBvå"xKvO"Yϋpc!h4=8qD@CoW`7cx23Ēk&ړt8R>$xgY>_EGwfF x R|)5,W_}i.c=eAlS9tjh 7HueA|P{y}W& cKYkAx~2`dW{|xfs det#ng'C4Nv ٢_Gv|cGZF5̱hku.i_ԃ32lw>?ZsYfZ޽qvFdq2uGoIjwE:ץקElr!\tE9y=< qx<ĖWVw:e?gFN UڏCu-yxݬb&*Z=W ⅌9U$$pV$'6kZX !楙~nP~΀%PpNM'(ESO ִqDAP@ Nn3g`9P˹R(!`&:@ |T"DW7mmt P*bUnn+Nz,ge{#7b~*B!PNb`kMz(8{hIոP>dL2'IEDy!xqH` d\Tp5;2}g=)%azRFx1L(*)03KP{4?S%/ <2?#GŠkۉ2z#Π S vh>E\Vz5$|>o: '%3{d6#Dek7)ƕ6uar.|rNnan9]K%9ܤDٴqry_zp swUL H0SM5`;_c)dDЫ̄5j0p #U 3x<\RᐪaAVTV\+dՏOrs6y@@ n#@ ;D(KĐ:p@߰fTcS3YhL 5&`OPs'U,L q 'k!8428,qyvKCM mJ`3\HP'(rתGPHAђJ3K@AK_kAxe~Gd uT]5Ƴ/#f?J 7&8igWeB3$ZwnCQ2ye0j)_6a|Tbn,V [;2.quNWZބ70Z`.bQ}[ϬhYD⭬YgZI%X'gXUP2Qv>TU/J'i +xKуLpBrEm20]01-hޝ$3;$ jtlWaI`IH(\)ď1HR@g4?d?g?j?nF/.%h jj ( X6pqQд`BciuEJP :9H &r8ޑna44P_u’v]#"lj_oz~s߂cIjZfE=PH 1\P B{̋X)d7#jd}]8X s!:IKWp Hp_v?j9"g[|Uj8̰BK،w|[;"ɤo͉~R2&B;-ASӥoH^aR$ΦgtȻ1Xfd(BLS\s5h8i3X~L5+O|?35^b$'Cmn+0=8uG!>i' cD75*, , N_;_]K~~~+?a?~~=NA{`8@1*H@9,9QóZuzf qsc08D^j5U=[U 9՚y\0PN`Q hSԆМ{dȱqdup58 9T I9^@NP* jJ*GzhLuhӳXG!$UZ~U~Qwa,Ǒlbw@Q #L# BJq46C6;/Uۿ[-Ygڤ$-Mf#@dXJj<Đy饗҉dZ++(R̻#O$9bR?gUӰ"6û=Q>?2뜧K_R.od>{S][_cK 7L%7o?a!* s]t;P}>$(]@I%9矒?4?7?:?UZ"ay~ԏՂz? ~BO4@Gv? +=oBfVfY`kne ~B21п[ !#Y < * SF9oq{)&לL@msJn̩#։Y^[{,x냽lZó2cPFd^q?;j^xf*霫D.02%{B]1pc `;a(̅0v+ E%aa{]m"#8bd>R#p#JM @IDATH3QFu9NQb0fAS:g|7};weB,MpH4Яr6ozӛGUÚ3^4I+e3U Їtp7/ [1v03u[r#=Ouf'aF,1b[̋#15ֆglٱ|!@\Ly7H!"⨋ށA}18>Il %l\UijIU,7j"X{  3D QFb>Ay+L R6HjN5mhKOBX? xm\20tF\dȟ2x<_&C{ss!|%2#m+x[O3W:k0ܮI~\${,tu7pΦ_7EKNT)4^We!P>P K>QQX= U,Ll $!1L7_Dj/ o è(һ6PR2;ֈK;6DKND |mf`$\:捅0zp?179ܲDӎjd+NlHP ~]1ōJVe0NVUY c@lCIj47GXScm ,IU d"܈§ "1EX$[qa#!IT&pbDBho|W썗RHh=5=S |TcψOYgO}&0DFeWҹ`xm}Kl# _Lr*gJ Ar8n:Dz__eаReB͇?̮qݢ1aQ K={=$I:}L27隊%t &+ <>?=ǹ+=*=gQHr'ğ㻁5dp2aMaUI3Lkl]Y&l1sqz,߈Hh kA/]mMpN'"-1H"t"6 t榶%&M3(C;O&otäiZ*OttAu/S1H&j@R^V⦾)q@edM[z|yf)X"-{Y@4lC6 ᫍa&u+\ϵxjl'W;:JɢǗx:IMnc#HvL44 h\D_&Φ U]k7j(| =Jm'J݀GFIÂYzqwiYi|91HssaGL4wrFCFMb(h`)A}{\ )HkÆ3QT%eJjIRvh45 o(U`{Qh3fSd-{C h щ@"ē@eU10 ټItOj>'"B4m~_ʀګ̜n^UȔ95KH?FIe찆`+ݟ9U_ֆa껸ї!@df,ƌzS_*[ .$`;kn 7*z_u[ٽYґ4-OeU9OsK''o9/wot- %)v44m޿3xU2L\G;j973T.%cy1(zNT Y~ XO3fMOSl 7?-/gxS.|37?9np 'ك`IY(!Tw3ڟ D {9]pQMjo*}m䃾ҘXyʯicYZC'io@ l:VvesLʖ70i }Yl c*nCgtVlU}8wRIoA|Rر԰ܖԘG+ϧ 05A_p6ҎPw怘;a0J,+)7p1t*c8RA f2 yH&*W0vS0 6ua;"[2:@pAt H>DwL (bDpH2tIJ.mz#sE?u U*fx lciLB(h KJ@-AT)a^Gs կ1T̏ qm1L3cIða JV3W(pc9`>$C@lI^وRoޢ/f)?3Ęe-zoz"-G`(DtO 54=&ǔsHu3"{WroR!O$q:Ͽ`%pɿ)9+]zWc(K` .^AM& ^m/=^G8b=Z7t p6aRZI*EQh{~'lpud>w2w4Gsh_tP+WI)jfrNrpd 9mv1>|G8Ee&#@{D@%*єމ0Wc@l=ba`gL'ٿuba2ь0CA9ވ)`YWQLm/~  ^^MoTF鍌 \:sXɛEaQ[O,%G RsWUTjfSQ5"U)0'4fZ6a0H%ݘ4B3L8G 13zwc><9:)ȳ|y %U4]8}su#@qNۆL^9O{%$1F__x0vhRc7ymٕJϜQs--$+(>LD׸Ǜ7$xb4N.T׻0P 9أtݧ-9';r052w:]([n:IV*̧, Eޕ1IYWWtHͿ_}kAmIDX CջaxazƘ}'m#cgLiw#y"LF⅐!j>eBh"jW1̠fE$&%3H bc2L8Iߺ7N(UIZلbʾ xMQpeWC(P-)Ӿ?jX>jzoӂ`lĝZLę( ?-LT3z ILp͍; wȕܱw>iCzÇ*ad W'Uc ԝ喏GG%-aP)AL|YHsyb'&O'WcV__0zLDfC-ɬy)o S=BN^9 ӪD&XЮx[*}S\scDNl|O^^"2s$%´~;g??=df/ZseÞuE(K@3hzx^i,9R;fNte!j+jԁqwq.q3FH}8*"G[aSįX}%1nd,Ŷ^6'cvCBXpўH!X=Qb M %!1FUC09!$B RtO&K AGfѳ+`HJ=2C@&54ŠE֥=5>|JHW(eZ j/ԽTWOՒ``6@fRg~0B" fIV!Qr\1ӻ|c1`>Uxr0dWQ% ٢r:LwifRHzZ;x;D)h|i lm\;2dwe\8($&7SsnE\sy8;~L]%(Q0p<ǰ4 Ċf3S5Y#罖Bck'LHO_z yl9Du㘌嘇}!\X0f^;Cq>ّ:1ۗ%'*>w3O Q Ϣ#3e|ORD{a#y@X#`b06IjDPlj.džذ'&Ū FΘv ]nu I.Et =!C8ĎJm>""zC9_J GB$0̸͂/KIa5yN'%bt Z\f^k*)W*(ʣtx%;~u\N L!xqTzfÀyH$Z7ed`f06$+zÐ]h8|1<1po'>!4]Gflr,5ywqG0f⍦~zwwx{te&Mb ^(H 6iԗ/56=\a,`YBbIl*Y(p6Po嵱F=SЌ65q1=|alTdzM+.d6NI>EP gJϤwQueA-3HWB"(ɿ^5}*{ JW\9LG[7c}S[bbF,9c[̋$ 6W@D$wT͂!L| e}L H щP4!ZwObp"A2QEOSCeP ES:TD QFTRe>D>@ mLu2(z}Y3}e_F3F Ärt1~:U/_+o < {g$aK>mO|:T%7iƠHiT]&`g05fy(aensK5PiUfci/a-Z: H| -c4wkcz)䚧Sf'>w.N \imji1 y_J s o XMٿ/&~TWB(*ĐGSt=5{6dl] \YddI)A,4Nsn 1] N!f|w`^L50%~색 T̅3bI'65^TX[cy?J8^&dr_Aiʄe,+<Ěq9 aH$]GR 䈯,)<֑7 )TF@ubmI;hJS$qhji aRF@S f48rg=0NP  7m{CKD "k S7z#=/7r$Kx}~h.ĕc߼_eI\@~4N?cx4N ̏zM?g^HQ19UM߿ŗe }K&|496]؛dݞ0Dqrw7?,5,zSzS?,Q mXR4+LjUK5QlfR2+[kԀdREq38 fؓ|ij- ׇ,* QU4_ޅ7 *5Pl'?d#M2F{_tagX'gX Ca.MC3Ycj``aC * i:Ğ8qDX"1lYifG$mLv02%pOC찔ծsR(R}RsѮYrgqO2s9*P)У6D+KSV:ĩr Zܩx KuܝF-9Cw`/yb(0_Hϊd%K+?ψ"]zwغxOGܚi2qr TYKml VNȖ6̋6Bl&l0VX` IS9󡭡gBsR p{~AoD":J=7&斔q)J;јL ")-LRj^`.-rY! 2^(V6q:]$korP72/:o D,јrAX+0{o <, I>%Fyʕ< XV_9nR8hn/ NPC%֮`%V"XB?I">DpOVP1AݰIƇ-6%Q\Evåu]q00 )t~#roۿgpDLaZCՔ|vqY W&/?$bT ,[n` Zbbabq[%>PLޅK d3Q D" #f$S/zIa0%>(eoo;X/Kb!vv*m %aBx!dVO#L|!98 *"୰d81nitSB:9*ʭ H>"BלH-Ri:szMRW=$LYM\za(\.+o 76w[7GM]'I镋Ñl^O- os[z2З\]TY =QNЗ\Aubu -+'ے\/dg #Jg9tA^pZߣ(M>;fݏ }m+dSٸE S;L* *@ 1:q*2x,bV\\S\BC*0O׾5G3l$T^ʯJxu/܅HJ*CHA"˾-AHAȃad@ d}C=0]N0)VŰ#>6 X~O AqD(Lr$wČB$<+,aQ" gNH*"+s2wAR-eT5(Xz4Yq5Gy_(_Z+m@P]?{A7Q3Y?o < dzOگ-& < eIQ@~ڇϸQ7^VōR/"aLok Y͖J{Sf8A=չn̯jmv2 #Il5f 1c9SmxaM.UW&W$QYI&p\}*Sp fX l% S/OHאY+7{1 eH-R=H].'2T&DCgT2[>*s{~ $?s?gGw!|TI,GͩW2gpGzNW#ҞEmJQ>b>@w0=<:Ns&x!*R??Vɟٟi8#>b/ ze7mt{E);|0|W,8Jo1|9ǠYQIbʲlHɣ?l‡W_ v d>?jhk\,\k ,*ȷL=dc]&Qb.Lۚj+haWי݌ûa $)dYFZaO Fع+dA%`|0`"Àpؐ`x0cOQ@  1d\"`!^8҆hH9 dx eJ-Cw"'a,x;tC%A DIQUZSsfAQ|__;1=p A/ RC'}rì$o2" t箼10po*<]`+IULߓx߮ $K"fQ$UR?ed\6HlǛ1na&/Bݥ_fJ%Q|7Sc f~rf2ۏ؏tOQp7[&5 DX#IË|=,x}С*wca%!O:F?F´4%BԹIdlv;RyWz7yq氢fLL ѲO.Ԋ+sbUw`## Q!Q9DݸGquEHSqMA'.Y -0i0{b?!@ '$G(m>CQZȒX#@b|ܨD(AJvՌ%KkITCvttKQCc啳MR|)%*E3O]PWCh Ag[&ubܟd;8ɿ ]sc`>x`P]\R3R{Il@8iT ܦ`RYwo}Q^s?(rd|IӕQbR2aE%¢FRbMor!S°̾}m1,kl*[f63tbթ¼}jC߲- RQrl&8LTKނ Q6wT o3 &רS2: Fu|U+`" džr3)jM}ڧ CĊݒݦ#+yz_Ж;L C GH=!6$"" 6(B͝ 1#iy=EX [#L0\[1Q_I ll)cm t Hbp "A\%ޮO"lã@cMl5kt1{P> [ekM|sxUo%NŬ)BP.T EEM DIQUEy%UMrT:6Uq/^9KNU=l `FU[L)*b 'L\OCWybke/=GLlr#MeUs ˂ֿQ7T!ʨ|Ug Ev:Tp;roVo9H.=%z PŝA lw#!|@v3KMˑT%[(ۂVNYw;1+7$ԉo:tXx4|G;v>\EKG!IZ !㩨 xicU/=, 쏆2w6!bx4d!=S\'PLX[ҾI;a3M9Rr% ȁz(&ʌKw$ƀ"oa,_bsKQvPE* !,$xLt(6qg }3@?kSsfa_(u8v."T?qf8Y l2 <bJY? vH:G]F_`a{*\s%I*Ŷñ U";._֚f P"(bZ 7@AŠwJ<ɖ5\О&msH@uDA i(jrb(}[WT7S|{Q)jL5 3z?3̏cM0L50͹ۻ!|TD_rg &2=y[D;6 ML[sw*L(*il %fy\N9\&.QBBxsS  }w}%`FU]l;-]1,aGIYr?+BO{ 1>^ˌ92e\p0;s?b6vMp)InaT4 !PL49wFʇX xc!%Uٙ2&8d;ۿ̓Lde3T* 2>Ü$׿m0Gg-e-\@4m bUD\6WA+g f$]]0 ~c\RA7Ƙkj̘hsPy cd쌩}ُJ""G |" "W &L-Qo0L$ x&,4j\T[&iC!~65AYPAFH?W(SOmi?]iL9n$yBjL^c ^YFaِhOs-7" 0T+h&ΘI32rjpcqb>uyZP%7"&19f$V99nNJ" P[йU)$ iSE#or#(IhD(ջ˂)MA\fEʜČ!aN??>BiR˻=D19U@4ei[ڸqb}a]ii5 `%]HLDk캎 ؘq3߹nԽLϘMPq-f)zK&F1u]p % 풸SN܋K,<2"rmiOo1P4~5b̝鰍b%u]A9uۂ38i|粖lEĭkixrW[Vs ^fsAAV1S)W^x~/N (2jxsm)oo797$y`yK(^K|ؿij9XAx\_݆[.&n$ʴVً}XUͼ֑s , =li( ăR'HԂؐ\j)꟤$Pkָz@{ bvqV0Z.չĘ ) Ē1#9CD<.E|(D;H{Bꍘ[& 5qGD=Og]bԒR6͈ј ?$f):3yPYT΍)YO]nnPz=)zҠ&9; &C9]x am>& [Ͳ]ycQa>xf.};ѣtWEa3SJ:j/Zcf5\C'y vP:++4]rly=̬ ۂg DxhAnxCbX8Uj>a0&lNcl8w[Dz|CM1aYbG<ݬ;H^4/V &&7NY e\>59[=:<=3P~h? ^4!c$+;5a$oAÀ@Éq֮7$s[Ćq[\;ufQ$ϫ6TqnhÆKN=2hrï!|``cyc[cDs?C hnX/YWe0]CJf8{b4Xq2C,ޅ`8uX3b¶4u32\!lzF$43rw!/l]]~#99jR|1+^j-=@!+< x9 le:G"ce_- 08F`FMb0O`S{L9|(/yGBї<1:[' n19L&2T\;rĶE58Q.lIQ }^% @%Xʄ ԪRۢ[zP TL !2)"Hdc.\eRO_c0@xz>+ 44h=̫ FN9f ( 0Q_P*͉HHG/KFyg2k*(* Ԋh1%EUi&Ջ݈Y-IRԫIM'56[*^/Z@. I?//V%,+o <6 Ƕ"O)}Y+PioQ9겟0>]w]$[\ >\O[n>;?`)ӝ/Q<|-5\B܉+x5ȭ͉ft-YQ v-j(ZIIۄz,߷LvL[6USqHFM{Giʾ@?i*~h^|#9wxVrFk0>/mms#igHe"Vp>Y\m:w25h)-hB[n)x H ! FI!05E2Fhؕ/eꛜC'-Iw9#UILJ, D uBf2zٹ$*b0$ FCrDVvQ 4HBTG %+I}o23CIQR&I:E KS1)DJv{#w߬P{FHLQ8fnpx7pQ(H اvO@3nr@Q2J+++RQnLg.z`Znwg3^@y ox6&bTic9O +aYဂQ(~Lؕ)gݱQe&tR0Gȉ1ߎǼLtd3#J:bV2e䁌aeGÖm,nNb@ydO`Mib e7̶#}ČC`ble1QNH,1&L:%6tĆ[{cn/}^˥̖:Fq]ع &Iwy:@85q=<ƥۼ0Teט#-2P|ԟhҔ;u(#<*5,U mqnފ;ٔsٴa\i|?1H0poB`<@Y6"6adpjDre[.t.0V.COQKa #3O#9haG4A}ExҩB2;xoQH)0kPĦg0G 9xdg !Bݓ aRkk$`j:׌(Sl>ᠷሾÖ2CŠȂ"Ĉ2m@fj@b0x͉A=6U=&N5Ȩ3857lCT.)M-EFjCsY)ntѿΙ{J5 eq wG{Cij\1Nώ ~GoM>u,q9q!xƷq͔G|4֒N='W.I*pW-t'[)d% 1._β(x:ȣp2+Z^o *X@´9yҲrc5kzs9b/O# `b|; \a!6'3ygdEV_~Jg'K]o*~m eӛU(hm]84B漝(l+rX d,YolYdv[nn2H@> $Z~)k Q:<4?򞓻v/aI0|=1i m,-C۰(~'{8"x CЩ!\&<tI\=3%tJA 'D1eT;{ ZH*{g9e\-JDhSsW˚|c6_90>s0ӻ!|DJ4K#3NA/|0j!Tͦ ;-ĝJf ;\qԹ ,7/QF DQc-F /˹(g^a;BpGK@|RJumj,?Q^˓. KHǢjWOhOZT{dJɃr5'cV5[T3!ˤ,܉#((e؇Pf_:|pjׇ |,WoK^ 6|}v],d1#ކ5u)`) ꒊsjݻE4Ҵg-[B[nn+<Ip!BI"]žy,S`-a%[bC(XcbP,?AD쩝u!j@E>Dr, QVy_8wd*Gb}w 2;~޵`D, Bd\tLN=3J)D{B;sQfmqb">zg6\CD&`?73 c^'˂KN$gN5zZ_$?ã{@)ꓪY:9N(5 :diLfGQ(qu&/ØIy`}GeVIk=˗l+݌Ғѣ{q5r-k]&ʔ9L>b6fw-|l`L|nҊ=ڡ pa.dņn|gPӃftR =`4{~yqe9L= +<|׭ѝ#9o KAX;l)\@}?!JNH1𜫫chl,峈!jq;}ZHĀ$T ""f:EcoLIq  ;` v6&ID0vt`̰&gm?y#:\"`!^Y<]B@SՀ$r{-s" ]+ d ^yT&5&ފSJM'BBG=jkZ#Ry`fSLQ!MzDY j -ꕛ2cChc#4YA(~73 sF= o*W;_W;zKztliCҦIG~Po˟e{nXf #U`X4P"d!&y9?WW\WKQ(5I,nٷF6:wdc%HN\s>qes1L\:7>1N]2=CڗSP).wEaJ)H2ԅˈ5At1ֹk2(̾=4? "S?|p%l*}yua1p}$"* 1A[0NҦul"4kH1dB ,Ã@61Br|Zd,`kS k$/|Cev e_;T`id;`l:b+Շe,#2LrtyxJ8qAhOD C>DA؍* gq,D2oiqR@585qIP:T H s (C' "'e=}`C1 8jf~zcQa>币y1*bE,,+m(^FnZ% ǚ xb.n ո0hp:0@gFB} $+OJ+X.8^"90]ҡ[Ie$1c<7CzL ͮe1(s{谥 3RmL$؀ydQwj!{D@Rja˸4[Nari-(VvgOhv,d7slp0: Y ,D=|N{+ȖeZ[MsvԔ`badĆA^ԻY&MTZb (GK? "v,'ZCf-d15=kYȑ:_% M[a9܋/ n.f @ L&D Btͼ"H{譙΅ijdOT&*93ԘExã'>EJ(jrbnp3?k蓥F#L(ֹ/g7X 31Η2v~bT2K'L *w¸kn < {r]\`MC箅\mҠ0*sDW=sDs[y?y%H7엺w2IT׈QIo;h<7|z[n ;[sR |a0dL{)`U <{;ށ:9!!GƲ ?tՌHMۀ"zo_tbQEgҵ8X:PB Ha ABBN i!0dA ( "`d $X@S G'l$siuٗ sG$q6X]~]O J~(h:+Wr̺@kh! pb|퉜E5PeAeP`j᎔SA)PsYq6ʜ/mFS,r&Y'[F$>ǰnDBq2Sxz H֞#VtMUn 0|bBmnZ[[Y+>t?4wuyPqIΈ\'YlU-kCJ?y cy8f^r~4׀-jŌ\c:]ܛJb1|q;?"yvO4"g^jST> QCN$,!p nb5\R 6caMj6jctrM&P^ a2zȨB#ڏHYsl^rQ>|^tD02uL ?s(YºLtF9"W&u}yΐ\jHNuxQ&RЌpO6?AlW/59=[S8IJ!z!9ەjc!,E X&1c)-h[b T= ڠ,cUVF efg3F;[#*YҕD2֋XcbOL gBcs̎ΉuBm!}bmY*JD:#]'}GS?S2s"@KyeM$@kt Gsp jeVۤOOȨG-3GƖ!.;V|UbIX'w邗Wf@Yy(6)9l6+ryV!DHꁵsBʡ`$$nUMkRțqlOnj C=I 6K/=FlСsV5>"Y9>}Ϊ sJL&Ptko(")%i[݂ ` &s{ &n2X{c2i G]h|K`!,GY|qA 8,Xb9eGlH-"WD;lv&r $Y'6.G^$9ڛq M8~Ӎ%DE=!Z&IxRz: :e0?E}w(* ȚRF" ʮWnʉpL7mDPT6ōA(q2`Od* of c`hsRc]sc1c>y峼 %Nx[EɬgAGcpJ+HՉo c74L|42xA=Z<1R0̔}ziYRO&,Jaal(/[\򳇕Y(YϧH u,{SEnٮ X.ȭ犑Yְ'kR)l)Ц` C$OV9ݘ⿯cBrjtojr@M!s9 +! hX4!lt -eKdM9хh(y.mX͠:ȯXKc,ŲdeB[d !Ē$ V tQ[b42&J [a 3bIm'&y_0F So$E,Z^ 8iI|Xz7B#-G=G),a뭐!<<$2 sMQ󣡆0y>/b]$5:D+AR")SOS=LR!i0 6dYU?+3fxz11po=ER= 4&ܩ+t")޳O~BAX6|ypJ$%4z|gn"QkhH D(0e-iT[zw\v bx)bm`$q[S[4)x0:s@ڧ`N6[V*39cMَ*'c}Esp n0{'DX/ˬQrCTR:/ SFWneJNxv CXOewDIJׂB{VJYY}*gzg_~^_5\?3;3eу?]z Bͺ Q H ЛkA^4 a- >mC"DT )2ClHik88CDlJx eC<2YzpXC`$v+M"pKD hH=hZ=M ˠGìa.'T6?Vљq(k!6b?#XgX8CL<˨6Xj\Ů+.AN ܎"v9=R z{%VaR?sm,t-N- ީQS{?U oxoP_W)L|tM$ `.H:LWP K0L51+Ule,G;P4v ~F="bx4Fs"!a#A0;Lqn^,+~QxAF R"H9|͖tرgF;`:F&5] nu+ HaflxP)Pe~zcb>EAz1#^;{`e u=51DWiՌדT0Dm .ooGO*X)יY }K:x#[kv0A&"u@"zh ^aVwmw]@ĝZX -!앎b@+60i/kngJnPepBw`nHn 1ė b_y]ԣ$(,NFQ=n6W(8[WA M)-;jD͑0,ao{rK"ϭ Qi)k-E]u:FȄRl3zrXKc,[ e]G$H)8 K^H׌􏘑tw%29.%\XLɜ4ƶNM,IN= "h/4bp#:(C}0Xeej}=Ƥ1AMPǤ>35t44 uxx pQQ)JRrx>fQ;:vCiafF9x\Nͯ57`"[ _hU"y#7Y5ꀹ-/\Rv%FXlUg/Η)F >L+T}򿞶Ԁg!ԖJo+r>9{Ș.aTgn.k'2Vb_^d]5nRfZ8$rDh)-e  Ā$@$I3\G`\m5  I(5ȦSQl;~p?z !Νmw#@D{, &R?-4EL[  E0V妐6(0l۪a:E\)-\.CRIDIy5-CrI b)G*@ϕ٭Qe Q3z`Tho9~uh@5_%, P;e/VP;@Ծ)21)S3,)CT@0_H: z-%_C3XDKm6vG8H)RA,s,(51Ev5vʹ0 z & .2ap8Xg T1DJ2V9DIH t'l{Q֘ }RTŁO9QFhb()IaQ[Koz|#_CB{/FWr.g-1]w͍Ǐ{CB($տ IeoYO~NW.X,Ӟ2ζ(f9iz^ٔ/#u-Cmr9PWW60E,{^>;&s<|\C4>]-&쓝~6qr\ Cyŭ $ xVv rBTHC2"Dq"Ѡ "a60BXIKl槽{F`XlKbaagL 3g:'" BG{fVً:W\D_dUB|,4#B;;j|b !Q-AuEJHvV"vEުiOi^\{8hL)f40qCPWkH)(zbw Q- 0*KX]{pP~|f8+il1NϻɺBSxN5 Lȟ}cBt(mqsFya8w.@Fp"4 y[b>p鍁lj{C8E~q8JA=R_ -+ hˆ}Sm4I^oS:?;iq3HH: ~6"Sf ӏuᩍTvI5Q#)bU$'@' YRF1-(Ρ+b`91y+O%Q0!U<Ļlc=uB3dc:P@|9 }dgrBhcwC6ֳtb8|6<6i dtWYxPmB܎+6WOOd^,Y@^jx2bN #KM_$P l32M5e(P! $ OG5[S°uw&+64k^? 1N= bо.eTQF&X=_􏺽o (EN5e9)4ӹ:-kLVz@SK"antLFhq0c O7P0poPV)YQ+|ɟԒq2 s=:̕+_+q27:W=nKV/pSA+(i 5h$5 Z3D1@0A3~s}Fש9gzZOV͚Fjf혹fN1pv7}xb(GbW 7Wȏ|.Lp+96~6 a Iw Pt*IŀKgrF2XQ0 z<كms1;=b7 #SRAjٕ!NeNH^ҋFaj vWqUǵ^4__L:-c Gf"EW<&MTO5|1(0 Fc /N{VU_8wuKm0_7q"THiʫ6c`oD=4 0@" ō es :C/8r=kDy;*DvL&%tE8`:%#Q.M1ed ~->fM\M2ٙKSXUBc*^3QZhvRYߦs1;,.U%K*i F%#ub;;ӸvB>4~F0$ҋxAjgyWL_(a+" 3&=k>4jCɀ:݌yQ\U pu0wm4b2Q-&-td)~ńIq[+jWLѩI"K@-4 WVTC%8jbh Ʈ}l^X9[C/cc'`IT&h.Bj=3fp'|nlgFuV+3*G.U_@L[nٮuS~CP`*md](-/}ɗhAfJ# -T԰Wc@Be"+N+*ZTCebwJ ʗnSkjk>&`rwacFdV1l?3#>.@IDATYLɰt.ѲW״$0"!B?Yi#Cf(}Zu k(`PaV3SUS)oOud1EM(S JMVLN h!A)QLUUt D=&0kGjo [**`YQKz'ŋ4Z*r <;WeeEo!^d;r?/ "3 xXP Ɇ/3; *4^Z!|Qѕ9l{jǠ#9=Y4_\ų30*Mj(_D>/ st?__lC-I;Kc!M5'j6C,z++/F|sK5BJB1`b؏#.EI~zV%5'8rPV W9K}z% PTL}5J492)uuQ}±)gq%zApOw/*D%]@xPUx 9DBH $tj؈3I9)l$Cfzu|}kA3rl1LL)&ӋS gg^>cr x5]u1e98b,+:tg, -aS>W%rsOֲU0걠a?@0Xa =~k-omZ8 k筧M`#;qeGGjuT 4=demRlƍ r{-dxeᶧlF]kz6<آLr=;U97S&W׊xu&0^INmf`e7`Oz @WI5~4Yǂr+ǕUdL‹OqP~s8)чP_l5N CNA+^y cǰb9ɖj!,e9ekH\Cܡ=" P{ΰ7HT YUM֠U믾8D*Nz3Qt9H#le RBs7DhUE*צּhΨkllkbV``av+&{%j v̗VGȇ5fqOnO:aOHy#!A"Nh0bv˜TJh.&t.^> `nvӫq2oMz`0QD +۲W,W&Sbx:+m2枣YǬNcLwmAAiq ي`镃eQȊYR%\B 0gwBo[>0`PCr0@$B @+/#+MWtV,VXP~ _RHٞحOO-HX:,W;6*S -#O2 f m ڹ8AB5 \$!y\ьN$ [_,K6]/4`]'ne ],܆a.W[QU&н yN}`B3ȶ;H@[T:HoN!-K0@x˚ǿ)zY#t&HFY:hSG[-C <̏j*ꩤV04P3d |L8U,S= FɄ혟tbJѕhE# CW!H tch"̷ڠ1u%Us-qE^ d 1 sݐ|Z5FpÔ, jti'1Ln/i)tS0-)xuFM-;]T)K%_r*-Me6=J$6k  2md"?xH@B3eT:xhvsU;ˌimmu4RK q%% g!:H ~1;?Ĝqt9FsRi7(֑21@XɸE`<4ͼ Vh_\U9e~r_]1Q+FeÉ"ĸbp/9+纪l`޴c]\ JGM`LB q B:Q1ܖ<b˃9L.*Ev[ &T\):Ŷ=g-&8>}eHtj΀M:`)^)$GEz*$!Qv%u-EccBl!!:QW"ӭىѺ[z@ UÉA"Nh YcwU:b|n8*i >`şSǑh`j!|pi`84Lod6Hn 1Lk1|*>+1tOM#eeGstismb,UMoATo4_˥EZ@bjIZ^5uY132c[-~ X1AEem@sq—#]68y(;Ќ'\>+HܔuPæ8ս/M%>p΁L;ĶZ-*hrfh˭J_dX@N2tᙖ{NA+ OtDRt=FT%Ks .ewȶCEy%;k`b}kt."֨ȍ-5qHlXl&$ߏ\Ѫ66Ӎ`.9by . ݩ{;MGgr"f73qi]DHx\x*"Vt*N:EZ"H#ȇ)|U@5TFK*j&kcV'08:[W?t:CuީEbCxFL+¶ V8~SG!{XNee 2 =51 jU@Mtn솼oC5]TiC*L>H)bBu ssJbBpSo>zbv[i)A|ݑc*>rtKkx|?l![JZ-֖Eke保Gt929 엮́g>~?o5 nݐ~:<+mQݕ璃__s58Ըݫ?FhvژlobY?ȷQQ`YB*;F9Wz!G*@ GnlqkUoW}@ַ1;{ |i)X_3p#6&20;2|S 9 tj_Ps;LcC1@s HF(~FHY#{@^Sި?- dHm"qL>٪^Rd(q'h xvlI0j²+1+;tAE::a]OA&=T U%fk#A%& (C AahD6X 1CI/ia+l8TDn njm7z5#6UF6yNNMYMΧSf?:>ZDҕ)ٳ YdLB>ɡDzqS<.Y(-MK'aZLjfiiAW9TlxC 0k@+מΎqgcno喲*Um ;kp{ `{ܕ_Y>~w}3Bf9>!$ ^5ZH1q2TOWeĿ9B"~e8*DPn_ \HȾ5Jew.A< ` hh|th[ 5n lA\ݜ9զN+=C`2Ih!]X wW.v!^Azn(3.N.K5!v }tzD&5мW1x&^LG/)*TUY U[5!5J&+rsF$bM~]hF׹x̟d! ooMg2!( -JuO O2 0!:Agc߰EW;bfZP)bqM+2jPvki4&o<}{Կ'W1z鄓$ #HKrctXz#f6 ѵؑ^ XnzUeu\oO#oHb&'c|Ҏ{jRkimDLpkĸhm \]*﨏#@M>C,ne69'ckr^,qu]y'Y #pc.rtdޥv^KdQmxM*Ĭg4H/ոaڢt.`ߢ ~(YUpE te`"p&GMf|ҀS?S\9?6Ӷȓ{&y(_2Ō#.ǐwZ"RmQglqՊ黻[zZ&ͼ~]xĶ>\P&k5VNRM1rCQW*F>"5Y899qK;{SUyF;ww ԫ8)P-`E2׺h/=,3iQI4W ٭vv\cxH2AKCXkpJlW&8eTޞ-VC{Ε1nV:EwT0\孱H'N?Y2¥0l\` {`MS$ixd/` SavfhD`2`n.c`&VU| 1)@xpu2&9G!Q$2"5H%u㧁`8Tz̰5G+PlJ#Ë` RŰM4h˦s&|4oT1ˎaJZcMȦe)ZMRua ,%ŅZh,7iQ՘|u^AEXxlTLIlYZ Bj6As΁V]0lIܿ W;Hru=i>;AZ/d a?AoI errŸٟ9 uDGKa_]1jSOxuL{4y}$L]_̡lt*]h,w g ܹ啑!}=V4k qA,=^e*02:}} A1dǠ6:@2}CI=sم:!o;-@XTJ aLpʩJBu֣֔$m\iU4bUQ>^0HQ7L: F19N6>]uj h9 UbCxBF"`]Ϋq%DcL 6&D=xf(.iAjaP'&&MCKΦ*n΋Lf:= &|Ӿ`!|\*5yS0E9SžU"i)~B- a?>b,=k@+מQLy {;d A6?$[}rOXU1%3W9c `,R+"e l 9J6Cmr"Q%rejYq~|vZ~}ѹb"`aVG_3KPe-<\\@Ki&:u=||?뺅JMcvҕr] rEo<5'LGͤ 2XsH<K"a c %ieCsĺן$HF7-NGKA 1 D` '*I!$kN"Ҹ{¿j^iZvC [bWS&ڋބp(M2%SVcLbGmtwBf`҄VҨ&gStm6uM&sSj8- zRql)H˟$+)#iգE`<:WZ ;f6:UP/~Zp W%'|GMT' |r^H5 25Es mu Wk"U>#?#<9MtxeZQ+|* gܹ#:=1n46G~7slU>hyc-[.U2Q8"Ki9T6iJϖp% (\ |9rus2BMugb6GLg3 yƴ1cwK;M` %}F=hiC>}̏-FLdU +Eܾ`N0-qmNS uխ:7b :}^ FDD²Brx7!Gc~`@cr36֎f1UTp[S JӋIfa LS&+S Mbif/͟)?`5īW&vQmkYaSI}/'aΪW5x˫",s**9Pjy%UVx9hE6 ſ7lZ[")IUmK뷔Ea$\Nv+u~rή6xh0 I9˥ HAW ,Zs}aY|@oN|IݎS"Rti*ҩlUQT>W&ᱪpq&M^Y,ْXߨYW{L[.U).r?jr#uza< 3o=ͪ#/snk&[@y9ې 3X*$qjeulcAWI˜pKm#Νl_`Z_b#B`vǀfۦ " px'w<ܜ ;q.gGgSs%R4g0z#w#x+W0 z[! 11"mMso|9X,[8n'*Β$ U:`ɋC .)CJ_,Y%1v/bUxuhuSW-fa?[;{1!MlM^KᎥAl@ꑗ"#;&#]}|uI,SBTnMaI@ \H{6awGP~gMxJ?h!OO\i CY5eL-VyPz9$CЪY'}m^>%iL(]OϮ-!;Q9JW3v.a [lՇܺTz;d*kK%"F+Ny[%9j|jL-úC}tM:K8ݧuuz X>ʭl[QAeǧCQx B1gV7kl8W0#l'N&ӋITc1|LA&"ӑI)4M 9qQsdb<%8Fl\VX m\LTe O´iɓ7exJ37V&ZWmHP pK}4^Z!|ԕ&loN^Mٔu'zs39.sEx9m!|YH1"-n?2?BJK(j= ~86A1H 9nl`9v)SS$U1tdJJ*ˆ(lx4bvyuU򳰝t|t{bΣޱ-ƞjVSV d \y'ui|JLBT e-BA (ZTCeTIvIr(]L ; *G紦=.RD:T^'Q ɭmogzisu2 4í>`h`:uʱ)R5L Da+"Ǫ *GR/J9Δ9fMyYLM;E[2;n#I,L!eĒ}fwRS@`'T`iN;h @+/#o;8v@4bL 0tB 'Zȭ4$v7{eo{Bz,ŕjʎ2bΖVBTl^(z x u{=K"t&:|˿`=!\Xrxv pkBo4Ggs GqH)Ώ-^g1O6: 9Ð7*|MarsKSoq5z~*)YP2)=Jꘛ6Fð:et\`\;C@b;lHeN#t|\0AO1 %!Y6 g6 V3u j29m1%sBKSܞcTSfq$&*`Lf+)2k,I:ޞ>S C%jbNebm6ERnA[XɘE߸6vtQjE/~:i;98?Uh!994~_Y8y/nw6͑ w 9%=_#iZaȭk;|̾-5=&C赦z{I5[#P)/HN.j}\q]k)h;yERh"M1US>Jsk#'H-aѿt#Azվ+@Wy&V lGQ_c@? +j vQi2d^A*kB:4SUHՁ8eEI1mNY V;[< ˷m*sCcX%GguJLtZ=N4R/;`& U%TF tB[na=~'AjٻLE/; bTAbO]ECx|>ߞɶ߶ZMs4)9 I|{{Өg ?]ę .=.bxTƍ TjyKB^S%R ;9J9 +6] mXMk^؁QjOkNמZoR$,6> ԤL F|/֡tɖZM_Znn;-kh._ _CUi8v$8ڄwH4IG)Xpz{ȗ (f܋(DT1bA*P`q3 ^wE]̝/%8UuXr`n>NH"Oڣ+A^ <4?=19G2,hJ.%Vۿl: e{@Z68 ]0"a>ZEGDBqҾ -D Ӣ*«/RGKA6 7mFHb J08͖a)1%KLc,? 6 nbv7YTorGyʦ*ZgK 5[-j*xK[gBOQ(Q!H[7 7W cZ]~ zI4' GR쑼03^y5l]4IL;15V?Hx>㇙ DnC`ץ+Q2ZU3\O7UvmSO;>|Gno}]"-(N$E~HE_(jB z+ʊG ~jU\ 9 (y>.^n+o [P =.;W2:<36e[=;:$F5AsqWY]oqn(3ߊ3U$g.>miW 3jxw񀒞fboIZAnBɟId=SP,t+VR,5u Z^M/(<o+\rd(nDGb3k{G$HJ4g~38^Lt*9 5LVa4Iz_Q8*̄}V'Y:wa>PB^ |yF!esѲq2fu3RdiW(I(,$NM Y!ZyV:N'uc"5췂4dk5ITlB6-M&j[TadK X\,1ˍE'LbY,L'ԢE8-hWQI,Sb-{gNN>  14as^6?n98з. OP)GbUعorbn,l4ڝk[@yo1-pN=cN\kܠxea(X$,okYAw;ⰀG B$ncYT[8)8HOm#$>K`뒰TMމ2e2**?\l;s,yo٧&P'Hc#Ct!PIKpmP%_f `-d..yh册H[ xZR"nP7 a|ҨŖGETO%UuhFiT᚟|0[0QBdڬU $*&CRIB(AUn\o M,&GL0ƬrtCM*c0iT:`"ĤtS ʹfr3ř`24%M&IS ӴHNeb7M&|Ӿ`!{a{G>PSI-Cc"li=DnE+RhS1wkM;ThzR/p7]])#ƚZBEVM<ͽNJcGTZ@ c!bIK֙[Ό٩**&G:G}@dj_xC1yUy rjҕ\i& u cjx~\wЅzS؞R'VU:ס)k lt#wdž@M_^UfqBǐFN+h|z+_*)u(TwEk=cYvJA+XlY#gOc|{}cGgPЌqRa8JJń;]8ƻxUy%zl,l-uWɤJ*)omJ !BQ?dڷ9dEIAo)ou|Lp#n|MuI3bˌ8^뱦;&OP@-a=2Xh@KMn8 -i2h;uC0 5t$9wеV$}zLq 7Fn&Q%o98辺Vu%m [-Z_ik4& 5٧"^uKK Z̎"y`Spt~"S̽5PeV"8P9v8H 5YBQL,Z EnY-po5v'vԫ\zf|_20 {6[ F׊pȔ33 u"zMcQREwHr_.)~e٬T'Frcb3!H4.j[ ۨ zm]b;,iimeQ@ېTsKlE)' )]@rƇqy  *^~rբ4%ʟwU mVYLzxOr\kv-+{e-J6O[ZzΈ^Wb!n*ßv;Xu"ܪWXgsd1Y|>?ՇB%!5 svk 5a2o@3R8blлLq:}asN*k1kD} M^)knx3N)T9́汝=_#kMX;vG6^5Z!|ԕZ[8\z JW]l&r0vRY2iBoLonHNtmo4k6I4ͻגC&̏*6>J/IN>*L8_<e/SB\G~Ty-}W+oi.HQSmE)BTJ/_ Z:a'@EؑxĔyȸEюhP,Sؔ\@ԣN11P[VObS8{+&]V6Ѵъ_\f69`͖Qs-ZүZ$^Ḱd$ȫJS?e9E(dܣC.02z栋+ +)_K&pjޞ>M{t)Y"mSSn_We3X;_U0ONY ~R82BW8 L/?H mc8Ȋwei1rkcVfbGIW+~9k)1[a2!հ'Bp/IҲ%!-/i*Cɑ#}}4)U}vb7PtcCCC1{ҝP54BdUl@ a6dT$U9LpKBsaJ*F tW5 +hMZ J@%s4ÈcI cji䬯MtkQCFӀxÜXmĨIa`gaALMM4p%8\og$!fBHfvNd'Őu6~Dl1NkEb4߮"ku`1mi cb"-:zk3֕ES0]8PhW0M9J9 @NR(-;I9IA*' .ɪn&AFSP,6rMvnv0bHbJBn&qI)LB*08XMGw DGg:'7Q-H&sݘ =6[Qn<}t͵T Q A&+9Em +$v6c65c؉& + SFCIzɎbS xmܱVM ϣO"PE@jJ* ktWfjlj>&`E1d]U ^a,o,]&Ӊ:]mN#Zu)Y"Zj l#10 O 4T XVnl8/&aSAnyɷF! pB+)޴]՛^]=4IDAT0r;}L?Ti>x[F_lt9'vCgQ[T<63l&AOnQIaۯUҵs[lcbzKmѮVQ,K)ao&IqUh%k79 uJЩ'/@}lbq9a(S19sST#3TxL0@ġnZ^E農 }G4CMS ?[4"]?ON 4Im;V{SUը[EkAq U ʨJV*h#s&1@lP-*1fl|]#tN5V8aō걮Wb-"!1nǬ>caPaJcD(aepMz54x +7 6-*rJoYos[#7zt9`>@,yoT-:mrÖ["hJboų8*c PHp|u0Ƿx?8 яۊ48ÜM"~2s7,Ҡx6"͋i3 M//4f廵Y8Ƴe<7aS7m&q*:[n\qףd|ݙ̡͹ u2j\puTTyIZC$E4,Cד*[~1A߬<CI47IfxcToJb>Zd? $Xԫ\elTLZ!|Z`fӠ 678fSDh*BgS$Ix, `0-˭-Z}tRWM>?9S='s-=cbH[%A6L ;ePC pnr;}$|Vyi#DC19/ol%S u`;@_g0y @KDƷM$x%h&3cWz F,+RVPUkG#R]u!fz[#w_ ˭ \ 1턙WBB L6X;A$} UOIv, [M<,&8DhTWۂlzSx49kzASLؾ$R,1ȕKX$yhݴ\Lh]g>ͺi#a@݀`M;MxKeL {4@;MnM̚^> e߁e?9|&] ;pvۄ T%J89{YnM:'W36[Aa *nڦCJa0].e}P]"SYH 8}K` R={CJi N0FX*tƌ4\C;݆25w G qY5ę+2@6+v&vÍ0cWl\l&T=ebSĤtǍ\Y6}KhA$:+Qa,)2f[kl\pVɇ(TS Q.: sm‘34sUbʓsӛ>hnN^uWetU,tG媆JXα!U&DCT@%׭񊿪@c#*̉+4`$|w3~h=i* b)|dc ?&egb|{vsqVw ҌN2_]S+J93DƦȵr_9/t9]!&b-˞ A^XAC +=]fZi ~vj/2(56s6;ɓ"`޳&hAg U%^-~M#icۼlL 5;MW߶Au9t^*dƉuco pT? D$a geI9ꮆt8h-R,[C 8)lC^A/_PlZbHso)u!Hrh"%(Xu۪^ ޡ0 :.Gv $! M=Ye,LcVલ"ZYquiYԞXFŠ c-K9UE3{G]EBq%h/tb՛䁂!ۉ476:b4oVYqp ma44LJTTޙOމh.\4\GЊqebDC^].ȦxS1a_$Cki455E0M& G#6U!ͣEUC~B6="K¯xݡgH=Ϧ]Jssw;WF+r[<w?[X 3P ǔ!)KՂjX[޲QQ3oo6y$5 W”+r7tB9.G,~9R } ?%#}[c[a [z܇MoS-Mc:H1 EI 1ptNʆSjv'` SX|} vqMyHs#LȱlyjH4@K3 1M*r>bpo_-?f$NBl0˞Fw28GtKL_%ɑL +Xu\Oz*x1eoQEXU&\v6:&`G8| w-04\l5 Zю <dl&J⠈D*ӄ)HŒvD2*xx6wֱǺM,T$+蟟ע=I Izl$!"'*G{.Ę'CX97*,miJڈoVR{2@RMB~QJ_; HoV?@ WU>u~nEJHu|}M2a3Qow) uĩ'=a,2d0eE>٬"a\RGOQ2odLwj$0уVAG$a:ZGdN!1E0ә=%,?o TA$6-=UzNm9.ǚ m6vڲHPdcgT_v|@IU CF&舱";z$Q`+)N3MYӫGLp-2Pg7B~㳷"Ŝ XڡGp6fdn%yh&k6+Y=6KV/o&9Pأ Pr[u@{$Ol;cxU[c>Lv*jv:Fw,@7!:pF}Ԣ ѕ;9JgiɁFA34X@*2HMy(+_ P0{Z|tٰTyZav[9,^KGOэR,m=4'@c<<hxP[vGbaLf1$sT~//#b NSΏ>%KӂM3{H 3&)/(+vKg#]1[ӣ磽`4,)%gSye?1٦FtHf&uu" R:Q9J>?YOLc8U19.!GSd?zlj?kgN?mnLB Օ4HxZ%m5ߞƘl~D&Scd[;*'n;Ϳbf0Vkʼ7Msrw]oq>"ae֋ ',ܟ` hEY; %w*.0gxƴbڥ5I+@* Tgi n@IՂ!?Zv`Zgfba̪~%3"/|X8,멾0"TсOV0KJO~i^k7t/! tgA!᝝/6a!;BoT<6 Bz; 9J ѕL bMsN99 KyCΖ0ȭe[Gms"ȃ? gs?䚸޲ AYjgͣ/ %Bj3`4d6gc : >aM0\$h>ҿexA9m 6Z8nGEŅbṢO_oZ@ 0WdPO}1܎҆=+p9|/<94(K@d,BgE>$JgX&E%&T)"J 3j9b]YoI-Y@Ÿs`0 Z~S[ @vAL tm c𾶳'rc4?ʌ]o~lNcnXtYz-95->xʡ`"lMa"[4JOJhn jvQvV:s `rNhrL{Iȧ@sLw'j4mS-*Cm@f7? AxH)lozV /f5Ȼ B09}Cikv? J8[z(RAkjYe-O٭L':Wkl#N6nCT* T5y?A%u]âe#RvڢjF)frU cfFni`(|Ϣ [%˪fN:6^,nXG44T * =o)zVp`#@21bQ%jgO2p&[JМIzR> vkhFDXMpͧqaE^a_.LK_xb0{1Y"tI>:Ky[ݤCL$1[MfF"`'rQĕЎY 6&D{oT3abI!oSަX'imui MqZ&=S 4[M 5=\Md^|$_1ˇy~ZT?XDL["iEP1bAӯBh=5g]F$hɕpmz4Vq*s pa3; ߲Gˇ!w`n d{ar ൙ʖ3 &(g6.{JLdW{g fyy <ՙ.ҋӺGDz |#3՘܎884@,J+ w=O* !C 3񪪳8…-@?G Ffu!fnuøL 2\;hǝPgp2r{S]ب4Fu~筦C?ڮs!X`v6A[I0)B&7K,cj#l/ؠ?GF3OnJ3+@S g6XҼe'#e}RR$ R7p0xp'h8ß~4|pi3E LxzTMQI.`DSR\5lY4LM3@8YcdlN|Pg]#T~codo :w߫eA:Wdw'g:$Ejw-+- Cu`mVh5diD훭"_,xH@|4`@ pWp?0خ3dHTx>7yZQI1}ag-&g9ƹaYr6)9`Wl4ؠAN@ցP7SݹIAKv(=)a:$fY+Fa :[!;'0*Ƚ 9"h'*i5O@fE 0dDga)mJ<9ZcHꯣaR6pw| lV1Gߩ[Qs~t蓊Ec& xͽJ%@'$-;vu=kQy8A"sBɕ1ǿ>\yЭ6V0)itE4&}"GD{c:x}09p *"v- I`>ׇ,c=SQ,P(ƹ@ JґX8a16ğ3-v{ Fxʰ> r} ?L9?4&f#7҃/1L_җlcVTпiF@mu 3sⅅ9CJ[A䏽 Gvk̿7](v5HJȦPD"1uu○ ,yJҵu*f\Lgg^w*i]hT"B%Pr1HΪbji*jTrJ,3S#|]pJb:QWx:4HAHdN`JJ q"Tc*"G!$k01&hvD} 01X A闑3 FtVM,&XUO1vIJKh FdHHnXӻI ߴoX,-iBZF-OZ?WDPKqJpK۫HK,%WS<0cs= k7m9Xve]Dorh*f'eq&nƄ3@.8E"RqC򇱹 !(;hn߷67jc##e"QKa R#mCZuLeq$x(95o3jz2{^TIbsJ 2֘e/y,Bϣ6`#Xx򝓏L+ƷX)gȌeyLL2Ie;)EVoUFJjzM5a,HX3#Z `H-bl^a5@GLeR>(խ/[ 4$JlJE#È '%0A=a!Xn%4 T:`1d B4 F00 O X|N˔nI@&ӂ!z2i =Z ,20aZD,%bfqa ƐLj ,US߭-R=t8,̧k)xNtds@+e>uUKp P6DmЇk#~*ɺ-v^guPoOD]g{~3ΆyekYP^vٯ@i 6eVϾ;lM{ǀZxW.vsW19 &|WC,I$!m7L,Xⅇ2˙Ra(ƎN!*D6`UB-E`qe qf(1ѓ1́]t lGf"X,Q+ b;ߒ @`o>^e9 '\80p%/>9_jhkEXr;A̶}A?|rD 1po8iS&4f&ʟ]bq>k?H,xWh򕄧bu\|ks5]k&ĸGdѻm(ji󜊞@rlVP+ w(Ց } 6zL"`7.2bwq1fZG*n:DM+sv6cA| zJ}baKXL=GR"+@αNc"C_rJ5%,hLd([PJTƀj|9WXcGʄEK´xC%:"5:(e:Xk"!1YA+u Z,e9g{$DGDF7!W0@  Cɀ!VĆhR 97l=E/ `ZsiAťKboJ3v)lMS&+ 7qLq&:ӝIO 4h24%E5RSdJuxIENDB`./nsf2.4.0/doc/example-scripts/tk-horse-race.png000644 000766 000024 00000063256 12501766547 022260 0ustar00neumannstaff000000 000000 PNG  IHDR`YiCCPICC ProfilexXeTU]^{y..i0@BBQJJQ@PDDBPQEE{?wy\~s"аH#]   cee׶ @㒻sno72[^BF!`D\ }l$OH;%>'0 z45<}`G|$BCpxkaOOszzȍC<م wGzRX]n5o7=kihG [} ijccGv__{`{0,'?MAv$[J"'#+;힯l@#E!Tm9cy$lq g>d+@@H9ԁ60gA HI dӠrP k <1x ^)|`lB@8$@d@ΐA1P"tʂr"T݀nC]P?4 =yh ڀQ0 f`!XVu`3p< * wSx bF$Q*(=%凊DAe QzT5B-~h4-VGt6}݌Aы_2#QØ`04L!2 ӋyYbXa2 &`ױQ vñq8K'.+]uppx"/7ĻB|-?oRR RQYRPʡj@I#4v BPO%",D>*њH> A8CC/F,0 cc5aE&z&&8R{LS(f!fFg,\,:,,,,c,kڬYnQ ؂ΰfG[d?˾ȡ͑L\2 *ϵ̭ĝ=ȓDѡP(=E^N^cދü||||^Ux,^R \rJjf6~%By"U ='X S +ŕωJ`$T%$*$&$I:uRRRR-R_]HIQ y)K/k*,&$'&-W*D,o(TUyIEE tnm%eHzyee2 F+lU]գwU)E5}STVU#wO՞ > OSM SZZZZ}/k\+ۤwXSo?l@o`oPbƐ߰pH(clf|x„ۤdTi֬읹yylajgjް-2򵕰UkuGYD>[[wZU;]"145kSNNٝ[]p..]V+U5~qBӸ{x8zzlyZzVxxxy-zy3;7?PX=8#v}XpXqF§"" "#"/GAQZDf(F$&5f:V34vqtqaqCe7NNNMLJ>sבGS~8ftJ!)8QLrnRR̤֥QEM@<1!Q+'s K&0k+;{ɢ;N (?=v3Wrrsg,)?  Ɯ*2/j-(>]UPTzgYF9scחsgo\0ybsPEa%2cCU%K5/g]ޮbsF6z5k3_j 1 nxxh}Sf-[eM MPŖVۦۚHݩ{ӽvB{JNG|JgxBL{NX >|`~N_Cwo * 6)5=R|44<t ׉Iɹ!Ͽ}+̫״ px+Խiw^x|~~CGYٚ9?sͅ/t_ʾ|MТwٖ(^Zyζ~Ͼ Ǎ̓[m_f^{FzPHT { 1CN \К!jA*hBi0|fffa{aIi]P2QU疠DKIIkTULV WޯbƭUgBSVD;G'S7C/K? 0(߸4)',S[I=nbt9%n_k@7wo_`$S~7 ][ GEG FF[>x&P[ptQcId|)T4t4Ltvjss^<4wWn"^"b>~2A2!H= i{C+lGD*K2MPNw"ck%O%JWkjmU=!ƌ.6]k:rE̝/wA>o`>ʃC kh>37~b̈́ݤs^r{f[)iw*3il\|ҧϖ J_~d{Rr앤صu[ۂvH8 XP DIim1h3d`bceX+T@JhXxDuz2Wd.ȗ*UUT>BC[Sa_[SKˀbH1sp1Z,a-M ---MǟNK._ͻ3 ޯ}}g>ῠΆ GG (Śz(1>;,p M &'ҘZV~DjF\fpl˓:sOsa%Qc PpϢŒϥʦν8?^>ra@@`Х#WFjFj=:xmzG7zye/mwҾֱֵֹ޽~gwj }zqxfdɱ'v?;4YEˢW9~5?dF\|çi _\}SXβDLAX!넟TMv J\Fjt&̑1H *' h;o :Rm 0C (Mp`C4Tt=`:XvQ3H恮@Hbb0Xv9n!a*yphDl$q2Hd_uM<-:%; SaN3 2eq`YfeS`{~Cc3k;grW5_NG0E@'/%j!F+6.^,))!.PX&TV_KnC} b|\<{iTkўYC#{[(8ˤt^}HJ [j;cd{. \ w5X&U5$@Аp3?}bŵK%T8RuL0qi23'O)<#;Qt^q`)Gٓy+*\zP]V[g{M:KNmw;g{$-#x"}ų׌omsg?̹]fjygmsSxy(DWň ؂h ~HxD Aa 8n(({ITA'{1D 3UĦb'pxU|~ʝAPF$IdUr= u9 'M)-m(-zm7Gh*UGYBX ll˜vx(̔!4>~%*h&(VN䠨AlLD7}E2:rlr?G*S>EC3@+Z;Y'OZ]`Ɉl,fblhe~%J=S> nkGz}h|]Յ`B3GDE>9zA\bƣIP㛩Q'Nfg՞8th.U^MYs/KV__oi̽Ӭr{½ݨj]'G ZO&n=_z%g]Yʼ/6T$Itٮ?31Lf Qp 4^o 1AJd AI&t `,[p /Ql}6Zh4uLˀu^npp[xM*zhI&L%NHQDMNޠY]K3%̘ۘ2ǰPԲγdgɑ)+[=O!ŌǯS9LH}_)(&-*!)(%,!="sY"JiSyCeK V'aTӲIխ՟56k1KT yado̙e߾D=z]}^AܳX|swܮ_ͯ*Xz  ׺u.[|٪~?1B :8a賗 ͈؀$ b___? w6駔O b0H@ td2 ~:)'*xnx^7XxKeS~\T^n6 f~ꮺͯ29_Z^rs+c^y7{g@Wd)?SʊUr WGMMMyy9JүH1 %(،3H1r@,{siwww[obZ󊊲J:[{Nb։G{r@[_Zrj)i'2zhfq;:딕E`DVԽ{靋i+8dջ~&3 1Mkcs˶FpR]x' ,W h~˶ֹ#mol0nTX.T09.u|07Coh޾}՛Z>KLsirڭ`DFf>@ }(Lp%%%}1>餓hoGmhF=w#OxEWeP4ԉNk3aԡk{$yUWeJdB<~1O|?(EKOᛯn5z3]}TlڬYٹ-'K7դBp~LS:cf{g[mYë i-Fdu_h7g 9l2}LfVTo9H_T:?O>r̙v3gNYYYWWROYp񳳃P*\H=T~W2d!,!{ f-𷗥,X$vC#{ /pF{JgLyvݤ7to:+뭂I>ujnR1 0hW=\[&|=GvV׌08ia'Hg6os-]dgg||f^=uXRG?iN*=xC*mu3,+pHKx:kv,<=$X{(|fZ#W3U|~+zfzs[E̞wM4ɷuI&ַoxe9{n>pWLH 2Rn @ /rLc.0m A z^}FWM:yoRe✌\nL:`_u&#'nwju/ɶ[mN, @F_~ծZ=հH-Rsgٳgw_… %T 8_!_׿nXOOv :@f#\JzRb@P;o;zٯ7nguϢo-|ռ V'?fەG(_ x۫?O/7k*ޚg__ۿRn4d{gꞳoM;¯fpڵ6V"]q3̒U[iH|{V멛yϝ26X6 \f]ut< 4܏`ßݿduR,X~xA)=SP͞q#ե:geپ'ڿꞅ3-ML1[YEno(j_ix, ʙg4cP &~w?nZ& 3?GBY k$HE| *ץriC239Ymb 㺻Xw+Tmh$Ӭ3 G4gu/ *̥|{2!CG|703_g>1lA )J˄izl۶m޼yF>Bea9Sz{闝nGi3>}O͑?^u;o]8in>ż: okp{ӛsb[؇K~w}usx\n*yn__nvC/:/fN;=5k76};:8ݴ?%8T&Xfs޶Rc34_7#Yv!tI92! #~LJh3g̖93x? w/39/\als;zSIw0cS#*FQp{S93XuF$2&.]t"fA޾&!xOn8퀟<~[AKDuOTwJS^J<2 9fOve:ܓ Tf\-'oo:,]_CMKT<6MULlݵ_x2Kt+~z%'uq#{CJ=z8grSuξcBXTGu4"5~mX}oW=Go;lv]ͥ2BO{\򃴇cGu{borT~ů覝;ɑO]u#s#U8W?jiWq? c:W){5}G𫇍dYH@`Q!hMXuXtt^^}MAUUn >ol5S,,Stux Ru_n*{Nl1PHq9d)zۖٙ9969Vwms O#Ur q_$Ӄ'DOЩ_~hU =NK͝;7ґzz<`1ET/jG+LSiڞ>X+t>7ZOOd1Hf=`T4ʢڈ<6_/(:hzL#iHaMڵKo4SPuMCuRЁEz% VhM1J+a.n@W\ T3n1P#^{tFMn :b{G I/鷕v3ڦM6^P @Z pG"%])J =kFoUޤxN7izB>Nb k(O9ILД>HCSG@h;E\Oߏv߈ߞ)}J"yzQ!(zW@FG& ! vy {R*zب@d&8= @Fa_MB 0~o//lG @ }opex?:k;?g=/@ > @tJ-LkI.‘!@SA@(PA|Ty쫂hy4=^  Y@ !'m/%kx Ԣ?Wh S9M΢vƗ}7&inF>I#7l   S~{ HW˓4r> 5 hŚ%pTȭSZ)+hHC)G84hkww^]HoirdPь?F  0$ D]E33b;b)2ҬH ʤDH@# aM? t@4\Rh張1E* h"HDB> @@8JH34r>=?HOȑx<εMǸJMyhe3Vg$x9`·^gn;N(TgVSp 1g.]%N=tj<gyĽhT (4XR8| @H@ܣ4/sGA1qjPJ6R׿p|Cg:V5z=_Oʺqɉ Ke`h n7fs߄ɺ3cc̋[Cg9\(hb9ynt:h`NƦ1/Cj%bsDruE;ڄ @ s/mf|q6z=o(j Oɢ\@Jp<˿]M'JkF{ɑ@&b\N{QB6c/R VsJxA tH{ӝ @ "so!K00T@q*gv-28|@I@>‡ ƾ71w $V@4>ѭщԣ\@ND*|@4(@yO4@B@1M 6!@H?X~GC 0?0 @ @SMf}8^@dyxX1SkI.c(" ʳ>:k{ \m-Pf(Rk y =mN18L"df @ X ,Ipl>ͱ47#MDD6 @ 1<ǫ<21}iՖ E¡z_[.)ZxUQ5ym=e*BjaS̈́gM 6!@i*0':+Њ.kqNmfq8!%SP8&%: $TG@L2[vOe&M}  @`q/<mc6e:mhB8_j@H/PRom˲[jw&Y )'@[skW#(aMc/R hA@`1/|4Ou\ڤiYL}Sr#C87%A _#ъUn*Y*).xJ_(*4eʴ|PrBW @x15cۈb/ @ t˽$A t>!B @`.½dM8 @H-U9k]Ƅ!@X/\k9=d@Z@Fyrt"'"\@ND*|@4(@=@^a& @џ=Lp ^N~F @xҌ @Дv{M @ $ޣ  @ |ttc[P"ѥ @H+uq~xssk 3p8@@꫄s$u|XPEs3TMI)Ad -A% bDuvFruaȈI9rH@)w574Ai妜L Qj @ЦiOV'GBzK}ɑrBD3,  @`14?w,%-"e0eY9#J4Ru5Ȅ hM`{?s3|x=+vVZFG ~F @ Ltlj3I+;74K|f[ϳ] GivQP" sȲn߷X-Tqm |`>U*EX y)'`,cT.bOHh `m}TqmCe*KVMr8&(Q4ʖ}짷2i@W`I}y}ޔ~K>Ԣ%=o.g_É i}a6` xr7:"vp8T M  @@Czz]t[+6us7|zo N2׃N"($M# @ q&'_Op2flV>SpAR_թH h0aws4@H4WۅzZ+3o&8>xz{=U l,Rد`d@@ (Kݛzro(P~Zk]_:܎.V2/n_;wnQ M Lܻ%l ˜|03>4fx"\vrIik" 'JkF{ɑ@&!&AD eBڏdHElB ZhiR;2@brG<{+( @R+ pB,I; @]@EZ}{#( @R, p,49e))Yܻ}o%>H4@1X-9:(J"  hp @$k#  tY#Ӂ` LiCL3!@Di %j' LNF=֒\zZ  @H !|=GgmO2 %]M! T;o||-gW CQNL@, p:U9ru<>qs,i&$ G @iW]_FzSwȻ @@#|{RUFΧrSW&0O@ M^ǵܵVkʱR9QNP(h& vA4%ijZMoM{܃fehFl(H] 75*B){G{63w6 E@Qi:6ȤR^ ^ffK,P< ڦca|]Br$$0hz\E:]ؕ%t@HkEbVo֏f{xhS:Z磎@dSy_>q\ېuAnٶҭBy}Sju(Q4Pp#7|!@HG~ z}y}ޔ~K:H+i+#xr7:"v+ hg0C=B-0ʹW:gإAXOua?qpK Rl(ASFdڧ4De@O|@]e3oPfh Fٖ#|.4[#J~NH6P# @ A'򹧎WۅU[8CZ01\kQ\\ <Ǫb)):t @@4Eɽ'emiٮNva~/ֱuOzbYwvwupBywKzj#KcvMjG!@ҰT9/3`&oJ*cwIg\{^NIBy#šz؂ @@SQB!! @@jDLZb@@K; @YzȒ{ @4' j{ڵxNscŀ @@$!} $grlƾ7CG@B OdJ8ȉH]Dȇ @@|58,  I7SK( @R'3.t=M!@80O3N8T @@SXL @`8P   hg4IkI.# @ qBx=<3-rb[P"ѕGAB EriQhsWyqzu&u_ND3 $V~E7*jOH "D xLZn4u;PwȻ @@#S1F֧rSW&0O@ Mj><ˑrJBD3{$ @ <(Ujz+s7-ьP"$aM~9 L)FiܟsdCL@X@LgdQC,< ڦca|]BN7trr.dl˿4R7i ^׾6t@@x6Oެgg-nfȀ6d][tkPo^$.~ʌ-r~2(eו^z+s @ }^owqB=)NWH,Yx# *oV ϻ8}-g'/ fh'@@@5]tXϰKn~~ЦIm\:oD6:dM'e9toj)$Mj?@ؠ'nt}u{P!QbFiپC}o%#= $U@];9ir9$!@Р0$@ 0F=]rGq@ w@d=&çc @XQ =G @xaMkI. !@=Yb[P"ѕNjaC PL#6HTyqz0dDNL  @ B s$x6|XPEs3TMI)AdϏ mA#@i"5O#=Gȓ4y hDV;%f SZ)+Qj @Ц/RZ*[]lS2 Iէ~!@c8.'׸2}^joXR[xoH9vop*Y5y֣TT^)A h If!@4B"qGC٣ӤȧiU}YиpYo>(Yom-u:f9|FNwqoMq] B- D_Nc=ڻ疼 viLm϶Z[&VH#}bMMK-`qWNLQv}  @G𪢾vѻ>[ɛ֣mOfxxwMfoxDP4 h]Pp#7L!@HS^Th8Zu[YN鲆:tvRT K"Zꊮ/  hg0Ck@H/F?Ęh-kMN6Z#<<`wH/ U ʌ֤]C!GY#,mxg{Ak(Gޫ(`zJ~²,:!I= $[`r&Y i\y[;1,~+~r xyǺ(Jք4{ɐ؄ @@ X!2Ou\ʧ˹~Sڴ|p>O0dκ5in5hiAYqSӹI=)w%'="j:g^ @H4,cWF+Bαkw1ܜ(a+F)3b_<6˄)="~%G @5M $ʄt{ɐ؄ @ r@A@ jFXzȒT C XZ}k(@R. p,5 Jb_{DmB 0z`SѠщ4>T hPLk5!A _§5@R!@rOsO E @iR.!@ѣ) @i.@r#IÇ @i&#,?֒\zC. @&rڞnG14(G3ktb Fq\"]9~PI@.P9ry:>qs,i&$  @q]`wYz-rخͲqF뾶?uLy!q2!@Zϰt=\a:=[:AfARjr=*vVy<εMǸJ }bMMK-y3pKt EtGD0hngltaWh. @`\XvB3M_p\ېuAnٶҭBy}D|ٻ[|Y _3 Zi|)~t[%g 'E3ʀF27R|D 4D]%tYzČJ\W$dx1_FVxUQi5? -i)%wC5SVJ{S5gmA4 џmgtI eȆF*SFd{w2CadcͬgIܦaM @ BYuݕїl_m9g@ñC4y=JCgϖ C{AK}Ujy)8I@@x=;+=wv ^wWoIJ}36zbMfX747cycU#:_O:||_{A )+cVF]wR\.k]j;s;ֻ:VX!˼ڻ[*VqSӹI=Iynt:hk4fuU-+sDrIkīm@@4>1fc‡)vَ[.{^xE [! &b e#2RXq>-~7-O4'1fB\H0Ad‚M@@ " @` ^;t-7^ @ &i#@ .1G@ ih @ 2 @Za-|  @iZKr=Q?ԇ @@<#G3kt'T @@cBXH།56ч|C^>[* I@.P9ry:>qs,i&$  @i\+s*OȻs]H@ x4>r2y m nOS{h6lQCo(d(A43*# @4"07d+ьP"$Z@XI M x4}r#}6c4o " 0Qjк踷K;SE7򆡳Vms<Ŝ`wf MXn燶mLz곅  @8nK^.w>G׷]LYەǛ[V/WLBe@m2i@W sO7 V 9 n(/s}7y糯l)DS M`&h  eFi2kΦ6RᚩK!I=z $Dg1^̝Ǽ izK?FY+uBdSh ^mdsmGoZᔡ9Ty }F kBZdHElB ! Z'w66YG兓,RQQ5CClP1*@*qF Wجy#_벊M ڔvTRv)o b* M+ +**%@x.u{ʻP됔34^2z; @@[ 6d%l?2 @WIDAT@ q \>-=d8D5@ tsO`%}, W@//okKj18@Ts~dcGc @ 5LGgmg#c @@I@ 4&jð!@zpR @ SOix2 @S[#soj!@H3>;>.  *+#zvwّJ5~` @ 46fJ-|.'S4@H r,Ipl>ͱ47#MDD6 @ 1t-Tɵb:w$+9;(aMHDZ M@ v(xA#'ʛtEws@˄)=2Q8#a mzʄ|%C*b L& $ QM @ "{ZzȒw!@@hJ[`ߩ#  hS@//Ϝ9$`!@&0|q@#BN[r91)@4/QOc @ (=A B@ _d;>P t96ր06k֬5S9z @@+\^xs=W+ @b =C 1 \17 FZ=b{qop#tGа󢆇AcSZJk\ZWhP/w[b2RN]\J}M(+e*یԅ.Se0QBuBNm?{1W(cfBU`›~YˋC>ra9!BHݟfBchnnk͛~]poٳj#T$G+ds ynZ`_#4/wrn/{wlf%;Ԗuqn雕%S[[UJ]i>.ykjLi`Pe tKE髕ƦN6K`瞖/_^QQo|'^{?@ q#9Fן[B~ڞm^ef (#}c}c յV)`W##:3O3'l" >tKI5|Te|N&.0p֭E9o6駔_x>?>}o[g}K/Ʌ\ @ e-麭,N.kxήc]G_E4f8/Vtᄒo:ֻ n ??XO ]x*8dueC42o%I/ n/Ȼ3\~d*5}-X>ŇƁ2! sz8{zz=؛W\\EꫯJgdd\wuʕ+srrM$  /Oe]H1O^Y9̠C=wW FDMi{պiʆܟ]:oD6N)t=X7cG̚8\(rzSp )`\JZAw]̓1M>+~,:Ҧ.ϻ8ЖU e!Z;L@`k害?\Q&ڨ.ovڥ܅4 庐~1ka6uwIA-йu,9G;{(#4nr6{pǺhs!GKBh&wܑX <*Kn|bﵽ'L?tjKeŠ tG>, ;Bxȁ%@&4OC eh/-u7n;w42R]]]UU%m_ׯ4Z!" R"I:K041C,MiӲ:<|9ܶZjZ-|9Jw 750ۼKqO;tQHsa) ٛug.Xb,bkcM*z(˻uqEs26 B^cl+nL8R_|Ox<5\tIf󅍬TM [+xϔr3,c|?O։uO~-Bv }{_Z&uVZPTTD1ЪU|IJHRkԃT @ sope(zrK2>xk1͸KE4qaD# $?z[A@ @AMQ $MNHD#{O( @' mf j1ox  @cTO=EO{XAY@ +N~itj^!@hм;TJ&\:~@ (e˖{ u$[ @' 4 @%p饗J34'<= /@ N^x'|Bfh= i3X!@S^@C$o>f @ yzQ5z @1 })'yJS}pSL(@@ (pꫯ54! ~.C @ (&7 DxP)xIENDB`./nsf2.4.0/doc/example-scripts/rosetta-clone.tcl000644 000766 000024 00000003013 12776662115 022352 0ustar00neumannstaff000000 000000 # # == Rosetta example: Polymorphic copy # # Let a polymorphic object contain an instance of some specific type S # derived from a type T. The type T is known. The type S is possibly # unknown until run time. The objective is to create an exact copy of # such polymorphic object. # https://rosettacode.org/wiki/Polymorphic_copy#Ruby # package req nx package req nx::test # # nx::Object provides a method +copy+ which creates a deep copy of any # source object (hence, polymorphic in the sense of this task), i.e., # it contains all structural and behavioral features of the source and # preserves its signature type. # nx::Class create T { :property -accessor public {label "T"} } nx::Class create S -superclasses T { :property -accessor public {label "S"} } set client [nx::Object new { :public object method duplicate {src} { # this is the polymorphic call site return [$src copy] } }] set t [T new] ? {$t label get} "T" set s [S new] ? {$s label get} "S" # # Provide two copies, using +copy+ underneath # set t2 [$client duplicate $t] set s2 [$client duplicate $s] # # Are the copies truly independent objects (identities)? Yes ... # ? {expr {$t2 ne $t}} 1 ? {expr {$s2 ne $s}} 1 # # Are the copies offsprings of the source types/classes? Yes ... # ? {$t info class} "::T" ? {$t2 info class} "::T" ? {$s info class} "::S" ? {$s2 info class} "::S" # # Do the copies operate exactly like their source objects? Yes ... # ? {$t label get} "T" ? {$t2 label get} "T" ? {$s label get} "S" ? {$s2 label get} "S" ./nsf2.4.0/doc/example-scripts/tutorial-properties.tcl000644 000766 000024 00000004737 13277227346 023646 0ustar00neumannstaff000000 000000 # NX supports the concept of properties, which can be used to # configure instance variables of a class (or an object) at creation # or run time and to add standardized accessor methods. package req nx package req nx::test # In a first step, we create a class named +Foo+ with three # properties, +x+, +y+ and +z+. ? {nx::Class create Foo { :property x :property -accessor public y :property -incremental z:0..n }} ::Foo # By defining something as a property, it will be possible # (1) to specify a value for the same-named instance variable at creation time, # (2) to modify the instance variable via +configure+, and # (3) to access the value of this instance variable from the via the +cget+ method. ? {Foo create f1 -x 1} ::f1 ? {f1 cget -x} 1 ? {f1 configure -x 2} "" ? {f1 cget -x} 2 # When a property is defined with an accessor (see property +y+), then # an accessor method is added with the specified protection level. The # accessor method has the same name as the property. All accessor # method can be used to +set+ and +get+ the value of the instance # variable. ? {f1 y set 3} 3 ? {f1 y get} 3 # Certainly, the methods +configure+ and +cget+ can be used also for # these properties as in the example with property +x+. ? {f1 cget -y} 3 # You might wonder, why these accessor methods are needed, when the # same behavior can be achieved via +cget+ and +configure+. The main # difference is that the accessor methods are tailorable (the behavior # can be modified) and extensible (more subcommands like +set+ and # +get+ can be defined). The details, how this is done is not covered # in this chapter. However, when a property is defined as # +incremental+ the sub-methods are extended. # When a property is defined as +incremental+, a public accessor and # multi-valued are assumed. By specifying +incremental+ the # sub-commands +add+ and +delete+ are provided to the accessor, which # allows one to add or delete values to a multi-valued property # incrementally (see property +z+). The term incrementally means here # that one can e.g. add a value to the list without the need to +get+ # the values of the list in a first step, to +lappend+ the value, and # to +set+ the variable to the resulting list. The +add+ sub-command # is similar to +push+ in MongoDB or +LPUSH+ in redis. ? {f1 z add 1} 1 ? {f1 z add 2} {2 1} ? {f1 z add 3 end} {2 1 3} ? {f1 z get} {2 1 3} # The sub-command +delete+ can be used to delete a certain value from # the list of value. ? {f1 z delete 2} {1 3} ./nsf2.4.0/doc/example-scripts/rosetta-delegates.html000644 000766 000024 00000050265 13523353476 023402 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-delegates.tcl

    Rosetta Example: Delegates

    package req nx
    
    nx::Class create Delegator {
    
      # The class Delegator has a property named "delegatee" which is an
      # object:
    
      :property delegatee:object
    
      # The method "operation" decides, whether it deletates the action to
      # another object, or it performs the action itself.
    
      :public method operation {} {
        if {[info exists :delegatee]} {
          ${:delegatee} operation
        } else {
          return "default implementatiton"
        }
      }
    }
    
    nx::Class create Delegatee {
    
      # The class "Delgatee" might receice invocations from the class
      # "Delegator"
    
      :public method operation {} {
        return "delegatee implementatiton"
      }
    }

    Demonstrating the behavior in a shell:

    Create a Delegator, which has no delegatee defined. Therefore delegator performs the action by itself, the default implementation.

    % set a [Delegator new]
    % $a operation
    default implementatiton

    Now, we set the delegatee; therefore, the delegatee will perform the action.

    % $a configure -delegatee [Delegatee new]
    % $a operation
    delegatee implementatiton

    ./nsf2.4.0/doc/example-scripts/rosetta-tokenizer.html000644 000766 000024 00000055625 13217207455 023457 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-tokenizer.tcl

    Assumes Tcl 8.6 (couroutine support)

    if {[catch {package req Tcl 8.6}]} return

    Rosetta example: Tokenize a string with escaping

    Write a class which allows for splitting a string at each non-escaped occurrence of a separator character.

    package req nx
    
    nx::Class create Tokenizer {
        :property s:required
        :method init {} {
            :require namespace
            set coro [coroutine [current]::nextCoro [current] iter ${:s}]
            :public object forward next $coro
        }
        :public method iter {s} {
            yield [info coroutine]
            for {set i 0} {$i < [string length $s]} {incr i} {
                yield [string index $s $i]
            }
            return -code break
        }
        :public object method tokenize {{-sep |} {-escape ^} s} {
            set t [[current] new -s $s]
            set part ""
            set parts [list]
            while {1} {
                set c [$t next]
                if {$c eq $escape} {
                    append part [$t next]
                } elseif {$c eq $sep} {
                    lappend parts $part
                    set part ""
                } else {
                    append part $c
                }
            }
            lappend parts $part
            return $parts
        }
    }

    Run some tests incl. the escape character:

    % Tokenizer tokenize -sep | -escape ^ ^|
    |
    % Tokenizer tokenize -sep | -escape ^ ^|^|
    ||
    % Tokenizer tokenize -sep | -escape ^ ^^^|
    ^|
    % Tokenizer tokenize -sep | -escape ^ |
    {} {}

    Test for the output required by the Rosetta example:

    % Tokenizer tokenize -sep | -escape ^ one^|uno||three^^^^|four^^^|^cuatro|
    one|uno {} three^^ four^|cuatro {}

    ./nsf2.4.0/doc/example-scripts/container.html000644 000766 000024 00000124550 13523353476 021747 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/container.tcl

    This example is a small design study to implement container classes with different features, namely a SimpleContainer, an OrderedContainer and a SortedContainer. First of all, we require NX:

    package req nx
    nx::test configure -count 1

    Simple Container

    The first container class presented here is called SimpleContainer, which manages its contained items. As all container classes presented here, the items are created as child objects embedded in the container. If the container is deleted, all items are deleted as well. The items, which will be put into the container, should be instances of a certain class. We define here for this purpose an arbitrary class C:

    nx::Class create C

    The class SimpleContainer keeps and manages items added to it. Every instance of this class might have different item classes. We might provide a prefix for naming the items, otherwise the default is member.

    nx::Class create SimpleContainer {
      :property {memberClass ::MyItem}
      :property {prefix member}
    
      # Require the method "autoname" for generating nice names
      :require method autoname
    
      # The method new is responsible for creating a child of the current
      # container.
      :public method new {args} {
        set item [${:memberClass} create [:]::[:autoname ${:prefix}] {*}$args]
        return $item
      }
    }

    Create and instance of the class SimpleContainer

    % SimpleContainer create container1 -memberClass ::C
    ::container1

    and add a few items:

    % container1 new
    ::container1::member1
    
    % container1 new
    ::container1::member2
    
    % container1 new
    ::container1::member3

    The elements of the container can be obtained via info children:

    % container1 info children
    ::container1::member1 ::container1::member2 ::container1::member3

    Ordered Container

    In the example with SimpleContainer, the order of the results of info children just happens to be in the order of the added items, but in general, this order is not guaranteed, but depends on the population of the hash tables. In the next step, we extend the example above by preserving the order of the elements.

    The class OrderedContainer is similar to SimpleContainer, but keeps a list of items that were added to the container. The item list is managed in a property items which is defined as incremental to make use of the add and delete methods provided by the slots.

    nx::Class create OrderedContainer -superclass SimpleContainer {
      :property -incremental {items:0..n {}}
    
      :public method new {args} {
        set item [${:memberClass} create [:]::[:autoname ${:prefix}] {*}$args]
        :items add $item end
        return $item
      }
    
      # Since we keep the list of items, we have to maintain it in case
      # items are deleted.
      :public method delete {item:object} {
        :items delete $item
        $item destroy
      }
    
    }

    Create an instance of OrderedContainer

    % OrderedContainer create container2 -memberClass ::C
    ::container2

    and add a few items:

    % container2 new
    ::container2::member1
    
    % container2 new
    ::container2::member2
    
    % container2 new
    ::container2::member3

    The elements of the container are obtained via the method items.

    % container2 items get
    ::container2::member1 ::container2::member2 ::container2::member3

    When we delete an item in the container …

    % container2 delete ::container2::member2

    the item is as well removed from the items list.

    % container2 items get
    ::container2::member1 ::container2::member3

    Sorted Container

    In the next step, we define a SortedContainer, that keeps additionally a sorted list for iterating through the items without needing to sort the items when needed. The implementation maintains an additional sorted list. The implementation of the SortedContainer depends on "lsearch -bisect" which requires Tcl 8.6. Therefore, if we have no Tcl 8.6, just return here.

    if {[info command yield] eq ""} return

    For sorting, we require the item class to have a key, that can be freely specified. We use there the property name of Class D:

    nx::Class create D {
      :property name:required
    }
    
    nx::Class create SortedContainer -superclass OrderedContainer {
    
      # In order to keep the index consisting of just the objects and to
      # ease sorting, we maintain two list, one list of values and one
      # list of objects. We assume for the time being, that the keys are
      # not changing.
    
      :variable values {}
      :variable index {}
      :property key
    
      :public method index {} { return ${:index}}
    
      :public method new {args} {
        set item [${:memberClass} create [:]::[:autoname ${:prefix}] {*}$args]
        if {[info exists :key]} {
          set value [$item cget -${:key}]
          set pos [lsearch -bisect ${:values} $value]
          set :values [linsert ${:values} [expr {$pos + 1}] $value]
          set :index  [linsert ${:index}  [expr {$pos + 1}] $item]
        }
        lappend :items $item
        return $item
      }
    
      # Since we keep the list of items, we have to maintain it in case
      # items are deleted.
      :public method delete {item:object} {
        set pos [lsearch ${:index} $item]
        if {$pos == -1} {error "item $item not found in container; items: ${:index}"}
        set :values [lreplace ${:values} $pos $pos]
        set :index  [lreplace ${:index}  $pos $pos]
        next
      }
    }

    Create a container for class D with key name:

    SortedContainer create container3 -memberClass ::D -key name

    Add a few items

    % container3 new -name victor
    ::container3::member1
    
    % container3 new -name stefan
    ::container3::member2
    
    % container3 new -name gustaf
    ::container3::member3

    The method items returns the items in the order of insertion (as before):

    % container3 items get
    ::container3::member1 ::container3::member2 ::container3::member3

    The method index returns the items in sorting order (sorted by the name member):

    % container3 index
    ::container3::member3 ::container3::member2 ::container3::member1

    Now we delete an item:

    % container3 delete ::container3::member2

    The item is as well removed from the result lists

    % container3 items get
    ::container3::member1 ::container3::member3
    
    % container3 index
    ::container3::member3 ::container3::member1

    ./nsf2.4.0/doc/example-scripts/per-object-mixins.tcl000644 000766 000024 00000006212 13677316542 023137 0ustar00neumannstaff000000 000000 # NX supports "open class definitions", object specific behavior # and mixin classes (among other things) to achieve dynamic behavior # extensions. The so-called per-object mixins are actually an # implementation of the decorator pattern. package req nx package req nx::test # Here is the original example: a method from a derived class # extends the behavior of the baseclass; the primitive "next" # calls other same-named methods. In the example below, the # baseclass method "speak" is called at the beginning of the # derived-class method. The primitive "next" can be placed at # arbitrary places, or it can be omitted when the baseclass method # should not be called. nx::Class create BaseClass { :public method speak {} { puts "Hello from BC." } } nx::Class create DerivedClass -superclass BaseClass { :public method speak {} { next puts "Hello from DC." } } DerivedClass create o1 o1 speak # The output is: # ---- # Hello from BC. # Hello from DC. # ---- # There are many ways to extend the behavior NX classes at # run time. The easiest thing is to add methods dynamically to # classes. E.g. we can extend the BaseClass with the method unknown, # which is called whenever an unknown method is called. BaseClass method unknown {m args} { puts "What? $m? I don't understand." } o1 sing # The output is: # ---- # What? sing? I don't understand. # ---- # # Often, you do not want to extend the class, but to # modify the behavior of a single object. In NX, an object # can have individual methods: o1 public object method sing {} { puts "Ok, here it goes: Lala Lala!" } o1 sing # The output is: # ---- # Ok, here it goes: Lala Lala! # ---- # # In many situations, it is desired to add/remove a set # of methods dynamically to objects or classes. The mechanisms # above allow this, but they are rather cumbersome and do # support a systematic behavior engineering. One can add # so-called "mixin classes" to objects and/or classes. For # example, we can define a class M for a more verbose methods: nx::Class create M { :public method sing {} { puts -nonewline "[self] sings: " next } :method unknown args { puts -nonewline "[self] is confused: " next } } # The behavior of M can be mixed into the behavior of o1 through # per object mixins ... o1 object mixins set M # ... and we call the methods again: o1 sing o1 read # The output is: # ---- # ::o1 sings: Ok, here it goes: Lala Lala! # ::o1 is confused: What? read? I don't understand. # ---- # # We can remove the new behavior easily by unregistering the # mixin class ... o1 object mixins set ""; # implicit: overwrite using empty string o1 object mixins clear; # explicit # ... and we call the methods again: o1 sing o1 read # The output is: # ---- # Ok, here it goes: Lala Lala! # What? read? I don't understand. # ---- # # Mixin classes can be used to extend the behavior of classes # as well. BaseClass mixins set M o1 sing o1 read DerivedClass create o2 o2 read # The output is: # ---- # ::o1 sings: Ok, here it goes: Lala Lala! # ::o1 is confused: What? read? I don't understand. # ::o2 is confused: What? read? I don't understand. # ---- ./nsf2.4.0/doc/example-scripts/rosetta-add-variable.html000644 000766 000024 00000075350 13217207455 023755 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-add-variable.tcl

    Rosetta example: Add a variable to a class instance at runtime

    Demonstrate how to dynamically add variables to an object (a class instance) at runtime.

    package req nx

    The class Empty does not provide any structural or behaviora features on behalf of future instances, they will remain empty.

    nx::Class create Empty

    Provide one instance of Empty to add an object variable to …

    Empty create ::e

    Is e truly empty?

    % ::e info vars

    NX offers different types of object-variable managers: properties, variable slots, and plain Tcl per-object variables. Below, we showcase variable slots (although the others can be added dynamically alike).

    a) Declare a variable slot foo; -accessor will provide getter/setter methods for this one object e automatically.

    ::e object variable -accessor public foo

    b) Define a value for the variable slot foo

    % ::e foo set 1
    1

    c) Is there a Tcl variable managed by the variable slot?

    % ::e info vars
    foo

    d) Retrieve foo's value

    % ::e foo get
    1

    A second instance of Empty has no such capability: foo

    Empty create ::f

    a) Is there any Tcl variable, one named foo? No …

    % ::f info vars

    b) Are there getter/setter methods for a foo? No …

    % ::f foo set
    ::f: unable to dispatch method 'foo'

    c) Is there a variable slot foo? No …

    % ::f info object variables foo

    In NX, once dynamically added, a variable slot can also be dynamically removed again.

    ::e delete object variable foo

    a) Is the variable slot foo gone? Yes …

    % ::e info object variables foo

    b) Is the Tcl variable gone? Yes …

    % ::e info vars

    c) Are the getter/setter methods gone? Yes …

    % ::e foo get
    ::e: unable to dispatch method 'foo'

    ./nsf2.4.0/doc/example-scripts/traits-simple.html000644 000766 000024 00000056637 13217207455 022567 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/traits-simple.tcl

    Implementation study based on

    1. Ducasse, O. Nierstrasz, N. Schärli, R. Wuyts, A. Black: Traits: A Mechanism for Fine-grained Reuse, ACM transactions on Programming Language Systems, Vol 28, No 2, March 2006

    Example in Fig 12: ReadStream and Trait tReadStream

    In this example, traits are used to extend classes and other traits.

    package require nx::trait

    Create a simple trait called tReadStream which provides the interface to a stream. In contrary to a composite trait, a simple trait does not inherit from another trait.

    nx::Trait create tReadStream {
      #
      # Define the methods provided by this trait:
      #
      :public method atStart {} {expr {[:position] == [:minPosition]}}
      :public method atEnd {} {expr {[:position] == [:maxPosition]}}
      :public method setToStart {} {set :position [:minPosition]}
      :public method setToEnd {} {set :position [:maxPosition]}
      :public method maxPosition {} {llength ${:collection}}
      :public method on {collection} {set :collection $collection; :setToStart}
      :public method next {} {
        if {[:atEnd]} {return ""} else {
          set r [lindex ${:collection} ${:position}]
          :nextPosition
          return $r
        }
      }
      :public method minPosition {} {return 0}
      :public method nextPosition {} {incr :position 1}
    
      # This trait requires a method "position" and a variable
      # "collection" from the base class. The definition is incomplete in
      # these regards.
    
      :requiredMethods position
      :requiredVariables collection
    }

    Define the class ReadStream with properties position and collection that uses the trait. The method require trait checks the requirements of the trait and imports the methods into ReadStream.

    nx::Class create ReadStream {
      :property {collection ""}
      :property -accessor public {position 0}
      :require trait tReadStream
    }

    Create an instance of the class ReadStream:

    ReadStream create r1 -collection {a b c d e}

    Test the behavior of the composed class:

    % r1 atStart
    1
    % r1 atEnd
    0
    % r1 next
    a
    % r1 next
    b

    ./nsf2.4.0/doc/example-scripts/ruby-mixins.tcl000644 000766 000024 00000016263 13565500370 022063 0ustar00neumannstaff000000 000000 # # == Design study to show the differences between decorator mixin classes and Ruby's mixin modules # # This example shows that the dynamic class structure of NX (and # XOTcl) is able to support _Ruby style mixins_ (called modules) and # _decorator style mixins_ (named after the design pattern Decorator) # in the same script. package req nx::test nx::test configure -count 1 # # One important difference between mixin classes in NX and Ruby's # mixins is the precedence order. While in NX, mixins are decorators # (the mixins have higher precedence than the intrinsic classes, # therefore a mixin class can overload the methods of the current # class and its subclasses), the mixins of Ruby have a lower # precedence (they extend the _base behavior_; although Ruby's modules # are not full classes, they are folded into the _intrinsic class # hierarchy_). Therefore, a Ruby style mixin can be refined by the # class, into which it is mixed in (or by a subclass). Decorator style # mixins modify the behavior of a full intrinsic class tree, while # Ruby style mixins are compositional units for a single class. # # To show the differences, we define the method +module+, which # behaves somewhat similar to Ruby's +module+ command. This method # adds the provided class to the precedence order after the current # class. The easiest way to achieve this is via multiple inheritance # (i.e. via the +superclass+ relationship). # package req nx nx::Class eval { :protected method module {name:class} { nsf::relation::set [self] superclass [concat $name [:info superclasses]] } } # # For illustration of the behavior of +module+ we define a class # +Enumerable+ somewhat inspired by the Ruby module with the same # name. We define here just the methods +map+, +each+, +count+, and # +count_if+. # nx::Class create Enumerable { :property members:0..n # The method 'each' applies the provided block on every element of # 'members' :public method each {var block} { foreach member ${:members} { uplevel [list set $var $member] uplevel $block } } # The method 'map' applies the provided block on every element of # 'members' and returns a list, where every element is the mapped # result of the source. :public method map {var block} { set result [list] :each $var { uplevel [list set $var [set $var]] lappend result [uplevel $block] } return $result } # The method 'count' returns the number of elements. :public method count {} { return [llength ${:members}] } # The method 'count_if' returns the number of elements for which # the provided expression is true. :public method count_if {var expr} { set result 0 :each $var { incr result [expr $expr] } return $result } } # After having defined the class +Enumerable+, we define a class # +Group+ using +Enumerable+ as a Ruby style mixin. This makes # essentially +Group+ a subclass of +Enumerable+, but with the only # difference that +Group+ might have other superclasses as well. nx::Class create Group { # # Include the "module" Enumerable # :module Enumerable } # Define now a group +g1+ with the three provided members. ? {Group create g1 -members {mini trix trax}} ::g1 # Since the definition of +Group+ includes the module +Enumerable+, # this class is listed in the precedence order after the class +Group+: ? {g1 info precedence} "::Group ::Enumerable ::nx::Object" # Certainly, we can call the methods of +Enumerable+ as usual: ? {g1 count} 3 ? {g1 map x {list pre-$x-post}} "pre-mini-post pre-trix-post pre-trax-post" ? {g1 count_if x {[string match tr*x $x] > 0}} 2 # # To show the difference between a +module+ and a +decorator mixin+ we # define a class named +Mix+ with the single method +count+, which # wraps the result of the underlying +count+ method between the # +alpha+ and +omega+. nx::Class create Mix { :public method count {} { return [list alpha [next] omega] } } # When the mixin class is added to +g1+, it is added to the front of # the precedence list. A decorator is able to modify the behavior of # all of the methods of the class, where it is mixed into. ? {g1 object mixins set Mix} "::Mix" ? {g1 info precedence} "::Mix ::Group ::Enumerable ::nx::Object" ? {g1 count} {alpha 3 omega} # For the time being, remove the mixin class again. ? {g1 object mixins set ""} "" ? {g1 info precedence} "::Group ::Enumerable ::nx::Object" # # An important difference between NX/XOTcl style mixins (decorators) # and Ruby style modules is that the decorator will have always a # higher precedence than the intrinsic classes, while the +module+ is # folded into the precedence path. # # Define a class +ATeam+ that uses +Enumerable+ in the style of a Ruby # module. The class might refine some of the provided methods. We # refined the method +each+, which is used as well by the other # methods. In general, by defining +each+ one can define very # different kind of enumerators (for lists, databases, etc.). # # Since +Enumerable+ is a module, the definition of +each+ in the # class +ATeam+ has a higher precedence than the definition in the # class +Enumerable+. If +Enumerable+ would be a decorator style mixin # class, it would not e possible to refine the definition in the class # +ATeam+, but maybe via another mixin class. # nx::Class create ATeam { # # Include the "module" Enumerable # :module Enumerable # # Overload "each" # :public method each {var block} { foreach member ${:members} { uplevel [list set $var $member-[string length $member]] uplevel $block } } # # Use "map", which uses the "each" method defined in this class. # :public method foo {} { return [:map x {string totitle $x}] } } # # Define now a team +t1+ with the three provided members. # ? {ATeam create t1 -members {arthur bill chuck}} ::t1 # As above, the precedence of +ATeam+ is higher than the precedence of # +Enumerable+. Therefore, the object +t1+ uses the method +each+ specialized in # class +ATeam+: ? {t1 info precedence} "::ATeam ::Enumerable ::nx::Object" ? {t1 foo} "Arthur-6 Bill-4 Chuck-5" # # The class +ATeam+ can be specialized further by a class +SpecialForce+: # nx::Class create SpecialForce -superclass ATeam { # ... } # Define a special force +s1+ with the four provided members. ? {SpecialForce create s1 -members {Donald Micky Daniel Gustav}} ::s1 # As above, the precedence of +Enumerable+ is lower then the # precedence of +ATeam+ and +Enumerable+. Therefore, +ATeam+ can refine # the behavior of +Enumerable+, the class +SpecialForce+ can refine # the behavior of +ATeam+. ? {s1 info precedence} "::SpecialForce ::ATeam ::Enumerable ::nx::Object" ? {s1 foo} "Donald-6 Micky-5 Daniel-6 Gustav-6" # Let us look again on decorator style mixin classes. If we add a # per-class mixin to +ATeam+, the mixin class has highest precedence, # and decorates the instances of +ATeam+ as well the instances of its # specializations (like e.g. +SpecialForce+). ? {ATeam mixins set Mix} "::Mix" ? {s1 info precedence} "::Mix ::SpecialForce ::ATeam ::Enumerable ::nx::Object" ? {s1 count} {alpha 4 omega} # This example showed that NX/XOTcl dynamic class structure is able to # support Ruby-style mixins, and decorator style mixins in the same script. ./nsf2.4.0/doc/example-scripts/tk-spread.html000644 000766 000024 00000067235 13217207455 021660 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/tk-spread.tcl

    A small Spreadsheet implementation, originally developed by Richard Suchenwirth in plain Tcl (see http://wiki.tcl.tk/1287). The spreadsheet was rewritten in an object oriented manner as a design study in NX by Gustaf Neumann in May 2011.

    tk-spread.png
    package require Tk
    package require nx::trait
    
     ##############################################################################
     # Class SpreadSheet
     #
     # The SpreadSheet computes simply totals for rows and columns.
     ##############################################################################
     nx::Class create SpreadSheet {
       #
       # The following attributes can be used for configuring the
       # spreadsheet.
       #
       :property {rows:integer 3}
       :property {cols:integer 2}
       :property {width:integer 8}
    
       #
       # If no widget is provided, use the name of the object as widget
       # name.
       #
       :property {widget ".[namespace tail [self]]"}
    
       #
       # Use the nx callback trait
       #
       :require trait nx::trait::callback
    
       #
       # The method "cell" hides the internal respresentation and sets a
       # cell to a value.
       #
       :method cell {pair value} {
         set :data($pair) $value
       }
    
       #
       # The constructor builds the SpreadSheet matrix via multiple text
       # entry fields.
       #
       :method init {} {
         set :last ${:rows},${:cols}  ;# keep grand total field
         trace var [:bindvar data] w [:callback redo]
         frame ${:widget}
         for {set y 0} {$y <= ${:rows}} {incr y} {
           set row [list]
           for {set x 0} {$x <= ${:cols}} {incr x} {
             set e [entry ${:widget}.$y,$x -width ${:width} \
                        -textvar [:bindvar data($y,$x)] -just right]
             if {$x==${:cols} || $y==${:rows}} {
               $e config -state disabled -background grey -relief flat
             }
             lappend row $e
           }
           grid {*}$row -sticky news
         }
         $e config -relief solid
       }
    
       #
       # The method "redo" is triggered via the updates in the cells
       #
       :public method redo {varname el op} {
         if {$el ne ${:last}} {
           lassign [split $el ,] y x
           if {$x ne ""} {
             :sum $y,* $y,${:cols}
             :sum *,$x ${:rows},$x
           } ;# otherwise 'el' was not a cell index
         }   ;# prevent endless recalculation of grand total
       }
    
       #
       # The method "sum" adds the values matched by pattern (typically a
       # row or column) and sets finally the target column with the total
       #
       :method sum {pat target} {
         set sum 0
         set total "" ;# default if no addition succeeds
         foreach {i value} [array get :data $pat] {
           if {$i != $target} {
             if {[string is double -strict $value]} {
               set total [set sum [expr {$sum + $value}]]
             }
           }
         }
         :cell $target $total
       }
     }

    Build spreadsheet "x"

    SpreadSheet create x {
       # populate with some values
       :cell 0,0 Spread1
       :cell 1,0 47
       :cell 2,1 11
     }

    Build spreadsheet "y"

    SpreadSheet create y -rows 4 -cols 4 {
       :cell 0,0 Spread2
       :cell 1,0 12
       :cell 2,2 22
     }

    Pack the spreadsheets into one pane

    pack [x cget -widget] [y cget -widget] -fill both

    ./nsf2.4.0/doc/example-scripts/evp.html000644 000766 000024 00000071407 13317121443 020545 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/evp.tcl

    A small Ludo/Mensch ärgere Dich nicht/Pachisie game, originally developed by Richard Suchenwirth in plain Tcl (see http://wiki.tcl.tk/956). The game was rewritten as a design study in NX by Gustaf Neumann in July 2013.

    Implementation

    package require Tk
    package require nx::trait

    Class Figure

        nx::mongo::Class create Supply {
            :property by_person:required
        }
        nx::mongo::Class create SupplyGood -superclass Supply {
            :property amount:required
        }
        nx::mongo::Class create SupplyWork -superclass Supply {
            :property from:required
            :property to:required
        }
    
        nx::mongo::Class create Comment {
            :property author:required
            :property comment:required
        }
    
        nx::mongo::Class create Demand {
            :property name:required
            :property -incremental {comments:embedded,type=::evp::Comment,0..n ""}
        }
        nx::mongo::Class create DemandGood -superclass Demand {
            :property amount:double,required
            :property supplied:double
            :property -incremental {supplies:embedded,type=::evp::SupplyGood,0..n ""}
        }
        nx::mongo::Class create DemandWork -superclass Demand {
            :property from:required
            :property to:required
            :property -incremental {supplies:embedded,type=::evp::SupplyWork,0..n ""}
        }
    
        nx::mongo::Class create Event {
            :index tags
            :property title:required
            :property date:required
            :property ts:required
            :property {open:required 1}
            :property -incremental demands:embedded,type=::evp::Demand,0..n
            :property -incremental {tags:0..n ""}
            :property -incremental {groups:0..n ""}
        }
    
        nx::mongo::Class create User {
            :property name:required
            :property email:required
            :property {password ""}
            :property {name_child ""}
            :property -incremental {groups:0..n ""}
            :index groups
            :index email
        }
    
    
    
        Comment template set -name edit {
            Comment by <b>@:author@</b>: <em>@:comment@</em>
        }
    
        DemandWork template set -name edit [subst {
            <if method-true=':fulfilled'><span class="glyphicon glyphicon-check"></span></if>
            <if method-false=':fulfilled'>
              <if method-true=':event_open'>
              [add-modal supply-work -context "@:name@" -glyphicon unchecked -title "Supply Work @:name@ from @:from@ - @:to@"]
              </if>
              <if method-false=':event_open'><span class="glyphicon glyphicon-unchecked"></span></if>
            </if>
            <b>@:name@</b> <div class="pull-right"><span class="glyphicon glyphicon-time"></span> @:from@ - @:to@</div>
            [add-modal comment -glyphicon comment -context @:name@]
            <ul><FOREACH var='s' in=':supplies' type='list'>
            <if method-true="%s% show_to_user %::user%"><li>provided by: @s;obj@</li></if>
            </FOREACH></ul>
            <ul><FOREACH var='c' in=':comments' type='list'><li>@c;obj@</li></FOREACH></ul>
        }]
    
    
    
    nx::mongo::Class create evp::DemandGood -superclass evp::Demand {
        :property amount:double,required
        :property supplied:double
        :property -incremental {supplies:embedded,type=::evp::SupplyGood,0..n ""}
        :method init {} {
            set sum 0
            if {[info exists :supplies]} {
                foreach s ${:supplies} {
                    set sum [expr {$sum + [$s cget -amount]}]
                }
            }
            set :supplied $sum
            set :needed   [expr {${:amount} - ${:supplied}}]
        }
    }
    
    
        forms modal add supply-good {
    <div class="modal fade" tabindex="-1" role="dialog" id="$id">
        <div class="modal-dialog" role="document">
        <form role="form" method="post" action="">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            <h4 class="modal-title">$title</h4>
          </div>
            <div class="modal-body">
                <div class="form-group">
                  <label for="amount"><span class="glyphicon glyphicon-shopping-cart"></span> Amount</label>
                  <input type="number" class="form-control" id="amount" name="amount" value="@:needed@" placeholder="Enter amount"
                   min="0" max="@:needed@">
                  <span class="validity"></span>
                 </div>
                 <input type='hidden' name='__id' value='@::_id@'>
                 <input type='hidden' name='by_person' value='@::current_user_name@'>
                 <input type='hidden' name='__context' value='$context'>
                 <input type='hidden' name='__what' value='$what'>
                 <input type='hidden' name='__action' value='$action'>
            </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
            <button type="submit" class="btn btn-primary" formaction="$href">Supply</button>
          </div>
         </div><!-- /.modal-content -->
         </form>
      </div><!-- /.modal-dialog -->
    </div><!-- /.modal -->
        }
    
    
    set id     [ns_queryget __id]
    set what   [ns_queryget __what ""]
    set action [ns_queryget __action]
    
     switch [ns_queryget __action] {
         ...
    
         supply-good {
             set e [Event find first -cond [list _id = [ns_queryget __id]]]
             if {$e ne ""} {
                 set demand_name [ns_queryget __context]
                 set demand [find-demand $e $demand_name]
                 $demand supplies add [SupplyGood new \
                                            -by_person [ns_queryget by_person] \
                                            -amount [ns_queryget amount]] end
                 $e save
                 ns_returnredirect $default_return_page
             }
         }
         ...
     }

    ./nsf2.4.0/doc/example-scripts/rosetta-singleton.html000644 000766 000024 00000055447 13523353476 023456 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-singleton.tcl

    Rosetta Example: Singleton

    A Singleton Class

    package req nx
    
    nx::Class create Singleton {
      #
      # We overload the system method "create". In the modified method we
      # save the created instance in the instance variable named
      # "instance"
      #
      :variable instance:object
    
      :public object method create {args} {
        return [expr {[info exists :instance] ? ${:instance} : [set :instance [next]]}]
      }
    }

    Demonstrating the behavior in a shell:

    Calling Singleton new multiple times returns always the same object:

    % expr {[Singleton new] eq [Singleton new]}
    1

    A Singleton Meta-class

    Alternatively, we can follow a more generic approach and define a metaclass which allows one to define several application classes as singletons. The metaclass has the most general metaclass nx::Class as superclass. In contrary to the example obove, the create method is not defined as a class method, but it will be inherited to its instances (to the application classes).

    nx::Class create Singleton -superclass nx::Class {
      #
      # We overload the system method "create". In the modified method we
      # save the created instance in the instance variable named
      # "instance"
      #
      :variable instance:object
    
      :public method create {args} {
        return [expr {[info exists :instance] ? ${:instance} : [set :instance [next]]}]
      }
    }

    Create an application class named Counter as a singleton:

    % Singleton create Counter
    ::Counter

    Calling Counter new multiple times returns always the same object:

    % expr {[Counter new] eq [Counter new]}
    1

    ./nsf2.4.0/doc/example-scripts/rosetta-add-variable.tcl000644 000766 000024 00000003553 13677316542 023577 0ustar00neumannstaff000000 000000 # # == Rosetta example: Add a variable to a class instance at run time # # Demonstrate how to dynamically add variables to an object (a class instance) at run time. # https://rosettacode.org/wiki/Add_a_variable_to_a_class_instance_at_runtime#Tcl # package req nx package req nx::test # # The class +Empty+ does not provide any structural or behavioral # features on behalf of future instances, they will remain empty. # nx::Class create Empty # # Provide one instance of +Empty+ to add an object variable to ... # Empty create ::e # Is +e+ truly empty? ? {::e info vars} "" # # NX offers different types of object-variable managers: properties, # variable slots, and plain Tcl per-object variables. Below, we # showcase variable slots (although the others can be added # dynamically alike). # # a) Declare a variable slot +foo+; +-accessor+ will provide # getter/setter methods for this one object +e+ automatically. ::e object variable -accessor public foo # b) Define a value for the variable slot +foo+ ? {::e foo set 1} 1 # c) Is there a Tcl variable managed by the variable slot? ? {::e info vars} "foo" # d) Retrieve +foo+'s value ? {::e foo get} 1 # # A second instance of +Empty+ has no such capability: +foo+ # Empty create ::f # a) Is there any Tcl variable, one named +foo+? No ... ? {::f info vars} "" # b) Are there getter/setter methods for a +foo+? No ... ? {::f foo set} "::f: unable to dispatch method 'foo'" # c) Is there a variable slot +foo+? No ... ? {::f info object variables foo} "" # # In NX, once dynamically added, a variable slot can also be dynamically removed again. # ::e delete object variable foo # a) Is the variable slot +foo+ gone? Yes ... ? {::e info object variables foo} "" # b) Is the Tcl variable gone? Yes ... ? {::e info vars} {} # c) Are the getter/setter methods gone? Yes ... ? {::e foo get} "::e: unable to dispatch method 'foo'" ./nsf2.4.0/doc/example-scripts/starmethod.tcl000644 000766 000024 00000013310 13316374540 021737 0ustar00neumannstaff000000 000000 # # = Star Methods # # Design study for implementing methods which applies to instances of # instances meta-classes. This study implements in addition to the # regular "method" a new construct called "*method" which has the # mentioned transitive property. The same behavior can be achieved in # many ways. In this study, we define a special class (the method # container class for *methods) which is kept in the precedence path # of instances. This way, it can be defined freely with other # extension mechanisms such as mixins, traits or filters. # package req nx::test nx::Class eval { # # Define a *method, which is a method that applies for instances of # the instances of a meta-class. # - *methods are only defineable on meta-classes # - *methods are applicable on the instances of the instances of the # meta-class # - If one defines a *method "bar" on a meta-class "MClass", and a # class "C" as an instance of "MClass", and "c1" is an instance of # "C", then "bar" is applicable for "c1". # # The "*method" has the same signature as regular methods, and can # be used in combination with the modifiers # public/protected/private as usual. # :public method *method {name arguments:parameter,0..* -returns body -precondition -postcondition} { # # Allow the definition only on meta-classes # if {![nsf::is metaclass [self]]} { error "[self] is not a meta-class" } # # Do we have the class for keeping the *methods already? # set starClass [nx::Class create [self]::*] if {![nsf::object::exists $starClass]} { # # If not, create the *method container class and provide # it as a default in the superclass hierarchy. This # happens by modifying the property "-superclasses" which # is used on every class to specify the class hierarchy. # :property [list superclasses $starClass] { # # Define a slot-specific method for keeping the # *method container class in the hierarchy. # :public object method appendToRelations { class property value } { set sc [nsf::relation::get $class $property] if {$sc eq "::nx::Object"} { nsf::relation::set $class $property $value } else { nsf::relation::set $class $property [concat $sc $value] } } # # Whenever the "-superclasses" relation is called, # make sure, we keep the *method container class in # the hierarchy. # :public object method value=set { class property value } { :appendToRelations $class superclass $value } } # # Update class hierarchies of the previously created instances # of the meta-class. # foreach class [:info instances] { set slot [$class info lookup slots superclasses] $slot appendToRelations $class superclass $starClass } } # # Define the *method as regular method in the star method # container class. # [self]::* method $name $arguments \ {*}[expr {[info exists returns] ? [list -returns $returns] : ""}] \ $body \ {*}[expr {[info exists precondition] ? [list -precondition $precondition] : ""}] \ {*}[expr {[info exists postcondition] ? [list -postcondition $postcondition] : ""}] } } set ::nsf::methodDefiningMethod(*method) 1 # # == Some base test cases: # # Define a meta-class MClass with a method "foo" and to star methods # named "foo" and "bar". # nx::Class create MClass -superclass nx::Class { :public method foo {} {return MClass-[next]} :public *method foo {} {return *-[next]} :public *method bar {} {return *-[next]} } # # Define a class based on MClass and define here as well a method # "foo" to show the next-path in combination with the *methods. # MClass create C { :public method foo {} {return C-[next]} } ? {C info superclasses} "::MClass::*" # # Finally create an instance with the method foo as well. # C create c1 { :public object method foo {} {return c1-[next]} } # # The result of "foo" reflects the execution order: object before # classes (including the *method container). # ? {c1 info precedence} "::C ::MClass::* ::nx::Object" ? {c1 foo} "c1-C-*-" ? {c1 bar} "*-" # # Define a Class D as a specialization of C # MClass create D -superclass C { :public method foo {} {return D-[next]} :create d1 } ? {d1 info precedence} "::D ::C ::MClass::* ::nx::Object" ? {d1 foo} "D-C-*-" # # Dynamically add *method "baz". # ? {d1 baz} "::d1: unable to dispatch method 'baz'" MClass eval { :public *method baz {} {return baz*-[next]} } ? {d1 baz} "baz*-" # # Test adding of *methods at a time, when the meta-class has already # instances. # # Create a meta-class without a *method nx::Class create MClass2 -superclass nx::Class MClass2 create X {:create x1} ? {x1 info precedence} "::X ::nx::Object" # Now add a *method MClass2 eval { :public *method baz {} {return baz*-[next]} } # Adding the *method alters the superclass order of already created # instances of the meta-class ? {x1 info precedence} "::X ::MClass2::* ::nx::Object" ? {x1 baz} "baz*-" # # Finally, there is a simple application example for ActiveRecord # pattern. All instances of the application classes (such as # "Product") should have a method "save" (together with other methods # now shown here). First define the ActiveRecord class (as a # meta-class). # Class create ActiveRecord -superclass nx::Class { :property table_name :method init {} { if {![info exists :table_name]} { set :table_name [string tolower [namespace tail [self]]s] } } :public *method save {} { puts "save [self] into table [[:info class] cget -table_name]" } } # # Define the application class "Product" with an instance # ActiveRecord create Product Product create p1 p1 save # The last command prints out: "save ::p1 into table products" ./nsf2.4.0/doc/example-scripts/rosetta-serialization.tcl000755 000766 000024 00000002561 13454166031 024127 0ustar00neumannstaff000000 000000 # == Rosetta Example: Object serialization # For details see https://rosettacode.org/wiki/Object_serialization # package req nx package req nx::test proc ! args {uplevel {*}$args} package req nx::serializer nx::Class create Being { :property {alive:boolean true} } nx::Class create Animal -superclass Being { :property name :public method print {} { puts "i am ${:name} alive ${:alive}" } } # === Demonstrating the behavior in a shell: # Create a few animals ? {Animal new -name "Fido"} "::nsf::__#0" ? {Animal new -name "Lupo"} "::nsf::__#1" ? {Animal new -name "Kiki" -alive false} "::nsf::__#2" # Print the created animals ? {foreach i [Animal info instances] { $i print }} "" # The loop prints: + # +i am Kiki alive false+ + # +i am Lupo alive true+ + # +i am Fido alive true+ # # Serialize the animals to a file ! {set fpath [::nsf::tmpdir]/dump} ! {set f [open $fpath w]} ? {foreach i [Animal info instances] { puts $f [$i serialize] }} "" ? {close $f} "" # Destroy all animal instances: ? {foreach i [Animal info instances] { $i destroy }} "" ? {puts ===========} "" # Print the existing animals (will print nothing) ? {foreach i [Animal info instances] { $i print }} "" ? {puts ===========} "" # Load the animals again ... ? {source $fpath} "" # and print it. The print output is the same as above ? {foreach i [Animal info instances] { $i print }} "" ./nsf2.4.0/doc/example-scripts/rosetta-singleton.tcl000644 000766 000024 00000003207 13454166031 023247 0ustar00neumannstaff000000 000000 # # == Rosetta Example: Singleton # For details see https://rosettacode.org/wiki/Singleton # # === A Singleton Class package req nx package req nx::test nx::Class create Singleton { # # We overload the system method "create". In the modified method we # save the created instance in the instance variable named # "instance" # :variable instance:object :public object method create {args} { return [expr {[info exists :instance] ? ${:instance} : [set :instance [next]]}] } } # === Demonstrating the behavior in a shell: # # Calling +Singleton new+ multiple times returns always the same object: ? {expr {[Singleton new] eq [Singleton new]}} 1 # # === A Singleton Meta-class # # Alternatively, we can follow a more generic approach and define a # metaclass which allows one to define several application classes as # singletons. The metaclass has the most general metaclass +nx::Class+ # as superclass. In contrary to the example obove, the +create+ method # is not defined as a class method, but it will be inherited to its # instances (to the application classes). # nx::Class create Singleton -superclass nx::Class { # # We overload the system method "create". In the modified method we # save the created instance in the instance variable named # "instance" # :variable instance:object :public method create {args} { return [expr {[info exists :instance] ? ${:instance} : [set :instance [next]]}] } } # Create an application class named +Counter+ as a singleton: ? {Singleton create Counter} ::Counter # Calling +Counter new+ multiple times returns always the same object: ? {expr {[Counter new] eq [Counter new]}} 1./nsf2.4.0/doc/example-scripts/rosetta-tree.tcl000644 000766 000024 00000005606 13325701456 022214 0ustar00neumannstaff000000 000000 # # == Rosetta example: https://rosettacode.org/wiki/Tree_traversal # # # Implement a binary tree structure, with each node carrying an # integer as a node label, and four traversal strategies: pre-order, # in-order, postorder, and levelorder traversals. # # https://rosettacode.org/wiki/Tree_traversal # package req nx package req nx::test # # The class +Tree+ implements the basic binary composite structure (left, right). # nx::Class create Tree { :property -accessor public value:required :property -accessor public left:object,type=[current] :property -accessor public right:object,type=[current] :public method traverse {order} { set list {} :$order v { lappend list $v } return $list } # Traversal methods :public method preOrder {varName script {level 0}} { upvar [incr level] $varName var set var ${:value} uplevel $level $script if {[info exists :left]} {${:left} preOrder $varName $script $level} if {[info exists :right]} {${:right} preOrder $varName $script $level} } :public method inOrder {varName script {level 0}} { upvar [incr level] $varName var if {[info exists :left]} {${:left} inOrder $varName $script $level} set var ${:value} uplevel $level $script if {[info exists :right]} {${:right} inOrder $varName $script $level} } :public method postOrder {varName script {level 0}} { upvar [incr level] $varName var if {[info exists :left]} {${:left} postOrder $varName $script $level} if {[info exists :right]} {${:right} postOrder $varName $script $level} set var ${:value} uplevel $level $script } :public method levelOrder {varName script} { upvar 1 $varName var set nodes [list [current]] while {[llength $nodes] > 0} { set nodes [lassign $nodes n] set var [$n value get] uplevel 1 $script if {[$n eval {info exists :left}]} {lappend nodes [$n left get]} if {[$n eval {info exists :right}]} {lappend nodes [$n right get]} } } } # # This is a factory method to build up the object tree recursively # from a nested Tcl list. Note that we create left and right children by # nesting them in their parent, this provides for a cascading cleanup # of an entire tree (there is no need for an explicit cascading of # +destroy+ methods down the composite). # Tree public object method newFromList {-parent l} { lassign $l value left right set n [:new {*}[expr {[info exists parent]?[list -childof $parent]:""}] -value $value] set props [list] if {$left ne ""} {lappend props -left [:newFromList -parent $n $left]} if {$right ne ""} {lappend props -right [:newFromList -parent $n $right]} $n configure {*}$props return $n } # Run the required tests: set t [Tree newFromList {1 {2 {4 7} 5} {3 {6 8 9}}}] ? {$t traverse preOrder} {1 2 4 7 5 3 6 8 9} ? {$t traverse inOrder} {7 4 2 5 1 8 6 9 3} ? {$t traverse postOrder} {7 4 5 2 8 9 6 3 1} ? {$t traverse levelOrder} {1 2 3 4 5 6 7 8 9} ./nsf2.4.0/doc/example-scripts/tk-spread.tcl000644 000766 000024 00000005742 13454166031 021466 0ustar00neumannstaff000000 000000 # A small Spreadsheet implementation, originally developed by Richard # Suchenwirth in plain Tcl (see https://wiki.tcl-lang.org/1287). The # spreadsheet was rewritten in an object oriented manner as a design # study in NX by Gustaf Neumann in May 2011. # # image::tk-spread.png[] # package require Tk package require nx::trait ############################################################################## # Class SpreadSheet # # The SpreadSheet computes simply totals for rows and columns. ############################################################################## nx::Class create SpreadSheet { # # The following attributes can be used for configuring the # spreadsheet. # :property {rows:integer 3} :property {cols:integer 2} :property {width:integer 8} # # If no widget is provided, use the name of the object as widget # name. # :property {widget ".[namespace tail [self]]"} # # Use the nx callback trait # :require trait nx::trait::callback # # The method "cell" hides the internal respresentation and sets a # cell to a value. # :method cell {pair value} { set :data($pair) $value } # # The constructor builds the SpreadSheet matrix via multiple text # entry fields. # :method init {} { set :last ${:rows},${:cols} ;# keep grand total field trace var [:bindvar data] w [:callback redo] frame ${:widget} for {set y 0} {$y <= ${:rows}} {incr y} { set row [list] for {set x 0} {$x <= ${:cols}} {incr x} { set e [entry ${:widget}.$y,$x -width ${:width} \ -textvar [:bindvar data($y,$x)] -just right] if {$x==${:cols} || $y==${:rows}} { $e config -state disabled -background grey -relief flat } lappend row $e } grid {*}$row -sticky news } $e config -relief solid } # # The method "redo" is triggered via the updates in the cells # :public method redo {varname el op} { if {$el ne ${:last}} { lassign [split $el ,] y x if {$x ne ""} { :sum $y,* $y,${:cols} :sum *,$x ${:rows},$x } ;# otherwise 'el' was not a cell index } ;# prevent endless recalculation of grand total } # # The method "sum" adds the values matched by pattern (typically a # row or column) and sets finally the target column with the total # :method sum {pat target} { set sum 0 set total "" ;# default if no addition succeeds foreach {i value} [array get :data $pat] { if {$i != $target} { if {[string is double -strict $value]} { set total [set sum [expr {$sum + $value}]] } } } :cell $target $total } } # Build spreadsheet "x" SpreadSheet create x { # populate with some values :cell 0,0 Spread1 :cell 1,0 47 :cell 2,1 11 } # Build spreadsheet "y" SpreadSheet create y -rows 4 -cols 4 { :cell 0,0 Spread2 :cell 1,0 12 :cell 2,2 22 } # Pack the spreadsheets into one pane pack [x cget -widget] [y cget -widget] -fill both ./nsf2.4.0/doc/example-scripts/evp.tcl000644 000766 000024 00000011774 13265351603 020371 0ustar00neumannstaff000000 000000 # A small Ludo/Mensch ärgere Dich nicht/Pachisie game, originally # developed by Richard Suchenwirth in plain Tcl (see # http://wiki.tcl.tk/956). The game was rewritten as a design study in # NX by Gustaf Neumann in July 2013. # # # == Implementation # package require Tk package require nx::trait # # Class Figure # # nx::mongo::Class create Supply { :property by_person:required } nx::mongo::Class create SupplyGood -superclass Supply { :property amount:required } nx::mongo::Class create SupplyWork -superclass Supply { :property from:required :property to:required } nx::mongo::Class create Comment { :property author:required :property comment:required } nx::mongo::Class create Demand { :property name:required :property -incremental {comments:embedded,type=::evp::Comment,0..n ""} } nx::mongo::Class create DemandGood -superclass Demand { :property amount:double,required :property supplied:double :property -incremental {supplies:embedded,type=::evp::SupplyGood,0..n ""} } nx::mongo::Class create DemandWork -superclass Demand { :property from:required :property to:required :property -incremental {supplies:embedded,type=::evp::SupplyWork,0..n ""} } nx::mongo::Class create Event { :index tags :property title:required :property date:required :property ts:required :property {open:required 1} :property -incremental demands:embedded,type=::evp::Demand,0..n :property -incremental {tags:0..n ""} :property -incremental {groups:0..n ""} } nx::mongo::Class create User { :property name:required :property email:required :property {password ""} :property {name_child ""} :property -incremental {groups:0..n ""} :index groups :index email } Comment template set -name edit { Comment by @:author@: @:comment@ } DemandWork template set -name edit [subst { [add-modal supply-work -context "@:name@" -glyphicon unchecked -title "Supply Work @:name@ from @:from@ - @:to@"] @:name@
    @:from@ - @:to@
    [add-modal comment -glyphicon comment -context @:name@]
    • provided by: @s;obj@
    • @c;obj@
    }] nx::mongo::Class create evp::DemandGood -superclass evp::Demand { :property amount:double,required :property supplied:double :property -incremental {supplies:embedded,type=::evp::SupplyGood,0..n ""} :method init {} { set sum 0 if {[info exists :supplies]} { foreach s ${:supplies} { set sum [expr {$sum + [$s cget -amount]}] } } set :supplied $sum set :needed [expr {${:amount} - ${:supplied}}] } } forms modal add supply-good { } set id [ns_queryget __id] set what [ns_queryget __what ""] set action [ns_queryget __action] switch [ns_queryget __action] { ... supply-good { set e [Event find first -cond [list _id = [ns_queryget __id]]] if {$e ne ""} { set demand_name [ns_queryget __context] set demand [find-demand $e $demand_name] $demand supplies add [SupplyGood new \ -by_person [ns_queryget by_person] \ -amount [ns_queryget amount]] end $e save ns_returnredirect $default_return_page } } ... } ./nsf2.4.0/doc/example-scripts/tk-geo.tcl000644 000766 000024 00000011112 12501766547 020760 0ustar00neumannstaff000000 000000 # Drawing geometric figures - the result of airplane travel. # # The example script shows the use of canvas and geometric figues # (regular, convex polygons) with different number of edges based on # trigonometric functions. # # -gustaf neumann (Aug 2, 2013) # # image::tk-geo1.png[width=400] # image::tk-geo2.png[width=400] # package require Tk package require nx # # Class Canvas is a simple convenience wrapper for the tk canvas, # which packs itself. # nx::Class create Canvas { :property {canvas .canvas} :property {bg beige} :property {height 500} :property {width 500} :method init {} { canvas ${:canvas} -bg ${:bg} -height ${:height} -width ${:width} pack ${:canvas} } } # # Class Area provides a center point (x, y) and a radius # nx::Class create Area { :property {canvas .canvas} :property {x 250} :property {y 250} :property {radius 200} :variable pi [expr {acos(-1)}] :method degree {d} { # # return a coordinate pair on a circle around the center point with # :radius at the provided degrees (0..360) # set x [expr {$d*${:pi}/180.0 - ${:pi}/2.0}] set x0 [expr {cos($x)*${:radius}+${:x}}] set y0 [expr {sin($x)*${:radius}+${:y}}] list $x0 $y0 } :method n-tangle {n} { # # Draw a regular n-tangle (e.g. when n==3, a triangle) inscribed to # a circle with radius :radius # for {set i 0} {$i < $n} {incr i} { set p($i) [:degree [expr {$i*360/$n}]] } lassign $p(0) x0 y0 for {set i 1} {$i < $n} {incr i} { lassign $p($i) x1 y1 ${:canvas} create line $x0 $y0 $x1 $y1 lassign $p($i) x0 y0 } lassign $p(0) x1 y1 ${:canvas} create line $x0 $y0 $x1 $y1 } } # # Class Inscribe draws multiple n-tangles with the came center point. # nx::Class create Inscribe -superclass Area { :property {count 4} :property {edges 3} :method init {} { for {set i 0} {$i < ${:count}} {incr i} { ${:canvas} create oval \ [expr {${:x}-${:radius}}] [expr {${:y}-${:radius}}] \ [expr {${:x}+${:radius}}] [expr {${:y}+${:radius}}] :n-tangle ${:edges} set :radius [expr {${:radius}/2.0}] } } } # # Class Hull creates an n-tangle with :density hull lines between # neighboring edges # nx::Class create Hull -superclass Area { :property {edges 3} :property {density 10} :method n-tangle {n} { for {set i 0} {$i < $n} {incr i} { set p($i) [:degree [expr {$i*360/$n}]] } lassign $p(0) x0 y0 for {set i 1} {$i < $n} {incr i} { lassign $p($i) x1 y1 set line($i) [list $x0 $y0 $x1 $y1] ${:canvas} create line $x0 $y0 $x1 $y1 lassign $p($i) x0 y0 } lassign $p(0) x1 y1 ${:canvas} create line $x0 $y0 $x1 $y1 set line(0) [list $x0 $y0 $x1 $y1] set line($n) [list $x0 $y0 $x1 $y1] for {set i 0} {$i < $n} {incr i} { lassign $line($i) x0 y0 x1 y1 lassign $line([expr {$i+1}]) x2 y2 x3 y3 set dx1 [expr {($x0 - $x1)*1.0/${:density}}] set dy1 [expr {($y0 - $y1)*1.0/${:density}}] set dx2 [expr {($x2 - $x3)*1.0/${:density}}] set dy2 [expr {($y2 - $y3)*1.0/${:density}}] for {set j 1} {$j < ${:density}} {incr j} { ${:canvas} create line [expr {$x0-$dx1*$j}] [expr {$y0-$dy1*$j}] \ [expr {$x2-$dx2*$j}] [expr {$y2-$dy2*$j}] } } } :method init {} { :n-tangle ${:edges} } } # Draw either one larger figure with inner figures # or a series of smaller figures next to each other. set multiple 0 if {$multiple} { # Draw a series of figures next to each other set c [::Canvas new -width 650 -height 750 -bg white] ::Inscribe new -canvas [$c cget -canvas] -x 100 -y 100 -radius 80 -count 7 ::Inscribe new -canvas [$c cget -canvas] -x 300 -y 100 -radius 80 -count 7 -edges 4 ::Inscribe new -canvas [$c cget -canvas] -x 500 -y 100 -radius 80 -count 7 -edges 5 ::Hull new -canvas [$c cget -canvas] -x 100 -y 300 -radius 80 -edges 3 -density 10 ::Hull new -canvas [$c cget -canvas] -x 300 -y 300 -radius 80 -edges 4 -density 10 ::Hull new -canvas [$c cget -canvas] -x 500 -y 300 -radius 80 -edges 5 -density 10 ::Hull new -canvas [$c cget -canvas] -x 300 -y 600 -radius 200 -edges 3 -density 40 } else { # Draw a several series of figures with the same center set c [::Canvas new -width 650 -height 650 -bg white] ::Hull new -canvas [$c cget -canvas] -x 300 -y 320 -radius 300 -edges 5 -density 40 ::Hull new -canvas [$c cget -canvas] -x 300 -y 320 -radius 150 -edges 4 -density 20 ::Hull new -canvas [$c cget -canvas] -x 300 -y 320 -radius 75 -edges 3 -density 10 ::Hull new -canvas [$c cget -canvas] -x 300 -y 320 -radius 30 -edges 5 -density 5 } ./nsf2.4.0/doc/example-scripts/tk-ludo.png000644 000766 000024 00000445022 12174275705 021163 0ustar00neumannstaff000000 000000 PNG  IHDRV^r#\ iCCPICC ProfileH WgXSS@HhPޑ^ l$$"bwQVtUDŵ]Y{XPPł ;ݻywo3 l8 U [/ g%%(P6lN/::&@k6./ Ӹyl5rĒ|H=bXMx'#i#mX52hlQAl' EO؛#`s!.:;;{ 6Of}fᑱq0OŞ50_Ïiÿ́y+䰃b!քx9nj8ՠ@?~@~03'q~4']5it,tI0!ϼ q1c8BLj avI+^Ӱ/'y08''rH\v [ll <D@$5 "q@ȂERk!=#und;c9Bx! *yõqo/,>;Gcþ6G/fJho=S0x 3S >br9J&[`Kyvk ;5bmq5 "+D@"HDc%7ŨEKEg{@&l~0VP=f@mķ 7uq/gck fs ؀l %<õrij$B wK5+Lıf9;b%4ew.RP63sFoo`D/%Wh=`aF  (t F<U`=[@h9pt.`A BG Vx#AH$$#!RY!kJd;RCN!NA Q j.jGP?4C|4-B+ ֣݇ TD1)`Lܰ, K1 6+ʱj5Lbp2Y P<\|9^35އ%I:$+)DfJH]"'Ldry6y9y3B$?!S(-ŋEaS)%}.G99}9`9Brr'=W7ϒ_)SI|UjFQ3 ԳԷ  **\PxJЦҤݴ[:nJ+5 E[0E<*zūL+)+Vԫ,lV\|Lr C^%J%[e^*ݪUS UbU00#a,bdet2;'WW11)3\<ļXq@q;Nm8θqAu,ubtfi n=۫[wBG/_RKbUΰ t B   >03j537h\l\k|DD`S3D% ffafEff>-n-:,QKgKe+Jh٪Ӛdn-eC)yd˴]h`jǟ.n={UpMo,8U_;Y98vf8Ot^Er5u-75hnIܛ?yx{3sg ;'<2b{mySy| |>>}||Ye{o/?!#`N@K XT00\2;%:Vn'&/5|NZDlDeHHIdDtbĵO2$¢F=6΍m2yrbcc2bg}2^y45A)ajBM‡5Is.'k' S() )RMY?kԒ7M+vqg(`8JJMLݛ:ȎbW6q88/uo yWn-G#( [3>dFeJ̪˖N>&Ret%bYG>IdW7-1_ rۤҟ >LyPPT6rֲYϋ~n-6(^Phߜsis[[1tdԓN'~fg/ >w.4_xۥ.ۜێv+W;;:'tsԵk箇]|cҍΛ7oߚzKv{N֝w ܛt:N";(Qp|tk3k{{:^LyRrO?72u/߿^K^YVwNZ~?=>A`/M_#%k4=7(:*܍}bd`/l` ,&8[ ;: &GCCou4E244yhNx@KȝP9~./O|#`l+ pHYs%%IR$iTXtXML:com.adobe.xmp 1110 1118 ڻ@IDATx |SUfi+]lK[ZBKY (_Gaeį8lU~'8(: nQ@eeҲJ[ٗ&'i7Mr'5c0|w{#׿O,s/i|nhQ?L1\_~fطVSL : DznO<~#n]kܷ3H $@t(7F˚x gey\k0?EZGg}btT׷V}yU<ʋ_zyޠhQ}Wѝ+>^Z4=R1<@H D /n~ HWv%QbC\_c;^Tdz,薅7ہ@vhζj,u-g uu,Dtw}*ηIJqQΆr#$EC̦S]:ۦH zێ{Q/Ңg,5,ӟ$ >Gw;xȒnX04W&h|Jm}Ӷ?T' uĨd?طҷ\ỊK ]^/Vr^!!O1C}ËG qo@H $DbS h>\|;c헛o,zz]ڟH_{즵Z.X7ޜGWBb)KSVjeíb<7SSRʶU'xt}@LjGonΑ E=Y'>'_%}d(˷My/T7y>z5,Zf)5mXzw>mwu{x2%>rʶ~@H $@p4 ,@Bo`|l/yh 5wQ-{EKѳPgۋ[ZYO3~¤}Ɇ=`unC*ǧyL*ZoK٧=\ҟ-אxҥwح0'vRMXg/trq_E+|zbIb|ז/J]Cm +wkϥ3҂|2,@H G`?d[#_aRiI`ڸkCË~Tih{0k-yw_=}}rէ} uGw?5kig&HtY{L@r|k/l.gܟX-8FklZ56?=~y֬ Tݑo'ZSӼv=F؆{.Ok&|bϴu_w0s;Iߞju3xs?8`"\Pb)j||Q=?_pW6,]{סj9 =io(eFJBUM}i2 O(%b (J>$idbp7D-b!{Vh@~X̾2ͫznu08>|[m?WsmV}U=mg򠥾z笛_pr?99q> Քxks{_Jg瞵Ǽ[ȸ8}\@M?{_*e&؍us-= 9R"@E,Kۓ8rc3>j37 pl,w_nRg>~,ǹy]G⩏JODS]K[ˑce-G]mb0KR\i;YA,פK\>Dg b{Vh{CWHA`Ɇ/FY=o3i8"c΢9kVM6 זǴ+~nfq#eχ81w~4AzbEKm^fYK3mOv8~yiPJyÞ O+.,hs3lQmϺ`m^'9̿O ^ejZdĘL ƾ-co [u6g "'_] z ˞~9Yqvx77۳}vmh9T^H~|v4ĩvCHro5x8O1͑{e}uE{1hBEEE'8PWW2קږ0wl5֑L]3ž;ux{Ȇܞr77,;5> w;{`:LrYw=Hr=^"7Wxt;|[j~@ۖ>B;HxO<(#"SPW_;FQ;<{OXnwYgnV|f u|xUu}{]@ZH o>⁻Ȋ=tdŞZ"$GT:CH0 >:g`{l[o={>F +]cr4pq^_R8}_0imOo8 )p3dtPܼqPOP8gʨHr9pgn,;اH979*'iECn4]*X\=(IK޷*޿-Y7 sa4N`I KO((Pdf B!ݬ՚4FijRUUuUW+/]j//68vp8v+<&{)r K50+eNd4& Fd[,Em[gLBY(H$.T.w N"`\9EH  ` 9Rt+Gz}Nw ?ߞ07UD6w&?_lٰhnvaS#8ڶ~~<ł7 ygO>dŎIb/}95~9?Fdթq?|pO"Fo(uc.-Rǎ͚>=sԒQ,ζpJlKG̰im45>x@}X WμY+9d JR35TVީ[ړ %S4FmqqM Ec||W$0&,51o1ԓ/ѱS[u5K}AHqEwt}IvwW}5Zʫ_`Bxt!E'Wɯ~υl޺U@{ԫi1OWp׼aQȊ=tO|@L4gFIV _%--]UIIIIy+ocG{$? "s l|wWGWaS1k>;<^ݶG4`غ|'̟="E=Qq=̾ssLo 7U{ Kt4SwZɆ ooK3N1 9S#O=xr}|s`3}Kl[NOJa ;-_OCY2@ HSFV쯅[V: uu /^O\Cp St:,H ( vd_cOl^w{Sʋx MT=/.I!Y*6mtOjUش뇮ww7¶R,scԎZxsʅE5cE=dXj_uq{Q,i!c+wdX7ɓy_WߙΓzm},[b-}.[p]@GĀ$FW򡌬_׬T}y;m@wҥ={~^P `\psGk%PȳVs/ᅫ6޹c -g+'IJ_$x}Ik_&r|תl{n?,5/q1CI;kw|a7XrO@{!-{ƶUi.yJn'xjDl7ymOa嗿[8~pNZWyh'߶gBo GbG/֎=޺Mk,7?3Xݸ$]ܰrы>X:O;@"t3Z䎽&7t#UsvzϟpFIJ_yteF,^, T3fd]}MeכԤy/C-r &!+zx.f]<#hwVʔ c0m\y&g^o<~ɓt:ZZO8/K'L9iḩI QN9Ïh.Fqz h޾w[^.!Y5{~xf?%]߱s{uCN{Ý lkƳ|m>rڽǟp h}{s[XOW?$bMLYmǧXEnr5BxnUVLy͗=&S'=]߇xͧ=~7ŲYXv*v]vmv'=̞]z<޴Uʺ?;Ț9uICYWs5FyfN$:U`|W}F s>I~2Ɯ9365gV.oKK;3fLsf&D'ΞSZX10@ ԌBFh(pY}fQjьM}u#߽6^lu'}۸<] Kּv͋p٢c.lU)w9"]tX:q7{_[Rp@-tHw7lS\Q|B3O;?(^sY|U&΋{uiC&D ͘L ?t#H&=uB\ CԃH IM Ȋ=pI3Cx !{{hm,ˮ]n=ϐ~6ܿ?:A pp 4F > < Ų$Yx"x^'I&rf, Ζ-m.ƶ!"}a$`CƆ]D,s8ql nf"++5~= JpY8Hޮ48'+R 4ʚ꫃zS!)WT_BHzW$Lҿ3qWゕǠ r5B}L?'GKq`0% ̖-*+b,۷O9ze GJKw̛g G]`00k8YA )PX\&7`QߪW/?曧jFQL@.1t$S?_8IbN8S6hIAPv[ɓYEufCS C4jke!ZAbYPǕmx O}K|JYIIՎĴ42 0"(@8 ύ$WT:ۚ#YIIAЉCvf X!]]qq$ BE>{W_9[ɵڋ#G]-)!Ӿ8$!p]!$_zk6S3x(HJAAx_",87Չ0<D-R θ&D39;8tiH!)$"Jד8aXw`rWi[ETA 9伀#ufe4pؐ Dږ*$@+@zSx-0N!5 (j/=mo†]L4Ʒ<\ NAyh)d3+ qAB@ ɫ8W =D*L"b\H T}Ljz?_H dc"{ά5(@'W,Y+'` aAH}[Ǚ'U9g>rF ` B#{άFup|9؋dtuW9;MMmpjHm;oW[oۢ}(J.4@-$>t!F?q bϳR=K*1x&3NKmmJ$q˕Oa0 $K@y~^r\l<=]CD6C? Ȋ=@gVrG ,A|Is3"n<Mp6N`)֫h=0k"#p~'$0-@OH*}+Юg}X#s #LMHa $10K $Їawj܊BQؿ&B@HP I}. +Y57GQa qŞ*ZF9Lr9WW[|#?#`8H pC7T1@8vV-L?Ȋ=>tj5|@R4$Em"zҸRŸbrDL"b8H 4+_ ,{#@aBsfmgYD Ny23S!/;~HNмEҔ$#%9.J@ˑ'u|>͈nȊ=>tDǜ1o Atm|WIOPtѣ>˃$N.>;|OźZTn̙*661I6$}ܹ3G'XpG9#G~5}zDB-BVGV\j<$L;{N֭w̛RP]٪|h8ti@ BR W?;kVU6!eK~PpNOn(|ss_\ ?SSr _gC*L!+Ƴqht*?^ʖI)?{>,hhqa: f>WOlT/mryV_!E -^8a9B\iu磌CTz?b#oFӦu L7bpW${\}XY,w;u|@iaacƕX\pW4]{:''b};q0 @__qxOHvLA} dZkXѨt*ҏ9`(h0m3e- ]\ 5ҪQq dg1ABu>h/̎m􃜣c= X-Aǎ1Bަ@Ȋ  }Xtƕ@ˁ Հ0 *1V+$0-&~={.^L?y=!cvkI%)>CM4`)`$XY$2 Z+6K*m G%m֜i4;bjAr͵:?Xuwri0$HYP5Vqc̤ \ϯbפV*rlG9Gxt]]U8t;I gxW"+čhp'DR  H%w*pG>k_k\Hl6>pFSӘ3g֦ldi4x)F3asK }8gT$L|y@[o2AT&*)!!!8)5\9iG;CzC*Y Y:EsR6q V-<# 9Gu(!?I D:@:pCnB$|Oҁn.e*L47.UbQ#;:畗^ig̀$s\bؿ~BJA['9qO Xd)O;D7xW;i`}ζGYʐ>}mܚioJz9[Gk+Dä8հA&[G H9" tt,ЮX6/3:@:pQM") 8KVhpy"XZ[GIV!490A}\Cvv{J^&85#la*) ̠!}Zv>5"-,i{B3͜e9286'J4kMWB*Cfqb^^X)@FL9G̥@'`h$N=$aNV|^K`iW "HP *@` @`jrS=he%%pXzzRWa!ػRŭ0Xf敄|O3U!90?G:1Y$4~5nrKuظ :" dRaaSXO60@]Lg>|pMCb8]c=WX&u?L),tDNE=လ  9P)wS`f`t9.#莜{B6  9P)4tm#:%gA H"S@s)1XL|qdW[?˭<^yx%ń{ҒA=w&+ˌete?g ͐}k6jkcτ7,} `$0,2 < "N ̙vnkG@C &/в3* >nFXBIPtsn`%w{Z\N" LW.fs 3 ^͂c0M9;sA#`R-+A ϜI:^TU1@VAUG 1M@0yȍs/ ?L5inm7?"w !49 !C,#+wda%۱o*28`>UbV @F4Y D5J 4Mp'3>\37)Pݎ})tu7O7a HeJ>hșW @z8"aRWa i^91WM t*tht)$@UU*)461,0GeJ>hrf\M ryPyXNeJ>hșW @"RWa i^91W醰WmȘ9B@%@߫(d#b,bj/` 98Wlhlچ܆Lrah-YA dPv]aD[r͵ ۾NkL+ *{*oHқ>Mov AAh,2dS"+˻"qSZDE ^fgez~ꊢ"Xѱe%lbb ϝeUn98W,7EE]:O%-? "iNf<"&ݍ7r3 E)^9 1-!JXHųlfHE[zxMm[oI&K}( +МYٷ_gϖT8+>GGukƎU%?6 p@oHZ Ck@KC*"i)l3yb 6hZ$->h|눖J E5v?2(:Νd`@ {,110 +˯DpHqŞ*ZF }9 m銞 G;"+pnF0T:Ъ;-IOq:Ro W%"i$ ~htT hx FaF !?'{$_})HC^ H!LrsYG*#¾1_-!32:q!@^XLZ+>}ZźMp9pHZBKCa"i#B`C?%s*7m"aZ "TV]!+ 7xYz  ţB^݋S^\ QFW?K"i ˴T:Je$"i!A B5@H9fu--0 ul $~{ά22t"|# n߂E=<$py0M||jKKvc#W8+'prE.bD*Z$->2펖Jୟ"iA! P!cZ} 7;3AAhƂJ$:ž-,Aّq8ŷ`QO пɸ)3]G@Lw,_D{T: s'IwgzR I\o $j .hx?9-!I!6D>y>Ұ~ϞOèA< AAh䐓bљUbIW9$&(+,X%=w8Ddshsƒ[Z$-C>!AK HZKT<:3U4} $OZi!Y-9{fgMycF/^QAâA6 @PbәUff;Zn\0F:{܃vvhSllnmmrg'R!ЅϴHZ&|8EKC6hx s0+*8IgRеo]"iyVHg1"Q韞LW670 A*LABbOՙULXCh-A*&:B)L.Ǜv=`f++`)ƭ}hx; NCZ*BpzZ$-W\5"һ%`eO7OGN =yIxufPYEa as\aJWi+)@ˣePjI`:!ѲC. D94v˫743^b@= lˇvJ&:?W{āD ɸbO-ÔK*G@EgΈ)8.Mhy3-.rEˣes7?ܤ@sg'q!qg<№M*\#g>_)g o~ |}A TLv &[dŞ V_}A p\HWiHH0پœ?1&jwt kKK3tXk|V(թ͜}sc@V(k)&滜n't63"'4گk422#g6>s,g?63| \j>n=I:lThȨG~g.-_Pax\i:gz_O),,zܛoqla\Vn7@cF逾@{tnYtE*U YO~?0b?T"ҒWY,/]Rj /ȅ`юُGb) 2!55%s!Dm0(b s\@Fz_{-ȸud&&e&' n_ O3O.ʈ$϶y}F";; NvU]]eK֭'bEܘ'+k^6vYxbe4+Jeb_tg .U'%ibw ɸݕz{*̺:6âִ4yq]x\iY$l Ys j5LrKLmmgG! ss}nl\c1G$}w X"41ϿbZ K✘!gN0$B4NO"ҡġCPBA"3SPH qmyY5i4fFԤg>]/CmiLLG=SmE6|=FV,T % F#$ I(4 0D%cH{dg%W9_;vWZ,TWæ !$!" 3q joYctPa?,EbV+,tl|uP[PUWٕF ާ9#+!?'@]-b9zXa ~TDӽd,â?ہuF|O $S G+0U݃HMp ߗ%!ݕϹ{9D'^u_m=Vơڴ%͂q_Jw;2룁@{t8ݫ$ 7WW˺agP?zhW~J*%F=!r&]! )tvoo_ +dAg0/:;W.!"#:b'kik9RPuW]:`kKA>D:} +.Ya ~Dӽ ܝT[gA盼<:{B;+P)L=I0#nmY%rn1'} I șut]9涓.NP3ou>ڥr+X;aP`1D,IaG&dd*@~*0S 6 κ X[o3z @@Хl>:N}t,"5(N|5!@\7iKlC9?>/]GJ$@+L\'^=`\C?vO} ݝRH< & -Y.Yj@t"8z! 18s8P@H "^؜,@('DF Sgz]Фoζ V1ߑTga?D7'b "$@"^^Q /*jm-lkyQbbΧV9mȹ( D83dlʜ~xw;6/7n{NX,sWF`=p82>p"?W?ۺW5Gü8D"v~ cߵxOHFr&(An_!oM% V)ʅkuR *]u|qmY-w]MznedM96HC~! tn˦RiHI1wLz-ggD 0=WZU2SXX0 (*)!! {#g$K3v랊(Z*}y+Ƃ6SޢufEZP*iʊ,<*DB{v*Z#~[yFRE*I9X@!?{\.0aIeXf!<)PEמ Kj D1E,BD%o39vj Ĉ0ԗ6myIq'ˇzIb/My5AΑwM1"~%U;WgQmO4̙!q:jΌӜ 5qr9< S ^J{\ܟsR F?;kVUUMBAn9?5޳<8!)'܉bٳSaHuM{yX5`?~ٳKB~͋(ʇW㽊W|6F4@DDًu;>uT)$>u|ܙɣrL6J@H " #2* $8+M U]k4fwxٸ ENV!I# 3Yb}thjjr>q˕OHEeŠHY뱲?ꮶvqiKҧSI=@g bOme5Pb\1nأ @H j ` GH``&Cu_g`k8n_`PmoNOF&f\4zALLNU++ &)P_\  + ܿh**{a[x஄߅b˰"@+]w D"['߫88$EX9= VDRa bBPltZI1k4&UUUWuҥn$W[7ٳOaFJd2uDZg*O),,z9sbܿBj]9Y3N"%o e ZuMep $N?$'ah^"iJocPJׯ_^)Gߝl2LFj\a D_,#$7튠$NkNVɄu}&T-&:h˫`j Bًu;>u+ÆO;wfhz06?+!ު?U(뮻]zJ$xBS \@}~/i!eexAEE&+Vh xe o), F[[v]ܒPpNOn(l/\ǟq_;vLGfA||z|ɷ~JAWyx ( $<0OвF22'EOo}TYٻI< ns|gT/mkL>{Kד$Ak-^.WO?={,< };q0mǼygw}p 90 Α@H D X~䙿'N&&0FcW׾_ Myy;jݺbFREԒB՚ghCg2I,qw7E"PHbc游Cڒ*Zc\%f!)p2 ھ};< `wGٰy 0p60b'Ly]P@({oW?SWV fB%0-W/@FEx@O-|\씝+6: $!L8兪{e0 B !4] "7WWhũAt@Y@7juUU{LExlՀ $9L8G ?!R G,^Lô!@ D< P_0!Z^WS蚞@~|s;N> F?/C! W> <ZZ^~-x $3@ |GzbP$"aZ "0a p ?%_öM dw((,8sW#F̛w߭s"\bAH @ŋΑ>]S Ϙ2)v @8vV-ji/]y?ՠq,0p&N7Ҿ(LAhْY=,P(<.?ݷtz0fm@%)P@s$BC^*E=„`ӏݫQX׻'dbY_ q<E>bv g'".U|{2I"D36`@")PcH @7 W(s `gAw @PL&P 6m1*홆^rb@RjqY3^pfƘYADVg\-Y!^ Z[ۙC'3 @$)P0ic_H @W{IO #gA`I%WxqyV⭨5[]@ H"@j@ѨW555J2?$ v h 3&L(/]"$"Q\AA?H 5]K[1UOBGE$KB?;M* ;,qI DHR]f͐@A )P cH t&V(H9" ttK;'ztBؐΦ;6EflÎ [\Zҁ4vYIK3DH @""$f}-I@tt5i{wX{/&^Z$-4^?Ι'6ŧO u8WAtt1"F쉡%@A&)PcwH d&H9" ttk@bIm|.xi;X{2߈ڿk e_CH)nZ"$d !$@/_h--ٍ{\ötp>|p? #$P(x9@& eLlA 9cHZ$-4^!eCN^DHGw;2X` ćX&%L )Gd`%q)I,hxNhxi97E@VkI\8ߜleshs¥J:@:p6m $ZXpDH @lr"Qb@;J$ N[Z$-i4vߜ={d6&s&SZ8*ҁ{@|&)jCHkAɤ#@HIyOWl,)@s"Kc93 n׳1[-Xl!LxxQP@ UUU:@:pNCtI{JhxNtxi>8WU/ 1>4 t4K:@:pXGUCH %"纪I9" tt04iix?/O #++zln9t hҀܥ1V"$‘@xP3@n $B)/]",ҁsl"C&3{G"`Z<@㥱3@{JH &л{l0t([OT.תkյ .x7z;E07כ4%)QrǫHY@˻FQ8c! 4ӁJ 36qؐK5ӤPT8 h[".@6 h&N7…tݥ{QǕWb8j Jp.}4s} ybݎ}-O1h]^rR_f0&K.}ܹ3GpD șWqH@18S~Mj+62&O?\Ah B9?cO檤$>@ IWyTt挸+msĤIٳx ¸;rxsR F[[v|.}EBAn9?UUB|q14wKnÜm:|8RS I ~2 "47>+a 4٤aqT_jj Y5AWzSIUsݑ3Y.P6o6?C϶w0WA$ [z@y@DhL]wze]s3ڰI*^Y+PĈ-kZsljx!Qls蜸d\u]liuI]]窠?39qޥAW\E~"ޫ""jnSnQbB*ҏ9`(h0m3e- ]\ 5ҪQq dg1:Js>h/̎qL ml_.3Lah9Gɨ0ӧxNIMd (BL*9)3W724Mlx1Ā0"21-c |T3LdOHBv[ "KQTֺTmRlV}b)[kUE)P6&-@e2dMNd;N{==JWUWVFo^_Q^+n'dWI=+#l쌶X"V!L[Zl>R(U@AC d霸/~B~նs,?j?q+cN6 8_0~ڳRȡÄY=pn}pi<F-*6 45!^ <–f9=!Bę<W\G_{VpOo3)4aڋvu WH>CQ"CI.>(?W2, ۷!!x'{/D㿾&֎4Wz`OFFuB8a_5$/n\9OcccssskkhDR#{*Huc0ccc{>ھӸڑaH`ཊVW79fl85lJӯO5g-JXg;&i?5XGNiŋw ᷣXQi8 CH ZVV93[RW!GEF'xNpqgⴉma^~GuTvJ]YY־?{31.sI.иrNA WZUT ^ʄ|_`vXgcI9z\V#iŖq䨽lXaS%+q,?s"QieX!,66l¤z>`<пm25;?~&**U5;wfeB zP4BD`(N*1=Ez<50L Q$I >0ܙc?ϖmj.Z%-L[:ͰeAME' ѹ8q6R#mU _}o"?V9VcK_zUSzTp*,Xo[o`2h\\ {ܗ,Ri? +=!q %[xSΰ5o/Vhg5!y0c.gU_>/ wﰌ5BYBoLkl}blj$-+I4N*"gCCS7 3. "?t<m@=x4lW2*zOH^AkDNm` 0w^;ŰW8"ScVҠ|$ξ3$ Ç@Q>;QA܁isF$:5G vNțki =xD.Ť8L~|Hl_<VDi\y +N*XM\{A_ 8쬘}^kivd@ P-He+XZM *A hg1]T+@xoԘϟ+! GH3+v@t6p`S~<H8{;DKLw24`Mc~/@̇ 1 PE⬢ERE m[1I-%%{x&+̝wȃHHea~/\$Ο5zp*` 1w,/wtht[EL̼o +=6ggU ^}!!z}YL NIA5.M]'}17+0QDW ٮǵ0=!q:-eO<4[lVd!K7O8ߘ\Q9BAC Uݛp6 ?; 0 Sg NjS41umihuHs66OL,NJ 8D%N9e>3{I(os@j { fͻAJfhmtLJ+dG Ou O-_gHaK 8,_?3&4'씿 I7l$ww뒭obCN;]\Aq׍{ƕwEUW! Da'ԫ8'xqn=*a$Y `+EڔL+Ys =иR 12U::BߑY "Yc^(GuE%s(a^*8%‹K]b@k-Kͺ+AvH+/R4'}7^$/^zxL)Gק- Uv_IRM5+ 8ԳKcaa݁5Y9}UWjv4~I_oϋ˯#T>٘ɋS/R #*L7ZS(ɋWT^/o2/($~La,|rû5;? 2Bh?G0Cѹx.dѧ\5${fl5l&XZg>gϢ}/D5^c6[j'@JWOuixdؒɋQ7x|ؒ//aySfágexx R+ɋW`FHEf#cYUw:dCVdn7}4EݕOƕ)^`yxQHjʇ S_"y)ݮ=xxQJݝʇ _"y^D@NHKtդGY?w7*{kjS؇)W||n_^$/o2/ARIH^Q=&DHJ)JֲioP5x4bDbҌː$,HJu 4RR D)#mvD2 /g_ d^?T]rt\{Hh<)YT& @㊆AUl8+QAHٟkMmX"Sge/>>J"0(WbJuUZmS dUzOH=7f :VVl!QW˴Y2 TkD D gYS> ^$/^y|͋Q)PTf 5[E+XKCPl^$/^I D" }뾼H^KCǻ^xx/LE(9בagR&<-/GQ,R(H D" "^5,LDE%r'Y^*XEËŋ}" ddF~ʊ-"y,!(V6/X$"v-5՜gL( Zumm;wNN KLK2|n ɋWl^*be"y~,B 85~,BklwX L/U*K%ʼF"#˗_?rTܹNX^+<2e̴iÕ St{pV R!"ųJexٻk$B =*L9h5IϾ0^zAD ep* , F2B:ZVWUX[55Lx5S15_ [e;vlo庺c&TTd54$wo;aNLl,0XJ>+BxqEWBw{.N4AI{AD .{OH$"@p4k|eV%@HA6+@UqH$  |t{|~; Ă=Иō˸f~Ѭ2 3ܾeܹ~[?ee{ȨXhWvv֭++-Z4C˭(@%UJcbA#{B̮qfws9ٰ/**a$Y `+Eڈ%`5K6v?t ]a`pSg˖}?8h肎[6tHBW1:Gg(y,/U* &^\)qR |Wg܇hl6{!E.y#VWYAB.v/xciwF^0S00Ο 2Tog ::U #wD@: hΗ/!͂S=!qb$q5 ({0 ˜H^0T~MH!ʷq'hr Y>qfMⲲ%%7<ǎة; >\8?沲O#Btݩ=r2>ih Jx%Z }:^poi:aRnM&@*KQ Y d j}Gּfig$3#[[TV"Ϲts(5n  8D%N1S.Ek ߰mv:;0 $ 7%$DBLH0AU`gOǘh)N{2u5! &R!@UtH*x; lΟSWUMhEctAGt-)_2ֿoXoCFw)xjUM={[,c(wIlgvM)٨˱5LqGQ O _ q4E@IDAT*$D#VʛKaykoQp %%#NF` a;8=`R?Ū 뿱.F`f6BX{V{(%E,˾ہH=!qhlWO3[!"@Tn& "!@UwH00˧^ƺm|\#ϜРAq?W\VV6uu#.;y)(6I^`PȺ1ygve/Y3e 3EVCd0IP G@@qU}Ţu8ί[R8\3 ,ci+`+Utzgz 8ݫ1Bx0:=!qfu!'t£&qĊv:_kSqџp{dx艬!_b' cgLu _U|˿l^W?C ZO[ZP]h>1ӯZUTIhuBGGZ[[uToSe-VGH]pKdzTT"ѼgXQd_FAhQ " {,܌xhWVo@'$N}CS 6Skv~*6OyRKWP"$7_x2Τ)Ӟ{8arDd6KeN9ꍓo_ NAwgي| VS{h\JcAPx l0:;XdZ,fSMT[ WLeTTطj߱c&l-xv̙N,dďUf7]:wfeBCY'$*(Ytn&n*:)8R -Y I +g훣o@8ENU}E/G-Jm&/7=CGt3HqWCS8^b Vee򾐃%pTe0,k  S~AW_4i4;w.gR2^,0{v!aB^rύ=Z+GVx]CKIR xM| ]qyV-钚|o0~~CNp8C/eUům8ښ]kbj`_s-ַʩW?'Lr*?SEt4w?G.k(%j?>HݻwX)Vۅص[-j(PTHUpw#f<ו!LoarOH].tu ̞Kf܏w6j(,{;#^i1{ڬ©mg?'IjNnx{6S5'N5*:;ېOI uz}Hdnc6j2L&S]̙ G;;ǥѤ-r]ߎ3x lKK;zw@lvlךE%5p\]_=&Ne|_wtnقKW~9/ޫl:P=pK$tt톪m.aҤԹsSfJ((&ةn48Po_cQY0}UW7YVoqdkLgƅrQ͡T`Sf-_Sj\U.\ؑ[-+Emvvٝw1!c.fP㊉p 0 ֻ^W'by8ܫg75I5NpjVUe>-laܻ]A qiL'nXhFEFz-&5#Ϊd$Xiҿc/4+qҦOKs뭳{.{1s&/]G[Y]3̵֋i=]VqI-ƶwy[iD]tX#ς~<ʺqIpXޙqzeMv q٢8-(:'L_]c;B* ޫ}_ϪOL4=5=!qLڧ@^=:B- ѴzQ?u#8:J+LSR"i`7n\g,^,EBpTQ~}ӉNANț#7>w6*+['nޏFbf_]r\>yfg?E))WLFH`{Pm xf{Tgp0k0'd43C!S x˧_eSə[WWƹ[5]AZ$gWllq~§=ks3/ç@ϵHE!Ygm3bǍlժz!]~S+ΖȩfveX| Ο~wZML,LN %[Tš+^/]hQq="""y`+P2U4]]iFcNKKqN/1+StO8ޛ8cȗ^غx[VCG#yjugn%њзۻ_/BZS.5tdٱs‹@#+ĆJ~)vlqkD7*,bcLz0/}雿ꮼoѾ<Ww޳gOYY[o#wVvv*ᔒǕx:\߫ $ѝKժs8Bza)HVkZCC[##1!v`tOy\@L+`_+%Σz|ۅQ+a vb1q Ul9K{@-SIr׬ڹ?:=[vR4I {$+JL,{dX ,{::::֭[g6Z_\wݶȕ+W_2ǕבR#@*\P<R A&WIŖ@qn^7^njq 59RL{7)f:ݔG{_6կe_'15N~IOa/S|/~1cWmuҹʲwѣáٸ;ee,]z¦@7tĉq5B^EOy~KxO>BY3_u),qVE!I~!?MZyk.] K12h˟晷?dlm_U$)'=::ZPu&=t }W?:iӧO\DqB$^E@)؝M- g+ʫ*j.,"d"[pL 2bN,tz?c4(e]{C،jkyi.zxgkv bұMM"TpWon?6:辜 21cS7xd lv{Zty>m˗/3g}\9ѣC"@_\u_S"@ O 5Okg #6#!$Nɗg LKfj4-++l6_u_$ǮJ+,f0z?|޽?.hϛ7+pZE{vʿɠ D~M 0UaS ec"Dvڿ3A8Nͤ8k,`exxK1ҤCsKmm6?(8hE#㸒re"@)% $W5>ck\T~mJ/~)0Uؚ[E%,ݸ*,,Cf7wPmmQxmNƕ;ڨ  D@jHjd?(}o[հrֿv C6kp;e9elʊ-"y h\Y,'NtuMJ9NPmܩ˸rG!DHMR }"@Io71)aSdCx @Pc*l& /-xx)tI7Ype Ʈ[^z D@\"-Jf VHJb+@̰YcexxqK7KJZ}QqT@@3$ D(d޾ʿ~VDR̶b H^%W#|ڲn).Gt,;+/"DxMR QG"@Kfg-Sii+W!L빍KJgZXY^$/^Dҍ+V%ׂ oޕWi^Dq P $.OF"Ts7ӑlF 0, ŚJ Lf|d$++ŋ(G-*//oiiin? >(^Cg\  rHN976*dr/g)A!X,zhS'Y pHȃ>AxVcAqշ¤ ':5"\8ƕ'Q["@T(,%D_&M"(!J aq1ѣ#]M^AICD . EwCw\lcǎAG.#,ø]$Y DNR "@E:wĉY<AI&3k1'̸^/wx]8uTgggMMjC[ :;x-ȇƇ̷2 D@(R$D8?5J5Ƈ,bgj NnaǤY2w} 3%<k]8>4>dQ/"@2 P B𒀩\98,,J/ !@!BF;?ڐ!4Sqq Yp ٢H7KJJѣya5TKP" JdCM@˩R/laC&أB_Ȏƙ?o{u/9Z5cyWqU\\p8ΞmkN':;w^+# H~ _8:7WBO 0.zBHHѸ(N&$@` R!XNFx@>p/.DeHׅT"%SU-kPX#soYƌ'&t:v@E,xy>hnnXtǏL/v||[& DH!d" syfȐY7Q+F 6Zqb b I5}y >`5||| 6SY=b4ҐȰF\? 2 FWX<^;kQb?~+Hx00|Ge>@>pPc"@ P Cڈ=m{L͓ڐY/?? ²RS[ AX. 1h-Ǐl֊X, ab6dGj@P JrH' n￧4չGǴ5#hԨ6Vfj40? [<^wf]]w׽ . kt""bT"@.M 2552r@e&=tό~VʆSV[A^^Qbboš;|0";8ky1<^;k~RM[\<^Y 8rߒoCe"@ 4@ՌH< *"/ZV"^H”w][Q_>iWIIiFcNKKN/1@>p9-߿Xug,ͭ5hh;:h%j9!v;ZڂZYk m Ěo3)+\H?,/5p7 NxX)y.LP5JT}H< b䰪 G-PVHYD|RҒS\~fl/Z)McD~3soY6jPCwDe\յ:'A8\%%% fJ匫R= Dw}E ~'1"Qal,,$ 4(G\"GnE2[l}r2 ¬k\ ˷% XAiSD P 5:HB $_hYφ}2G~㢿檍ƺmѣ%i]a`͎R7!=[UսJ;  <뢆E:EP R L@`H^PN!} x 0r )Ďlji8\l<[V^VQv.2DeEer3($'+fZz6:5NÈ1cNwj ;;e+wB6DK蒈 *#4?h,*V*RrBcYB HiF.x^R'ph*+3SU^Yn2y^ߖQ^QK wAASq~PԒ"0@P  &/Tee>GP"dvH2ZvرSNUVVfeUGАcY,:5MhUΘ游&$&ŵ:EFF1c&L)иr!D P B D@ƵWlւ+21,!XVDWHKttt| a61|&Q !!!)))Y=p i\y"R‘l"@\H[8;-hd׿2,qAU*w@PP**+B2"j4#c=(#A/| CtttlllBBBbGu}#W*$ P !0jN`KbNAl!vrLc ݸB#:W~O_,"@$wMAиĉ{fhäh\\"@"@)Td. %`NO[t%ڵDF@r0!d @J" 5J&Lw}n>qdfvB@ L< x4M RH dE*&pݺzvkL6BC q%jrD@%D(Uw#)ֶk(BW" f2 ]B u+ "@P ? 'MOΝ'7mb**@63 C*Lƕ D@\˓"897-dկ.CU T!Bƕ_S"@((#!D@43~.J/HtX{W2?\+Tl uq+:+?"@x(%Y"D@#S<3,FTf aT#W~O zԗH[8;eLnKIɞut "!iCRh\"@(u!D@&;u,&{bu?^d!!C*(+\Apd:~kjIP5{峕O7_!&/ooD&'+*.o)=(lji8\l<[V^VQcinmv G"#Bc2Ӣ Sb164u9H  D($"j@@@x˩RUdj꼵kY X{9gي+?S3nvEJ59G{ѿi\?y'DxDR pQc"@V N7G޿?XxsTKc5bci 9gxos[ JݝƕԄ> D@,E"&t艗jE/Z4㩧"J׬?k3gbvflM"BXbԊ塆(JdƕD`, D@\˓"]v{ѫ-;XUreފZ7q%7[gmk+ ;_`i1+#l쌶X"Vb-8ت՚uְM]@#x_(坙i;;kh\>@d(Sc_g|N}E'@)H  j"P#k{\"vܸV9o Tڵ'N0mOL[p_̲˧_PxI241%d u8uhjҘa`._0~ڳCuWN=+\ R2J"#E=@RP&@УDSu_j>ֿUܸqߟoHܱx7珩bXu.ǖ8G!aJ~dj26|T߷f_cے29,h{v6lzUQ8r@rpJ0f~.\0HᔜT p 1 qqqz4AR ]VJvEH *#*-֫7@c)?@#?C{AȂ5u_t*øRŅ`N)V|p=bX!o(:6L[To}:7E#I(W>MS!eD? ,x Jb 7:o͋//J]J @OpH D@q:ZZϔ 0 .Ի(<A6ć(S*"J&F~bRxP[߲g\𿮟2 wMgغm_IKGxGGx攫ymw 'Ncn8N"@ʫh5ls΋ų(@kN)P2g'uu?lQϼo)mصߛZݾr&ޚ+3DmS)nJ5G{~=O7\ϨA?r%7M'}MP,-baexx &aD@X$\8fl@!c[Fӣƾ$rgYouľsc=?sE}"'V9:&2 H^2ԑ "얟gn" K؄6T;{+ \ui-ywN~7[׼Yř5>՛8}߾f/|s_m{fc>,ޑeźHh" i"D@Lu-J[Oj͵燒゚D&SGgŌяL2v&L7dvZ^$/^.bK#{O_{}w`4 ݽaMo_lZҝA"8g+?>f= =Š[^=3ū|4vT)a='׿ѠwWq]UG)Yq "@(l8TXs xhG]h\ =Ho<?Vx >uʀP9HPػz2~W7]E]8z\hNLxhoj;s?8RHjdU0Ul|z>{+ O/^dn7(Dam1 l #ij 4u9H[Gxz:l:'}-z60!AvAZ{?ފfl :}+٭}":uaYW 2u_ +OV7()Y$D@  $8,,~ĘQ 99^ׇDv?ұVf2ꌥee-g\8z>*x.+mѕc6ԝ*u)U S| ijB 4r!H"J~v$>3MXM 7)J/.zͰ X弄"p p#Jd""MGnڶ{P &Ν2kVBAAphmPSaScnj ׻bi,,;pv߾Ƣvu؏WM\uWxBEgw{0tQ_"-geh\?i΂1=Őު3Aػ<{g#O>\)Ǐt-\\KHdKv췛l&v}ZZe9˗㙏)%Os-[ʶn5oSH~1ᇷܴTrߋ-2ӚlBٙ|ij 4\+@^y^]%||ҠGCr.~qhGoҔkHbf~o wϓ UJr/:OP~RM#s _z)7n+,|ЗIL 8\g!2 zҙְ0VVlɋ`W"O~B: Wnθ{M ,ɝwswKa3E×W[q7Fy7?jH @ b!D\|;f77UFMcOU;Kzޯ׮m>qYn>V<KƱJ L|kNP^$//ji\;9Umٸ9Mƚ%;g"Z /koDsn~w|d 9wTHPljFߴP-7vs~vaO2Ɖ)?^MߘtM׾i@SnRK&)l袢 V[B+T4$ZW^Yys:dbmd_soY6i8sFz?M6TBD ųJy 4L^# 6_p~zך8h 景~^>D/uNg\\AiP7UWm|ŕ7:ӣ!a]8!K&)Ґ0"@$$ؐc8?]Gco]G! RUy/CbGe g4:~J<@6E+`'b`wBzqo9 ˟݇^x_q^ĸ.MX/`zMxMg\Iy MDd^Ag2m.w͹S"QF`ИL"@d g,y#̗VCX '7m:_9_'uQ~@^y (FίKݓ^ݻ ܨ[o="zW#%>}zǎwqڽOagPUUֶ C32R?hFtA!q>`N۸qŋG͔gX J @OpH }%P $FR!Ylk3_5C\S7 y1/UJ]q%5a?D奧Mˑ HII5^W' ( .#A{0O I%kL`-d/@ $A - 9 L3;=alCSi\IMF&qPɆ"gxO/Nƍ~V6=$A3 S\9:o*^j4dYW%"@'\RBcJpH ro{0OH0w}/z ,oZg} r"!Aftw2!„f "nW$k~!bY`5ދsL u]P#"@Ia&[Fٟ yψCdTX.NL4t$&R!Pq%dr!ܲL&>Owk,d()r"@$!`4X}t,7H]byhlbkvPJݷ1$HHu-i\ΐ,(n٣Ν;=_!T! P>lER 4l/=N q؊jXzڵ |g Bp|)(N&`PȺ1LDB*;@Jjd_N eeeFR9 @D@{ۚ0GQ1a.  ٬APPBE㙣#F\ow & Pq%dr!䖖SN~J #`lyAR /Q"@TCo71)d&dC+8E*=;{~ee|G 2濵 W_u y4xTcGFbdwv>--cb"%Ă0q&iCxGllh@RA^^QbboF>˃A>;8kHJF RH d?n {2pgP@8*)`)^wM_KHHQrnjٓ^a0X<肎#0Gp'o5+  "pouI'DA 76*dr/g) p,BHJKt,h_غ #ХTGGGՅh%j9!v;Zbs!VkZCC[##:2#eGA]*"@NR _AO3/I[A!Ƣ"!y$kټ;[^)McD~J:>eV,5DK4J6Hl>G@@M/JNBRU*e!MHQw뒭obCN\4A{@>Kv=||O" JԆ0U2>@>p E!屋b\iF"@&@)# J$`=drrX9 ||J"||#D P $?sH:/43-TXxyɇ< (ם&K BzV x@ߠxĖLKNO3fdfΞrqJn㥺 CD)L̢+.tdp*9 A)|H7U*'?j;mo/2ɚS^fy'Y85.P]~("@@4\"` 5=R(Rc!e&+x]?ּc@CKl }ʲY[7V'鱹kEu%'y#DH2>uM&WU319N٨4='~-_}٘?8xp!x!2vpH @3Ж@USSay m;$nqʬQ7attyڟ>6:;<\vgdy<^or n&&=6vp? {u/ڲv^!S]iM"@4%@S Ms"@ V:\#ݰcDz}̀8b!YHm,Z?ǟ\9/|J*\.G Wڴ)~ $œt6dgef,pџ6ƕ߽ߨeDj$DX=gţF1"@FΝpmƁ0@R,,kG8{[w4q|K/^׷4 !( 98WX :SܨQS]I"D%@S <  P{Zخ70EXhٽA 7EZz"@O9 n(p \C;A'~Lk㼮x )j DhB@`%DKyZCSO19iGE0̙ٳKsW܂sGy0prO3"@h 5aO1uK=N߻ט8D @:^m4~@`U{--NWX-8.#0Q]C@ Dh dcG" G dõLO=\(@  4٦<~w~r4==E#;€`t~"'"`]4ȉB`ݷ2Sμ"۴)@",x kTpִ̑S:S@HlSc҇9BK@by7"@LD {~eX@5O>96-'@~S6 MX S76j[t;ς $׈tt"`4ʑ8w'9%KGŋ9l x%IAjz9'Y@T#-NkDttL]"@#@S ؒg"@'+w8Zyi!†Y6})[%n\KATW, Y|<,Lú2؈> dUZ|x-=}~i)S dx˫ i*SS ob [VI]YpPD7YF|DډBVs''E8%3"@ Ah Dw ?eB-D'1}0w Hg2 D"@(6auD} Ё@FR)): $^[2'D#`)hllkll_jjrNNfQQ^EEqEE>wwIm!JFr2}dΞŒ8WiN7gQx5X\.*fdǟ{Ƀ{&AyD7t+s-=uUظ~ϞY--25aCSE (?5cӀ;5W_P8zt˕>w {ϟe|tw2ɁazŰiV{[v 5d55)Ac~OO)?X+!pԜUYKndϘ᛼ 6F3 4^X76g*&&`t}[S X?Rv}2 dpԎՕvl4$PHtJ{N B}^&EBfP&dЮ @]`]bH! *cA%`ֿ`CR jm|HY@3}緰`j]ߨa-  bP!`i~+#+FuW\U д ?SOGrzo{(rsVGbk$ZB !TW-$>m.##O6̻̊R!nrYi=1qƊJZ `<^֒^2cxh'?SuW>uE|`V1}.n#e]H@V:wW]۞wFG%4v~܃S( 4{olvݷ;0Aj e=%eƒ%sdUTdVV:d3)}얚\>1w'#h IuPD "lׅHj0!yb {zd `8+!BƫHU*H΃ H(+iiLMUP w{NTϩbu棏^|Q|]m\w3VTW7~ |Iilf\ťxan'g\~ֿ,AԺjoibI |o#宨_ŢTW|⵮fxڧ6dd  yI WKpo/n?6NjLL?N/yc5Ϻ\i?@ `_OT^vq\6X GeUNUղg`i=O?CC"*--qƊJ"@*+>P?R ?ђʾ"퍴ILp:23Gm 5)|_WaT b7llguu/9E%沲gE:ƀ1*&?C 7/鈀g{yn ux'Mt8M3f=xǗK&H xᤤv1;â"0[|ב-fTigț[w3=*{Խrr<TBUh[ a%r +WZwj5sÿ4?U:!!1VGGG \A{7W~|ij{{o.tLi`zN?X||5(, n|ꩢyWWϾ˳***:r)o喤GqB VTM*j"0Y0/oJt$iO%'wzrrݞ؄F c]_>L缿eȫ2?Jv<-r:]!"lW*:h]i]M౷?O-EM~sQgX"0]^9ggƲn[EE-^y啭%AA4^q06$`yd{ɍW+]W-y̛W>Е=k[V!t]i#;$͊` x>yrܳMMg>ۺukIIp] +5cNx(I:d?|ޡʥ 7j/v{zmjfVWauLN;td(5uuvYMMA>y6**_%<ȃKFǜc{ u%]z3VOiS|0:; NWiiۂT: >[wЪwߍuptlpR~}b΋}k? e^\g`كtnA%k׶Y‡ժU.b]+} Xs6+ݑWpQv=-c{y9F[Wpvy0R f?t~s>΃vS1וҬcׇ)G?x<<Mo 裹%%K ?Ͽ-|O2 ɥI$K5JoZq_e "+p'?~% ;wngggooGuuۭ… ?O?xءT VxMŠ?చ3 usYg“rI Q{Rg8ˊ\߳/}y`aݚQNNs<h]e]Ŝ"CX]{s%vʵ񖟹Y%`6oOfcc=׈6lxR}ꫛ`qBzbe_r~Ȕ_s?> eUr?#K+ւ~C v:|8{mڴ ^*xC1ˊ?N2xeB2wPx]76߳G~8X **pyP҈L[MY wag"d̙M:ʕGNM 'B\II{uMv[.?Ͽbє7WwKw}5Wb5 V0gGS֞RyÇVe7pϟ u}s7Xt4?^cYIBvLXH +Xʕ'^G]Ng{Iɱ]6nFAM1JS>عT{9E$c[W޽竇Sa^OٮV3W0im-O__W­/@b@/?7? !Hm X{7>?P!`Ċ`JSZZ )(ZlaB|ԕsYIJ@2:xj4^E=FԨ`f_U]]| &4.EA5!>'S:.<=譛9_7 ËOT]}^ڷomXokjjW*p6V~$WY4-^ b~X,g.־~YK'ND%KWVjWdKqƊ?$nlp={nܷo]Xkݰ᭥K~ӟ٨[]iNJ3SjqJ:@k dڵ"Ѩ1J#2n.PKMׅOU)fKCZ`((Gi!l @RlSj׿n!lr<ϩS\uj2A:RلXӍHCɓxU p5"!ޮvu'ѥǏG3kt΃hn҂I$Y2,C^﹓m.< &5'P_d$vgʐ6A JHxN l[|&+PeflYŖrVĊ!Mq,c~t+XK]YIY9? @΃+CJ]ꊭŲe tg}.۟l#`p=55%I rO< iCR%faC GkQPWJpe2̉?4YGBڍƫcǎ?ZוvԃuYIuU=~6ZR "-vY!S +S f>T#dd VV6y2kF C L R٦J!UmibX ,6sR`Va588s24c,*dUZ+~4ەWiҿ5ԺE@<(OI^֕p<R<w,7znc*KN?<& @ D^g/0M kMr&Ul񨷂 'c+z5PزVVdS&Vcij=^iҿԺק P^+֕x|bl 4ڶ]o/nMMSpR/ <$i͘ V˶oO csT* !H9+ΧJ Y#@kĊ?tlu)8 gʨ $VER6:KZePձu4 :;RϜePJ0Q@:ʣcirfJuh@"΄ ӳP\W`0[|x V`;ij7OW)OsA ΃4^_Zj]WCCWeZՕ "vY4V+S }},czA/I<@v:BE?8H #NdSq:&g%I5r#XV?:"VȄeZ"tl:xɇ<*Wvbu+x'j_%VBu%6g` 'S:=%6qz%ׁ&nLJeH MHVY9KJ6 d1Ft )o3bO3PWDZL{ V Ų4iVuԡ8LAk*u?ճR0jym- laX)'7V!lg*(jt )fe6زŖ( iB:e6˪/ƺC0"UXE_vbO[,+~IS񪹹YAN`ꏎغҎL{ +<=@`BA~b4RWUG=+KcW~mr! 6%l55`"Y8$ )+ fJ7UV1TItHb+QX49bM*Z?c;WS-"ԡ(; &$ :_+Q%+)PSCK;<an-ZTV:Lu $F2kaҥY34.\ء"'aM2`X62塨Sl*rb~eN'r)|Ѕ?!x)g1^V:4oޙ@vĒн<-`\@j)C{1+{JJ^0V}AR fc544U_W\lfVXTϊ/nlAZ?>^M=]Kxzel'b ΃SceRjXqMN7mm/MJ ;7{p0#6W`\[Aju 8V bwc%ө! 5:N3l"<+p"=ϙQ$53QĊzV}ǫJՌ%Sĉs6;sAXIe  \`]!6>Y:6jXqM?jbyf3Y)8)qb"YqN'68eT>U"yJ38ALx6N8A8g4N'n,,-Ƌ^x "5^eϙ‰Fye%߯!{q8q` vi.&COI> ĉdwa čĉs&M+NskqQZۙ &rrzgjxOR jH8A8glKUpZYT 'L`Wz{{[Zo 9=`Zj8A8g4N'n,,-Ƌ + 7ŀ30l]qGR*:y2O;: g/4N'5 )"sdJnl NUysp,ĉs&M2+]g5 N3 l]qGR%!X #eԎM 9&p8qkeah1^]e4^h9.\$a '$A)[+ 0A!Օg$HubWڵ>8AAֵ/ާ@Tɓ>uΡ vp d= t|J@WBĂ ⁚) ƋƫظJ}1Ի|e9"[pNAE;Y}1b>M%@5ȩ'dTSf 6f$w̗Qk)eQ5cPYV^]9@0oOM2șO@wYM>Uqge179X j~CTJʱ+MMr\V3E?ඥ΃uh y1+EA@Ņ,Gc22gnkk`܂s:V'ڈMT un N3Nl]qcs4+:8A8l]q[K '`WR ĭ%x1*h5ŀ3`l]qc5s}E{CtT3\ HJ 4N'5 )9*Nidr ’%GϜ?<yTp Ρ (rX Ne<$ YHm*X5رkY)QeHuj8͛7_}uuuOniѤl6[Y٬/Z(7WY];jqŊG2x7$wP*X7k .Ʈ< U䱫+/;{*73?.ଲ2:2  +rV%+)[4m ´k_jpyy 5cVCZb%%V5+i/&@c;!/+y>x/4eb%%V?IiI| y0>;\͜ZE)ϱhwelSĪ_m=V?_* bŅi\X0Ic; +bEW25@A8AIJ.Ty˦EXdw=VZ6-!@6 ҁئ@!ՑTk1V0͘+"T VL"HdBuc5D"@c{$2*IbLh; eXq dW 1^='bhlP!`[ t )- bznhV* aA"b Ċ**j0PDUTDLX1QbS V bsfъG1GfݛZL+@*"D )\bno{=`AB0cB X$V2pv*(ڔ!@c ]*&X$VApbyȬ, 8-d']v́$c6!6Y_>(o{Zjҥ#G7oNL2/+_2<+"H VA@d6 ]F 6e.'h "Id"VA@d6j  ,?8t^rhJ?|x`w4wc!5+fKnsUbV.>\q=Ōo0XE= *:I b5I"e=>Ҙ$@c$'VMjIO3 V$N`P|ǺuL|fA3~0~80XV=Oފk{819YBY,޽'; =s=T$*vb$R"FhleXE"NBDj!VȄ+D%&Kn{tJ~ቸ2_w_+d=+o0K%)M, ^5waN֢ k~+L+4 +/ 6A3 V$$Jhl$*:I b5I"UtFJ"!` G']99r^v3 ʾ7y؊v]!|2/'gd{A_XEbѤ$b=\Ҙ$@c$'VMjIO3 V@BĥnZ7ph ,?+kȨ1ze;f7qO7ò 﩯/\ʨ:;7 X1X VLd#$Y@yHĈU$2*IbLh;6pgmknF4Li1#sËA%hbKߔߕ_V5`]c9,}RZڌŋaMO¾'VQH(nb`DM*J"(nb`DU@h4ges>B4Ĉmo8Av8\ۋۏ Í2~S?< òʩZ}uz=D)bUtFjD[UdHc$XEg4A&ID?hRczd H];}ǽug&Nq |Tbz|U(H-*v MZ"=vb$R D&X22 Yi5ģ~K~")߷eOEЮ6e.{g-C3}WeneMVΒ-[*nͪpccÎ;wڈU* X!QDFhlG0* X!QDb=Xi8wx]o#S١Gֹ֜qWS;8${g^z"kQ%N l.-^h͚jxMQ~}+9xJ<⏕\r4_CnXѹ|sJ)tCkn'<yfTy*/yN?4DWZkFrG8q=đl .VOxFeeOIPp_(YTt:rIc|n\{ss0+b%;HuFd(HH&"V5&Hrs/}ă(S3oZ;[2+JgN?~M+~VOXפ"V5㻮tIн.7,=]kCTUeo(YMsfH|+H?~M+~VOXפ"V5㵮 1CݝDб ]_H"`2\UVoh9MbȈ'Iuϊ4 P]+~TWĊfՕS g4?jr/v{bqzq8kn9cEY AF.zz}#zLLNJJMqd!VĊ'@ZA~ĊXפ2 A-͇vmF"@ D"@'`D1QD"@ D(/ D"@ )ЩK"@ D"@"@S SD"@ D@@@. D"@0M"O"@ D"`$D"@ D(42gHre:H-,Bh|PYn ǂLN/.^3/f- jknnoga'{ꇖwyZ -,؄ʲY[7V'c\2q3lHS|NRbLgFr m#mYtpR`(1쩾;|wiܞ[=d7~332=I؃G/>B|2_z3} ߑ}ο$wM/`pX^v:,pYua?ϳ/ ukwY.Don*%qw4o[χ(_Oa y9MbBS S~|^^ڼQ!Ѧxm8w"vh勏r9su|z?߰NJۃ~kAM<(ၯ}}CR?LVe%t+<ˣRͩmz>kzu7>#7}\KDm)t4.?jn+Zw>(_ OǗ_̂I9`ß! ct9H ?> |9t|uHÒe tG譛H๲Xj>@0-jÆo#oug>a iy^F c@ը].y)nQ1ڳN:/XޞH|Djyj]ϑ]%՗ fmK+(` xH AlS绍wyKtuA5k 0)P| ,P#(9c^=Ӂ֩~#ʗAL]=G:ht)Pcrv۴)@",x kHG`kQ gX6/_!Չ>5 R "<>zt}@j^ǜ;t ]NM8Q10t|g/kR6hlm._}{]0̯>!AHmj'#Sx?-  HF|Z׳xH@`>5M#^+Ju eS3Ͻ0yM[U5s:@:O=jN~?4 /d HR|,!ֳ`H@BSe?x࿖_`j{>|h:d]Q0_|->&ǁӁ4!YM Y|fO٦j6c(_:1CYMHdKF x|.3 AB H:Q _!W2e.S7G&qXC@ HJҁ4!Yy}{Ͼ71RJ!IrP;|3偎(g{ O<5`?]U0jymbGt )N5`^~w2o/wg+@, &@0t6!T(_:׳)PD@;._ Myeak>|\#:*PVS5̾rV&Ǎd!eRkk|Zu?u I*+0|–T'"gyZbyd.|D|T2Ot~pS?yKfUTf6H Rc9YynOjdt 0$5 ؜禝&_ؒg"`-.$ [TO.1o8`/`spKHF`E,];·׮ +qj8ehErMc+A`' a򍍛Vt|&L \6>FwcPn617v>|CABW "_jї>qj8ex@1wEk09NY`-zy;:vП6M%@` ylHG>"`f)~sF -Z(`l)_ES[|/n@852OH\S #SRy\[QR!eH\x2LJջ}SCY<6|yCW70'>s)EnTx8lE1c"v+ yxrMN70_@`q&@ju LGz6I'\W qk H9 +UJLO}:zҦ|,! &$lB#K6zpb}pG//x/_=[)PGW%kH']ׇO@&45 /bYM(_yV?cyB¯MHlBBeB,@Mh]@?zl|rL|~G5 3ho8H<' l]q믆sFM+Nsp8xH vi$ӫӍDy' % qXGF&ؕp8xΨ vi 68WAD/_efsĉGk  )"@O0|\k &rh DpMfr\ 8AdiO$q8xM+y+ q!a\5$3l]q믆 H '|vPR&j8H%&dsӸH.x%ǁ*Htm$*_DŀH.^RoKI67>%&dsӸH.^R oKI67>5Q/_e&ŭVƇ)|r5OAn|X2 `N9ٮrxfdίGo_÷A;-}O#%&Yds7,4ez+aHM2E!o .܅n&)μ [6"xI /%4.T›R͍O"xI% /%4.7^+(6+MF&ymFw~y"xJ JB32 WC_j؅uJq @yU}X* 7DPʄB\pFĖ N7/)7_IhFI{bbŦdj?:uqw|~ۀH.^"oR L6|嗵vaR 7>B)0OjqT 7YElـ%&dsӸH.^R oKI67>%&dsӸH.x%¶{Jdџ+0>YGKMx)Ƨq\ބln|K*Mx)Ƨq\&J+դՊp:@'B-O8*nlQ8hRlش`@Hŋoꬌ?k<٘/y8e'C?+~Wܜ(qbzP)UeQ_mW~Ym/ rʓKXjز%d9[,YN'osy_<8[nڤSG=k STq)j#G[_=&ؑN_pn?v*5~#>+5Վp~PS j;n͢B֭@@lFA#S7+vj^)ݑ!U#6MH'2H* ѪY+aV QveaWc={l^_=~)˜߲ .!^)᭩ھ}p9ڱL)&ˤիS.b;}R*%IJIRj2~Cb1e'ί))XϽ~)Ԉ܄ ]=߈ύ q~8d \1j\ "! W'dk=oYd]1dzS#$UlF/oăg$ u# `55@2氅~M8\_=\CaL({}w8ߕl:vz.v9JFNZM_$jϚ?4% $CtMHa8#B6u<+ `eДh`惱BmTIu @%7r_+6m2"ēA)6 ǵ~NRp|eM|i&$CCHԊj5d=e4 B /+ǙRuM\}({ƎT_mTU7BSKk>vf~F6 dDqbN0o7֊'Q1,Nk z$a$Olj/ί&i"ƌae lD {:MX*uJ]gt`ĿGk`c<=~Yv*Ǿķ2׶T2/};px:w[pUnܟԉ{Ǖ.i)k=ol_j/ƄO%M|Blj/ί)d)#sHzii0y֯s0gx?D{nί~yȄ=B*M6uwWUMX|,Gi>?p?p&?f1=WzBV1@/؄]xۢY|AG\/oАpxJa dy XUj_K~c;'מ~<8zCd Dgrⅽ+[+*ҲKKCv`7m:sBጇϙ7Kld#wuV*&7s2d6Wct|~q~x60e'׀<ԩu{H2LPIk¾} &kl,/鋨S[a;9f{v%~t=g'u$,>qyH6__mGY[/WxV1s1SԔx2Cᨿ' j:@G'C:\&~"sUou_~&5{vx}E!JqOK Ȱ=4o~ox/O%@ޘwCG*k xיt'y//BCLp,!s[-g211ZHU'8x?kb nK{#=1t~?cxyp>:xpʞ7)Sn}T3'BJںZN9 ]inPcϡonLF4Be?9s,ϝW9g[\BĻW~sb =7j, R?mពUGwH/6ӽxv;h}z׿4@IDAT #*p~edz K` da51C>;)j92!d\Rw Φ]Sqז~%&/d(1Nt#}"͂nOy//OMCϷ@ pnupþ@lEgqߜꮉ =}dʤWcY3S'Dz~DԒkؠ[fh;Ư0i2Q09dz}թ]Ng_ $\?6k/hMz))1v̇2PWkӁvdS *սw7DgM[<˚]o% ),X$nk?y gij(qӽIW{R4,;R;rTW@\)~GBO@an03vS *-'*似Eg=}Wۿ4I OB 靾ZmVQ%)7~ҢOr_ed?yhn)h>zsD>~ m< n'L?} uf?5kqϡXWPm1AU]v6?N3qߔ~{_sr%)PĐO,9 , ܴ665Mvhg%<)'ǔQ_'οݯX76dr`yۙsgϷz|"r+9N23q|u~q~i<[@V;#҃g>Gϣ])j[V_#vRRJ׮zaߜNz{On\3=zfC\$b0@FG  `)])r^iCO7ӧMn]E]>\1=6z1r ne D#[]522M+yqުB́;7lhrC]O2ɯ rG(}")Plh#0 Сk/zg^_Hr\YjUjQQС6[+++lܺ[STN5w.oAd  DS vݮHL MGo<ΐc+k̼ s*-< eeuppoĬG@@S n} Ob!Y\BMR'NBbwnv˟|=^յUT=3ghZÑ䆩E  GS N`4\4RU?Kv2|1-u]ljX@@ Z ` g@@`$)r[D+;/(ɉ j=t܊oYr_q?  20݄)@ D~.Ayhs]iRN|Cd(0H@]9i1>zYZ_ņCf$qN@`kADFSȸZQpn)Pzyު=܏     u{#ES ȣ_` dtt      `L"~A@@@@L ) %Y02<0@&@G     f,@@@@@]ES ȣ_` dtt      `L"~A@@@@L ) %Y02<0@&@G     fpx뭮k9Qz|bár~TYKƸ R'OH]+ UWcswsOb]NgbB|zjBf:X +yԃS+' q1+;^9oҁv\$]d&Ι7+{niuI9Yb`%N gb\ɳB<+' qV3l\0j[Ns6&BVܜ;yd$+' q% 0Y}okb`%CIAyV: U?Kvvuˣ+3.!`))* ՒJXĸgLyW`%O@> gF2h Db!%$dΘ6iRjQ؝t]n3-^o]][EEkeeӍGvup/awB,OX<L+yVȔ'qV31J|;tFGMjwocRO^qؤW~k|^[IMIC,fuSΆ#7ugHY3g-\;~Vii\||Ȝvvw7W{w!  g=Zyy%-ʴϦvݮ菚 B1mZɃ[;Ľlv(߰رvӧ{+\DN&X :VA@T6JELq}{aOE$J62V/Ot-z @jGo pݮ|;3=^#}ڴY,ZwWWN\)ُ%t4`% J|&ƕ<+d+yW`%O@>3个L̋׉8sVm_SԜ+}ݮn~Wg^zҵk^kh}'7o.{fbWwgPXA:~8 hd0乁Xĸ!+Oj h֐}1θȘ+[=Ǿ40Ra ,YaC((KK'qG{UUkE8tDʼ>H0&+y`V31Y!SXĸ+y!.)%_?s_Q?+q Vx= UoQV`%O@>J2 `\<L+' 4.3u=qwǵNO G4uď<+?(:cN0+}8H<GkMN)'5Ul@"I*  `%J|&ƕ<+d+yW`%O@>3h\?Xt߿Z|3I$I%kM#]~тZK3Fx@RI0VtC VT gb\ɳB<+' qV3Mђ$$d+24nA~ zLl"5\)){(j;22J\8+yn`V bgd/+uUezI|{$ dDN )P[7ug['6m2"ēA)6#JXJ~${G0+o=f^ w/)4@FD_Gs/˘6`"!;6GXЃ|+ *qUaV)!;G#nc Uo-Ԕ< v&)V`A-+~+1V` *qKmDvͽ]_fuC@꧓)%lY|`·+NC=+u>(Xq"q%OJ!+mJIvȔ30@UDVtĆV4l@vȔ͊oVJ? Vz V|p42W  3%bLCP#vӘKDUD57EfrdJX'z+^p:~8 A xcn*v)P{󟬙3SlM-x2E!nY xCR'V|Q4cR烣V` P`u:̘z:JȚvN@v o-\Rև5n9,S!/V'skrXyC^0"Oָ尔`XḘqa) yX?[㖭ܦ 9dߦvͭqC![ra~2-7*bdn[K9oAn,7-Gv TC8w|GYqa yX?[Ra~2-7*bdn[K9o Ul}6U!s63ln[*?~ސ lߝ#ސ 5n9,!/V'skrXyãcaQ2-Xy:./UZ*Sڎ9d *2X+L3jY U`&C V "3x?gw2sDz\:{T{.5j9Q!-qb3_%&` `i`G##q% j0\_ f2mY2qCued|&5j=uVJ8QQpܸYބln4ntR r.x^JҸAn\oKI6W7ȍ˅-r-ć+%&ds{qܸ ބln4ntR r.xh\sq2y׊QpG7ȍ7T7ȍK:Mx)JqI /%^i 7.7$+j9^ rux^JҸAn\oKI6W7ȍKMx)JqIIKMӸAn|X;RS _EQS\, An\,oKI6W7ȍKMx)JqI /%^i 7.7$+j9^ rux^JҸAn\oKI6W7ȍKMx)JqIIMj.9p8 ;C ,ssE7py+u`·+NC=U:;T-|0X?jL׎ ֋]VQv8* jXʚ54a)&yU K72?Fj%}q{TРZC+kW`p/&߻2AC= )s9BWO44aaO) ԰)(TCV) ԰)(?6DB8^=:РNC+kW`tF?ҖE!gr2РZC+kW`а~#3ACmQ˱G} jXʚ54a)&yUg|v^@VA؂(5jUN5,eA K5 ȫp0hXJ^ 6R(أҾ5,eM԰XY* C?z?@AC=,m)31AzE5,eM԰XY*  j#58^=*khPRDA K5 ȫp0$.Y-?* } A K 44a)K!b44a)!R5,e)DB 7EpV-UGC"!FC,hhPRB$hh0GR_tm?xM%5!3l୫K*d"B쒅~Olx d:1RÏZVCNGGBq͠>Hp}·ՐUf*}`agKtdP AarQBQpܸYބln4ntR r.x^JҸAn\oKI6W7ȍ˅-r-ć+%&ds{qܸ ބln4ntR r.xxV6MaHM܅yPke2qI /%^i 7.7$+%]&ds{qܸ ބln4n [x9v[W$7ȍKMx)JqI /%^i 7.7$+%]&ymK6W7ȍBj :y(r2qI /%^i 7.7$+%]&ds{qܸ ބln4n [x9v[W$7ȍKMx)JqI /%^i 7.7$+%]&&ds{q.@iWBGvw( qS=M W#+NC=9+8 ෝPJ? Vz V|QjRSR\~A; @ܤJޮ}?Y# LuV L3rVCU{5P{j(2`&C YNiL{T{.59f Xu8n[&o Urސ 5n9,!/V'skrXyC^0"Oָe+B÷dskP!`dָ`XḘqa) yX?[RN5nYƂ({n(W{,ָl`XḘqa) yX?[Ra~2-7*bdn[r*9|J6-r?o LNn[o Urސ 5n9,5u)aQ2-X\70j8|/U!Ӎ-rYReS& JXGPJFFJX'+NC=փդƤܶ(\L5숝*()'Ϯ*lQ)jC%ˑ+yn`VrV{QNWz V|Q4cRÏ2]v DƭY ܺ5(}}dJfN7+un`·+NC=+u>8+ynZ?Skz+\ʱl#.c;Ճ0@,K迏歩ھ]VAd̎D?X+RHЖ|fc|[gjwx0+\͎ϭ k#dL)#nc r',[( o (IfGb X)wP~$hJ_dJ~ X)¸x\q6Dv@LC!tX]V#|+y`V;(?`%;2{%? ¸l\5'ͪu{xS OQaׯ'g `% %ǀNW#J~X]r wq<@F؈ÛQSK|͛ŦM@FxnP,J!XGPJFFJX YKJ!gUԜx |% dDN )PUŅo˞y^l. >MȠaV ;2tR*&X :VA@T6JNС VwcM4k@iƺ^-}O؈]Tzd%pXJw{i`·+NC=+u>(gw<~^1OOFxc_ ׼39əxaJ֊p똞|Ӧ='dxyĦ&Xc+A1`J8DWA@T6JN!  V*p*hKh J沓+N k7kH;O"`Ŧ-LTCĦX+' q% 0J|&X W~[8:|3I0F~7ɯR܊].^,TLd)=d g_vO|" 3I$I%&푼 $xu79jl?thŠNN+;c{^9;) V`%O@>J2 `\<L+' 4ҺW]Jzw\kA.㫻OjJ6nԌMՊ2rqK%$ n?X#N>X `5,"VŰX  V`%O@>*bVپi zE ˤ?4vWv{jNzfáҦLYc>:.4iNo-'OjYK<;kNXɃ+' q%J̮KΜk?{\MwskNw+9)>=5e|~ʄBsJ2Ҵڰ:W gb\չ,:ל/b@&CϿoXAv @DݻG[NT"yy֯,){ ɷ 6[Q7nxR`JH2?:U>h=}6:&̿f7_=9&c\+' q5VȴJٴ}) o[Xv^CL=ˮ+|/wqy6~CJaH+bE4/6>N­FMa_ޱ]Ż-b|>ƕJ|&s?c?=&pL*B7*_z&BPc\GPJ? VzZ4%+y`V31Ygs[(zcwKLGl czk}]s{\>gr/e}q=X_L|kE&^*Y+8.WJ|&Yѽg\>)`bab}1θȘ+.nx ys'h }ڴY,ZwWǎRNc?`V31Y}O5}t /l+^Ւ{73p>(-h-nbkZnO<,o?. jeM+V`%O@>j*;7yWHVڔ>JV^ܞ -{Z<U2soLl_M7])⤳_D̙y ΟUZJ/fjgowwCYYݾ}w7>2p3ݟv+' q%ɪ?ο,nh;$ָ<[WeH|Xxub+sV`%O@>J+V3;>m?:{2{;;31y5u)o(퍼n} XObBOq 4J8 yݹN֑s&'S^o]][Ei=s=]];Knz]P +V`%O@>J}/b]}s~᪻=z. ?y q%?* gb\iȪ;C5ZOWMjwcROs?.okKoiO|b̸n7h l<򹗪NpZljWՄJ`%J|&UHVI?26z%q {A>e?'`b\ `5,"VŰX H$D7+C@ Sp-QKsKǭ9.G#X<L Vτ[~qN߂Pܛv6At'f߉M[W J|&X0;+P;.\僤9f'Ҥ,+SV`%O@>XoF[7U&fF(V}MWmF`W "3x?X f2Q)K 3'&|ή?ź4^Bfzr(D 5J*X<̠qpe6@q@4&~FTL-e.`7c_⛈CS ( nnjs{Dlـ-+@N`m8 ŘY@ xZNT:=_뫽8<7]:yBUܡ2!ܖ^ AEr…ŃQ2,~ $ uۇ7- Nj1@V;# `E ]:PVÎ d$6*Dfy\W%[6{@d~"xcx+p Ӱ`zOYP$x}5oze'M~4Cq+nοe˝aYmK JͿ9t4.^Wӕ}hTq4+ M@涏њ/' Amh<򹗪~%Pe?NNOQ99I=-m0/..7HHElRb@ ,@jdk] k0s|5o3Ŀvq 3fMZT).v:nL|Kx~[WVQZYrt#]C+p/awByUo:v2+"W,XmE([ø2 =:(?`9.JH6ډ)NK_3.̝??4.>zݽ B[TnRN5w.w <ӥI9}oLԋ}+_Es󰑽 *$!rS(;;WsMԜ` .$D!Zx?j>z2[ƴi%>8nRGllСov(߰رjӧ{+/}/{yE۴m A:ycgR{g6Wijg2wЉ@țBMѩG!LFAM|;3=^n#}ڴY,ZwWWN\)ُ%tTl{Jf挎B9MqU}K̤qeH@ `Kfq8Űb 4,"$D'zHS:VnϕRvիc |eLxʙ}Ƭ⺚Z^])E#6p~ -S}EmIH0 1 C@MD<g/Z@ho^ ,YaC((KK'qG{UUk͖#'ZOVX 9VM. 82wM~} oVL9Z'u҄)dĥFj$@^ޘ+nw;`ܨ5F0S # 豷w:$ĺ\sk5ZZ48',_va>zSHluáׇ&۫jWJv;VjRV"<52ALk덽~ĸR烣 0Ϟ=kwO]yQW yy~۩kֈ=&$Đ$࠷Q]q$t5p3JP H \ةwq7a ` !L:zNOH6eʲ,){LH I"aB &$^1&x)}͢ $);I0J{Jo¨ H[ `]~̙ss%c5$JR$@!a$Ol`\]~0ҏ-*L(z՝BDڵI99bv' B6Yx 8Omg)2^uGRB{ abӀ@t%)xQ@L7(O6mbӦY #B<7(vx3-]Td=EDQw|CbJ/pW0G/  -Lj V!VywYƙԖI@Ȉ(Eɦ4 m|롱 }iVx!C).# 1FD0t:(  FH @8'{)&P˘6` D!;6tc^-KpA./~ 9&$>`@ )TQ@d=^_BDɃ8 nlYM' "]9ȳ~f+xG6dSY*=R$? A@0﹃r! Լ[9t鐩6<@vȔ"lYMg3}bl[~K=vHͩnR*+ Rw)umo+q" bk @+;fʕب#;dJfNcZmWS?7]?n >%{C 9RuDQc\q2A@^^){)ZP'QUL-*Rob ٷ1)'Kls[(ͭv2K:sR'vw'}^z:WkE|뙄ɍ剁ŧKL¸|r@lJͦ @8f̙7!wd5g/@IDAT>8%?X68iɄUK-g^hJp8;c=VVWD50@']!;2?rq˖ 1  0B 4Bh `9?rqd~͵r'OYISU]gÒ:iBk~SՓjw2q7m] ` +^0%׸RY#]]!Y&\:(sKΜk?{\ /{;-JN|RL(L=$!#mg`\0.JODޖQ52xHЦ)M1`\A;@D  `kJ8^ r6DB8^=:q[H!) %؆|k wp8A cפՊpܸtBDLSѡ! j/ YbGe rQi\S/n*zqCY0@3G :jlݹZ@0q @)˱G%nJ0 0: ` 4:;\@DŽ7- An<*͚kUS 7Sw(  x@@GˋD+\>?׌˱kց qܸ4B @#‡ V#"ʀƣҬ8^\U: r:u  `<LgA@@@@L#)i1b]_||zta 7nQأ 7 r<1ؚ@>} L vx"ʀƣҬ8^\U: r:u  `<LgAt$*} rpV-U-%b@@`$0 =t[W' An<*͚kUS 7Sw(  x@@GycD Ge rQi\S/n*zqCY0@3G :pꭕ"ʀƣҬ8^\U: r:u  `<LgAt$:yr24k)c7WNsܸNݡ,O``XF  9E#GzŞh q AWS˥mgε=~v6;ɕD/ܧOP8>{NIBFdix1`@lGS ۝2P#.Mq%vu5;Wm52'dRV?:U>h=}v(a=-m"%Ir_3ү,v`\~ @4$)0Q @r:o(R)Yɲ z߿~nˎȔД;<ƯZZ\Ji J[ &@&G Ȟ[*-( 5n,m=W~c.P)*He8?dJ!sѯSn[֯GT .#r5>L[ۥYrbaA 87v Ș9Z_jqWϙK~_\7Wj=Zp䦣>/=*^|dǯ\p\qgsWzF}Е@Eq$dz}@wŖ-%t%,YƲu8 ۊW^U6{{S zhnؚVvhCO<}ۯCf-ӌq$b'ؑYfa[qȨܺnS(}}dJfNc{ZP'>?.'n㗵 5 F 9R<:SȘƸ2<m ` -OT[%ھ4QcRM2Q0Ьr#?TW'Kt{'rR9RT0.q&uGyWLk1([Ȗ A b DC6_0Тmf⶿zz\nQ)*He8o_&$4 Ƹ22` ddt `)W盎޵:tIFNaMccߗ{U=PY*>ԑOH +q } ` ds j 1?q%#ȾA!0DFc'7o6 AS׀^<=_yuuG=$$Mc@%)hH Ǿa9/\Պ@__=MǏ;_>`#>#1kzgs&'=F7v5(=Zw1mRWl\iJ^_g_&W`D0@@F #+XrCO !3))kM?b(<6; i#> \ڸ˽$h$V8Q+P# LFBmAlL&9c\:y?h_w7:[yy&`z׮w~嗩k=U5;OFDJpa{8kF{-"go{:.O3JNȘM+c8 LFBmAlOS<ˎu*y?o&ddNp\zڭj_OO>冟KV|q\zy7/m[+.}$N} Ɇza\A5A@@+s:  @ooK&kV,^*HZ+++lܺ[STN5w.7~ %y?>.eu߮W̓s,|ERm60L? ! `  vF MGo<ΐf[0wRz=dP;{ݽp7XwbVF~6wObuUg~/"%97? Nøқ0@0 A@ˉ_bKH= G<\M9/?z^뭫k{>gд+48# Sᅨ(t{m'S _2VEW,4Hl/h*ƕH@F'{zޮU %@,Xp}wz I?.c;wsܲf^aJ||o!W9P 0 ` 4> Cyso+;/(&5sKǭ9.w6(eW:CG{ =]p:?𣖊GԉQK9j8 K(V.:+P;.\۰E9f'Ҥ,VHJWQyZa @F0ɂTФe[]Gu:=_Ko4*)+kv .̣O{>ܐit'^JUHċ(WV> 0z` 4z5hC&3_r/[gr]v@=X D"[/bd\t@'@t#}@XSE%b\eCY02<KHQRZa[2āAS 3O< KuI^ ⭯ A@ &)؃gx!];H.^$ @  !d){&vY G"`.^D   K  `I}nKHIIL+N  0<׈Tpy\Џ@@L   WwMbfyۣbF.[D  @+_=S 9'{zޮȫK/Xp}wz U-t0OοKh'n̫;zϏϿQG-/;`P0"  `$L@l@9Ś7މ BʍKHȜ1#mҤԢ"Oq;7vng/}z**Z++[Nn>K%wvǥYp'keܰnߨ]5l$D( ,H   ߎ?6`N=MX'd_ؿ=t oĖq2U*[t{O_8Suf//Л̬Otݝگn?hߑz iw.Qq1"@@@Jx "ʧ{|ݺSƥh^؂/+J(iǞ-/R; e,$ 'Z6ɡ5N-Ymiu3^w:G>ȩOI*żb̀R "@C E=C@`#=ն__W>!#O =q'ZkZtDes/mǐٔZju& gܹA0vT D t4 !y D `_}xӭ|D8ma1i ʮbiKQC?^մ}w}s: s6)h9@UO"@F@aCM"觾wpH ScZy2YRUM,mmL E(Hsl:;Ht~M+S'BPRȃ DJ!uJ7~I..S**Bŋ<`ok:]Q"΍pwo籪M-Mx_f7n:$e'$/,KMvKjWF"!Ol"@b?'c•>)Ia[=pDZcL Zo)w&xԮ&Ƀ0%{$X 4}/?3)M\\7_<=`:شIѰ(5a dd0@* r!܄? !P«)֝:{+"CZtI?a$@**"@\h$YK@ ̖ o`z1` LAEEԮ1H"@O42"}ZMٹkD_ +F8J0y鎔]II|"@"G@cO5" 7e ֯WcoAP,@>XHxԮ L> !S݂ ZP8#Ld ̎ " MPR!aD@ h-@  'k6o^RA!A!J,Bλ pwo籪M-M֞>enDZAg4Ssť&AUUP !D( \H ী/ޑK"46BJ>澎C'5Nۏ_KEdfyfg,{ʔ93Y jWJx " I" O25K2; vꗿCl3]Mw7C&{ܼ k nQg2JR0zG|w5Pl<^T\Q"I  D PPY"@B`{1$1i!X,~;oi_&QP笻t&'Ӽ/wξU=>24v[ݧj6Eq<^{) B"@hT?AQ6"@&Ԕ >@>pj=;m3[w`gn_w[Fg,.w1T) D@4*$D b[k21;& >@>pY~زk?Es,~mϛM6(+ь*Ps QĒK1R,DLr4 'F>4I! ';?:x6d־PrG7K@11R3x@>J !< &హGi8RS>"||Ո/6L3$_gTP)KHb<^|5F3 x%QDi HZ""7lkiDQ*GAat"@  h<J!D u.햱f8 &6G׬0)o{<mRTͯ0n؃B"@"@CpQf"@N@$ffǤ.yx矲-_ɵ?G7HU3 O֗x@> "@&"@CP: QI@tc}He4؃cI(lJ  y.%7x@>p%h# DIH¤ۙ Z|0ƪb@İ U[~RZcxW@>p mxmlW }}]:լ{j~?;q\|mxxy|c&@ $*P_%6r xԮIF @_eà ۅjIh:>A0 yB^P98'<~v ol>81K8 ~NU5{)wՍ3~1Bj5lq͈r]~iN15ŋc", .9IL5LKouuUэJ̾ڸ3_V8*1u/Wʜ>KU(?Wi{o}\!w@(@]'8q<##'U*Ǻuor}+BOsfwwuTc~Nڻy>Ix_]CoFiK$sva1e]wam{v镼 Ij㝗Ǝ-[(g +D@ooO'D `)= N?6<(('p"'@yd<%!PWe%UĎ %h wkec"VW!Rt/yE6d^o{4,B dZ7} ͻw#(Q0Drhlanjcc"y*v%!LrEWo,1hCtB}3$bCV:mZy^l8QBp^M[y>t t&gev |8@iRa,3E%CJB0b_xn \Qp<%3 :̩Մb(UohuK?83 dL.|W~wMͅc#vpbQFÔڋ֘i)"yR!ԮIވ}*  xgHĆ@]Бī ]nCces=P 9٫aOnQⱞL?B@ ,'DRZf=]љ`1/I?+i8"*Md}B 9ƣ&qDliic'󚂳EW#!ߵv8*s_K$/^*PτR@ľJ YPtE}BgAy e q/f65򂂳ఠepb{NpW]]tzVnۇX ȃHHeaEod/5Z$yxIODd(O@d }B8+Oy&i4 J eռl mpbq'KqA`ޣ_Z8vP\@$ ]m/,cUtW[ ųD jW2%뫬$NO8gI$?-c456|ᕼ@m@Ny2 1qI3KC~pe*AQA( !>l] 5UW1 +('pE}B83,Wmoi @AGÀNy{T xQ;#w* F83dvTsAl୻VyA1 lGp>ܛVZ$Ⱦ .  eD jWr&1L﫨_b"('g`[j#=վCkOݚl1UT [Ԁogv}BKKv6sd؊JEÜ88UE4z}/G{u93ub)2+;:ϼ0xgOr[a03\PPiiWZPoUޚ bүIS#9T#|f?'M3STfىInni;/Uvs:n4%wnXFɛ::?)-hDbJ8_#%^k.tȾiwL)rFl?y=q7D{bmI=MX'd_ؿ=55Zɾ~ 'Z϶1>.}3"J&Գό-%-]M(D}y"^{fjM h]hNsPCOqFyPYeI}B!Οaa)'ͣ Trgw\ʈ84Wߏn_+V_!,})X{3 ɰOy8# `~;OTkI=졇roAYevk޽g/+ϽxŜxǭ;ΙǦ).ksog }dz9%k;v?+9xo_={ nO/_%\BX{qa͚7MIRP ^ nɾp-~6;yw\TKmkv][YyEbb'U*ݮQT&4mGg%Zkyoڴ(X^|%yfP]-H Ӭ8+Ah$OJ߰(w<:CMv==iRR$=8ݡ ާd}rYKxdh27vE_pu)T;?5J*- *ǫe?*bպvWW 'Npc`HFI1#EaO5S-oϸ4uw، 87",n?[vk~}O%⫯~ԩU,_~/ Թs+n/,Q4ue^xǵ/sn\}V0/s?AүC]ݧ6omG=ie-_tiZy9^|gС*+=fYwMǧz? Ӱmg2ȓ CHR/+/p!౯r4&wO<S.< qjPOnw}c32<:G^}ͬ?wn˷˜c)s",` ]EP'0bS;0=3'ׅfasO"l6OZ}B4c D_!>/>3~ǐa[f'O^׿ޖx['R[oj_⊓qߗs;\a.h_S@|&g(@CK ^xD ΃RX5}nO,9Z;<^ğ/6L4/ZuW#?tTlCJAH`|_;To_` mmBV[~|!55,{~w7M>!q$D?}U?E>zo{ eg CS[; SFW\Q1.R  }=mB78G# '/ܚ֏$|ֿ|{ܰIY>WD1F'>[4OkN-sjj76`iѢ>с施l]y&(7(4mՏG^2(UM..^~9A ұ>]͇f|VD'R1]76ey60OchݟyקeTԮ1HIU/nv7 7# c_/JnlQǵp(k;[t!bOH`fcĪi2!KoTVs:ճf &FQJJjkjJQdٲǻSP)K@XQXbX:qf( a `H˻z.lv:6?CKŮU-(3fMxG9\{TgG49c(>9g66ﳠb3PR!ap`]֏W6a7+AZ„}BT>!qfĻa_}-^WfWG@IDATomM $b/vF3RU5l6-^na|N|79mkNQY k e$mJ־޿]a+j&D )>ەBɐ[_&D `kP}d\aI0a"KfUMhH|||j 6rmm7ö }VQGGF{{V|`q,o [\ >ކ`2J d 5&a`[#Od\Rcp 稂[}JH\Hp`70BF5( ~ Q@}B̞wC!׮8n**ʑRZZENd++]|"tv Re9 &1F 97pp&8\2:.ɏͬ:l:ܺ! V:9!%W4^vR%TazKdCf z!be 3{> )@^ڎ*5z1[==я7<޿,b ILAe8G"D 6 `EܼgCÆ,‘!u]S\ថ֧8~Cq3SUP),"2@L*??LՃяY,11$R8O٧\{lt,OCؘۛܓ<4EP}f]I!}R`B%0}͵8ǒS\ϧeeɾiz+ 27JDA:TWȈc +ͫV߰ {>wb2p *6U:d34Oqj@QQgEg'_l.[YL'g5>D)by*T@fO!۬{ L<%g%?F&!ly~Gp䴫.޿z]wigrq3<#V0pDBdC(ÄsTbcKO>47{hկ^m[x(=}$>^(>ǎ_EdCftI@C,0`l s-ߵN%7mRf{Ig<]S]]B[7ϗ X﹍i8G˓"D` k K_F?:L$ 9* .Ttwn'Ȯz^84}28!qK3 RźUZgɝ먭-6de[AA[/! [ )68+ѐ0"@0D]kw`Ё \!p;'˿ 4##K$2 2 xWg',J Uhg/l7(('n<^B䉷OH=>b Ǫ^bq[S@bqk T^6KT &J~RLZ:_u/mK( AA@=D]~ `o?pDXwkVqXِEPpǎ4 W9?@0Upb0cpx,Q/8YqpC/}uu*cS>3{̀oN`}0_^2]=:WZ"/8+"@x)sf)ݽǪ7 4 4b%en]مtFINI,K_X 6v8kXKx _mnXYId"U+O/ qJOkpWC>?{B8ј%\XJ\6)?jg<Ο;7/>̫ -å D(N_}_D?Dg2Nrs{ASZ}yjj}2L+h g (x^8?S WG}ifT;OHk,{)eCV$ N7pZbϢPK%|F"lP䦝;kAAG \q<Oԧ  N 6pW}B\;` ӓܜYg><a8S|"H^?e#J# j"@T=-%mDqqw8 %!*g]-nqOg0 \JLK$/ޟK%= @XN*ϟTg3É ɋ\9T> OD"~8ZԋNC]ttjj0CʅR &'Dq8+?E&T>gH!PS+sT1mP$+!:t‹Ļ>+$/<e D@CC0?nOyJ[b}yh$Dt/`d3R|" C l3fwueLApWp>"y> F6/*%DD@CCR ]nI~@@J>a!dTn=fyx>m^*wę#pޔyԙ}M\6wnZաC6;`H^xJ!xID  }g-my8෍YSM9YI3K M3'I铓@{{orO"ѕ6DWTG i*J ANj nqX@xx"~ʇ]qH0wj~pN"A p!ܮ]ɋSQ)T>/"8tD`Ê#O~OٮUe9 3"}qyƒrCFK'c=1ӯ%ѕ֟HN j⽝hPMIp!vyV"yȐ /K C 7\??lNHK] \!̙g%Ns?Aq6u7'D185m~ܛ^ud -Fb4 *qе"XDW/vx f$ BG Yk 9"eVGݞxon0ۋ!Βp Hxx/pʇEqnZ7o?ǭ.8[8G.]0]9. >B* bYB|_`O(Βp H xx ኗʇ.GY `ǏͬK1ijjf R,%տp;Uxh"YlY sfZCpz^2wnILɤ3)b3fܹKN ;2lmځy٫uP0@߮46ۈFc1"PJcv<*" oWla4 >ׁV Uxh"?)!Di8'!H^96>71%' >3annSss> WXt3[qV"y1@`-;KڼyY˗g.]V^=A"nťɗRR"X!fZ**j;po7gus7:gJR+H||WzTC "E*JK*i]Gp0G/A>!6 MB>2Ŕn>!q?7(s~n/2Da90DbE'ʯt^*DDd('9vSvvC?G,Hoo=uٳWW^}5oZZsц[8G  O$;Ӯf̘a0.ff6^Q 'yWOMՂNd- qm"y3+'ʇQ!qEeuwuߛO(c`x ųDeTgD)Umf\߾W%P*Eլ H0ȣEqI+FdĵwУ!Б }žx[PUpxk "YxLJ{Fl4#\#86sёޞ7X\\vKK8Gedty<!2(8+ѐh$؎ףGhꪫ>XPW.9|xC?SPNF#"ݮXd(WQ;U>2}O.g ك` cQ*Bu{ R}BF{X:e1B*+w`0EPMX+R5 )jzDq8G$V熋v˦K^0Z]J3ʽi%z qaXY&jfUgр0cldLH C:z֘0J IL BplfKݶ|w_X1PQN )FfV }غM L(/OR ۅ7Iw1F9#@byTm*g0e?uieΜ_j$7%79'%'9!:ra ZZr[Zrssα.[f3 ]B0 QH=ut W$l:^ǎ![_vW[ٴcO3[ҡ,IIEVcMgrhK_ͬƙ}8{]b|F/_,+Z~vΝGy-eeknxy0%pp%x+ڕp(b }5uùrYh5 M)Wr1)OgSA}B̞lf5*Y%V\_;í WXغ 5))ɽqqVΪ/2lzU==ݣu#撒N>lz3SEyDљ|l(fVԿYQDl fyw'Xwx_{ x斶{Ri>J^_7sYp;%6Ħ5xk}v9)sQSkD~™.a:uBWSK:;H ]8`k` ~!*ڕG-*{q{>!&gJ6VAB7.ok 6 zAo*U ?US'$cH6Be{Չj8gʶM$bh(1 DE&JjmPoo|Vlwy٢"8Gc"J#sZ4SofQS(־ﻯul&W]-RX}-nL>>K%wvǥ3^ݬ})SV+`8}͵>ZbŲe 2(]Q82q|s B|_7AGaa(4Cf9#n$9f# w%ӯ_soLáLoWW:KO2`dkrj4vlM|`b@RR_JJOZZ'Z>ʜƾs/;6`]_T%qV3"J#`ЎFَ")MG=ߺ.K[xW`n뱬|Xvb |UP笻t&R^Vl:K U}_fOD ƖkS\g: ޺nm;Ԕ╿ۏ}id͓^ei#?ʼk&Ϲq?^6G3׮^}U@(xnvLTZS6en} vό|pr8$}fûXͲɴKG@y. QHvDԿ `׿]h`fba609α6L1Atp N `!2 ِ]Y֚WY9QDNdCv`]*>!@}B̞wC!%]Uku/𼋐.0ȋډ%Ρ3$PWw/`sVV?LdC<ˌ oQV!ö;d5ձ!b ͐]>}n55\6n!!3vr*|n}Cx'RQ5@( V&bʪK6j`5BҶb5s($pjV'gk|AԏZc?Ob PC9@ !_@%1K6n)]D#J["'DgPqקXqoS TJQ5gSACGe'H7n4dd˨3 !0 0C5ȴmpP*GAa#]v500P__) Q{Nw#ޮ|* QM5a BuU31'$YOd2BesUeb(]a{/:~1>8̣@ pf럘۔ٳ3]Fe2pfα m4O ~k*Pj~EA^~c]UVVb]_ə3ջ!q#XbI汏%~d}H\ك}9˱ v+j4mQ'Rfa.}BvJƎލy m?j'0ڔ\һHYӖZt{N[ڮx `/ GFT͝k6/^+jW>dX!0bkV4$G'\}6u9&$g/ 5B:kwQTϪɘ?a^Ի=E.m&RK,9Rr{K ؈+)?eޡO#CCY+;{46B]kϹ>W!j6d>SD?u3* ѭ򵫎wy'~pֿM.Y;<\VVf2|*!"ʻ$KU4NՂĂA޵٣TQcp-i}B̞!5g] wWa7ĝST^Kc1p|zN[+IpL3Ol"66K1#fĥ6%3x j1G#cs>8g7?1iXS"V|tmk5qztڮ>'q}bzäԶ츸" ~anW^B[1Ic_%?nTؐ:8"q6խg7~G}±D7%asڲE?8 ]!S+#VUJ6>-M{4aE8a]4q |ZZvk{Pf^ҟ_#@ e/<&;U")wja^h^p)%_R۷)A .]4vg-xhMΥjGT-Vm}„ag0Yؖ  8 j%jcS02慴KUj0ծ[M8 pYWWo~h:MFGc6JTuWU/ '@t#{z:+L{ޭdy#=導3᎜"T;5177'&_jll!Pg n7İ$Ú:/Z04O%X? ı/c9s=P 'P.)͛{Z'"#[$h)innֽ66HʟOuBLC ڕn~'g ofm]1dLZ*̸dop|OȸgHC9ޅt^ۅ*l)\Zpۍ:1в18åм<e-_=sEhl`'Zu٭L\vA )sfJ.UvU[[Z[ -.AAl'nw C BUW ϓ%9G`$p_Uo8t=^ǔK޴R:5Fc"qƧFC$q$t)c@h~K1(>d g-{y\{,Q!AޅwGl9>xҶA{S@"N$])ِ Jxq9GlDJ Gq !#pBISx)cEieC ^TkWuuu*cSE֮2\8ĪCbuAP_ L`#?bOC髯K?r r%ߑ'[[Dm^SbXE1xX;v<\vۛ KW!R&!^گkWUUUc AnEϟ9/^셒?nWh@>="@BH!d" KE(1iK,^d~p\k"yCt.̮ ! J26*EP )$"@'0|-)S%OI>@>pIjö4fb ^$/^<^{VtaH2Z$D( DH !fdbvL||;4f4G!Nxx;Sv<]]]73(n/1' ̔HF4ƧF}ȵdKC >@> r:ي5xxIxy8glVVb+Pe`>H@P)A "@!ٙ#4% VR^$/8%QW-[=)||{D!#D$pyŒё08 CtEʼn M@|):"?@P\'>-]%5ElH^$ygB1xv](Sɋv!=8OMM)RdkCsTd2"@L@J~:L^Bܔ4% 6!/3[//`/=8*+^'݆/ xpR)"@ H$" %p1k*__4% 6!?;Z^fջD%|``y^ZUDqEQ*c>@>p)"hO4']NhSSN4% 6(x4 EY<^{>+++q PI]ah(>- T3 ||3S" D  (i&1N෿}풿5N{ϝcvL||鮎+ ųP /=2+ q_8>@>p  QM@iQM"?nMK YKN/L!@%bĥ&'O:P] R!^yZiU"Tǧcݮ@y r!܄? 7B)izaZX|dxK7yykG\r%K3;$T0ϒ<^$Dv%NUWkGF6 )BxB38UGyLQƕW[1; >4>d ̽i%z qGB1lC乽Ņj 4XX]@erB  '@C ? G&|q=I_\`v|h|2gfbaiWվ*s ]A!%t\y,?FJ޿ꪓW\1hp>OY?- T,Ų! d"@b6b^f{pk˖'4ckUY )EyBcY$Fކ5Uaʜxʉͬ0 -C]ן3*#9--9 !;`24ש~-BU (/ D@z4)y$D 87B`So'$~)ߐo;ToGxW1`#(ERZk ^mͶvJ[ElK0щ.!:$o^lYuuummmsssS~>~3:;SݝgV͆Ǧ[u:;&'vۑޛꚠSTy%%%\DqakW|d"@O@gN5"|_|Dvױ!PÎ7_8QKw:F̖ЙEw?6UϦkʶI^QpͭvH\SJva5 5~vo0jǻgy|lW>P"@h$+^rN@ CUWW#ãߝ[[~;o(;kJԨ#XYθsCް!ey53!I̯OITSvʬpt~ߏ1~vi4 uP ?III)))iiiW ] "@B'@C"@$ φb S.oڱGY쳱4B8”u6~ψ^x'4Dʀ 6HHU| Ȫ߻0+b. D@V#x9 p%bILz-.|^2G-pTa~9c?vt0K   ]gP-y&D †*"D`BFܹm׮Y|#Gvv:`Sdf9٫aNn0JVB@ 0٥|ޤZGM6/=jUCd +"@ 1H"čgŊ۶mtnw'uح^bQj D SNւnd;t{%oRKE@]]83~;{D/vrIaκX-[;:er !pF1}͵31{ <P)f2fica0]2UA e"@#`2DF uuvEԐz nH#-{6xКk^U|4r:GYˮ:Cm寚b)xW,zkYE튧A6 D ,P=2L@0H(=gmcQd@6@6 bNzC[wԾ,` U"~bvDh$@Ch|j޾.8ӟ^bQa@0d3A0jv y"k߿ʵA* b0Ԯ #DHH@$WD(JG%DqmMՓ&H`o"< SX~ƿq^8\ݢJͬ:l:9UC@?C"d"@ ]ϋID@wֽ??f7>)(Ӱ}}uuLޒ|+{2ƅr<'g{ gƥ=|zS`k(v"D(@##ֆ>u))iY _ڨsAlϞ?kC팅 ym|B>4t;ݱkK%斶{Ri71*3{yef}D~uASNl??z"|:+D@ZWD&!ge G>~vppxt!nEd[ tE|DP۾C,LVʜ Ͼ?Y+b (K:6qM;TmOm9l(c%h8j̴LqtnjK^w>RU>AN}JR/_ŧPiM"@}Hz3i9+hTSӰgaet3uj{iiu~~SZZ8b1tu76UW^1n+g.M? %  [n^qvXwsNlnw|_-?){kcov 'K] s_3ܠOLŏe]ɊOBsx>a^-T7 MB0'4t!=O+J3>7YC ÁωVړ965ݻy/@Huq^"ξQ%clNom=՘b)ee,%ݰY>#KWa3[^մ}w?(O,۰u&?{gUj[[Kd-dɒH^dgb' I &070^|d^ G,v6'&}jI$kmWJܾꥺԪ.M{-稪nw ϫwsaYˤL)ۨlP*@9Ӏ_a v{TټK/}W&UWmݺU67rã&$"[}ߓ%9+{;7 o? Qzn~}iölU9K&ލ@x^%bQ9 \ţxU}WћUnQ$) u-,9SK_܇?iiC]Y٠k<'?;<9.s^ q{(?R\S7 f xgͿ~e5ޑM-Mx^hlpHDۻ92OҬWդ kӴx^vi(,! voq hZq!gqs°\]^? o[?B L %S~+y8t:23kSb'{yE n3H¯$ϣʣӭTnQn Y|_C؃⩧^߲eˎF+7'=}ꖖjkx.0=MDeKJgtţѶ_oy< ]^dy~E?n{[/):H<b(lc(`(=`R̜0Ar`+o@?Bt)V 3 ׌^OrVcz_|ӟnz,2x`.dI%\.wXx^%zQm Wo1F`9aP>,ĭ;oBM  lF,9- XyEWj~}cǏ<`S7p!ȀHND<qը9.Df.@5œ0$9LXZӋ.jZ$ ]T0g*3ƙ6 %<㑖g_ Z[<>y˗__n]^mmr3>:UW׾)K;IDATo_޽]Et˶ߚ+zHt<}?6\Z!Y&hKDxƫT?,XpY6 h@_S']7tr({슊JgQt8׸\.joﯯ5g1q|dAl('Qv%>W \%G^ e8,ӈ[ MUSٙر\r؂2@)rԣO{a/9sbO+w[>UkӅxy^%ޚQqJbXNbN跀,[ yyUSٙر\r؂2@Y_/j}g^_g5eO;>}d 2'W\/5WT US e q+'̤RĎ撳ĘJxPǻ> ֮@SpimzA^;Sye堘Ps(%)~Ԝqsx8.۳gh?ٰa嗿6<ғ|;kѰ;W~y>"wZMΖ_Y KY ֏K ? jAssU^{ u2'LS.S.۠l={epHӹOeNiCSN?ՙG橹s_u97GQҔ]xkkɅ p.)i=vlq CQ>-b[N&CÓ?'(޽ߺ~l)m   ${^|U׈cJNEiAӫW(%J."CJwҺXY<0 0mp$Ad@X- HH,F 0WKjUۏ?IQRpǫx)!sB `?b0 ㏬j#qh,V߯k#։?'/`_4]2q2ԟcǖ)7C755cK^bPC= Y8r<C&:{t#4l;(.ľ,ϩtΛxfwc5rg=<TnOKNssʏUSU(27-\;msr%6Jc2'!lPcA%HNN }}oYl Y"Z%d\M.}]pu'hPapSPh]x_ߘZԼ_۠w< utuS׹݃Ctu>bdEkW䯩-6 O[gdtsdz? H%eદP4.:%LN(08h k(^_<0rBrRFTJ A!NnT:2+K1g`0ѠcPn7W*._d=9ҳ $wif3Y$M܍*%^pfЬy +82 *˿smCZaW*n}D be c  ~ QY>'$gܙ|_ϼ;C޺M6ƌOϜZ%) s8EYYee-!mO^3\{0Y?{(R}MΉ^T ;Jwvl@,`}g؉Ԝl9 Ygő ྫྷ]ؓ>'\R\k;$P)W5kڽ \֜~NH~Wp'*m OTe:S^Ǘb嗿40sb_4pcglbD(5H`ωG~׺ ;eVa693wМ#Y΢1pz\\InW_א{&gGFv%\tgp( R.[6g슊JgQt8_1rzϜpȈUV__O`uƽpxG*hp ]X9'$g?/@B1{?}Q^6TUuJtj40,5uS0Cc$@16iL1!r6Qa">㑖g_ *>oPud͇|3S=T(xG}ζ]}z[_z-W/~kZ^f֭˫MN RsrbNuahW]]}m{vYYYwꊄ_K>@(P !e蔢+'0 LPrB޳rNHDny#hއթ.߾;\䄶bhR;$5udz)yˆ/Ko| UPON %/Ć@,o}_~Qq%7]Xݶ/t]t -'MF1 ~_ב5>btC^g,^hKd4 gQɪ}5_E^,)IJi~_E>lk璕JJerK愗+cwBѕb_l5NQF09a~kge<1ar!X-S>J`rBdwb$"+rt|OCNG? L X0'$K/0?F{b iNUPBV_$Tȹ+liJZRQ<sBLt0rPzdlD!p觿Aq/RWV,#0ȓ Gj5eJvvlO A\U(eJ-C@UsR SN^8ȫI#1?$|vzzr;"h`: ^'RgnR9 A JﴑmfWG=m R#!}A麱$^$!";*ZċU(=9W9KƈWW*ǔ儘#0abHYq#K%€hE^0"a^-^|<%e,`#bӹ),R drasXD`ys{PyؼN4&=$@!UE%h]~Ezk֒sb3& lX#HY|؉ KCVE|xt6ٞD+n7oBF![ @8J|5nS'R^yb$Y  ts 9aRR̜ lXkHY|؉ KCVE2J!aܛzڲe?0AF`  'G7SdrYZpWџ?&,gI: b0Bh!VMF٥7Yd%P6b*){,L@UzsBC!b0S^8Y,k$KCЖM2J W3t>l쬭̤Y׶#kϊQY0rրC]O:2~-qxGPX\ok? ޑIVzG cr2dו⹝eDNnf ¸AY,^{V܏R4J ?z=()1,)Yףa6!ٰʌQޒb@ t,AHBh;^EdVwDf ;(Qe=$G`0SP:rBAq?w+9-%ݙ.E[ޝe% ՗"epH*5 \NLY<\uw 1k "ŋn12;晅#(:#kȦ*2eUr֕wgx HeAHYH*!P92|%И+Qg[[;q>4q0+kL1!YB(m g o`Wl?c1Ì @20׈'%'<,bvFX:b ȹJ;|NPO8\hE5,U!6r$ ד{_`yN%+ AU]r[)ǘ-KC%Cal 0<^imD3 *3f5w!+1/*9W)F,{|"e&_ Y*9GXF@wTȬ_^H3Y 8 e'2SjIelE h}ɷ9KF6VjR'"L1e*M! 4dtdƲţV% *|Vx]e[qQ,Β~HY|&闥sdb@ `}Oq27Tzޠ##Y 8 eA)5$T99(vϼ*k3:a/ 9Xѩ!OغՖd)XA rSCNVq! *:ش:II:V,ÅvUE6O,U!BrŀWGFlFi2! } "xY4gCJ\#2 [m+( 9(#j[dvZؽMخmLLl"]JN0p^ C=:vmӑNzgLPmk+w8m933 8[ZZZJ˚K7ʕ c., Z,J ޓ/IAt[#p<_sj:Bhxz*81fJ8rgusB]EiiVsB,SJRdNw+0uab9,XM JOpWOO-}BG?嗿yғ'Q453379szSSGє1cRFGHJo< 'q (7GFcy8,M69'JQgnXp#P@aSY-;>d/X J ^6Σdo8sN̛ʛKJ5ʕrNݩtWUFcRO/>s9Jh¨숀K@=ʔp<SGZ#'$g:@gƂm=ߪ<_^gɘ%W^&>iC;(cJoW}IK qaf fy͹.Te6!&bD-ِ<Œ{1mylJcJO܈<rO,AO@ЎZDeRҎ JJ#>A8r|sBr9cX  oVgF{NU?kʢE'ٙOWW~OON__vp:$;y||BdrVZPV@vv_NNO^^'IIX"HR;Sr!o@}%Z,J=iVůʁ  yJVeD?*(3.ylJ&(XQPm| ȹJx-~9!  |٦p1G(9JvzP&627`6P>TSp~J+$rBr9od YsUW@a),'@ƹW}~@$Ff @ %0rw09G^/wE{(2q%HV !g( rխY~ो(`:|dk!crBr#7ƹKE^+cـ!"ms.eǀz!ZudwNnqqa`vg7%4Ý r!idUn~8b ,X_%f[ =cI} hQP]@Ad<29dž3$"K tX20@MGLP2Z2-\I2</p  jNH:O0K xuƝP/0)AN/<5G#s (t\xc C~h)c9RP\%wOCNp sBr0y>O/\kApp-d\W0 r"2  0\x [/WZ)\ Ζ YuFTJ 8[vm7l^QpSE̞ #~c9[f)Q]^܃q]Qc`A=whʜ<(s*U{wE̞ #YFJ w]tj7pc^Y%ۀ 8 #@9 {f9{|chg8u&- 49^GxD'Nx:9!\|۬ Yg'Aݾa[ ab( "Ȁ }z(pxɃz d`n@h)q!(@J$$\O^W_ Bb0'$P?)- pƯkyg jYsG⛻a^_%fi7\y8_TGpՒd ,`{H3xNjwT6([Yz{ooQGsJ1P('+"hCfcI%4W{l}|zI]#vcr1Sy8/J9!9-|AkHUBnGԜwmIƛOOzhX!'zY`c(.i}}{&т`&ʪ^`eX Y A3d&;I*(T>{'>WuNH<'IƛO75ʜ?&g)1YO酺c,C?+< JWn-ܕ=Io:wiݛu, Aaq ?} ,`)} :g%09@9pSdS:'09@9ĊjMK h3G ?u+zRI?p^8璶,9ʓ@J _MvyM9J6>$ܚU F+G3?O;SΦvqH ZoBbj]9H{.N+5u(O=sF&(3ylJ&(XQP UPic<=Җ5ڕ16l '.Iyy}:3*Ӓ*dNH?+ eIM\v扝gkD(i!W#˹s[޸-%+Scl8Dγac(s+š GdA `EvCrkBhPА y YiQC@;WAIB:>zLaN(@׈i FR?<ߴf?MUY6ۦOpZ"C!W~Qh|$.p5xpOw骫+\fFb=N7?ZǾ4^X^W,Xc,?Dγ]jV-X_,jLeϪ%P} Y A j$sPd'ggJ !ZÌtvwl@c@S+R7ntә9$4kU5s6 簈82Ԋmof:,B_hO1/}iZep޽B*Y A j$s @H%JyPh hҥmS(W¾QS(3NCybסC ,bZ?A!4SYtiJ1! 0Wݴ&fΓO ɿi+rP!G"vFf̳w"+2% ` %  }jaa1&z%DN yzî]^kz<JАtύ#IHlXmEH%^:5,DKYJ0LMe3f/jm%+=b,+=9HE%P/ @ `ߛyׯ} D@VEi+; =[6 _#nOxX Y ( t 0 @&Y 0[?#O;D @x9@YC6s'̎yf!")!g @| /z'"9Օ[,H_]BhШ(X=8ԑ< @؈*@w! 3` dU hXVw H~hy]w&K8Ќ9gXZx˥z$+mfGIH .X; Ĉ@Z^ҿY8kٝ}ⱄ!^jH#=fݻS(1`=$@$w,@$]ޒJ8 G|ӈ~37 BW~tя#(1c=$@$_,˟IN;2'Ϙm;6B0dAPb&؞ϟ2_ =ccFXXҐC$@$,₝NIbJ9h7.R^}h_ B<A8Vm~h_ 7:&,@׈=+?J$@%@|; 5\{łmJ{KeK+T ȃHH_`u/}=<%w<=uJX#+¯/V~2HH {GtM$@1#PS Tr~F٦To4w?&֭杶X*U6mJNMBFƫw'<@׈/+?1J$@"(^H P<_uYׁ#CoAtnOf'j4ݷ_8!F孬Y{F0Vm)ZWEUNxem6U(tqgJIH bDw$@$@rje?FQfM#b I !C`NpMr Ӳ 1$FVU(y' XUXҦ/ HNI)aÅZ^zGx~mw޸l׷ai\bI0O?̯N7{W%+¯a*V~HbO%P# @ Ldo?( zlmguH-\r8hPG[;h>@x3EOXy^ĉ5kuSPG[sGd0'RI$@1#(fHD6^960}Wztܚa[ o+'{WYω)41{Gpk`Uϭ *{]='N:JHbFr3:" h}=86,^ rg؏ž㾝/\syFf6+oaCd65 1ܱqyY4D;X l @j:"0)׹w=G}Q.~4Bz旲<}|ʕ8YZG;(:[`n^:CS \e{HH XE/ $xScnנbghm~"אRsNî9VΌs姷ؒ#3YJ*nܶ-%} ;w6jm3HV~@_8J$@Q%(xiH  wuH˳|x@:W^`ts|Thlۛu:t˶ߚfV8Vˋׯ/Z.*L+Ѯ}:t(\RXUf' N%HiH ?Zwxo A9`4b$rY4fwzrU{8"w&ܮ$W>!l ʞ,l%\tg% AR/^ׅ*+EEv3&s.1ΞE3>2YVW$@$`@Ʊ%  oh9S^;>bolyׯYG/Ygő$@$=,ǖIk۠5?j:_S[ѫK᜸b?dJ?+$ h`  I$`5C]ԡx~Q~(~ .M/ȋBL!++EVYq$ H%0iH`Vxtmȅў>g̍v{ZjJNvܜBgiqxǜ\G{J?aϊ#IH`X $;%RJ$@$@$@$@$@z KHHHHH,@%! %H/)#    @XD@$@$@$@$@$K 8HHHHHXY` ^,8      ` dEd$@$@$@$@$@z KHHHHH,@%! %H/)#    @XD@$@$@$@$@$K 8HHHHHXY` ^,8      ` dEd$@$@$@$@$@z ޼#vIENDB`./nsf2.4.0/doc/example-scripts/tk-geo.html000644 000766 000024 00000105653 13217207455 021151 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/tk-geo.tcl

    Drawing geometric figures - the result of airplane travel.

    The example script shows the use of canvas and geometric figues (regular, convex polygons) with different number of edges based on trigonometric functions.

    -gustaf neumann (Aug 2, 2013)

    tk-geo1.png
    tk-geo2.png
    package require Tk
    package require nx

    Class Canvas is a simple convenience wrapper for the tk canvas, which packs itself.

    nx::Class create Canvas {
      :property {canvas .canvas}
      :property {bg beige}
      :property {height 500}
      :property {width 500}
    
      :method init {} {
        canvas ${:canvas} -bg ${:bg} -height ${:height} -width ${:width}
        pack ${:canvas}
      }
    }

    Class Area provides a center point (x, y) and a radius

    nx::Class create Area {
      :property {canvas .canvas}
      :property {x 250}
      :property {y 250}
      :property {radius 200}
    
      :variable pi [expr {acos(-1)}]
    
      :method degree {d} {
        #
        # return a coordinate pair on a circle around the center point with
        # :radius at the provided degrees (0..360)
        #
        set x  [expr {$d*${:pi}/180.0 - ${:pi}/2.0}]
        set x0 [expr {cos($x)*${:radius}+${:x}}]
        set y0 [expr {sin($x)*${:radius}+${:y}}]
        list $x0 $y0
      }
    
      :method n-tangle {n} {
        #
        # Draw a regular n-tangle (e.g. when n==3, a triangle) inscribed to
        # a circle with radius :radius
        #
        for {set i 0} {$i < $n} {incr i} {
          set p($i) [:degree [expr {$i*360/$n}]]
        }
        lassign $p(0) x0 y0
        for {set i 1} {$i < $n} {incr i} {
          lassign $p($i) x1 y1
          ${:canvas} create line $x0 $y0 $x1 $y1
          lassign $p($i) x0 y0
        }
        lassign $p(0) x1 y1
        ${:canvas} create line $x0 $y0 $x1 $y1
      }
    }

    Class Inscribe draws multiple n-tangles with the came center point.

    nx::Class create Inscribe -superclass Area {
      :property {count 4}
      :property {edges 3}
      :method init {} {
        for {set i 0} {$i < ${:count}} {incr i} {
          ${:canvas} create oval \
              [expr {${:x}-${:radius}}] [expr {${:y}-${:radius}}] \
              [expr {${:x}+${:radius}}] [expr {${:y}+${:radius}}]
          :n-tangle ${:edges}
          set :radius [expr {${:radius}/2.0}]
        }
      }
    }

    Class Hull creates an n-tangle with :density hull lines between neighboring edges

    nx::Class create Hull -superclass Area {
      :property {edges 3}
      :property {density 10}
    
      :method n-tangle {n} {
        for {set i 0} {$i < $n} {incr i} {
          set p($i) [:degree [expr {$i*360/$n}]]
        }
        lassign $p(0) x0 y0
        for {set i 1} {$i < $n} {incr i} {
          lassign $p($i) x1 y1
          set line($i) [list $x0 $y0 $x1 $y1]
          ${:canvas} create line $x0 $y0 $x1 $y1
          lassign $p($i) x0 y0
        }
        lassign $p(0) x1 y1
        ${:canvas} create line $x0 $y0 $x1 $y1
        set line(0) [list $x0 $y0 $x1 $y1]
        set line($n) [list $x0 $y0 $x1 $y1]
    
        for {set i 0} {$i < $n} {incr i} {
          lassign $line($i) x0 y0 x1 y1
          lassign $line([expr {$i+1}]) x2 y2 x3 y3
          set dx1 [expr {($x0 - $x1)*1.0/${:density}}]
          set dy1 [expr {($y0 - $y1)*1.0/${:density}}]
          set dx2 [expr {($x2 - $x3)*1.0/${:density}}]
          set dy2 [expr {($y2 - $y3)*1.0/${:density}}]
          for {set j 1} {$j < ${:density}} {incr j} {
            ${:canvas} create line [expr {$x0-$dx1*$j}] [expr {$y0-$dy1*$j}] \
                [expr {$x2-$dx2*$j}] [expr {$y2-$dy2*$j}]
          }
        }
      }
    
      :method init {} {
        :n-tangle ${:edges}
      }
    }

    Draw either one larger figure with inner figures or a series of smaller figures next to each other.

    set multiple 0
    
    if {$multiple} {
      # Draw a series of figures next to each other
      set c [::Canvas new -width 650 -height 750 -bg white]
      ::Inscribe new -canvas [$c cget -canvas] -x 100 -y 100 -radius 80 -count 7
      ::Inscribe new -canvas [$c cget -canvas] -x 300 -y 100 -radius 80 -count 7 -edges 4
      ::Inscribe new -canvas [$c cget -canvas] -x 500 -y 100 -radius 80 -count 7 -edges 5
      ::Hull new -canvas [$c cget -canvas] -x 100 -y 300 -radius 80 -edges 3 -density 10
      ::Hull new -canvas [$c cget -canvas] -x 300 -y 300 -radius 80 -edges 4 -density 10
      ::Hull new -canvas [$c cget -canvas] -x 500 -y 300 -radius 80 -edges 5 -density 10
      ::Hull new -canvas [$c cget -canvas] -x 300 -y 600 -radius 200 -edges 3 -density 40
    } else {
      # Draw a several series of figures with the same center
      set c [::Canvas new -width 650 -height 650 -bg white]
      ::Hull new -canvas [$c cget -canvas] -x 300 -y 320 -radius 300 -edges 5 -density 40
      ::Hull new -canvas [$c cget -canvas] -x 300 -y 320 -radius 150 -edges 4 -density 20
      ::Hull new -canvas [$c cget -canvas] -x 300 -y 320 -radius 75 -edges 3 -density 10
      ::Hull new -canvas [$c cget -canvas] -x 300 -y 320 -radius 30 -edges 5 -density 5
    }

    ./nsf2.4.0/doc/example-scripts/tk-horse-race.tcl000644 000766 000024 00000012746 13454166031 022242 0ustar00neumannstaff000000 000000 # A small Horse Race game, originally developed by Richard Suchenwirth # in plain Tcl (see https://wiki.tcl-lang.org/3467). The game was rewritten # as a design study in NX by Gustaf Neumann in May 2011. # # image::tk-horse-race.png[] # package require Tk package require nx::trait ############################################################################## # Trait ListUtils # # Some list utilities, not part of a package we can require here. ############################################################################## nx::Trait create ::nx::trait::listUtils { :protected method lpick {list} { # return a random entry from a given list lindex $list [expr {int(rand()*[llength $list])}] } :protected method lremove {listName what} { # remove a list element referenced by the elements value :upvar $listName list set pos [lsearch $list $what] set list [lreplace $list $pos $pos] } } ############################################################################## # Class Horse # # This class defines the logic, how and where a single horse and # jockey are drawn. The painting of the horse happens just at startup # time, later the horses are moved via their tags. ############################################################################## nx::Class create Horse { :property name:required ;# name is the external name of the horse :property tag:required ;# tag is an internal id :property canvas:required ;# the canvas, on which the horse is drawn :property n:integer,required ;# the position on the canvas :require trait nx::trait::callback :require trait nx::trait::listUtils :method draw {x y} { set hide [:lpick {black brown white gray brown3 brown4}] set c1 [:lpick {red yellow blue purple pink green}] set c2 [:lpick {red yellow blue purple pink green}] ${:canvas} create oval 0 -1 18 4 -fill $hide -outline $hide -tag ${:tag} ${:canvas} create line 1 12 3 0 5 12 -fill $hide -tag ${:tag} -width 2 ${:canvas} create line 15 12 17 0 19 12 -fill $hide -tag ${:tag} -width 2 ${:canvas} create line 16 0 20 -7 24 -5 -fill $hide -tag ${:tag} -width 3 # Jockey: ${:canvas} create line 9 4 11 1 7 -1 -fill $c1 -width 2 -tag ${:tag} ${:canvas} create line 7 -2 10 -6 15 -3 -fill $c2 -width 2 -tag ${:tag} ${:canvas} create oval 9 -7 12 -10 -fill orange -outline orange -tag ${:tag} ${:canvas} move ${:tag} $x $y } :method init {} { set w [entry ${:canvas}.e${:n} -textvar [:bindvar name] -width 7 -bg green3] ${:canvas} create window 5 [expr {${:n}*30+5}] -window $w -anchor nw :draw 70 [expr {${:n}*30+14}] } } ############################################################################## # Class HorseGame # # Defines the main canvas of the Game and contains the logic of # starting, resetting etc. ############################################################################## nx::Class create HorseGame { :property {bg1 green4} ;# background color of the canvas :property {bg2 green3} ;# background color of the result label :property {width 750} ;# width of the canvas :property {height 330} ;# height of the canvas :property {horses} ;# a list of horse names participating in the game :require trait nx::trait::callback :require trait nx::trait::listUtils :method init {} { # # create the canvas # set :canvas [canvas .c -bg ${:bg1} -width ${:width} -height ${:height}] pack ${:canvas} # # create the Horses # set n 0 foreach name ${:horses} { set h [::Horse create horse$n -name $name -canvas ${:canvas} -n $n -tag horse$n] lappend :tags horse$n incr n } # finish line set w [expr {${:width} - 20}] ${:canvas} create line $w 0 $w ${:height} -fill white -tag finish # start button button ${:canvas}.button -text Start -pady 0 -width 0 \ -command [:callback start ${:tags}] ${:canvas} create window 5 [expr {$n*30}] -window ${:canvas}.button -anchor nw # label for the results label ${:canvas}.winners -textvar [:bindvar winners] -bg ${:bg2} -width 80 ${:canvas} create window 70 [expr {$n*30}] -window ${:canvas}.winners -anchor nw } :public method start {running} { # # When the "Start" button is pressed, we turn this button into a # "Reset" button and the horse race starts. We stop, when more # than two horses pass the finish line. # ${:canvas}.button config -text Reset -command [:callback reset] set :winners {} set finish [expr {[lindex [${:canvas} bbox finish] 2]+10}] while {[llength ${:winners}]<3} { set this [:lpick $running] ${:canvas} move $this [:lpick {0 1 2 3}] 0 update if {[lindex [${:canvas} bbox $this] 2] > $finish} { lappend :winners [expr {[llength ${:winners}]+1}]:[$this cget -name] :lremove running $this } } } :public method reset {} { # # When the "Reset" button is pressed, we switch back to the start # configuration, the horses come back to the start. # ${:canvas}.button config -text Start -command [:callback start ${:tags}] foreach tag ${:tags} { set x [lindex [${:canvas} bbox $tag] 0] ${:canvas} move $tag [expr {70-$x}] 0 } } } # # everything is defined, create the game # bind . {exec wish $argv0 &; exit} HorseGame new -horses {Blaise NX Animal Ada Alan XOTcl Grace itcl John Linus} ./nsf2.4.0/doc/example-scripts/rosetta-clone.html000644 000766 000024 00000057367 13217207455 022552 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-clone.tcl

    Rosetta example: Polymorphic copy

    Let a polymorphic object contain an instance of some specific type S derived from a type T. The type T is known. The type S is possibly unknown until run time. The objective is to create an exact copy of such polymorphic object.

    package req nx

    nx::Object provides a method copy which creates a deep copy of any source object (hence, polymorphic in the sense of this task), i.e., it contains all structural and behavioral features of the source and preserves its signature type.

    nx::Class create T {
        :property -accessor public {label "T"}
    }
    nx::Class create S -superclasses T {
        :property -accessor public {label "S"}
    }
    
    set client [nx::Object new {
        :public object method duplicate {src} {
            # this is the polymorphic call site
            return [$src copy]
        }
    }]
    
    set t [T new]
    % $t label get
    T
    set s [S new]
    % $s label get
    S

    Provide two copies, using copy underneath

    set t2 [$client duplicate $t]
    set s2 [$client duplicate $s]

    Are the copies truly independent objects (identities)? Yes …

    % expr {$t2 ne $t}
    1
    % expr {$s2 ne $s}
    1

    Are the copies offsprings of the source types/classes? Yes …

    % $t info class
    ::T
    % $t2 info class
    ::T
    
    % $s info class
    ::S
    % $s2 info class
    ::S

    Do the copies operate exactly like their source objects? Yes …

    % $t label get
    T
    % $t2 label get
    T
    
    % $s label get
    S
    % $s2 label get
    S

    ./nsf2.4.0/doc/example-scripts/starmethod.html000644 000766 000024 00000112211 13523353477 022127 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/starmethod.tcl

    Star Methods

    Design study for implementing methods which applies to instances of instances meta-classes. This study implements in addition to the regular "method" a new construct called "*method" which has the mentioned transitive property. The same behavior can be achieved in many ways. In this study, we define a special class (the method container class for *methods) which is kept in the precedence path of instances. This way, it can be defined freely with other extension mechanisms such as mixins, traits or filters.

    nx::Class eval {
        #
        # Define a *method, which is a method that applies for instances of
        # the instances of a meta-class.
        # - *methods are only defineable on meta-classes
        # - *methods are applicable on the instances of the instances of the
        #   meta-class
        # - If one defines a *method "bar" on a meta-class "MClass", and a
        #   class "C" as an instance of "MClass", and "c1" is an instance of
        #   "C", then "bar" is applicable for "c1".
    
        #
        # The "*method" has the same signature as regular methods, and can
        # be used in combination with the modifiers
        # public/protected/private as usual.
        #
        :public method *method {name arguments:parameter,0..* -returns body -precondition -postcondition} {
            #
            # Allow the definition only on meta-classes
            #
            if {![nsf::is metaclass [self]]} {
                error "[self] is not a meta-class"
            }
            #
            # Do we have the class for keeping the *methods already?
            #
            set starClass [nx::Class create [self]::*]
    
            if {![nsf::object::exists $starClass]} {
                #
                # If not, create the *method container class and provide
                # it as a default in the superclass hierarchy. This
                # happens by modifying the property "-superclasses" which
                # is used on every class to specify the class hierarchy.
                #
                :property [list superclasses $starClass] {
                    #
                    # Define a slot-specific method for keeping the
                    # *method container class in the hierarchy.
                    #
                    :public object method appendToRelations { class property value } {
                        set sc [nsf::relation::get $class $property]
                        if {$sc eq "::nx::Object"} {
                            nsf::relation::set $class $property $value
                        } else {
                            nsf::relation::set $class $property [concat $sc $value]
                        }
                    }
    
                    #
                    # Whenever the "-superclasses" relation is called,
                    # make sure, we keep the *method container class in
                    # the hierarchy.
                    #
                    :public object method value=set { class property value } {
                        :appendToRelations $class superclass $value
                    }
                }
    
                #
                # Update class hierarchies of the previously created instances
                # of the meta-class.
                #
                foreach class [:info instances] {
                    set slot [$class info lookup slots superclasses]
                    $slot appendToRelations $class superclass $starClass
                }
            }
    
            #
            # Define the *method as regular method in the star method
            # container class.
            #
            [self]::* method $name $arguments \
                {*}[expr {[info exists returns] ? [list -returns $returns] : ""}] \
                $body \
                {*}[expr {[info exists precondition]  ? [list -precondition $precondition] : ""}] \
                {*}[expr {[info exists postcondition] ? [list -postcondition $postcondition] : ""}]
        }
    }
    set ::nsf::methodDefiningMethod(*method) 1

    Some base test cases:

    Define a meta-class MClass with a method "foo" and to star methods named "foo" and "bar".

    nx::Class create MClass -superclass nx::Class {
        :public method foo {} {return MClass-[next]}
        :public *method foo {} {return *-[next]}
        :public *method bar {} {return *-[next]}
    }

    Define a class based on MClass and define here as well a method "foo" to show the next-path in combination with the *methods.

    MClass create C {
        :public method foo {} {return C-[next]}
    }
    
    % C info superclasses
    ::MClass::*

    Finally create an instance with the method foo as well.

    C create c1 {
        :public object method foo {} {return c1-[next]}
    }

    The result of "foo" reflects the execution order: object before classes (including the *method container).

    % c1 info precedence
    ::C ::MClass::* ::nx::Object
    % c1 foo
    c1-C-*-
    % c1 bar
    *-

    Define a Class D as a specialization of C

    MClass create D -superclass C {
        :public method foo {} {return D-[next]}
        :create d1
    }
    
    % d1 info precedence
    ::D ::C ::MClass::* ::nx::Object
    % d1 foo
    D-C-*-

    Dynamically add *method "baz".

    % d1 baz
    ::d1: unable to dispatch method 'baz'
    MClass eval {
        :public *method baz {} {return baz*-[next]}
    }
    % d1 baz
    baz*-

    Test adding of *methods at a time, when the meta-class has already instances.

    Create a meta-class without a *method

    nx::Class create MClass2 -superclass nx::Class
    MClass2 create X {:create x1}
    % x1 info precedence
    ::X ::nx::Object

    Now add a *method

    MClass2 eval {
        :public *method baz {} {return baz*-[next]}
    }

    Adding the *method alters the superclass order of already created instances of the meta-class

    % x1 info precedence
    ::X ::MClass2::* ::nx::Object
    % x1 baz
    baz*-

    Finally, there is a simple application example for ActiveRecord pattern. All instances of the application classes (such as "Product") should have a method "save" (together with other methods now shown here). First define the ActiveRecord class (as a meta-class).

    Class create ActiveRecord -superclass nx::Class {
        :property table_name
    
        :method init {} {
            if {![info exists :table_name]} {
                set :table_name [string tolower [namespace tail [self]]s]
            }
        }
        :public *method save {} {
            puts "save [self] into table [[:info class] cget -table_name]"
        }
    }

    Define the application class "Product" with an instance

    ActiveRecord create Product
    Product create p1
    p1 save

    The last command prints out: "save ::p1 into table products"


    ./nsf2.4.0/doc/example-scripts/rosetta-sudoku.tcl000644 000766 000024 00000016416 13454166031 022565 0ustar00neumannstaff000000 000000 # # == Rosetta Example: Sudoku # # Solve a partially filled-in 9x9 Sudoku grid and display the result # in a human-readable format. For detailed description of this # example, see https://rosettacode.org/wiki/Sudoku_Solver # # This implementation is based on https://wiki.tcl-lang.org/19934 package require nx # # The class +Sudoku+ implements the basic interface to a sudoku 9x9 # board to load/dump data and to set/access cells, rows, columns and # regions. nx::Class create Sudoku { :variable board # Setup an array from 0..9 to ease iterations over the cells of # lines and columns. for {set i 0} {$i < 9} {incr i} {lappend positions $i} :variable positions $positions :public method load {data} { # # Load a 9x9 partially solved sudoku. The unsolved cells are # represented by a@ symbols. # set error "data must be a 9-element list, each element also being a\ list of 9 numbers from 1 to 9 or blank or an @ symbol." if {[llength $data] != 9} { error $error } foreach y ${:positions} { set row [lindex $data $y] if {[llength $row] != 9} { error $error } foreach x ${:positions} { set cell [lindex $row $x] if {![regexp {^[@1-9]?$} $cell]} { error $cell-$error } if {$cell eq "@"} {set cell ""} :set $x $y $cell } } } :public method dump {-pretty-print:switch} { # # Output the current state of the sudoku either as list or in # a pretty-print style. # set rows [lmap y ${:positions} {:getRow 0 $y}] if {${pretty-print}} { set result +-----+-----+-----+\n foreach line $rows postline {0 0 1 0 0 1 0 0 1} { append result |[lrange $line 0 2]|[lrange $line 3 5]|[lrange $line 6 8]|\n if {$postline} { append result +-----+-----+-----+\n } } return $result } else { return $rows } } :method log {msg} { #puts "log: $msg" } :method set {x y value:integer,0..1} { # # Set cell at position x,y to the given value or empty. # if {$value<1 || $value>9} { set :board($x,$y) {} } else { set :board($x,$y) $value } } :method get {x y} { # # Get value of cell at position x, y. # return [set :board($x,$y)] } :method getRow {x y} { # # Return a row at constant position y. # return [lmap x ${:positions} {:get $x $y}] } :method getCol {x y} { # # Return a column at constant position x. # return [lmap y ${:positions} {:get $x $y}] } :method getRegion {x y} { # # Return a 3x3 region # set xR [expr {($x/3)*3}] set yR [expr {($y/3)*3}] set regn {} for {set x $xR} {$x < $xR+3} {incr x} { for {set y $yR} {$y < $yR+3} {incr y} { lappend regn [:get $x $y] } } return $regn } } # The class +SudokuSolver+ inherits from +Sudoku+, and adds the # ability to solve a given Sudoku game. The method 'solve' applies all # rules for each unsolved cell until it finds a safe solution. nx::Class create SudokuSolver -superclass Sudoku { :public method validchoices {x y} { set v [:get $x $y] if {$v ne {}} { return $v } set row [:getRow $x $y] set col [:getCol $x $y] set regn [:getRegion $x $y] set eliminate [list {*}$row {*}$col {*}$regn] set eliminate [lsearch -all -inline -not $eliminate {}] set eliminate [lsort -unique $eliminate] set choices {} for {set c 1} {$c < 10} {incr c} { if {$c ni $eliminate} { lappend choices $c } } if {[llength $choices]==0} { error "No choices left for square $x,$y" } return $choices } :method completion {} { # # Return the number of already solved items. # return [expr {81-[llength [lsearch -all -inline [join [:dump]] {}]]}] } :public method solve {} { # # Try to solve the sudoku by applying the provided rules. # while {1} { set begin [:completion] foreach y ${:positions} { foreach x ${:positions} { if {[:get $x $y] eq ""} { foreach rule [Rule info instances] { set c [$rule solve [self] $x $y] if {$c} { :set $x $y $c :log "[$rule info class] solved [self] at $x,$y for $c" break } } } } } set end [:completion] if {$end == 81} { :log "Finished solving!" break } elseif {$begin == $end} { :log "A round finished without solving any squares, giving up." break } } } } # The class rule provides "solve" as public interface for all rule # objects. The rule objects apply their logic to the values # passed in and return either '0' or a number to allocate to the # requested square. nx::Class create Rule { :public method solve {hSudoku:object,type=::SudokuSolver x y} { :Solve $hSudoku $x $y [$hSudoku validchoices $x $y] } # Get all the allocated numbers for each square in the row, column, and # region containing $x,$y. If there is only one unallocated number among all # three groups, it must be allocated at $x,$y :create ruleOnlyChoice { :object method Solve {hSudoku x y choices} { if {[llength $choices] == 1} { return $choices } else { return 0 } } } # Test each column to determine if $choice is an invalid choice for all other # columns in row $X. If it is, it must only go in square $x,$y. :create RuleColumnChoice { :object method Solve {hSudoku x y choices} { foreach choice $choices { set failed 0 for {set x2 0} {$x2 < 9} {incr x2} { if {$x2 != $x && $choice in [$hSudoku validchoices $x2 $y]} { set failed 1 break } } if {!$failed} {return $choice} } return 0 } } # Test each row to determine if $choice is an invalid choice for all other # rows in column $y. If it is, it must only go in square $x,$y. :create RuleRowChoice { :object method Solve {hSudoku x y choices} { foreach choice $choices { set failed 0 for {set y2 0} {$y2 < 9} {incr y2} { if {$y2 != $y && $choice in [$hSudoku validchoices $x $y2]} { set failed 1 break } } if {!$failed} {return $choice} } return 0 } } # Test each square in the region occupied by $x,$y to determine if $choice is # an invalid choice for all other squares in that region. If it is, it must # only go in square $x,$y. :create RuleRegionChoice { :object method Solve {hSudoku x y choices} { foreach choice $choices { set failed 0 set regnX [expr {($x/3)*3}] set regnY [expr {($y/3)*3}] for {set y2 $regnY} {$y2 < $regnY+3} {incr y2} { for {set x2 $regnX} {$x2 < $regnX+3} {incr x2} { if { ($x2!=$x || $y2!=$y) && $choice in [$hSudoku validchoices $x2 $y2] } then { set failed 1 break } } } if {!$failed} {return $choice} } return 0 } } } SudokuSolver create sudoku { :load { {3 9 4 @ @ 2 6 7 @} {@ @ @ 3 @ @ 4 @ @} {5 @ @ 6 9 @ @ 2 @} {@ 4 5 @ @ @ 9 @ @} {6 @ @ @ @ @ @ @ 7} {@ @ 7 @ @ @ 5 8 @} {@ 1 @ @ 6 7 @ @ 8} {@ @ 9 @ @ 8 @ @ @} {@ 2 6 4 @ @ 7 3 5} } :solve puts [:dump -pretty-print] } # The dump method outputs the solved Sudoku: # # +-----+-----+-----+ # |3 9 4|8 5 2|6 7 1| # |2 6 8|3 7 1|4 5 9| # |5 7 1|6 9 4|8 2 3| # +-----+-----+-----+ # |1 4 5|7 8 3|9 6 2| # |6 8 2|9 4 5|3 1 7| # |9 3 7|1 2 6|5 8 4| # +-----+-----+-----+ # |4 1 3|5 6 7|2 9 8| # |7 5 9|2 3 8|1 4 6| # |8 2 6|4 1 9|7 3 5| # +-----+-----+-----+ ./nsf2.4.0/doc/example-scripts/rosetta-tree.html000644 000766 000024 00000070237 13331305262 022370 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-tree.tcl

    Rosetta example:https://rosettacode.org/wiki/Tree_traversal

    Implement a binary tree structure, with each node carrying an integer as a node label, and four traversal strategies: pre-order, in-order, postorder, and levelorder traversals.

    package req nx

    The class Tree implements the basic binary composite structure (left, right).

    nx::Class create Tree {
        :property -accessor public value:required
        :property -accessor public left:object,type=[current]
        :property -accessor public right:object,type=[current]
    
        :public method traverse {order} {
            set list {}
            :$order v {
                lappend list $v
            }
            return $list
        }
    
        # Traversal methods
        :public method preOrder {varName script {level 0}} {
            upvar [incr level] $varName var
            set var ${:value}
            uplevel $level $script
            if {[info exists :left]} {${:left} preOrder $varName $script $level}
            if {[info exists :right]} {${:right} preOrder $varName $script $level}
        }
    
        :public method inOrder {varName script {level 0}} {
            upvar [incr level] $varName var
            if {[info exists :left]} {${:left} inOrder $varName $script $level}
            set var ${:value}
            uplevel $level $script
            if {[info exists :right]} {${:right} inOrder $varName $script $level}
        }
        :public method postOrder {varName script {level 0}} {
            upvar [incr level] $varName var
            if {[info exists :left]} {${:left} postOrder $varName $script $level}
            if {[info exists :right]} {${:right} postOrder $varName $script $level}
            set var ${:value}
            uplevel $level $script
        }
        :public method levelOrder {varName script} {
            upvar 1 $varName var
            set nodes [list [current]]
            while {[llength $nodes] > 0} {
                set nodes [lassign $nodes n]
                set var [$n value get]
                uplevel 1 $script
                if {[$n eval {info exists :left}]} {lappend nodes [$n left get]}
                if {[$n eval {info exists :right}]} {lappend nodes [$n right get]}
            }
        }
    }

    This is a factory method to build up the object tree recursively from a nested Tcl list. Note that we create left and right children by nesting them in their parent, this provides for a cascading cleanup of an entire tree (there is no need for an explicit cascading of destroy methods down the composite).

    Tree public object method newFromList {-parent l} {
        lassign $l value left right
        set n [:new {*}[expr {[info exists parent]?[list -childof $parent]:""}] -value $value]
        set props [list]
        if {$left ne ""} {lappend props -left [:newFromList -parent $n $left]}
        if {$right ne ""} {lappend props -right [:newFromList -parent $n $right]}
        $n configure {*}$props
        return $n
    }

    Run the required tests:

    set t [Tree newFromList {1 {2 {4 7} 5} {3 {6 8 9}}}]
    % $t traverse preOrder
    1 2 4 7 5 3 6 8 9
    % $t traverse inOrder
    7 4 2 5 1 8 6 9 3
    % $t traverse postOrder
    7 4 5 2 8 9 6 3 1
    % $t traverse levelOrder
    1 2 3 4 5 6 7 8 9

    ./nsf2.4.0/doc/example-scripts/tk-locomotive.html000644 000766 000024 00000126032 13217207455 022551 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/tk-locomotive.tcl

    Example by <Richard Suchenwirth> http://wiki.tcl.tk/1329

    • translated from Tcl to XOTcl by gustaf neumann in 2001

    • translated from XOTcl to NX by gustaf neumann in 2010

    tk-locomotive.png

    Left mousebutton starts, middle slows down, right stops

    package require Tk
    package require nx
    package require nx::trait
    
    nx::Class create Wheel {
      :property x
      :property y
      :property r
      :property {spokes 24}
      :property {pivot 0}
      :property {color red}
      :property {tag ""}
    
      :public method drawSpokes {} {
        ::nx::var import [:info parent] c alpha
        set delta [expr {360.0 / ${:spokes}}]
        set deg2arc [expr {atan(1.0)*8/360.}]
        for {set i 0} {$i < ${:spokes}} {incr i} {
          set x1 [expr {${:x} + cos($deg2arc*$alpha) * ${:r}}]
          set y1 [expr {${:y} + sin($deg2arc*$alpha) * ${:r}}]
          $c create line ${:x} ${:y} $x1 $y1 -fill ${:color} -tag spoke
          set alpha [expr {$alpha + $delta}]
        }
        if {[info exists :act_pivot]} {
          lassign [set :act_pivot] item perc
          set rp [expr {${:r} * $perc}]
          set xp [expr {${:x} - $rp * cos($deg2arc * $alpha)}]
          set yp [expr {${:y} - $rp * sin($deg2arc * $alpha)}]
          $c coords $item $xp $yp [expr {$xp + 1}] [expr {$yp + 1}]
        }
      }
    
      :method init {} {
        ::nx::var import [:info parent] c alpha
        set alpha 0.
    
        set :y [expr {${:y} - ${:r}}]
        $c create oval \
            [expr {${:x} - ${:r}}] [expr {${:y} - ${:r}}] \
            [expr {${:x} + ${:r}}] [expr {${:y} + ${:r}}] \
            -outline white
        set r1 [expr {${:r}-2}]
        set W [$c create oval \
                   [expr {${:x} - $r1}] [expr {${:y} - $r1}] \
                   [expr {${:x} + $r1}] [expr {${:y} + $r1}] \
                   -outline ${:color} -width 2]
        :drawSpokes
    
        if {${:pivot}} {
          set deg2arc [expr {atan(1.0) * 8 / 360.0}]
          set rp [expr {$r1*${:pivot}}]
          set xp [expr {${:x} - $rp * cos($deg2arc * $alpha)}]
          set yp [expr {${:y} - $rp * sin($deg2arc * $alpha)}]
          set new_pivot [$c create rect $xp $yp [expr {$xp + 1}] [expr {$yp + 1}] \
                             -fill ${:color} -tag [list ${:tag} pivot]]
          set :act_pivot [list $new_pivot ${:pivot}]
    
          $c create arc [expr {${:x} - $r1}] [expr {${:y} - $r1}]\
              [expr {${:x} + $r1}] [expr {${:y} + $r1}] \
              -style chord -fill ${:color} -start 310 \
              -extent 80 -tag counterweight
          set :pivot $new_pivot
        }
        set rh [expr {${:r} / 12.0}]
        $c create oval \
            [expr {${:x} - $rh}] [expr {${:y} - $rh}] \
            [expr {${:x} + $rh}] [expr {${:y} + $rh}] \
            -fill white -tag hub
        set :r $r1
      }
    }
    
    
    nx::Class create Locomotive {
      :property {speed 4}
    
      :require trait nx::trait::callback
    
      :method turn {} {
        set :alpha [expr {round(${:alpha} + 360 - ${:speed}) % 360}]
        foreach i [${:c} find withtag counterweight] {
          ${:c} itemconfig $i -start [expr {310 - ${:alpha}}]
        }
        ${:c} delete spoke
        foreach wheel [:info children] { $wheel drawSpokes }
        ${:c} raise hub
        set xp0 [expr {105 + 15 * sin((${:alpha} - 90) * atan(1.0) * 8 / 360)}]
        ${:c} delete piston
        ${:c} coords p0 $xp0 120 [expr {$xp0+2}] 122 ;#CW
        ${:c} create line 90 121 $xp0 121 -width 2 -fill white -tag piston ;#CW
        :drawRod p0 p1 p2 p3
        ${:c} raise p0
        foreach i [${:c} find withtag smoke] {
          if {[lindex [${:c} bbox $i] 3]<0} {
            ${:c} delete $i
          } else {
            ${:c} move $i [expr {rand() * ${:speed} / 3.0}] [expr {rand() * 2 - 2}]
          }
        }
        set t [${:c} create oval [${:c} bbox chimney] -fill white -outline white -tag smoke]
        ${:c} move $t 0 -10
        ${:c} lower smoke
      }
    
      :method drawRod {p0 p1 p2 p3} {
        ${:c} delete rod
        ${:c} create rect [${:c} bbox $p1 $p3] -fill white -tag rod
        ${:c} create line {*}[lrange [${:c} bbox $p0] 0 1] \
            {*}[lrange [${:c} bbox $p2] 0 1] -width 3 -fill white -tag rod
        ${:c} raise rod
        ${:c} raise pivot
      }
    
      :public method tick {} {
        :turn
        foreach i [after info] {after cancel $i}
        after 10 [self] tick
      }
    
      :public method throttle {} {
        incr :speed 2
        :tick
      }
    
      :public method break {} {
        incr :speed -2
        if {${:speed}<0} {set :speed 0}
        :tick
      }
    
      :public method emergencyBreak {} {
        set :speed 0
        :tick
      }
    
      :method init {} {
        set :c [canvas .c -width 600 -height 160 -background lightblue]
        pack ${:c}
    
        bind ${:c} <1> [:callback throttle]
        bind ${:c} <2> [:callback break]
        bind ${:c} <3> [:callback emergencyBreak]
    
        ${:c} delete all
        ${:c} create rect 32 115 360 125 -fill black ;# frame
        ${:c} create rect 22 118 32 122 -fill grey30 ;# buffer
        ${:c} create line 22 115 22 125
        ${:c} create poly 60 95 40 115 50 115 70 95 -fill black
        ${:c} create rect 60 45 310 95 -fill grey25 ;# boiler
        ${:c} create oval 55 50 65 90 -fill black ;# smokebox
        ${:c} create rect 70 32 85 50 -fill black -tag chimney
        ${:c} create rect 40 52 90 75 -fill black ;# wind diverter
        ${:c} create oval 130 36 150 52 -fill black ;# dome
        ${:c} create rect 195 35 215 50 -fill black ;# sandbox
        ${:c} create oval 260 36 280 52 -fill black ;# dome
        ${:c} create rect 65 100 90 135 -fill black ;# cylinder
        ${:c} create rect 90 120 92 122 -fill red -tag p0 ;# crossbar
        ${:c} create rect 72 87 82 100 -fill black ;# steam tube
        ${:c} create rect 310 40 370 115 -fill black ;# cab
        ${:c} create rect 310 32 390 42 -fill grey30 ;# cab roof
        ${:c} create text 338 82 -text "01 234" -fill gold -font {Times 7}
        ${:c} create rect 318 48 333 66 -fill white ;# cab window #1
        ${:c} create rect 338 48 355 66 -fill white ;# cab window #2
        Wheel new -childof [self] -x 50 -y 150 -r 13 -spokes 12
        Wheel new -childof [self] -x 105 -y 150 -r 13 -spokes 12
        Wheel new -childof [self] -x 150 -y 150 -r 30 -pivot 0.5 -tag p1
        Wheel new -childof [self] -x 215 -y 150 -r 30 -pivot 0.5 -tag p2
        Wheel new -childof [self] -x 280 -y 150 -r 30 -pivot 0.5 -tag p3
        :drawRod p0 p1 p2 p3
        Wheel new -childof [self] -x 340 -y 150 -r 16 -spokes 12
        ${:c} create rect 360 110 380 118 -fill black
        ${:c} create rect 380 65 560 125 -fill black -tag tender
        ${:c} create rect 560 118 570 122 -fill grey30 ;# buffer
        ${:c} create line 571 116 571 125
        ${:c} create rect 390 45 525 65 -fill black -tag tender
        Wheel new -childof [self] -x 395 -y 150 -r 13 -spokes 12
        Wheel new -childof [self] -x 440 -y 150 -r 13 -spokes 12
        ${:c} create rect 380 132 456 142 -fill red
        Wheel new -childof [self] -x 495 -y 150 -r 13 -spokes 12
        Wheel new -childof [self] -x 540 -y 150 -r 13 -spokes 12
        ${:c} create rect 480 132 556 142 -fill red -outline red
        ${:c} create rect 0 150 600 160 -fill brown ;# earth
        ${:c} create line 0 150 600 150 -fill grey -width 2 ;# rail
        :tick
      }
    }
    
    Locomotive new

    ./nsf2.4.0/doc/example-scripts/tk-mini.tcl000644 000766 000024 00000001733 13030507001 021122 0ustar00neumannstaff000000 000000 # # Tiny Tk example scriped based on NX. # # image::tk-mini.png[] # package require Tk package require nx::trait nx::Class create MyClass { # # A sample application class that creates a text entry field bound # to an instance variable. When the provided button is pressed, the # content of the variable is placed into an additional output label. # # The callback trait imports methods "callback" and "bindvar": # :require trait nx::trait::callback :public method button-pressed {} { # When this method is invoked, the content of the ".label" widget # is updated with the content of the instance variable "myvar". .label configure -text ${:myvar} } :method init {} { wm geometry . -500+500 pack [label .title -text "Type something and press the start button ..."] pack [entry .text -textvariable [:bindvar myvar]] pack [label .label] pack [button .button -text start -command [:callback button-pressed]] } } MyClass new ./nsf2.4.0/doc/example-scripts/rosetta-polymorphism.tcl000755 000766 000024 00000001677 13454166031 024023 0ustar00neumannstaff000000 000000 # == Rosetta Example: Polymorphism # For details see https://rosettacode.org/wiki/Polymorphism # package req nx package req nx::test nx::Class create Point { :property x:double :property y:double :public method print {} { return "Point(${:x},${:y})" } } nx::Class create Circle -superclass Point { :property radius:double :public method print {} { return "Circle(${:x},${:y},${:radius})" } } # === Demonstrating the behavior in a shell: # Create a point and get the print string: ? {set p [Point new -x 1.0 -y 2.0]} "::nsf::__#0" ? {$p print} "Point(1.0,2.0)" # Get the x coordinate of this point: ? {$p cget -x} "1.0" # Create a circle: ? {set c [Circle new -x 3.0 -y 4.0 -radius 5.0]} "::nsf::__#1" # Copy the circle ? {set d [$c copy]} "::nsf::__#3" # Change the radius of the copied circle: ? {$d configure -radius 1.5} "" # Print the two circles: ? {$c print} "Circle(3.0,4.0,5.0)" ? {$d print} "Circle(3.0,4.0,1.5)" ./nsf2.4.0/doc/example-scripts/rosetta-constraint-genericity.tcl000644 000766 000024 00000002541 13565500370 025572 0ustar00neumannstaff000000 000000 # # == Rosetta Example: Constrained genericity # For details see https://rosettacode.org/wiki/Constrained_genericity # package req nx package req nx::test # # Define the two classes +Eatable+ and +Fish+. +Eatable+ is a class # for all eatable things, a +Fish+ is a subclass ant therefore # eatable. # nx::Class create Eatable nx::Class create Fish -superclass Eatable { :property name } # # A +FoodBax+ may only contain eatable items. Therefore, with we define # +items+ as a property of type +Eatable" which has a multiplicity of # +0..n+ (might contain 0 to n eatable items). Furthermore, we define # items as +incremental+, such we can add / remove items with +item # add+ or +item remove+. # nx::Class create FoodBox { :property -incremental item:object,type=::Eatable :public method print {} { set string "Foodbox contains:\n" foreach i ${:item} {append string " [$i cget -name]\n"} return $string } } # === Demonstrating the behavior in a shell: # Create two fishes, Wanda and Nemo: ? {set f1 [Fish new -name "Wanda"]} "::nsf::__#0" ? {set f2 [Fish new -name "Nemo"]} "::nsf::__#1" # Create a Foodbox and add the two fishes: ? {set fb [FoodBox new]} "::nsf::__#2" ? {$fb item add $f1} "::nsf::__#0" ? {$fb item add $f2} "::nsf::__#1 ::nsf::__#0" # Return the print string of the contents: ? {$fb print} {Foodbox contains: Nemo Wanda } ./nsf2.4.0/doc/example-scripts/rosetta-unknown-method.html000644 000766 000024 00000047651 13523353477 024430 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-unknown-method.tcl

    Rosetta Example: Respond to an unknown method call

    package req nx

    Define a class Example modelled after the Python version of Rosetta:

    nx::Class create Example {
    
      :public method foo {} {return "This is foo."}
      :public method bar {} {return "This is bar."}
    
      :method unknown {method args} {
        set result "Tried to handle unknown method '$method'."
        if {[llength $args] > 0} {
          append result " It had arguments '$args'."
        }
        return $result
      }
    }

    Demonstrating the behavior in a shell:

    Create an instance of the class Example:

    % set e [Example new]
    
    % $e foo
    This is foo.
    
    % $e bar
    This is bar.
    
    % $e grill
    Tried to handle unknown method 'grill'.
    
    % $e ding dong
    Tried to handle unknown method 'ding'. It had arguments 'dong'.

    ./nsf2.4.0/doc/example-scripts/tutorial-properties.html000644 000766 000024 00000057434 13317121443 024014 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/tutorial-properties.tcl

    NX supports the concept of properties, which can be used to configure instance variables of a class (or an object) at creation or run time and to add standardized accessor methods.

    package req nx

    In a first step, we create a class named Foo with three properties, x, y and z.

    % nx::Class create Foo {
        :property x
        :property -accessor public y
        :property -incremental z:0..n
    }
    ::Foo

    By defining something as a property, it will be possible (1) to specify a value for the same-named instance variable at creation time, (2) to modify the instance variable via configure, and (3) to access the value of this instance variable from the via the cget method.

    % Foo create f1 -x 1
    ::f1
    
    % f1 cget -x
    1
    % f1 configure -x 2
    % f1 cget -x
    2

    When a property is defined with an accessor (see property y), then an accessor method is added with the specified protection level. The accessor method has the same name as the property. All accessor method can be used to set and get the value of the instance variable.

    % f1 y set 3
    3
    % f1 y get
    3

    Certainly, the methods configure and cget can be used also for these properties as in the example with property x.

    % f1 cget -y
    3

    It is possible to add more and application specific subcommands to the accessor method, but this is not covered in this chapter. However, when a property is defined as incremental it uses this feature to extend the sub-methods.

    When a property is defined as incremental, a public accessor and multivalued are assumed. By specifying incremental the sub-commands add and delete are provided to the accessor, which allows one to add or delete values to a "multivalued" property incrementally (see property z). The term incrementally means here that one can e.g. add values to the list without the need to get the values of the list in a first step, to lappend the value, and to set the value again. The add sub-command is similar to push in MongoDB or LPUSH in redis.

    % f1 z add 1
    1
    % f1 z add 2
    2 1
    % f1 z add 3 end
    2 1 3
    
    % f1 z get
    2 1 3

    The submethod delete can be used to delete a certain value from the list of value.

    % f1 z delete 2
    1 3

    ./nsf2.4.0/doc/example-scripts/tk-locomotive.png000644 000766 000024 00000045571 12501766547 022410 0ustar00neumannstaff000000 000000 PNG  IHDR_ԗlYiCCPICC ProfilexXeTU]^{y..i0@BBQJJQ@PDDBPQEE{?wy\~s"аH#]   cee׶ @㒻sno72[^BF!`D\ }l$OH;%>'0 z45<}`G|$BCpxkaOOszzȍC<م wGzRX]n5o7=kihG [} ijccGv__{`{0,'?MAv$[J"'#+;힯l@#E!Tm9cy$lq g>d+@@H9ԁ60gA HI dӠrP k <1x ^)|`lB@8$@d@ΐA1P"tʂr"T݀nC]P?4 =yh ڀQ0 f`!XVu`3p< * wSx bF$Q*(=%凊DAe QzT5B-~h4-VGt6}݌Aы_2#QØ`04L!2 ӋyYbXa2 &`ױQ vñq8K'.+]uppx"/7ĻB|-?oRR RQYRPʡj@I#4v BPO%",D>*њH> A8CC/F,0 cc5aE&z&&8R{LS(f!fFg,\,:,,,,c,kڬYnQ ؂ΰfG[d?˾ȡ͑L\2 *ϵ̭ĝ=ȓDѡP(=E^N^cދü||||^Ux,^R \rJjf6~%By"U ='X S +ŕωJ`$T%$*$&$I:uRRRR-R_]HIQ y)K/k*,&$'&-W*D,o(TUyIEE tnm%eHzyee2 F+lU]գwU)E5}STVU#wO՞ > OSM SZZZZ}/k\+ۤwXSo?l@o`oPbƐ߰pH(clf|x„ۤdTi֬읹yylajgjް-2򵕰UkuGYD>[[wZU;]"145kSNNٝ[]p..]V+U5~qBӸ{x8zzlyZzVxxxy-zy3;7?PX=8#v}XpXqF§"" "#"/GAQZDf(F$&5f:V34vqtqaqCe7NNNMLJ>sבGS~8ftJ!)8QLrnRR̤֥QEM@<1!Q+'s K&0k+;{ɢ;N (?=v3Wrrsg,)?  Ɯ*2/j-(>]UPTzgYF9scחsgo\0ybsPEa%2cCU%K5/g]ޮbsF6z5k3_j 1 nxxh}Sf-[eM MPŖVۦۚHݩ{ӽvB{JNG|JgxBL{NX >|`~N_Cwo * 6)5=R|44<t ׉Iɹ!Ͽ}+̫״ px+Խiw^x|~~CGYٚ9?sͅ/t_ʾ|MТwٖ(^Zyζ~Ͼ Ǎ̓[m_f^{FzPHT { 1CN \К!jA*hBi0|fffa{aIi]P2QU疠DKIIkTULV WޯbƭUgBSVD;G'S7C/K? 0(߸4)',S[I=nbt9%n_k@7wo_`$S~7 ][ GEG FF[>x&P[ptQcId|)T4t4Ltvjss^<4wWn"^"b>~2A2!H= i{C+lGD*K2MPNw"ck%O%JWkjmU=!ƌ.6]k:rE̝/wA>o`>ʃC kh>37~b̈́ݤs^r{f[)iw*3il\|ҧϖ J_~d{Rr앤صu[ۂvH8 XP DIim1h3d`bceX+T@JhXxDuz2Wd.ȗ*UUT>BC[Sa_[SKˀbH1sp1Z,a-M ---MǟNK._ͻ3 ޯ}}g>ῠΆ GG (Śz(1>;,p M &'ҘZV~DjF\fpl˓:sOsa%Qc PpϢŒϥʦν8?^>ra@@`Х#WFjFj=:xmzG7zye/mwҾֱֵֹ޽~gwj }zqxfdɱ'v?;4YEˢW9~5?dF\|çi _\}SXβDLAX!넟TMv J\Fjt&̑1H *' h;o :Rm 0C (Mp`C4Tt=`:XvQ3H恮@Hbb0Xv9n!a*yphDl$q2Hd_uM<-:%; SaN3 2eq`YfeS`{~Cc3k;grW5_NG0E@'/%j!F+6.^,))!.PX&TV_KnC} b|\<{iTkўYC#{[(8ˤt^}HJ [j;cd{. \ w5X&U5$@Аp3?}bŵK%T8RuL0qi23'O)<#;Qt^q`)Gٓy+*\zP]V[g{M:KNmw;g{$-#x"}ų׌omsg?̹]fjygmsSxy(DWň ؂h ~HxD Aa 8n(({ITA'{1D 3UĦb'pxU|~ʝAPF$IdUr= u9 'M)-m(-zm7Gh*UGYBX ll˜vx(̔!4>~%*h&(VN䠨AlLD7}E2:rlr?G*S>EC3@+Z;Y'OZ]`Ɉl,fblhe~%J=S> nkGz}h|]Յ`B3GDE>9zA\bƣIP㛩Q'Nfg՞8th.U^MYs/KV__oi̽Ӭr{½ݨj]'G ZO&n=_z%g]Yʼ/6T$Itٮ?31Lf Qp 4^o 1AJd AI&t `,[p /Ql}6Zh4uLˀu^npp[xM*zhI&L%NHQDMNޠY]K3%̘ۘ2ǰPԲγdgɑ)+[=O!ŌǯS9LH}_)(&-*!)(%,!="sY"JiSyCeK V'aTӲIխ՟56k1KT yado̙e߾D=z]}^A>vЈ3g"@ !0<kƴ)3߻ .MswC D {kv/O<ěf Η_x6ѝ/oX~DdvD8p`Ek߰~}.\:kٗ^:wfw}Kֽ4:{߽x/kfMl ~ YC?{ّ/XuY>7=kN}mo9魏qţo=RO"MH_pOg1c_R#NW^yT{zz-WD ־-o?*hZ#K K rU3gWT!81kO<952lg߱_cH|=>p<$ێ l%nL~~jO|ySۺXb|_U<}r,\C\Yr闞L';-=ѱLvl(q'H_:fyRC<; xw~w޹`\`9|ƍ.]_A5\ec+N6s/|%Ϟ\=|cq{jc惿AF[V///D tkoMNcWaN%bh"_m۹ki=;=mrt#ocC+Iv%҉X[jYcy?}i3e)[QّH6OeQp}==+7.b\G})SX^9Ȫ8#;n~{F"|u۲sl͟_nN97׾w{ß9W}m-/l|??̎l7y;onr$߿^s_2M~o}_{7ݛSߗ8PQ'y~@!BtʕUUiױ3Rt{G*L$c Q\t<3Έ =zNN=t{-q$2H[<M$'8ML3erWw*OA+4o)p)ݾG7Sg, w׾ѮƊqdȎ_^8d>>zx}bӅ}k2ƃbsY+\髿w͇V/HϘ6m~ߙ9{.3Ld,JD׎Izqŵ-jKx*٦v ĆCmcIxX^p^ =M;sy}3XLh_zH 7|v3Oϥ s`@3#u;pȾ=)I]]Hgc08=~,r/724>mgI&u;ұTkG;G IżN<;T;PCb)|'ND񳔱PdzlB(2G,qr+W=Hu7UFǝM_&hTqɎaD.M}@ vc,g}۾Ж…mcN,^*JYt=^FGpc#r72.iB2µ1D[F|EG3m랜`1@/iMe{>3Bf#}.jL&IvH6Am}c0c A8}"SDjR2wx4;=0xi={wx"G=zc8W޶_+,x3;~??n_8>~=?5k7;ܩ8%#EyȆO\P$qs:VW^ީQ['LJE6oL;S8 %-)\. \?薭["s{ׅҹJ'YbGF>M}NZfpӖ{Oڍ[ΥTR68{3Ix\9s{Kf㲬C19hj$2gt*}'Dhp mO=~o^믯{`^]v-dɎ8tq NW:.|շ^es χrsD=mc_|nd׎ft殬J21>qM=9$#o_x">5ʷֿfμ߼(/|]L޲clg@ z?{*=DV'wLJiw3c'VP##D\kCًO~M,ӿ{9V<6fƜoZ<6={r0twC D@WS_L9˗z+-U,_{?v8g;oxo̗&W.=嫧ⷽgOo=_x{];oYozs!TX078#GȞ#مG?7|wǿ_}R]=]c=z,:={#CA;'OzG'2;>QI`ոc,V~! [|D@^;pBwjh^|EoKD 'gmX`Zi+VEF4c^ܧ/0~}&{v?~ִ&c Cw)YDBW\j4[.Dgse"@BΏ哯0—kL":Y@)S=_V [SI@ Ԉ|b_}jMm>u> DaM2+D"@숚@~J D~%~ΕU|B6ѩ9KEb:6Cf Qʿ!@f5C`YO8SM2`GA={NyF޴ Be#BR ;pPžR Ӻ%EV??J1fDtbҳi!NB5>=@cǧ#A6p1Y"@ ;öb Aэ 5D cǨ24 @eDdH_c$5k-h$I+0$VZ.@m ;"zqӞ8+4(K&קRc}pgDrc尬DDRY0ZR( RcQpјC4.+YMk2 5@XuRNQ(e4:MA>ɋM1,L @v⡐LAt8hnCw]" ci`JȈ[+,V hV:#cU H?ͪb,KI4lG60}"|揀ExH?&[hȎ Yv-_& r%sU@ǀf-<,4?dǓcDoΘ'#RB@tc0jJh]("@,Ȏ^a kAK bz"Upw_$D ;:ĪH@3PY ZNz%Dhv$8.Jȹ]]h8ɋ wP2a"@@h~i\)?̎̐"NÉxxb}afB@"дȅc"U0HA ҆"PKZ@})c2ҳF T"@B@s{Z0T$=O> Y2TZ6n/e"@@h+B3䧀f5H]"@‰1R\V&ۙg^T"@Z 漲ڔCVs_1:Q4nJX DLhQd٢41=0WQPҹ!ɤfixsobGD@Ӳ԰i"HR]؆\uU^=u]Ap$:$D@sL?fnwg[C) /j4 he7BTA(͝'$Hd7Ux>G38/dR/#=Q͓E&kΥ ^>Q(ECXĘY gJ ݫi3#HCʀD ;,||D8)kshTJ(T I! Y-

    h7}sqMSűP,?D5 ;渳j"l{`?>g>t:v??grҺaI@ @vlf-XVgv::yy[d'q2^:{ܳD@%hn #2rU 8ORڲnɂ9m"_q݋x`O;굺N@ ;mD(<~f%EUqÚWU6J41 ve5c|`QF= Ǝ="@@ "WV~aA"@Z[;/ZeD!xX=,"@ АWV|ԿѲ LJz ^zA[YB݇ "dG#jh҉E~|ɪSqzXB gDDQ1`ya"A]\^cِ2jS3J% yvD@iKíF^&Q܌X0!0%h$,)K(3%1L&"*jR˃ɑ!H CSQ)" 6nܸv`!:oFY9٣2.5V(BcVVVKEY YYA[j//ASfHd|cq\rF];ZR ]W.]ݛ7:/]ig^Hswa/"c eNx긔< =R"D4g 6*SmbTWG1FR]HVu@3"@|hrFG6"cF\+?:!RSTo*JZ&A;KP2 f(FO@|.<")oF:;:y#\IDAT”vEL+8  #0k|4&Ԓ0^Eiw,w UQ(ꐠ1 >4;615rM"b3>M|eք UO(wKpc⩩(xH% %#"ԨCIB`jL Lc4nҤFK((ag&FB]O䑏]Ըw -^BA?H `Dv7Ͽ"+[1ڻlU %Ae+[1ڻDTP?8ʍN:25j` @-{RiZbDS4z2NQ; w :ND]Js7'nQq,W枒w(];6=5beuwkIP8?V]K4n"tkW96 Ջ E (C̃2֟[Ѩ>|Z̓A͎PxeQˆPxX:BBjfxq)sWte Xp2SŅ֮au4IEcǦFZwW:)&#Z].8jK j`vU SWefh壉ٝ*i4Y_'~6U%3I [102"CE9f hOp|L`X4N,]]A2-xFL`%B(!L)E D"yP 0dɟIӜUVAK45]{/զYV AL[j|jd @ ,"|e޷8Bd K?_{y>ȿKfQU&("80hABF29tv0AT T!H "B<\,[쎍ŢX|g󖐯j(cQp+r$"}At!1(tRlMeX8l+1E.QG҅|⫥Ȯf\5zQꮙtM% 6lܸqڵ/d;$skП鷱| ba42 ihE׀ApB#}AٗJe%xxFSw dMU315t8*#4@|%h@S"&UwYʕ+vjaL5e!uT-€h|JYBAOc.%(Ɏ%R2YE4#Љnꅊ`ArƮv;K0I@T[i9h`4QtײQ4QVzBj>mòY1&P&dǫJkҴή9`V®RB xҌ(eCpab%d.4a+X @ؤX/+ޯL</}|U1ؤ 9T0FV2(a%ZQ.0Q5sT@3!@vhbrљD(o1Wil|>Y惒To4R-04ձ`4 ͇@%ٱi.9=ʜ5NAڔlA2d 2CFA <Q3r\!BgDÀD0I%1 >:[Fg1(L"z^ JMU(UJPj P*ǸV\dpiY|kC(dNJ rJ[tڭj.Hb챫zqD5le^UT5K/˖%(J@s\|"u$Ȫe>[M!I I!I݊?INaU"ęs5H̊۸ӨT津U[\w55j "K4SVG7nhbAFjJObӀ,H4$yJGF$ڈmNո(&ڵ/aSR|k_ B?!IiO7JkѿElgҜ,TyN ʮ=.?IdeBK5tB0_щVSҠs'M+#6";K; 8wq:gS rD-]i(gG2غ*MsJF2#XbH/ $I$ Jh;df"+'s>ccW3K>ˊGP$ႤjYkQآU"؈lt zksT#t![ݝhnn?ioYi$1ٚb#2,5͔h>9*f`SݭY !I?$4*5VgEMp5 ^!R+U=Ij-sFք* >ZWAldW^nO>MVtg*X.UمS㓧O Y v5sFvvSqĚ<ϾJM%bV狼Yh%$ CdHǪq(y6+ 6?ѿwϨ'ib@Y\)sz RWV` gGڕ|4=CtVsXL 7aCdHpSM=׎a+%ɩh%N]M؅|y,+[$ ҴXQFeD ЛJ& (*^WzSVrFA':1K,T#ZP񳬡OXSֺc8 Q_V\~,%hw܀H+&JKXwPQEvSoL|Gd3Brβ2 I9$ɐUs8.Lj,SpS>@UJ02?>Uk1eAI&D]VϮ0Z2KPl-d] vkW, ՗ QAXn%_H̜,NhQՔ#T<| \ICJ5*ɔR7j4JioɎ:l"(4 p@&Uj1`BRVj֨Jfi閥 uv^ 4衹:Ajc ,AQqZ[j/-Vоbi/Tdqk*JmRAm*M (JmRApk^@ԇ52/.4 T5L>xɃQ$u%SEŶ˧U:;%O}pOk DjiVѽzY%@}эN r3z3{m4LZ{y%5f,Huap{ܘ5QP/S@0,h[K@,'NZ%\߷bzPE^knrkL2eEs.XBTjX#}A$>ui:9}&!Iÿ$4*Z7vԹXwzM>fnJiSܑLRg%t)kJm .R  Ǣ> .f<#Xيl|3%@ %b`:W6ϲ:f4I!I+ֺLmHXK&c%w.JJj,l*-=K%XqGApzĪhdkWm%$iXYY!I2$iX.v3VFRr[j &YBz%9@*Jj"a A(hґyi՛JQ"{݊]"@ԇ'zfA)l4-wPIJzf-IJG +]O(3t.4O- *άƒ,A([y([ *cu@`'gKl4dAe$ Qv &v< Xʡ" 7K@= 'C}!s\zAd4<41RbZ-Y+U0\qé٨>s>'Nf}9-ɪTF/K:t/AܠC9<]tsT3SQaKLʦYe3&v )w'ҧ5$id$4*n(#-L<Xjfb]-8q#5rEy"=į,!0`IY柡hA&D[ky4,°^)-^#D"TU!TEl+ HsM!D" @Z4 CA>䓛6m袋N_"@ ̓%K~vŊ \c(sgddd80d2>lhI w+[zG!ρ/sfjAN"@ D;lIRmt:}ȑ.L, ?6~XIENDB`./nsf2.4.0/doc/example-scripts/rosetta-abstract-type.html000644 000766 000024 00000055653 13523353477 024236 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-abstract-type.tcl

    Rosetta Example: Abstract type

    Define a class without instances and without implemented methods. For detailed description of this example see https://rosettacode.org/wiki/Abstract_type

    package req nx

    Define a class AbstractQueue

    nx::Class create AbstractQueue {
    
      :public method enqueue {item} {error "not implemented"}
      :public method dequeue {} {error "not implemented"}
    
      :public object method create {args} {
        error "Cannot instantiate abstract class [self]"
      }
    }

    Define a concrete queue (named ListQueue) based on the Abstract Queue

    nx::Class create ListQueue -superclass AbstractQueue {
    
      :variable list {}
    
      :public method enqueue {item} {
        lappend :list $item
      }
    
      :public method dequeue {} {
        set item [lindex ${:list} 0]
        set :list [lrange ${:list} 1 end]
        return $item
      }
    }

    Demonstrating the behavior in a shell:

    Trying to create an instance of the AbstraceQueue returns an error message:

    % AbstractQueue new
    Cannot instantiate abstract class ::AbstractQueue

    Create an instance of the concrete queue:

    % set q [ListQueue new]

    Enqueue and dequeue items

    % $q enqueue 100
    100
    % $q enqueue 101
    100 101
    % $q dequeue
    100

    ./nsf2.4.0/doc/example-scripts/rosetta-serialization.html000644 000766 000024 00000061151 13523353477 024317 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-serialization.tcl

    Rosetta Example: Object serialization

    package req nx
    package req nx::serializer
    
    nx::Class create Being {
      :property {alive:boolean true}
    }
    
    nx::Class create Animal -superclass Being {
      :property name
      :public method print {} {
        puts "i am ${:name} alive ${:alive}"
      }
    }

    Demonstrating the behavior in a shell:

    Create a few animals

    % Animal new -name "Fido"
    % Animal new -name "Lupo"
    % Animal new -name "Kiki" -alive false

    Print the created animals

    % foreach i [Animal info instances] { $i print }

    The loop prints:
    i am Kiki alive false
    i am Lupo alive true
    i am Fido alive true

    Serialize the animals to a file

    % set fpath [::nsf::tmpdir]/dump
    % set f [open $fpath w]
    % foreach i [Animal info instances] { puts $f [$i serialize] }
    % close $f

    Destroy all animal instances:

    % foreach i [Animal info instances] { $i destroy }
    % puts ===========

    Print the existing animals (will print nothing)

    % foreach i [Animal info instances] { $i print }
    % puts ===========

    Load the animals again …

    % source $fpath

    and print it. The print output is the same as above

    % foreach i [Animal info instances] { $i print }

    ./nsf2.4.0/doc/example-scripts/rosetta-sudoku.html000644 000766 000024 00000120472 13523353477 022756 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-sudoku.tcl

    Rosetta Example: Sudoku

    Solve a partially filled-in 9x9 Sudoku grid and display the result in a human-readable format. For detailed description of this example, see https://rosettacode.org/wiki/Sudoku_Solver

    This implementation is based on https://wiki.tcl-lang.org/19934

    package require nx

    The class Sudoku implements the basic interface to a sudoku 9x9 board to load/dump data and to set/access cells, rows, columns and regions.

    nx::Class create Sudoku {
    
        :variable board
    
        # Setup an array from 0..9 to ease iterations over the cells of
        # lines and columns.
        for {set i 0} {$i < 9} {incr i} {lappend positions $i}
        :variable positions $positions
    
        :public method load {data} {
            #
            # Load a 9x9 partially solved sudoku. The unsolved cells are
            # represented by a@ symbols.
            #
            set error "data must be a 9-element list, each element also being a\
                    list of 9 numbers from 1 to 9 or blank or an @ symbol."
            if {[llength $data] != 9} {
                error $error
            }
            foreach y ${:positions} {
                set row [lindex $data $y]
                if {[llength $row] != 9} {
                    error $error
                }
                foreach x ${:positions} {
                    set cell [lindex $row $x]
                    if {![regexp {^[@1-9]?$} $cell]} {
                        error $cell-$error
                    }
                    if {$cell eq "@"} {set cell ""}
                    :set $x $y $cell
                }
            }
        }
    
        :public method dump {-pretty-print:switch} {
            #
            # Output the current state of the sudoku either as list or in
            # a pretty-print style.
            #
            set rows [lmap y ${:positions} {:getRow 0 $y}]
            if {${pretty-print}} {
                set result +-----+-----+-----+\n
                foreach line $rows postline {0 0 1 0 0 1 0 0 1} {
                    append result |[lrange $line 0 2]|[lrange $line 3 5]|[lrange $line 6 8]|\n
                    if {$postline} {
                        append result +-----+-----+-----+\n
                    }
                }
                return $result
            } else {
                return $rows
            }
        }
    
        :method log {msg} {
            #puts "log: $msg"
        }
    
        :method set {x y value:integer,0..1} {
            #
            # Set cell at position x,y to the given value or empty.
            #
            if {$value<1 || $value>9} {
                set :board($x,$y) {}
            } else {
                set :board($x,$y) $value
            }
        }
        :method get {x y} {
            #
            # Get value of cell at position x, y.
            #
            return [set :board($x,$y)]
        }
    
        :method getRow {x y} {
            #
            # Return a row at constant position y.
            #
            return [lmap x ${:positions} {:get $x $y}]
        }
        :method getCol {x y} {
            #
            # Return a column at constant position x.
            #
            return [lmap y ${:positions} {:get $x $y}]
        }
    
        :method getRegion {x y} {
            #
            # Return a 3x3 region
            #
            set xR [expr {($x/3)*3}]
            set yR [expr {($y/3)*3}]
            set regn {}
            for {set x $xR} {$x < $xR+3} {incr x} {
                for {set y $yR} {$y < $yR+3} {incr y} {
                    lappend regn [:get $x $y]
                }
            }
            return $regn
        }
    }
    

    The class SudokuSolver inherits from Sudoku, and adds the ability to solve a given Sudoku game. The method solve applies all rules for each unsolved cell until it finds a safe solution.

    nx::Class create SudokuSolver -superclass Sudoku {
    
        :public method validchoices {x y} {
            set v [:get $x $y]
            if {$v ne {}} {
                return $v
            }
    
            set row [:getRow $x $y]
            set col [:getCol $x $y]
            set regn [:getRegion $x $y]
            set eliminate [list {*}$row {*}$col {*}$regn]
            set eliminate [lsearch -all -inline -not $eliminate {}]
            set eliminate [lsort -unique $eliminate]
    
            set choices {}
            for {set c 1} {$c < 10} {incr c} {
                if {$c ni $eliminate} {
                    lappend choices $c
                }
            }
            if {[llength $choices]==0} {
                error "No choices left for square $x,$y"
            }
            return $choices
        }
    
        :method completion {} {
            #
            # Return the number of already solved items.
            #
            return [expr {81-[llength [lsearch -all -inline [join [:dump]] {}]]}]
        }
    
        :public method solve {} {
            #
            # Try to solve the sudoku by applying the provided rules.
            #
            while {1} {
                set begin [:completion]
                foreach y ${:positions} {
                    foreach x ${:positions} {
                        if {[:get $x $y] eq ""} {
                            foreach rule [Rule info instances] {
                                set c [$rule solve [self] $x $y]
                                if {$c} {
                                    :set $x $y $c
                                    :log "[$rule info class] solved [self] at $x,$y for $c"
                                    break
                                }
                            }
                        }
                    }
                }
                set end [:completion]
                if {$end == 81} {
                    :log "Finished solving!"
                    break
                } elseif {$begin == $end} {
                    :log "A round finished without solving any squares, giving up."
                    break
                }
            }
        }
    }
    

    The class rule provides "solve" as public interface for all rule objects. The rule objects apply their logic to the values passed in and return either 0 or a number to allocate to the requested square.

    nx::Class create Rule {
    
        :public method solve {hSudoku:object,type=::SudokuSolver x y} {
            :Solve $hSudoku $x $y [$hSudoku validchoices $x $y]
        }
    
        # Get all the allocated numbers for each square in the row, column, and
        # region containing $x,$y. If there is only one unallocated number among all
        # three groups, it must be allocated at $x,$y
        :create ruleOnlyChoice {
            :object method Solve {hSudoku x y choices} {
                if {[llength $choices] == 1} {
                    return $choices
                } else {
                    return 0
                }
            }
        }
    
        # Test each column to determine if $choice is an invalid choice for all other
        # columns in row $X. If it is, it must only go in square $x,$y.
        :create RuleColumnChoice {
            :object method Solve {hSudoku x y choices} {
                foreach choice $choices {
                    set failed 0
                    for {set x2 0} {$x2 < 9} {incr x2} {
                        if {$x2 != $x && $choice in [$hSudoku validchoices $x2 $y]} {
                            set failed 1
                            break
                        }
                    }
                    if {!$failed} {return $choice}
                }
                return 0
            }
        }
    
        # Test each row to determine if $choice is an invalid choice for all other
        # rows in column $y. If it is, it must only go in square $x,$y.
        :create RuleRowChoice {
            :object method Solve {hSudoku x y choices} {
                foreach choice $choices {
                    set failed 0
                    for {set y2 0} {$y2 < 9} {incr y2} {
                        if {$y2 != $y && $choice in [$hSudoku validchoices $x $y2]} {
                            set failed 1
                            break
                        }
                    }
                    if {!$failed} {return $choice}
                }
                return 0
            }
        }
    
        # Test each square in the region occupied by $x,$y to determine if $choice is
        # an invalid choice for all other squares in that region. If it is, it must
        # only go in square $x,$y.
        :create RuleRegionChoice {
            :object method Solve {hSudoku x y choices} {
                foreach choice $choices {
                    set failed 0
                    set regnX [expr {($x/3)*3}]
                    set regnY [expr {($y/3)*3}]
                    for {set y2 $regnY} {$y2 < $regnY+3} {incr y2} {
                        for {set x2 $regnX} {$x2 < $regnX+3} {incr x2} {
                            if {
                                ($x2!=$x || $y2!=$y)
                                && $choice in [$hSudoku validchoices $x2 $y2]
                            } then {
                                set failed 1
                                break
                            }
                        }
                    }
                    if {!$failed} {return $choice}
                }
                return 0
            }
        }
    }
    
    SudokuSolver create sudoku {
    
        :load {
            {3 9 4    @ @ 2    6 7 @}
            {@ @ @    3 @ @    4 @ @}
            {5 @ @    6 9 @    @ 2 @}
    
            {@ 4 5    @ @ @    9 @ @}
            {6 @ @    @ @ @    @ @ 7}
            {@ @ 7    @ @ @    5 8 @}
    
            {@ 1 @    @ 6 7    @ @ 8}
            {@ @ 9    @ @ 8    @ @ @}
            {@ 2 6    4 @ @    7 3 5}
        }
        :solve
    
        puts [:dump -pretty-print]
    }

    The dump method outputs the solved Sudoku:

    +-----+-----+-----+
    |3 9 4|8 5 2|6 7 1|
    |2 6 8|3 7 1|4 5 9|
    |5 7 1|6 9 4|8 2 3|
    +-----+-----+-----+
    |1 4 5|7 8 3|9 6 2|
    |6 8 2|9 4 5|3 1 7|
    |9 3 7|1 2 6|5 8 4|
    +-----+-----+-----+
    |4 1 3|5 6 7|2 9 8|
    |7 5 9|2 3 8|1 4 6|
    |8 2 6|4 1 9|7 3 5|
    +-----+-----+-----+

    ./nsf2.4.0/doc/example-scripts/rosetta-tokenizer.tcl000644 000766 000024 00000003022 13300453302 023240 0ustar00neumannstaff000000 000000 # Assumes Tcl 8.6 (couroutine support) if {[catch {package req Tcl 8.6}]} return # # == Rosetta example: Tokenize a string with escaping # # # Write a class which allows for splitting a string at each non-escaped # occurrence of a separator character. # # See https://rosettacode.org/wiki/Tokenize_a_string_with_escaping # package req nx package req nx::test nx::Class create Tokenizer { :property s:required :method init {} { :require namespace set coro [coroutine [current]::nextCoro [current] iter ${:s}] :public object forward next $coro } :public method iter {s} { yield [info coroutine] for {set i 0} {$i < [string length $s]} {incr i} { yield [string index $s $i] } return -code break } :public object method tokenize {{-sep |} {-escape ^} s} { set t [[current] new -s $s] set part "" set parts [list] while {1} { set c [$t next] if {$c eq $escape} { append part [$t next] } elseif {$c eq $sep} { lappend parts $part set part "" } else { append part $c } } lappend parts $part return $parts } } # Run some tests including the escape character: ? {Tokenizer tokenize -sep | -escape ^ ^|} {|} ? {Tokenizer tokenize -sep | -escape ^ ^|^|} {||} ? {Tokenizer tokenize -sep | -escape ^ ^^^|} {^|} ? {Tokenizer tokenize -sep | -escape ^ |} {{} {}} # Test for the output required by the Rosetta example: ? {Tokenizer tokenize -sep | -escape ^ one^|uno||three^^^^|four^^^|^cuatro|} {one|uno {} three^^ four^|cuatro {}} ./nsf2.4.0/doc/example-scripts/tk-ludo.html000644 000766 000024 00000260443 13565476242 021351 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/tk-ludo.tcl

    A small Ludo/Mensch ärgere Dich nicht/Pachisie game, originally developed by Richard Suchenwirth in plain Tcl (see http://wiki.tcl.tk/956). The game was rewritten as a design study in NX by Gustaf Neumann in July 2013.

    Major changes:

    • object-oriented design (no global variables)

    • knowledge about the paths of the figures

    • animated moves

    • knowledge about the basic rules (e.g. need 6 to move out of the nest, have to move figures from starting position)

    • throw opponents out

    • sanity checks

    • user feedback

    tk-ludo.png

    Short Instructions

    • The active player (marked with the button) has to dice (click on the die, or press somewhere on the board "d").

    • If all figures are in the nest (start position), the player needs to dice a 6. The player is allowed to try three times, then the player is done (press "done" button, or type "n") and the turn moves to the next player.

    • When a player got 6 eyes, he can move out of the nest. This is done by clicking on the figure the player wants to move.

    • After dicing 6, the player can dice again and move the player on the field (always by clicking on the figure).

    Implementation

    package require Tk
    package require nx::trait

    Define an application specific converter "expr" that passes the scalar result of the expression. Since the converter is defined on nx::Slot, it is applicable to all method and configure arguments.

    ::nx::Slot method type=expr {name value} {return [expr $value]}

    Class Figure

    nx::Class create Figure {
        :property canvas:required
        :property x:double
        :property y:double
        :property size:double
        :property position:integer
        :property color
        :property no:integer
        :property board:object,required
        :variable tag ""
    
        :require trait nx::trait::callback
    
        :method init {} {
            #
            # Draw figure and define interactions
            #
            set d [expr {${:size}/6.}]
            set s [expr {${:size}/1.5}]
            set y [expr {${:y}-$d*2.5}]
            set :tag ${:color}${:no}
            set id [${:canvas} create arc [expr {${:x}-$s}] [expr {${:y}-$s}] \
                        [expr {${:x}+$s}] [expr {${:y}+$s}] -outline grey \
                        -start 250 -extent 40 -fill ${:color} \
                        -tags [list mv ${:tag}]]
            ${:canvas} create oval \
                [expr {${:x}-$d}] [expr {${:y}-$d}] \
                [expr {${:x}+$d}] [expr {${:y}+$d}] \
                -fill ${:color} -outline grey -tags [list mv ${:tag}]
            #${:board} figure set $id [self]
            ${:canvas} bind ${:tag} <B1-ButtonRelease> [:callback go]
        }
    
        :public method go {} {
            #
            # Start moving the figure if the draw is permitted.
            # The board knows the die and the rules.
            #
            if {![${:board} moveFigure [self]]} {
                # stay at old position
                :gotoNr ${:position}
            }
        }
    
        :public method gotoNr {nr {-path ""} {-afterCmd ""}} {
            #
            # Move figure to the numbered position. If a path is given it
            # moves stepwise from position to position.
            #
            set oldPos ${:position}
            set :position $nr
            if {$path eq ""} {set path $nr}
            return [:move {*}[${:board} getPointCenter $oldPos] $path \
                        -afterCmd $afterCmd]
        }
    
        :protected method move {x0 y0 path:integer,1..n {-afterCmd ""}} {
            #
            # Move figure from old position (x0 y0) stepwise along the
            # path using animation. At the end of the move, 'afterCmd' is
            # issued.
            #
            set t 0
            foreach pos $path {
                lassign [${:board} getPointCenter $pos] x y
                set stepx [expr {($x-$x0)/50.0}]
                set stepy [expr {($y-$y0)/50.0}]
                for {set i 0} {$i < 50} {incr i} {
                    after [incr t 8] ${:canvas} move ${:tag} $stepx $stepy
                }
                lassign [list $x $y] x0 y0
                incr t 100
            }
            after $t ${:canvas} raise ${:tag}
            after $t $afterCmd
            set :x $x; set :y $y
        }
    
        :public object method lookup {position} {
            #
            # Return the figure at the provided position.  This function
            # could be made faster, but is efficient enough as it is.
            #
            foreach f [Figure info instances] {
                if {[$f cget -position] == $position} {
                    return $f
                }
            }
            return ""
        }
    }

    Helper functions for the die

    proc random:select L {lindex $L [expr int(rand()*[llength $L].)]}
    proc lexpr {term L} {
        # map an expr term to each element \$i of a list
        set res [list]
        foreach i $L {lappend res [eval expr $term]}
        set res
    }

    Class Die

    nx::Class create Die {
        :property canvas:required
        :property x:double
        :property y:double
        :property {size:double 25}
        :property {fg gold}
        :property {bg red}
        :property {eyes 0}
    
        :require trait nx::trait::callback
    
        :method set {n} {
            #
            # Set the eyes of the die.
            #
            ${:canvas} itemconfig ${:grouptag} -fill ${:bg} -outline ${:bg}
            foreach i [lindex [list \
                   {} {d5} [random:select {{d3 d7} {d1 d9}}] \
                   [random:select {{d1 d5 d9} {d3 d5 d7}}] \
                   {d1 d3 d7 d9} {d1 d3 d5 d7 d9} \
                   [random:select {{d1 d3 d4 d6 d7 d9} {d1 d2 d3 d7 d8 d9}}] \
                  ] $n] {
                ${:canvas} itemconfig ${:id}$i -fill ${:fg} -outline ${:fg}
            }
            set :eyes $n
        }
    
        :public method invalidate {} {
            #
            # Invalidate the eyes to avoid double uses of the eyes.
            #
            set :eyes 0
        }
    
        :public method roll {} {
            #
            # Roll the dice and animate rolling
            #
            # wiggle: amount, pick one of eight wiggle directions
            set dwig [expr {${:size}/5}]
            for {set i 10} {$i<100} {incr i 10} {
                :set [expr {int(rand() * 6) + 1}]
                set wig [random:select {0,1 0,-1 1,0 -1,0 1,1 -1,1 1,-1 -1,-1}]
                set wig [lexpr \$i*$dwig [split $wig ,]]
                ${:canvas} move group${:id} {*}$wig
                update
                set wig [lexpr \$i*-1 $wig] ;# wiggle back
                ${:canvas} move group${:id} {*}$wig
                after $i
            }
        }
    
        :method init {} {
            #
            # initialize the widgets with tags interactions
            #
            set x [expr {${:x} - ${:size}/2.0}]
            set y [expr {${:y} - ${:size}/2.0}]
            set :id [${:canvas} create rect $x $y \
                         [expr {$x+${:size}}] [expr {$y+${:size}}] \
                         -fill ${:bg} -tags mvg]
            set :grouptag group${:id}
            ${:canvas} addtag ${:grouptag} withtag ${:id}
            set ex [expr {$x+${:size}/10.}]
            set ey [expr {$y+${:size}/10.}]
            set d  [expr {${:size}/5.}];# dot diameter
            set dotno 1 ;# dot counter
            foreach y [list $ey [expr {$ey+$d*1.5}] [expr {$ey+$d*3}]] {
                foreach x [list $ex [expr {$ex+$d*1.5}] [expr {$ex+$d*3}]] {
                    ${:canvas} create oval $x $y [expr {$x+$d}] [expr {$y+$d}] \
                        -fill ${:bg} -outline ${:bg} \
                        -tags [list mvg ${:grouptag} ${:id}d$dotno]
                    incr dotno
                }
            }
            :set [expr {int(rand()*6)+1}]
            :invalidate
            #
            # To dice, let people click on the die, or press <d> on the
            # board
            #
            ${:canvas} bind mvg <1> [:callback roll]
            bind . <d> [:callback roll]
        }
    }

    Class Board

    nx::Class create Board {
        :property canvas:required
        :property {size:integer 25}
        :property {bg LightBlue1}
        :property {fg white}
        :property {colors:1..n {red green yellow blue}}
    
        :require trait nx::trait::callback
    
        :method lookup {var idx} {
            #
            # Convenience lookup function for arbitrary instance
            # variables.
            #
            set key "${var}($idx)"
            if {[info exists $key]} {return [set $key]}
            return ""
        }
    
        :public method getPointCenter {nr} {:lookup :pointCenter $nr}
        :public method getPointId {nr}     {:lookup :pointId $nr}
    
        :method line {
            x0:expr,convert y0:expr,convert x1:expr,convert y1:expr,convert
            {-width 1} {-arrow none}
        } {
            #
            # Convenience function for line drawing, evaluates passed
            # expressions.
            #
            ${:canvas} create line $x0 $y0 $x1 $y1 -width $width -arrow $arrow
        }
    
        :method point {x:expr,convert y:expr,convert d {-number:switch false} -fill} {
            #
            # Draw a point (a position on the game board) and keep its
            # basic data in instance variables. We could as well turn the
            # positions into objects.
            #
            if {![info exists fill]} {set fill ${:fg}}
            incr :pointCounter
            set id [${:canvas} create oval \
                        [expr {$x-$d/2.}] [expr {$y-$d/2.}] \
                        [expr {$x+$d/2.}] [expr {$y+$d/2.}] \
                        -fill $fill -tags [list point] -outline brown -width 2]
            #${:canvas} create text $x $y -text ${:pointCounter} -fill grey
            set :pointNr($id) ${:pointCounter}
            set :pointCenter(${:pointCounter}) [list $x $y]
            set :pointId(${:pointCounter}) $id
            return ${:pointCounter}
        }
    
        :method fpoint {x:expr,convert y:expr,convert psize fsize color no} {
            #
            # Draw a point with a figure, note the position in the board
            # in the figure
            #
            set nr [:point $x $y $psize -fill $color]
            Figure new -board [self] -canvas ${:canvas} \
                -x $x -y [expr {$y-$fsize/2.0}] \
                -size $fsize -color $color -no $no -position $nr
            return $nr
        }
    
        :method pnest {x:expr,convert y:expr,convert d colorNr xf yf} {
            #
            # Draw the nest with the figures in it
            #
            set fsize [expr {$d/0.75}]
            set color [lindex ${:colors} $colorNr]
            lappend :nest($colorNr) [:fpoint $x-$d $y-$d $d $fsize $color 0]
            lappend :nest($colorNr) [:fpoint $x-$d $y+$d $d $fsize $color 1]
            lappend :nest($colorNr) [:fpoint $x+$d $y-$d $d $fsize $color 2]
            lappend :nest($colorNr) [:fpoint $x+$d $y+$d $d $fsize $color 3]
            set :buttonPos($colorNr) [list [expr $x+($xf*$d)] [expr $y+($yf*$d)]]
        }
    
        :method pline {
            x0:expr,convert y0:expr,convert
            x1:expr,convert y1:expr,convert d {-width 1} {-arrow none}
        } {
            #
            # Draw a path of the play-field with points (potential player
            # positions) on it.
            #
            set id [${:canvas} create line $x0 $y0 $x1 $y1 \
                        -width $width -arrow $arrow -fill brown]
            if {$x0 eq $x1} {
                # vertical
                set f [expr {$y1<$y0 ? -1.25 : 1.25}]
                for {set i 0} {$i < int(abs($y1-$y0)/($d*1.25))} {incr i} {
                    :point $x0 $y0+$i*$d*$f $d
                }
            } else {
                # horizontal
                set f [expr {$x1<$x0 ? -1.25 : 1.25}]
                for {set i 0} {$i < int(abs($x1-$x0)/($d*1.25))} {incr i} {
                    :point $x0+$i*$d*$f $y0 $d -number
                }
            }
            ${:canvas} lower $id
        }
    
        :method draw {m} {
            #
            # Draw board and create figures
            #
            set d ${:size}
            set u [expr {$d * 1.25}]
            #
            # Major positions: p0 .. p1 ..m.. p2 .. p3
            #
            set p0 [expr {$u-$d/2.0}]
            set p1 [expr {$m-$u}]
            set p2 [expr {$m+$u}]
            set p3 [expr {2*$m-$u+$d/2}]
    
            :pline $p0 $p1 $p1 $p1 $d -width 4
            :pline $p1 $p1 $p1 $p0 $d -width 4
            :pline $p1 $p0 $p2 $p0 $d -width 4 ;# horizontal short line
            :pline $p2 $p0 $p2 $p1 $d -width 4
            :pline $p2 $p1 $p3 $p1 $d -width 4
            :pline $p3 $p1 $p3 $p2 $d -width 4 ;# vertical short line
            :pline $p3 $p2 $p2 $p2 $d -width 4
            :pline $p2 $p2 $p2 $p3 $d -width 4
            :pline $p2 $p3 $p1 $p3 $d -width 4 ;# horizontal short line
            :pline $p1 $p3 $p1 $p2 $d -width 4
            :pline $p1 $p2 $p0 $p2 $d -width 4
            :pline $p0 $p2 $p0 $p1 $d -width 4 ;# vertical short line
            :line $m+5*$d  $m+2*$d  $m+6*$d  $m+2*$d -arrow first
            :line $m-2*$d  $m+5*$d  $m-2*$d  $m+6*$d -arrow first
            :line $m-5*$d  $m-2*$d  $m-6*$d  $m-2*$d -arrow first
            :line $m+2*$d  $m-5*$d  $m+2*$d  $m-6*$d -arrow first
    
            set d2 [expr {$d*0.75}]
            set d15 $d2*2
            set o [expr {$u*5}]
            :pnest $m+$o-$d $m-$o+$d $d2 0 -1  3
            :pnest $m+$o-$d $m+$o-$d $d2 1 -1 -2.5
            :pnest $d15     $m+$o-$d $d2 2  1 -2.5
            :pnest $d15     $m-$o+$d $d2 3  1  3
            for {set i 0; set y [expr $d*2]} {$i<4} {incr i;set y [expr {$y+$d}]} {
                lappend p(0) [:point $m      $y      $d2 -fill [lindex ${:colors} 0]]
                lappend p(1) [:point $m*2-$y $m      $d2 -fill [lindex ${:colors} 1]]
                lappend p(2) [:point $m      $m*2-$y $d2 -fill [lindex ${:colors} 2]]
                lappend p(3) [:point $y      $m      $d2 -fill [lindex ${:colors} 3]]
            }
            #
            # Setup the path per player and color the starting points
            #
            for {set i 1} {$i < 41} {incr i} {lappend path $i}
            foreach c {0 1 2 3} pos {11 21 31 1} o {11 21 31 1} {
                ${:canvas} itemconfig [:getPointId $pos] -fill [lindex ${:colors} $c]
                set :path($c) [concat [lrange $path $o-1 end] [lrange $path 0 $o-2] $p($c)]
            }
        }
    
        :public method msg {text} {
            #
            # Report a message to the user.
            #
            ${:canvas} itemconfig ${:msgId} -text $text
            return 0
        }
    
        :public method wannaGo {obj pos {-path ""}} {
            #
            # We know that we can move the figure in principle.  We have
            # to check, whether the target position is free. If the target
            # is occupied by our own player, we give up, otherwise we
            # through the opponent out.
            #
            if {$pos eq ""} {return [:msg "beyond path"]}
            set other [Figure lookup $pos]
            set afterCmd ""
            if {$other ne ""} {
                if {[$obj cget -color] eq [$other cget -color]} {
                    # On player can't have two figure at the same place.
                    return [:msg "My player is already at pos $pos"]
                } else {
                    # Opponent is at the target position. Find a free
                    # position in the opponents nest and though her out.
                    set opponent [$other cget -color]
                    foreach p [set :nest([lsearch ${:colors} $opponent])] {
                        if {[Figure lookup $p] eq ""} {
                            set afterCmd [list $other gotoNr $p]
                            break
                        }
                    }
                }
            }
            :msg "[$obj cget -color]-[$obj cget -no] went to $pos"
            $obj gotoNr $pos -path $path -afterCmd $afterCmd
            ${:die} invalidate
        }
    
        :public method moveFigure {obj} {
            #
            # Move the provided figure by the diced eyes according to the
            # rules. First we check, if we are allowed to move this
            # figure, which might be in the nest or on the run.
            #
            set currentColor [lindex ${:colors} ${:player}]
            if {[$obj cget -color] ne $currentColor} {
                return [:msg "figure is not from the current player"]
            }
            set eyes [${:die} cget -eyes]
            if {$eyes == 0} {
                return [:msg "Must dice first"]
            }
            set position [$obj cget -position]
            if {$position in [set :nest(${:player})]} {
                # Figure is in the nest, just accept eyes == 6
                if {$eyes == 6} {
                    :wannaGo $obj [lindex [set :path(${:player})] 0]
                } else {
                    return [:msg "Need 6 to move this figure"]
                }
            } else {
                #
                # Check, if we have still figures in the nest
                #
                set inNest ""
                foreach p [set :nest(${:player})] {
                    set inNest [Figure lookup $p]
                    if {$inNest ne ""} break
                }
                #
                # Check, if the actual figure is at the start position.
                #
                set startPos [lindex [set :path(${:player})] 0]
                set atStart [Figure lookup $startPos]
                if {$eyes == 6} {
                    if {$inNest ne ""} {
                        # Move a figure out from the nest, if we can
                        if {$atStart ne ""} {
                            if {[$atStart cget -color] eq $currentColor} {
                                set path [set :path(${:player})]
                                set current [lsearch $path $position]
                                set targetPos [expr {$current + [${:die} cget -eyes]}]
                                :wannaGo $obj [lindex $path $targetPos] \
                                    -path [lrange $path $current+1 $targetPos]
                                return 1
                            }
                        }
                        return [:msg "You have to move the figures from your nest first"]
                    }
                }
                if {$atStart ne "" && $inNest ne "" && $obj ne $atStart} {
                    return [:msg "You have to move the figures from the start first"]
                }
                set path [set :path(${:player})]
                set current [lsearch $path $position]
                set targetPos [expr {$current + [${:die} cget -eyes]}]
                :wannaGo $obj [lindex $path $targetPos] \
                    -path [lrange $path $current+1 $targetPos]
            }
            return 1
        }
    
        :public method nextPlayer {} {
            #
            # Switch to the next player.
            #
            set :player [expr {(${:player}+1) % 4}]
            ${:canvas} coords ${:buttonWindow} {*}[set :buttonPos(${:player})]
        }
    
        :method init {} {
            set hw [expr {14 * ${:size}}]
            set center [expr {$hw / 2}]
            canvas ${:canvas} -bg ${:bg} -height $hw -width $hw
            :draw $center
            set :die [Die new -canvas ${:canvas} -x $center -y $center -size ${:size}]
            set :msgId [${:canvas} create text [expr {${:size}*4}] 10 -text ""]
            #
            # Player management (signal which player is next, etc.)
            #
            set :player 2
            button .b1 -text "Done" -command [:callback nextPlayer]
            set :buttonWindow [.p create window 22 14 -window .b1]
            :nextPlayer
            bind . <n> [:callback nextPlayer]
        }
    }

    Finally, create the board and pack it

    Board new -canvas .p -bg beige -size 40
    pack .p

    ./nsf2.4.0/doc/example-scripts/rosetta-polymorphism.html000644 000766 000024 00000055541 13523353500 024175 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/rosetta-polymorphism.tcl

    Rosetta Example: Polymorphism

    package req nx
    
    nx::Class create Point {
    
      :property x:double
      :property y:double
    
      :public method print {} {
        return "Point(${:x},${:y})"
      }
    }
    
    nx::Class create Circle -superclass Point {
    
      :property radius:double
    
      :public method print {} {
        return "Circle(${:x},${:y},${:radius})"
      }
    }

    Demonstrating the behavior in a shell:

    Create a point and get the print string:

    % set p [Point new -x 1.0 -y 2.0]
    % $p print
    Point(1.0,2.0)

    Get the x coordinate of this point:

    % $p cget -x
    1.0

    Create a circle:

    % set c [Circle new -x 3.0 -y 4.0 -radius 5.0]

    Copy the circle

    % set d [$c copy]

    Change the radius of the copied circle:

    % $d configure -radius 1.5

    Print the two circles:

    % $c print
    Circle(3.0,4.0,5.0)
    
    % $d print
    Circle(3.0,4.0,1.5)

    ./nsf2.4.0/doc/example-scripts/ruby-mixins.html000644 000766 000024 00000121124 13523353500 022231 0ustar00neumannstaff000000 000000 Listing of doc/example-scripts/ruby-mixins.tcl

    Design study to show the differences between decorator mixin classes and Ruby’s mixin modules

    This example shows that the dynamic class structure of NX (and XOTcl) is able to support Ruby style mixins (called modules) and decorator style mixins (named after the design pattern Decorator) in the same script.

    nx::test configure -count 1

    One important difference between mixin classes in NX and Ruby’s mixins is the precedence order. While in NX, mixins are decorators (the mixins have higher precedence than the intrinsic classes, therefore a mixin class can overload the methods of the current class and its subclasses), the mixins of Ruby have a lower precedence (they extend the base behavior; although Ruby’s modules are not full classes, they are folded into the intrinsic class hierarchy). Therefore, a Ruby style mixin can be refined by the class, into which it is mixed in (or by a subclass). Decorator style mixins modify the behavior of a full intrinsic class tree, while Ruby style mixins are compositional units for a single class.

    To show the differences, we define the method module, which behaves somewhat similar to Ruby’s module command. This method adds the provided class to the precedence order after the current class. The easiest way to achieve this is via multiple inheritance (i.e. via the superclass relationship).

    package req nx
    
    nx::Class eval {
      :protected method module {name:class} {
        nsf::relation::set [self] superclass [concat $name [:info superclasses]]
      }
    }

    For illustration of the behavior of module we define a class Enumerable somewhat inspired by the Ruby module with the same name. We define here just the methods map, each, count, and count_if.

    nx::Class create Enumerable {
      :property members:0..n
    
      # The method 'each' applies the provided block on every element of
      # 'members'
      :public method each {var block} {
        foreach member ${:members} {
          uplevel [list set $var $member]
          uplevel $block
        }
      }
    
      # The method 'map' applies the provided block on every element of
      # 'members' and returns a list, where every element is the mapped
      # result of the source.
      :public method map {var block} {
        set result [list]
        :each $var {
          uplevel [list set $var [set $var]]
          lappend result [uplevel $block]
        }
        return $result
      }
    
      # The method 'count' returns the number of elements.
      :public method count {} {
        return [llength ${:members}]
      }
    
      # The method 'count_if' returns the number of elements for which
      # the provided expression is true.
      :public method count_if {var expr} {
        set result 0
        :each $var {
          incr result [expr $expr]
        }
        return $result
      }
    }

    After having defined the class Enumerable, we define a class Group using Enumerable as a Ruby style mixin. This makes essentially Group a subclass of Enumerable, but with the only difference that Group might have other superclasses as well.

    nx::Class create Group {
      #
      # Include the "module" Enumerable
      #
      :module Enumerable
    }

    Define now a group g1 with the three provided members.

    % Group create g1 -members {mini trix trax}
    ::g1

    Since the definition of Group includes the module Enumerable, this class is listed in the precedence order after the class Group:

    % g1 info precedence
    ::Group ::Enumerable ::nx::Object

    Certainly, we can call the methods of Enumerable as usual:

    % g1 count
    3
    
    % g1 map x {list pre-$x-post}
    pre-mini-post pre-trix-post pre-trax-post
    
    % g1 count_if x {[string match tr*x $x] > 0}
    2

    To show the difference between a module and a decorator mixin we define a class named Mix with the single method count, which wraps the result of the underlying count method between the alpha and omega.

    nx::Class create Mix {
      :public method count {} {
        return [list alpha [next] omega]
      }
    }

    When the mixin class is added to g1, it is added to the front of the precedence list. A decorator is able to modify the behavior of all of the methods of the class, where it is mixed into.

    % g1 object mixins set Mix
    ::Mix
    
    % g1 info precedence
    ::Mix ::Group ::Enumerable ::nx::Object
    
    % g1 count
    alpha 3 omega

    For the time being, remove the mixin class again.

    % g1 object mixins set ""
    % g1 info precedence
    ::Group ::Enumerable ::nx::Object

    An important difference between NX/XOTcl style mixins (decorators) and Ruby style modules is that the decorator will have always a higher precedence than the intrinsic classes, while the module is folded into the precedence path.

    Define a class ATeam that uses Enumerable in the style of a Ruby module. The class might refine some of the provided methods. We refined the method each, which is used as well by the other methods. In general, by defining each one can define very different kind of enumerators (for lists, databases, etc.).

    Since Enumerable is a module, the definition of each in the class ATeam has a higher precedence than the definition in the class Enumerable. If Enumerable would be a decorator style mixin class, it would not e possible to refine the definition in the class ATeam, but maybe via another mixin class.

    nx::Class create ATeam {
      #
      # Include the "module" Enumerable
      #
      :module Enumerable
    
      #
      # Overload "each"
      #
      :public method each {var block} {
        foreach member ${:members} {
          uplevel [list set $var $member-[string length $member]]
          uplevel $block
        }
      }
    
      #
      # Use "map", which uses the "each" method defined in this class.
      #
      :public method foo {} {
        return [:map x {string totitle $x}]
      }
    }

    Define now a team t1 with the three provided members.

    % ATeam create t1 -members {arthur bill chuck}
    ::t1

    As above, the precedence of ATeam is higher than the precedence of Enumerable. Therefore, the object t1 uses the method each specialized in class ATeam:

    % t1 info precedence
    ::ATeam ::Enumerable ::nx::Object
    
    % t1 foo
    Arthur-6 Bill-4 Chuck-5

    The class ATeam can be specialized further by a class SpecialForce:

    nx::Class create SpecialForce -superclass ATeam {
      # ...
    }

    Define a special force s1 with the four provided members.

    % SpecialForce create s1 -members {Donald Micky Daniel Gustav}
    ::s1

    As above, the precedence of Enumerable is lower then the precedence of ATeam and Enumerable. Therefore ATeam can refine the behavior of Enumerable, the class SpecialForce can refine the behavior of ATeam.

    % s1 info precedence
    ::SpecialForce ::ATeam ::Enumerable ::nx::Object
    
    % s1 foo
    Donald-6 Micky-5 Daniel-6 Gustav-6

    Let us look again on decorator style mixin classes. If we add a per-class mixin to ATeam, the mixin class has highest precedence, and decorates the instances of ATeam as well the instances of its specializations (like e.g. SpecialForce).

    % ATeam mixins set Mix
    ::Mix
    
    % s1 info precedence
    ::Mix ::SpecialForce ::ATeam ::Enumerable ::nx::Object
    
    % s1 count
    alpha 4 omega

    This example showed that NX/XOTcl dynamic class structure is able to support Ruby-style mixins, and decorator style mixins in the same script.


    ./nsf2.4.0/doc/example-scripts/container.tcl000644 000766 000024 00000014172 13270041752 021551 0ustar00neumannstaff000000 000000 # # This example is a small design study to implement container classes # with different features, namely a +SimpleContainer+, an # +OrderedContainer+ and a +SortedContainer+. First of all, we require NX: # package req nx package req nx::test nx::test configure -count 1 # == Simple Container # # The first container class presented here is called # +SimpleContainer+, which manages its contained items. As all # container classes presented here, the items are created as child # objects embedded in the container. If the container is deleted, all # items are deleted as well. The items, which will be put into the # container, should be instances of a certain class. We define here # for this purpose an arbitrary class +C+: nx::Class create C # The class +SimpleContainer+ keeps and manages items added to it. # Every instance of this class might have different item classes. We # might provide a prefix for naming the items, otherwise the default # is +member+. # nx::Class create SimpleContainer { :property {memberClass ::MyItem} :property {prefix member} # Require the method "autoname" for generating nice names :require method autoname # The method new is responsible for creating a child of the current # container. :public method new {args} { set item [${:memberClass} create [:]::[:autoname ${:prefix}] {*}$args] return $item } } # Create and instance of the class +SimpleContainer+ ... ? {SimpleContainer create container1 -memberClass ::C} ::container1 # and add a few items: ? {container1 new} "::container1::member1" ? {container1 new} "::container1::member2" ? {container1 new} "::container1::member3" # The elements of the container can be obtained via +info children+: ? {container1 info children} "::container1::member1 ::container1::member2 ::container1::member3" # == Ordered Container # # In the example with +SimpleContainer+, the order of the results of # +info children+ just happens to be in the order of the added items, # but in general, this order is not guaranteed, but depends on the # population of the hash tables. In the next step, we extend the # example above by preserving the order of the elements. # The class +OrderedContainer+ is similar to +SimpleContainer+, but # keeps a list of items that were added to the container. The item # list is managed in a property +items+ which is defined as # +incremental+ to make use of the +add+ and +delete+ methods provided # by the slots. # nx::Class create OrderedContainer -superclass SimpleContainer { :property -incremental {items:0..n {}} :public method new {args} { set item [${:memberClass} create [:]::[:autoname ${:prefix}] {*}$args] :items add $item end return $item } # Since we keep the list of items, we have to maintain it in case # items are deleted. :public method delete {item:object} { :items delete $item $item destroy } } # Create an instance of +OrderedContainer+ ... ? {OrderedContainer create container2 -memberClass ::C} "::container2" # and add a few items: ? {container2 new} "::container2::member1" ? {container2 new} "::container2::member2" ? {container2 new} "::container2::member3" # The elements of the container are obtained via the method +items+. ? {container2 items get} "::container2::member1 ::container2::member2 ::container2::member3" # When we delete an item in the container ... ? {container2 delete ::container2::member2} "" # the item is as well removed from the +items+ list. ? {container2 items get} "::container2::member1 ::container2::member3" # == Sorted Container # # In the next step, we define a +SortedContainer+, that keeps # additionally a sorted list for iterating through the items without # needing to sort the items when needed. The implementation maintains # an additional sorted list. The implementation of the SortedContainer # depends on "lsearch -bisect" which requires Tcl 8.6. Therefore, if # we have no Tcl 8.6, just return here. if {[info command yield] eq ""} return # For sorting, we require the item class to have a key, that can be # freely specified. We use there the property +name+ of Class +D+: nx::Class create D { :property name:required } nx::Class create SortedContainer -superclass OrderedContainer { # In order to keep the index consisting of just the objects and to # ease sorting, we maintain two list, one list of values and one # list of objects. We assume for the time being, that the keys are # not changing. :variable values {} :variable index {} :property key :public method index {} { return ${:index}} :public method new {args} { set item [${:memberClass} create [:]::[:autoname ${:prefix}] {*}$args] if {[info exists :key]} { set value [$item cget -${:key}] set pos [lsearch -bisect ${:values} $value] set :values [linsert ${:values} [expr {$pos + 1}] $value] set :index [linsert ${:index} [expr {$pos + 1}] $item] } lappend :items $item return $item } # Since we keep the list of items, we have to maintain it in case # items are deleted. :public method delete {item:object} { set pos [lsearch ${:index} $item] if {$pos == -1} {error "item $item not found in container; items: ${:index}"} set :values [lreplace ${:values} $pos $pos] set :index [lreplace ${:index} $pos $pos] next } } # Create a container for class +D+ with key +name+: SortedContainer create container3 -memberClass ::D -key name # Add a few items ? {container3 new -name victor} "::container3::member1" ? {container3 new -name stefan} "::container3::member2" ? {container3 new -name gustaf} "::container3::member3" # The method +items+ returns the items in the order of insertion (as before): ? {container3 items get} "::container3::member1 ::container3::member2 ::container3::member3" # The method +index+ returns the items in sorting order (sorted by the +name+ member): ? {container3 index} "::container3::member3 ::container3::member2 ::container3::member1" # Now we delete an item: ? {container3 delete ::container3::member2} "" # The item is as well removed from the result lists ? {container3 items get} "::container3::member1 ::container3::member3" ? {container3 index} "::container3::member3 ::container3::member1" ./nsf2.4.0/doc/variable.man.inc000644 000766 000024 00000011455 13463554607 017012 0ustar00neumannstaff000000 000000 [comment {-*- tcl -*- manpage fragment for variable method, shared by nx::Object and nx::Class}] [keywords "variable"] [comment { At the time of writing, the only material difference between property and variable is a different -configurable default. }] Defines a [term variable] for the scope of the [vset SCOPE]. The [arg spec] provides the [term variable] specification: [arg variableName][opt "[const :][arg typeSpec]"]. The [arg variableName] will be used to name the underlying Tcl variable and the getter/setter methods, if requested (see [option "-accessor"]). [arg spec] is optionally equipped with a [arg typeSpec] following a colon delimiter which specifies a [term "value checker"] for the values managed by the [term variable]. Optionally, a [emph defaultValue] can be defined. [para] If [option "-accessor"] is set explicitly, a [term variable] will provide for getter and setter methods: [list_begin definitions] [def "[arg obj] [arg variableName] [method exists]"] Returns 1 if the value store of [arg variableName] (e.g., an object variable) exists and has been given a value, returns 0 otherwise. [def "[arg obj] [arg variableName] [method set] [arg varValue]"] Sets [arg variableName] to [arg varValue]. [def "[arg obj] [arg variableName] [method get]"] Returns the current value of [arg variableName]. [def "[arg obj] [arg variableName] [method unset]"] Removes [arg variableName], if existing, underlying the property. [list_end] The option value passed along [option "-accessor"] sets the level of [term "call protection"] for the getter and setter methods: [const public], [const protected], or [const private]. By default, no getter and setter methods are created. [para] Turning on the [term switch] [option -incremental] provides a refined setter interface to the value managed by the [term variable]. First, setting [option -incremental] implies requesting [option -accessor] ([const public] by default, if not specified explicitly). Second, the managed value will be considered a valid Tcl list. A [term multiplicity] of [const 1..*] is set by default, if not specified explicitly as part of [arg spec] (see above). Third, to manage this list value element-wise ([emph incrementally]), two additional setter operations become available: [list_begin definitions] [def "[arg obj] [arg variableName] [method add] [arg element] [opt [arg index]]"] Adding [arg element] to the managed list value, at the list position given by [arg index] (by default: 0). [def "[arg obj] [arg variableName] [method delete] [opt [option -nocomplain]] [arg elementPattern]"] Removing the first occurrence of an element from the managed list value which matches [arg elementPattern]. [arg elementPattern] can contain matching characters (see [cmd "string match"]). An error will be thrown if there is no match, unless [option -nocomplain] is set. [list_end] [para] By setting [option -configurable] to [const true], the [term variable] can be accessed and modified via [method cget] and [method configure], respectively. If [const false] (the default), the interface based on [method cget] and [method configure] will not become available. In this case, and provided that [option -accessor] is set, the [term variable] can be accessed and modified via the getter/setter methods. Alternatively, the underlying Tcl variable, which is represented by the [term variable], can always be accessed and modified directly, e.g., using [method eval]. By default, [option -configurable] is [const false]. [para] The [option -trace] option causes certain slot methods to be executed whenever [const get], [const set], or [const default] operations are invoked on the [term variable]: [list_begin itemized] [item] [const set]: [arg slot] [const value=set] [arg obj] [arg variableName] [arg value] [item] [const get]: [arg slot] [const value=get] [arg obj] [arg variableName] [item] [const default]: [arg slot] [const value=default] [arg obj] [arg variableName] [list_end] [para] A [term variable] becomes implemented by a [term "slot object"] under any of the following conditions: [list_begin itemized] [item] [option -configurable] equals [const true]. [item] [option -accessor] is one of [const public], [const protected], or [const private]. [item] [option -incremental] is turned on. [item] [option -initblock] is a non-empty string. [list_end] Provided a [term "slot object"] managing the [term variable] is to be created, a custom class [arg className] from which this [term "slot object"] is to be instantiated can be set using [option -class]. The default value is [cmd ::nx::VariableSlot]. [para] Using [option -initblock], an optional Tcl [arg script] can be defined which becomes passed into the initialization procedure (see [method configure]) of the [term variable]'s [term "slot object"]. See also [sectref description "[arg initBlock] for [method create] and [method new]"]. ./nsf2.4.0/doc/require.man.inc000644 000766 000024 00000001042 12501766547 016670 0ustar00neumannstaff000000 000000 [comment {-*- tcl -*- manpage fragment for forward method, shared by nx::Object and nx::Class}] [keywords "call protection"] [call [arg [vset CMD]] [method require] [opt "[method public] | [method protected] | [method private]"] [method "[vset MODIFIER] method"] [arg methodName]] Attempts to register a method definition made available using [cmd ::nsf::method::provide] under the name [arg methodName] with [arg [vset CMD]] . The registered method is subjected to default [term "call protection"] ([const protected]), if not set explicitly. ./nsf2.4.0/doc/nxwish.1000644 000766 000024 00000016345 14274463622 015362 0ustar00neumannstaff000000 000000 '\" '\" Generated from file 'nxwish\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2014-16 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. '\" .TH "nxwish" 1 2\&.4\&.0 nxwish "Command-line interface" .\" The -*- nroff -*- definitions below are for supplemental macros used .\" in Tcl/Tk manual entries. .\" .\" .AP type name in/out ?indent? .\" Start paragraph describing an argument to a library procedure. .\" type is type of argument (int, etc.), in/out is either "in", "out", .\" or "in/out" to describe whether procedure reads or modifies arg, .\" and indent is equivalent to second arg of .IP (shouldn't ever be .\" needed; use .AS below instead) .\" .\" .AS ?type? ?name? .\" Give maximum sizes of arguments for setting tab stops. Type and .\" name are examples of largest possible arguments that will be passed .\" to .AP later. If args are omitted, default tab stops are used. .\" .\" .BS .\" Start box enclosure. From here until next .BE, everything will be .\" enclosed in one large box. .\" .\" .BE .\" End of box enclosure. .\" .\" .CS .\" Begin code excerpt. .\" .\" .CE .\" End code excerpt. .\" .\" .VS ?version? ?br? .\" Begin vertical sidebar, for use in marking newly-changed parts .\" of man pages. The first argument is ignored and used for recording .\" the version when the .VS was added, so that the sidebars can be .\" found and removed when they reach a certain age. If another argument .\" is present, then a line break is forced before starting the sidebar. .\" .\" .VE .\" End of vertical sidebar. .\" .\" .DS .\" Begin an indented unfilled display. .\" .\" .DE .\" End of indented unfilled display. .\" .\" .SO ?manpage? .\" Start of list of standard options for a Tk widget. The manpage .\" argument defines where to look up the standard options; if .\" omitted, defaults to "options". The options follow on successive .\" lines, in three columns separated by tabs. .\" .\" .SE .\" End of list of standard options for a Tk widget. .\" .\" .OP cmdName dbName dbClass .\" Start of description of a specific option. cmdName gives the .\" option's name as specified in the class command, dbName gives .\" the option's name in the option database, and dbClass gives .\" the option's class in the option database. .\" .\" .UL arg1 arg2 .\" Print arg1 underlined, then print arg2 normally. .\" .\" .QW arg1 ?arg2? .\" Print arg1 in quotes, then arg2 normally (for trailing punctuation). .\" .\" .PQ arg1 ?arg2? .\" Print an open parenthesis, arg1 in quotes, then arg2 normally .\" (for trailing punctuation) and then a closing parenthesis. .\" .\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b .\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out .\" # BS - start boxed text .\" # ^y = starting y location .\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. .\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. .\" # VS - start vertical sidebar .\" # ^Y = starting y location .\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. .\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. .\" # Special macro to handle page bottom: finish off current .\" # box/sidebar if in box/sidebar mode, then invoked standard .\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. .\" # DS - begin display .de DS .RS .nf .sp .. .\" # DE - end display .de DE .fi .RE .sp .. .\" # SO - start of list of standard options .de SO 'ie '\\$1'' .ds So \\fBoptions\\fR 'el .ds So \\fB\\$1\\fR .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. .\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\*(So manual entry for details on the standard options. .. .\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. .\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. .\" # CE - end code excerpt .de CE .fi .RE .. .\" # UL - underline word .de UL \\$1\l'|0\(ul'\\$2 .. .\" # QW - apply quotation marks to word .de QW .ie '\\*(lq'"' ``\\$1''\\$2 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\$2 .. .\" # PQ - apply parens and quotation marks to word .de PQ .ie '\\*(lq'"' (``\\$1''\\$2)\\$3 .\"" fix emacs highlighting .el (\\*(lq\\$1\\*(rq\\$2)\\$3 .. .\" # QR - quoted range .de QR .ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3 .. .\" # MT - "empty" string .de MT .QW "" .. .BS .SH NAME nxwish \- Simple windowing shell containing NSF/NX interpreter .SH SYNOPSIS \fBnxwish\fR ?\fIfileName\fR? .sp .BE .SH DESCRIPTION .TP \fBnxwish\fR ?\fIfileName\fR? \fBnxwish\fR is a shell-like application including Tcl and the NX extension as well as the Tk toolkit\&. \fBnxwish\fR creates a main window and, then, reads commands from its standard input or from \fIfileName\fR and evaluates them\&. If invoked without \fIfileName\fR, then it runs in REPL mode, reading commands from standard input\&. \fBnxwish\fR will continue processing commands until all windows have been deleted or until end-of-file is reached on standard input\&. .sp \fBnxwish\fR can be used like \fBwish\fR to make NX scripts directly invocable from the shell, by providing the following first line ("shebang") in the respective script: .CS #! /usr/bin/env nxwish .CE .IP A (more portable) alternative is: .CS #! /bin/sh # the next line restarts using nxwish \\ exec nxwish "$0" "$@" .CE .PP .SH COPYRIGHT .nf Copyright (c) 2014-16 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. .fi ./nsf2.4.0/doc/next.html000644 000766 000024 00000007547 12422512320 015607 0ustar00neumannstaff000000 000000 nx::next -

    nx::next(3) 2.0 next ""

    Name

    nx::next - Skip to the next most specific method implementation

    Description

    next ?arguments?

    This command is invoked inside a method body to call the next most specific method implementation in the list of available methods. This list of available methods is specific to the current method-call context. This context is set by the usage context of nx::next (method combination vs. method-call interception; see below). The optional arguments are the argument values to be passed into the next most specific method implementation. If omitted, the arguments of the current method call are automatically forwarded. To call the next most specific method implementation without arguments (or to suppress argument forwarding), arguments must be set to an empty string. To pass an empty string as a (single) argument value, protect it as a list. The result of a call to nx::next is the result of the next most specific method implementation. If there are no more further applicable methods, the result of nx::next will depend on its usage context: method combination or method-call interception. If nx::next is used in a method body for method combination, the result will be an empty string. If nx::next is used in the body of a filter method for method-call interception, the result will be an error.

    When executing a method call, the NX dispatch mechanism computes a list of applicable method implementations for the method name requested from a given object receiving the call; in support of method combination and method-call interception.

    For method combination, the computed list contains any object-local method implementation and any method implementations inherited by the object from the classes in its precedence list. Examples are overloading method implementations in the class hierarchy of the object, as well as from mixin classes of the object. For method-call interception, the computed list contains the applicable filter methods, again ordered by their definition order according to the precedence list of the called object.

    To retrieve the next most specific method implementation to be invoked by nx::current from the internally computed list, if any, use nx::current.

    ./nsf2.4.0/doc/TextFileStorage-xotcl.html000644 000766 000024 00000001565 12161565463 021043 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/store/TextFileStorage.xotcl

    ./library/store/TextFileStorage.xotcl ./library/store/TextFileStorage.xotcl


    Package/File Information

    No package provided/required

    Filename: ./library/store/TextFileStorage.xotcl




    Back to index page.

    ./nsf2.4.0/doc/configure.html000644 000766 000024 00000006101 12422512320 016573 0ustar00neumannstaff000000 000000 nx::configure -

    nx::configure(3) 2.0 configure ""

    Name

    nx::configure - Get and set configuration options on the object system

    Description

    configure option ?arg?

    This command sets and retrieves options for the NX object system. Legal configuration options are:

    • defaultMethodCallProtection returns the currently active call-protection level used as default for newly defined method implementations (if not specified explicitly by a method definition), if arg is not provided. If arg is set, this default call-protection level is re-set to any of the available ones: public, private, protected.

    • defaultAccessor returns the currently active call-protection level used as the default for newly defined properties (if not specified explicitly by a property definition), if arg is not provided. If arg is set, this default call-protection level is re-set to any of the following values: public, private, protected, or none. none indicates that no accessors (getter/setter methods) will be generated for newly defined properties, if not requested explicitly.

    ./nsf2.4.0/doc/current.man000644 000766 000024 00000010777 13076704513 016136 0ustar00neumannstaff000000 000000 [comment {-*- Tcl -*- nx::current manpage}] [include version.inc] [manpage_begin nx::current 3 [vset VERSION]] [copyright {2014-16 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3.0 Austria license (CC BY 3.0 AT).}] [titledesc {Return information about the method callstack}] [moddesc {NX API}] [description] [list_begin definitions] [call [cmd "current"] [opt [arg option]]] This introspection command provides information about various details, to be identified using [arg option], on the callstack. The command is invoked from a method body. If [arg option] is not provided, [cmd nx::current] will default to option [option "object"] (see below). [cmd nx::current] operates on the Tcl callstack and is aware of NX-specific callstack and stackframe details. Except for the options [option callinglevel] and [option level], calling [cmd "nx::current"] outside an NX object or method will result in an error. [arg option] can be any of the following: [list_begin itemized] [item] [option "activelevel"] returns the actual callstack level which calls into the currently executing method directly. This [option "activelevel"] might correspond the [option "callinglevel"], but this is not necessarily the case. The [option "activelevel"] also includes intermediate calls, such as [cmd nx::next] invocations. The level is reported as an absolute level number (# followed by a digit) to be directly used as the first argument to [cmd uplevel] or [cmd upvar]. [comment {[item] [option "activemixin"] ...}] [item] [option "args"] returns the list of argument values passed into the currently executing method implementation. [item] [option "calledclass"] returns the name of the class that provides the method implementation to which the intercepted method call is to be redirected (only available from within filter methods). [item] [option "calledmethod"] returns the original method name requested by intercepted method call (only available from within filter methods). [item] [option "callingclass"] returns the name of the class which provides the method implementation calling into the currently executing method. See also [option "callingobject"]. [item] [option "callinglevel"] resolves the callstack level of the originating invocation of the currently executing method implementation. Callstack levels introduced by method interception (e.g., filters) and by method combination ([cmd nx::next]) are ignored. The level is reported as an absolute level number ([const #] followed by a digit) to be directly used as the first argument to [cmd uplevel] or [cmd upvar]. See also [option "activelevel"]. If called outside NX, [const 1] is returned (which is the default for [cmd upvar] and [cmd uplevel]). [item] [option "callingobject"] returns the name of the object which is calling into the currently executing method. See also [option "callingclass"]. [item] [option "class"] returns the name of the class providing the currently executing method implementation. The returned method-providing class may be different to the class of the current object. If called from within a method implementation provided by the current object itself, an empty string is returned. [item] [option "filterreg"] returns the object (class) on which the currently executing method was registered as a filter method (only available from within filter methods). [item] [option "isnextcall"] will return 1, if the currently executing method implementation was invoked via [cmd nx::next]; 0 otherwise. [item] [option "level"] will return a number indicating the stack level of the currently executed method or script, or an empty string when executed outside an NX context (e.g., in a Tcl proc or a namespace script). The resulting value can be directly passed as [arg "level"] to [cmd "info level"]. [item] [option method] returns the name of the currently executing method. If an ensemble-method call, the name of the bottom-most ("leaf") method is returned. [item] [option "methodpath"] returns the combined name of the currently executing method (including all ensemble levels) in an ensemble-method call. Otherwise, for a regular method call, the result corresponds to the result of option [option "method"]. [item] [option "nextmethod"] returns the name of the next most specific method implementation to be called when invoking [cmd nx::next]. [item] [option "object"] gives the name of the object on which the currently executing method implementation is evaluated. [list_end] [list_end] [manpage_end] ./nsf2.4.0/doc/next.man000644 000766 000024 00000005063 13076704513 015422 0ustar00neumannstaff000000 000000 [comment {-*- Tcl -*- nx::next manpage}] [include version.inc] [manpage_begin nx::next 3 [vset VERSION]] [copyright {2014-16 Stefan Sobernig , Gustaf Neumann }] [titledesc {Skip to the next most specific method implementation}] [moddesc {NX API}] [description] [list_begin definitions] [call [cmd "next"] [opt [arg arguments]]] This command is invoked inside a method body to call the next most specific method implementation in the list of available methods. This list of available methods is specific to the current method-call context. This context is set by the usage context of [cmd nx::next] (method combination vs. method-call interception; see below). The optional [arg "arguments"] are the argument values to be passed into the next most specific method implementation. If omitted, the arguments of the current method call are automatically forwarded. To call the next most specific method implementation without arguments (or to suppress argument forwarding), [arg "arguments"] must be set to an empty string. To pass an empty string as a (single) argument value, protect it as a list. The result of a call to [cmd nx::next] is the result of the next most specific method implementation. If there are no more further applicable methods, the result of [cmd nx::next] will depend on its usage context: method combination or method-call interception. If [cmd nx::next] is used in a method body for method combination, the result will be an empty string. If [cmd nx::next] is used in the body of a filter method for method-call interception, the result will be an error. [para] When executing a method call, the NX dispatch mechanism computes a list of applicable method implementations for the method name requested from a given object receiving the call; in support of method combination and method-call interception. [para] For [emph "method combination"], the computed list contains any object-local method implementation and any method implementations inherited by the object from the classes in its precedence list. Examples are overloading method implementations in the class hierarchy of the object, as well as from mixin classes of the object. For [emph "method-call interception"], the computed list contains the applicable filter methods, again ordered by their definition order according to the precedence list of the called object. [para] To retrieve the next most specific method implementation to be invoked by [cmd nx::current] from the internally computed list, if any, use [cmd "nx::current"]. [list_end] [manpage_end] ./nsf2.4.0/doc/test-xotcl.html000644 000766 000024 00000004147 12161565463 016750 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/lib/test.xotcl

    ./library/lib/test.xotcl ./library/lib/test.xotcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./library/lib/test.xotcl

    Description: Simple regression test support.


    Class: Test

    Class: Class
    Description: Class Test is used to configure test instances, which can be configured by the following parameters:
    • cmd: the command to be executed
    • expected: the expected result
    • count: number of executions of cmd
    • pre: a command to be executed at the begin of the test (before cmd)
    • post: a command to be executed after the test (after all cmds)
    • namespace in which pre, post and cmd are evaluated; default ::
    The defined tests can be executed by Test run



    Back to index page.

    ./nsf2.4.0/doc/Serializer-xotcl.html000644 000766 000024 00000027254 13443231445 020100 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/serialize/Serializer.xotcl

    ./library/serialize/Serializer.xotcl ./library/serialize/Serializer.xotcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./library/serialize/Serializer.xotcl

    Description: This package provides the class Serializer, which can be used to generate a snapshot of the current state of the workspace in the form of XOTcl source code.
    Authors: Gustaf Neumann, Gustaf.Neumann@wu-wien.ac.at
    Date: $Date: 2007/10/05 09:06:00 $


    Class: Serializer

    Procs/Instprocs: all, deepSerialize, exportMethods, methodSerialize, serialize.

    Instprocs

    • serialize entity
      Arguments: entity: Object or Class
      Description: Serialize the specified object or class.
      Return: Object or Class with all currently defined methods, variables, invariants, filters and mixins

    Procs

    • all ?-ignoreVarsRE RE? ?-ignore obj1 obj2 ...?
      Arguments: ?-ignoreVarsRE RE?: provide regular expression; matching vars are ignored
      ?-ignore obj1 obj2 ...?: provide a list of objects to be omitted
      Description: Serialize all objects and classes that are currently defined (except the specified omissions and the current Serializer object).

      Examples:

      Serializer all -ignoreVarsRE {::b$}
      Do not serialize any instance variable named b (of any object).

      Serializer all -ignoreVarsRE {^::o1::.*text.*$|^::o2::x$}
      Do not serialize any variable of c1 whose name contains the string "text" and do not serialze the variable x of o2.

      Serializer all -ignore obj1 obj2 ... 
      do not serizalze the specified objects
      Return: script
    • deepSerialize objs ?-ignoreVarsRE RE? ?-ignore obj1 obj2 ...? ?-map list?
      Arguments: objs: Objects to be serialized
      ?-ignoreVarsRE RE?: provide regular expression; matching vars are ignored
      ?-ignore obj1 obj2 ...?: provide a list of objects to be omitted
      ?-map list?: translate object names in serialized code
      Description: Serialize object with all child objects (deep operation) except the specified omissions. For the description of ignore and igonoreVarsRE see Serizalizer all. map can be used in addition to provide pairs of old-string and new-string (like in the tcl command string map). This option can be used to regenerate the serialized object under a different object or under a different name, or to translate relative object names in the serialized code.

      Examples:

      Serializer deepSerialize ::a::b::c -map {::a::b ::x::y}
      Serialize the object c which is a child of a::b; the object will be reinitialized as object ::x::y::c, all references ::a::b will be replaced by ::x::y.

      Serializer deepSerialize ::a::b::c -map {::a::b [self]}
      The serizalized object can be reinstantiated under some current object, under which the script is evaluated.

      Serializer deepSerialize ::a::b::c -map {::a::b::c ${var}}
      The serizalized object will be reinstantiated under a name specified by the variable var in the recreation context.
      Return: script
    • methodSerialize object method prefix
      Arguments: object: object or class
      method: name of method
      prefix: either empty or 'inst' (latter for instprocs)
      Description: Serialize the specified method. In order to serialize an instproc, prefix should be 'inst'; to serialze procs, it should be empty.

      Examples:

      Serializer methodSerialize Serializer deepSerialize ""
      This command serializes the proc deepSerialize of the Class Serializer.

      Serializer methodSerialize Serializer serialize inst
      This command serializes the instproc serialize of the Class Serializer.

      Return: Script, which can be used to recreate the specified method
    • exportMethods list
      Arguments: list: list of methods of the form 'object proc|instproc methodname'
      Description: This method can be used to specify methods that should be exported in every Serializer all. The rationale behind this is that the serializer does not serialize objects from the ::xotcl:: namespace, which is used for XOTcl internals and volatile objects. It is however often useful to define methods on ::xotcl::Class or ::xotcl::Objects, which should be exported. One can export procs, instprocs, forward and instforward

      Example:

            Serializer exportMethods {
      	::xotcl::Object instproc __split_arguments
      	::xotcl::Object instproc __make_doc
      	::xotcl::Object instproc ad_proc
      	::xotcl::Class  instproc ad_instproc
      	::xotcl::Object forward  expr
            }



    Back to index page.

    ./nsf2.4.0/doc/delete.man.inc000644 000766 000024 00000002132 12501766547 016457 0ustar00neumannstaff000000 000000 [comment {-*- tcl -*- manpage fragment for delete method, shared by nx::Object and nx::Class}] [keywords "alias method"] [keywords "forwarder method"] [call [arg [vset CMD]] [method [string trim "delete [vset MODIFIER]"]] [arg feature] [arg arg]] This method serves as the equivalent to Tcl's [cmd rename] for removing structural (properties, variables) and behavioral features (methods) of the [vset SCOPE]: [def "[arg [vset CMD]] [method "delete [vset MODIFIER] property"] [arg propertyName]"] [def "[arg [vset CMD]] [method "delete [vset MODIFIER] variable"] [arg variableName]"] [def "[arg [vset CMD]] [method "delete [vset MODIFIER] method"] [arg methodName]"] Removes a property [arg propertyName], variable [arg variableName], and method [arg methodName], respectively, previously defined for the scope of the [vset SCOPE]. [para] [method "delete [vset MODIFIER] method"] can be equally used for removing regular methods (see [method "[vset MODIFIER] method"]), an [term "alias method"] (see [method "[vset MODIFIER] alias"]), and a [term "forwarder method"] (see [method "[vset MODIFIER] forward"]). ./nsf2.4.0/doc/forwardtest-xotcl.html000644 000766 000024 00000001471 12161565464 020333 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./tests/forwardtest.xotcl

    ./tests/forwardtest.xotcl ./tests/forwardtest.xotcl


    Package/File Information

    No package provided/required

    Filename: ./tests/forwardtest.xotcl




    Back to index page.

    ./nsf2.4.0/doc/secure-webserver-xotcl.html000644 000766 000024 00000002437 12161565464 021262 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/comm/secure-webserver.xotcl

    ./apps/comm/secure-webserver.xotcl ./apps/comm/secure-webserver.xotcl


    Package/File Information

    No package provided/required

    Filename: ./apps/comm/secure-webserver.xotcl

    Description: This small secure web server that provides its documents via SSL (https, port 8443) and plain http (port 8086).
    This file requires TLS. If you experice problems with versions obtained from the Web, contact gustaf.neumann@wu-wien.ac.at for a patch.



    Back to index page.

    ./nsf2.4.0/doc/xowish.man000644 000766 000024 00000002535 13723231463 015764 0ustar00neumannstaff000000 000000 [comment {-*- Tcl -*- xowish manpage}] [include version.inc] [manpage_begin xowish 1 [vset VERSION]] [copyright { 2014 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3.0 Austria license (CC BY 3.0 AT).}] [titledesc {Simple windowing shell containing NSF/XOTcl2 interpreter}] [moddesc {Command-line interface}] [description] [list_begin definitions] [call [syscmd "xowish"] [opt [arg fileName]]] [syscmd "xowish"] is a shell-like application including Tcl and the XOTcl2 as well as the Tk toolkit. [syscmd "xowish"] creates a main window and, then, reads commands from its standard input or from [arg fileName] and evaluates them. If invoked without [arg fileName], then it runs in REPL mode, reading commands from standard input. [syscmd "xowish"] will continue processing commands until all windows have been deleted or until end-of-file is reached on standard input. [para] [syscmd "xowish"] can be used like [syscmd "wish"] to make XOTcl2 scripts directly invocable from the shell, by providing the following first line ("shebang") in the respective script: [example { #! /usr/bin/env xowish }] A (more portable) alternative is: [example_begin] #! /bin/sh # the next line restarts using xowish \ exec xowish "$0" "$@" [example_end] [list_end] [manpage_end] ./nsf2.4.0/doc/property.man.inc000644 000766 000024 00000012230 13463554607 017101 0ustar00neumannstaff000000 000000 [comment {-*- tcl -*- manpage fragment for property method, shared by nx::Object and nx::Class}] [keywords "property"] [keywords "slot object"] [keywords "call protection"] [keywords "public"] [keywords "protected"] [keywords "private"] [keywords "switch"] [keywords "value checker"] [keywords "multiplicity"] [comment { At the time of writing, the only material difference between property and variable is a different -configurable default. }] Defines a [term property] for the scope of the [vset SCOPE]. The [arg spec] provides the [term property] specification as a [cmd list] holding at least one element or, maximum, two elements: [arg propertyName][opt "[const :][arg typeSpec]"] [opt [arg defaultValue]]. The [arg propertyName] is also used as to form the names of the getter/setter methods, if requested (see [option "-accessor"]). It is, optionally, equipped with a [arg typeSpec] following a colon delimiter which specifies a [term "value checker"] for the values which become assigned to the property. The second, optional element sets a [arg defaultValue] for this property. [para] If [option "-accessor"] is set, a property will provide for different getter and setter methods: [list_begin definitions] [def "[arg obj] [arg propertyName] [method exists]"] Returns 1 if the value store of [arg propertyName] (e.g., an object variable) exists and has been given a value, returns 0 otherwise. [def "[arg obj] [arg propertyName] [method set] [arg value]"] Sets the [term property] [arg propertyName] to [arg value]. [def "[arg obj] [arg propertyName] [method get]"] Returns the current value of [term property] [arg propertyName]. [def "[arg obj] [arg propertyName] [method unset]"] Removes the value store of [arg propertyName] (e.g., an object variable), if existing. [list_end] The option value passed along [option "-accessor"] sets the level of [term "call protection"] for the generated getter and setter methods: [const public], [const protected], or [const private]. By default, no getter and setter methods are created. [para] Turning on the [term switch] [option -incremental] provides a refined setter interface to the value managed by the [term property]. First, setting [option -incremental] implies requesting [option -accessor] (set to [const public] by default, if not specified explicitly). Second, the managed value will be considered a valid Tcl list. A [term multiplicity] of [const 1..*] is set by default, if not specified explicitly as part of [arg spec]. Third, to manage this list value element-wise ([emph incrementally]), two additional setter methods become available: [list_begin definitions] [def "[arg obj] [arg propertyName] [method add] [arg element] [opt [arg index]]"] Adding [arg element] to the managed list value, at the list position given by [arg index] (by default: 0). [def "[arg obj] [arg propertyName] [method delete] [opt [option -nocomplain]] [arg elementPattern]"] Removing the first occurrence of an element from the managed list value which matches [arg elementPattern]. [arg elementPattern] can contain matching characters (see [cmd "string match"]). An error will be thrown if there is no match, unless [option -nocomplain] is set. [list_end] [para] By setting [option -configurable] to [const true] (the default), the property can be accessed and modified through [method cget] and [method configure], respectively. If [const false], no configuration option will become available via [method cget] and [method configure]. [para] If neither [option -accessor] nor [option -configurable] are requested, the value managed by the [term property] will have to be accessed and modified directly. If the property manages an object variable, its value will be readable and writable using [cmd set] and [method eval]. [para] The [option -trace] option causes certain slot methods to be executed whenever [const get], [const set], or [const default] operations are invoked on the [term property]: [list_begin itemized] [item] [const set]: [arg slot] [const value=set] [arg obj] [arg propertyName] [arg value] [item] [const get]: [arg slot] [const value=get] [arg obj] [arg propertyName] [item] [const default]: [arg slot] [const value=default] [arg obj] [arg propertyName] [list_end] [para] A [term property] becomes implemented by a [term "slot object"] under any of the following conditions: [list_begin itemized] [item] [option -configurable] equals [const true] (by default). [item] [option -accessor] is one of [const public], [const protected], or [const private]. [item] [option -incremental] is turned on. [item] [arg initBlock] is a non-empty string. [list_end] Assuming default settings, every [term property] is realized by a [term "slot object"]. [para] Provided a [term "slot object"] managing the [term property] is to be created, a custom class [arg className] from which this [term "slot object"] is to be instantiated can be set using [option -class]. The default value is [cmd ::nx::VariableSlot]. [para] The last argument [arg initBlock] accepts an optional Tcl script which is passed into the initialization procedure (see [method configure]) of the [term property]'s [term "slot object"]. See also [sectref description "[arg initBlock] for [method create] and [method new]"]. ./nsf2.4.0/doc/changeXOTclVersion-xotcl.html000644 000766 000024 00000001572 12161565463 021475 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/lib/changeXOTclVersion.xotcl

    ./library/lib/changeXOTclVersion.xotcl ./library/lib/changeXOTclVersion.xotcl


    Package/File Information

    No package provided/required

    Filename: ./library/lib/changeXOTclVersion.xotcl




    Back to index page.

    ./nsf2.4.0/doc/webserver-xotcl.html000644 000766 000024 00000010304 13532210311 017743 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/comm/webserver.xotcl

    ./apps/comm/webserver.xotcl ./apps/comm/webserver.xotcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./apps/comm/webserver.xotcl

    Description: This small demo program starts two different webservers:
    • Firstly, it provides a sample web server that povides the documents in ../../src/doc (or the files specified with -root) at port 8086 (or at the port specified via the -port option) as unprotected resources.

    • Secondly, it starts a second webserver with basic access control (it accepts test/test as user/password) on port 9096 (or on the port specified via -protected-port). If it receives a request for an resource named "exit", it terminates. For all other requests it returns actual information about the user and the issued request.
    To see, how it works, contact it e.g. from netscape.


    Class: SpecializedWorker

    Class: Class
    Procs/Instprocs: respond.
    Description: Specialized worker that can be passed to any webserver

    Instprocs

    • respond
      Description: This method handles all responses from the webserver to the client. We implement here "exit", and we return the information about the actual request and user in HTML format for all other requests.

      This method is an example, how to access on the server side request specific information.


    Object: h1

    Class: Httpd
    Description: unprotected web server


    Object: h2

    Class: Httpd
    Description: Web server with basic authentication using the specialized worker



    Back to index page.

    ./nsf2.4.0/doc/next-migration.html000644 000766 000024 00001246403 14274463622 017614 0ustar00neumannstaff000000 000000 Migration Guide for the Next Scripting Language
    Abstract

    This document describes the differences between the Next Scripting Language Framework and XOTcl 1. In particular, it presents a migration guide from XOTcl 1 to NX, and presents potential incompatibilities between XOTcl 1 and XOTcl 2.

    The Next Scripting Language (NX) is a successor of XOTcl 1 and is based on 10 years of experience with XOTcl in projects containing several hundred thousand lines of code. While XOTcl was the first language designed to provide language support for design patterns, the focus of the Next Scripting Framework and NX are on combining this with Language Oriented Programming. In many respects, NX was designed to ease the learning of the language by novices (by using a more mainstream terminology, higher orthogonality of the methods, less predefined methods), to improve maintainability (remove sources of common errors) and to encourage developer to write better structured programs (to provide interfaces) especially for large projects, where many developers are involved.

    The Next Scripting Language is based on the Next Scripting Framework which was developed based on the notion of language oriented programming. The Next Scripting Frameworks provides C-level support for defining and hosting multiple object systems in a single Tcl interpreter. The whole definition of NX is fully scripted (e.g. defined in nx.tcl). The Next Scripting Framework is shipped with three language definitions, containing NX and XOTcl 2. Most of the existing XOTcl 1 programs can be used without modification in the Next Scripting Framework by using XOTcl 2. The Next Scripting Framework requires Tcl 8.5 or newer.

    Although NX is fully scripted (as well as XOTcl 2), our benchmarks show that scripts based on NX are often 2 or 4 times faster than the counterparts in XOTcl 1. But speed was not the primary focus on the Next Scripting Environment: The goal was primarily to find ways to repackage the power of XOTcl in an easy to learn environment, highly orthogonal environment, which is better suited for large projects, trying to reduce maintenance costs.

    We expect that many users will find it attractive to upgrade from XOTcl 1 to XOTcl 2, and some other users will upgrade to NX. This document focuses mainly on the differences between XOTcl 1 and NX, but addresses as well potential incompatibilities between XOTcl 1 and XOTcl 2. For an introduction to NX, please consult the NX tutorial.

    1. Differences Between XOTcl and NX

    The Next Scripting Framework supports Language Oriented Programming by providing means to define potentially multiple object systems with different naming and functionality in a single interpreter. This makes the Next Scripting Framework a powerful instrument for defining multiple languages such as e.g. domain specific languages. This focus differs from XOTcl 1.

    Technically, the language framework approach means that the languages implemented by the Next Scripting Framework (most prominently XOTcl 2 and NX) are typically fully scripted and can be loaded via the usual Tcl package require mechanism.

    Some of the new features below are provided by the Next Scripting Framework, some are implemented via the script files for XOTcl 2 and NX.

    1.1. Features of NX

    In general, the Next Scripting Language (NX) differs from XOTcl in the following respects:

    1. Stronger Encapsulation: The Next Scripting Language favors a stronger form of encapsulation than XOTcl. Calling the own methods or accessing the own instance variables is typographically easier and computationally faster than these operations on other objects. This behavior is achieved via resolvers, which make some methods necessary in XOTcl 1 obsolete in NX (especially for importing instance variables). The encapsulation of NX is stronger than in XOTcl but still weak compared to languages like C++; a developer can still access other objects' variables via some idioms, but NX makes accesses to other objects' variables explicit. The requiredness to make these accesses explicit should encourage developer to implement well defined interfaces to provide access to instance variables.

    2. Additional Forms of Method Definition and Reuse: The Next Scripting Language provides much more orthogonal means to define, reuse and introspect scripted and C-implemented methods.

      1. It is possible to use NX alias to register methods under arbitrary names for arbitrary objects or classes.

      2. NX provides means for method protection (method modifiers public, protected, and private). Therefore, developers have to define explicitly public interfaces in order to use methods from other objects.

      3. One can invoke in NX fully qualified methods to invoke methods outside the precedence path.

      4. One can define in NX hierarchical method names (similar to commands and subcommands, called method ensembles) in a convenient way to provide extensible, hierarchical naming of methods.

      5. One can use in NX the same interface to query (introspect) C-implemented and scripted methods/commands.

    3. Orthogonal Parameterization: The Next Scripting Language provides an orthogonal framework for parameterization of methods and objects.

      1. In NX, the same argument parser is used for

        • Scripted Methods

        • C-implemented methods and Tcl commands

        • Object Parametrization

      2. While XOTcl 1 provided only value-checkers for non-positional arguments for methods, the Next Scripting Framework provides the same value checkers for positional and non-positional arguments of methods, as well as for positional and non-positional configure parameters (-parameter in XOTcl 1).

      3. While XOTcl 1 supported only non-positional arguments at the begin of the argument list, these can be used now at arbitrary positions.

    4. Value Checking:

      1. The Next Scripting Language supports checking of the input parameters and the return values of scripted and C-implemented methods and commands.

      2. NX provides a set of predefined checkers (like e.g. integer, boolean, object, …) which can be extended by the applications.

      3. Value Checking can be used for single and multi-valued parameters. One can e.g. define a list of integers with at least one entry by the parameter specification integer,1..n.

      4. Value Checking can be turned on/off globally or on the method/command level.

    5. Scripted Init Blocks: The Next Scripting Language provides scripted init blocks for objects and classes (replacement for the dangerous dash "-" mechanism in XOTcl that allows one to set variables and invoke methods upon object creation).

    6. More Conventional Naming for Predefined Methods: The naming of the methods in the Next Scripting Language is much more in line with the mainstream naming conventions in OO languages. While for example XOTcl uses proc and instproc for object specific and inheritable methods, NX uses simply method.

    7. Profiling Support: The Next Scripting Language provides now two forms of profiling

      • Profiling via a DTrace provider (examples are e.g. in the dtrace subdirectory of the source tree)

      • Significantly improved built-in profiling (results can be processed in Tcl).

    8. Significantly Improved Test Suite: The regression test suite of Next Scripting framework contain now more than 5.000 tests, and order of magnitude more than in XOTcl 1.6

    9. Much Smaller Interface: The Next Scripting Language has a much smaller interface (i.e. provides less predefined methods) than XOTcl (see Table 1), although the expressiveness was increased in NX.

    Table 1. Comparison of the Number of Predefined Methods in NX and XOTcl
    NX XOTcl

    Total

    45

    124

    Methods for Objects

    14

    51

    Methods for Classes

    9

    24

    Info-methods for Objects

    11

    25

    Info-methods for Classes

    11

    24

    This comparison list compares mostly XOTcl 1 with NX, some features are also available in XOTcl 2 (2a, 2c 2d, 3, 4).

    1.2. NX and XOTcl Scripts

    Below is a small, introductory example showing an implementation of a class Stack in NX and XOTcl. The purpose of this first example is just a quick overview. We will go into much more detailed comparison in the next sections.

    NX supports a block syntax, where the methods are defined during the creation of the class. The XOTcl syntax is slightly more redundant, since every definition of a method is a single top-level command starting with the class name (also NX supports the style used in XOTcl). In NX, all methods are per default protected (XOTcl does not support protection). In NX methods are defined in the definition of the class via :method or :public method. In XOTcl methods are defined via the instproc method.

    Another difference is the notation to refer to instance variables. In NX, instance variable are named with a single colon in the front. In XOTcl, instance variables are imported using instvar.

    Stack example in NX Stack example in XOTcl
    Class create Stack {
    
       #
       # Stack of Things
       #
    
       :variable things ""
    
       :public method push {thing} {
          set :things [linsert ${:things} 0 $thing]
          return $thing
       }
    
       :public method pop {} {
          set top [lindex ${:things} 0]
          set :things [lrange ${:things} 1 end]
          return $top
       }
    }
    #
    # Stack of Things
    #
    
    Class Stack
    
    Stack instproc init {} {
       my instvar things
       set things ""
    }
    
    Stack instproc push {thing} {
       my instvar things
       set things [linsert $things 0 $thing]
       return $thing
    }
    
    Stack instproc pop {} {
       my instvar things
       set top [lindex $things 0]
       set things [lrange $things 1 end]
    }

    1.3. Using XOTcl 2.0 and the Next Scripting Language in a Single Interpreter

    In general, the Next Scripting Framework supports multiple object systems concurrently. Effectively, every object system has different base classes for creating objects and classes. Therefore, these object systems can have different interfaces and names of built-in methods. Currently, the Next Scripting Framework is packaged with three object systems:

    • NX

    • XOTcl 2.0

    • TclCool

    XOTcl 2 is highly compatible with XOTcl 1, the language NX is described below in more details, the language TclCool was introduced in Tip#279 and serves primarily an example of a small OO language.

    A single Tcl interpreter can host multiple Next Scripting Object Systems at the same time. This fact makes migration from XOTcl to NX easier. The following example script shows to use XOTcl and NX in a single script:

    Using Multiple Object Systems in a single Script
    namespace eval mypackage {
    
      package require XOTcl 2.0
    
      # Define a class with a public method "foo" using XOTcl
      xotcl::Class C1
      C1 instproc foo {} {puts "hello world"}
    
      package require nx
    
      # Define a class with a public method "foo" using NX
      nx::Class create C2 {
        :public method foo {} {puts "hello world"}
      }
    }

    One could certainly create object or classes from the different object systems via fully qualified names (e.g. using e.g. ::xotcl::Class or ::nx::Class), but for migration for systems without explicit namespaces switching between the object systems eases migration. "Switching" between XOTcl and NX effectively means the load some packages (if needed) and to import either the base classes (Object and Class) of XOTcl or NX into the current namespace.

    2. XOTcl Idioms in the Next Scripting Language

    The following sections are intended for reader familiar with XOTcl and show, how certain language Idioms of XOTcl can be expressed in NX. In some cases, multiple possible realizations are listed

    2.1. Defining Objects and Classes

    When creating objects or classes, one should use the method create explicitly. In XOTcl, a default unknown method handler was provided for classes, which create for every unknown method invocation an object/class with the name of the invoked method. This technique was convenient, but as well dangerous, since typos in method names lead easily to unexpected behavior. This default unknown method handler is not provided in NX (but can certainly be provided as a one-liner in NX by the application).

    XOTcl Next Scripting Language
    Class ClassName
    Class create ClassName
    Object ObjectName
    Object create ObjectName

    2.2. Defining Methods

    In general, both XOTcl and NX support methods on the object level (per-object methods, i.e. methods only applicable to a single object) and on the class level (methods inherited to instances of the classes). While the naming in XOTcl tried to follow closely the Tcl tradition (using the term proc for functions/methods), NX uses the term method for defining scripted methods.

    XOTcl uses the prefix inst to denote that methods are provided for instances, calling therefore scripted methods for instances instproc. This is certainly an unusual term. The approach with the name prefix has the disadvantage, that for every different kind of method, two names have to be provided (e.g. proc and instproc, forward and instforward).

    NX on the contrary uses the same term for defining instance method or object-specific methods. When the term (e.g. method) is used on a class, the method will be an instance method (i.e. applicable to the instances of the class). When the term is used on an object with the modifier object, an object-specific method is defined. This way one can define the same way object specific methods on an object as well as on a class.

    Furthermore, both XOTcl and NX distinguish between scripted methods (section 3.2.1) and C-defined methods (section 3.2.2). Section 3.2.3 introduces method protection, which is only supported by NX.

    2.2.1. Scripted Methods Defined in the Init-block of a Class/Object or with Separate Calls

    The following examples show the definition of a class and its methods in the init-block of a class (NX only), and the definition of methods via separate top-level calls (XOTcl and NX).

    XOTcl Next Scripting Language
    # Define instance method 'foo' and object
    # method 'bar' for a Class 'C' with separate
    # top-level commands
    
    Class C
    C instproc foo args {...}
    C proc bar args {...}
    # Define instance method and object method
    # in the init-block of a class
    
    Class create C {
      :method foo args {...}
      :object method bar args {...}
    }
    # Define instance method and object method
    # with separate commands
    
    Class create C
    C method foo args {...}
    C object method bar args {...}
    # Define object-specific method foo
    # for an object 'o' with separate commands
    
    Object o
    o set x 1
    o proc foo args {...}
    # Define object method and set
    # instance variable in the init-block of
    # an object
    
    Object create o {
      set :x 1
      :object method foo args {...}
    }
    # Define object method and set
    # instance variable with separate
    # commands
    
    Object create o
    o eval {set :x 1}
    o object method foo args {...}

    2.2.2. Different Kinds of Methods

    This section describes various kinds of methods. The different kinds of methods are defined via different method-defining methods, which are summarized in the following table for XOTcl and NX.

    XOTcl Next Scripting Language
    # Methods for defining methods:
    #
    #     proc
    #     instproc
    #     forward
    #     instforward
    #     parametercmd
    #     instparametercmd
    #
    # All these methods return empty.
    # Methods for defining methods:
    #
    #     alias
    #     forward
    #     method
    #
    # All these methods return method-handles.

    In addition to scripted methods (previous section) XOTcl supports forwarder (called forward and instforward) and accessor functions to variables (called parametercmd and instparametercmd). The accessor functions are used normally internally when object-specific parameters are defined (see Section 3.4).

    In NX forwarders are called forward. NX does not provide a public available method to define variable accessors like parametercmd in XOTcl, but use internally the Next Scripting Framework primitive nsf::method::setter when appropriate.

    XOTcl Next Scripting Language
    Class C
    C instforward f1 ...
    C forward f2 ...
    
    Object o
    o forward f3 ...
    # Define forwarder
    
    Class create C {
      :forward f1 ...
      :object forward f2 ...
    }
    
    Object create o {
      :object forward f3 ...
    }
    # Define setter and getter methods in XOTcl.
    #
    # XOTcl provides methods for these.
    
    Class C
    C instparametercmd p1
    C parametercmd p2
    
    Object o
    o parametercmd p3
    # Define setter and getter methods in NX.
    #
    # NX does not provide own methods, but uses
    # the low-level framework commands, since
    # application developer will only
    # need it in rare cases.
    
    Class create C
    ::nsf::method::setter C p1
    ::nsf::method::setter C -per-object p2
    
    Object create o
    ::nsf::method::setter o p3

    NX supports in contrary to XOTcl the method alias which can be used to register arbitrary Tcl commands or methods for an object or class under a provided method name. Aliases can be used to reuse a certain implementation in e.g. different object systems under potentially different names. In some respects aliases are similar to forwarders, but they do not involve forwarding overhead.

    XOTcl Next Scripting Language
    # Method "alias" not available
    # Define method aliases
    # (to scripted or non-scripted methods)
    
    Class create C {
      :alias a1 ...
      :object alias a2 ...
    }
    
    Object create o {
      :object alias a3 ...
    }

    2.2.3. Method Modifiers and Method Protection

    NX supports four method modifiers object, public, protected and private. All method modifiers can be written in front of every method defining command. The method modifier object is used to denote object-specific methods (see above). The concept of method protection is new in NX.

    XOTcl Next Scripting Language
    # Method modifiers
    #
    #   "object",
    #   "public",
    #   "protected", and
    #   "private"
    #
    # are not available
    # Method modifiers
    #
    #   "object",
    #   "public",
    #   "protected"
    #
    # are applicable for all kinds of
    # method defining methods:
    #
    #    method, forward, alias
    #
    # The modifier "private" is available for
    #
    #    method, forward, alias
    #
    Class create C {
      :/method-definition-method/ ...
      :public /method-definition-method/ ...
      :protected /method-definition-method/ ...
      :private /method-definition-method/ ...
      :object /method-definition-method/ ...
      :public object /method-definition-method/ ...
      :protected object /method-definition-method/ ...
      :private object /method-definition-method/ ...
    }

    XOTcl does not provide method protection. In NX, all methods are defined per default as protected. This default can be changed by the application developer in various ways. The command ::nx::configure defaultMethodCallProtection true|false can be used to set the default call protection for scripted methods, forwarder and aliases. The defaults can be overwritten also on a class level.

    NX provides means for method hiding via the method modifier private. Hidden methods can be invoked only via the -local flag, which means: "call the specified method defined in the same class/object as the currently executing method".

    XOTcl Next Scripting Language
    # XOTcl provides no means for
    # method hiding
    # Hiding of methods via "private"
    #
    nx::Class create Base {
      :private method baz {a b} {expr {$a + $b}}
      :public method foo {a b} {: -local baz $a $b}
    }
    
    nx::Class create Sub -superclass Base {
      :public method bar {a b} {: -local baz $a $b}
      :private method baz {a b} {expr {$a * $b}}
    
      :create s1
    }
    
    s1 foo 3 4  ;# returns 7
    s1 bar 3 4  ;# returns 12
    s1 baz 3 4  ;# unable to dispatch method 'baz'

    2.2.4. Method Deletion

    NX provides an explicit delete method for the deletion of methods.

    XOTcl Next Scripting Language
    # XOTcl provides only method deletion with
    # the equivalent of Tcl's "proc foo {} {}"
    /cls/ instproc foo {} {}
    /obj/ proc foo {} {}
    # Deletion of Methods
    #
    /cls/ delete method /name/
    /obj/ delete object method /name/

    2.3. Resolvers

    The Next Scripting Framework defines Tcl resolvers for method and variable names to implement object specific behavior. Within the bodies of scripted methods these resolvers treat variable and function names starting with a colon : specially. In short, a colon-prefixed variable name refers to an instance variable, and a colon-prefixed function name refers to a method. The sub-sections below provide detailed examples.

    Note that the resolvers of the Next Scripting Framework can be used in the XOTcl 2.* environment as well.

    2.3.1. Invoking Methods

    In XOTcl, a method of the same object can be invoked via my, or in general via using the name of the object in front of the method name.

    In NX, the own methods are called via the method name prefixed with a single colon. The invocation of the methods of other objects is the same in NX and XOTcl.

    XOTcl Next Scripting Language
    Class C
    C instproc foo args {...}
    C instproc bar args {
      my foo 1 2 3 ;# invoke own method
      o baz        ;# invoke other object's method
    }
    Object o
    o proc baz {} {...}
    Class create C {
      :method foo args {...}
      :method bar args {
         :foo 1 2 3 ;# invoke own method
         o baz      ;# invoke other object's method
      }
    }
    Object create o {
      :public object method baz {} {...}
    }

    2.3.2. Accessing Own Instance Variables from Method Bodies

    In general, the Next Scripting Language favors the access to an objects’s own instance variables over variable accesses of other objects. This means that in NX it is syntactically easier to access the own instance variables. On the contrary, in XOTcl, the variable access to own and other variables are fully symmetric.

    In XOTcl, the following approaches are used to access instance variables:

    • Import instance variables via instvar and access variables via $varName

    • Set or get instance variables via my set varName ?value? or other variable accessing methods registered on xotcl::Object such as append, lappend, incr, etc.

    • Register same-named accessor functions and set/get values of instance variables via my varName ?value?

    In NX, the favored approach to access instance variables is to use the name resolvers, although it is as well possible to import variables via nx::var import or to check for the existence of instance variables via nx::var exists.

    The following examples summary the use cases for accessing the own and other instance variables.

    XOTcl Next Scripting Language
    Class C
    C instproc foo args {
      # Method scoped variable a
      set a 1
      # Instance variable b
      my instvar b
      set b 2
      # Global variable/namespaced variable c
      set ::c 3
    }
    Class create C {
      :method foo args {...}
        # Method scoped variable a
        set a 1
        # Instance variable b
        set :b 2
        # Global variable/namespaced variable c
        set ::c 3
      }
    }
    ... instproc ... {
       my set /varName/ ?value?
    }
    # Set own instance variable to a value via
    # resolver (preferred and fastest way)
    
    ... method ... {
       set :/newVar/ ?value?
    }
    ... instproc ... {
       my instvar /varName/
       set /varName/ ?value?
    }
    # Set own instance variable via
    # variable import
    
    ... method ... {
       ::nx::var import [self] /varName/
       set /varName/ ?value?
    }
    ... instproc ... {
       set /varName/ [my set /otherVar/]
    }
    # Read own instance variable
    
    ... method ... {
       set /varName/ [set :/otherVar/]
    }
    ... method ... {
       set /newVar/ ${:/otherVar/}
    }
    ... instproc ... {
       my exists /varName/
    }
    # Test existence of own instance variable
    
    ... method ... {
       info :/varName/
    }
     ... method ... {
       ::nx::var exists [self] /varName/
    }

    2.3.3. Accessing Instance Variables of other Objects

    XOTcl Next Scripting Language
    /obj/ set /varName/ ?value?
    # Set instance variable of object obj to a
    # value via resolver
    # (preferred way: define property on obj)
    
    /obj/ eval [list set :/varName/ ?value?]
    set /varName/ [/obj/ set /otherVar/]
    # Read instance variable of object obj
    # via resolver
    
    set /varName/ [/obj/ eval {set :/otherVar/}]
    ... instproc ... {
       /obj/ instvar /varName/
       set /varName/ ?value?
    }
    # Read instance variable of object /obj/
    # via import
    
    ... method ... {
       ::nx::var import /obj/ /varName/
       set /varName/ ?value?
    }
    /obj/ exists varName
    # Test existence of instance variable of
    # object obj
    
    /obj/ eval {info exists :/varName/}
    ::nx::var exists /obj/ /varName/

    2.4. Parameters

    While XOTcl 1 had very limited forms of parameters, XOTcl 2 and NX provide a generalized and highly orthogonal parameter machinery handling various kinds of value constraints (also called value checkers). Parameters are used to specify,

    • how objects and classes are initialized (we call these parameter types Configure Parameters), and

    • what values can be passed to methods (we call these Method Parameters).

    Furthermore, parameters might be positional or non-positional, they might be optional or required, they might have a defined multiplicity, and value-types, they might be introspected, etc. The Next Scripting Framework provide a unified, C-implemented infrastructure to handle both, object and method parameters in the same way with a high degree of orthogonality.

    Configuration parameters were specified in XOTcl 1 primarily via the method parameter in a rather limited way, XOTcl 1 only supported non-positional parameters in front of positional ones, supported no value constraints for positional parameters, provided no distinction between optional and required, and did not support multiplicity.

    Furthermore, the Next Scripting Framework provides optionally Return Value Checking based on the same mechanism to check whether some methods return always the values as specified.

    2.4.1. Parameters for Configuring Objects: Variables and Properties

    Configure parameters are used for specifying values for configuring objects when they are created (i.e. how instance variables are initialized, what parameters can be passed in for initialization, what default values are used, etc.). Such configuration parameters are supported in XOTcl primarily via the method parameter, which is used in XOTcl to define multiple parameters via a list of parameter specifications.

    Since the term "parameter" is underspecified, NX uses a more differentiated terminology. NX distinguishes between configurable instance variables (also called properties) and non-configurable instance variables (called variables), which might have as well e.g. default values. The values of configurable properties can be queried at run time via cget, and their values can be altered via configure. When the value of a configure parameter is provided or changed, the value checkers from the variable definition are used to ensure, the value is permissible (i.e. it is for example an integer value). The sum of all configurable object parameters are called configure parameters. To define a define a configurable variable, NX uses the method property, for non-configurable variables, the method variable is used.

    Optionally, one can define in NX, that a property or a variable should have a public, protected or private accessor. Such an accessor is a method with the same name as the variable. In XOTcl, every parameter defined as well automatically a same-named accessor method, leading to potential name conflicts with other method names.

    In the examples below we show the definition of non-configurable instance variables using variable and property respectively.

    XOTcl Next Scripting Language
    # Define class "Foo" with instance
    # variables "x" and "y" initialized
    # on instance creation. The initialization
    # has to be performed in the constructor.
    
    Class Foo
    Foo instproc init args {
       instvar x y
       set x 1
       set y 2
    }
    
    # Create instance of the class Foo
    Foo f1
    
    # Object f1 has instance variables
    # x == 1 and y == 2
    # Define class "Foo" with instance variables
    # "x" and "y" initialized on instance creation.
    # The method "variable" is similar in syntax
    # to Tcl's "variable" command. During
    # instance creation, the variable
    # definitions are used for the
    # initialization of the variables of the object.
    
    Class create Foo {
      :variable x 1
      :variable y 2
    }
    
    # Create instance of the class Foo
    Foo create f1
    
    # Object f1 has instance variables
    # x == 1 and y == 2

    While XOTcl follows a procedural way to initialize variables via the constructor init, NX follows a more declarative approach. Often, classes have superclasses, which often want to provide their own instance variables and default values. The declarative approach from NX solves this via inheritance, while a procedural approach via assign statements in the constructor requires explicit constructor calls, which are often error-prone. Certainly, when a user prefers to assign initial values to instance variables via explicit assign operations in constructors, this is as well possible in NX.

    NX uses the same mechanism to define class variables or object variables.

    XOTcl Next Scripting Language
    # No syntactic support for creating
    # class variables
    # Define an object variable "V" with value 100 and
    # an instance variable "x". "V" is defined for the
    # class object Foo, "x" is defined in the
    # instances of the class. "object variable" works
    # similar to "object method".
    
    Class create Foo {
      :object variable V 100
      :variable x 1
    }

    In the next step, we define configurable instance variables which we call properties in NX.

    XOTcl uses the method parameter is a shortcut for creating multiple configurable variables with automatically created accessors (methods for reading and writing of the variables). In NX, the preferred way to create configurable variables is to use the method property. The method property in NX is similar to variable, but makes the variables configurable, which means that

    1. one can specify the property as a non-positional parameter upon creation of the object,

    2. one can query the value via the method cget, and

    3. one can modify the value of the underlying variable via the method configure.

    XOTcl Next Scripting Language
    # Parameters specified as a list
    # (short form); parameter
    # "a" has no default, "b" has default "1"
    
    Class Foo -parameter {a {b 1} {c "[info tclversion]"}}
    
    # Create instance of the class Foo
    Foo f1 -a 0
    
    # Object f1 has instance variables
    # a == 0 and b == 1
    
    # XOTcl registers automatically accessors
    # for the parameters. Use the accessor
    # "b" to output the value of variable "b"
    puts [f1 b]
    
    # Use the setter to alter value of
    # instance variable "b"
    f1 b 100
    
    # Return the substituted value of
    # parameter "c", something like 8.7.
    # XOTcl substitutes always when it sees
    # square brackets or dollar signs.
    f1 c
    
    # Define property "a" and "b". The
    # property "a" has no default, "b" has
    # default value "1"
    
    Class create Foo {
      :property a
      :property {b 1}
      :property {c "[info tclversion]"}
      :property {d:substdefault "[info tclversion]"}
    }
    
    # Create instance of the class Foo
    Foo create f1 -a 0
    
    # Object f1 has instance variables
    # a == 0 and b == 1
    
    # Use the method "cget" to query the value
    # of a configuration parameter
    puts [f1 cget -b]
    
    # Use the method "configure" to alter the
    # value of instance variable "b"
    f1 configure -b 100
    
    # Return the (non-substituted) value of
    # parameter "c", and the substituted value
    # of parameter "d"
    f1 cget -c
    f1 cget -d
    

    In general, NX allows one to create variables and properties with and without accessor methods. The created accessor methods might be public, protected or public. When the value none is provided to -accessor, no accessor will be created. This is actually the default in NX. In order to change the default behavior in NX, one can use ::nx::configure defaultAccessor none|public|protected|private.

    XOTcl Next Scripting Language
    # "parameter" creates always accessor
    # methods, accessor methods are
    # always public, no "cget" is available.
    
    Class create Foo -parameter {a {b 1}}
    
    # Use the accessor method to query
    # the value of a configuration parameter
    puts [f1 b]
    
    # Use the accessor method to set the
    # value of instance variable "a"
    f1 a 100
    
    # Use the accessor method to unset the
    # value of instance variable "a" n.a. via
    # accessor
    # Define property "a" and "b". The
    # property "a" has no default, "b" has
    # default value "1"
    
    Class create Foo {
      :variable -accessor public a
      :property -accessor public {b 1}
    }
    
    # Use the accessor method to query
    # the value of a configuration parameter
    puts [f1 b get]
    
    # Use the accessor method to set the
    # value of instance variable "a"
    f1 a set 100
    
    # Use the accessor method to unset the
    # value of instance variable "a"
    f1 a unset

    Similar to variable, properties can be defined in NX on the class and on the object level.

    XOTcl Next Scripting Language
    # XOTcl provides no means to define
    # configurable variables at the object
    # level
    # Define class with a property for the class object
    # named "cp". This is similar to "static variables"
    # in some other object-oriented programming
    # languages.
    
    Class create Foo {
      ...
      :object property cp 101
    }
    
    # Define object property "op"
    
    Object create o {
      :object property op 102
    }

    NX supports value constraints (value-checkers) for object and method parameters in an orthogonal manner. NX provides a predefined set of value checkers, which can be extended by the application developer. In NX, the value checking is optional. This means that it is possible to develop e.g. which a large amount of value-checking and deploy the script with value checking turned off, if the script is highly performance sensitive.

    XOTcl Next Scripting Language
    # No value constraints for
    # parameter available
    # Predefined value constraints:
    #    object, class, alnum, alpha, ascii, boolean,
    #    control, digit, double, false, graph, integer,
    #    lower, parameter, print, punct, space, true,
    #    upper, wordchar, xdigit
    #
    # User defined value constraints are possible.
    # All parameter value checkers can be turned on
    # and off at run time.
    #
    # Define a required boolean property "a"
    # and an integer property "b" with a default.
    # The first definition uses "properties",
    # the second definition uses multiple
    # "property" statements.
    
    Class create Foo -properties {
       a:boolean
       {b:integer 1}
    }
    Class create Foo {
       :property a:boolean
       :property {b:integer 1}
    }

    In XOTcl all configure parameters were optional. Required parameters have to be passed to the constructor of the object.

    NX allows one to define optional and required configure parameters (as well as method parameters). Therefore, configure parameters can be used as the single mechanism to parameterize objects. It is in NX not necessary (and per default not possible) to pass arguments to the constructor.

    XOTcl Next Scripting Language
    # Required parameter not available
    # Required parameter:
    # Define a required property "a" and a
    # required boolean property "b"
    
    Class create Foo -properties {
       a:required
       b:boolean,required
    }
    Class create Foo {
       :property a:required
       :property b:boolean,required
    }

    NX supports in contrary to XOTcl to define the multiplicity of values per parameter. In NX, one can specify that a parameter can accept the value "" (empty) in addition to e.g. an integer, or one can specify that the value is an empty or nonempty list of values via the multiplicity. For every specified value, the value checkers are applied.

    XOTcl Next Scripting Language
    # Multiplicity for parameter
    # not available
    # Parameter with multiplicity
    #   ints is a list of integers, with default
    #   objs is a nonempty list of objects
    #   obj is a single object, maybe empty
    
    Class create Foo -properties {
      {ints:integer,0..n ""}
       objs:object,1..n
       obj:object,0..1
    }
    Class create Foo {
      :property {ints:integer,0..n ""}
      :property objs:object,1..n
      :property obj:object,0..1
    }

    For the implementation of variables and properties, NX uses slot objects, which are an extension to the -slots already available in XOTcl. While very for every property in NX, a slot object is created, for performance reasons, not every variable has a slot associated.

    When a property is created, NX does actually three things:

    1. Create a slot object, which can be specified in more detail using the init-block of the slot object

    2. Create a parameter definition for the initialization of the object (usable via a non-positional parameter during object creation), and

    3. register optionally an accessor function (setter), for which the usual protection levels (public, protected or private) can be used.

    XOTcl Next Scripting Language
    # Define parameters via slots
    
    Class Foo -slots {
       Attribute a
       Attribute b -default 1
    }
    
    # Create instance of the class Foo
    # and provide a value for instance
    # variable "a"
    Foo f1 -a 0
    
    # Object f1 has a == 0 and b == 1
    # Configurable parameters specified via the
    # method "property" (supports method
    # modifiers and scripted configuration;
    # see below)
    
    Class create Foo {
       :property a
       :property {b 1}
    }
    
    # Create instance of the class Foo and
    # provide a value for instance variable "a"
    Foo create f1 -a 0
    
    # Object f1 has a == 0 and b == 1

    Since the slots are objects, the slot objects can be configured and parameterized like every other object in NX. Slot objects can be provided with a scripted initialization as well. We show first the definition of properties similar to the functionality provided as well by XOTcl and show afterwards how to use value constraints, optional parameters, etc. in NX.

    XOTcl Next Scripting Language
    # Define parameter with an
    # attribute-specific type checker
    
    Class Person -slots {
      Attribute create sex -type "sex" {
        my proc type=sex {name value} {
          switch -glob $value {
            m* {return m}
            f* {return f}
            default {
              error "expected sex but got $value"
            }
          }
        }
      }
    }
    # Configure parameter with scripted
    # definition (init-block), defining a
    # property specific type checker
    
    Class create Person {
        :property -accessor public sex:sex,convert {
    
          # define a converter to standardize representation
          :object method type=sex {name value} {
            switch -glob $value {
              m* {return m}
              f* {return f}
              default {error "expected sex but got $value"}
            }
          }
    
        }
    }

    The parameters provided by a class for the initialization of instances can be introspected via querying the parameters of the method create: /cls/ info lookup parameters create (see [info_configure_parameter]).

    2.4.2. Delete Variable Handlers

    XOTcl Next Scripting Language
    # No syntactic support for deleting
    # variable handlers
    # Like deletion of Methods:
    # Delete on the object, where the
    # variable handler is defined.
    
    /cls/ delete property /name/
    /obj/ delete object property /name/
    
    /cls/ delete variable /name/
    /obj/ delete object variable /name/

    2.4.3. Method Parameters

    Method parameters are used to specify the interface of a single method (what kind of values may be passed to a method, what default values are provided etc.). The method parameters specifications in XOTcl 1 were limited and allowed only value constraints for non-positional arguments.

    NX and XOTcl 2 provide value constraints for all kind of method parameters. While XOTcl 1 required non-positional arguments to be listed in front of positional arguments, this limitation is lifted in XOTcl 2.

    XOTcl Next Scripting Language
    # Define method foo with non-positional
    # parameters (x, y and y) and positional
    # parameter (a and b)
    
    Class C
    C instproc foo {
       -x:integer
       -y:required
       -z
       a
       b
    } {
       # ...
    }
    C create c1
    
    # invoke method foo
    c1 foo -x 1 -y a 2 3
    # Define method foo with
    # non-positional parameters
    # (x, y and y) and positional
    # parameter (a and b)
    
    Class create C {
       :public method foo {
          -x:integer
          -y:required
          -z
          a
          b
       } {
          # ...
       }
       :create c1
    }
    # invoke method foo
    c1 foo -x 1 -y a 2 3
    # Only leading non-positional
    # parameters are available; no
    # optional positional parameters,
    # no value constraints on
    # positional parameters,
    # no multiplicity, ...
    # Define various forms of parameters
    # not available in XOTcl 1
    
    Class create C {
      # trailing (or interleaved) non-positional
      # parameters
      :public method m1 {a b -x:integer -y} {
        # ...
      }
    
      # positional parameters with value constraints
      :public method m2 {a:integer b:boolean} {
        #...
      }
    
      # optional positional parameter (trailing)
      :public method set {varName value:optional} {
        # ....
      }
    
      # parameter with multiplicity
      :public method m3 {-objs:object,1..n c:class,0..1} {
        # ...
      }
    
      # In general, the same list of value
      # constraints as for configure parameter is
      # available (see above).
      #
      # User defined value constraints are
      # possible. All parameter value checkers
      # can be turned on and off.
    }

    2.4.4. Return Value Checking

    Return value checking is a functionality available in the Next Scripting Framework, that was not yet available in XOTcl 1. A return value checker assures that a method returns always a value satisfying some value constraints. Return value checkers can be defined on all forms of methods (scripted or C-implemented). Like for other value checkers, return value checkers can be turned on and off.

    XOTcl Next Scripting Language
    # No return value checking
    # available
    # Define method foo with non-positional
    # parameters (x, y and y) and positional
    # parameter (a and b)
    
    Class create C {
    
      # Define method foo which returns an
      # integer value
      :method foo -returns integer {-x:integer} {
        # ...
       }
    
      # Define an alias for the Tcl command ::incr
      # and assure, it always returns an integer
      # value
      :alias incr -returns integer ::incr
    
      # Define a forwarder that has to return an
      # integer value
      :forward ++ -returns integer ::expr 1 +
    
     # Define a method that has to return a
     # nonempty list of objects
     :public object method instances {} \
        -returns object,1..n {
       return [:info instances]
      }
    }

    2.5. Interceptors

    XOTcl and NX allow the definition of the same set of interceptors, namely class- and object-level mixins and class- and object-level filters. The primary difference in NX is the naming, since NX abandons the prefix "inst" from the names of instance specific method, but uses the modifier object" for object specific methods.

    Therefore, in NX, if a mixin is registered on a class-level, it is applicable for the instances (a per-class mixin), and if and object mixin is registered, it is a per-object mixin. In both cases, the term mixin is used, in the second case with the modifier object. As in all other cases, one can register the same way a per-object mixin on a plain object or on a class object.

    2.5.1. Register Mixin Classes and Mixin Guards

    XOTcl Next Scripting Language
    /cls/ instmixin ...
    /cls/ instmixinguard /mixin/ ?condition?
    
    # Query per-class mixin
    /cls/ instmixin
    # Register/clear per-class mixin and guard for
    # a class
    
    /cls/ mixins add|set|clear ...
    /cls/ mixins guard /mixin/ ?condition?
    /cls/ configure -mixin ...
    
    # Query per-class mixins
    /cls/ mixins get
    /cls/ cget -mixins
    
    # Query per-class mixins (without guards)
    /cls/ mixins classes
    /obj/ mixin ...
    /obj/ mixinguard /mixin/ ?condition?
    
    # Query per-object mixins
    /obj/ mixin
    # Register/clear per-object mixin and guard for
    # an object
    
    /obj/ object mixins add|set|clear ...
    /obj/ object mixins guard /mixin/ ?condition?
    /obj/ configure -object-mixins ...
    
    # Query per-object mixin
    /obj/ object mixins get
    /obj/ cget -object-mixin
    
    # Query per-object mixins (without guards)
    /cls/ mixins classes

    2.5.2. Register Filters and Filter Guards

    XOTcl Next Scripting Language
    # Register per-class filter and guard for
    # a class
    /cls/ instfilter ...
    /cls/ instfilterguard /filter/ ?condition?
    
    # Query per-class filter
    /cls/ instfilter
    # Register/clear per-class filter and guard for
    # a class
    
    /cls/ filters add|set|clear ...
    /cls/ filters guard /filter/ ?condition?
    /cls/ configure -filters ...
    
    # Query per-class filters
    /cls/ filters get
    /cls/ cget -filters
    
    # Query per-class filters (without guards)
    /cls/ filters methods
    /obj/ filter ...
    /obj/ filterguard /filter/ ?condition?
    # Register(clear per-object filter and guard for
    # an object
    
    /obj/ object filters add|set|clear ...
    /obj/ object filters guard /filter/ ?condition?
    /obj/ configure -object-filters ...
    
    # Query per-object filters
    /cls/ object filters get
    /obj/ cget -object-filters
    
    # Query per-object filters (without guards)
    /cls/ object filters methods

    2.6. Introspection

    In general, introspection in NX became more orthogonal and less dependent on the type of the method. In XOTcl it was e.g. necessary that a developer had to know, whether a method is e.g. scripted or not and has to use accordingly different sub-methods of info.

    In NX, one can use e.g. always info method with a subcommand and the framework tries to hide the differences as far as possible. So, one can for example obtain with info method parameter the parameters of scripted and C-implemented methods the same way, one can get the definition of all methods via info method definition and one can get an manual-like interface description via info method syntax. In addition, NX provides means to query the type of a method, and NX allows one to filter by the type of the method.

    2.6.1. List sub- and superclass relations

    While XOTcl used singular words for introspecting sub- and superclass relations, NX uses plural word to indicate that potentially a list of values is returned.

    XOTcl Next Scripting Language
    /cls/ info superclass ?pattern?
    /cls/ info superclasses ?pattern?
    /cls/ info subclass ?pattern?
    /cls/ info subclasses -type setter ?pattern?

    2.6.2. List methods defined by classes

    While XOTcl uses different names for obtaining different kinds of methods defined by a class, NX uses info methods in an orthogonal manner. NX allows as well to use the call protection to filter the returned methods.

    XOTcl Next Scripting Language
    /cls/ info instcommands ?pattern?
    /cls/ info methods ?pattern?
    /cls/ info instparametercmd ?pattern?
    /cls/ info methods -type setter ?pattern?
    /cls/ info instprocs ?pattern?
    /cls/ info methods -type scripted ?pattern?
    # n.a.
    /cls/ info methods -type alias ?pattern?
    /cls/ info methods -type forwarder ?pattern?
    /cls/ info methods -type object ?pattern?
    /cls/ info methods -callprotection public|protected ...

    2.6.3. List methods defined by objects

    While XOTcl uses different names for obtaining different kinds of methods defined by an object, NX uses info methods in an orthogonal manner. NX allows as well to use the call protection to filter the returned methods.

    XOTcl Next Scripting Language
    /obj/ info commands ?pattern?
    /obj/ info object methods ?pattern?
    /obj/ info parametercmd ?pattern?
    /obj/ info object methods -type setter ?pattern?
    /obj/ info procs ?pattern?
    /obj/ info object methods -type scripted ?pattern?
    # n.a.
    /obj/ info object methods -type alias ?pattern?
    /obj/ info object methods -type forwarder ?pattern?
    /obj/ info object methods -type object ?pattern?
    /obj/ info object methods -callprotection public|protected ...

    2.6.4. Check existence of a method

    NX provides multiple ways of checking, whether a method exists; one can use info method exists to check, if a given method exists (return boolean), or one can use info methods ?pattern?, where pattern might be a single method name without wild-card characters. The method info methods ?pattern? returns a list of matching names, which might be empty. These different methods appear appropriate depending on the context.

    XOTcl Next Scripting Language
    /obj|cls/ info \
       [inst](commands|procs|parametercmd) \
       ?pattern?
    /cls/ info method exists /methodName/
    /cls/ info methods /methodName/
    /obj/ info object method exists /methodName/
    /obj/ info object methods /methodName/

    2.6.5. List callable methods

    In order to obtain the set of artefacts for an object defined in the class hierarchy, NX uses info lookup. One can either lookup methods (via info lookup methods) or slots (via info lookup slots). The plural term refers to a potential set of return values.

    XOTcl Next Scripting Language
    /obj/ info methods ?pattern?
    /obj/ info lookup methods ... ?pattern?
    # Returns list of method names
    # n.a.
    # List only application specific methods
    /obj/ info lookup methods -source application ... ?pattern?
    # Returns list of method names
    # Options for 'info methods'
    #
    # -incontext
    # -nomixins
    # Options for 'info lookup methods'
    #
    # -source ...
    # -callprotection ...
    # -incontext
    # -type ...
    # -nomixins
    # n.a.
    # List slot objects defined for obj
    # -source might be all|application|baseclasses
    # -type is the class of the slot object
    
    /obj/ info lookup slots ?-type ...? ?-source ...? ?pattern?
    
    # Returns list of slot objects
    # List registered filters
    /obj/ info filters -order ?-guards? ?pattern?
    
    # List registered mixins
    /obj/ info mixins -heritage ?-guards? ?pattern?
    # List registered filters
    /obj/ info lookup filters ?-guards? ?pattern?
    
    # List registered mixins
    /obj/ info lookup mixins ?-guards? ?pattern?

    2.6.6. List object/class where a specified method is defined

    info lookup can be used as well to determine, where exactly an artefact is located. One can obtain this way a method handle, where a method or filter is defined.

    The concept of a method-handle is new in NX. The method-handle can be used to obtain more information about the method, such as e.g. the definition of the method.

    XOTcl Next Scripting Language
    /obj/ procsearch /methodName/
    /obj/ info lookup method /methodName/
    # Returns method-handle
    /obj/ filtersearch /methodName/
    /obj/ info lookup filter /methodName/
    # Returns method-handle

    2.6.7. List definition of scripted methods

    XOTcl contains a long list of info subcommands for different kinds of methods and for obtaining more detailed information about these methods.

    In NX, this list of info subcommands is much shorter and more orthogonal. For example, info method definition can be used to obtain with a single command the full definition of a scripted method, and furthermore, it works as well the same way to obtain e.g. the definition of a forwarder or an alias.

    While XOTcl uses different names for info options for objects and classes (using the prefix "inst" for instance specific method), NX uses for object specific method the modifier object. For definition of class object specific methods, use the modifier object as usual.

    XOTcl Next Scripting Language
    # n.a.
    /cls/ info method definition /methodName/
    /obj/ info object method definition /methodName/
    /cls/ info instbody /methodName/
    /obj/ info body /methodName/
    /cls/ info method body /methodName/
    /obj/ info object method body /methodName/
    /cls/ info instargs /methodName/
    /obj/ info args /methodName/
    /cls/ info method args /methodName/
    /obj/ info object method args /methodName/
    /cls/ info instnonposargs /methodName/
    /obj/ info object method args /methodName/
    /cls/ info method parameter /methodName/
    /obj/ info object method parameter /methodName/
    /cls/ info instdefault /methodName/
    /obj/ info default /methodName/
    # not needed, part of
    # "info ?object? method parameter"
    /cls/ info instpre /methodName/
    /obj/ info pre /methodName/
    /cls/ info method precondition /methodName/
    /obj/ info object method precondition /methodName/
    /cls/ info instpost /methodName/
    /obj/ info post /methodName/
    /cls/ info method postcondition /methodName/
    /obj/ info object method postcondition /methodName/

    Another powerful introspection option in NX is info ?object? method syntax which obtains a representation of the parameters of a method in the style of Tcl man pages (regardless of the kind of method).

    XOTcl Next Scripting Language
    # n.a.
    /cls/ info method syntax /methodName/
    /obj/ info object method syntax /methodName/

    2.6.8. List Configure Parameters

    The way, how newly created objects can be configured is determined in NX via properties. The configuration happens during creation via the methods create or new or during run time via configure. These methods have therefore virtual argument lists, depending on the object or class on which they are applied.

    XOTcl Next Scripting Language
    # n.a.
    # Return the parameters applicable to
    # the create method of a certain class.
    # class can be configured. A pattern can
    # be used to filter the results.
    
    /cls/ info lookup parameters create ?/pattern/?
    
    # Return in the result in documentation syntax
    
    /cls/ info lookup syntax create ?/pattern/?
    
    # "info lookup parameters configure" returns
    # parameters available for configuring the
    # current object  (might contain object
    # specific information)
    
    /obj/ info lookup parameters configure ?pattern?
    
    # "info lookup configure syntax" returns syntax of
    # a call to configure in the Tcl parameter syntax
    
    /obj/ info lookup syntax configure
    
    # Obtain information from a parameter
    # (as e.g. returned from "info lookup
    # parameters configure").
    
    nsf::parameter::info name /parameter/
    nsf::parameter::info syntax /parameter/
    nsf::parameter::info type /parameter/

    2.6.9. List Variable Declarations (property and variable)

    XOTcl Next Scripting Language
    # obtain parameter definitions defined
    # for a class
    /cls/ info parameter
    # "info variables" returns handles of
    # properties and variables defined by this
    # class or object
    
    /cls/ info variables ?pattern?
    /obj/ info object variables ?pattern?
    
    # "info lookup variables" returns handles
    # of variables and properties applicable
    # for the current object (might contain
    # object specific information)
    
    /obj/ info lookup variables /pattern/
    
    # "info variable" lists details about a
    # single property or variable.
    
    /obj/ info variable definition /handle/
    /obj/ info variable name /handle/
    /obj/ info variable parameter /handle/

    2.6.10. List Slots

    XOTcl Next Scripting Language
    # n.a.
    # Return list of slots objects defined on the
    # object or class
    #
    # -source might be all|application|baseclasses
    # -type is the class of the slot object
    # -closure includes slots of superclasses
    
    /cls/ info slots \
       ?-type value? ?-closure? ?-source value? ?pattern?
    /obj/ info object slots ?-type ...? ?pattern?
    
    # List reachable slot objects defined for obj
    # -source might be all|application|baseclasses
    # -type is the class of the slot object
    # Returns list of slot objects.
    
    /obj/ info lookup slots \
       ?-type ...? ?-source ... ?pattern?
    
    # Obtain definition, name or parameter from
    # slot object
    
    /slotobj/ definition
    /slotobj/ name
    /slotobj/ parameter

    2.6.11. List Filter or Mixins

    In NX all introspection options for filters are provided via info filters and all introspection options for mixins are provided via info mixins.

    XOTcl Next Scripting Language
    /obj/ info filter ?-guards? ?-order? ?pattern?
    /obj/ info filterguard /name/
    /obj/ info object filters \
       ?-guards? ?pattern?
    /cls/ info instfilter \
       ?-guards? ?-order? ?pattern?
    /cls/ info instfilterguard /name/
    /cls/ info filters \
       ?-guards? ?pattern?
    /obj/ info mixin ?-guards? ?-order ?pattern?
    /obj/ info mixinguard /name/
    /obj/ info object mixins \
       ?-guards? ?pattern?
    /cls/ info instmixin \
       ?-guards? ?-order? ?pattern?
    /cls/ info instmixinguard /name/
    /cls/ info mixins \
       ?-closure? ?-guards? ?-heritage? ?pattern?

    2.6.12. List definition of methods defined by aliases, setters or forwarders

    As mentioned earlier, info method definition can be used on every kind of method. The same call can be used to obtain the definition of a scripted method, a method-alias, a forwarder or a setter method.

    XOTcl Next Scripting Language
    # n.a.
    /cls/ info method definition /methodName/
    /obj/ info object method definition /methodName/

    2.6.13. List Method-Handles

    NX supports method-handles to provide means to obtain further information about a method or to change maybe some properties of a method. When a method is created, the method creating method returns the method handle to the created method.

    XOTcl Next Scripting Language
    # n.a.
    #
    # List the method handle of the specified method,
    # can be used e.g. for aliases. "handle" is the short
    # form of "definitionhandle".
    #
    /cls/ info method handle /methodName/
    /obj/ info object method handle /methodName/
    #
    # For ensemble methods (method name contains
    # spaces) one can query as well the registration
    # handle, which is the handle to the root of the
    # ensemble; the definition handle points to the
    # leaf of the ensemble.
    #
    /cls/ info method registrationhandle /methodName/
    /obj/ info object method registrationhandle /methodName/
    #
    # For aliases, one can query the original
    # definition via "info method origin"
    #
    /cls/ info method origin /methodName/
    /obj/ info object method origin /methodName/

    2.6.14. List type of a method

    The method info ?object? method type is new in NX to obtain the type of the specified method.

    XOTcl Next Scripting Language
    # n.a.
    /cls/ info method type /methodName/
    /obj/ info object method type /methodName/

    2.6.15. List the scope of mixin classes

    NX provides a richer set of introspection options to obtain information, where mixins classes are mixed into.

    XOTcl Next Scripting Language
    /cls/ info mixinof ?-closure? ?pattern?
    # List objects, where /cls/ is a
    # per-object mixin
    
    /cls/ info mixinof -scope object ?-closure? \
       ?pattern?
    /cls/ info instmixinof ?-closure? ?pattern?
    # List classes, where /cls/ is a per-class mixin
    
    /cls/ info mixinof -scope class ?-closure? \
       ?pattern?
    # n.a.
    # List objects and classes, where /cls/ is
    # either a per-object or a per-class mixin
    
    /cls/ info mixinof -scope all ?-closure? \
       ?pattern?
    /cls/ info mixinof ?-closure? ?pattern?

    2.6.16. Check properties of object and classes

    Similar as noted before, NX uses rather a hierarchical approach of naming using multiple layers of subcommands).

    XOTcl Next Scripting Language
    /obj/ istype /sometype/
    # Check if object is a subtype of some class
    /obj/ info has type /sometype/
    /obj/ ismixin /cls/
    # Check if object has the specified mixin registered
    /obj/ info has mixin /cls/
    /obj/ isclass ?/cls/?
    # Check if object is an NX class
    /obj/ has type ::nx::Class
    
    # Check if object is a class in one of the
    # NSF object systems
    ::nsf::is class /obj/
    /obj/ ismetaclass /cls/
    # Check if class is an NX metaclass
    expr {[/cls/ info heritage ::nx::Class] ne ""}
    
    # Check if object is a metaclass in one of the
    # NSF object systems
    ::nsf::is metaclass /obj/
    # n.a.
    # Check if object is a baseclass of an object system
    ::nsf::is baseclass /obj/
    # n.a.
    # Return name of object (without namespace prefix)
    /obj/ info name
    /obj/ object::exists /obj/
    # Check for existence of object (nsf primitive)
    ::nsf::object::exists /obj/

    2.6.17. Call-stack Introspection

    Call-stack introspection is very similar in NX and XOTcl. NX uses for subcommand the term current instead of self, since self has a strong connotation to the current object. The term proc is renamed by method.

    XOTcl Next Scripting Language
    self
    self
    current object
    self class
    current class
    self args
    current args
    self proc
    current method
    self callingclass
    current calledclass
    self callingobject
    current callingobject
    self callingproc
    current callingmethod
    self calledclass
    current calledclass
    self calledproc
    current calledmethod
    self isnextcall
    current isnextcall
    self next
    # Returns method-handle of the
    # method to be called via "next"
    current next
    self filterreg
    # Returns method-handle of the
    # filter method
    current filterreg
    self callinglevel
    current callinglevel
    self activelevel
    current activelevel

    2.7. Other Predefined Methods

    XOTcl Next Scripting Language
    /obj/ requireNamespace
    /obj/ require namespace
    # n.a.
    /obj/ require method

    2.8. Dispatch, Aliases, etc.

    todo: to be done or omitted

    2.9. Assertions

    In contrary to XOTcl, NX provides no pre-registered methods for assertion handling. All assertion handling can e performed via the Next Scripting primitive nsf::method::assertion.

    XOTcl Next Scripting Language
    /obj/ check /checkoptions/
    ::nsf::method::assertion /obj/ check /checkoptions/
    /obj/ info check
    ::nsf::method::assertion /obj/ check
    /obj/ invar /conditions/
    ::nsf::method::assertion /obj/ object-invar /conditions/
    /obj/ info invar
    ::nsf::method::assertion /obj/ object-invar
    /cls/ instinvar /conditions/
    ::nsf::method::assertion /cls/ class-invar /conditions/
    /cls/ info instinvar
    ::nsf::method::assertion /cls/ class-invar
    /cls/ invar /conditions/
    ::nsf::method::assertion /cls/ object-invar /conditions/
    /cls/ info invar
    ::nsf::method::assertion /cls/ object-invar

    2.10. Method Protection

    As described above, NX supports method protection via the method modifiers protected and public. A protected method can be only called from an object of that class, while public methods can be called from every object. The method protection can be used to every kind of method, such as e.g. scripted methods, aliases, forwarders, or accessors. For invocations, the most specific definition (might be a mixin) is used for determining the protection.

    3. Incompatibilities between XOTcl 1 and XOTcl 2

    3.1. Resolvers

    The resolvers (variable resolvers, function resolvers) of the Next Scripting Framework are used as well within XOTcl 2. When variable names or method names starting with a single colon are used in XOTcl 1 scripts, conflicts will arise with the resolver. These names must be replaced.

    3.2. Parameters

    The following changes for parameters could be regarded as bug-fixes.

    3.2.1. Parameter usage without a value

    In XOTcl 1, it was possible to call a parameter method during object creation via the dash-interface without a value (in the example below -x).

    # XOTcl example
    
    Class Foo -parameter {x y}
    Foo f1 -x -y 1

    Such cases are most likely mistakes. All parameter configurations in XOTcl 2 require an argument.

    3.2.2. Ignored Parameter definitions

    In XOTcl 1, a more specific parameter definition without a default was ignored when a more general parameter definition with a default was present. In the example below, the object b1 contained in XOTcl 1 incorrectly the parameter x (set via default from Foo), while in XOTcl 2, the variable won’t be set.

    # XOTcl example
    
    Class Foo -parameter {{x 1}}
    Class Bar -superclass Foo -parameter x
    Bar b1

    3.2.3. Changing classes and superclasses

    NX does not define the methods class and superclass (like XOTcl), but allows one to alter all object/class relations (including class/superclass/object-mixin/…) nsf::relation::set. The class and superclass can be certainly queried in all variants with info class or info superclasses.

    # NX example
    
    nx::Class create Foo
    Foo create f1
    
    # now alter the class of object f1
    nsf::relation::set f1 class ::nx::Object

    3.2.4. Overwriting procs/methods with objects and vice versa

    NSF is now more conservative on object/method creation. In contrary to XOTcl 1 NSF does not allow one to redefined a pre-existing command (e.g. "set") with an object and vice versa. Like in XOTcl 1, preexisting objects and classes con be redefined (necessary for reloading objects/classes in a running interpreter).

    3.2.5. Info heritage

    info heritage returns in XOTcl 1 the transitive superclass hierarchy, which is equivalent with info superclasses -closure and therefore not necessary. In XOTcl 2 (and NX), info heritage includes as well the transitive per-class mixins.

    3.3. Slots

    All slot objects (also XOTcl slot objects) are now next-scripting objects of baseclass ::nx::Slot. The name of the experimental default-setter initcmd was changed to defaultcmd. Code directly working on the slots objects has to be adapted.

    3.4. Obsolete Commands

    Parameter-classes were rarely used and have been replaced by the more general object parameterization. Therefore, cl info parameterclass has been removed.

    3.5. Stronger Checking

    The Next Scripting Framework performs stronger checking than XOTcl 1 For example, the requiredness of slots in XOTcl 1 was just a comment, while XOTcl 2 enforces it.

    3.6. Exit Handlers

    The exit handler interface changed from a method of ::xotcl::Object into the Tcl command ::nsf::exithandler:

    # NX example
    ::nsf::exithandler set|get|unset ?arg?

    ./nsf2.4.0/doc/compositeExample-xotcl.html000644 000766 000024 00000002417 12161565464 021306 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/scripts/compositeExample.xotcl

    ./apps/scripts/compositeExample.xotcl ./apps/scripts/compositeExample.xotcl


    Package/File Information

    No package provided/required

    Filename: ./apps/scripts/compositeExample.xotcl

    Description: Simple Graphics example of the composite pattern taken from the paper 'Filters as a Language Support for Design Patterns in Object-Oriented Scripting Languages'. They demonstrate instfilters, filter chains and filter inheritance.



    Back to index page.

    ./nsf2.4.0/doc/TclGdbmStorage-xotcl.html000644 000766 000024 00000001560 12161565463 020626 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/store/TclGdbmStorage.xotcl

    ./library/store/TclGdbmStorage.xotcl ./library/store/TclGdbmStorage.xotcl


    Package/File Information

    No package provided/required

    Filename: ./library/store/TclGdbmStorage.xotcl




    Back to index page.

    ./nsf2.4.0/doc/man.css000644 000766 000024 00000012223 14274463622 015234 0ustar00neumannstaff000000 000000 body { color: #252525; font: 13px/1.231 "Arial","Verdana", sans-serif; text-align: left; } DIV.doctools { margin-left: 10%; margin-right: 10%; } DIV.doctools H1,DIV.doctools H2 { margin-left: -5%; } H1, H2, H3, H4 { margin-top: 1em; font-family: sans-serif; font-size: large; color: #89a618; background: transparent; text-align: left; } h2 { border-bottom: 1px solid #89a618; text-transform: uppercase; } H1.doctools_title { text-align: center; } /* UL,OL { margin-right: 0em; margin-top: 3pt; margin-bottom: 3pt; } */ UL LI { list-style: disc; } OL LI { list-style: decimal; } DT { padding-top: 1ex; } UL.toc,UL.toc UL, UL.toc UL UL { font: normal 12pt/14pt sans-serif; list-style: none; } LI.doctools_section, LI.doctools_subsection { list-style: none; margin-left: 0em; text-indent: 0em; padding: 0em; } PRE { display: block; font-family: monospace; white-space: pre; margin: 0%; padding-top: 0.5ex; padding-bottom: 0.5ex; padding-left: 1ex; padding-right: 1ex; width: 100%; } PRE.doctools_example { color: black; background: #f5dcb3; border: 1px solid black; } UL.doctools_requirements LI, UL.doctools_syntax LI { list-style: none; margin-left: 0em; text-indent: 0em; padding: 0em; } /* DIV.synopsis { color: black; background: #80ffff; border: 1px solid black; font-family: serif; margin-top: 1em; margin-bottom: 1em; } */ /* UL.syntax { margin-top: 1em; border-top: 1px solid black; }*/ UL.doctools_requirements { margin-bottom: 1em; border-bottom: 1px solid black; } i.term { border-bottom: 1px dotted #000000; font-style: normal; text-decoration: none; } dl.doctools_definitions b.method { /* background: none repeat scroll 0 0 #fcfbfa; border: 1px solid #efeeed; padding: 0 3px; */ font-family: Menlo,Monaco,"DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",Courier,monospace; font-size: 92.308%; line-height: 1.35; font-weight: bold; } dl.doctools_definitions i.arg, dl.options i.arg { /* background: none repeat scroll 0 0 #ffffff; border: 1px solid #efeeed; padding: 0 3px; */ font-family: Menlo,Monaco,"DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",Courier,monospace; font-size: 92.308%; line-height: 1.35; font-weight: normal; } dl.doctools_definitions b.option, dl.options b.option { /* background: none repeat scroll 0 0 #ffffff; border: 1px solid #efeeed; padding: 0 3px; */ font-family: Menlo,Monaco,"DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",Courier,monospace; font-size: 92.308%; line-height: 1.35; font-weight: normal; text-decoration: none; } dl.doctools_definitions b.cmd, p b.cmd { /* background: none repeat scroll 0 0 #e7edd3; border: 1px solid #89a618; padding: 0 3px; */ font-family: Menlo,Monaco,"DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",Courier,monospace; font-size: 92.308%; line-height: 1.35; font-weight: bold; } dl.doctools_definitions b.const, p b.const { /* background: none repeat scroll 0 0 #ffffff; */ /* border: 1px solid #efeeed; */ padding: 0 3px; font-family: Menlo,Monaco,"DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",Courier,monospace; font-size: 92.308%; line-height: 1.35; font-weight: normal; text-decoration: none; } code, kbd, pre, samp { font-family: Menlo,Monaco,"DejaVu Sans Mono","Bitstream Vera Sans Mono","Courier New",Courier,monospace; font-size: 92.308%; line-height: 1.35; } pre.doctools_example { background: none repeat scroll 0 0 #fcfbfa; border-color: #efeeed; border-image: none; border-style: solid; border-width: 1px 1px 1px 5px; } div.doctools_synopsis { background: none repeat scroll 0 0 #e7edd3; border-color: #d4d8eb; border: 1px solid; border-radius: 3px; margin: 1em 0; padding: 0 1em; } div.doctools_synopsis ul { padding-left: 0; } a:link { color: #002a4b; text-decoration: none } /* SF-specific styling */ hr { border: 0; height: 1px; background: #89a618; } @media print { body { font-size: 13px !important; /*prince-linebreak-magic: auto;*/ } pre.doctools_example { font-size: 80% !important; white-space: wrap !important; page-break-inside: avoid; } ul.syntax { margin-left: 0 !important; padding-left: 0 !important; } ul.syntax li { text-indent: 1em hanging !important; } h2 { string-set: chapter-title content() } } @page { size: A4; /* DIV 15 for A4 paper */ margin: 19.80mm 14mm; /* Not supported by Chrome, kept for later reference */ @top-center { font-family: "Arial","Verdana", sans-serif; color: #666; font-size: 80%; content: string(chapter-title) } @bottom-center { font-family: "Arial","Verdana", sans-serif; font-size: 80%; color: #666; content: "- " counter(page) " -" } } @page:first { @top { content: normal } } ./nsf2.4.0/doc/link-checker-xotcl.html000644 000766 000024 00000003454 13463555442 020332 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/comm/link-checker.xotcl

    ./apps/comm/link-checker.xotcl ./apps/comm/link-checker.xotcl


    Package/File Information

    No package provided/required

    Filename: ./apps/comm/link-checker.xotcl

    Description: A simple link checking program that checks in parallel pages of a site.

    Options:

    -url Start-URL
    -foreign 0 or 1, specifies, whether foreign links of local pages should be checked (default 1)
    -local A string match pattern to decide which url should be treated as local e.g. -local *wu-wien.ac.at/* Per default the locality filter is set to the name of the host followed by '/*'
    -restrict 0 or 1, sets the locality filter to the subtree implied by the URL
    -verbose 0 or 1 or 2, verbosity level (default 0)




    Back to index page.

    ./nsf2.4.0/doc/langRef2.xotcl000644 000766 000024 00000011202 13442267627 016461 0ustar00neumannstaff000000 000000 # -*- tcl -*- source [file dirname [info script]]/xodoc-tools.xotcl namespace eval ::xodoc-tools { @ xotclCmd ::xotcl::self { The command [:cmd ${:name}] returns callstack related information } { :variant self { [:cmd ${:name}] returns the name of the object, which is currently executed. If it is called from outside of an XOTcl method, it returns an error. } :variant "self class" { [:cmd ${:name}] returns the name of the class, which holds the currently executing method. Note that this may be different to the class of the current object. If it is called from an object specific method it returns an empty string. } :variant "self method" { [:cmd ${:name}] returns the name of the currently executing method. } :variant "self callingclass" { [:cmd ${:name}] returns the name of the class that has called the executing method. } :variant "self callingobject" { [:cmd ${:name}] returns the name of the object that has the object that has called the executing method. } :variant "self callingmethod" { [:cmd ${:name}] returns the name of the method that has called the executing method. } :variant "self calledclass" { [:cmd ${:name}] returns the class name of the class that holds the target method (in mixins and filters). } :variant "self calledmethod" { [:cmd ${:name}] returns the name of the target called method (only applicable in a filter). } :variant "self isnextcall" { [:cmd ${:name}] returns 1 if this method was invoked via next, otherwise 0. } :variant "self next" { [:cmd ${:name}] returns the "next" method on the precedence path. } :variant "self filterreg" { [:cmd ${:name}] returns the name of the object/class on which the filter is registered. } :variant "self callinglevel" { [:cmd ${:name}] returns the calling level, from where the actual method was called from. Intermediary next calls are ignored in this computation. The level is returned in a form that can be used as first argument in [:cmd uplevel] or [:cmd upvar]. } :variant "self activelevel" { [:cmd ${:name}] returns the level, from where the actual method was invoked from. This might be the calling level or a next call, whatever is higher in the stack. The level is returned in a form that can be used as first argument in [:cmd uplevel] or [:cmd upvar]. } } @ xotclCmd ::xotcl::alias -arguments { object -per-object:switch methodName -nonleaf:switch -objscope:switch cmd } { The command [:cmd ${:name}] is used to register a Tcl command as method for an object or class. } { :param object {is the object or class, on which the command is registered as a method} :param -per-object {if provided, the method is a per-object method (not inheritable)} :param methodName {the name for the method to be added} :param -nonleaf:switch {if provided, the method will have a call stack entry such it can call [:cmd next]} :param -objscope:switch {if provided, the variables created during the execution of the method will be instance variables} :param cmd {is the Tcl command to be registered as method} } @ xotclClass ::xotcl2::Object { This class holds the pre-defined methods available for all XOTcl 2 objects. These methods are also available on XOTcl 2 classes. } # # i think, we do not have to distinguish between alias registered on Object and Class # @ xotclMethod alias -partof ::xotcl2::Object \ -arguments {-nonleaf:switch -objscope:switch methodName cmd} \ { This method is used to register an existing Tcl command as a method for a class or object. } { :param "-nonleaf:switch" {} -use ::xotcl::alias :param "-objscope:switch" {} -use ::xotcl::alias :param "methodName" {} -use ::xotcl::alias :param "cmd" {} -use ::xotcl::alias :returns "Fully qualified method name" } @ xotclMethod setter -partof ::xotcl2::Object \ -arguments {methodName} { Register a method as a setter for same-named instance variables } { :param methodName {the name for the method to be added} :returns "Fully qualified method name" } @ xotclClass ::xotcl2::Class { } } namespace eval ::xodoc-tools { puts "

    Primitive XOTcl framework commands

    \n
      " foreach cmd [sorted [xotclCmd info instances] name] { $cmd renderCmd } puts "
    \n\n" puts "

    XOTcl Classes

    \n
      " foreach cmd [sorted [xotclClass info instances] name] { $cmd renderClass } puts "
    \n\n" } ./nsf2.4.0/doc/xotclsh.1000644 000766 000024 00000016256 14274463622 015527 0ustar00neumannstaff000000 000000 '\" '\" Generated from file 'xotclsh\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2014 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. '\" .TH "xotclsh" 1 2\&.4\&.0 xotclsh "Command-line interface" .\" The -*- nroff -*- definitions below are for supplemental macros used .\" in Tcl/Tk manual entries. .\" .\" .AP type name in/out ?indent? .\" Start paragraph describing an argument to a library procedure. .\" type is type of argument (int, etc.), in/out is either "in", "out", .\" or "in/out" to describe whether procedure reads or modifies arg, .\" and indent is equivalent to second arg of .IP (shouldn't ever be .\" needed; use .AS below instead) .\" .\" .AS ?type? ?name? .\" Give maximum sizes of arguments for setting tab stops. Type and .\" name are examples of largest possible arguments that will be passed .\" to .AP later. If args are omitted, default tab stops are used. .\" .\" .BS .\" Start box enclosure. From here until next .BE, everything will be .\" enclosed in one large box. .\" .\" .BE .\" End of box enclosure. .\" .\" .CS .\" Begin code excerpt. .\" .\" .CE .\" End code excerpt. .\" .\" .VS ?version? ?br? .\" Begin vertical sidebar, for use in marking newly-changed parts .\" of man pages. The first argument is ignored and used for recording .\" the version when the .VS was added, so that the sidebars can be .\" found and removed when they reach a certain age. If another argument .\" is present, then a line break is forced before starting the sidebar. .\" .\" .VE .\" End of vertical sidebar. .\" .\" .DS .\" Begin an indented unfilled display. .\" .\" .DE .\" End of indented unfilled display. .\" .\" .SO ?manpage? .\" Start of list of standard options for a Tk widget. The manpage .\" argument defines where to look up the standard options; if .\" omitted, defaults to "options". The options follow on successive .\" lines, in three columns separated by tabs. .\" .\" .SE .\" End of list of standard options for a Tk widget. .\" .\" .OP cmdName dbName dbClass .\" Start of description of a specific option. cmdName gives the .\" option's name as specified in the class command, dbName gives .\" the option's name in the option database, and dbClass gives .\" the option's class in the option database. .\" .\" .UL arg1 arg2 .\" Print arg1 underlined, then print arg2 normally. .\" .\" .QW arg1 ?arg2? .\" Print arg1 in quotes, then arg2 normally (for trailing punctuation). .\" .\" .PQ arg1 ?arg2? .\" Print an open parenthesis, arg1 in quotes, then arg2 normally .\" (for trailing punctuation) and then a closing parenthesis. .\" .\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b .\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out .\" # BS - start boxed text .\" # ^y = starting y location .\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. .\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. .\" # VS - start vertical sidebar .\" # ^Y = starting y location .\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. .\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. .\" # Special macro to handle page bottom: finish off current .\" # box/sidebar if in box/sidebar mode, then invoked standard .\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. .\" # DS - begin display .de DS .RS .nf .sp .. .\" # DE - end display .de DE .fi .RE .sp .. .\" # SO - start of list of standard options .de SO 'ie '\\$1'' .ds So \\fBoptions\\fR 'el .ds So \\fB\\$1\\fR .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. .\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\*(So manual entry for details on the standard options. .. .\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. .\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. .\" # CE - end code excerpt .de CE .fi .RE .. .\" # UL - underline word .de UL \\$1\l'|0\(ul'\\$2 .. .\" # QW - apply quotation marks to word .de QW .ie '\\*(lq'"' ``\\$1''\\$2 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\$2 .. .\" # PQ - apply parens and quotation marks to word .de PQ .ie '\\*(lq'"' (``\\$1''\\$2)\\$3 .\"" fix emacs highlighting .el (\\*(lq\\$1\\*(rq\\$2)\\$3 .. .\" # QR - quoted range .de QR .ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3 .. .\" # MT - "empty" string .de MT .QW "" .. .BS .SH NAME xotclsh \- Simple shell containing NSF/XOTcl2 interpreter .SH SYNOPSIS \fBxotclsh\fR ?\fIfileName\fR? .sp .BE .SH DESCRIPTION .TP \fBxotclsh\fR ?\fIfileName\fR? \fBxotclsh\fR is a shell-like application that reads XOTcl2 and Tcl commands from its standard input or from \fIfileName\fR and evaluates them\&. If invoked without \fIfileName\fR, then it runs in REPL mode, reading commands from standard input and printing command results and error messages to standard output\&. It runs until the exit command is invoked or until it reaches end-of-file on its standard input\&. .sp \fBxotclsh\fR can be used like \fBtclsh\fR to make XOTcl2 scripts directly invocable from the shell, by providing the following first line ("shebang") in the respective script: .CS #! /usr/bin/env xotclsh .CE .IP A (more portable) alternative is: .CS #! /bin/sh # the next line restarts using xotclsh \\ exec xotclsh "$0" "$@" .CE .PP .SH COPYRIGHT .nf Copyright (c) 2014 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. .fi ./nsf2.4.0/doc/Announce2.2.0000644 000766 000024 00000016717 13353343554 016032 0ustar00neumannstaff000000 000000 Dear Community, We are pleased to announce the availability of the Next Scripting Framework (NSF) 2.2.0. The changes are mostly performance and robustness improvements, providing better error messages etc. See below for the details. Diff stats since 2.1.0: 214 files changed, 54192 insertions(+), 44982 deletions(-) Major changes relative to 2.1.0 are: New Features - NSF: * Robustness improvements: + Use exactly the same six whitespace-delimiter characters in NSF as in plain Tcl to avoid surprises (internal API: NsfHasTclSpace()) + Improved parameter parsing: Don't allow bytearrays as name of non-positional arguments, to avoid that bytearrays get unwanted string representations (and losing potentially the pure bytearray property). This could lead to problems with newer Tcl versions when passing binary data to NSF procs and methods. * Performance improvements: + coloncmd reform: Dispatch performance of [:myMethod ...] is improved by up to 30% by caching the result of the method lookup in a Tcl_Obj + Lookup of (bytecode-compiled) object variables is now performed via a sorted lookup cache to avoid repeated linear searches for compiled locals (especially an improvement for unsuccessful searches). + Reduced number of string comparisons (strcmp()) via first-char comparison in method-parameter parsing and argument handling. + Reduced number of strlen() operations, especially in method-parameter parsing and argument handling. + Reduced memory consumption via better member aligning of structs, esp. on 64-bit machines. * New, low-level helper command: * "::nsf::definitionnamespace": Determines the default namespace for objects etc. as used internally in NSF * "::nsf::cmd::info disassemble /methodName/", "/cls/ info method disassemble /methodName/", "/obj/ info method disassemble /methodName/": This is the pendant to ::tcl::unsupported::disassemble adding support for NSF methods and NSF procs (nsf::proc). See, e.g., https://wiki.tcl.tk/21445. The "info" methods are only available when NSF has been built using --enable-development. - NX: * Improvements to incremental property methods: Adding ("value=add") and deleting elements ("value=delete") now enforce any value checkers defined on their properties and behave correctly when conversion is used. * Improvements to handling of parameter option "substdefault". NX provides now controls to the developer to select the kind of substitution at runtime when a default value is used. + the "substdefault" options can control via a single argument whether command/variable/backslash substitution is wanted. Examples: 0x111 substitute all 0x100 only command substitution 0x010 only variable substitution 0x001 only backslash substitution or any bit combination. Combinations can be used to define the equivalents of the flag "-nocommands" (0x011), "-novariables" (0x101), "-nobackslashes" (0x110), and their mixes, respectively, available to [subst]. + make behavior of per-object and per-class substdefaults consistent, early check for complete substitution scripts. * Improvements to ensemble methods: + Fixed bug when ensemble method was dispatched via colon dispatcher (problem with leading colon) + [current nextmethod] + [current isnextcall] return now proper ensemble methods when necessary - MongoDB interface upgrade: * Upgraded driver and utilities to mongodb-c-driver 1.12.0 and libbson 1.12.0. * Add regular expression queries to conditions in nx::mongo * Improved portability between platforms/ OS * Added auto-cleanup of resources (objects) for long-living execution environments (destroy_on_cleanup). * More robust serialization of object graphs, by preserving original classes in serialization/deserialization. * Fixed default-value handling under certain conditions - nx::test: * Provide support for expressing expected results in terms of error codes, rather than error messages. This is to prepare an upcoming reform on providing error codes from within NSF more extensively. - nx::serializer: * Fix potential problem in NaviServer ns_eval with blueprint updates on objects, which were not created by the blueprint. Such objects could lose their classes when these classes are cleaned up on blueprint evaluation. - DTrace support (macOS): Adjusted NSF/DTrace integration for changes on recent macOS (incl. SIP). See dtrace/README for instructions. - Documentation: * NSF now has support for TIP #59 introspection via ::nsf::pkgconfig; see https://core.tcl.tk/tips/doc/trunk/tip/59.md * Added tutorials on NX properties: tutorial-properties.tcl * Improved spelling in documentation: next-migration.txt etc. - Continued testing: NSF is now continuously built and tested under Linux, macOS, and Windows against different Tcl targets, using different tool chains (gcc, clang, MinGW, MSVC). For this purpose, there is now an official GitHub mirror at: https://github.com/nm-wu/nsf Build and test reports are available from: https://travis-ci.com/nm-wu/nsf https://ci.appveyor.com/project/mrcalvin/nsf-2ylk0 - Maintenance & bug fixes: * Execution namespace reform: As in earlier releases, NSF methods can execute in different namespaces such as their object's definition namespace. Starting with NSF 2.2, the execution namespace is maintained in a context structure and the namespace is just changed while the proc is executing. This fixes some counter-intuitive results using standard Tcl introspection on these commands. * Migration to C type 'bool': replace legacy 0/1 integer bools by proper types when possible. * Tcl 8.7: Support for Tcl 8.7a1 and the upcoming, unreleased Tcl 8.7a2 (core.tcl.tk branch "core-8-branch"). NSF compiles and its regression tests execute successfully. * Misc (esp. NSF/C): + Bug fix: Avoid preemptive frees on %proc substitution for forwarder methods. + Aliases: Avoid Tcl_obj re-creations + Guarded against potential Tcl_Obj leaks, esp. when using "NsfMethodNamePath", as indicated by valgrind. + Silenced warnings emitted by GCC 8.1+ on strncat() and strncpy(). + Addressed 5 code-quality issues as indicated by Coverity Scan, incl. control-flow issues (risking NULL dereferencing) and buffer overflows in string operations. + Silence warnings under MSVC 1914 * New configure option: "--enable-development=test" Enable computationally intensive runtime tests, having noticeable effects on runtime. A version of NSF configured with "--enable-development" can be used also for production environments. * Extended regression test suite: The test suite contains now 6243 tests (for Tcl 8.6.8). This compares with 5852 tests in NSF 2.1.0 (for Tcl 8.6.6). - Packaging & distribution: * Initial support for the new nmake system of TEA (TIP 477) and MSVC 1914 (VS 2017; win/makefile.vc); various fixes to install target. The detailed changelog is available at https://next-scripting.org/xowiki/download/file/ChangeLog-2.1.0-2.2.0.log The Next Scripting Framework 2.2.0 (containing NX 2.2.0 and XOTcl 2.2.0) can be obtained from https://next-scripting.org/. Please report issues and wishes by opening a ticket at https://sourceforge.net/p/next-scripting/tickets/. Best regards - Gustaf Neumann - Stefan Sobernig./nsf2.4.0/doc/observer-xotcl.html000644 000766 000024 00000002222 12161565464 017611 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/scripts/observer.xotcl

    ./apps/scripts/observer.xotcl ./apps/scripts/observer.xotcl


    Package/File Information

    No package provided/required

    Filename: ./apps/scripts/observer.xotcl

    Description: Simple observer pattern meta-class taken from the paper 'Filters as a Language Support for Design Patterns in Object-Oriented Scripting Languages'.



    Back to index page.

    ./nsf2.4.0/doc/current.pdf000644 000766 000024 00000211133 12422512322 016106 0ustar00neumannstaff000000 000000 %PDF-1.4 % 1 0 obj <> endobj 7 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj 10 0 obj <> endobj 11 0 obj <> endobj 6 0 obj <> endobj 5 0 obj <> endobj 2 0 obj <> endobj 18 0 obj <> stream xZr+f6rF7U<5""A3$l}P36Mlpn{׹ ȨX1Y#8~D V<^XQf1T, ȮV"2&1祌q )%$XJ$dydl$7ˌdd,IhA;$)`aqew6XQ:K5+V$֔5q'++ZiЮ,K:Rwt쿸zZ m?jQHuK2Fyl NH5 RZ`pV j׆Huk"҉+JCUOfSdt)tgy|wN!cRO?3+mt)ґvBV&R 6n.,~5>l2u> hzRtvo_wsq/KV.39& /bT]bp|,q]-T"u.M #b+ PA,qXIC[utrIPH,n _>~ow_޴:&BS'ńPn/k.idP,HFFH[Y[.rM: ;QQ";%^A!b: 5 @h^ A82PW0 yڠ/ɱz.QO"/|MwK\/eVۗX-*]oC ֫u="r¥#r{<\L#ƗkĠ&BQ\%J@յ?'xfK*-K6/_^ȥHg"b_Vv8ť(UhD46ѾLY V f*]^|?U/DK+"-Wrf/%PIB'65s eSzA*L'(;oY ͎E-hym Ɯ240emo󃃽 虥fgDO_}%rvP2Ԕ!ʊBh Y×Ap b9Զ[Zd,_~:¼`ެ\6kQt\`iT仰 y! d焮5_iIl8P)"QGNw.eo)L 8*Y焇?zPT-0ѧc[䟄cpOk^M?Ceۡfb+t ^<իģיy V .:l:-@j4< zhۉyH&#eh1B'7BNtBԆ!T7> F:i׻f_OFUVl YG=H)(pL+4%$hf+hylJp˾ؖ;}qL2 ?GSC\k#ċ9/* A)8MeW~ǦAr5i[Zپ 'nKN~oj]K |r@N HFF _]fP!IhX6%uY9em05{f"ɶ@\M: P%Y9A_Ih> ^`GdPv4g5UVuU]4K X3w1u-/8X: ̆#H/ڡoSG9L}2~+<߇}oQFep+TOE^05qRdFWu7tWcB6Xڽpskot9}$} Oiݸ/T \ׂ~DI> ϖtn3  >$!kbPsF1$!0 /4IacTøi"!$9lDK~kD`K=y@ 14zPDwS:$yӱ{H/اp+rpla#M:u=Fj_QQZroռ%X4Iz9GdbW8N2ӧf{0Oho@u0`̙]jNl9<Db81ǜ@<80؎]Jꆣ{[ZA%KwX;G-$ɡicLK_3 .iK.tD;G]Z1=Rf V)N11l#@&v$3 R*(ԬPdG43w̻NavtdMƶ;ހd rSbkz &؇Ve'] endstream endobj 19 0 obj 2769 endobj 27 0 obj <>>> stream xuRIr0BzT%9x.!ؓT*'-hht`ACXCd3<Ȉ`Hjܽn1U\h-CWk!4ɔE{R9/p:KKm\pO+]ih؜ 5(*PY 9#3]0TDΦh?tq*$;{A?cSbrYМTaejdEI[4Z#d_ )>JKmEmҩW]ںЦ90kiր dZ;/ZzVv}&X˜qc|T]~ endstream endobj 28 0 obj 303 endobj 3 0 obj <> /ProcSet [/PDF /Text]>> /Annots [25 0 R 26 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R]>> endobj 25 0 obj <> /BS <> /Subtype /Text /T (www.princexml.com) /Subj (Prince - Non-commercial License) /Contents (This document was created with Prince, a great way of getting web content onto paper.) /Popup 26 0 R /Name /Note>> endobj 26 0 obj <> /Subtype /Popup /Parent 25 0 R /Open false>> endobj 20 0 obj <> endobj 21 0 obj <> endobj 22 0 obj <> endobj 23 0 obj <> endobj 24 0 obj <> endobj 29 0 obj <> stream xXr6+0]%D44i6M&3P2$1HHuѿII$MR$>p92Q9srbD:ETHkJ dfld1y?0ʕd9J@@pb2L&>jb⟗dmt)_ҒZ $RLΩT~WIY}n{>׊jQ )*LRUBN8 1:zgi-7?/T}N*m+OxI*HRI2-7؍L ܼ[#|W/W%_'qZO`PǬ)NAn-'=%Y#8.AY$w{aqQ##EAy #t( / #ee!Nu%te[sK5QO,Vf'weճg7H\buU&k(egLavGguHf%ʼFҸȪavÁȉwRWOev`LS|ZT,<$*Htt\Yu,06{FMHr[5␕AD1 b)n>K{J^c.I4 4v=.ҲlWhf{z2Im KgM [i\?eR@bRxOy},uDqapA(LkE .\(`B%tz&E濗:,b݇$M $${J hˎnN}7PO,ƴgHX(V&# IP>ax:K_0Co*gA,>Fj}:Іx U@0#ۇ!P&G,XK0w1sOLh,`n+s6iS:o08 FbvլmjꉣY^zxFFƌcxb ]h':S0^ tA'j0&.WC,|=KrX,{-z1.,8gzjUNHWR)9?:O2l3@O^fxWer}? &toy|_>>kp%.sorU`Xҿ~Y%m,ۢz@;i\rE>2^?ng:>8ƶiUY-~4uewJl=v/z+qTbwpJg nd+kZ)گxYHx=X"UxS6ЭTk"a&^ endstream endobj 30 0 obj 1588 endobj 4 0 obj <> /ProcSet [/PDF /Text]>>>> endobj 12 0 obj <> endobj 31 0 obj <> endobj 32 0 obj <> stream x xE0\Utw64YHC D &h4B(ĕE񪨣QG@\t!uQt;3\A.Tu'|SuNUSuΩS!#B\eڞr%w})O} BҒm+V_DH)EHxŪM g5BBiM >_ l>&6C}| Pۼc4'sUDPaXݰM6Uau߿elkk]B#TYJڛkN(_PՇj/OsH- Td0#r$ڒO/Jfi/Jөܑ)9I($߀5R) 8kG.t' h&Cz9B XDLݍ|@o{[H@9mHۉv ! :=DcN³R|I#9=ʽ}c: 1,@yĭ!8$A-!!=<12'wF*t#} oo,b܌A<% I%sIE&ssWB~*pp / ~>~;f?M^4:>?A?Q'%:eކ7w*L*aVvOя8|FB \*7[=>8o~?_G`f+>Y5X*6mWҭe Gp/ t#XIa$Dg`g%x:³Z܄o[Ih: dr4&r;J!/y|DNS q~n7[]í:`1K+̚w7{~R8*   "d1W\)$DZ.}(Mn8 $FG kp O q`Y@s?XCe\LAxQNQ߁_AME$Db~ :~/Fxxѳv<HJbx}#z߀סg)< ߌ!qr 4$᱂g$@q :s}?c!-D7QD@4:1"*z(R8FGMHe9HQ$V2]3V%GLKJW!êFKP#}`mMVk=VDp}/o@ o|XNaK=qXv(xU`z}~2M o1^VZ l&1MA/|iע_`h Ɨ*@f6 5_@o3.&0=킨52}֎0C\ċըFqATwXlESq* 5]"4><'RLZ#Dv$t^ RX@!|A[&#)^~9R%BzBl' 'dgHOKj1)I n3gY-fѠ*$ '< 1 ΜBeeR+a_:)M,* $aw9Iӫt/[|W Gj2x$~"T Dg$C]AV{3KlEgREo£F*}%ǩ 7+ iwHrRG;/qx̹ H%pX=#[<~zܠn6~ y0ӋbK:#_faN _ڨnS~eemE^lu&.5;WxR"NT&f4eik{CC΀{lXr-ĢCɲ )'½01q5&Ssgs򯥉|fD_*Y&REIY΂Emt!/vD0w}]_/\׫p^ZAj9XnFA .ӯ}0?]W 劤䊔 {e1QCbQ ]P(uM96cI%??ylG)-eBSv|"P8b5ZR`uBgJ郦^#Olźc5#qOp:XQrº$6fԣkO’׭-%m:(%2PBt%lh+WmH*%)!$az௮Kռ#(  ɐR"ŵxm̖;^3SHTM[M4^x kOji_%`O]9 |J'?>]躦?Io^XֻLu:I0K'zwOJ&{g!Sg Ӂq"^Մxsz=&X8ׄuӽ&b2ag&Gy$ LhC5'4[s3ul%u -=E$fRjU0*ť1f֓#fB ]rB|cgc}Oo9c!X|hT:_[k:[V;=reds]xK_?7o yϿ:\JIaoW>ǍݢU7>cǙC'+>)rDQxsReNAct呻TTm7qm.m0&bN=3wtݿٖ sW. P:#]8T¡trnpA'uЛ4`tZ# min#D*uJjeS@3` Ⱥ9#`T=[)b9 "HV a8 xV$E&0ˊAU9(n8#OQ${܇MӁC5uQwr-X%]"c#`$}X@t BznLteXϬ=[Kj-MLZ[*'GCl(cǸn`AG:b~Gm0+Öv~X‡çŸ80Ooq3MSC,hN8a5uQPF%UB= 4%!I2'"q lTcjLcFn66Ct $CJS],(DuT5đ@%3ikU,#UuB֢>2BitW .C!SĜ2srӹ;`CIN|;&*s+\߸r7w@rGeCjSP z h&9 !]B1 $ Ɠ i2)],IfiϤg_OWK鿉!dJ69"~aWEh Fjp\plӹ*陬/a?I}CCƇͼ%l1N~xvǶmm;,.٩N4O7OHU9:'\]q^.|6E/zWQ떗w+K¡w>.{;7glYϊ|kg<>_oK9x{p݋wq#G>cȼ(l\n_m\1~Cʝ)Fc< yWS_kSnIjilX_)RL&&ӍM;R{MRU1/AM09STjk[On&C %A27 'e;84Ӱ43Q aWzw 2+'Xygg)".\WUE'0!1ZPӃZ`,@;|vI SI)ScϡT0(qb/1i% J7Ti+~ ?ԍN2g*RϤ>؍^GAf7}b6rx3Ϣ7YXKܽ*[{;K [f/cwG7gm4/03ɞ3y^_ SKiWknxIYZUK}p@< <'Dq`!hD%8_H<x1DA;W %8ahSH`XޫGrl$dgO҈}*NQ2n@+*[`IsK| I 7o0#0"_eSWc:--M oYrluĸYYZcQd/r VN}~Ab;;)@KvG\`5 c Zl!#tv@tC;1Ƈ[xh\؋rM1y51I:k/~T7)?4`u>_N Ożln[n^3} vzsm?5| cΝi{Z9P2~Y#醒GvY {WWL}3ȕtu}_o?ROI?Lɖx=)%mKc\<Θ2.'{Ln;hhчkПdu4}7X87>j1׏i{ ?u% 'DM))híg: dIVȒme, g!N"0)X c %T萋`NaroskO*lxV2AtxƊ٣k -c:=:P|.r'~} ;ZS.ܭ Sdp_[Zܟ=}*|fU7nX N[wKq%r8 rk Rs$I4 p$8݉tmlXՙ:6&mnUCBpa ,F|_ R6;ЏIβO'Y^[1'|m˱Jfv_b~6C* S?_'Ox{8 iاL22ZxeN)*}v]\=| ]p(~q"Bts.2nWrtwvauh<nc𳚪`h8} BtIF9ž'gx/DlE.~pWXPf#723ftՍ%[p">^x?9Ӭy&< ~v=鮫m+lNRRj"U/dxqxDd>'v Wgi˗:hO}O^-Lm8 ͙tWY8aEs;OQ;zӀʔR?t$R"3"T,π&)/MēxxNRt)K ~:/_.kF~߬>^PM/I5>K-'9 ^e, t"'z]F[#€><8.;auslK'p'  LQ͆t$8,DO.Dŀ>:$(t4״4hL&Zm?^_Li2MeyZJ0O'D%USL@r_vm;YqIxK>|x{xOp?ae}<32b߷,>~zKqs)Eʛ.]t!+2Kȥ)9ŠΟ?/Ɗw>%~t (ϯC!@ uF+_B 5@z@XP~\܏P_Kib4 #C"HPKA[@1&תhJ+ u R!!"@B2h,s`rͺ!Pkr+!%A( xJ9mB^3 Bn1EߣRt/8bEh^J^C} Js*+QӨ#sow~F"p Bp&o!%:1 Ydp.::g W4n‹guXfΣDiéT5)mb8(yddD&`+e7Jpc WbQGxQ9FpJtN_pSgQ(`o ϦR ~TQG_Rw[7.֎Q$O~,*7qϡt^ɔ; 9@&sϢQT?ZD+, fɑ)O\HYb\HB ($zR M@OCGr4\tȏA@@AwzW1b\ISe H ݐ"8'Y=r9p?CLvpZmVAT 7 @"}v"@^ʞLXի@}r 9fe7I-d1Qί+lDk p ` \#219^5 +2.sUr@2G efX8 9)^tfmʷ-d?Ipp]@Xp*̬4YثwB0d`55!M㒑nRP<rO@p'{^g\F;D]kJɜ?PpS5&l6C -FH?tYMNH GpGh6h6FD9ꁣ8ꁣqG=pG=G=jjQ Q Ռ8q:ЁC8tơ:<<Ƒyy#8#qhЀC 84ơ8aeV8AA11c8cl᎗ ,ǁ8g,ǁ881;1fH[ uA;;x{uBAG8#AGq#A  ݌88G7sNH!Z҅1}ftQ7=  (AqSd)wB zHvC:($a RꩼE+HG%4(8W-qP$Zy18 - 6VF0nl!$NiecYh> ,iF7OT1"O~'z(~ HB*)R$=5aH4:r:hz?1=o\(#^ e er(c\Q=`x 9 Gs!+<uׄ2")\zS8?Y dBqtJA8\NLq y&H yJ(2ce3Hr wǺss[` p,X9{B*'ٓ(zx~'C= v6DsG<]lӳNi4YI)Erv*eʲ,ʼLd$;G~iCdӉ)2?X J`Z m}-ZuG/=qOR?8{jk۹]fb+^y>N{4U&?6OHJmUaU35|LOZ ;@2(2y*(ē (J@TJgt骉ЦUhIC9FрoeOz:iR:x$Hay0,{$-FR8BREOƑ9LiN:g;iMwovjZI_†`2WLx2ͯ 5=M i޲ҚK>2VMe:+б/\NXtr:V^ƚBGFSk+^bP듼Sֶ)ԡ'{ݛCm4AM m2kroM:ŚPmME#_D:UA%5Uzl}f7R P` ޣ)Ѻ˾:.\GN:Y W$ :cu=2/2~w(KlJ'%B )G` qdC(]Ɇ4z-BRJ+iQ۲ٙ3{gQwZwvwH *={VáaCQ߭%)af666az]ǺhX'0;:cL1E;F/(!z endstream endobj 33 0 obj 14600 endobj 13 0 obj <> endobj 34 0 obj <> endobj 35 0 obj <> stream x`TU0~}{[LfR&H!yJ^Dt!4EQ*ED^We 0ZXص*X(] dr}{O?FqM3X y!윹ryd[@B9K.zsUհ}VӇ& d1fϘut{ot8y]4o+,ʰ=O\x $ l\4%=-3Jq%-OZџ_t#_)i>|pa$#Etcwt!? о`p^> " D cEDqIiYW>}+k?}( J/i5z=gKe|ځvGCуh5G" =7qNH q?NFעȋuh-P!:A 4 }_jEroIߞ~=qLw! LJ+57 θ ݇>Ʒ+{wi#&D0DF_`?^ OZj(:سY,B` WFnM>g~':~h|dFƓH)YL"|pp%:9=?͟RvH=~~m0^şAd:y|o"̀Y_{X|1W6|>/ydYHq-܋/ 7_>]^=߅C}a;|#8'{-?q;O_H7F+ȝArG7GrI0f|\)-l^N+oyJmHݝڕjOyABπ@q;[Xq>_|%@|?~7{;٘{r> KlB6I;yI98W 㚸rnw7ƽ}}7ͫ|_'$?ί oH\'v#ΕHc&Vi {=ד1n 7ۃn!U| y:ō$@I\Ip8 ģ >~l!@n$ǣoj z'򕢎%߉:2ׇOroXⷡxp'yT"0Eo| CD?-o:0W4(ZSt=ZH:7{,~.U 8pEpX&zkd>p;"v].œF7&~;>Z*{Fɟyנu%s'8 jB}Hi w9p7z@9]L q?|9 RO]@:\A~y#5MM?KEoG@O+>>C'h _$ %^d#y'w_v l+<6!)Pw HХBtf-J";C%0ߏyhzL ) 8n^fq|í ύ֠γ=~5U}TU,+-)NċbHA~^8 }^4 ݦk"Ks!͑Ds]pA/3zt4EkǴEa98iuH=Utc@H['kdͬmv4 'D Ȑ+m<.SSV{M Zmؒw.f 2`'A   #hCfj3vʐhWy43viHC v6qPnOgn,?qS.mNbfLh0pmބ;MYso8??B77n\i:vJϽQZ665\ڼq(zq܍m҆-#t&tV͎ = "mJؼ 5mhܪ`ڗ>C"'LEB;hUV$p^; 3؝vGz6fwc-v8m YLGLbvqf8 >jߦ jh 6!n"bߜ3##ƍ#ڤtMj?nK&(H0svM$[bD1*(EM6ZNlGХ]ȪH6f@ng"Ӛ}zs (Ȟ69s^אyڰgc#N9 ߽/js …HEB D9`1EoQdJփ#Cی 2e_ԑ>Abϧe6 y1aƍY27ф)Ƞ6483jd@YFPU>ƍCc7H^K4#PMyx0A cwZxS?m0edP;`ߔ},Kh/F`."C,Z^u>9ׇ3r}LʘAƒ f68i2f JL;pin7awaZH`&J5QEc$"G$׫U! G lf5-O]FW5κ:'.Urs^=ԇۍ}'Nʔt| Z_?(G&;s=~j<Rx΍A4hO)dT]26dN]g -Hϟ4N5%;ǻ^2 Lit(ͺ ( T5QWGUD+ʹ_0|dT8!>ChW: W>ƷV@DzI CiI/5H0~ N;ǬKyq=٠mpfI!<&yƅJ < ͡U qvcxt(yW|W2Ŋƪ()H2*,;F_)+hIvfZPO?.ٯu1VU3DP'.|k]_ֶWݶo۷_&9LߝJMRS|w c@ivXJuVr?cѫtN3>Ƹ _[&Ch! P]90u" GzeH% pIf>A jha&ԔLQj+ޚp']]aOsSWrmL5ÀV[ȧ$ӽa;;NT/R`D ;+>DC+)N'a7Ir9fiN}ڻҔU4LQiŠFޏލ7P(>/$>/*B}*U/8? ~:_Ҟs6|CmeV0_5dQ|=tA90aΖotGw6ف{ ]]{ Mi?O֠2pK74d1;3~= ܮή㦓bI;(C9菚pƸ'WS τ"GP(Kgj/=yտzsN]OggsF~vS/4,b6u1(G"=ݓ߁ `3Uy}gN`1,Ru2ٔ[])qޢ̠X܊[]^*f-Q01அxNmYǺ7ۣ_Ιͩ/]_o}ۯVos?Dfn!չfMwHstdV IXSyv5]v'9Ƒ.rjt`9 A!x{prցyҪ^uWO/Ȁc,niuz:Ja{1iE 249n WS5xc3>L}WB/8x`H+ H"\=y"*P"T[lvN Kp<\C>0(C<XTv֪X]ݡ= VNRg{OTIST/מVy656R=|O"<9rC㫋]]]FcDk%7nsP ˍ:g|Oꐥʵ"DN&d*trd*}~<kAO#< |=S+Sw2N@Epd'|(s!c3)5Ow~?FJnk#,LG dF > {rDBv7Gv!`\C35> kR3v\;5ZSuQ!)DVWȥ!Pa'SAY~v bDR7jF ԂH}4.ɿ\ķȸ$*iA, )jğѧ@L:n2QnH B%=Oqj'.+-zW,߿/a4)_\0rce}CG~.l,uũ;;h&Q#F5*pТÇM`R( o̻8:tIsJW[ZCpSMcGxUGqmF4< B#pj}n$$Ir?{+.(rHX [c̹ȹQXbc?ގBeEpb!Kɛ4 {d0 &ǁju\;5f=n5դ(VWEXaQQ1ŋE+ytI'eQe'mGtCu7LZԳN];c_:eOԍMu~7-޿趥ugX- GF\e|э9>o] lAHȎv?۳f "lR`eǘ+S f5qdO"cyZ/_^mTEydQthˢ.ah񈤻a8}\p/rȉd Y"XCkS7n 6unum8Njt2"5:@-=;il#Hf :h덃25p6mSN?P/mi1\cypbQH՟ɔz`Z4L]qM4v7ȦS&CeصawI9e 8?BXbyr旕d[8 H'D"VD'UH!/"õt N'0=CWq: =JG6dS̓fS;Cr!f.yZMɁ^ Սb#;Of4TWaΘn˪2=l3;heNP̈QhMOlܵNnݦ5/1W>.I :`]R ;Zlˍ3sF_\zz_8tܪTsI!3,#8}iM<ݐ/<=fǵ^Agڝyf^W&eH0$dϤ&p"<>)A*_>':S=zo|KU/߱i>_' Oy^[o8mϧն }fUD 9C@2 Y̵QQ)*Y#=&y5}#rK˶~&}q!IeAe^ ~"j* |QCQU((&eY(>&@he?,|k/um֦v;d=z6ߓwѥHϨ|_!_=e0E@eC4KdvrEE(8'D"t|;"*nfq;Q;B|%"*VYD $f^MP#SP6~#- g_`> Á0' #I$8(:\Q8HU(ģ8|&J48(!܇B{M<>7"q]&wYtkֿc>؂K.^1璆gpױK.^>>KZGa-S?Ψ&% k9LaUՙWL]RcLLfTGV!1ct tnF(M1)hZ&mAmjuز)HnT5-9*N\jٯ{AcS-yDA`rH2Eɍ [pҡVOhh8FcDkMV"Elp-͓J{u`J9̀֊ꙝ\LdnǞj9P^c>x5`:٪4+@{Ь4io5--V'w{]4vz#ř|# ^b|ULJz OCӭT6!5&nB!7xBv^+vH$2GFa2٘hNwMMO N仏|sk':(;)Gc]ؠLJ4Ia.QD)`ks$(E!'ijjQȳ͠\ e]kJdVPOh&ހ>ݞ'V}u۟R"S=S>uWnݑ ` ?B|Ɗ:5;v O-#/*J"RbeMjiC5\ّd3X ݅&+6#[KdFЈ/ _M / /UrU78mwt801nt]qH4UE' ~E|e"h!չw8r~[s %`^!3 Ef6EqEUf9Q?rblYgu0]͠>pٽl$}U(l&+MN #ReQ0ap ;ف:8 3 /750)Aob\o:fBw&F6|Y2ɗ'^>WtwTa?zݼxѨM5kWUj<1-}*qy>^\Յqå .Z~nݞEhJD)N Tt}h60תЍ!{m8.xj[d<^J~cܞ+)c0Ъr*:3ߐ+^diBlƐ,Q Zn `b/1/m%5B%Jq)^v;XJf+aN8ᤊr:'P^͚CM#Sdf%'錀GI=FhAڹjIUeJ,*qL:k{>/cD*$LL{6,~jiS?ȏgmߟzպӿ~5{7O>!scGf/ݬot˚GWU-,g˖E)xYF&|8bJY;#Tp]{Ҙx9k8 ))9 i8ꉚĕ7Bg2|8EXjYkrmYR3ZnmZ2AGq__*he?@+^ OiT\<_ /g;WWɔ{p^Zo6wsWu~)iY.uJrRi Dn2#H% UB CI V!IdE4v t\4Nw RT+I<9sp!.0+<#O.nVځ;L'[!вT2 ΀,5nfQ']MMM5dϛ4Y/d @lv^>س DpרTCuNA\0 Ʌ:W+L&X:6Wrz}ȠK9'ѨܚBgE(/ZEhKw>":K[%q6(*ׯ*4RRҿXA.< דLΐߦ6h3yG”D :^WVp@>J_Xvh(8Z(35| N uL|ܘ#O?~LvEվʨ?tq)) Wڷva};;g׳M_rNZ`g vZaAKdj`HZ $2$ǣETfo2bO^Dc4t8b7*闢re/Jr$'#!Q۝js0}똋Swlu>:}qaEKa "Pf(,&ڙ̢$b=DHI鴩; >hϨp<[ߒ1Wؠ1eԒYA-Tg%Rz?`s8U^($7٦8ȗ9.^73fTqqB`(6| %Zh(yaF*Ea fBu{;0vYq XmO/QRc0&d6&X|<#Zh̬2r' 903p'ڗtG/,$o[c+V>#o}}YԻw4Coyh1/NWA<5Rm΁%C3I0aG%6{Ig^b~W2J&ƻ];GGl |nB_bk=Q{tݫ?%pc: bU}XmE 0 <0 .3Ti:.#QY ;0N=E%\ 5HDXJxf-XJfӥ!L;Lv.EHͺ 8xk>.Nl~9~gw9~W7>nx܂; &kvl -o򯨎 88'Zmն6]L&s,a2>Pgq :"HyWMlHmbN͵}&~ 5I&4Fq7#&6Ll6[M`MJ5sL(" 1ɂ⦝Bܤ' tbS˝E/IS8)R~ژZczpZSήL^S|lVsj2[YyfǞmt-8:s \Rsȋ6oٻyÎV Ofp].ߘ;g%٨ e6R\Vfö` oմΣjx"**a*Sa  _2)9(ṠfAC>Θ>ɓ]2ti2!De_8`JdJ}{/]kgn:J'ݸz;{qIԏFdyu=R(lB>l v*}V`IAv|£$XP'8V$.ōi<혅w_pAfee6%P.ʳ?9w6 5S;惱؎O13E)Mcf]kitv6eLk!Ygfu܆)*(d(2EGSf N,2c5U4jǵkWM 7aM- NvZ|3s#OGexլi\/҆E%/W%:Bm{4Ec+/>7vnEś˷KJʇjCCJ'D'ΗfFg6-2mb=dg{I%1MbDPGZtJ*pء) SR~6|db9k>&|bĚQ5zH3bG );p8ؑvhPtcA[G!#L`d#,_ N)Һ>zoLf@אT,pvsvh_o+>8qo~g_5|+5&\ô_4W/W~Oqn쩇Sc6g'z qa _%,^p!lyS$:CM¦c3HtW.iL1RgN''a\gzr5b>ʠѴ0lٽ{~fUzCd7eÑ 5BTyp& ঙnS k:WWg~;?փ#gQ~Z~hd38IpۿS"Ҏ2cjl -MPSXDng1Ph)=a=" X T) ((=.☘r_i5Q_%ܧ"W<.~%}/({*pODQR6YK[DUe d) T;,EYtP[̲f08"qn@s<QfQ2r2 \m l[eHf橯fѼk .sƒm#\o{dr-U)ϫS似zIz{WU;Ll|E>+ʖwyi.NTlKgN.L-<^] OOfg(s8njD?W*Qju3/ʮYsZƯb3)5OLyu -?W ,Z4W JL{قp3IOi>:cYc,NF ϖ]TxQ&M-%ldt)_Yy94OHVǕ>"'Gb?Q8.=Ԥ  Hoo81{|Myl~歱0t&{^N$ocbd:3h2Nd˅/b чLzӒ!x(/1C_^ϋHU, LcQ1Y |&g#LgPaϰdQ_8:#d#]l0A0&6}=ەpf;mκ.c1u螊{[ VSp=;6%wOuњ|Q/ޮb˦Ѯ{Ȯ+sm]lρ^%p!&EwUWpXfGg|= D8p@)RJRX;؃9IW'b7cfuygGKld"`3 7U-/g⋩uZ>sw\Hj>½5u4{С߿R P `DY+\q9r^TLYTlXJf˅vBwz?XfE#2AtEqF(簃7N.==Rۯ9Hfg7Q@Q} _rĝ'\0a KަPhH(||pr2hR- E.)gD>!D&bTb?MLSiie@[/'ڋ4]_TQU<A{]ђ݉?$%9K0׈EFI;C\(ȣrq\W`$yA+ Յ@C`t`z`Gp@t xp`nM7 wՙݬƸH^#%h<|rQZA_]IO`Z`oD虁=+w:Ż2Ζpݑ2\FB(el_'t˂VTҸ}g]Fr Amdފ)r0`sD'+䆝 L[ gE1}Q٥d3>JX.-}S_&Ѫ_z{wy4B[$)^Pa3jPa̦˥j+CȣvVyV5kPqD?MO'{~|Q]^}eMW}^_TM_6"tKL5.=?^9|ͨaJ \=?nڸX8ϥUz-|Z')C>}H $٫΃Fk#T!$*nNsۜq%y2YZ"J%UjHG$ngsO2*h[cF6'F&vYƪȏ '48N%|g{w3`_}32`ֲ^Te7ܰ{W$tYM]w,2d1\ 1GGڇoTk<$K[mtq[qD#1WrCVhb,ŝo`2*pVH}  2syns؈y ^!lfBeek2sU C װKmhyر lEkۻvwn uv4Q| #U"AL"DHECƇ4C =W#`Th֩T:j$nqVi(CɏV(ݩƫ :j][һEp襨DIuF S'IQs|yr%_AVW*WzQ oT~UnSA/礝kQ T=N0Տj F[-TSGD P Y KAhBЇI %%QECCeȪU%Y+[QTc &,;IU8 녲eYKh-K j_RSg0woʾ;h)4+.55Fq&0MK]'nxJ39u8 uCNj2I>%<+-3gvhg@Җim0¢a㭺 򦚍NeI_Ysx6}d2St2T%ɼ@)cR6y\AQ5/K )#^.; RXiyƥ29iF5y}07Lmcyb8Bi<׹JJZ.;:-VJ4؊%bg?u^!џO'=hG]}KKΓOJXcOv4LStf6$%GN8ٰuߵj1_͆.Q̄4'iejs*HёAϠnbfmEdE&=ޠj,7' $AQU|0M#v 6pkG~oJrD2Τ A6f$U #Sn9A˲$Qq:v;Rݧ nф#ցh/Vyd6b:tK30{)ש9$ <~ɚf=f3ĸdrϮ*i޳d7韶D[)!/M{ GQG 4YYN눶qrN:GUD%9}l:GhS ..ԟܩyfn5G{]X=0{utYs.m&Mٯ\A&PtmF.,_UsDd w8 p،|~CġWbĻ3_a[gRh~u;ۮ U QRA3-$]qzm~gVl5LYlt5z;{V+m̫Wy6\7U^07VpeNsui9YY ƃá +r]SuÆCaTpUMDz6¤"R;Hrw ജd%'qv:p!R.-+G=͞9w`CC x]=@D5~}^gotS!GQr%MJR@FAAHe6 8RKs& }u[: |fBR^0YX=uyE}VONn:VY,<7V"|@*؇8<޲+4'2B}{]uyw?ͿЦo _ o<+@pysOjOyTϾDtwGUкOoyҌ /EQ躢;Pd:%D~%kWAo.J,}} H ( ! (`nhdhlר H+tS#evc:3q&lb*;Dggh*?Nfm]A'E20?&3L&1?Ij'w{`8ns{{}H?ݴ{)ln#ww;yeNI巑ULU̵{="ݾbej+ rs旒l llRת4/Zʊs K(4s[_ٝ,/ /(W07- k'^|ډ|Ե>Ö9Ö=ܵWdѡcqm$~6q&=q2x̵̵_> >=ޟo瞁-O8>WN34{_[,[R%Ks% ͌@7\FٹaXN h)L Y;ut=m`=X1=OamQ)sxe7=E{Tc&[6 |]臦 ;b0/\9@) )ƺ GIuRB8 Qz I4(Dg ~(hkD8`"Z&QWlcD)B(Q׉ ^+D1WfMj ꏈּKTQãDwVD-O>Mt"'.݁;<ɣ>MfX*bJ@ \܍IA)2eKpNs)bpҗ nJԉ<W n15x}=kl~;fjӛ3{8--iW64J[etf3m-T jMv;remM"jeuȼB/k2*3 Z= N:Y_^^kDڂ^iYKH1iP> k8]nc:3Y#ʽE=rC2oQAo ʝc%Ĉ~ɖ¿Zn#?~=w؇~>f+HݫjL9Fb%Z"r/k2$WgϬ3v_T5)=<8³_juuk>5F `0߯uEZ/ yk\!w MjFͰ6[- Hڥ;ÚG<^߀'tH <4@oGyOćom0z@$kft  ^O[um/ /:<h=рyk+֭uQmsD}-Լ`?:06؃' BHLsDt!i ўXPIzQgm:`_;;KwX}>^U#V\R?fDC~ "x3F#шeOpvjG 8SY6vA+t. .qyʰeUƔSxtR͊$cSiʹt Y ~98.>NWN2ޅ<ӟic#BJ%]R.VG%JqQu&rE\٤VJ 2Su103>Հ p "zbŖTkcŧSB*d-t',A`q*GW"ăRwȦGoS6GpznMwkV5ͺ^LyЙَK|%!r#TPJaq*y#vǩqDL T.),pe)~H\).;_5lNU _m0\7V.{H)xVk,א9 7HD:Ǩ$յQ+ RPd|G;ʎ#uAYLh8QBM*~5Ѫ']u h@^{b#@.~ Nu,IfՕ/S*3#(OKRz0Qk cVZ)S\|S!k&8_yr&-zOi 9NFl@M{-`Sv?~M!? &~׽`B a¾{.0$ο/Q1͕ÇP!TiU"O$rV ;鬮Rcc,v:Y4X(bYl/UJXbZ"Ɯ^r-I}c6e28@OimۛY[Ruk?l/KwʚY<ںkےx}u[7{ kߟdԵ+ɦX(1{"{MMyrrߐ)?-ŋ㏷m?[;*vAr}~2>ʽkT>iveCݖd;ica|,,xc~YJt_ï\(edPȐ~&&-ҧ@ h>𩨐>1>1 ]l6ؤ [D6bc.3.șvǦd_ɾkf#=FZ} nMqwgeh/.{Z=7#ZiOk׮=N_KZiqlXU?kfZq`"*1צt׋Mbz1Wks5lf=s2_m,-> endobj 37 0 obj <> endobj 38 0 obj <> stream xZ xTյ^{3sfLr&IBeB `xDR2$d$Ʉ*b6j ">*pTW[^ZJ"Vܵ9 _9{Z{ϙ3`'͝n*F#9ۼů.z;iCSkw[gBɁm}vwm##Ja3;ߖ@ˑ>tREzjk[P <+H]NH M;2yݽ&Zyz؊?^ bo?QH w8 dc__Q޴ϣpv0kd"B xޅ~%%Gc z )X{C{HDB2F?' (Bc "C'4o]q[!`}S4ބ4p@ za?nKOֆ d jVqD8k$5g!V`.zq5O³'x >%kI+Z[4m)#4(Zk 0c?A_='X^9u0WUb%d&E!T D0x ›‡Rq12 s@&,GUm&w.~wýp 0{x'$DGzB_ogU+] W Mvb>N"_)f/g ?6exFٸȸn1h$HRCAt&!1+ =y x YM#wh! 6 ?%m +d  cQB}xOnncȷK/$ 3?x>o;d16脟xx] Oύf:2RG,+)k\" ~ ]xF:rIjF2LW ϒ3xz"tmK6] +M_l3Nd2_#xNriXO2ꅟ r&cۨHn³ KHXG#89$LpXFȾR#\0 L%/FPv%&㹼O3 qLfy5mfX]0iilWo :`#u!pINK2q&e-!`ʘ9ۋd7ݚVUP:VN4 quB*M+q2#L3Jn J&,E!je@nZii`6a酓IE Aj#&*_iS+]΍6U{Φ FoM TEbV KmAn$[j(MKgnDpp.2JeT!jN.9AghR's~rCm}@)9NrD I"$H6 LNA O,TRdť(E,i4L*a'',n~G$qoA4C']ei~,(<وD0JI%&xi)FPj.,cELB;E*:"c抽&z&&[dK}Jf;۰|4Tt,ɩ ]LbmhZ6ND]TPrZ=SWkF@vrOڭ $CI$`NIffR4G"qsUq ܩSČ7 ^@\O3yBZiZGJL۬XO[3=c$R(DwV`MsT"b$ɘJ)1fF%Z,A@ yd(Na)ٲʲⵈz|dt(ɨ# `ź$H軀Ӹ̥38l.,h{i $gJYFhL $ӳ+'YjqNpN~[\Ἱt 6nܗm ˜iN1ٲw ؘ7ol #E F:MUe&MhHM.7$N&4)r[M>`R#'o.d% R7~Ip'ٸ۾+=wE>4n&qeqr *32)XLEӖG~tun::-mt&({<#EGƞ:t{i^ӵW6_=pw]/ b|L9ҝ:1 b "fYacO(Kb 2Hո,IH_ȏ4crRF||kۓ4k´DjB iX3x:Jt5j lH)Afd hp|9*HS,Gi*D`3%rF\0=f{Sq3/ ވK bϰ2Sb ͘7(V4'H#c+.rvz٢G~ʍ{)zzh൉3J:/iA=/힢 !f?l)`J6מ'Nn\wKmoJT'~^Z<#D_2IoNF#S-,{[:K@.q  oqܺKfdw!xa?T{ʱ5x<bBαS"${:6 ~TFJDK0JT 6C?yUm0=\dKu,@aE2|W:6Ba@4~c$tlᢎ-dс(h:!Eϱ1?˱GzKǘC%7u|S&1/ج_Z5_Z5_Z5_Z5_Z5ሰG=jG2ݬc7u,eftJhqA7 LJ0>, LS^39wZ_13u8# :F~D9NDNSXMa700}ߗ]B;q\^>r|YBk䢤 k5k~0ʍ`߂e=8=%Oaz6EB:i&ŔcQazɇBDhP҃͞d9e~b4WYhAEe5;L5rW 竵nuv^_{]jYGQ׸{ܾ-2ձ4O*VOWVs5ލhmVWpZǥָzZp) {{NWFi˯j\yٌ7YxZw3fǹ>oKojk;GOWsGo n:OVݝvv7z-l>w[%eZVu[ 2=dykwkW29 .m{{ݽ~Žuݓ3^@#hdù/Ml e-_5:a|0,:vVu&r̓ZUjty#v伅K.gэ7/ڇ+WB?X_~B"C,ZU_$$"/µ&WͰ qMt/nxp'o# wf`mq8衡sAzhXN(`b n(҃p l籉*l 8phWVdv,61;0uFϘezc<b 'LӦٴ)1'~؏;"PʸJˊYv7oޗ>1]'xy/*{y9,^wM@!r6&3 HG\%W-W QTqT]TU f/nk59GvY.9HJ+efR "sWNlPOygPCŜ Y7K Ȑ|Q>Q+gTFP!%EԺ'+Ht(*k036CR# GҌ:5ȼT+4sLq"+H1š|Oçǔ+pwٚZll8Bg܋SYk1[EI@4P(I@4`fJӤxSI6EL&hM`~ň7l09)%& WA NU5KHUd3TmTIDuC`[BUPU$)0^BkEABnGn$P[$Ɍus*oKecaʖҤ_5}I~W]E5H0rIwTV(` 4*F]_7B&9+FȯP_7"dk_Ȯ­zX3ـzAe'M4)*ظm:Io:b%\oz0Qbf5uF5[(p<* WQ*Urt \I uMǢX'q/۝V+M|6N}$/7u^B>a[-$\BQ#$lL{aZҎQ!l.))c"^&fv,LK%tl+$9==WPȪ V7 J3hG^8/2 Ԙ,aLAPͺ"fتlJ!EBCAG"vb endstream endobj 39 0 obj 6235 endobj 15 0 obj <> endobj 40 0 obj <> endobj 41 0 obj <> stream xX{PTW7M74M țD֠FFnhh|Q38ƠqԸ)8CB*c6vf7kEˍIv]gvvrg&K߽ݚLnӗs8~w :nh5'I۰MzLIOxuԺ߻h>>NAf#>L`cY/kɖ >\@ibx|w&luSVUhYG<1PQ"Ï FHЂ/ǦtvK5eK`-OI3JM,&j-l]MPC:y`I4+p=p .UsO = PO ;p^w! 0+,ޣy&3ОS! )VMco$o{)شYa5o1 곃z ;0(VsOG!DQU,p]M$Cpc~S ;`&t5IiwԻkSH ɖ,a,~ud,Z) vlRL0F.,r0'R _[:d+*T8|nST Aҝ>rzUTao?eߦבZ-Is¬C6 2Dydt-u/wKO՚no++a7!z&ŎQ U d`dKą\V,K {ʼ)N47|2|,R+CTw;c 9K ȓowwKw;S)(!`M'*" UՙLQt'o24s ӛN{ ?E;=&=мtF!ʍ1ouZ]N3(H+J՚dZE>i'=!lq3:ˍ!w)6W>[,D)$[cؿ+i{c}>i鄾>{_b^&hl)3,2 ESS 3'hE.{5:Yyinwu7~̬ 敵\xٶyca߾ue`Ïe៥]b$A'9ۃsn cKrŚd Э F4?w p\B[,GX5gVx^ZshϪ)bӘ%l~KgϾY2]k G)ȓnJk1C3.\=Ů< \o5kk18Le DTj%7*b/?gG_ \n,d9,űY'mV߶mfΣ4\8:փmΨ-7\QȐ$:6 vɷ%k]rP?^:Σ\C'Ilzкt;+Ȧ WJ[KGucUG2hb%K?gi_9),{3;U{6kqPId3arl [xdnt'`+U;|Wss"Фe@`д|߬a5 75_p|_c8뫑?#ߑdI*jN{ Nu~L6P:@WW:AqŪ"aQ6%#Qܙߵ@#^.n+m-Ĭٳ2FGǩ@g0q(8Y=`eG"Lgse;2K Et 㭬[ulܵ`F.RqG*[\i?{>]<˾U7gE>5PqiHE "G}ơ?Q%k-Z.Z/.Vjؑ8hҬUJjtUPgNLab|L~A>&=>z7bt0jD" 3R#@8 FVtZA+2QG`4@(iLZVsw#Q?" ^"N/Akzc (N#s(|Os츼~g@h?#/3rY^>S[%)G~{v$4 SrGrzk#!1uTrZ*kNtTQR[F2OǨsn8;=F0Ahcx z\Wt}qEhߍit"}_ҜEi QZ ا>Ҍ1QOًGi=1m6'XR6tMO`/f777MrT]Zڸ1T' S5fGnh+mZ@ր?wq!4'W IfHrd_:T9_o|?k$j:_ۖ@P9PmtpoP4B4H DtKtQ?[4MDAd,%I@ AתڈW VBDI^3٨!dG"Mkev5D"~4DY~l. CFP=ԑ,ʛ,R4m4tȣg=DO6DF{| ]ڳƟE7p/^8/lz<^<{ ?+^~ O8i <%n<'2^+n~|c2hK2/ׁߗ{2>/{Ӂa;:hlxЂjS7vp_}{)}V^ {pw,ge"{]n;3?~w ;45xڍN~&VZcxk l-2nf6w`ȁMIƆ*8bC7TaGܴ 7q=c. R먪c-yMŀ2nFF_V˸Ώk2>e5nq+$'e\U2\a+-ˆ˗^\VaXa2.YKzqX.|a/.'q0e|nmqgLKgygqzI"ދ%ӌ$K:iF:xq1N%pSXTEX8 8ņwsx< KTɶ8<˳/qYfY2q4c&_=OXT> endobj 43 0 obj <> endobj 44 0 obj <> stream xW{pSǹ|g%YeIm8BI'` D XX&888JʭJ)M!)鍚TSBrHhJc24-w8m0w.y?wrݣ0Ȅ-@Tvl-1'jgZmUQ|xֹGp@o7#$08`$plWRuFZY2ˈ/ vE\WП|@>h'6 w;U};#?HJ2j>jFt=W )_0sѐר!ia ${ M)> q8JYѼ2x Njs`)N@+/< {$x~!8 i|^%$f4)P)iIaE葁_dF~GEX?@3qxIP/z{S)"VQll7v% .9 ".ZnI{4.K;&vJg#U-GR_WQd}Tx}Tlo#Y|}f9T Z|G0AZ "JC5`X@=D(1(Q,Iɽ<)?;=%b^Išdn%51'p&mHn;O5>%%i%M$[#RHL%KV=` ~-P(K:ꓬ$X,%OK|.2 /+K@FRe:_>g/NZ183'i\#̒JIoT$Ϯ%8~ʺ)ys-DdOP IOr.gr`x`H)8)O iA 4Dt/I5j,P.Iq"[/H~& EBn'AS%]bZxXsNiup H[%X@q[j#7exf\Xm#FIqY6! ^3gLd];gMj*l|q߿g0':jgUѹme=EWX#<)jYʙ[=wb *BVU䪡7o/u)|#&k+gkCr@+Кr5A8Vݐ2;B2Lhʛ-+eldVUڬg>%fϙm^ȤԉK(-7XChXm|[3޽GaK 1.BbNqU\hQ6]"'GZ|⬶PE N"Yr(Y !0bi&[25j*d)/܍.v錫+RU03=#)I.x&xKW~opk{*浵ub^tuxWq{={6|ս  !2ԝE\nezmUVGa;V(٩ӭj}oӐS\,dkOʭs(қ__&5BHY |[ u|9y5?2>4P5Q"Å[':]lZ# A+i}=qDߜv^$̂vБ7 xJٸͦ[KcLgIZ_NN?Mt{"MsB>u$>MaUDuPҐ?ƋF3 4 zݪ_Od&͏* Fm$!t9yl!%Z4j:dh)SR&Fojޝ[T3 !?mkIg *FlLt0|\-K[%:B~IT}/Y@CjwB>};~ ~ &-I 6|FwF|:O&6|J'I'DsMoc3|ě$8}O43yQ%+LBj|^7N1)nh`is(}@+ZВlr-Ќn,MdkJQ`d4^zZiATH#gyFd)aHgݴ  endstream endobj 45 0 obj 3210 endobj 17 0 obj <> endobj 46 0 obj <> endobj 47 0 obj <> stream x8 tTյ}o旙d!gH@3?j'A1 ƔP^`j$B5M@0F[bZ@{gDtkzs眳>3 xfVrN Q`S/k ,VO"h'&_3=M$Dm}p^}ґeG>"iЂ{1ŰJ!  4 Ha v@5e? gap =L~lΓ'k2{= 0u"0=q$yKV%4H_wQOkb %n;>6NXGX7mx5<`ҀlvM,elX> = Hf~K,ۮz HZ - ˈ]l^Y ̠qlGx @5jhxDi v|5,U e=OѬ,H:3̞'Au31/hdIDA-.ސz-ϝ#eѸaawZŅb-Evc[=&O$&]쬀,"`D&zv:h;U\jNnNN6a.u sy>vYQ{@ x2%\Yݬ}Ƹ 2$f%3Z\-KZ\3\%d:DiK^2y[A\w7/Xh7*rDUNKIXB@)(aG.̽!)+ۛvveEtR+di  7ZZX%> DTS;B!ĺcdg^*KMw@@>e̾i GǁAOms[" aЧCcZyr>);hK.(t&=0v/>->CD́1F=O(44zT?gTLuK͝VTsK]wUxs6g,\yi;N^¶+m$m  hk et5۩i[]/E]kt1f,(;c9;?4bMOG>yv5ݚnK=(Oq{FtA]GCB]a]ᦥ,v찇L6f"ȴ$eNvKM fBﵿ+>\So}o]-[R֓ʵ#]Bm55G7~g-/?ڳ?ꮵ-Jk.07iaY4Fl m(3ȷ!ʙW䣇y^fZ28kMŎMwռimeo|~͒$OH~n___Wn٢s =q0H[,҆6]/vی OQW1=c9wGrn#Hqs~,7<`}K邭ǎeIc^6COLNKa#,H`o3۴^ CEVaeɯ55vbb!ij0K,y7JMͭ͛0[rnbSYěc8~{{z {R=u LV u?S1 ci8Y8riI% }}ܾʊKws}7{75?O_*3#?>XDw^t6SaLNppbbnߴngvuM`SӧWv$wPdGnfiU/B_ש3! ۬mz&0'H'fؕngjZjU1bϊַ|v={x_xjxlQP|B$AGy2ןG[#Fy#[sx W=*r6SpZ,˦XP'X'<ގ {h! Qڴl7ZMp͠tYM`L)Ck68O=.V<YIs=Oߵ8Q~?F̗Io *fCPz5eC():2M&\ީ~?`#=~ٕ$qﴙu"dވa X|HXٹs}QR>*=Yr^)Ly՜v v)MYY `mF>l,9st\8񁚥m{ڶsϖSߜ?}yػǏ{l;GX"4fI^~*5"yF:EaZ).×D%?uzfL|e쫍Zq벾=&*?Mع@9U󐭠o p=EBc@⃦^~^AKP)Vdѷx,`a \eZ)醜sbMw5L1oܪ(Zaq^IҚq7X~n֠;lg+;\I~^qX'|ٲUO|R)|pםE|S(hgבY)P/{$ Li,~I'$Άl cb&}hM2oijrפ*WEIlipؒX6ȖydK3b'PY#(jA0T!8:=S^BZM^#2QKv HCVک'SBjUuL֔ jV#k٢w'z-bu䖸W3=ǫbYX03Y5^<hտr^KUƷ6uwԫ Z_,5l*?RC/CdO9].NjR2Nj:5ݷMt_9^_Q"D0X2Qvݤ̚a%_\0?,/;0REƏ`x MwO~:|YWDp?#88, 0Y F$<>fmmz'5fekvUq9erhkqU]WG‘YQ_W_[ZX3mJ"εvuiIҪՋJZYX®25)S2t7.%ѓ2 JKBDEеVWue̫X^XnzueeuPPGJ.:sR .Jhu0*ZA %"ʉRRrhfI.Ve*_=A7TKZ*{y5$WT!aUW"7ҿPգPJhF[KI"eW@٤4$(DǣJțzzj`2$ӳF}7J &=i8U!A_͢.I}x-\jg3E~ D[ʯ#2Ooy%]sW^yJ":~&?*NpAfUaڛ!M*3iq, 3m`f<ʥUIE*EP)̛Ǒsn!qom7ϟ˓η&ّҹ<<ώĿ},~ǿ;~فd Aދ3t*9~3O9?*=> wZc#QHU?x/=qNhwwqۈV8lf8nxWUc?fJ?nu?mqi#6FLx5Ws\UoVqXo>Άu^mk8VWHXU9JQ)cE _=XƱc hcXh,X 2.-_%,c)sx9$"LI .qq!|(89Ҝ8{MYNiǙ,l'f!k"NϴJm8'x:1sYʴbO¦yM43N>¼FkB5aIF1Ddµp*)p2t pz N.M9NHK8pi\L!c 1pG%;1I"%`bBhDMX`LPǎrCcp0Yqx#)e5f8lFpt%w#1f.FhQ#)#hU"0cG'P:CRH&:ɑv _m> endobj xref 0 50 0000000000 65535 f 0000000016 00000 n 0000000783 00000 n 0000004227 00000 n 0000007368 00000 n 0000000722 00000 n 0000000585 00000 n 0000000080 00000 n 0000000167 00000 n 0000000279 00000 n 0000000383 00000 n 0000000491 00000 n 0000007546 00000 n 0000023138 00000 n 0000046505 00000 n 0000053676 00000 n 0000058417 00000 n 0000062562 00000 n 0000000845 00000 n 0000003689 00000 n 0000005003 00000 n 0000005139 00000 n 0000005275 00000 n 0000005411 00000 n 0000005547 00000 n 0000004486 00000 n 0000004833 00000 n 0000003711 00000 n 0000004206 00000 n 0000005683 00000 n 0000007346 00000 n 0000008234 00000 n 0000008425 00000 n 0000023115 00000 n 0000023870 00000 n 0000024056 00000 n 0000046482 00000 n 0000047135 00000 n 0000047329 00000 n 0000053654 00000 n 0000054318 00000 n 0000054508 00000 n 0000058395 00000 n 0000059047 00000 n 0000059241 00000 n 0000062540 00000 n 0000063217 00000 n 0000063402 00000 n 0000068963 00000 n 0000068985 00000 n trailer < ]>> startxref 69080 %%EOF ./nsf2.4.0/doc/next.pdf000644 000766 000024 00000174217 12422512322 015415 0ustar00neumannstaff000000 000000 %PDF-1.4 % 1 0 obj <> endobj 7 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj 10 0 obj <> endobj 11 0 obj <> endobj 6 0 obj <> endobj 5 0 obj <> endobj 2 0 obj <> endobj 17 0 obj <> stream xYKoW4 N={vg=$|]ITHʏn"iʢ9 $ջQ-I53`NqR<8ND0DIIah)lRéNN:'uL;8rh"ѨRmHPm *%8siƣlg:':g)XywNjWs&Ixg2%9rl"ѡ9YZUͬ59j nXjz ȕMG 11@=k2.VzHg)Ιf*tjκHg*#Rt"eh4G 0>/Yu>\Q |9wNxjοUW UE~ 1#cFsu?n;48CQ: E2 y3ۓ*'GۼHl-W|I~~WUzR?,> \$x5a[r|zCq-5Fs1gi|wXv zx2'dɑ7_.l?Oi"{^WE?w?$ckJ6N!ѵ(Ѝ^GJ e>-ہq7wRYĠ&b>|?2:4 5ts ƄpLT%pt4^櫆V6IchW(£ HJ%_ARɀU"KmBJJ'G[|T<ď66Q8(P F-UW=(y(g%Pf9j-wݘJ؉8龒M rP|(6 AX͸0 ;(sTDDU2UO.:;=g@ؓ'_ t!QodHf]ӓ0rDgsZ;"s>D%A7hZ}}nt|deH #:U]̔+ocڀʦ*߂2X5!, BR^Xn@i#~IYSls:.zƠmozAYȑp\X-d__@ͮ")XOׇMluϖnr$*A2V3X>  96H,=4D me {'1?S>2w,y%Ņt;6+hPB٫+D¨,~S@lxoItOQL&4: ˲տš ;wEw&ˬܧb ?..+9C囖`[MGjI7ż ]E s)̋dU[ؖ jFBXqK8Ezdd5! O?awG3xBK2]j ּhlr,.VjYp]zN1: p| R٥-|=rݾ( >&Oqt>QP iX7HgWH-foOLIasfPۺF=sjMCɓHn_a ;BP TП0dsGI} V.{;%b]yrx Tc:*M*"K\`!c@g@Y͋ӯ1 &945f}$r6AMN5pzM-"Md+q_C-2atL<2t'xM Jfj=&+Հ {P~g)e4"cv{u$ ; !t endstream endobj 18 0 obj 2302 endobj 26 0 obj <>>> stream xuRIr0BzT%9x.!ؓT*'-hht`ACXCd3<Ȉ`Hjܽn1U\h-CWk!4ɔE{R9/p:KKm\pO+]ih؜ 5(*PY 9#3]0TDΦh?tq*$;{A?cSbrYМTaejdEI[4Z#d_ )>JKmEmҩW]ںЦ90kiր dZ;/ZzVv}&X˜qc|T]~ endstream endobj 27 0 obj 303 endobj 3 0 obj <> /ProcSet [/PDF /Text]>> /Annots [24 0 R 25 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R]>> endobj 24 0 obj <> /BS <> /Subtype /Text /T (www.princexml.com) /Subj (Prince - Non-commercial License) /Contents (This document was created with Prince, a great way of getting web content onto paper.) /Popup 25 0 R /Name /Note>> endobj 25 0 obj <> /Subtype /Popup /Parent 24 0 R /Open false>> endobj 19 0 obj <> endobj 20 0 obj <> endobj 21 0 obj <> endobj 22 0 obj <> endobj 23 0 obj <> endobj 28 0 obj <> stream x]N0~=.ߵ !./$H(?B<o)egZ#Iv#=l)E%Nld*h I]H)J,nn֗84VBAbM.N 3>mzI6 V(`-X> /ProcSet [/PDF /Text]>>>> endobj 12 0 obj <> endobj 30 0 obj <> endobj 31 0 obj <> stream x XG0\UJt76-,B#D^ʨLH@A K&Qdb&Yg$DMb$\F/s3f2Y'NxtwSuNUSuԩSau .|Uu-K~ 5-]צ4OGHZe*) /_quݚJYPW3? qFmrG7jHtʟAK>F46/Pybu!, # \@"HB3&cEpP|B"mII 2n*}^a>ħQçS)|QH`pr$E_A,g` uȉ.x<@<q @ ;Zvch!yuoUK~h.cTfBԀ@G"aC }~[|sjGAŨ__B.~pJy݋`14Kv_PFOgA&#mAx @A!l$5\pFh=ځw W ះE SY)]z[0_ ׆J¿ KXGB[ÏLC@#a%v2z'loF|u5ēMd>ʆրh FG1Q?q"{H Qπ(tԆB`?N`ŕxn_~ ߑyB³@.~nBAOn=c+8wD!)di!S9n6w/2_Oo?vJuR}B_ c4`O}93^Qm~~Y"N!H9LZAO0 x$_?8KskǹÝ|͏0Lp0_xZ8 "zEZMĆPc(ەnM=v;߃BtOx_mx+%~? `D}'uA >L&S H伜sram&~>5wVɏ} {τU~B8. K"$1G\!>-YR]@܂p&H $( T$cY`>X+Jlq$ AuY$xbg\>ĵ8ǭ!t.rS ,"qF_o@Zt-oF7߁O+x>@t+_^7_&fO=h7Ot qQWl3x +zHd&tF8 5=krz䫊'M,PX5֗9&#=-u7ţG%'%&Ļ8{-j1U%Q9ةiZ 6yOϢeoT hP5m$M@edHJ(ԇ(U+FYc^-nWV~wZ a,b pr-kiwL- jATNoKvN !ΩM T [>5-ԩuʹUS=ꬱ\Ի$S#AelX0Z کuqW-uUj:F-8o:\meU[&r;4Zܱc[5CjxI`@5l -0FgBg_w*]o4 ;hFO0!A ڎU^O$[]WeG;m׵-Yc1v-Qh4 1Sbސf1; "-@*/i&K'1paEJYDZOBի ndM]FLQɐA D2XSq2+d]C{[PUO{oG ޙvW5LOc%hJoۥmWZ mAU`RV;k4UBZ2TKK- $2kJ`<`=:y=$Rgeuʂ0.o $4CCJX$!(^4@0B.|@lYŨp%zb<1a0.i\%]@?!P 5=LFݿUj8/7 :aADE*K2dͪ%**Y|T@b=,1"5\'gS8/͸.sBHN7F}dEtseGd#Ŋl17e 9"wJԍQ ΝA%%b+`o)Ǝ/'$ns:Hw.]tGWxCs?|!5?z/t~zeT2Dg]$]]Ny=mيf2=" ߅GT 3G ;+.aK:|bҲ7o/oqhԅ D%gq5 )Sx0fm=fo MT!91VIkxg(1V#?o|kZp=Q"dz!tCn_MU!x J˥|AɸDEסw7]']'O&eeIeɋp&b2„|,,A?:smKz,ydنZuw$J(YNZqj$[A넮Mݠ!C&htۘc$F9XA9p@XQrʺďT9YԢ|kNÖլ)-c}5{Qr/SDeZ"^ r "{UwlAnPIb,*jṰ:!hH0aB5^So+)yaRǏσx%x)o}X~ WځOc]%,aϓ~v/)=WF|Xj"􉞷58Id/~;,<^vݎģd5_瘰nDL&DcsbI,UoD_<>XzjAqNG')9d|LLQNMtAhFkPSU)*(ԇjbSe3I!5N&y4n!oYjj{y+ܭfL_f $zu[Зx3to4eq_pM̬eϵwģ[^<۠? /z"7^UriXr"=<(=H.-_ qknfkKX6IgvxO Кk%Vjp,`jFN 1EFh2vVt?I~֞ڬen_q7Nx/ ^ }o\Z_T`-z}Clfj#? 35]UKrhs 8W8Ljp|*]j@$Vpd ؐrM3i@&32[Y_a[ Oۊ#7M%!/:ch͏  Z^R%MΕyLdE%8͐k WOQ$߃ܙI~1*S]> <ܴ *F-[;[w$*SL9m1Qtõeas&W[!!뛦7[$QMw'`Jؑ%*6lsbq,mte:,ܭ:ݶ5)䦐N[TK6p%dSMhϋ_?{p }/>Zs$8гxx_f|N[) a'=+2}>*rDQSyAsReNAt瑝zn4՚SPS4x1DF\Gn57;2!kcE ^Mbgr:5pT80 %v P)tjww} ~QL'uJox5 .+Pa=>bQFopAb {1;!j6ӝH*Й硿Fim?m l!^u‰r޿8;zdp~O 2>de,eJwmPۤ1ۍwض۷msnsݙ`l` q{+.A2)YH?bZU-rZn\ܒܑܙ,jgI5azek~WwҦWLD[6 Oey-ލЦбPoheW_>~AC-A#_!HmP8t']]@^O^{Z˅bI5(Jc -us^>id@:F1),kO`j[HLbxRŭ-^ysqK/kB&ɜ少y5[55TyLpYtzl\*\a+/޲;Z\(3} _ sS'M@ϸ@g1n)35 4X|R7'Pcyu/k2 OyB”joqm)cw&m^zbr)sSz_Ny˯IY5VW)E&B0yWM7l7H٫3=ILjɑ"xU\zovfq& (DetLҌ͟u\k.܉oPd1;SuRzZB;W>&Y|.Off[߹l.XXHL 8 z@N[I,Yh׺u"ESloknDu 8T2ͻW}&EEnz82@\N,ޔgb-a{g޿n3؎RT-:#g8~W}tﶍs3mٓm|e?cZ ȟlձ>cj_c'gi7GsJEPv)sDBt&ytU46]\IZHEx/<]U]V!P~:꓊Y G?fwf\dY@*ދoɆ>/p/5`Vuj xxxA;_ℾE|" A<| 9e }$G[OC {$n?M=Bɲ(&Exl}}c c+|-/H7w()0rik>( ?ً 4C#֧}利'Ax:Zx(M-G)G)ɒ'&tswެtP3ެ"{ ΂|v)C5>,WkEyٽNrs0-Mlt)ӹ +.x^#x|7Cn9isY-[p=Ku.e~o--X;9F2DikaϮG]Niqu]إҌpX ™ʖX:,\!%luOҏi γ7l/GbMϧOWhk&mPyG0{ә_{_x>FCc,3)>8Grbو8ER%c݂΀=a;5FG?o?mgB9%Ҝq%=vae?i?kjvs.^(_Ğ}ԡ]3#HOϘ-bxyc$ 7>+Ɛ I3]KnME[qZp/)S=OvЏ,OC3Cz'I3t$R3B4Anf.i'ixxARR4)S2~*/L]W*uE-V??S/&$Eu%4^ՉlFuzW 2=ms8'z1ƏyUa@FLxd!BnqsinDD!|ր);ِ;cn7UA1_9=~gh57jوK| `| 0-x3 =%۷f0fEUS3~FqЏwg~T)C?j a_6/yؼ8.&5P3Z mD- JӼE6/[ p-66:owZhJQ&ц&E15Te@Mh)6C{3Z}Kְ轉IYͨXu6hYPjVJWCmAc}7Yj0fmLZJ}  aLlP/cZYl-ђlYK#J=*\d>Lˆ54j&t`;[Ȝ#:]dmcu͐׳6ơkPdjy5M\zjab:ǠWFzHǠh[ԃK}grS\y2] 33gMP 1E-}W?rCkep-J3n#4lL"sic Z6aU346llp N~A3 c7#h..csx[foqǸ׸w oQ?(E(_gDkG֫;X;jng%)ȶAy6_˭6&R31lR }Y:#>\Sy7?ė _WEéؾvqqo\[,4OC8>T3v46m\ p:յ=B0r R'$ܳݒ)Oh3tz}LgYuP>T.<'E`8rYK-A(6=@:I?A C⸧'SБ=W+8)Sh R=٭O2DI@n  HaH`O@pOpnkmDGӇ}}CV-yz{UB"(B}t{/݋W1Vt<+w ;aN1+(X%< VW^%ha\yp.ꑉɩw[y0^ pqRѡ+跭=h̃q.FbLP`[;Lۺo[wIpus@t[q*f[1*5r ` @-nWVn*v#NF1{UwZw%1&s^_M X_wuMCi\ʅD@Ǜ̌~`;`vJ퀕BCvh49M[vA85 (!3zxUbMVT2W\Fs^1n-ZSں#\&nW"eh 㜑F]c\(*&sJPFCNR%ɇt`wQn>}ddS?P_Dn =r 57P)'<zzrn ANDwjq&F#4B^FIG|6IDnBFR'/CpqJ <DRe(y@ @\0-jN0yݶR<9 D(D6Dv+xTs]d*S,}/R!+jV p {_BH:]d{/ ꀼa0 Anj=˰́DM6Ct+! ! Vz&--8Z8Zq!QZZeQ Q8Q8*8*qTG%pTG%Jd:p8tЁCq8r#8r#qG.pG.\eph84ЀCqh8a+pX8a+㰲iD98qG?pG?~'뻸I`9 ,'I`9 ,'$c9 ,'dtmLf͐: Q>>c}̼!Qp#p#8NN  n;$7Ґ[q g-c܌cp:-^nc&Tz `r8.:́tfH{ tİ)L "͑HpPꗈE#E/4ׂafȿ% +!~~~chgx&>ĥ iJ7MvT>& `R^> endobj 33 0 obj <> endobj 34 0 obj <> stream x |E0^U}MwsIz21@B F. p* Ⅾ^ Kue`akU5x@fOUĠ3鮧 !+Z34Y{PB5c2Ȼ8BY>,_8{YoD(Binylc9o*du8Y/>cMHrB{MMW w!4H_شY(AuD뢥%nz;^|B #::"ELJ8xADEF +Q6dwh9]nh?`p$@Nn͏E%^-?Op @0gp|NTKszKܑ9ڎ-izvZD둈@ɍ P~'QzqpkÁ:{Zl( Bc"t 8MEףjt1ZZ;ҏߡܟ]HE!4_ O;BGy/2)h kqzv'A]}(t$Ih}x7ZٖnKZԀ\05=*} ] nF>v1lNMDAT.񴣿\kM"Tj" :cd`C*h"qS=q/ ;vm'Oex D"Y};?IXn$FIOہ" t?z`:^dMjQ_[Г{8|WvGd@o9by 넛SSRM}.OC@B#=~b;|u߂O9+0|r<@(|.Uq\=z߽?O˅-vIEh~cA7n*0RRwvD^ajM 8n'z[w!\fx10y9һ賍DX{*rI3YL6;H;yI98/W fnk>ŝ7+|'$?/?? @\'v%ΗJ6i%=Sqn 7ۋn%|yɍ"d;@@RH$\Ld 7 \lMO@R˿:`lZhE1"5?q}$::}%a>`?$sc &(=_Xn>04hjct=G:A7{L~6UU3HEP,Uo$n܎FW 0'x O#>䞂!F'Kk:8&ó'8*Bzht=0%/&Z@/-.N h`Ǡu`ny=u ~ mNF w^֧WA'6M]ZQ.H·ba9" K"{d<\8!s,ȿƣ鷁@nIt:p!wUF]a\+#4.x:+hNz>C$%mo0ޫQ3$kNn,n4O0Ȩ;ځjWWUVSֻWi0/GܜH8 }^vUUd$ W*]AbVMЇnQJ: 42mM6:ލd}iWfx'+Woo'3fIt94{m?\n69nd} nGN8'g^}-O$0ǮSNL3m|D3;$ p%+6B\D˛:'],L7$<'N90L#'LٸQ92 p<09nCA2ב>؟6P6V32s*3p=|(w*na1}ƍMc۸H^:187ۆ\Pt0n72y?x6 wL7^PMޯ#dRBKi!4Fbnba V<+`2K ,Ӳex`eCu {r^3[@`KEQgN&ݳ:w!3HRnUjiD:P i.ɢibb@j8-q:qO99N7tNwںھ}pNgeu QW2jskVKdjslXי~T^J?͆iDV4\2큲Ð-vvM#`v_E!<;?1 _C|+|0jk N&+jsSFI?);uԷ) ԇz4zH}Rcj E Ҁ1`;.Kh+`ГS NhZ-gSNWM>U^(WKkq/)1*t8\p8Ǎ鼸lP78^ P ީKy |`cx%B\^X/+ݭ8FQwT6>2F&ySs)cءTGTh7rɄ nD G}[s(\b,0|Z"/罹ue}V޾ǪU;v\jDyIR`oNg:u9欜_Gn#-S<(N{ a*Lp2FA팠e#Hɕ O*6GD!x-2Yuq4?QԐƜ(UTT3ޜpϿʖW*_FV ^cůdxIvj-NQVr:!k@!VͥWs#vk= Vz$D,{0=Feu|2/~"쁆psM&zhm{74MEEUD?V iÌ~ +W#Ez=ɬy}`{_>=1 @ l8asMαga}*\]l\ d9IPTNBV`8q՘hjO:k(fkjNX~dKUVpj8>'6Qu PkXD5?i&`,T g7䜘uy/ܞ~;;wwuY'yLZ"sMCꔇ-p1G] S~vÇ>1]ֶ5ʖ׫U'U8T+ÔIJW"]ϔjEQ cB-ϺL"QcaGK0EwəbS3gjI ],v{>N0V/~ ۸ՠnY2 92L: 5':OBҥSPvN`YhT'|LT`^gS!kW=XMnj== L{ =#VD!.`!ӃO:iC0U>^'kRM{pݓEm) VrQ>(9tS 0gm)H?; -Bي=8uF,Sjh4]P?@\575NQʁŌӠ@pjU'=5 Oij'.;-xW,/?b4B0n)p5``wlٴwؗ5>l{.JFѥ{R>h4^e_V0&د*8!$Bj's.N*tQ@s|VU9K nݜsSt}"h7jiQGU=K.DHlWdk$Q<rƞ \[}Vh&/)2 YUɗL'S ::OuXf `蚌rIy㯮D,~JR+pD>_PPHBr0MR 㠇ooK߳)8jҒO>eꚷƿx?S7~:u"ٍ4PŠw0jo4s<}K}A8ti*Ea ka 2H1+; :xzE G3BUS{tGOA`v}}p5{] @DZ=a/i,ė[O(0i0v.+' 0ø axo1FBY=L'KVœ`9cJ01nQ5Ό:O] &ըeyJm`!|, EN&7D,DBe[ /ģ8g{pʕQT S*P^y*{ w_t?;ӺzԸlr(jzCo\C{yMSQiiQfk֖شJ]$JVԆ2ǂ} . 7!N0|~ [~e˯ly[-ߩvJ߽aPxImWCLX|EO`̣R+VZV'J! >K$Y,2O,YxN9;5-h t`l4jUP- u,n`ďψ߯52:aq.f_NG\3VgEp^}>ycX a5k` ",7AZcj$7͟0sR]ޚLO0`K ;x#^9Y_0~t~-g5clȁ=<կ}=pqdRms{Z`RMD r+W Zv`fP"HYhؔ/"ŹDtBsp#Ai(2 ^XDsI R0pF4TY% %0o68EБ/cz=~x,ܙmڟYSk}wnqp􎶇k&jݙ_IfK/X:d옿)Yyg~ӭk.SQ1hˏ,]Xrn4l#/w{hgD2sřhʔ%9YʪгYbҋh}{NЕ'>Zi`U;oLOߴA~HؕԠ~WEh"dtsҀv^ɰnCRXGz'yg 3˄e֫kvY`HB:l`q@Dbdz.= 445xaA!0x0Fb<^oe\ @pӣiNléY. \@s8db!Чt"Kid< g/}:u|Ӯ&BP+0zhOaf6K0>g k:­kPy#G9Mۥ@8@~'٦BJX K 4DqW w)J? Bocb^ZlBI*8[w].> ڹ4p<6l{dQ R>q5_o`rU[wE+]dH-ʙBi-W$KEj= PiZ& lϵS[ͮU{p]^o6*wg\/Zny3sO]"[װ:AY3P y=Z@qE*v i""6dQaF 1!eM;aٰٜ.[Y݊Ee֑AHͦ[9)qmR̋հklR*ҁ;N#[!nhc#A%CQ}1L}lC`gCgm9,hjjʕC=+3\Yeb*55,{ \шpLx@p%?\?;BHۈpp>gC8OYopT]55'zF9ZU2(DJ=zf +)8+2NY?Xͮ.<-/כDΒ?6,{)^5DU567U7"9GE2Je\Jm%%5~Jl %sm-%}6?- * >Q/lѡy?( \::r1#UTj&R(ϟHT5N'gYZ+뭯ZtVW1TˣEŤ8RffbOۅ-oݚY[2~54;[)tnpľ]HDBRMOC 7iMHd3W,4J\sw>7|UC7\2-"M-_2D=v-TW:~q`M#6%ʉs='5 725*4(255xIɵ R{hȇ6|&mF4G  OPj w .7Hʹe7-OQʬ3͆m< '*ij lUhQPRރRF)S"F>F/TOؐub~i۳ y`P۵6[ EΠK"f{팛qn\Ooky쭸(aGMy`k9q W o"?;e>A#mڂ|(WcqVGD^yND#w`2ӷ% &#yTL yX$EL LՓ ~ɦDX韞afض@9|Ei N'{SlaZWi.x4(K,$MvSt1%k$ɒ gZZK޲~S/rw͋U2qggD\} J"QUO\rN0TMxJc5j?ug4Y|;M[K~~uaѡ[ōK~:MdW{Q-DQ6FQf+("24?bU|ފx7~PN&2gj߭L}u(ZD7՚#(9p8ȑvy:8B|ښ#B[r0`L.RT u4gzmim&LOYRCL=篪pXCک^v͆h{¿U5_n~U۟C3T݄k?]}vG|+xhi=B]Wrmaurl<+V-{8#GD3dd\獽LohxiWgA&7j țr|PH>)KHΓ[Lq9-+y2XO8YHD^-V?ŃI ^BM[L3 }*4l|6S!R(і_boI-٠e%l`eC{{;#Gxęcӏl.1@BX'~ HDRR#lcl|8YW ſ'/-^QdbKGDE-з% H,R0dgѕ| Euh&08"qCc@r=Lő8`b ZmՓ֌lciDތˁyY/{;! ݳR˱s&Ji)<]j(riNlɩi-v,_މ郻lt&jD3a9+Kv5XZh>ョy<w7+lV f.0}e$PS_'8nKIJéز|usyL5|sވt-G?N'.OhV imT%`lA gmCۛ61K.Ф%BsuU^4td.c9 b\dqAnRmqB]x[8EɁ.s\,7"zI!a1 j8'qc&'vc 0o桃ttN6Ɯ,@[Ƌ 5a\0k.L;isa6K&簕6F´="8>0ɝv)+ER8QK8E{;Wtb3Q$^)%.\8gQt-%.t]l'|!Pцx>oMW O@Er)KR⅖IbebTj\|UHHTa|j]X ,gj \ |3W`, ˸ 2|YhV[2<aHݯI, fC -9\4>F&'t- .&,ֈ",Z fp6I!k&Ɇ =hݷB=tڒ ts֪h,z:ECOcT޳vnƅHs^ :>G.Z^yHt[c9 rZMe@xDrujxeE[> AI-h9)Mu9_E_Į"{ਂ5P 3FO R d?e -l]c; awpl\( e-dd|N<(eɝ5=Ry=wr=wpt򏮞r[oc+|eKwZ7wsm37]< CkR)0j($IJH*y#r p]x pcܷķ]_X h$ߚ֐*Edu i!Y|"i,q` ET.z"<o@4p4:V;\es@;` D8DB >k*uL{,s:Z$ $|krrύ>jש_-L_&pNT䞉ϧYZHW+>smb8`Ç_zw^3Z @'zXc|%?v6YD)r& n&gm`8{L4"SDXs/0GsBk8#ɾWۯ9D7׌I0Q}.? ^/ptEPX|Oy<`R~s*VOd(3& ʱj*OUSSms-s\uu=^ۨ LQՙEb VVyzG=wyTaVhўğ%bY abY E~WnKaܪ!=9!Յ`]pLpZpgHPt󂋂mA|h`nCkDGf{x|f ĸԜ9$'xs &>>5ܔ|¡TX6`A]A8Y;A.-{#5GKp } $ uIVNXbT6,'uI9i2M,jsS=?:v0cGY67!ϨbɒљdrqrT%鋫7e>t2֓Q+7&xJNͥ5N̷a$Ia,SQ{,c6X BY|i92Q\f ꡎh]3UMa7W%dUWV1>8۬K[V7pϤ9>/2oIbxEkF_YفK^R丕ANrSTN ߒa3G \q V1V9CSZ>6W܊ӒeN>E;2f,OrsoG8=+vTPN@~Ng^ݛML}'DSF~bꚄNHkhk-!k\8/QىC82hŠilo"`<:xNH} vf_! $pDxk,N3XRܘY,L0  ru޾|MmW Ǎu`.Sѵ疾Ǎm9s Q| XD,*H-&B{{,at] ?S%`Q~9kdp3+-D@gR2h%*;x% rnjkzW"Nk1*J R.DÕIxLgY"_W++x=Y(mlDʷ+OG3.U'z[ }AR@>׋ CU*4CGD6%ot(-c, +%`U醠8''Q KcT+,+#$nmLQUCX(bk0 yLk"d:1p(7u] ] @牆KqE' *ُGG>5'yWS D MXA6X:F"B3.>E-S}M`bxjcS`ռpn. J!  Ueub+SDLE?pX{Qnc6: X!#9ourN|I&"9fx&[ A#^Tenqiy%J,I{%XڇpECev wp]5OiZ)^%-8E EBW?v]aYg8NY}wN?U=&ؔή ۆw!E%GN8ٰ5nHcTS-e+a {ܢ:J9D\T Ha˒m 5g mYQ,( }fȘ8KNɢKN+)HA@pw]IAK.pZ6=q#a#sZFp:ㆢQ":(d!qEIs&F'@ߋOOb&Qpԩ5G!wg ]1-ovns`GvǡG/gOȶ q]R GUJ]n4BCA[--FIݍwg9(:l~kA4_uޓQd mC 9<2u|Ŏ[۷3wAYuɬ3Ȫgq<_i486 )©L<>㊦q_Q<N"AKTEra3,K>MΦG; Dj<;ΰ@OFOUvlWZh-U7;"WB_]mq[+Ϋ Cuq}r{?~Z2{?KQtCS +/R*JޖL'(U hMhoy2Ȋ"P‡jZ\f( :A/:ݩN;W~y*%88$%+JPuNN'p$2@A ʢ.,~O;fkbKpOF5Ο~ZDo@'*vԠ' ~)Gp:jeR4Œ Yp<$LBb Z^St ,}#X#4apnH/c=~m됢'zZǐLz!q-\ =!x H)Oglf8XYuI8nEH] 49W!yCWEf"׊PBpBà Pt#B{#TP *8P <{ 8B} G@gf5բP#zA1LLegr&Ȏe`]~ue`:6F |W7 _Pud*3/jg` m؆' A|S i$|&% 07 384a&lЄM0ߣC6qh&Mġ 84aVz_e}v?`M=Q }=ʃfubpN:y=V,K(lQ܋ [zYXv FM@sP3"eh%je%!`znV7\WG@lZr͐6Cp 5gf5A/5GMu6f*hPԂfEp}-hkg-Mp,cc -/`Oew|V&Br:P˙O^e=M1,/dja{L膆>\=c.^ LF+st)*_Kؕp^zh[G}Q H9gVBYX"8dy+GC֧e1/d1MV Y,Ngmd1Q-3,ZhֲbVkrRI_if%E[ą-˚g5-kئ+~}n@ y{gH L: &@b8YL6iHC]IIlcaUy{Mwιw?4Gcj1u(b=\Ԯ'bCQuz81h/Ć#v;fCz$G0nuw^O(VOϨd=c'JXrttP9O:TGcb)>3b#3CcѱD$=@#ȳ2D|䌺-VFO "v.>hϒQfVZŌK*z'~,^#H"Y9u}5tj4R#< GGFgh'Ϋ qő#a%Z/+>*.~E+Ҕ ifg=]IZ珓3e%hlY)/wZeGg~_+wb̐i[Uܺ.Փ%IRJFJ5-QH2\ /9 p nɽ*&%*%P*TF  `(<^ʌW`eKBeNxD1l*/LCȅҫp}۰p}<,.\#aqኜŅX?,.\]= ?ݪ4wHU#K84N,lo䡅FC2voPY]aF(RMdAӂr1OJ(z#lrV8EKOP@MG_:=\k:5ʿ 50{epTDPM@j{[kSw ֎p nj^վk}u6?ݝfW3)"bwNH{>Sg XURhXUg+fq:OִEws)wm]T״w*LXU4O)C!AHP:;evOI߷RqcG6wì܉}RVn?+,?y- 9i$C 0 zКŽ<$C`ir%F~s^A*HM+)YdW3B@뒅 endstream endobj 35 0 obj 20855 endobj 14 0 obj <> endobj 36 0 obj <> endobj 37 0 obj <> stream x{ |TE喙޷;tw{NBHg#@ Y";$$ME088 8  88긎e:2:΢;Uu{ͭ:uTթ: Bt_yqlS罗];ל\ ƎmV `s:죤K|/V]-Ūl,ܼ[`W;7cc>޾h* Pګ=EX;l>lF@~D^`Xmvθ~}tg˟(f >>`X('V7/_(|*h',a8An3 9  yv:$7t@!p- up z3xz`Dx^eOt"IP'+g `/}4D`{Fl%复t89E'i#m?/ >a}DJ\!}ccDmѡsяg"yPA&8∏  ~DINH)!+Jl$}d'H 6Ogo'SDafj M4et#CG)$~_?t!KX$,a(l1WQ|@n4L/d+ C3 NS!xw>n2!q􉯋=G8z f2~H]"=~ ?~\; .Yd1[1|A**'䰮Ov #m2Wmz't"9;IZNȏ{t-,7aqM'th #,h}kĝ2\*<Woa1O?IrQhG-S܀{QfX'49&ApBN:ɝF\T<. J~G E?Cigڱ>ыܽ=8 2q?ގ͈=ץp%w R Ɇe46waԛGN71g *+;lvE3 r9ӳeefT%5%9)q'ĻnZ&ApU VjpVSX-Zʾfd4Ob4UdL M\L*@ɶH4$r(U}j*!V#}[A _RNY`BZP=Uj4ᚭMUߠT radFҌT$]=gZ}Ua2[+VWW%5IeoC| v?J>LX_0jMnUs Ȱoi6_Q?[v6qRFB_UM aX#m(110}Ձ5pE*yv {wjM^c:Nq3vi[fV[TԤއ͒lhbi *܊ +9ڇuOp}>iqHft0*q!Q<+/wke3Vc9yZ[[#؀ZY IC(7i97^hC=O}aC?W>'LMuP]]^ha[fJI=QqBQ4IhWLB%,f?=ֈd@SքEZ`JK6D?axvYL))YTX̢k ՠ5M͑ >U M+5)\'N栵RX8#{WG&]S?D lZ0u#*@sTVZ>D *i$׊-ghP's~Xg˯/F+ RDK@'FHIL#N:VOA ˟忖/?+_:ZHdFa#͑  5d=fS j' [z_Cqi,I"N[˺q>Zg3LSg̝C}pY487,dgY;dBT皬.ɚ{U(e쮷'@j*P/}M 8Ő*v O0eʾ_ (RPqh=|Z'p`pߌBz/=kVqIIiIFiɬiYt4dfw}Yqzd񮄙E%%|;OyY$>bGρgez.kmqec{nYR̨( 6?.Bf CQR\63 463L-M&I| BHѩu.[w8/t(/g3Vmׯptg>8r2}7m7^EО`_T&\ыHZQ\fAH wtzWkzޞa[m&xۏ Db "URH(ĖJYz6jM]LK^?;Vϭ^$Jpym{E`8)!)^=W !bRbc:X$7Z3BHr,_jbnۈy55@f?3"Z^`ik=eƵYݳtY4ә_劘vLlk z{`@qIl>[J1zF3&$׹.pv׻ `̓F!zGI{VΪ00Sq[6MŦrZ~\FwQO/zg9[.CgK&Ġ9,n~[fZZ:~Kg 6-R˝pчizeGd;o;xڟo8śv\~|jWUCxM T?ߑl~=Lr/=վU^zsҕɁH_Ni.{q]",(J$Ӱ.^qHU0<ЋfF]f0Rhj0bhb4"jC&l,VXjerzkUZ#@^"SF'WÊH@bd؂K%O/W1|] EX<`역_/`s4\=иeR|_\l%+nzé=)6 sc0yy[{f=za_FύF㝇N%qS)~*/|.H\҂ˍX`T& r$TZ+)A{EwD@rYW `_OO8~" VgXkf.Wo$t,L[A_n90$*IHJjOQ]*cDQTs\"qqLEU,9J*;fFntֻd((7JZZ0TΩ'EPDžQe%1`Xll(&9 3=/=虙@3)g͔KpcLWu*3x-7Է<8uxCWĬ[BW꙱et }.|FGˋ?3ȐfIG3 %PG/펇gAdxaT k˺ZŜ|!cDmq[5FCzmre?Aœ%g$B&碓fqmlyyy1ęg}v.aO}[Gm:|{N_(fln?k f-|/cNЭx[@#j<$K4#iJNz]R+UhpKS}[]W'L=)Q#ٮB Ҽ*H- RozVpOhl"' 'jӠ8Vʎ`y{>?w>75gCurs-ȝcسǮ񁻿_t%-?WE? p~H/Jx}]&nN,Z\j_Rܮ#O+q vs z,"Qn iB:1)˶-݊QM41Bht80Uf.5Bz6snzqюR_6b~!koh%h$dׂFL eiB05~'3T\;;>wc!Si}c]ѳm Vs׵](\8Ff㝆FQoM5<'QBglq6)r lv*>~Hk9] Bvlr1YB첈g&p *m P')i#?```J5A 1ynƢKCƓQxDqшǷ[܂V`U%?_N[K؅:\9ǎ7Hav%"q҅N,.1*$nn15^cHKͶ,`\$UqAD%N))GrٵHUv$xp<~ r&$!Ș^ r}'$<_~8zɞ ζL٥.#h|rW/Q4vqCǣaojSmߞ9ʪO>sqPe{^굯5?'rdyYgMӂӻ:9r(+d]m˿{DYboovo܃p?aH!x4:,Ɓ!yAMv-4d3?IX 3rXeFw 'f/ `vo-@\dJ|K|3JO:ߑrG+RvgǬj.Gt׎7z;AMF*fa { ^]iz$hr..#Cz4SggsI\X ^Wp,8 .C!G `& x۴+t ^Nv'gWx]]^ 'g3٢kwt]n[hL-cvk-./`C wq,@ %;[M{R؝oX ޳_}OS;_rPZBJө<*hڂ%Jȋ Ҡ_e=?>g7G7ޖĈju ePiz7Xeb~եG!ZaX/:|Z׋y>W3s0PezU~2샵/gt6V7+?0Xl8!{ z,ΧQ5=' ٸS(uubӥqxX-|M<\SK` 2Z|uH?L-h[6M҇iflkUhwE1Zݲ-Ewc!`4~ h#T뾌VV(X6-Bt:*F33|wc4b"1xN8?/F3~15Z_55Z_55Z_55Z_55Z_5m4wӤ2" -̢ 7h Z[ -bNW^617qyFQkI3ycJf~N'p~uf՜~c4c$. F3N4nʤqHf< ϛ1!sߤ7q:cʋ؏ۀaI&0i^IIIb_ VPZ|)tA'>}eSYڌǚh{BFl<[1mEHm,Fk#͙$nF:%U7 pB(A*e2=XӋO>=]}E5Sڄ̚(fF?G{ڭRK 3Vsm8lNTw;G@E]NWKk&*6>F,/GYmG 6t[kڑ֡O*zd5\CmUTehUES9V;0疡Yôy]r~7oUpbshfS7}3p q;bBk1G$nnAq Ccכ!sLG爴U$XNet̙Em}w?bke|-f0V5whs[<_k+rw],yʪcUg\?oɴ:aZ?L% ?V״ե]]};jeWOwWOs_3_]ѡ mlUW{=[ zB;B-plhQ9u^E_Xf/ tvMׄ5!Nz[Մzf5g/TCj֭ [}}AlZգvaM Ot%U=Bmmڀ- wu4+YKY]يSQg.jW77P{82j٧u2[&ysc*n;YX>6mȤ0utJtuvPC $;:oe Y2,/k.QvG nfp֮m]ͭSAh֦Oߧ2Q==| 74f/ _ZiRKi!3/ap~+WM_ [Z"+7Ef6"At8ߌ/uoVt},t}M1QqX4Yj _R8˦RS+4sgt[>d5Nj6n?k ;.=6T63dž"IаYt= '9Pr|#`Cw0Cy6len_dr-/ Wog#Esr 1OSu8ŚNL*Q0;U<0as~D?^PJ>:iO xj~FYiO+x]<~?|pB.ȹDVH 2BPN4Vy@ )_EHݐ1!J@w7 seB#J}oH(D#r ;lW:NWua0+-h]:^Q|KRU9BN+efoZĚVf(=J‡ՆͲ4,R/ϕHgI ~?Sڟ" Nl,`D5^[ ^f^dij/(1PX8֮^HjZvj_V | IY kz³)*\ K+.$5eoGpU7ݖM54@ OsX:ﴞ]cW~XRIX\=)kWׇNi1"PszE9N!~D%ǫW1[PK3,C9P&rhv\ >.KPȥǘ\PrT;}p3Z_r.((p* Q"5Eb""|$\Q4:.ce#GB:leE6T^ r|V‡`7Mao!TTxY>LzngW1.mA5V oBeU6bU]sӒΐc*c}}Ouj_o66\r]$UMU +Ց9r D4N/%R*4{Qh2}< 9n endstream endobj 38 0 obj 9428 endobj 15 0 obj <> endobj 39 0 obj <> endobj 40 0 obj <> stream xW P[ו>wX'cĕ% @PK8K:qmfMR23ۙzhkОsZ"[>Lp9oOq}fLcQf1,~xW" uf0LN0( f n%\F\r~*yn|o %*,]p]{Ncf%ڃ6 VEx$KBpo %뤿 iz@pfAgY9-c[(M\&W~Cm|s/>Ȃbv uD0턩Ǯll̔WwLYnv$Zu,%LcwU~R<+>|qÃ~ofv|N7GG_QQO8iCl2' s0^L;T,tqh/$HS3)PSݶeMӮg^ \k+)Qū'+`Y=~.<33XQPX`;=O{7Y[TW PBxmP#3710izܮm TFO|ceR/eU2"X"zG_C{^8'jvpɶOGZ>P7x?Arݩ$d3]Vc-[_nuvP>?\&go׬|#Ad(z_6].;cRj[AEV;E}gF˕ti0wնm?^m#/‡z#'ȅFh5"ZddFVtZA+2Qg`4@(iJL R Ejw%WzzQ4z\}lV zed.=s0W>ʆK|,_bglb?͎1 N A[(w=^{X<(~H# qⳊlw}񟍒$Q$!(~`/bex꤅I h'8`qmXx7?ڀG3n> endobj 42 0 obj <> endobj 43 0 obj <> stream xW{xTEV?wO]t\Rso|zWUQu=UPBl'0`e}QzQ6!VE!Ս5"z5۪Ѿ! y`m8T﬙FmLEF~lm}˖ 11R"$# miOby*8_#-ÛjB~Yn|gG_H%(#"TEy6B +Z _?K%oa9%Jm4EO\G KEKC{lr+c6D0&E; (ȇMU؞$%NL[ʌׄ58"L'B5rY$'!$W^M} зݢWlO^d=y'{^WUMrmWUEUvU,GTv)|u;y]cR-cJ7V[vbA@WP@ *P-|M"PL ~2J:1;H34!9b"%ˀ+,) z2E- 6):S+ QI5m8H灐GJRl"I.ԈN/h d6f6 ZZ+IeO[{ kN{8 ~e1ښ_V\Z ']vrrՊ[Va-35 ;ʔ>ߛNiY`r_NZ~z/饽B/􊽆^ I.sn }B}>cb_RhTDvg^x Lԛ?i'6?)͋u:*XkKFҚG>HӼmŋ4j6M+ވx7;LW10Fi$o~,,ta1D "”^0q hy3kbAc|-_~ؗPϛ^$| ݷjַví]%/ܮޓV ƭo'tףSƳxq pە$0ϜNb6:tڱ̗T_'au$mV75vݓԍMM9*UT4WSIlٔ5(/B$Fj\ӦӮ TNyC8%]0`X^2k M9ƍf-tZ%\IcEͱ`yFGG5{%5p~6 ;lJ1eǥmŽӋZ?&OXClÁ:-$z`NoY{8mHXb.2ڀu9vZb& VfД ^ƭM:7\rf޲݄a &JvQ\rŨhz|EQ77}ʓC]byb߽Z j%5h5 2TL1 `#cZH+Tvj1KTUjmdPׂͮNj {چ667.l'PJqG_Ǔ?H$J4ۑ't.K7ǛW;Slo['e#xA|fM-K*}k[֦j>*=$̮^S1El)k^o]S9Ig{͑{0$4%$&WR_e` a/3vxGLJLp1Mon,o\:AZBo,$;(޹5㭏lx Zh roTfx=U(?$:Bc%c4EO>CkT"J62F1ZGQO֓".FS#mMu5-ҳRnNN4qcX*i̒nRE<~}F ȓ{̪kini #ffn(-4KK᪬; #%-u )S)Y9U9oS+5K!iyS*\j Eoda]MeSSyv> d#-xl!M$LBGI=n Iوfr HGPZaR&҈Z05މ"YMhRW+ZYTwF_v$Dlc?o2IHGTFD6,̂%8c%W#5(q~,FRDmU,eQSXT!Z?.KY}ekPlR07"A&~3Jdf8Y9ՈnWXUk'JQa{`Ep?e%{&xO:^˅WO:+3Μ_9d<lONt@|9 ^:^NeI'r!j{8p ob9G]lQ?l_sSpDv[x6{qx=CO:!OIv d(9X#V!Rt&DV`ⰜòVR+,ᰘÝYgE lPby=0C1f,6vdY0Ȅ,04S9.cE=P8e+\SAI C.r8dgY M#C&poqLi|D˅R9xPR 1*cd%[J3ȊXbM%p8YCmo`EY`3Nh` 3%{@AV4NPĹPV"3, c4hVu?C~/< endstream endobj 44 0 obj 4327 endobj 45 0 obj <> endobj xref 0 46 0000000000 65535 f 0000000016 00000 n 0000000777 00000 n 0000003754 00000 n 0000005552 00000 n 0000000716 00000 n 0000000585 00000 n 0000000080 00000 n 0000000167 00000 n 0000000279 00000 n 0000000383 00000 n 0000000491 00000 n 0000005708 00000 n 0000020707 00000 n 0000042583 00000 n 0000052975 00000 n 0000057194 00000 n 0000000839 00000 n 0000003216 00000 n 0000004519 00000 n 0000004655 00000 n 0000004791 00000 n 0000004927 00000 n 0000005063 00000 n 0000004002 00000 n 0000004349 00000 n 0000003238 00000 n 0000003733 00000 n 0000005199 00000 n 0000005531 00000 n 0000006390 00000 n 0000006581 00000 n 0000020684 00000 n 0000021429 00000 n 0000021615 00000 n 0000042560 00000 n 0000043241 00000 n 0000043435 00000 n 0000052953 00000 n 0000053609 00000 n 0000053799 00000 n 0000057172 00000 n 0000057832 00000 n 0000058026 00000 n 0000062442 00000 n 0000062464 00000 n trailer < ]>> startxref 62556 %%EOF ./nsf2.4.0/doc/forward.man.inc000644 000766 000024 00000014225 13030507001 016637 0ustar00neumannstaff000000 000000 [comment {-*- tcl -*- manpage fragment for forward method, shared by nx::Object and nx::Class}] [keywords "value checker"] [keywords "forward method"] [keywords "debugging level"] [call [arg [vset CMD]] [opt "[method public] | [method protected] | [method private]"] [method "[vset MODIFIER] forward"] [opt [option -debug]] [opt [option -deprecated]] [arg methodName] [opt "[option -prefix] [arg prefixName]"] [opt "[option -frame] [const object]"] [opt "[option -returns] [arg valueChecker]"] [opt [option -verbose]] [opt [arg target]] [opt "[arg arg] ..."]] Define a [term "forward method"] for the given [vset SCOPE]. The definition of a [term "forward method"] registers a predefined, but changeable list of forwarder arguments under the (forwarder) name [arg methodName]. Upon calling the [term "forward method"], the forwarder arguments are evaluated as a Tcl command call. That is, if present, [arg target] is interpreted as a Tcl command (e.g., a Tcl [cmd proc] or an object) and the remainder of the forwarder arguments [arg arg] as arguments passed into this command. The actual method arguments to the invocation of the [term "forward method"] itself are appended to the list of forwarder arguments. If [arg target] is omitted, the value of [arg methodName] is implicitly set and used as [arg target]. This way, when providing a fully-qualified Tcl command name as [arg methodName] without [arg target], the unqualified [arg methodName] ([cmd "namespace tail"]) is used as the forwarder name; while the fully-qualified one serves as the [arg target]. [para] As for a regular [method "[vset MODIFIER] method"], [option "-returns"] allows for setting a [term "value checker"] on the values returned by the resulting Tcl command call. When passing [const object] to [option "-frame"], the resulting Tcl command is evaluated in the context of the object receiving the [term "forward method"] call. This way, variable names used in the resulting execution of a command become resolved as object variables. [para] To express deprecation of the [term "forward method"] [arg methodName], set the [option "-deprecated"] flag. Deprecated methods remain usable from client code, but their usage will be signaled to the developer and/or can be tracked using [cmd ::nsf::deprecated]. To register [arg methodName] with the debugger, set the [option "-debug"] flag. Entering and exiting a method, which was flagged for debugging, is recorded by calling the redefinable callback procs [cmd ::nsf::debug::call] and [cmd ::nsf::debug::exit], respectively. By default, these callbacks forward to [cmd ::nsf::log], which can also be customized at the script level. [para] The list of forwarder arguments [arg arg] can contain as its elements a mix of literal values and placeholders. Placeholders are prefixed with a percent symbol (%) and substituted for concrete values upon calling the [term "forward method"]. These placeholders allow for constructing and for manipulating the arguments to be passed into the resulting command call on the fly: [list_begin itemized] [item] [const %method] becomes substituted for the name of the [term "forward method"], i.e. [arg methodName]. [item] [const %self] becomes substituted for the name of the object receiving the call of the [term "forward method"]. [item] [const %1] becomes substituted for the first method argument passed to the call of [term "forward method"]. This requires, in turn, that [emph "at least"] one argument is passed along with the method call. [para] Alternatively, [const %1] accepts an optional argument [arg defaults]: {[const %1] [arg defaults]}. [arg defaults] must be a valid Tcl list of two elements. For the first element, [const %1] is substituted when there is no first method argument which can be consumed by [const %1]. The second element is inserted upon availability of a first method argument with the consumed argument being appended right after the second list element. This placeholder is typically used to define a pair of getter/setter methods. [item] {[const %@][arg index] [arg value]} becomes substituted for the specified [arg value] at position [arg index] in the forwarder-arguments list, with [arg index] being either a positive integer, a negative integer, or the literal value [const end] (such as in Tcl's [cmd lindex]). Positive integers specify a list position relative to the list head, negative integers give a position relative to the list tail. Indexes for positioning placeholders in the definition of a [term "forward method"] are evaluated from left to right and should be used in ascending order. [para] Note that [arg value] can be a literal or any of the placeholders (e.g., [const %method], [const %self]). Position prefixes are exempted, they are evaluated as [const %][arg cmdName]-placeholders in this context. [item] {[const %argclindex] [arg list]} becomes substituted for the [emph n]th element of the provided [arg list] , with [emph n] corresponding to the number of method arguments passed to the [term "forward method"] call. [item] [const %%] is substituted for a single, literal percent symbol (%). [item] [const %][arg cmdName] is substituted for the value returned from executing the Tcl command [arg cmdName]. To pass arguments to [arg cmdName], the placeholder should be wrapped into a Tcl [cmd list]: {[const %][arg cmdName] [opt "[arg arg] ..."]}. [para] Consider using fully-qualified Tcl command names for [arg cmdName] to avoid possible name conflicts with the predefined placeholders, e.g., [const %self] vs. %[cmd ::nx::self]. [list_end] [para] To disambiguate the names of subcommands or methods, which potentially become called by a [term "forward method"], a prefix [arg prefixName] can be set using [option "-prefix"]. This prefix is prepended automatically to the argument following [arg target] (i.e., a second argument), if present. If missing, [option "-prefix"] has no effect on the [term "forward method"] call. [para] To inspect and to debug the conversions performed by the above placeholders, setting the [term "switch"] [option "-verbose"] will have the command list to be executed (i.e., after substitution) printed using [cmd ::nsf::log] ([term "debugging level"]: [const notice]) upon calling the [term "forward method"]. ./nsf2.4.0/doc/prince.js000644 000766 000024 00000013476 12440622624 015570 0ustar00neumannstaff000000 000000 var asciidoc = { // Namespace. ///////////////////////////////////////////////////////////////////// // Table Of Contents generator ///////////////////////////////////////////////////////////////////// /* Author: Mihai Bazon, September 2002 * http://students.infoiasi.ro/~mishoo * * Table Of Content generator * Version: 0.4 * * Feel free to use this script under the terms of the GNU General Public * License, as long as you do not remove or alter this notice. */ /* modified by Troy D. Hanson, September 2006. License: GPL */ /* modified by Stuart Rackham, 2006, 2009. License: GPL */ // toclevels = 1..4. toc: function (toclevels) { function getText(el) { var text = ""; for (var i = el.firstChild; i != null; i = i.nextSibling) { if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants. text += i.data; else if (i.firstChild != null) text += getText(i); } return text; } function TocEntry(el, text, toclevel) { this.element = el; this.text = text; this.toclevel = toclevel; } function tocEntries(el, toclevels) { var result = new Array; var re = new RegExp('[hH]([1-'+(toclevels+1)+'])'); // Function that scans the DOM tree for header elements (the DOM2 // nodeIterator API would be a better technique but not supported by all // browsers). var iterate = function (el) { for (var i = el.firstChild; i != null; i = i.nextSibling) { if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { var mo = re.exec(i.tagName); if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { result[result.length] = new TocEntry(i, getText(i), mo[1]-1); } iterate(i); } } } iterate(el); return result; } var toc = document.getElementById("toc"); if (!toc) { return; } // Delete existing TOC entries in case we're reloading the TOC. var tocEntriesToRemove = []; var i; for (i = 0; i < toc.childNodes.length; i++) { var entry = toc.childNodes[i]; if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") && entry.getAttribute("class").match(/^toclevel/)) tocEntriesToRemove.push(entry); } for (i = 0; i < tocEntriesToRemove.length; i++) { toc.removeChild(tocEntriesToRemove[i]); } // Rebuild TOC entries. var entries = tocEntries(document.getElementById("content"), toclevels); for (var i = 0; i < entries.length; ++i) { var entry = entries[i]; if (entry.element.id == "") entry.element.id = "_toc_" + i; var a = document.createElement("a"); a.href = "#" + entry.element.id; a.appendChild(document.createTextNode(entry.text)); var div = document.createElement("div"); div.appendChild(a); div.className = "toclevel" + entry.toclevel; toc.appendChild(div); } if (entries.length == 0) toc.parentNode.removeChild(toc); }, ///////////////////////////////////////////////////////////////////// // Footnotes generator ///////////////////////////////////////////////////////////////////// /* Based on footnote generation code from: * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html */ footnotes: function () { // Delete existing footnote entries in case we're reloading the footnodes. var i; var noteholder = document.getElementById("footnotes"); if (!noteholder) { return; } var entriesToRemove = []; for (i = 0; i < noteholder.childNodes.length; i++) { var entry = noteholder.childNodes[i]; if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote") entriesToRemove.push(entry); } for (i = 0; i < entriesToRemove.length; i++) { noteholder.removeChild(entriesToRemove[i]); } // Rebuild footnote entries. var cont = document.getElementById("content"); var spans = cont.getElementsByTagName("span"); var refs = {}; var n = 0; for (i=0; i" + n + "]"; spans[i].setAttribute("data-note", note); } noteholder.innerHTML += "
    " + "" + n + ". " + note + "
    "; var id =spans[i].getAttribute("id"); if (id != null) refs["#"+id] = n; } } if (n == 0) noteholder.parentNode.removeChild(noteholder); else { // Process footnoterefs. for (i=0; i" + n + "]"; } } } }, install: function(toclevels) { var timerId; function reinstall() { asciidoc.footnotes(); if (toclevels) { asciidoc.toc(toclevels); } } function reinstallAndRemoveTimer() { clearInterval(timerId); reinstall(); } //console.log("install 1"); //timerId = setInterval(reinstall, 500); //if (document.addEventListener) //document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false); //else //window.onload = reinstallAndRemoveTimer; reinstall(); //console.log("install END"); } } asciidoc.install(3); ./nsf2.4.0/doc/pinger-xotcl.html000644 000766 000024 00000002306 12161565464 017251 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/scripts/pinger.xotcl

    ./apps/scripts/pinger.xotcl ./apps/scripts/pinger.xotcl


    Package/File Information

    No package provided/required

    Filename: ./apps/scripts/pinger.xotcl

    Description: Pinger example for the observer pattern taken from the paper 'Filters as a Language Support for Design Patterns in Object-Oriented Scripting Languages'. It demonstrates how to observe a network connection.



    Back to index page.

    ./nsf2.4.0/doc/man-princexml.css000644 000766 000024 00000001352 12776662115 017237 0ustar00neumannstaff000000 000000 body { font-size: 13px !important; /*prince-linebreak-magic: auto;*/ } pre.example { font-size: 80% !important; white-space: pre-wrap !important; } ul.syntax { margin-left: 0 !important; padding-left: 0 !important; } ul.syntax li { text-indent: 1em hanging !important; } h2 { string-set: chapter-title content() } @page { size: A4; /* DIV 15 for A4 paper */ margin: 19.80mm 14mm; @top { font-family: "Arial","Verdana", sans-serif; color: #666; font-size: 80%; content: string(chapter-title) } @bottom { font-family: "Arial","Verdana", sans-serif; font-size: 80%; color: #666; content: "- " counter(page) " -" } } @page:first { @top { content: normal } } ./nsf2.4.0/doc/adapter-xotcl.html000644 000766 000024 00000002214 12161565464 017403 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./apps/scripts/adapter.xotcl

    ./apps/scripts/adapter.xotcl ./apps/scripts/adapter.xotcl


    Package/File Information

    No package provided/required

    Filename: ./apps/scripts/adapter.xotcl

    Description: Simple adapter pattern meta-class taken from the paper 'Filters as a Language Support for Design Patterns in Object-Oriented Scripting Languages'.



    Back to index page.

    ./nsf2.4.0/doc/testx-xotcl.html000644 000766 000024 00000033564 12161565464 017146 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./tests/testx.xotcl

    ./tests/testx.xotcl ./tests/testx.xotcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./tests/testx.xotcl

    Description: This is a file which provides a regression test for the features of the XOTcl - Language.


    Class: TestX

    Class: Class


    Object: assertions

    Class: TestX
    Description: Regression test object testing the assertions.


    Object: condMixins

    Class: TestX
    Description: Regression test for conditional mixins


    Object: copymove

    Class: TestX
    Description: Regression test for copy/move methods


    Object: filterAddRemove

    Class: TestX
    Description: Regression test object testing adding/removing of filters.


    Object: filterClassChange

    Class: TestX
    Description: Regression test object testing class changes of filters.


    Object: filterGuards

    Class: TestX
    Description: Regression test object testing filter guards.


    Object: filterInfo

    Class: TestX
    Description{: Regression
    Test: object
    Testing: introspection
    Of: filters.
    }:


    Object: filterSimpleObserver

    Class: TestX
    Description: Regression test object testing a simple observer using filters.


    Object: init_params

    Class: TestX
    Description: Regression test object testing the parameter instance method, the init dash '-' and constructor calling.


    Object: mixinGuards

    Class: TestX
    Description: Regression test object testing mixin guards.


    Object: mixinInheritanceTest

    Class: TestX
    Description: Regression test object testing per-object mixin inheritance.


    Object: mixinTest

    Class: TestX
    Description: Regression test object testing per-object mixins.


    Object: nestingClasses

    Class: TestX
    Description: Regression test object testing the class nesting feature.


    Object: nestingObjects

    Class: TestX
    Description: Regression test object testing the object nesting feature.


    Object: nextTest

    Class: TestX
    Description: Regression test object testing the next primitive.


    Object: objectReferences

    Class: TestX
    Description: Regression test for object and class references in tcl_objs


    Object: procsearchTest

    Class: TestX
    Description: Regression test for procsearch


    Object: recreation

    Class: TestX
    Description: Regression test for object recreation/cleanup.


    Object: smallScripts

    Class: TestX
    Description: Regression test object testing arbitrary features.


    Object: stdargs

    Class: TestX
    Description: Regression test object testing the ability of the next primitive to pass arguments without naming them.


    Object: volatileObjects

    Class: TestX
    Description: Regression test for volatile objects



    Back to index page.

    ./nsf2.4.0/doc/configure.man000644 000766 000024 00000003047 13076704513 016425 0ustar00neumannstaff000000 000000 [comment {-*- Tcl -*- nx::configure manpage}] [include version.inc] [manpage_begin nx::configure 3 [vset VERSION]] [copyright {2014-16 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3.0 Austria license (CC BY 3.0 AT).}] [titledesc {Get and set configuration options on the object system}] [moddesc {NX API}] [description] [list_begin definitions] [call [cmd "configure"] [arg option] [opt [arg arg]]] This command sets and retrieves options for the NX object system. Legal configuration options are: [list_begin itemized] [item] [option "defaultMethodCallProtection"] returns the currently active call-protection level used as default for newly defined method implementations (if not specified explicitly by a method definition), if [arg arg] is not provided. If [arg arg] is set, this default call-protection level is re-set to any of the available ones: [const public], [const private], [const protected]. [item] [option "defaultAccessor"] returns the currently active call-protection level used as the default for newly defined properties (if not specified explicitly by a property definition), if [arg arg] is not provided. If [arg arg] is set, this default call-protection level is re-set to any of the following values: [const public], [const private], [const protected], or [const none]. [const none] indicates that no accessors (getter/setter methods) will be generated for newly defined properties, if not requested explicitly. [list_end] [list_end] [manpage_end] ./nsf2.4.0/doc/xodoc-xotcl.html000644 000766 000024 00000020563 13443231446 017100 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/lib/xodoc.xotcl

    ./library/lib/xodoc.xotcl ./library/lib/xodoc.xotcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./library/lib/xodoc.xotcl

    Description: XOTcl documentation tool. Overloads the command @, which is used as a documentation token.


    Class: ConstraintTokenHTML

    Class: Class
    Heritage: MetadataTokenHTML


    Class: FileTokenHTML

    Class: Class
    Heritage: MetadataTokenHTML


    Class: MetadataTokenHTML

    Class: Class
    Procs/Instprocs: getDocPropertiesHTML, printHTML.
    Description: Instmixin to provide HTML printing. Such instmixins are registered for all token types.

    Instprocs

    • abstract printHTML
      Description: Print token to HTML document object
    • getDocPropertiesHTML
      Description: Returns list of properties as HTML.


    Class: MethodTokenHTML

    Class: Class
    Heritage: MetadataTokenHTML


    Class: ObjTokenHTML

    Class: Class
    Heritage: MetadataTokenHTML


    Class: XODoc

    Class: Class
    Procs/Instprocs: documentFileAsHTML, printHTML, writeFile.
    Description: Handler class for building a documentation database

    Instprocs

    • printHTML name
      Arguments: name: name of the HTML document
      Description: Create HTML documentation object from metadata token
    • writeFile filename name
      Arguments: filename: file name destination
      name: name of the HTML document
      Description: Create HTML docuemntation from metadata token and write to file

    Procs

    • documentFileAsHTML file docdir
      Arguments: file: filename of the xotcl file to be documented
      docdir: directory to which the HTML file is written
      Description: Uses the xoDoc package to produce an HTML documentation of a specified file ***.xotcl. The file is written to ***.html in docdir
      Return: file basename without suffix



    Back to index page.

    ./nsf2.4.0/doc/staticMetadata-xotcl.html000644 000766 000024 00000005575 12161565463 020727 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/lib/staticMetadata.xotcl

    ./library/lib/staticMetadata.xotcl ./library/lib/staticMetadata.xotcl


    Package/File Information

    No package provided/required

    Defined Objects/Classes:
    Filename: ./library/lib/staticMetadata.xotcl

    Description: XOTcl file static analyzer for @ metadata. E.g. used for doumentation with xoDoc. I.e. allows for reading in a file and evaluating the metadata-related info only.


    Class: StaticMetadataAnalyzer

    Class: Class
    Heritage: MetadataAnalyzer
    Procs/Instprocs: analyzeFile.
    Description: Metadata analyzer class that allows for reading in files and evaluation of the metadata content in the file.

    Instprocs

    • analyzeFile name
      Arguments: name: File name
      Description: Analyze a file and build up a token structure for each metadata token in the file.



    Back to index page.

    ./nsf2.4.0/doc/Object.man000644 000766 000024 00000100054 13532210151 015631 0ustar00neumannstaff000000 000000 [comment {-*- Tcl -*- nx::Object manpage}] [include version.inc] [manpage_begin nx::Object 3 [vset VERSION]] [comment {For the time being, we do not render keywords & terms; and the corresponding reverse index}] [proc keywords args {}] [proc term v {return $v}] [keywords baseclass] [keywords NX] [keywords "mixin class"] [keywords "re-classification"] [keywords "submethod"] [keywords "method ensemble"] [keywords "linearization"] [vset SCOPE "object"] [vset CMD "obj"] [vset MODIFIER "object"] [copyright {2014-19 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3.0 Austria license (CC BY 3.0 AT).}] [moddesc "NX API"] [titledesc {API reference of the base class in the NX object system}] [description] [para] [cmd nx::Object] is the [term "base class"] of the [term NX] object system. All objects defined in [term NX] are (direct or indirect) instances of this [term "base class"]. The methods provided by the [cmd nx::Object] [term "base class"] are available to all objects and to all classes defined in NX. [example { +---------+ | ::nx::* | +---------+--------------------------------------Y | | | +---------+ instance of +----------+ | | | |<....................| | | | | Class | | Object | | | | |....................>| | | | +----+----+ subclass of +-----+----+ | | ^ ^ ^ | instance.|...........................|....|......./ of | | | +-----+-----+ subclass of | | instance | |.....................| | of | /cls/ | (by default) | | | | +-----------+ | ^ | instance |.............(xor)..............| of | +-----------+ | |.........| |..........| | /obj/ | | | +-----------+ }] [term NX] allows for creating and for using objects (e.g. [emph obj]) which are instantiated from the [term "base class"] [cmd nx::Object] directly. Typical use cases are singletons and anonymous, inline objects. In such use cases, [term NX] does not require creating an intermediate application class (e.g. [emph cls]), which specializes the [term "base class"] [cmd nx::Object] by default, beforehand. [para] Objects (e.g. [emph obj]) which are creating by instantiating a previously defined application class (e.g. [emph cls]) are indirect instances of [cmd nx::Object]. [para] Direct instances of [cmd nx::Object] can be created as follows: [list_begin definitions] [call [cmd nx::Object] [method create] [arg obj] [opt "[option -object-mixins] [arg mixinSpec]"] [opt "[option -class] [arg newClassName]"] [opt "[option -object-filters] [arg filterSpec]"] [opt [arg initBlock]]] [para] To create a direct instance of [cmd nx::Object] having an explicit name [arg obj], use [method create] on [cmd nx::Object]. Note that [method create] is defined by [cmd nx::Class] and is available to [cmd nx::Object] being an instance of [cmd nx::Class]. This way, singleton objects can be created, for example. [call [cmd nx::Object] [method new] [opt "[option -object-mixins] [arg mixinSpec]"] [opt "[option -class] [arg newClassName]"] [opt "[option -object-filters] [arg filterSpec]"] [opt [arg initBlock]]] To create a direct instance of [cmd nx::Object] having an automatically assigned, implicit object name, use [method new] on [cmd nx::Object]. Note that [method new] is defined by [cmd nx::Class] and is available to [cmd nx::Object] being an instance of [cmd nx::Class]. Using [method new] allows for creating anonymous, inline objects, for example. [list_end] The configuration options for direct and indirect instances of [cmd nx::Object], which can be passed when calling [method create] and [method new], are documented in the subsequent section. [section {Configuration Options for Instances of nx::Object}] [para] Configuration options can be used for configuring objects during their creation by passing the options as non-positional arguments into calls of [method new] and [method create] (see [cmd nx::Class]). An existing object can be queried for its current configuration using [method cget] and it can be re-configured using [method configure]. Legal configuration options are: [list_begin options] [opt_def -class [opt [arg className]]] Retrieves the current class of the object or sets the object's class to [arg className], if provided. [opt_def -object-filters [opt [arg filterMethods]]] Retrieves the list of currently active per-object filter methods or sets a list of per-object filter methods, if [arg filterMethods] is provided. [opt_def -object-mixins [opt [arg mixinSpecs]]] If [arg mixinSpecs] is not specified, retrieves the list of currently active per-object mixin specifications. If [arg mixinSpecs] is specified, sets a list of per-object mixin specifications to become active. [term "mixin class"]es are returned or set in terms of a list of [term "mixin specification"]s. [list_end] [section {Methods for Instances of nx::Object}] [list_begin commands] [cmd_def alias] [list_begin definitions] [include alias.man.inc] [list_end] [cmd_def cget] [list_begin definitions] [call [arg obj] [method cget] [arg configurationOption]] The method is used to obtain the current value of [arg configurationOption] for [arg obj]. The configuration options available for querying through [method cget] are determined by the configurable properties defined by the class hierarchy of [arg obj]. The queryable configuration options for [arg obj] can be obtained by calling [method "info lookup syntax configure"]. The [arg configurationOption] can be set and modified using [method configure]. [example_begin] % nx::Object create obj ::obj % ::obj info lookup syntax configure ?-object-mixins /mixinreg .../? ?-class /class/? ?-object-filters /filterreg .../? ?/__initblock/? % ::obj cget -class ::nx::Object [example_end] [list_end] [cmd_def configure] [list_begin definitions] [call [arg obj] [method configure] [opt "[arg configurationOption] [arg value] ..."]] This method sets configuration options on an object. The configuration options available for setting on [arg obj] are determined by the configurable properties defined by the class hierarchy of [arg obj]. The settable configuration options for [arg obj] can be obtained by calling [method "info lookup syntax configure"]. Furthermore, [method configure] is also called during object construction. Under object construction, it receives the arguments passed into calls of [method create] and [method new]. Options set using [method configure] can be retrieved using [method cget]. [example_begin] % nx::Class create Foo {:property x} ::Foo % Foo create f1 -x 101 ::f1 % f1 cget -x 101 % f1 configure -x 200 % f1 cget -x 200 [example_end] [list_end] [cmd_def contains] [list_begin definitions] [call [arg obj] [method contains] [opt "-withnew [arg trueFalse]"] [opt "-object [arg objectName]"] [opt "-class [arg className]"] [arg cmds]] This method acts as a builder for nested object structures. Object and class construction statements passed to this method as its last argument [arg cmds] are evaluated in a way so that the receiver object [arg obj] becomes the parent of the newly constructed objects and classes. This is realized by setting explicitly the namespace for constructing relatively named objects. Fully qualified object names in [arg cmds] evade the nesting. [para] [option "-withnew"] requests the automatic rescoping of objects created using [method new] so that they become nested into the receiver object [arg obj], rather than being created in the default namespace for autonamed objects (i.e., ::nsf). If turned off, autonamed objects do not become children of [arg obj]. [para] The parent object [arg objectName] to be used instead of [arg obj] can be specified using [option "-object"]. If this explicitly set parent object does not exist prior to calling [method contains], it will be created on the fly as a direct instance of [cmd nx::Object]. Alternatively, using [option "-class"], a class [arg className] other than [cmd nx::Object] for the on-the-fly creation of [arg objectName] can be provided. [example { % nx::Class create Window { :contains { # # Become children of Window, implicitly # nx::Class create Header; # Window::Header nx::Object create Panel; # Window::Panel } # # Explicitly declared a child of Window using [self] # nx::Class create [self]::Slider; # Window::Slider # # Fully-qualified objects do not become nested # nx::Class create ::Door; # ::Door } ::Window % ::Window info children ::Window::Panel ::Window::Header ::Window::Slider }] [list_end] [cmd_def copy] [list_begin definitions] [call [arg obj] [method copy] [opt [arg newObjectName]]] Creates a full and deep copy of a source object [arg obj]. The object's copy features all structural and behavioral properties of the source object, including object variables, per-object methods, nested objects, slot objects, namespaces, filters, mixins, and traces. The copy can be named explicitly, if [arg newObjectName] is provided, or it is named automatically (in the spirit of [method new] of [cmd nx::Class]). [list_end] [comment { [cmd_def defaultmethod] [list_begin definitions] [call [arg obj] [cmd defaultmethod]] This method is called implicitly when the object command is invoked without an argument. By default, the [cmd defaultmethod] implementation returns the fully qualified object name. [example_begin] % Object create ::foo ::foo % ::foo defaultmethod ::foo % ::foo ::foo [example_end] [list_end] }] [cmd_def delete] [list_begin definitions] [include delete.man.inc] [list_end] [cmd_def destroy] [list_begin definitions] [call [arg obj] [method destroy]] This method allows for explicitly destructing an object [arg obj], potentially prior to [arg obj] being destroyed by the object system (e.g. during the shutdown of the object system upon calling [cmd exit]): [example {[nx::Object new] destroy}] By providing a custom implementation of [method destroy], the destruction procedure of [arg obj] can be customized. Typically, once the application-specific destruction logic has completed, a custom [method destroy] will trigger the actual, physical object destruction via [cmd next]. [example { % [nx::Object create obj { :public method destroy {} { puts "destroying [self]" next; # physical destruction } }] destroy destroying ::obj }] A customized object-destruction scheme can be made shared between the instances of a class, by defining the custom [method destroy] for an application class: [example_begin] % nx::Class create Foo { :method destroy {} { puts "destroying [lb]self[rb]" next; # physical destruction } } ::Foo % Foo create f1 ::f1 % f1 destroy destroying ::f1 [example_end] Physical destruction is performed by clearing the in-memory object storage of [arg obj]. This is achieved by passing [arg obj] into a call to [method dealloc] provided by [cmd nx::Class]. A near, scripted equivalent to the C-implemented [method destroy] provided by [cmd nx::Object] would look as follows: [example { % Object method destroy {} { [:info class] dealloc [self] } }] Note, however, that [method destroy] is protected against application-level redefinition. Trying to evaluate the above script snippet yields: [example { refuse to overwrite protected method 'destroy'; derive e.g. a subclass! }] A custom [method destroy] must be provided as a refinement in a subclass of [cmd nx::Object] or in a [term "mixin class"]. [list_end] [cmd_def eval] [list_begin definitions] [call [arg obj] [method eval] [arg arg] [opt "[arg arg] ..."]] Evaluates a special Tcl script for the scope of [arg obj] in the style of Tcl's [cmd eval]. There are, however, notable differences to the standard [cmd eval]: In this script, the colon-prefix notation is available to dispatch to methods and to access variables of [arg obj]. Script-local variables, which are thrown away once the evaluation of the script has completed, can be defined to store intermediate results. [example { % nx::Object create obj { :object property {bar 1} :public object method foo {x} { return $x } } ::obj % ::obj eval { set y [:foo ${:bar}] } 1 }] [list_end] [cmd_def filters] [list_begin definitions] [include filter.man.inc] [list_end] [cmd_def forward] [list_begin definitions] [include forward.man.inc] [list_end] [cmd_def info] [list_begin definitions] [call [arg obj] [method "info baseclass"]] Returns the [term "base class"] of [arg obj]. The [term "base class"] is the class from which all [term NX] objects are instantiated directly or indirectly (typically [cmd nx::Object]). [call [arg obj] [method "info children"] [opt "[option -type] [arg className]"] [opt [arg pattern]]] Retrieves the list of nested (or aggregated) objects of [arg obj]. The resulting list contains the fully qualified names of the nested objects. If [option -type] is set, only nested objects which are direct or indirect instances of class [arg className] are returned. Using [arg pattern], only nested objects whose names match [arg pattern] are returned. The [arg pattern] string can contain special matching characters (see [cmd "string match"]). This method allows for introspecting on [method contains]. [call [arg obj] [method "info class"]] Returns the fully qualified name of the current [cmd nx::Class] of [arg obj]. In case of [term "re-classification"] (see [method configure]), the returned class will be different from the [cmd nx::Class] from which [arg obj] was originally instantiated using [method create] or [method new]. [call [arg obj] [method "info has"] [opt "[method mixin] | [method namespace] | [method type]"] [opt "[arg arg] ..."]] [list_begin definitions] [def "[arg obj] [method "info has mixin"] [arg className]"] Verifies whether [arg obj] has a given [cmd nx::Class] [arg className] registered as a [term "mixin class"] (returns: [const true]) or not (returns: [const false]). [def "[arg obj] [method "info has namespace"]"] Checks whether the object has a companion Tcl namespace (returns: [const true]) or not (returns: [const false]). The namespace could have been created using, for example, [method "object require namespace"]. [comment {Note that the results do not necessarily correspond to those yielded by '''[namespace exists /obj/]'''.}] [def "[arg obj] [method "info has type"] [arg className]"] Tests whether the [cmd nx::Class] [arg className] is a type of the object (returns: [const true]) or not (returns: [const false]). That is, the method checks whether the object is a direct instance of [arg className] or an indirect instance of one of the superclasses of [arg className]. [list_end] [call [arg obj] [method "info lookup"] [arg submethod] [opt "[arg arg] ..."]] A collection of submethods to retrieve structural features (e.g. configuration options, [term "slot object"]s) and behavioral features (e.g. methods, [term "filter"]s) available for [arg obj] from the perspective of a client to [arg obj]. Features provided by [arg obj] itself and by the classes in its current linearization list are considered. [list_begin definitions] [def "[arg obj] [method "info lookup filter"] [arg name]"] Returns the [term "method handle"] for the [term "filter"] method [arg name], if currently registered. If there is no filter [arg name] registered, an empty string is returned. [def "[arg obj] [method "info lookup filters"] [opt [option -guards]] [opt [arg namePattern]]"] Returns the [term "method handle"]s of all filters which are active on [arg obj]. By turning on the [term switch] [option -guards], the corresponding guard expressions, if any, are also reported for each filter as a three-element list: [arg methodHandle] -guard [arg guardExpr]. The returned filters can be limited to those whose names match [arg namePattern] (see [cmd "string match"]). [def "[arg obj] [method "info lookup method"] [arg name]"] Returns the [term "method handle"] for a method [arg name] if a so-named method can be invoked on [arg obj]. If there is no method [arg name], an empty string is returned. [def "[arg obj] [method "info lookup methods"] [opt [arg namePattern]]"] Returns the names of all methods (including aliases and forwarders) which can be invoked on [arg obj]. The returned methods can be limited to those whose names match [arg namePattern] (see [cmd "string match"]). [def "[arg obj] [method "info lookup mixins"] [opt [option -guards]] [opt [arg namePattern]]"] Returns the object names of all [term "mixin class"]es which are currently active on [arg obj]. By turning on the [term switch] [option -guards], the corresponding guard expressions, if any, are also reported as a three-element list for each [term "mixin class"]: [arg className] -guard [arg guardExpr]. The returned [term "mixin class"]es can be limited to those whose names match [arg namePattern] (see [cmd "string match"]). [def "[arg obj] [method "info lookup parameters"] [arg methodName] [opt [arg namePattern]]"] Returns the [term "parameter specification"] of the method [arg methodName] callable on [arg obj] as a list of parameter names and type specifications. The resulting [term "parameter specification"] can be limited to those parameters whose names match [arg namePattern] (see [cmd "string match"]). [def "[arg obj] [method "info lookup slots"] [opt "[option "-type"] [arg className]"] [opt "[option "-source"] all | application | system"] [opt [arg namePattern]]"] Returns the command names of all [term "slot object"]s responsible for managing properties, variables, and relations of [arg obj]. The returned [term "slot object"]s can be limited according to any or a combination of the following criteria: First, [term "slot object"]s can be filtered based on their command names matching [arg namePattern] (see [cmd "string match"]). Second, [option "-type"] allows one to select [term "slot object"]s which are instantiated from a subclass [arg className] of [cmd nx::Slot] (default: [cmd nx::Slot]) . Third, [option -source] restricts [term "slot object"]s returned according to their provenance in either the NX [emph system] classes or the [emph application] classes present in the linearization list of [arg obj] (default: [emph all]). [para] To extract details of each [term "slot object"], use the [method info] submethods available for each [term "slot object"]. [def "[arg obj] [method "info lookup syntax"] [arg methodName] [opt [arg namePattern]]"] Returns the method parameters of the method [arg methodName] callable on [arg obj] as a concrete-syntax description to be used in human-understandable messages (e.g., errors or warnings, documentation strings). The result can be limited to those parameters matching the [arg namePattern] (see [cmd "string match"]). [def "[arg obj] [method "info lookup variables"]"] Returns the command names of all [term "slot object"]s responsible for managing properties and variables of [arg obj], if provided by [arg obj] or the classes in the linearization list of [arg obj]. [para] This is equivalent to calling: [arg obj] [method "info lookup slots"] -type ::nx::VariableSlot -source all [opt [arg namePattern]]. [para] To extract details of each [term "slot object"], use the [method info] submethods available for each [term "slot object"]. [list_end] [call [arg obj] [method {info name}]] Returns the unqualified name of an object, i.e., the object name without any namespace qualifiers. [include info.man.inc] [call [arg obj] [method {info parent}]] Returns the fully qualified name of the parent object of [arg obj], if any. If there is no parent object, the name of the Tcl namespace containing [arg obj] (e.g. "::") will be reported. [call [arg obj] [method {info precedence}] [opt [option -intrinsic]] [opt [arg pattern]]] Lists the classes from which [arg obj] inherits structural (e.g. properties) and behavioral features (e.g. methods) and methods, in order of the [term linearization] scheme in [term NX]. By setting the [term switch] [option -intrinsic], only classes which participate in superclass/subclass relationships (i.e., intrinsic classes) are returned. If a [arg pattern] is provided only classes whose names match [arg pattern] are returned. The [arg pattern] string can contain special matching characters (see [cmd "string match"]). [call [arg obj] [method {info variable}] [arg option] [arg handle]] Retrieves selected details about a variable represented by the given [arg handle]. A [arg handle] can be obtained by querying [arg obj] using [method "info [vset SCOPE] variables"] and [method "info lookup variables"]. Valid values for [arg option] are: [list_begin itemized] [item] [const name] returns the variable name. [item] [const parameter] returns a canonical parameter specification eligible to (re-)define the given variable (e.g. using [method "[vset SCOPE] variable"]) in a new context. [item] [const definition] returns a canonical representation of the definition command used to create the variable in its current configuration. [list_end] [call [arg obj] [method {info vars}] [opt [arg pattern]]] Yields a list of Tcl variable names created and defined for the scope of [arg obj], i.e., object variables. The list can be limited to object variables whose names match [arg pattern]. The [arg pattern] string can contain special matching characters (see [cmd "string match"]). [list_end] [comment { [cmd_def init] [list_begin definitions] [call [arg obj] [cmd init] [opt "[arg arg] ..."]] The method [method init] is called during the object construction process. It is invoked as the last step during object construction (i.e. after method [method configure]) to provide the fully initialized state of the object. Note that the definition of an [method init] method must contain an empty parameter specification, since [method init] is always called with an empty argument list. [example_begin] % nx::Class create Foo {:property x} % Foo method init {} {set :y [lb]expr {${:x} + 1}[rb]} % Foo public method bar {} {return ${:y}} % Foo create f1 -x 101 % f1 cget -x 101 % f1 bar 102 [example_end] [list_end] }] [cmd_def method] [list_begin definitions] [include method.man.inc] [list_end] [cmd_def move] [list_begin definitions] [call [arg obj] [method move] [arg newObjectName]] Effectively renames an object. First, the source object [arg obj] is cloned into a target object [arg newObjectName] using [method copy]. Second, the source object [arg obj] is destroyed by invoking [method destroy]. [method move] is also called internally when [cmd rename] is performed for a Tcl command representing an object. [list_end] [cmd_def mixins] [list_begin definitions] [include mixin.man.inc] [list_end] [cmd_def __object_configureparameter] [list_begin definitions] [def "[arg obj] [method "__object_configureparameter"]"] Computes and returns the configuration options available for [arg obj], to be consumed as method-parameter specification by [method configure]. [list_end] [cmd_def property] [list_begin definitions] [call [arg obj] [method "object property"] [opt "[option -accessor] [const public] | [const protected] | [const private]"] [opt "[option -class] [arg className]"] [opt "[option -configurable] [arg trueFalse]"] [opt [option -incremental]] [opt [option -nocomplain]] [opt "[option -trace] [const set] | [const get] | [const default]"] [arg spec] [opt [arg initBlock]]] [include property.man.inc] [para] By default, the [term property] will ascertain that no (potentially) pre-existing and equally named object variable will be overwritten when defining the property. In case of a conflict, an error exception is thrown: [example { % Object create obj { set :x 1 } ::obj % ::obj object property {x 2} object ::obj has already an instance variable named 'x' }] If the [term switch] [option -nocomplain] is on, this check is omitted (continuing the above example): [example { % ::obj object property -nocomplain {x 2} % ::obj eval {set :x} 2 }] [list_end] [cmd_def require] [list_begin definitions] [call [arg obj] [method "require namespace"]] Create a Tcl namespace named after the object [arg obj]. All object variables become available as namespace variables. [include require.man.inc] [list_end] [cmd_def unknown] [list_begin definitions] [call [arg obj] [method unknown] [arg unknownMethodName] [opt "[arg arg] ..."]] This method is called implicitly whenever an unknown method is invoked. [arg unknownMethodName] indicates the unresolvable method name, followed by the remainder of the original argument vector as a number of [arg arg] of the calling method invocation. [list_end] [cmd_def uplevel] [list_begin definitions] [call [arg obj] [method uplevel] [opt [arg level]] [arg arg1] [opt "[arg arg2] ..."]] Evaluate a script or a command at a different stack-frame level. The command behaves in essence like Tcl's [cmd uplevel], but can be used to achieve identical results when filters or mixins are registered. [list_begin itemized] [item] If the [arg level] specifier is omitted, [method uplevel] will skip any auxiliary frames added to the stack by active [term "filter"]s and [term mixin]s. The resulting stack-frame level corresponds to the [term callinglevel] as indicated by [cmd nx::current]. In this case method [method uplevel] can be used to evaluate the command in the next enclosing procedure call, i.e., a frame corresponding to a proc, method, or apply call, while skipping frames of filters and mixins. [item] If the [arg level] specifier is provided (relative, or absolute), [method "uplevel"] will execute the command in the stack-frame level. In such cases, method [method uplevel] behaves like Tcl's [method uplevel] command. [list_end] [example { % nx::Object create ::obj ::obj % ::obj public object method foo {varName} { :uplevel set $varName 1; return } ::obj::foo % namespace eval ::ns1 { ::obj foo BAR } % namespace eval ::ns1 { info exists BAR } 1 }] [list_end] Note, in the example above, [method "uplevel"] is guaranteed to resolve to the calling context of [method "foo"] ([term "ns1"]) despite mixins and filters being (potentially) registered on [cmd "obj"]. [cmd_def upvar] [list_begin definitions] [call [arg obj] [method upvar] [opt [arg level]] [arg otherVar1] [arg localVar1] [opt "[arg otherVar2] [arg localVar2] ..."]] Links one or more local variables to variables defined in other scopes (namespaces, objects, call frames). The command behaves in essence like Tcl's [cmd upvar], but can be used to achieve identical results when filters or mixins are registered. [list_begin itemized] [item] If the [arg level] specifier is omitted, [method upvar] will skip any auxiliary frames added to the stack by active [term "filter"]s and [term "mixin"]s. The resulting stack-frame level corresponds to the [term "callinglevel"] as indicated by [cmd nx::current]. Therefore, method [method upvar] gives access to the next enclosing procedure call, i.e., a frame corresponding to a proc, method, or apply call, while skipping frames of filters and mixins. [item] If the [arg level] specifier is provided (relative, or absolute), [method "upvar"] will link into the requested stack-frame level. In these cases, method [method upvar] behaves like Tcl's [method upvar] command. [list_end] [example { % nx::Object create ::obj ::obj % ::obj public object method foo {varName} { :upvar $varName x; set x 1; return } ::obj::foo % namespace eval ::ns1 { ::obj foo BAR } % namespace eval ::ns1 { info exists BAR } 1 }] [list_end] Note, in the example above, [method "upvar"] is guaranteed to resolve to the calling context of [method "foo"] ([term "ns1"]) despite mixins and filters being (potentially) registered on [cmd "obj"]. [cmd_def variable] [list_begin definitions] [comment {::nx::Object variable ?-accessor /value/? ?-incremental? ?-class /value/? ?-configurable /boolean/? ?-initblock /value/? ?-nocomplain? /spec/ ?/defaultValue/?}] [call [arg obj] [method "object variable"] [opt "[option -accessor] [const public] | [const protected] | [const private]"] [opt [option -incremental]] [opt "[option -class] [arg className]"] [opt "[option -configurable] [arg trueFalse]"] [opt "[option -initblock] [arg script]"] [opt "[option -trace] [const set] | [const get] | [const default]"] [opt [option -nocomplain]] [arg spec] [opt [arg defaultValue]]] [include variable.man.inc] [para] By default, the [term variable] will ascertain that a pre-existing and equally named object variable will not be overwritten when defining the [term variable]. In case of a conflict, an error exception is thrown: [example { % Object create obj { set :x 1 } ::obj % ::obj object variable x 2 object ::obj has already an instance variable named 'x' }] If the [term switch] [option -nocomplain] is on, this check is omitted (continuing the above example): [example { % ::obj object variable -nocomplain x 2 % ::obj eval {set :x} 2 }] [list_end] [list_end] [comment { COMMANDS list }] [comment { [cmd nx::Object] provides a set of default implementations for internally called methods, which are called primarily during the creation or destruction of NX objects. Application developers can provide custom implementations of these methods by providing tailored implementations for these methods in application classes (i.e., subclasses of [cmd nx::Object]). An adequate method implementation must comply with the method signature interfaces described below. }] [section {Object Self-Reference}] Objects are naturally recursive, with methods of an object [const ::obj] frequently invoking other methods in the same object [const ::obj] and accessing [const ::obj]'s object variables. To represent these self-references effectively in method bodies, and depending on the usage scenario, NX offers two alternative notations for self-references: one based on a special-purpose syntax token ("colon prefix"), the other based on the command [cmd nx::current]. [para] Both, the colon-prefix notation and [cmd nx::current], may be used only in method bodies and scripts passed to [method eval]. If they appear anywhere else, an error will be reported. There are three main use cases for self-references: [list_begin enumerated] [enum] As a [emph placeholder] for the currently active object, [cmd nx::current] can be used to retrieve the object name. [enum] Reading and writing [emph "object variables"] directly (i.e. without getter/setter methods in place) require the use of variable names carrying the prefix [const :] ("colon-prefix notation"). Internally, colon-prefixed variable names are processed using Tcl's variable resolvers. Alternatively, one can provide for getter/setter methods for object variables (see [method property] and [method variable]). [enum] [emph {Self-referential method calls}] can be defined via prefixing ([const :]) the method names or, alternatively, via [cmd nx::current]. Internally, colon-prefixed method names are processed using Tcl's command resolvers. The colon-prefix notation is recommended, also because it has a (slight) performance advantage over [cmd nx::current] which requires two rather than one command evaluation per method call. [list_end] See the following listing for some examples corresponding to use cases 1--3: [example { Object create ::obj { # 1) print name of currently active object ('::obj') puts [current]; # 2) object variables set :x 1; :object variable y 2; :public object method print {} { # 2.a) method-local variable set z 3; # 2.b) variable substitution using '$' and ':' puts ${:x}-${:y}-$z; # 2.c) reading variables using 'set' puts [set :x]-[set :y]-[set z]; # 2.d) writing variables using 'set', 'incr', ... set :x 1; incr :y; } :public object method show {} { # 3.a) self-referential method call using ':' :print; # 3.b) self-referential method call using 'nx::current' [current] print; # 3.c) self-referential method call using 'nx::current object' [current object] print; } :show } }] [manpage_end] ./nsf2.4.0/doc/MultiStorage-xotcl.html000644 000766 000024 00000001546 12161565463 020410 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./library/store/MultiStorage.xotcl

    ./library/store/MultiStorage.xotcl ./library/store/MultiStorage.xotcl


    Package/File Information

    No package provided/required

    Filename: ./library/store/MultiStorage.xotcl




    Back to index page.

    ./nsf2.4.0/doc/header.html.inc000644 000766 000024 00000000473 13030507001 016614 0ustar00neumannstaff000000 000000 ./nsf2.4.0/doc/configure.3000644 000766 000024 00000016710 14274463622 016021 0ustar00neumannstaff000000 000000 '\" '\" Generated from file 'configure\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2014-16 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. '\" .TH "nx::configure" 3 2\&.4\&.0 configure "NX API" .\" The -*- nroff -*- definitions below are for supplemental macros used .\" in Tcl/Tk manual entries. .\" .\" .AP type name in/out ?indent? .\" Start paragraph describing an argument to a library procedure. .\" type is type of argument (int, etc.), in/out is either "in", "out", .\" or "in/out" to describe whether procedure reads or modifies arg, .\" and indent is equivalent to second arg of .IP (shouldn't ever be .\" needed; use .AS below instead) .\" .\" .AS ?type? ?name? .\" Give maximum sizes of arguments for setting tab stops. Type and .\" name are examples of largest possible arguments that will be passed .\" to .AP later. If args are omitted, default tab stops are used. .\" .\" .BS .\" Start box enclosure. From here until next .BE, everything will be .\" enclosed in one large box. .\" .\" .BE .\" End of box enclosure. .\" .\" .CS .\" Begin code excerpt. .\" .\" .CE .\" End code excerpt. .\" .\" .VS ?version? ?br? .\" Begin vertical sidebar, for use in marking newly-changed parts .\" of man pages. The first argument is ignored and used for recording .\" the version when the .VS was added, so that the sidebars can be .\" found and removed when they reach a certain age. If another argument .\" is present, then a line break is forced before starting the sidebar. .\" .\" .VE .\" End of vertical sidebar. .\" .\" .DS .\" Begin an indented unfilled display. .\" .\" .DE .\" End of indented unfilled display. .\" .\" .SO ?manpage? .\" Start of list of standard options for a Tk widget. The manpage .\" argument defines where to look up the standard options; if .\" omitted, defaults to "options". The options follow on successive .\" lines, in three columns separated by tabs. .\" .\" .SE .\" End of list of standard options for a Tk widget. .\" .\" .OP cmdName dbName dbClass .\" Start of description of a specific option. cmdName gives the .\" option's name as specified in the class command, dbName gives .\" the option's name in the option database, and dbClass gives .\" the option's class in the option database. .\" .\" .UL arg1 arg2 .\" Print arg1 underlined, then print arg2 normally. .\" .\" .QW arg1 ?arg2? .\" Print arg1 in quotes, then arg2 normally (for trailing punctuation). .\" .\" .PQ arg1 ?arg2? .\" Print an open parenthesis, arg1 in quotes, then arg2 normally .\" (for trailing punctuation) and then a closing parenthesis. .\" .\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b .\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out .\" # BS - start boxed text .\" # ^y = starting y location .\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. .\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. .\" # VS - start vertical sidebar .\" # ^Y = starting y location .\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. .\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. .\" # Special macro to handle page bottom: finish off current .\" # box/sidebar if in box/sidebar mode, then invoked standard .\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. .\" # DS - begin display .de DS .RS .nf .sp .. .\" # DE - end display .de DE .fi .RE .sp .. .\" # SO - start of list of standard options .de SO 'ie '\\$1'' .ds So \\fBoptions\\fR 'el .ds So \\fB\\$1\\fR .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. .\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\*(So manual entry for details on the standard options. .. .\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. .\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. .\" # CE - end code excerpt .de CE .fi .RE .. .\" # UL - underline word .de UL \\$1\l'|0\(ul'\\$2 .. .\" # QW - apply quotation marks to word .de QW .ie '\\*(lq'"' ``\\$1''\\$2 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\$2 .. .\" # PQ - apply parens and quotation marks to word .de PQ .ie '\\*(lq'"' (``\\$1''\\$2)\\$3 .\"" fix emacs highlighting .el (\\*(lq\\$1\\*(rq\\$2)\\$3 .. .\" # QR - quoted range .de QR .ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3 .. .\" # MT - "empty" string .de MT .QW "" .. .BS .SH NAME nx::configure \- Get and set configuration options on the object system .SH SYNOPSIS \fBconfigure\fR \fIoption\fR ?\fIarg\fR? .sp .BE .SH DESCRIPTION .TP \fBconfigure\fR \fIoption\fR ?\fIarg\fR? This command sets and retrieves options for the NX object system\&. Legal configuration options are: .RS .IP \(bu \fBdefaultMethodCallProtection\fR returns the currently active call-protection level used as default for newly defined method implementations (if not specified explicitly by a method definition), if \fIarg\fR is not provided\&. If \fIarg\fR is set, this default call-protection level is re-set to any of the available ones: \fBpublic\fR, \fBprivate\fR, \fBprotected\fR\&. .IP \(bu \fBdefaultAccessor\fR returns the currently active call-protection level used as the default for newly defined properties (if not specified explicitly by a property definition), if \fIarg\fR is not provided\&. If \fIarg\fR is set, this default call-protection level is re-set to any of the following values: \fBpublic\fR, \fBprivate\fR, \fBprotected\fR, or \fBnone\fR\&. \fBnone\fR indicates that no accessors (getter/setter methods) will be generated for newly defined properties, if not requested explicitly\&. .RE .PP .SH COPYRIGHT .nf Copyright (c) 2014-16 Stefan Sobernig , Gustaf Neumann ; available under the Creative Commons Attribution 3\&.0 Austria license (CC BY 3\&.0 AT)\&. .fi ./nsf2.4.0/doc/speedtest-xotcl.html000644 000766 000024 00000002040 13443231446 017752 0ustar00neumannstaff000000 000000 XOTcl - Documentation -- ./tests/speedtest.xotcl

    ./tests/speedtest.xotcl ./tests/speedtest.xotcl


    Package/File Information

    No package provided/required

    Filename: ./tests/speedtest.xotcl

    Description: Regression and speed test for various ways to achieve a similar behavior.



    Back to index page.

    ./nsf2.4.0/doc/nx-small.css000644 000766 000024 00000002627 14274463622 016223 0ustar00neumannstaff000000 000000 @media print { body {font-size: 10pt; text-align: justify;} .nx {font-size: 65%; color: #000000; font-weight: normal; font-style: normal; padding-left: 10px} table.nx {border-collapse: collapse; border-spacing: 3px;} .nx-linenr {font-size: 65%; border-right: 1px solid #DDDDDD;padding-right: 5px; color: #2B547D; font-style: italic;} .nx-string {color: #779977; font-weight: normal; font-style: italic;} .nx-comment {color: #717ab3; font-weight: normal; font-style: italic;} .nx-keyword {color: #7f0055; font-weight: normal; font-style: normal;} .nx-placeholder {color: #AF663F; font-weight: normal; font-style: italic;} .nx-variable {color: #AF663F; font-weight: normal; font-style: normal;} .listingblock {font-size: 65%;} div.toclevel1 {display: block;} div.toclevel2 {display: block;} div.toclevel3 {display: block;} div.toclevel4 {display: block;} div.tableblock table { page-break-inside: avoid; } div.listingblock pre { page-break-inside: avoid; } } @page { size: A4; /* DIV 15 for A4 paper */ margin: 19.80mm 14mm; /* Not supported by Chrome, kept for later reference */ @top-center { color: #717ab3;font-style: italic; font-size: 80%; content: string(chapter-title) } @bottom-center { font-size: 80%; color: #717ab3; content: "- " counter(page) " -" } } h2 { string-set: chapter-title content() } ./nsf2.4.0/generic/stubs8.5/nsfStubInit.c000644 000766 000024 00000007245 14260520102 020613 0ustar00neumannstaff000000 000000 /* * nsfStubInit.c -- * * This file contains the initializers for the stub vectors of the Next * Scripting Framework. * * Copyright (C) 1999-2014 Gustaf Neumann (a, b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #include "nsfInt.h" /* * Remove macros that will interfere with the definitions below. */ /* * WARNING: The contents of this file is automatically generated by the * tools/genStubs.tcl script. Any modifications to the function declarations * below should be made in the generic/tcl.decls script. */ #if defined(PRE86) EXTERN NsfStubs nsfStubs; # else MODULE_SCOPE const NsfStubs nsfStubs; #endif /* !BEGIN!: Do not edit below this line. */ NsfIntStubs nsfIntStubs = { TCL_STUB_MAGIC, NULL, }; static NsfStubHooks nsfStubHooks = { &nsfIntStubs }; NsfStubs nsfStubs = { TCL_STUB_MAGIC, &nsfStubHooks, Nsf_Init, /* 0 */ NULL, /* 1 */ NsfIsClass, /* 2 */ NsfGetObject, /* 3 */ NsfGetClass, /* 4 */ NsfDeleteObject, /* 5 */ NsfRemoveObjectMethod, /* 6 */ NsfRemoveClassMethod, /* 7 */ Nsf_ObjSetVar2, /* 8 */ Nsf_ObjGetVar2, /* 9 */ Nsf_UnsetVar2, /* 10 */ NsfDStringVPrintf, /* 11 */ NsfPrintError, /* 12 */ NsfErrInProc, /* 13 */ NsfObjErrType, /* 14 */ NsfStackDump, /* 15 */ NsfSetObjClientData, /* 16 */ NsfGetObjClientData, /* 17 */ NsfSetClassClientData, /* 18 */ NsfGetClassClientData, /* 19 */ NsfRequireObjNamespace, /* 20 */ NsfCallMethodWithArgs, /* 21 */ NsfAddObjectMethod, /* 22 */ NsfAddClassMethod, /* 23 */ NsfCreate, /* 24 */ Nsf_ArgumentParse, /* 25 */ NsfLog, /* 26 */ Nsf_PointerAdd, /* 27 */ Nsf_PointerDelete, /* 28 */ Nsf_PointerTypeRegister, /* 29 */ Nsf_ConvertToBoolean, /* 30 */ Nsf_ConvertToClass, /* 31 */ Nsf_ConvertToInt32, /* 32 */ Nsf_ConvertToInteger, /* 33 */ Nsf_ConvertToObject, /* 34 */ Nsf_ConvertToPointer, /* 35 */ Nsf_ConvertToString, /* 36 */ Nsf_ConvertToTclobj, /* 37 */ Nsf_EnumerationTypeRegister, /* 38 */ Nsf_CmdDefinitionRegister, /* 39 */ NsfArgumentError, /* 40 */ Nsf_DStringPrintf, /* 41 */ }; /* !END!: Do not edit above this line. */ /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * End: */ ./nsf2.4.0/generic/stubs8.5/nsfDecls.h000644 000766 000024 00000050116 14260520102 020104 0ustar00neumannstaff000000 000000 /* * nsfDecls.h -- * * Declarations of functions in the platform independent public Nsf API. * * This file is part of the Next Scripting Framework. * * Copyright (C) 1999-2014 Gustaf Neumann (a, b) * Copyright (C) 1999-2007 Uwe Zdun (a, b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #ifndef NSF_INCLUDE_NSFDECLS #define NSF_INCLUDE_NSFDECLS /* * WARNING: This file is automatically generated by the tools/genStubs.tcl * script. Any modifications to the function declarations below should be made * in the nsf.decls script. */ /* !BEGIN!: Do not edit below this line. */ #ifdef __cplusplus extern "C" { #endif /* * Exported function declarations: */ #ifndef Nsf_Init_TCL_DECLARED #define Nsf_Init_TCL_DECLARED /* 0 */ EXTERN int Nsf_Init(Tcl_Interp *interp); #endif /* Slot 1 is reserved */ #ifndef NsfIsClass_TCL_DECLARED #define NsfIsClass_TCL_DECLARED /* 2 */ EXTERN struct Nsf_Class * NsfIsClass(Tcl_Interp *interp, ClientData cd); #endif #ifndef NsfGetObject_TCL_DECLARED #define NsfGetObject_TCL_DECLARED /* 3 */ EXTERN struct Nsf_Object * NsfGetObject(Tcl_Interp *interp, CONST char *name); #endif #ifndef NsfGetClass_TCL_DECLARED #define NsfGetClass_TCL_DECLARED /* 4 */ EXTERN struct Nsf_Class * NsfGetClass(Tcl_Interp *interp, CONST char *name); #endif #ifndef NsfDeleteObject_TCL_DECLARED #define NsfDeleteObject_TCL_DECLARED /* 5 */ EXTERN int NsfDeleteObject(Tcl_Interp *interp, struct Nsf_Object *object); #endif #ifndef NsfRemoveObjectMethod_TCL_DECLARED #define NsfRemoveObjectMethod_TCL_DECLARED /* 6 */ EXTERN int NsfRemoveObjectMethod(Tcl_Interp *interp, struct Nsf_Object *object, CONST char *methodName); #endif #ifndef NsfRemoveClassMethod_TCL_DECLARED #define NsfRemoveClassMethod_TCL_DECLARED /* 7 */ EXTERN int NsfRemoveClassMethod(Tcl_Interp *interp, struct Nsf_Class *class, CONST char *methodName); #endif #ifndef Nsf_ObjSetVar2_TCL_DECLARED #define Nsf_ObjSetVar2_TCL_DECLARED /* 8 */ EXTERN Tcl_Obj * Nsf_ObjSetVar2(struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, Tcl_Obj *valueObj, unsigned int flags); #endif #ifndef Nsf_ObjGetVar2_TCL_DECLARED #define Nsf_ObjGetVar2_TCL_DECLARED /* 9 */ EXTERN Tcl_Obj * Nsf_ObjGetVar2(struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, unsigned int flags); #endif #ifndef Nsf_UnsetVar2_TCL_DECLARED #define Nsf_UnsetVar2_TCL_DECLARED /* 10 */ EXTERN int Nsf_UnsetVar2(struct Nsf_Object *object, Tcl_Interp *interp, CONST char *name1, CONST char *name2, unsigned int flags); #endif #ifndef NsfDStringVPrintf_TCL_DECLARED #define NsfDStringVPrintf_TCL_DECLARED /* 11 */ EXTERN void NsfDStringVPrintf(Tcl_DString *dsPtr, CONST char *fmt, va_list argPtr); #endif #ifndef NsfPrintError_TCL_DECLARED #define NsfPrintError_TCL_DECLARED /* 12 */ EXTERN int NsfPrintError(Tcl_Interp *interp, CONST char *fmt, ...); #endif #ifndef NsfErrInProc_TCL_DECLARED #define NsfErrInProc_TCL_DECLARED /* 13 */ EXTERN int NsfErrInProc(Tcl_Interp *interp, Tcl_Obj *objName, Tcl_Obj *clName, CONST char *procName); #endif #ifndef NsfObjErrType_TCL_DECLARED #define NsfObjErrType_TCL_DECLARED /* 14 */ EXTERN int NsfObjErrType(Tcl_Interp *interp, CONST char *context, Tcl_Obj *value, CONST char *type, Nsf_Param CONST *NsfObjErrType); #endif #ifndef NsfStackDump_TCL_DECLARED #define NsfStackDump_TCL_DECLARED /* 15 */ EXTERN void NsfStackDump(Tcl_Interp *interp); #endif #ifndef NsfSetObjClientData_TCL_DECLARED #define NsfSetObjClientData_TCL_DECLARED /* 16 */ EXTERN void NsfSetObjClientData(Tcl_Interp *interp, Nsf_Object *object, ClientData data); #endif #ifndef NsfGetObjClientData_TCL_DECLARED #define NsfGetObjClientData_TCL_DECLARED /* 17 */ EXTERN ClientData NsfGetObjClientData(Tcl_Interp *interp, Nsf_Object *object); #endif #ifndef NsfSetClassClientData_TCL_DECLARED #define NsfSetClassClientData_TCL_DECLARED /* 18 */ EXTERN void NsfSetClassClientData(Tcl_Interp *interp, Nsf_Class *cl, ClientData data); #endif #ifndef NsfGetClassClientData_TCL_DECLARED #define NsfGetClassClientData_TCL_DECLARED /* 19 */ EXTERN ClientData NsfGetClassClientData(Tcl_Interp *interp, Nsf_Class *cl); #endif #ifndef NsfRequireObjNamespace_TCL_DECLARED #define NsfRequireObjNamespace_TCL_DECLARED /* 20 */ EXTERN void NsfRequireObjNamespace(Tcl_Interp *interp, Nsf_Object *object); #endif #ifndef NsfCallMethodWithArgs_TCL_DECLARED #define NsfCallMethodWithArgs_TCL_DECLARED /* 21 */ EXTERN int NsfCallMethodWithArgs(Tcl_Interp *interp, Nsf_Object *object, Tcl_Obj *methodObj, Tcl_Obj *arg1, int givenObjc, Tcl_Obj *CONST objv[], unsigned int flags); #endif #ifndef NsfAddObjectMethod_TCL_DECLARED #define NsfAddObjectMethod_TCL_DECLARED /* 22 */ EXTERN int NsfAddObjectMethod(Tcl_Interp *interp, struct Nsf_Object *object, CONST char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); #endif #ifndef NsfAddClassMethod_TCL_DECLARED #define NsfAddClassMethod_TCL_DECLARED /* 23 */ EXTERN int NsfAddClassMethod(Tcl_Interp *interp, struct Nsf_Class *class, CONST char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); #endif #ifndef NsfCreate_TCL_DECLARED #define NsfCreate_TCL_DECLARED /* 24 */ EXTERN int NsfCreate(Tcl_Interp *interp, Nsf_Class *class, Tcl_Obj *nameObj, int objc, Tcl_Obj *CONST objv[]); #endif #ifndef Nsf_ArgumentParse_TCL_DECLARED #define Nsf_ArgumentParse_TCL_DECLARED /* 25 */ EXTERN int Nsf_ArgumentParse(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], Nsf_Object *object, Tcl_Obj *procNameObj, Nsf_Param CONST *paramPtr, int nrParams, int serial, unsigned int processFlags, Nsf_ParseContext *pcPtr); #endif #ifndef NsfLog_TCL_DECLARED #define NsfLog_TCL_DECLARED /* 26 */ EXTERN void NsfLog(Tcl_Interp *interp, int requiredLevel, CONST char *fmt, ...); #endif #ifndef Nsf_PointerAdd_TCL_DECLARED #define Nsf_PointerAdd_TCL_DECLARED /* 27 */ EXTERN int Nsf_PointerAdd(Tcl_Interp *interp, char *buffer, size_t size, CONST char *typeName, VOID *valuePtr); #endif #ifndef Nsf_PointerDelete_TCL_DECLARED #define Nsf_PointerDelete_TCL_DECLARED /* 28 */ EXTERN int Nsf_PointerDelete(CONST char *key, VOID *valuePtr, int free); #endif #ifndef Nsf_PointerTypeRegister_TCL_DECLARED #define Nsf_PointerTypeRegister_TCL_DECLARED /* 29 */ EXTERN int Nsf_PointerTypeRegister(Tcl_Interp *interp, CONST char*typeName, int *counterPtr); #endif #ifndef Nsf_ConvertToBoolean_TCL_DECLARED #define Nsf_ConvertToBoolean_TCL_DECLARED /* 30 */ EXTERN int Nsf_ConvertToBoolean(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); #endif #ifndef Nsf_ConvertToClass_TCL_DECLARED #define Nsf_ConvertToClass_TCL_DECLARED /* 31 */ EXTERN int Nsf_ConvertToClass(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); #endif #ifndef Nsf_ConvertToInt32_TCL_DECLARED #define Nsf_ConvertToInt32_TCL_DECLARED /* 32 */ EXTERN int Nsf_ConvertToInt32(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); #endif #ifndef Nsf_ConvertToInteger_TCL_DECLARED #define Nsf_ConvertToInteger_TCL_DECLARED /* 33 */ EXTERN int Nsf_ConvertToInteger(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); #endif #ifndef Nsf_ConvertToObject_TCL_DECLARED #define Nsf_ConvertToObject_TCL_DECLARED /* 34 */ EXTERN int Nsf_ConvertToObject(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); #endif #ifndef Nsf_ConvertToPointer_TCL_DECLARED #define Nsf_ConvertToPointer_TCL_DECLARED /* 35 */ EXTERN int Nsf_ConvertToPointer(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); #endif #ifndef Nsf_ConvertToString_TCL_DECLARED #define Nsf_ConvertToString_TCL_DECLARED /* 36 */ EXTERN int Nsf_ConvertToString(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); #endif #ifndef Nsf_ConvertToTclobj_TCL_DECLARED #define Nsf_ConvertToTclobj_TCL_DECLARED /* 37 */ EXTERN int Nsf_ConvertToTclobj(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); #endif #ifndef Nsf_EnumerationTypeRegister_TCL_DECLARED #define Nsf_EnumerationTypeRegister_TCL_DECLARED /* 38 */ EXTERN int Nsf_EnumerationTypeRegister(Tcl_Interp *interp, Nsf_EnumeratorConverterEntry *typeRecords); #endif #ifndef Nsf_CmdDefinitionRegister_TCL_DECLARED #define Nsf_CmdDefinitionRegister_TCL_DECLARED /* 39 */ EXTERN int Nsf_CmdDefinitionRegister(Tcl_Interp *interp, Nsf_methodDefinition *definitionRecords); #endif #ifndef NsfArgumentError_TCL_DECLARED #define NsfArgumentError_TCL_DECLARED /* 40 */ EXTERN int NsfArgumentError(Tcl_Interp *interp, CONST char *errorMsg, Nsf_Param CONST *paramPtr, Tcl_Obj *cmdNameObj, Tcl_Obj *methodPathObj); #endif #ifndef Nsf_DStringPrintf_TCL_DECLARED #define Nsf_DStringPrintf_TCL_DECLARED /* 41 */ EXTERN void Nsf_DStringPrintf(Tcl_DString *dsPtr, CONST char *fmt, ...); #endif typedef struct NsfStubHooks { struct NsfIntStubs *nsfIntStubs; } NsfStubHooks; typedef struct NsfStubs { int magic; struct NsfStubHooks *hooks; int (*nsf_Init) (Tcl_Interp *interp); /* 0 */ VOID *reserved1; struct Nsf_Class * (*nsfIsClass) (Tcl_Interp *interp, ClientData cd); /* 2 */ struct Nsf_Object * (*nsfGetObject) (Tcl_Interp *interp, CONST char *name); /* 3 */ struct Nsf_Class * (*nsfGetClass) (Tcl_Interp *interp, CONST char *name); /* 4 */ int (*nsfDeleteObject) (Tcl_Interp *interp, struct Nsf_Object *object); /* 5 */ int (*nsfRemoveObjectMethod) (Tcl_Interp *interp, struct Nsf_Object *object, CONST char *methodName); /* 6 */ int (*nsfRemoveClassMethod) (Tcl_Interp *interp, struct Nsf_Class *class, CONST char *methodName); /* 7 */ Tcl_Obj * (*nsf_ObjSetVar2) (struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, Tcl_Obj *valueObj, unsigned int flags); /* 8 */ Tcl_Obj * (*nsf_ObjGetVar2) (struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, unsigned int flags); /* 9 */ int (*nsf_UnsetVar2) (struct Nsf_Object *object, Tcl_Interp *interp, CONST char *name1, CONST char *name2, unsigned int flags); /* 10 */ void (*nsfDStringVPrintf) (Tcl_DString *dsPtr, CONST char *fmt, va_list argPtr); /* 11 */ int (*nsfPrintError) (Tcl_Interp *interp, CONST char *fmt, ...); /* 12 */ int (*nsfErrInProc) (Tcl_Interp *interp, Tcl_Obj *objName, Tcl_Obj *clName, CONST char *procName); /* 13 */ int (*nsfObjErrType) (Tcl_Interp *interp, CONST char *context, Tcl_Obj *value, CONST char *type, Nsf_Param CONST *NsfObjErrType); /* 14 */ void (*nsfStackDump) (Tcl_Interp *interp); /* 15 */ void (*nsfSetObjClientData) (Tcl_Interp *interp, Nsf_Object *object, ClientData data); /* 16 */ ClientData (*nsfGetObjClientData) (Tcl_Interp *interp, Nsf_Object *object); /* 17 */ void (*nsfSetClassClientData) (Tcl_Interp *interp, Nsf_Class *cl, ClientData data); /* 18 */ ClientData (*nsfGetClassClientData) (Tcl_Interp *interp, Nsf_Class *cl); /* 19 */ void (*nsfRequireObjNamespace) (Tcl_Interp *interp, Nsf_Object *object); /* 20 */ int (*nsfCallMethodWithArgs) (Tcl_Interp *interp, Nsf_Object *object, Tcl_Obj *methodObj, Tcl_Obj *arg1, int givenObjc, Tcl_Obj *CONST objv[], unsigned int flags); /* 21 */ int (*nsfAddObjectMethod) (Tcl_Interp *interp, struct Nsf_Object *object, CONST char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); /* 22 */ int (*nsfAddClassMethod) (Tcl_Interp *interp, struct Nsf_Class *class, CONST char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); /* 23 */ int (*nsfCreate) (Tcl_Interp *interp, Nsf_Class *class, Tcl_Obj *nameObj, int objc, Tcl_Obj *CONST objv[]); /* 24 */ int (*nsf_ArgumentParse) (Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], Nsf_Object *object, Tcl_Obj *procNameObj, Nsf_Param CONST *paramPtr, int nrParams, int serial, unsigned int processFlags, Nsf_ParseContext *pcPtr); /* 25 */ void (*nsfLog) (Tcl_Interp *interp, int requiredLevel, CONST char *fmt, ...); /* 26 */ int (*nsf_PointerAdd) (Tcl_Interp *interp, char *buffer, size_t size, CONST char *typeName, VOID *valuePtr); /* 27 */ int (*nsf_PointerDelete) (CONST char *key, VOID *valuePtr, int free); /* 28 */ int (*nsf_PointerTypeRegister) (Tcl_Interp *interp, CONST char*typeName, int *counterPtr); /* 29 */ int (*nsf_ConvertToBoolean) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 30 */ int (*nsf_ConvertToClass) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 31 */ int (*nsf_ConvertToInt32) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 32 */ int (*nsf_ConvertToInteger) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 33 */ int (*nsf_ConvertToObject) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 34 */ int (*nsf_ConvertToPointer) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 35 */ int (*nsf_ConvertToString) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 36 */ int (*nsf_ConvertToTclobj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 37 */ int (*nsf_EnumerationTypeRegister) (Tcl_Interp *interp, Nsf_EnumeratorConverterEntry *typeRecords); /* 38 */ int (*nsf_CmdDefinitionRegister) (Tcl_Interp *interp, Nsf_methodDefinition *definitionRecords); /* 39 */ int (*nsfArgumentError) (Tcl_Interp *interp, CONST char *errorMsg, Nsf_Param CONST *paramPtr, Tcl_Obj *cmdNameObj, Tcl_Obj *methodPathObj); /* 40 */ void (*nsf_DStringPrintf) (Tcl_DString *dsPtr, CONST char *fmt, ...); /* 41 */ } NsfStubs; extern NsfStubs *nsfStubsPtr; #ifdef __cplusplus } #endif #if defined(USE_NSF_STUBS) && !defined(USE_NSF_STUB_PROCS) /* * Inline function declarations: */ #ifndef Nsf_Init #define Nsf_Init \ (nsfStubsPtr->nsf_Init) /* 0 */ #endif /* Slot 1 is reserved */ #ifndef NsfIsClass #define NsfIsClass \ (nsfStubsPtr->nsfIsClass) /* 2 */ #endif #ifndef NsfGetObject #define NsfGetObject \ (nsfStubsPtr->nsfGetObject) /* 3 */ #endif #ifndef NsfGetClass #define NsfGetClass \ (nsfStubsPtr->nsfGetClass) /* 4 */ #endif #ifndef NsfDeleteObject #define NsfDeleteObject \ (nsfStubsPtr->nsfDeleteObject) /* 5 */ #endif #ifndef NsfRemoveObjectMethod #define NsfRemoveObjectMethod \ (nsfStubsPtr->nsfRemoveObjectMethod) /* 6 */ #endif #ifndef NsfRemoveClassMethod #define NsfRemoveClassMethod \ (nsfStubsPtr->nsfRemoveClassMethod) /* 7 */ #endif #ifndef Nsf_ObjSetVar2 #define Nsf_ObjSetVar2 \ (nsfStubsPtr->nsf_ObjSetVar2) /* 8 */ #endif #ifndef Nsf_ObjGetVar2 #define Nsf_ObjGetVar2 \ (nsfStubsPtr->nsf_ObjGetVar2) /* 9 */ #endif #ifndef Nsf_UnsetVar2 #define Nsf_UnsetVar2 \ (nsfStubsPtr->nsf_UnsetVar2) /* 10 */ #endif #ifndef NsfDStringVPrintf #define NsfDStringVPrintf \ (nsfStubsPtr->nsfDStringVPrintf) /* 11 */ #endif #ifndef NsfPrintError #define NsfPrintError \ (nsfStubsPtr->nsfPrintError) /* 12 */ #endif #ifndef NsfErrInProc #define NsfErrInProc \ (nsfStubsPtr->nsfErrInProc) /* 13 */ #endif #ifndef NsfObjErrType #define NsfObjErrType \ (nsfStubsPtr->nsfObjErrType) /* 14 */ #endif #ifndef NsfStackDump #define NsfStackDump \ (nsfStubsPtr->nsfStackDump) /* 15 */ #endif #ifndef NsfSetObjClientData #define NsfSetObjClientData \ (nsfStubsPtr->nsfSetObjClientData) /* 16 */ #endif #ifndef NsfGetObjClientData #define NsfGetObjClientData \ (nsfStubsPtr->nsfGetObjClientData) /* 17 */ #endif #ifndef NsfSetClassClientData #define NsfSetClassClientData \ (nsfStubsPtr->nsfSetClassClientData) /* 18 */ #endif #ifndef NsfGetClassClientData #define NsfGetClassClientData \ (nsfStubsPtr->nsfGetClassClientData) /* 19 */ #endif #ifndef NsfRequireObjNamespace #define NsfRequireObjNamespace \ (nsfStubsPtr->nsfRequireObjNamespace) /* 20 */ #endif #ifndef NsfCallMethodWithArgs #define NsfCallMethodWithArgs \ (nsfStubsPtr->nsfCallMethodWithArgs) /* 21 */ #endif #ifndef NsfAddObjectMethod #define NsfAddObjectMethod \ (nsfStubsPtr->nsfAddObjectMethod) /* 22 */ #endif #ifndef NsfAddClassMethod #define NsfAddClassMethod \ (nsfStubsPtr->nsfAddClassMethod) /* 23 */ #endif #ifndef NsfCreate #define NsfCreate \ (nsfStubsPtr->nsfCreate) /* 24 */ #endif #ifndef Nsf_ArgumentParse #define Nsf_ArgumentParse \ (nsfStubsPtr->nsf_ArgumentParse) /* 25 */ #endif #ifndef NsfLog #define NsfLog \ (nsfStubsPtr->nsfLog) /* 26 */ #endif #ifndef Nsf_PointerAdd #define Nsf_PointerAdd \ (nsfStubsPtr->nsf_PointerAdd) /* 27 */ #endif #ifndef Nsf_PointerDelete #define Nsf_PointerDelete \ (nsfStubsPtr->nsf_PointerDelete) /* 28 */ #endif #ifndef Nsf_PointerTypeRegister #define Nsf_PointerTypeRegister \ (nsfStubsPtr->nsf_PointerTypeRegister) /* 29 */ #endif #ifndef Nsf_ConvertToBoolean #define Nsf_ConvertToBoolean \ (nsfStubsPtr->nsf_ConvertToBoolean) /* 30 */ #endif #ifndef Nsf_ConvertToClass #define Nsf_ConvertToClass \ (nsfStubsPtr->nsf_ConvertToClass) /* 31 */ #endif #ifndef Nsf_ConvertToInt32 #define Nsf_ConvertToInt32 \ (nsfStubsPtr->nsf_ConvertToInt32) /* 32 */ #endif #ifndef Nsf_ConvertToInteger #define Nsf_ConvertToInteger \ (nsfStubsPtr->nsf_ConvertToInteger) /* 33 */ #endif #ifndef Nsf_ConvertToObject #define Nsf_ConvertToObject \ (nsfStubsPtr->nsf_ConvertToObject) /* 34 */ #endif #ifndef Nsf_ConvertToPointer #define Nsf_ConvertToPointer \ (nsfStubsPtr->nsf_ConvertToPointer) /* 35 */ #endif #ifndef Nsf_ConvertToString #define Nsf_ConvertToString \ (nsfStubsPtr->nsf_ConvertToString) /* 36 */ #endif #ifndef Nsf_ConvertToTclobj #define Nsf_ConvertToTclobj \ (nsfStubsPtr->nsf_ConvertToTclobj) /* 37 */ #endif #ifndef Nsf_EnumerationTypeRegister #define Nsf_EnumerationTypeRegister \ (nsfStubsPtr->nsf_EnumerationTypeRegister) /* 38 */ #endif #ifndef Nsf_CmdDefinitionRegister #define Nsf_CmdDefinitionRegister \ (nsfStubsPtr->nsf_CmdDefinitionRegister) /* 39 */ #endif #ifndef NsfArgumentError #define NsfArgumentError \ (nsfStubsPtr->nsfArgumentError) /* 40 */ #endif #ifndef Nsf_DStringPrintf #define Nsf_DStringPrintf \ (nsfStubsPtr->nsf_DStringPrintf) /* 41 */ #endif #endif /* defined(USE_NSF_STUBS) && !defined(USE_NSF_STUB_PROCS) */ /* !END!: Do not edit above this line. */ #endif /* NSF_INCLUDE_NSFDECLS */ ./nsf2.4.0/generic/stubs8.5/nsfIntDecls.h000644 000766 000024 00000005062 14260520102 020557 0ustar00neumannstaff000000 000000 /* * nsfIntDecls.h -- * * This file contains the declarations for all unsupported * functions that are exported by the Tcl library. These * interfaces are not guaranteed to remain the same between * versions. Use at your own risk. * * Copyright (C) 1998-2008 Uwe Zdun * Copyright (C) 1998-2014 Gustaf Neumann * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #ifndef NSF_INCLUDE_NSFINTDECLS #define NSF_INCLUDE_NSFINTDECLS /* * WARNING: This file is automatically generated by the tools/genStubs.tcl * script. Any modifications to the function declarations below should be made * in the nsfInt.decls script. */ /* !BEGIN!: Do not edit below this line. */ #ifdef __cplusplus extern "C" { #endif /* * Exported function declarations: */ typedef struct NsfIntStubs { int magic; struct NsfIntStubHooks *hooks; } NsfIntStubs; extern NsfIntStubs *nsfIntStubsPtr; #ifdef __cplusplus } #endif #if defined(USE_NSF_STUBS) && !defined(USE_NSF_STUB_PROCS) /* * Inline function declarations: */ #endif /* defined(USE_NSF_STUBS) && !defined(USE_NSF_STUB_PROCS) */ /* !END!: Do not edit above this line. */ #endif /* NSF_INCLUDE_NSFINTDECLS */ ./nsf2.4.0/generic/nsfCmdDefinitions.c.ast.sh000644 000766 000024 00000001007 13543460713 021561 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.8b6471.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfCmdDefinitions.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/generic/nsfCmdDefinitions.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfCmdDefinitions.c.ast.bdump./nsf2.4.0/generic/nsf.c.ast.sh000644 000766 000024 00000000735 13543460614 016750 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.6cbc64.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsf.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/generic/nsf.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsf.c.ast.bdump./nsf2.4.0/generic/nsfStack.c000644 000766 000024 00000131231 14274721710 016532 0ustar00neumannstaff000000 000000 /* * nsfStack.c -- * * Stack handling functions of the Next Scripting Framework. * * Copyright (C) 2010-2017 Gustaf Neumann * Copyright (C) 2011-2017 Stefan Sobernig * * Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /* * Static functions defined in this file. */ static void Nsf_PushFrameObj( Tcl_Interp *interp, NsfObject *object, const CallFrame *framePtr ) nonnull(1) nonnull(2) nonnull(3); static void Nsf_PopFrameObj(Tcl_Interp *interp, CallFrame *framePtr) nonnull(1) nonnull(2); NSF_INLINE static void Nsf_PushFrameCsc( Tcl_Interp *interp, const NsfCallStackContent *cscPtr, CallFrame *framePtr ) nonnull(1) nonnull(2) nonnull(3); static void Nsf_PopFrameCsc(Tcl_Interp *interp, CallFrame *UNUSED(framePtr)) nonnull(1); static Tcl_CallFrame* CallStackGetActiveProcFrame(Tcl_CallFrame *framePtr) nonnull(1) NSF_pure; NSF_INLINE static NsfObject* GetSelfObj2( const Tcl_Interp *UNUSED(interp), Tcl_CallFrame *framePtr ) nonnull(2) NSF_pure; static Tcl_CallFrame* CallStackGetTclFrame( const Tcl_Interp *interp, Tcl_CallFrame *varFramePtr, int skip ) nonnull(1) NSF_pure; static NsfCallStackContent* CallStackGetTopFrame( const Tcl_Interp *interp, Tcl_CallFrame **framePtrPtr ) nonnull(1); NSF_INLINE static NsfCallStackContent* CallStackGetTopFrame0(const Tcl_Interp *interp) nonnull(1) NSF_pure; static NsfCallStackContent* NsfCallStackFindCallingContext( const Tcl_Interp *interp, int offset, Tcl_CallFrame **callingProcFramePtrPtr, Tcl_CallFrame **callingFramePtrPtr ) nonnull(1); static NsfCallStackContent* NsfCallStackFindActiveFrame( const Tcl_Interp *interp, int offset, Tcl_CallFrame **framePtrPtr ) nonnull(1); static void CallStackUseActiveFrame( const Tcl_Interp *interp, callFrameContext *ctx ) nonnull(1) nonnull(2); static void CallStackRestoreSavedFrames( Tcl_Interp *interp, const callFrameContext *ctx ) nonnull(1) nonnull(2); static NsfCallStackContent* CallStackFindActiveFilter(const Tcl_Interp *interp) nonnull(1) NSF_pure; static NsfCallStackContent* CallStackFindEnsembleCsc( const Tcl_CallFrame *framePtr, Tcl_CallFrame **framePtrPtr ) nonnull(1) nonnull(2); static Tcl_CallFrame* CallStackNextFrameOfType( Tcl_CallFrame *framePtr, unsigned int flags ) nonnull(1); static Tcl_Obj* CallStackMethodPath(Tcl_Interp *interp, Tcl_CallFrame *framePtr) nonnull(1) nonnull(2); NSF_INLINE static bool FilterActiveOnObj( const Tcl_Interp *interp, const NsfObject *object, const Tcl_Command cmd ) nonnull(1) nonnull(2) NSF_pure; static void CallStackReplaceVarTableReferences( const Tcl_Interp *interp, TclVarHashTable *oldVarTablePtr, TclVarHashTable *newVarTablePtr ) nonnull(1) nonnull(2) nonnull(3); #if defined(NRE) static NsfCallStackContent* CscAlloc( Tcl_Interp *interp, NsfCallStackContent *cscPtr, const Tcl_Command cmd ) nonnull(1); #else static NsfCallStackContent* CscAlloc( Tcl_Interp *interp, NsfCallStackContent *cscPtr, const Tcl_Command cmd ) nonnull(2); #endif NSF_INLINE static void CscInit_( NsfCallStackContent *cscPtr, NsfObject *object, NsfClass *class, const Tcl_Command cmd, unsigned short frameType, unsigned int flags ) nonnull(1) nonnull(2); NSF_INLINE static void CscFinish_(Tcl_Interp *interp, NsfCallStackContent *cscPtr) nonnull(1) nonnull(2); #ifdef CHECK_ACTIVATION_COUNTS static NsfClasses * NsfClassListUnlink(NsfClasses **firstPtrPtr, const void *key); /* *---------------------------------------------------------------------- * CscListAdd -- * * Add an entry to the list of unstacked CSC entries. * * Results: * None. * * Side effects: * List element added * *---------------------------------------------------------------------- */ static bool CscListRemove(const Tcl_Interp *interp, const NsfCallStackContent *cscPtr, NsfClasses **cscListPtr) nonnull(1) nonnull(2); static void CscListAdd(const Tcl_Interp *interp, const NsfCallStackContent *cscPtr) nonnull(1) nonnull(2); static void CscListAdd(const Tcl_Interp *interp, const NsfCallStackContent *cscPtr) { nonnull_assert(interp != NULL); nonnull_assert(cscPtr != NULL); NsfClassListAdd(&RUNTIME_STATE(interp)->cscList, (NsfClass *)cscPtr, NULL); } /* *---------------------------------------------------------------------- * CscListRemove -- * * Removes an entry from the list of unstacked CSC entries. * * Results: * Boolean value indicating success. * * Side effects: * * List element potentially removed and freed. If a list becomes * empty, the interp's state is updated. * *---------------------------------------------------------------------- */ static bool CscListRemove(const Tcl_Interp *interp, const NsfCallStackContent *cscPtr, NsfClasses **cscListPtr) { NsfClasses *entryPtr, **cscList; nonnull_assert(interp != NULL); nonnull_assert(cscPtr != NULL); cscList = &RUNTIME_STATE(interp)->cscList; entryPtr = NsfClassListUnlink(cscList, cscPtr); if (entryPtr != NULL) { FREE(NsfClasses, entryPtr); } if (cscListPtr != NULL) { *cscListPtr = *cscList; } return (entryPtr != NULL); } #endif /* *---------------------------------------------------------------------- * NsfShowStack -- * * Print the contents of the call-stack to stderr. This function is * for debugging purposes only. * * Results: * None. * * Side effects: * Output on stderr. * *---------------------------------------------------------------------- */ void NsfShowStack(Tcl_Interp *interp) { Tcl_CallFrame *framePtr; nonnull_assert(interp != NULL); fprintf(stderr, "NsfShowStack framePtr %p varFramePtr %p\n", (void *)Tcl_Interp_framePtr(interp), (void *)Tcl_Interp_varFramePtr(interp)); /* framePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); for (; framePtr != NULL; framePtr = Tcl_CallFrame_callerPtr(framePtr)) { fprintf(stderr, "... frame %p flags %.6x cd %p objv[0] %s\n", framePtr, Tcl_CallFrame_isProcCallFrame(framePtr), Tcl_CallFrame_clientData(framePtr), Tcl_CallFrame_objc(framePtr) ? ObjStr(Tcl_CallFrame_objv(framePtr)[0]) : "(null)"); }*/ framePtr = (Tcl_CallFrame *)Tcl_Interp_framePtr(interp); fprintf(stderr, "... varFrame flags clientData lvl ns\n"); for (; framePtr != NULL; framePtr = Tcl_CallFrame_callerPtr(framePtr)) { unsigned int frameFlags = (unsigned int)Tcl_CallFrame_isProcCallFrame(framePtr); NsfCallStackContent *cscPtr = (frameFlags & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) ? ((NsfCallStackContent *)Tcl_CallFrame_clientData(framePtr)) : NULL; fprintf(stderr, "... %16p %.6x %16p %4lu %16p %s ov %s %ld", (void *)framePtr, frameFlags, Tcl_CallFrame_clientData(framePtr), (unsigned long)Tcl_CallFrame_level(framePtr), (void *)Tcl_CallFrame_nsPtr(framePtr), Tcl_CallFrame_nsPtr(framePtr)->fullName, Tcl_CallFrame_objc(framePtr) > 0 ? ObjStr(Tcl_CallFrame_objv(framePtr)[0]) : "(null)", Tcl_CallFrame_objc(framePtr) > 0 ? (unsigned long)Tcl_CallFrame_objc(framePtr) : 0u); if (cscPtr != NULL) { fprintf(stderr, " csc %p frameType %.4x flags %.6x (%s.%p %s)\n", (void *)cscPtr, cscPtr->frameType, cscPtr->flags, ObjectName(cscPtr->self), (void *)cscPtr->cmdPtr, Tcl_GetCommandName(interp, cscPtr->cmdPtr)); } else { fprintf(stderr, " no csc"); if (frameFlags & FRAME_IS_NSF_OBJECT) { NsfObject *object = (NsfObject *)Tcl_CallFrame_clientData(framePtr); fprintf(stderr, " obj %p %s", (void *)object, ObjectName(object)); } fprintf(stderr, "\n"); } } } /* * Push and pop operations. * * Note that it is possible that between push and pop * an object->nsPtr can be created (e.g. during a read trace) */ /* *---------------------------------------------------------------------- * Nsf_PushFrameObj -- * * Push a frame with a call-stack content as an OBJECT frame. * Friend of Nsf_PopFrameObj(). * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Nsf_PushFrameObj(Tcl_Interp *interp, NsfObject *object, const CallFrame *framePtr) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(framePtr != NULL); /*fprintf(stderr, "PUSH OBJECT_FRAME (Nsf_PushFrameObj) frame %p\n", framePtr);*/ if (object->nsPtr != NULL) { Tcl_PushCallFrame(interp, (Tcl_CallFrame *)framePtr, object->nsPtr, 0|FRAME_IS_NSF_OBJECT); } else { /* The object has no nsPtr, so we disguise as a proc, using fakeProc */ Tcl_PushCallFrame(interp, (Tcl_CallFrame *)framePtr, Tcl_CallFrame_nsPtr(Tcl_Interp_varFramePtr(interp)), FRAME_IS_PROC|FRAME_IS_NSF_OBJECT); Tcl_CallFrame_procPtr(framePtr) = &RUNTIME_STATE(interp)->fakeProc; if (unlikely(object->varTablePtr == NULL)) { object->varTablePtr = VarHashTableCreate(); } Tcl_CallFrame_varTablePtr(framePtr) = object->varTablePtr; } Tcl_CallFrame_clientData(framePtr) = (ClientData)object; } /* *---------------------------------------------------------------------- * Nsf_PopFrameObj -- * * Pop a frame with a call-stack content as an OBJECT frame. * Friend of Nsf_PushFrameObj(). * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Nsf_PopFrameObj(Tcl_Interp *interp, CallFrame *framePtr) { nonnull_assert(interp != NULL); nonnull_assert(framePtr != NULL); /*fprintf(stderr, "POP OBJECT_FRAME (Nsf_PopFrameObj) frame %p, varTable %p set to NULL, already %d\n", framePtr, Tcl_CallFrame_varTablePtr(framePtr), Tcl_CallFrame_varTablePtr(framePtr) == NULL);*/ Tcl_CallFrame_varTablePtr(framePtr) = NULL; Tcl_PopCallFrame(interp); } /* *---------------------------------------------------------------------- * Nsf_PushFrameCsc, Nsf_PopFrameCsc -- * * Push or pop a frame with a call-stack content as a CMETHOD frame. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static void Nsf_PushFrameCsc(Tcl_Interp *interp, const NsfCallStackContent *cscPtr, CallFrame *framePtr) { CallFrame *varFramePtr; nonnull_assert(interp != NULL); nonnull_assert(cscPtr != NULL); nonnull_assert(framePtr != NULL); varFramePtr = Tcl_Interp_varFramePtr(interp); /*fprintf(stderr, "PUSH CMETHOD_FRAME (Nsf_PushFrameCsc) frame %p cscPtr %p methodName %s\n", framePtr, cscPtr, Tcl_GetCommandName(interp, cscPtr->cmdPtr));*/ Tcl_PushCallFrame(interp, (Tcl_CallFrame *)framePtr, Tcl_CallFrame_nsPtr(varFramePtr), FRAME_IS_PROC|FRAME_IS_NSF_CMETHOD); Tcl_CallFrame_clientData(framePtr) = (ClientData)cscPtr; Tcl_CallFrame_procPtr(framePtr) = &RUNTIME_STATE(interp)->fakeProc; } NSF_INLINE static void Nsf_PopFrameCsc(Tcl_Interp *interp, CallFrame *UNUSED(framePtr)) { nonnull_assert(interp != NULL); /*fprintf(stderr, "POP CMETHOD_FRAME (Nsf_PopFrameCsc) frame %p, varTablePtr = %p\n", framePtr, Tcl_CallFrame_varTablePtr(framePtr));*/ Tcl_PopCallFrame(interp); } /* * Stack query operations. */ /* *---------------------------------------------------------------------- * CallStackGetActiveProcFrame -- * * Return the Tcl call frame of the last scripted method. * * Results: * Active Tcl_CallFrame (might be NULL). * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_CallFrame * CallStackGetActiveProcFrame(Tcl_CallFrame *framePtr) { nonnull_assert(framePtr != NULL); do { register unsigned int flag = (unsigned int)Tcl_CallFrame_isProcCallFrame(framePtr); if ((flag & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) != 0) { /* never return an inactive method frame */ if (likely(!(((NsfCallStackContent *)Tcl_CallFrame_clientData(framePtr))->frameType & NSF_CSC_TYPE_INACTIVE))) { break; } } else { if (likely((flag & (FRAME_IS_NSF_OBJECT)) == 0u)) { if (flag == 0 || (flag & FRAME_IS_PROC) != 0) { break; } } } framePtr = Tcl_CallFrame_callerPtr(framePtr); } while (framePtr != NULL); return framePtr; } /* *---------------------------------------------------------------------- * GetSelfObj, GetSelfObj2 -- * * Return the corresponding object from a method or from an object * frame. GetSelfObj defaults to the top-most call-frame, * GetSelfObj2 allows one to set another frame. * * Results: * NsfObject * or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ #define SKIP_LEVELS 1 #define SKIP_LAMBDA 1 #if defined(SKIP_LAMBDA) # if !defined(SKIP_LEVELS) # define SKIP_LEVELS 1 # endif #endif #define GetSelfObj(interp) \ GetSelfObj2((interp), (Tcl_CallFrame *)Tcl_Interp_varFramePtr((interp))) NSF_INLINE static NsfObject* GetSelfObj2(const Tcl_Interp *UNUSED(interp), Tcl_CallFrame *framePtr) { register Tcl_CallFrame *varFramePtr; nonnull_assert(framePtr != NULL); /*fprintf(stderr, "GetSelfObj interp has frame %p and var-frame %p\n", Tcl_Interp_framePtr(interp), Tcl_Interp_varFramePtr(interp));*/ for (varFramePtr = framePtr; varFramePtr != NULL; varFramePtr = #if defined(SKIP_LEVELS) Tcl_CallFrame_callerPtr(varFramePtr) #else NULL #endif ) { register unsigned int flags; flags = (unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr); if (likely((flags & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) != 0u)) { return ((NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr))->self; } else if ((flags & FRAME_IS_NSF_OBJECT) != 0u) { return (NsfObject *)Tcl_CallFrame_clientData(varFramePtr); } #if defined(SKIP_LAMBDA) if ((flags & FRAME_IS_LAMBDA) != 0u) { continue; } break; #endif } return NULL; } /* *---------------------------------------------------------------------- * CallStackGetTclFrame -- * * Return the Tcl_Callframe a (scripted or non-leaf) method starting with * the specified or topmost frame; if skip is a positive number the * specified number of Tcl frames are skipped. * * Results: * Tcl_CallFrame or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_CallFrame* CallStackGetTclFrame(const Tcl_Interp *interp, Tcl_CallFrame *varFramePtr, int skip) { nonnull_assert(interp != NULL); assert(skip >= 0); /* NsfShowStack(interp); */ if (varFramePtr == NULL) { varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); } while(skip-- && varFramePtr != NULL) { varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr); } for (; varFramePtr != NULL; varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr)) { if (((unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr) & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) != 0u) { return varFramePtr; } } return NULL; } /* *---------------------------------------------------------------------- * CallStackGetTopFrame, CallStackGetTopFrame0, NsfCallStackGetTopFrame -- * * Return the NsfCallStackContent* of the topmost invocation of a (scripted * or non-leaf) method. If framePtrPtr is provided, it is used to return the * Tcl frame as well. * * Results: * Call stack content or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfCallStackContent* CallStackGetTopFrame(const Tcl_Interp *interp, Tcl_CallFrame **framePtrPtr) { register Tcl_CallFrame *varFramePtr; nonnull_assert(interp != NULL); for (varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); varFramePtr != NULL; varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr)) { if (((unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr) & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) != 0u) { if (framePtrPtr != NULL) { *framePtrPtr = varFramePtr; } return (NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr); } } if (framePtrPtr != NULL) { *framePtrPtr = NULL; } return NULL; } NSF_INLINE static NsfCallStackContent* CallStackGetTopFrame0(const Tcl_Interp *interp) { register Tcl_CallFrame *varFramePtr; NsfCallStackContent *result = NULL; nonnull_assert(interp != NULL); for (varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); varFramePtr != NULL; varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr)) { if (likely(((unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr) & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) != 0u)) { result = (NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr); break; } } return result; } #if defined(NSF_PROFILE) NsfCallStackContent* NsfCallStackGetTopFrame(const Tcl_Interp *interp, Tcl_CallFrame **framePtrPtr) nonnull(1); NsfCallStackContent* NsfCallStackGetTopFrame(const Tcl_Interp *interp, Tcl_CallFrame **framePtrPtr) { return CallStackGetTopFrame(interp, framePtrPtr); } #endif /* *---------------------------------------------------------------------- * NsfCallStackFindCallingContext -- * * Find the calling context (frame) with a specified offset. Find the * frame corresponding to the calling proc or (scripted or non-leaf) * method. * * Results: * Call stack content (for NSF methods) or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfCallStackContent * NsfCallStackFindCallingContext(const Tcl_Interp *interp, int offset, Tcl_CallFrame **callingProcFramePtrPtr, Tcl_CallFrame **callingFramePtrPtr) { register Tcl_CallFrame *varFramePtr; nonnull_assert(interp != NULL); varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); if (likely(varFramePtr != NULL)) { TCL_SIZE_T lvl = Tcl_CallFrame_level(varFramePtr); do { register unsigned int flags = (unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr); if (flags != 0u) { /* * A proc frame */ NsfCallStackContent *cscPtr = (flags & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) ? ((NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr)) : NULL; if ((cscPtr != NULL) && ((cscPtr->flags & (NSF_CSC_CALL_IS_NEXT|NSF_CSC_CALL_IS_ENSEMBLE)) || (cscPtr->frameType & NSF_CSC_TYPE_INACTIVE)) ) { /* * Skip NSF method frames, which are next calls, ensembles or * inactive. */ } else { if (offset != 0) { offset--; } else if (Tcl_CallFrame_level(varFramePtr) < lvl) { if (callingProcFramePtrPtr != NULL) { *callingProcFramePtrPtr = varFramePtr; } return cscPtr; } } } else if (callingFramePtrPtr != NULL && *callingFramePtrPtr == NULL && Tcl_CallFrame_level(varFramePtr) < lvl ) { *callingFramePtrPtr = varFramePtr; } /* * Continue in loop. */ varFramePtr = Tcl_CallFrame_callerVarPtr(varFramePtr); } while (likely(varFramePtr != NULL)); if (callingProcFramePtrPtr != NULL) { *callingProcFramePtrPtr = NULL; } } return NULL; } /* *---------------------------------------------------------------------- * NsfCallStackFindActiveFrame -- * * Search for the first active frame on the call-stack. * * Results: * Call stack content or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfCallStackContent * NsfCallStackFindActiveFrame(const Tcl_Interp *interp, int offset, Tcl_CallFrame **framePtrPtr) { register Tcl_CallFrame *varFramePtr; nonnull_assert(interp != NULL); /* skip #offset frames */ for (varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); (offset > 0) && (varFramePtr != NULL); varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr), offset--); /* search for first active frame and set Tcl frame pointers */ for (; varFramePtr != NULL; varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr)) { if (((unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr) & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) != 0u) { NsfCallStackContent *cscPtr = (NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr); if (!(cscPtr->frameType & NSF_CSC_TYPE_INACTIVE)) { /* we found the highest active frame */ if (framePtrPtr != NULL) { *framePtrPtr = varFramePtr; } return cscPtr; } } } /* * We could not find an active frame; called from top-level? */ if (framePtrPtr != NULL) { *framePtrPtr = NULL; } return NULL; } /* *---------------------------------------------------------------------- * CallStackUseActiveFrame -- * * Activate the varFrame of the first active non-object frame and * save the previously active frames in the call frame context. * These stored frames are typically reactivated by * CallStackRestoreSavedFrames(). * * Results: * None. * * Side effects: * The varFramePtr of the interp is potentially updated. * *---------------------------------------------------------------------- */ static void CallStackUseActiveFrame(const Tcl_Interp *interp, callFrameContext *ctx) { Tcl_CallFrame *framePtr, *inFramePtr; nonnull_assert(interp != NULL); nonnull_assert(ctx != NULL); inFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); /* * Get the first active non-object frame . */ framePtr = CallStackGetActiveProcFrame(inFramePtr); /*fprintf(stderr, "... use frameptr %p \n", framePtr);*/ if (inFramePtr == framePtr) { /* call frame pointers are fine */ ctx->frameSaved = NSF_FALSE; } else { ctx->varFramePtr = inFramePtr; /*fprintf(stderr, "CallStackUseActiveFrame stores %p\n", framePtr);*/ Tcl_Interp_varFramePtr(interp) = (CallFrame *)framePtr; ctx->frameSaved = NSF_TRUE; } } /* *---------------------------------------------------------------------- * CallStackRestoreSavedFrames -- * * Restore the previously saved frames from the specified call * frame context. These frames are typically saved by * CallStackUseActiveFrame(). * * Results: * None. * * Side effects: * The varFramePtr of the interp is potentially updated. * *---------------------------------------------------------------------- */ static void CallStackRestoreSavedFrames(Tcl_Interp *interp, const callFrameContext *ctx) { nonnull_assert(interp != NULL); nonnull_assert(ctx != NULL); if (ctx->frameSaved) { /*fprintf(stderr, "CallStackRestoreSavedFrames drops %p restores %p\n", Tcl_Interp_varFramePtr(interp), ctx->varFramePtr);*/ Tcl_Interp_varFramePtr(interp) = (CallFrame *)ctx->varFramePtr; } } /* *---------------------------------------------------------------------- * CallStackFindActiveFilter -- * * Return the call-stack content of the currently active filter * * Results: * Call-stack content or NULL, if no filter is active. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfCallStackContent * CallStackFindActiveFilter(const Tcl_Interp *interp) { register const Tcl_CallFrame *varFramePtr; nonnull_assert(interp != NULL); varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); for (; varFramePtr != NULL; varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr)) { if (((unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr) & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) != 0u) { NsfCallStackContent *cscPtr; cscPtr = (NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr); if (cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_FILTER) { return cscPtr; } } } /* * For some reasons, we could not find invocation (might be top-level, * destroy). */ return NULL; } /* *---------------------------------------------------------------------- * CallStackFindEnsembleCsc -- * * Return the call-stack content and the optionally the stack frame * of the last ensemble invocation. * * Results: * Call-stack content. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfCallStackContent * CallStackFindEnsembleCsc(const Tcl_CallFrame *framePtr, Tcl_CallFrame **framePtrPtr) { register Tcl_CallFrame *varFramePtr; NsfCallStackContent *cscPtr = NULL; nonnull_assert(framePtr != NULL); nonnull_assert(framePtrPtr != NULL); for (/* Skipping the starting frame, assuming a "leaf" frame in an ensemble dispatch */ varFramePtr = Tcl_CallFrame_callerPtr(framePtr); ((unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr) & FRAME_IS_NSF_CMETHOD) != 0u; varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr)) { cscPtr = (NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr); assert(cscPtr != NULL); /*fprintf(stderr, "--- frame %p cmdPtr %p NSF_CSC_TYPE_ENSEMBLE %d NSF_CSC_CALL_IS_ENSEMBLE %d \ NSF_CSC_TYPE_INACTIVE %d\n", varFramePtr, cscPtr->cmdPtr, (cscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE) != 0, (cscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE) != 0, (cscPtr->frameType & NSF_CSC_TYPE_INACTIVE) != 0);*/ /* * The "root" frame in a call-stack branch resulting from an ensemble * dispatch is not typed as an NSF_CSC_TYPE_ENSEMBLE frame, the call type * /is/ NSF_CSC_CALL_IS_ENSEMBLE. */ if ((cscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE) == 0u && (cscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE)) { break; } } *framePtrPtr = varFramePtr; return cscPtr; } /* *---------------------------------------------------------------------- * CallStackNextFrameOfType -- * * Return the next frame on the call stack being of a specified type. The * type is specified by a bit mask passed as flags. * * Results: * Tcl_CallFrame (might be NULL). * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_CallFrame * CallStackNextFrameOfType(Tcl_CallFrame *framePtr, unsigned int flags) { nonnull_assert(framePtr != NULL); do { NsfCallStackContent *cscPtr = Tcl_CallFrame_clientData(framePtr); if (cscPtr != NULL && (cscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE) != 0u) { (void)CallStackFindEnsembleCsc(framePtr, &framePtr); } if (((unsigned int)Tcl_CallFrame_isProcCallFrame(framePtr) & flags) != 0u) { /* * framePtr has already the return value. */ break; } framePtr = Tcl_CallFrame_callerPtr(framePtr); } while (framePtr != NULL); return framePtr; } /* *---------------------------------------------------------------------- * CallStackMethodPath -- * * Return the method path of the current ensemble in a Tcl_Obj with * refCount 0. * * Results: * Tcl_Obj containing the method path * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj* CallStackMethodPath(Tcl_Interp *interp, Tcl_CallFrame *framePtr) { int elements; Tcl_Obj *resultObj, *methodPathObj = Tcl_NewListObj(0, NULL); nonnull_assert(interp != NULL); nonnull_assert(framePtr != NULL); /* * Append all ensemble names to the specified list obj */ for (elements = 0; ((unsigned int)Tcl_CallFrame_isProcCallFrame(framePtr) & (FRAME_IS_NSF_CMETHOD|FRAME_IS_NSF_METHOD)) != 0u; framePtr = Tcl_CallFrame_callerPtr(framePtr)) { const NsfCallStackContent *cscPtr = (NsfCallStackContent *)Tcl_CallFrame_clientData(framePtr); assert(cscPtr != NULL); /*fprintf(stderr, "--- frame %p cmdPtr %p cmd %s NSF_CSC_TYPE_ENSEMBLE %d \ NSF_CSC_CALL_IS_ENSEMBLE %d NSF_CSC_TYPE_INACTIVE %d\n", framePtr, cscPtr->cmdPtr, Tcl_GetCommandName(interp, cscPtr->cmdPtr), (cscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE) != 0, (cscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE) != 0, (cscPtr->frameType & NSF_CSC_TYPE_INACTIVE) != 0);*/ /* * The "ensemble" call type, we find applied to all intermediate and * leaf ensemble frames. By filtering according to the ensemble call * type, we effectively omit leaf ensemble and non-ensemble frames * from being reported. */ if ((cscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE) == 0u) { break; } /* * The call-stack might contain consecutive calls of ensemble entry * calls chained via next. We can detect consecutive calls via the * elements count. */ if (elements == 0 && (cscPtr->flags & NSF_CM_ENSEMBLE_UNKNOWN) && (cscPtr->flags & NSF_CSC_CALL_IS_NEXT)) { break; } Tcl_ListObjAppendElement(interp, methodPathObj, Tcl_NewStringObj(Tcl_GetCommandName(interp, cscPtr->cmdPtr), TCL_INDEX_NONE)); elements++; /* * The "root" frame in a call-stack branch resulting from an * ensemble dispatch is not typed as an NSF_CSC_TYPE_ENSEMBLE frame, * the call type /is/ NSF_CSC_CALL_IS_ENSEMBLE (as checked above). */ if ((cscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE) == 0u) { break; } } /* * The resulting list has reversed order. If there are multiple * arguments, reverse the list to obtain the right order. */ if (elements > 1) { int oc, i; Tcl_Obj **ov; INCR_REF_COUNT(methodPathObj); Tcl_ListObjGetElements(interp, methodPathObj, &oc, &ov); resultObj = Tcl_NewListObj(0, NULL); for (i = elements-1; i >= 0; i--) { Tcl_ListObjAppendElement(interp, resultObj, ov[i]); } DECR_REF_COUNT(methodPathObj); } else { resultObj = methodPathObj; } /*fprintf(stderr, "--- CallStackMethodPath returns %s\n", ObjStr(resultObj));*/ return resultObj; } /* *---------------------------------------------------------------------- * FilterActiveOnObj -- * * Check, if there is an active filter on "obj" using the specified * cmd. * * Results: * Boolean value indicating success. * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static bool FilterActiveOnObj( const Tcl_Interp *interp, const NsfObject *object, const Tcl_Command cmd ) { register const Tcl_CallFrame *varFramePtr; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); varFramePtr = (const Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); for (; varFramePtr != NULL; varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr)) { if (((unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr) & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) != 0u) { NsfCallStackContent *cscPtr = (NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr); if (cmd == cscPtr->cmdPtr && object == cscPtr->self && cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_FILTER) { return NSF_TRUE; } } } return NSF_FALSE; } /* *---------------------------------------------------------------------- * CallStackReplaceVarTableReferences -- * * Replace all references to the old var table (arg 1) by * references to a new var table (arg 2) on the call-stack. * This function is e.g. used by require namespace. * * Results: * None. * * Side effects: * Updated stack. * *---------------------------------------------------------------------- */ static void CallStackReplaceVarTableReferences(const Tcl_Interp *interp, TclVarHashTable *oldVarTablePtr, TclVarHashTable *newVarTablePtr) { Tcl_CallFrame *framePtr; nonnull_assert(interp != NULL); nonnull_assert(oldVarTablePtr != NULL); nonnull_assert(newVarTablePtr != NULL); for (framePtr = (Tcl_CallFrame *)Tcl_Interp_framePtr(interp); framePtr != NULL; framePtr = Tcl_CallFrame_callerPtr(framePtr)) { unsigned int frameFlags = (unsigned int)Tcl_CallFrame_isProcCallFrame(framePtr); if ((frameFlags & FRAME_IS_NSF_OBJECT) == 0u) { continue; } if (!(Tcl_CallFrame_varTablePtr(framePtr) == oldVarTablePtr)) { continue; } /*fprintf(stderr, "+++ makeObjNamespace replacing varTable %p with %p in frame %p\n", oldVarTablePtr, newVarTablePtr, framePtr);*/ Tcl_CallFrame_varTablePtr(framePtr) = newVarTablePtr; } } /* *---------------------------------------------------------------------- * CallStackPopAll -- * * Unwind the stack and pop all call-stack entries that are still * alive (e.g. if "exit" is called and we were jumping out of the * call-frame). * * Results: * None. * * Side effects: * Updated stack. * *---------------------------------------------------------------------- */ static void CallStackPopAll(Tcl_Interp *interp) { nonnull_assert(interp != NULL); if (RUNTIME_STATE(interp)->logSeverity == NSF_LOG_DEBUG) { NsfShowStack(interp); } while (1) { const Tcl_CallFrame *framePtr = Tcl_Interp_framePtr(interp); unsigned int frameFlags; if (framePtr == NULL || (Tcl_CallFrame_level(framePtr) == 0)) { break; } frameFlags = (unsigned int)Tcl_CallFrame_isProcCallFrame(framePtr); /*fprintf(stderr, "--- popping %p frame-flags %.6x\n", framePtr, frameFlags);*/ if ((frameFlags & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD))) { /* free the call stack content; we need this just for decr activation count */ NsfCallStackContent *cscPtr = ((NsfCallStackContent *)Tcl_CallFrame_clientData(framePtr)); #if defined(NRE) /* Mask out IS_NRE, since Tcl_PopCallFrame takes care about TclStackFree */ cscPtr->flags &= ~NSF_CSC_CALL_IS_NRE; #endif CscFinish(interp, cscPtr, TCL_OK, "popall"); } else if (frameFlags & FRAME_IS_NSF_OBJECT) { Tcl_CallFrame_varTablePtr(framePtr) = NULL; } /* pop the Tcl frame */ Tcl_PopCallFrame(interp); } #if defined(CHECK_ACTIVATION_COUNTS) { int count = 0; NsfClasses *unstackedEntries = RUNTIME_STATE(interp)->cscList, *nextCscPtr = unstackedEntries; while (nextCscPtr != NULL) { NsfCallStackContent *cscPtr = (NsfCallStackContent *)nextCscPtr->cl; CscListRemove(interp, cscPtr, &unstackedEntries); CscFinish(interp, cscPtr, TCL_OK, "unwind"); count ++; nextCscPtr = (unstackedEntries != NULL) ? unstackedEntries->nextPtr : NULL; } if (count>0 && RUNTIME_STATE(interp)->logSeverity > 0) { fprintf(stderr, "+++ unwind removed %d unstacked csc entries\n", count); } } #endif } /* *---------------------------------------------------------------------- * CscAlloc -- * * Allocate the CSC structure either from the stack or via StackAlloc (the * latter is recorded in the callType). The CscAlloc operation requires a * CscFinish operation later. * * Results: * A valid, semi-initialized cscPtr. * * Side effects: * Memory allocation * *---------------------------------------------------------------------- */ static NsfCallStackContent * CscAlloc(Tcl_Interp *interp, NsfCallStackContent *cscPtr, const Tcl_Command cmd) { #if defined(NRE) Tcl_ObjCmdProc *proc = (cmd != NULL) ? Tcl_Command_objProc(cmd) : NULL; if (proc == TclObjInterpProc) { cscPtr = (NsfCallStackContent *) NsfTclStackAlloc(interp, sizeof(NsfCallStackContent), "csc"); cscPtr->flags = NSF_CSC_CALL_IS_NRE; } else { cscPtr->flags = 0; } #else nonnull_assert(cscPtr != NULL); (void)interp; (void)cmd; cscPtr->flags = 0; #endif /*fprintf(stderr, "CscAlloc allocated %p\n", cscPtr);*/ return cscPtr; } /* *---------------------------------------------------------------------- * CscInit -- * * Initialize call stack content and track activation counts * of involved objects and classes * * Results: * None. * * Side effects: * Initialized Csc, updated activation counts * *---------------------------------------------------------------------- */ NSF_INLINE static void CscInit_( NsfCallStackContent *cscPtr, NsfObject *object, NsfClass *class, const Tcl_Command cmd, unsigned short frameType, unsigned int flags ) { #if defined(NSF_PROFILE) struct Tcl_Time trt; #endif nonnull_assert(cscPtr != NULL); nonnull_assert(object != NULL); #if defined(NSF_PROFILE) Tcl_GetTime(&trt); cscPtr->startUsec = trt.usec; cscPtr->startSec = trt.sec; #endif /* * When cmd is provided, the call is not unknown, the method * will be executed and the object will be stacked. In these * cases, we maintain an activation count. */ if (likely(cmd != NULL)) { /* * Track object activations. */ object->activationCount ++; MEM_COUNT_ALLOC("object.activationCount", object); /*fprintf(stderr, "CscInit %p method %s activationCount ++ (%s) --> %d (cl %p)\n", cscPtr, (cmd != NULL) ? Tcl_GetCommandName(object->teardown, cmd) : "UNK", ObjectName(object), object->activationCount, cl);*/ /* * Track class activations. */ if (class != NULL) { /* * handle class activation count */ class->object.activationCount ++; MEM_COUNT_ALLOC("class.activationCount", class); /* * Increment the namespace pointer in case Tcl tries to delete * this namespace during the invocation. */ NSNamespacePreserve(Tcl_Command_nsPtr(cmd)); /*fprintf(stderr, "NSNamespacePreserve %p\n", nsPtr);*/ } NsfCommandPreserve(cmd); } cscPtr->flags |= flags & NSF_CSC_COPY_FLAGS; cscPtr->self = object; cscPtr->cl = class; cscPtr->cmdPtr = cmd; cscPtr->objv = NULL; cscPtr->filterStackEntry = object->filterStack; cscPtr->frameType = frameType; /*fprintf(stderr, "CscInit %p (%s) object %p %s flags %.6x cmdPtr %p\n", cscPtr, msg, object, ObjectName(object), cscPtr->flags, cscPtr->cmdPtr);*/ } /* *---------------------------------------------------------------------- * CscFinish -- * * Counterpart of CscInit(). Decrement activation counts * and delete objects/classes if necessary. * * Results: * None. * * Side effects: * potentially deletes objects, classes or namespaces. * *---------------------------------------------------------------------- */ NSF_INLINE static void CscFinish_(Tcl_Interp *interp, NsfCallStackContent *cscPtr) { nonnull_assert(interp != NULL); nonnull_assert(cscPtr != NULL); assert(cscPtr->self != NULL); #if defined(NSF_PROFILE) if (RUNTIME_STATE(interp)->doProfile) { NsfProfileRecordMethodData(interp, cscPtr); } #endif /*fprintf(stderr, "CscFinish %p object %p %s flags %.6x cmdPtr %p\n", cscPtr, cscPtr->self, ObjectName(cscPtr->self), cscPtr->flags, cscPtr->cmdPtr); */ /* * In the cases, where a cmd was provided, we tracked in init the * activations. Release these activations now. Note that * cscPtr->cmdPtr might have been epoched, but it is still * available, since we used NsfCommandPreserve() in CscInit(). */ if (likely(cscPtr->cmdPtr != NULL)) { int allowDestroy = RUNTIME_STATE(interp)->exitHandlerDestroyRound == NSF_EXITHANDLER_OFF; NsfObject *object = cscPtr->self; if ((Tcl_Command_flags(cscPtr->cmdPtr) & NSF_CMD_DEBUG_METHOD) != 0) { #if defined(NSF_PROFILE) || defined(NSF_DTRACE) NsfProfileDebugExit(interp, cscPtr->self, cscPtr->cl, cscPtr->methodName, cscPtr->startSec, cscPtr->startUsec); #else NsfProfileDebugExit(interp, cscPtr->self, cscPtr->cl, Tcl_GetCommandName(interp, cscPtr->cmdPtr), 0, 0); #endif } /* * Track object activations */ object->activationCount --; MEM_COUNT_FREE("object.activationCount", object); /*fprintf(stderr, "CscFinish decr activationCount for %s to %d object->flags %.6x dc %.6x succ %.6x\n", ObjectName(cscPtr->self), cscPtr->self->activationCount, object->flags, object->flags & NSF_DESTROY_CALLED, object->flags & NSF_DESTROY_CALLED_SUCCESS );*/ assert(object->activationCount > -1); if (object->activationCount < 1 && (object->flags & NSF_DESTROY_CALLED) && allowDestroy) { /*fprintf(stderr, "CscFinish calls destroy object %p\n", object);*/ CallStackDoDestroy(interp, object); } /* * Track class activations */ if (unlikely(cscPtr->cl != NULL)) { NsfObject *clObject = &cscPtr->cl->object; clObject->activationCount --; MEM_COUNT_FREE("class.activationCount", clObject); /*fprintf(stderr, "CscFinish class %p %s check ac %d flags destroy %.6x success %.6x\n", clObject, ObjectName(clObject), clObject->activationCount, clObject->flags & NSF_DESTROY_CALLED, clObject->flags & NSF_DESTROY_CALLED_SUCCESS);*/ if (clObject->activationCount < 1 && clObject->flags & NSF_DESTROY_CALLED && allowDestroy) { /* fprintf(stderr, "CscFinish calls destroy class %p\n", clObject);*/ CallStackDoDestroy(interp, clObject); } /* * Release the Namespace */ NSNamespaceRelease(Tcl_Command_nsPtr(cscPtr->cmdPtr)); } /* * Release the Command */ NsfCommandRelease(cscPtr->cmdPtr); } #if defined(NRE) if ((cscPtr->flags & NSF_CSC_CALL_IS_NRE)) { NsfTclStackFree(interp, cscPtr, "CscFinish"); } #endif /*fprintf(stderr, "CscFinish done\n");*/ } /* *---------------------------------------------------------------------- * BeginOfCallChain -- * * Experimental function to track the begin of a call chain. * Currently not used. * * Results: * Callframe ptr * * Side effects: * None. * *---------------------------------------------------------------------- */ #if 0 static Tcl_CallFrame * BeginOfCallChain(const Tcl_Interp *interp, NsfObject *object) nonnull(1); static Tcl_CallFrame * BeginOfCallChain(const Tcl_Interp *interp, NsfObject *object) { Tcl_CallFrame *varFramePtr, *prevFramePtr; nonnull_assert(interp != NULL); varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); prevFramePtr = varFramePtr; if (object != NULL) { fprintf(stderr, "BeginOfCallChain obj %s\n", ObjectName(object)); for (; varFramePtr != NULL; varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr)) { register unsigned int flags = Tcl_CallFrame_isProcCallFrame(varFramePtr); if (flags & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) { const NsfCallStackContent *cscPtr = (NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr); if (cscPtr->self == object) { prevFramePtr = varFramePtr; continue; } } else if ((flags & (FRAME_IS_NSF_OBJECT|FRAME_IS_LAMBDA)) != 0u) { continue; } break; } } fprintf(stderr, "BeginOfCallChain returns %p\n", prevFramePtr); return prevFramePtr; } #endif /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * End: */ ./nsf2.4.0/generic/nsfFunPtrHashTable.c000644 000766 000024 00000016223 14260303325 020453 0ustar00neumannstaff000000 000000 /* * nsfFunPtrHashTable.c -- * * Provide a custom Tcl hashtable type, using function pointers * as hash keys, and a slim wrapper around Tcl's hashtable * API to manage them. * * Copyright (C) 2016-2018 Gustaf Neumann * Copyright (C) 2016 Stefan Sobernig * * Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #include "nsfInt.h" /* * Definitions for HashType funPtr. * * Background: since it is not guaranteed that sizeof(function * pointer) == sizeof(data pointer) (or sizeof(function pointer) <= * sizeof(data pointer)), passing function pointers via data pointers * - which is what default Tcl hash types do - is potentially * dangerous. Therefore, and on top, it is not allowed under ISO * C. So, we define our own type that allows one to hash on function * pointers safely. * */ static Tcl_HashKeyProc FunPtrKey; static Tcl_CompareHashKeysProc CompareFunPtrKeys; static Tcl_AllocHashEntryProc AllocFunPtrEntry; typedef struct funPtrEntry_t { Nsf_AnyFun *funPtr; } funPtrEntry_t; static Tcl_HashKeyType funPtrHashKeyType = { 1, /* version*/ 0, /* flags */ FunPtrKey, /* hashKeyProc*/ CompareFunPtrKeys, /* compareKeysProc */ AllocFunPtrEntry, /* allocEntryProc */ NULL /* freeEntryProc */ }; /* *---------------------------------------------------------------------- * * FunPtrKey -- * * Computes an unsigned int hash value from a function pointer. * * Results: * Returns the computed hash. * * Side effects: * None. * *---------------------------------------------------------------------- */ static #if defined TCL_HASH_TYPE TCL_HASH_TYPE #else unsigned int #endif FunPtrKey( Tcl_HashTable *UNUSED(tablePtr), /* Hash table. */ void *keyPtr /* Key from which to compute hash value. */ ) { funPtrEntry_t *e = (funPtrEntry_t *)keyPtr; Nsf_AnyFun *value = e->funPtr; /* * This is a very simple approach for obtaining a hash value. Maybe one * needs a more sophisticated approach with weird endians machines. */ return PTR2UINT(value); } /* *---------------------------------------------------------------------- * * CompareFunPtrKeys -- * * Compares two function pointer keys. * * Results: * The return value is 0 if they are different and 1 if they are the * same. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int CompareFunPtrKeys( void *keyPtr, /* New key to compare. */ Tcl_HashEntry *hPtr /* Existing key to compare. */ ) { funPtrEntry_t *e = (funPtrEntry_t *)keyPtr; Nsf_AnyFun *existingValue; memcpy(&existingValue, &hPtr->key.oneWordValue, sizeof(Nsf_AnyFun *)); return e->funPtr == existingValue; } /* *---------------------------------------------------------------------- * * AllocFunPtrEntry -- * * Allocate space for a Tcl_HashEntry containing the function pointer. * * Results: * The return value is a pointer to the created entry. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_HashEntry * AllocFunPtrEntry( Tcl_HashTable *UNUSED(tablePtr), /* Hash table. */ void *keyPtr /* Key to store in the hash table entry. */ ) { funPtrEntry_t *e = (funPtrEntry_t *)keyPtr; Tcl_HashEntry *hPtr; unsigned int size; Nsf_AnyFun *value = e->funPtr; size = sizeof(Tcl_HashEntry) + (sizeof(Nsf_AnyFun *)) - sizeof(hPtr->key); if (size < sizeof(Tcl_HashEntry)) { size = sizeof(Tcl_HashEntry); } hPtr = (Tcl_HashEntry *) ckalloc(size); memcpy(&hPtr->key.oneWordValue, &value, sizeof(Nsf_AnyFun *)); hPtr->clientData = 0; return hPtr; } /* *---------------------------------------------------------------------- * Nsf_InitFunPtrHashTable -- * * Initializes a hash table structure providing for function * pointers as hash keys. It is a slim wrapper around * Tcl_InitCustomHashTable(). * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Nsf_InitFunPtrHashTable(Tcl_HashTable *tablePtr) { nonnull_assert(tablePtr != NULL); Tcl_InitCustomHashTable(tablePtr, TCL_CUSTOM_PTR_KEYS, &funPtrHashKeyType); } /* *---------------------------------------------------------------------- * Nsf_CreateFunPtrHashEntry -- * * Creates or finds an entry based on a given function-pointer * key. It is a slim wrapper around Tcl_CreateHashEntry(). * * Results: * Returns a pointer to the matching entry. * * Side effects: * A new entry may be stored in the hash table. * *---------------------------------------------------------------------- */ Tcl_HashEntry * Nsf_CreateFunPtrHashEntry( Tcl_HashTable *tablePtr, Nsf_AnyFun *key, int *isNew ) { Tcl_HashEntry *hPtr; funPtrEntry_t entry; nonnull_assert(tablePtr != NULL); nonnull_assert(key != NULL); entry.funPtr = key; hPtr = Tcl_CreateHashEntry(tablePtr, (const char *)&entry, isNew); return hPtr; } /* *---------------------------------------------------------------------- * Nsf_FindFunPtrHashEntry -- * * Finds the entry with a matching function-pointer key in a given * table. It is a slim wrapper around Tcl_FindHashEntry(). * * Results: * Returns a pointer to the matching entry, or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_HashEntry * Nsf_FindFunPtrHashEntry(Tcl_HashTable *tablePtr, Nsf_AnyFun *key) { Tcl_HashEntry *hPtr; funPtrEntry_t entry; nonnull_assert(tablePtr != NULL); nonnull_assert(key != NULL); entry.funPtr = key; hPtr = Tcl_FindHashEntry(tablePtr, (const char *)&entry); return hPtr; } /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * eval: (c-guess) * End: */ ./nsf2.4.0/generic/nsfStubLib.c.ast.sh000644 000766 000024 00000000762 13543460717 020241 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.8bd202.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfStubLib.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/generic/nsfStubLib.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfStubLib.c.ast.bdump./nsf2.4.0/generic/nsf.decls000644 000766 000024 00000016654 14260517246 016431 0ustar00neumannstaff000000 000000 # -*- Tcl -*- # # nx.decls -- # # This file contains the declarations for all supported public # functions that are exported by the Next Scripting Framework # (NSF) library via stubs tables. This file is used to # generate nsfDecls.h. # # Copyright (C) 1999-2014 Gustaf Neumann (a, b) # Copyright (C) 1999-2007 Uwe Zdun (a, b) # # (a) University of Essen # Specification of Software Systems # Altendorferstrasse 97-101 # D-45143 Essen, Germany # # (b) Vienna University of Economics and Business # Institute of Information Systems and New Media # A-1020, Welthandelsplatz 1 # Vienna, Austria # # This work is licensed under the MIT License https://www.opensource.org/licenses/MIT # # Copyright: # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. # library nsf interface nsf hooks {nsfInt} # Declare each of the functions in the public Tcl interface. Note that # the an index should never be reused for a different function in order # to preserve backwards compatibility. declare 0 generic { int Nsf_Init(Tcl_Interp *interp) } # 1 is reserved for safe init #declare 1 generic { # int Nsf_SafeInit(Tcl_Interp *interp) #} declare 2 generic { struct Nsf_Class *NsfIsClass(Tcl_Interp *interp, ClientData cd) } declare 3 generic { struct Nsf_Object *NsfGetObject(Tcl_Interp *interp, const char *name) } declare 4 generic { struct Nsf_Class *NsfGetClass(Tcl_Interp *interp, const char *name) } declare 5 generic { int NsfDeleteObject(Tcl_Interp *interp, struct Nsf_Object *object) } declare 6 generic { int NsfRemoveObjectMethod(Tcl_Interp *interp, struct Nsf_Object *object, const char *methodName) } declare 7 generic { int NsfRemoveClassMethod(Tcl_Interp *interp, struct Nsf_Class *class, const char *methodName) } declare 8 generic { Tcl_Obj *Nsf_ObjSetVar2(struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, Tcl_Obj *valueObj, unsigned int flags) } declare 9 generic { Tcl_Obj *Nsf_ObjGetVar2(struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, unsigned int flags) } declare 10 generic { int Nsf_UnsetVar2(struct Nsf_Object *object, Tcl_Interp *interp, const char *name1, const char *name2, unsigned int flags) } declare 11 generic { void NsfDStringVPrintf(Tcl_DString *dsPtr, const char *fmt, va_list argPtr) } declare 12 generic { int NsfPrintError(Tcl_Interp *interp, const char *fmt, ...) } declare 13 generic { int NsfErrInProc (Tcl_Interp *interp, Tcl_Obj *objName, Tcl_Obj *clName, const char *procName) } declare 14 generic { int NsfObjErrType(Tcl_Interp *interp, const char *context, Tcl_Obj *value, const char *type, Nsf_Param const *NsfObjErrType) } declare 15 generic { void NsfStackDump (Tcl_Interp *interp) } declare 16 generic { void NsfSetObjClientData(Tcl_Interp *interp, Nsf_Object *object, ClientData data) } declare 17 generic { ClientData NsfGetObjClientData(Tcl_Interp *interp, Nsf_Object *object) } declare 18 generic { void NsfSetClassClientData(Tcl_Interp *interp, Nsf_Class *cl, ClientData data) } declare 19 generic { ClientData NsfGetClassClientData(Tcl_Interp *interp, Nsf_Class *cl) } declare 20 generic { void NsfRequireObjNamespace(Tcl_Interp *interp, Nsf_Object *object) } declare 21 generic { int NsfCallMethodWithArgs(Tcl_Interp *interp, Nsf_Object *object, Tcl_Obj *methodObj, Tcl_Obj *arg1, int givenObjc, Tcl_Obj *const objv[], unsigned int flags) } declare 22 generic { int NsfAddObjectMethod(Tcl_Interp *interp, struct Nsf_Object *object, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags) } declare 23 generic { int NsfAddClassMethod(Tcl_Interp *interp, struct Nsf_Class *class, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags) } declare 24 generic { int NsfCreate(Tcl_Interp *interp, Nsf_Class *class, Tcl_Obj *nameObj, int objc, Tcl_Obj *const objv[]) } declare 25 generic { int Nsf_ArgumentParse(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Nsf_Object *object, Tcl_Obj *procNameObj, Nsf_Param const *paramPtr, int nrParams, int serial, unsigned int processFlags, Nsf_ParseContext *pcPtr) } declare 26 generic { void NsfLog(Tcl_Interp *interp, int requiredLevel, const char *fmt, ...) } declare 27 generic { int Nsf_PointerAdd(Tcl_Interp *interp, char *buffer, size_t size, const char *typeName, void *valuePtr) } declare 28 generic { int Nsf_PointerDelete(const char *key, void *valuePtr, int free) } declare 29 generic { int Nsf_PointerTypeRegister(Tcl_Interp *interp, const char* typeName, int *counterPtr) } declare 30 generic { int Nsf_ConvertToBoolean(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) } declare 31 generic { int Nsf_ConvertToClass(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) } declare 32 generic { int Nsf_ConvertToInt32(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) } declare 33 generic { int Nsf_ConvertToInteger(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) } declare 34 generic { int Nsf_ConvertToObject(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) } declare 35 generic { int Nsf_ConvertToPointer(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) } declare 36 generic { int Nsf_ConvertToString(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) } declare 37 generic { int Nsf_ConvertToTclobj(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) } declare 38 generic { int Nsf_EnumerationTypeRegister(Tcl_Interp *interp, Nsf_EnumeratorConverterEntry *typeRecords) } declare 39 generic { int Nsf_CmdDefinitionRegister(Tcl_Interp *interp, Nsf_methodDefinition *definitionRecords) } declare 40 generic { int NsfArgumentError(Tcl_Interp *interp, const char *errorMsg, Nsf_Param const *paramPtr, Tcl_Obj *cmdNameObj, Tcl_Obj *methodPathObj) } declare 41 generic { void Nsf_DStringPrintf(Tcl_DString *dsPtr, const char *fmt, ...) } ./nsf2.4.0/generic/asm/asmExecuteTemplateCallThreading.c000644 000766 000024 00000003313 13773664100 023760 0ustar00neumannstaff000000 000000 $GENERATED_INSTRUCTIONS; /* *---------------------------------------------------------------------- * AsmExecute -- * * Define the execution engine for the code * *---------------------------------------------------------------------- */ static int AsmExecute(ClientData cd, Tcl_Interp *interp, AsmCompiledProc *proc, int argc, Tcl_Obj *CONST argv[]) { //AsmInstruction *ip; int i, result; #if 0 Var *compiledLocals; compiledLocals = ((Interp *) interp)->varFramePtr->compiledLocals; if (compiledLocals != NULL) { fprintf(stderr, "compiledLocals = %p\n", compiledLocals); } #endif /* * Place a copy of the actual argument into locals. */ for (i=1; i < argc; i++) { proc->locals[i-1] = argv[i]; } /* * Update all references to compiled arguments. */ for (i=0; i < proc->nrAsmArgReferences; i++) { AsmArgReference *arPtr = &proc->argReferences[i]; *(arPtr->objPtr) = proc->locals[arPtr->argNr]; } /* * Set the instruction pointer to the begin of the code. */ proc->ip = proc->code; //fprintf(stderr, "ip %p\n", proc->ip); while (*proc->ip->cmd) { //fprintf(stderr, "will execute instruction ip %p cmd %p %p/%d\n", ip, ip->cmd, ip->argv[0], ip->argc); //if (ip->cmd == tclFormat) {AsmInstructionPrint(ip);} //if (ip->cmd == (Tcl_ObjCmdProc*)tclDispatch) {AsmInstructionPrint(ip);} result = (*proc->ip->cmd)(proc->ip->clientData, interp, proc->ip->argc, proc->ip->argv); /*fprintf(stderr, "%s returned <%s> (%d)\n", Tcl_GetString(ip->argv[0]), Tcl_GetString(Tcl_GetObjResult(interp)), result);*/ if (unlikely(result != TCL_OK)) break; proc->ip++; //fprintf(stderr, "ip %p\n", proc->ip); } return result; } ./nsf2.4.0/generic/asm/nsfAsmExecuteCallThreading.c000644 000766 000024 00000022574 13773664100 022745 0ustar00neumannstaff000000 000000 static int asmEval(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { int result; result = Tcl_EvalObjv(interp, argc, argv, 0); return result; } static int asmDuplicateObj(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { AsmCompiledProc *proc = clientData; { int indexValue = PTR2INT(argv[0]); //fprintf(stderr, "duplicateObj var[%d] = %s\n", indexValue, ObjStr(argv[1])); if (proc->slots[indexValue]) { Tcl_DecrRefCount(proc->slots[indexValue]); } proc->slots[indexValue] = Tcl_DuplicateObj(argv[1]); Tcl_IncrRefCount(proc->slots[indexValue]); proc->slotFlags[indexValue] |= ASM_SLOT_MUST_DECR; } return TCL_OK; } static int asmIncrInt(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { AsmCompiledProc *proc = clientData; { int intValue, incrValue; //fprintf(stderr, "incrInt var[%d] incr var[%d]\n", PTR2INT(argv[0]), PTR2INT(argv[1])); intValue = PTR2INT(proc->slots[PTR2INT(argv[0])]); incrValue = PTR2INT(proc->slots[PTR2INT(argv[1])]); //fprintf(stderr, ".... intValue %d incr Value %d\n", intValue, incrValue); proc->slots[PTR2INT(argv[0])] = INT2PTR(intValue + incrValue); //fprintf(stderr, ".... [%d] => %d\n", PTR2INT(argv[0]), intValue + incrValue); } return TCL_OK; } static int asmIncrObj(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { AsmCompiledProc *proc = clientData; { int intValue, incrValue; Tcl_Obj *intObj, *incrObj; //fprintf(stderr, "asmIncrScalar var[%d] incr var[%d], ", PTR2INT(argv[0]), PTR2INT(argv[1])); intObj = proc->slots[PTR2INT(argv[0])]; incrObj = proc->slots[PTR2INT(argv[1])]; if (likely(intObj->typePtr == Nsf_OT_intType)) { intValue = intObj->internalRep.longValue; } else { Tcl_GetIntFromObj(interp, intObj, &intValue); } if (likely(incrObj->typePtr == Nsf_OT_intType)) { incrValue = incrObj->internalRep.longValue; } else { Tcl_GetIntFromObj(interp, incrObj, &incrValue); } //fprintf(stderr, "%d + %d = %d,", intValue, incrValue, intValue + incrValue); Tcl_InvalidateStringRep(intObj); intObj->internalRep.longValue = (long)(intValue + incrValue); //fprintf(stderr, "updated %p var[%d] %p\n", intObj, PTR2INT(argv[0]), proc->slots[PTR2INT(argv[0])]); //Tcl_SetObjResult(interp, intObj); } return TCL_OK; } static int asmJump(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { AsmCompiledProc *proc = clientData; //fprintf(stderr, "asmJump oc %d instructionIndex %d\n", argc, PTR2INT(argv[0])); NsfAsmJump(PTR2INT(argv[0])); return TCL_OK; } static int asmJumpTrue(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { AsmCompiledProc *proc = clientData; if (proc->status != 0) { //fprintf(stderr, "asmJumpTrue jump oc %d instructionIndex %d\n", argc, PTR2INT(argv[0])); NsfAsmJump(PTR2INT(argv[0])); } else { //fprintf(stderr, "asmJumpTrue fall through\n"); NsfAsmJumpNext(); } return TCL_OK; } static int asmLeInt(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { AsmCompiledProc *proc = clientData; { int value1, value2; value1 = PTR2INT(proc->slots[PTR2INT(argv[0])]); value2 = PTR2INT(proc->slots[PTR2INT(argv[1])]); proc->status = value1 <= value2; } return TCL_OK; } static int asmLeIntObj(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { AsmCompiledProc *proc = clientData; { int value1, value2; Tcl_Obj *obj; //fprintf(stderr, "leIntObj oc %d op1 %p op2 %p\n", argc, argv[0], argv[1]); // for the time being, we compare two int values obj = proc->slots[PTR2INT(argv[0])]; if (likely(obj->typePtr == Nsf_OT_intType)) { value1 = obj->internalRep.longValue; } else { Tcl_GetIntFromObj(interp, obj, &value1); } obj = proc->slots[PTR2INT(argv[1])]; if (likely(obj->typePtr == Nsf_OT_intType)) { value2 = obj->internalRep.longValue; } else { Tcl_GetIntFromObj(interp, obj, &value2); } //fprintf(stderr, "asmLeScalar oc %d op1 %d op2 %d => %d\n", argc, value1, value2, value1 <= value2); proc->status = value1 <= value2; } return TCL_OK; } static int asmMethodDelegateDispatch(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { int result; { Tcl_Command cmd = NULL; NsfObject *object; // obj and method are unresolved result = GetObjectFromObj(interp, argv[0], &object); if (likely(clientData != NULL)) { cmd = clientData; } else { cmd = Tcl_GetCommandFromObj(interp, argv[1]); } //fprintf(stderr, "cmd %p object %p\n", cmd, object); result = MethodDispatch(object, interp, argc-1, argv+1, cmd, object, NULL, ObjStr(argv[1]), 0, 0); } return result; } static int asmMethodDelegateDispatch11(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { int result; // obj and method are resolved { AsmResolverInfo *resInfo = clientData; result = MethodDispatch(resInfo->object, interp, argc-1, argv+1, resInfo->cmd, resInfo->object, NULL, ObjStr(argv[1]), 0, 0); } return result; } static int asmMethodSelfCmdDispatch(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { int result; { AsmResolverInfo *resInfo = clientData; assert(resInfo->cmd != NULL); result = Tcl_NRCallObjProc(interp, Tcl_Command_objProc(resInfo->cmd), resInfo->proc->currentObject, argc, argv); } return result; } static int asmMethodSelfDispatch(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { int result; { AsmResolverInfo *resInfo = clientData; Tcl_Command cmd = (resInfo->cmd != NULL) ? resInfo->cmd : Tcl_GetCommandFromObj(interp, argv[0]); result = MethodDispatch(resInfo->proc->currentObject, interp, argc, argv, cmd, resInfo->proc->currentObject, NULL, ObjStr(argv[0]), 0, 0); } return result; } static int asmNoop(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { return TCL_OK; } static int asmSelf(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { AsmCompiledProc *proc = clientData; Tcl_SetObjResult(interp, proc->currentObject->cmdName); return TCL_OK; } static int asmSetInt(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { AsmCompiledProc *proc = clientData; proc->slots[PTR2INT(argv[0])] = argv[1]; return TCL_OK; } static int asmSetObj(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { AsmCompiledProc *proc = clientData; //fprintf(stderr, "setObj var[%d] = %s\n", PTR2INT(argv[0]), ObjStr(argv[1])); proc->slots[PTR2INT(argv[0])] = argv[1]; return TCL_OK; } static int asmSetObjToResult(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { AsmCompiledProc *proc = clientData; //fprintf(stderr, "setObjToResult var[%d] = %s\n", PTR2INT(argv[0]), ObjStr(argv[1])); proc->slots[PTR2INT(argv[0])] = Tcl_GetObjResult(interp); return TCL_OK; } static int asmSetResult(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { AsmCompiledProc *proc = clientData; Tcl_SetObjResult(interp, proc->slots[PTR2INT(argv[0])]); return TCL_OK; } static int asmSetResultInt(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { AsmCompiledProc *proc = clientData; Tcl_SetObjResult(interp, Tcl_NewIntObj(PTR2INT(proc->slots[PTR2INT(argv[0])]))); return TCL_OK; } static int asmStoreResult(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv[]) { argv[0] = Tcl_GetObjResult(interp); Tcl_IncrRefCount(argv[0]); return TCL_OK; } ; /* *---------------------------------------------------------------------- * AsmExecute -- * * Define the execution engine for the code * *---------------------------------------------------------------------- */ static int AsmExecute(ClientData cd, Tcl_Interp *interp, AsmCompiledProc *proc, int argc, Tcl_Obj *CONST argv[]) { //AsmInstruction *ip; int i, result; #if 0 Var *compiledLocals; compiledLocals = ((Interp *) interp)->varFramePtr->compiledLocals; if (compiledLocals != NULL) { fprintf(stderr, "compiledLocals = %p\n", compiledLocals); } #endif /* * Place a copy of the actual argument into locals. */ for (i=1; i < argc; i++) { proc->locals[i-1] = argv[i]; } /* * Update all references to compiled arguments. */ for (i=0; i < proc->nrAsmArgReferences; i++) { AsmArgReference *arPtr = &proc->argReferences[i]; *(arPtr->objPtr) = proc->locals[arPtr->argNr]; } /* * Set the instruction pointer to the begin of the code. */ proc->ip = proc->code; //fprintf(stderr, "ip %p\n", proc->ip); while (*proc->ip->cmd) { //fprintf(stderr, "will execute instruction ip %p cmd %p %p/%d\n", ip, ip->cmd, ip->argv[0], ip->argc); //if (ip->cmd == tclFormat) {AsmInstructionPrint(ip);} //if (ip->cmd == (Tcl_ObjCmdProc*)tclDispatch) {AsmInstructionPrint(ip);} result = (*proc->ip->cmd)(proc->ip->clientData, interp, proc->ip->argc, proc->ip->argv); /*fprintf(stderr, "%s returned <%s> (%d)\n", Tcl_GetString(ip->argv[0]), Tcl_GetString(Tcl_GetObjResult(interp)), result);*/ if (unlikely(result != TCL_OK)) break; proc->ip++; //fprintf(stderr, "ip %p\n", proc->ip); } return result; } ./nsf2.4.0/generic/asm/asmExecuteTemplate.c000644 000766 000024 00000003152 12501766547 021345 0ustar00neumannstaff000000 000000 int AsmExecute(ClientData cd, Tcl_Interp *interp, AsmCompiledProc *proc, int argc, Tcl_Obj *CONST argv[]) { int i, result, indexValue; ClientData clientData; NsfObject *object; Tcl_Command cmd; AsmInstruction *ip; static void *instructionLabel[] = { &&INST_objProc, &&INST_asmStoreResult, &&INST_asmSetResult, &&INST_asmNoop, &&INST_asmDispatch, &&INST_asmMethodDelegateDispatch00, &&INST_asmMethodDelegateDispatch11, &&INST_asmMethodSelfDispatch, &&INST_asmMethodSelfCmdDispatch, &&INST_asmMethodSelf, &&INST_asmJump, &&INST_asmJumpTrue, &&INST_asmLeScalar, &&INST_asmCopyScalar, &&INST_asmSetScalar, &&INST_asmSetScalarResult, &&INST_asmIncrScalar, &&INST_NULL }; /* * Place a copy of the actual argument into locals. */ for (i=1; i < argc; i++) { proc->locals[i-1] = argv[i]; } /* * Update all references to compiled arguments. */ for (i=0; i < proc->nrAsmArgReferences; i++) { AsmArgReference *arPtr = &proc->argReferences[i]; *(arPtr->objPtr) = proc->locals[arPtr->argNr]; } /* * Set the instruction pointer to the begin of the code. */ ip = proc->code; proc->status = 0; //fprintf(stderr, "AsmExecute jumps to %p\n", ip); goto *instructionLabel[ip->labelIdx]; INST_NULL: return result; EXEC_RESULT_CODE_HANDLER: if (likely(result == TCL_OK)) { ip++; goto *instructionLabel[ip->labelIdx]; } else { return result; } INST_objProc: result = (*ip->cmd)(ip->clientData, interp, ip->argc, ip->argv); goto EXEC_RESULT_CODE_HANDLER; GENERATED_INSTRUCTIONS; } ./nsf2.4.0/generic/asm/asmAssembleTemplate.c000644 000766 000024 00000020666 13774105235 021501 0ustar00neumannstaff000000 000000 enum asmStatementIndex { asmObjProcIdx, $STATEMENT_INDICES }; static CONST char *asmStatementNames[] = { "cmd", $STATEMENT_NAMES, NULL }; enum asmStatementArgTypeIndex { asmStatementArgTypeArgIdx, asmStatementArgTypeArgvIdx, asmStatementArgTypeInstructionIdx, asmStatementArgTypeIntIdx, asmStatementArgTypeObjIdx, asmStatementArgTypeResultIdx, asmStatementArgTypeSlotIdx, asmStatementArgTypeVarIdx }; static CONST char *asmStatementArgType[] = { "arg", "argv", "instruction", "int", "obj", "result", "slot", "var", NULL}; static CONST char *asmStatementCmdType[] = {"arg", "obj", "result", "var", NULL}; static CONST char *asmStatementInstructionType[] = {"instruction", NULL}; static CONST char *asmStatementIntType[] = {"int", NULL}; static CONST char *asmStatementObjType[] = {"obj", NULL}; static CONST char *asmStatementSlotObjArgType[] = {"slot", "obj", "arg", NULL}; static CONST char *asmStatementSlotType[] = {"slot", NULL}; static CONST char *asmStatementSlotIntType[] = {"slot", "int", NULL}; static CONST char *asmStatementStoreType[] = {"instruction", "argv", NULL}; static AsmStatementInfo asmStatementInfo[] = { /* asmObjProcIdx, */ {ASM_INFO_PAIRS|ASM_INFO_SKIP1, NULL, 2, -1, NR_PAIRS1}, $STATEMENT_INFO }; /* *---------------------------------------------------------------------- * AsmAssemble -- * * The assmbler, takes an assembly script in the form of a nested * list and emits the internal representation for the execution * engine. * *---------------------------------------------------------------------- */ static int AsmAssemble(ClientData cd, Tcl_Interp *interp, Tcl_Obj *nameObj, int nrArgs, Tcl_Obj *asmObj, AsmCompiledProc **retAsmProc) { AsmPatches patchArray[100], *patches = &patchArray[0], *patchPtr; // TODO: make me dynamic Tcl_Command cmd; AsmCompiledProc *proc; AsmInstruction *inst; int i, result, nrAsmInstructions, nrLocalObjs, totalArgvArgs; int oc, currentAsmInstruction, currentSlot; Tcl_Obj **ov; CONST char *procName; assert(nameObj != NULL); procName = ObjStr(nameObj); if (Tcl_ListObjGetElements(interp, asmObj, &oc, &ov) != TCL_OK) { return NsfPrintError(interp, "Asm code is not a valid list"); } /* * First Iteration: check wellformedness, determine sizes */ nrAsmInstructions = 0; nrLocalObjs = 0; totalArgvArgs = 0; for (i = 0; i < oc; i++) { int index, offset, wordOc; Tcl_Obj *lineObj = ov[i], **wordOv; if (Tcl_ListObjGetElements(interp, lineObj, &wordOc, &wordOv) != TCL_OK) { return NsfPrintError(interp, "Asm: line is not a well-formed asm instruction: %s", ObjStr(lineObj)); } result = Tcl_GetIndexFromObj(interp, wordOv[0], asmStatementNames, "asm instruction", 0, &index); if (result != TCL_OK) { return NsfPrintError(interp, "Asm: line is not a valid asm instruction: word %s, line %s", ObjStr(wordOv[0]), ObjStr(lineObj)); } offset = (asmStatementInfo[index].flags & ASM_INFO_SKIP1) ? 2 : 1; if ((asmStatementInfo[index].flags & ASM_INFO_PAIRS) && (wordOc-offset) % 2 == 1) { return NsfPrintError(interp, "Asm: argument list of cmd must contain pairs: %s", ObjStr(lineObj)); } if (asmStatementInfo[index].minArgs > -1 && wordOc < asmStatementInfo[index].minArgs) { return NsfPrintError(interp, "Asm: statement must contain at least %d words: %s", asmStatementInfo[index].minArgs, ObjStr(lineObj)); } if (asmStatementInfo[index].maxArgs > -1 && wordOc > asmStatementInfo[index].maxArgs) { return NsfPrintError(interp, "Asm: statement must contain at most %d words: %s", asmStatementInfo[index].maxArgs, ObjStr(lineObj)); } if (asmStatementInfo[index].argTypes) { result = AsmInstructionArgvCheck(interp, offset, wordOc, asmStatementInfo[index].argTypes, nrLocalObjs, oc, wordOv, lineObj); if (unlikely(result != TCL_OK)) {return result;} } if ((asmStatementInfo[index].flags & ASM_INFO_DECL) == 0) { int cArgs = asmStatementInfo[index].cArgs; /* * Determine the actual number of arguments passed to the * emitted instruction. This number might be determine by the * instruction type, or by the actual instruction being * processed (and later maybe for {*} etc.). */ if (cArgs == NR_PAIRS) { cArgs = (wordOc-offset) / 2; } else if (cArgs == NR_PAIRS1) { cArgs = 1 + (wordOc-offset) / 2; } //fprintf(stderr, "instruction %s need argvargs %d\n", ObjStr(lineObj), cArgs); totalArgvArgs += cArgs; nrAsmInstructions++; } else { /* currently obj and var from the same pool, will change... */ nrLocalObjs ++; } /* * optional, per-statement check operations */ switch (index) { case asmObjProcIdx: /* {cmd ::set slot 0 slot 2} */ cmd = Tcl_GetCommandFromObj(interp, wordOv[1]); if (cmd == NULL) { return NsfPrintError(interp, "Asm: cmd is not a valid Tcl command: %s\n", Tcl_GetString( wordOv[1])); } break; /* begin generated code */ $ASSEMBLE_CHECK_CODE /* end generated code */ default: break; } } nrAsmInstructions ++; fprintf(stderr, "%s: nrAsmInstructions %d nrLocalObjs %d nrArgs %d argvArgs %d => data %d\n", procName, nrAsmInstructions, nrLocalObjs, nrArgs, totalArgvArgs, nrLocalObjs + nrArgs + totalArgvArgs ); /* * Allocate structures */ proc = (AsmCompiledProc *)ckalloc(sizeof(AsmCompiledProc)); proc->code = (AsmInstruction *)ckalloc(sizeof(AsmInstruction) * nrAsmInstructions); memset(proc->slotFlags, 0, sizeof(int) * NSF_ASM_NR_STATIC_SLOTS); proc->ip = proc->code; /* points to the first writable instructon */ proc->firstObj = proc->staticObjs; /* point to the first free obj */ proc->locals = proc->staticObjs; /* locals is just an alias */ proc->nrAsmArgReferences = 0; proc->slots = proc->locals + nrArgs; //fprintf(stderr, "args = %ld\n", proc->slots - proc->locals); AsmLocalsAlloc(proc, nrArgs + nrLocalObjs); /* when freeing, we need something like for (i=0; i < nrArgs + nrLocalObjs; i++) { if (proc->slotFlags[i] & ASM_SLOT_MUST_DECR) {Tcl_DecrRefCount(proc->slots[i]); } } */ /* * Second Iteration: emit code */ currentSlot = 0; currentAsmInstruction = 0; for (i = 0; i < oc; i++) { int index, offset, cArgs, argc, codeIndex, argvIndex, j; Tcl_Obj *lineObj = ov[i], **argv; Tcl_ListObjGetElements(interp, lineObj, &argc, &argv); Tcl_GetIndexFromObj(interp, argv[0], asmStatementNames, "asm instruction", 0, &index); offset = (asmStatementInfo[index].flags & ASM_INFO_SKIP1) ? 2 : 1; cArgs = asmStatementInfo[index].cArgs; if (cArgs == NR_PAIRS) { cArgs = (argc-offset) / 2; } else if (cArgs == NR_PAIRS1) { cArgs = 1 + (argc-offset) / 2; } switch (index) { case asmObjProcIdx: /* {cmd ::set slot 0 slot 2} */ cmd = Tcl_GetCommandFromObj(interp, argv[1]); #if defined(LABEL_THREADING) inst = AsmInstructionNew(proc, objProc, cArgs); inst->cmd = ((Command *)cmd)->objProc; #else inst = AsmInstructionNew(proc, ((Command *)cmd)->objProc, cArgs); #endif inst->clientData = ((Command *)cmd)->objClientData; /* use the assembly word as cmd name; should be ok when we keep assembly around */ inst->argv[0] = argv[1]; /*fprintf(stderr, "[%d] %s/%d\n", currentAsmInstruction, Tcl_GetString(argv[1]), 1+((argc-offset)/2));*/ AsmInstructionArgvSet(interp, offset, argc, 1, inst, proc, argv, 0); break; /* begin generated code */ $ASSEMBLE_EMIT_CODE /* end generated code */ } if ((asmStatementInfo[index].flags & ASM_INFO_DECL) == 0) { currentAsmInstruction ++; } } /* * add END instruction */ inst = AsmInstructionNew(proc, NULL, 0); /* * All addresses are determined, apply the argv patches triggered * from above. */ for (patchPtr = &patchArray[0]; patchPtr < patches; patchPtr++) { fprintf(stderr, "want to patch code[%d]->argv = code[%d]->argv[%d]\n", patchPtr->targetAsmInstruction, patchPtr->sourceAsmInstruction, patchPtr->argvIndex); /* set the argument vector of code[1] to the address of code[4]->argv[1] */ (&proc->code[patchPtr->targetAsmInstruction])->argv = &(&proc->code[patchPtr->sourceAsmInstruction])->argv[patchPtr->argvIndex]; } *retAsmProc = proc; return TCL_OK; } ./nsf2.4.0/generic/asm/genAssemble.tcl000644 000766 000024 00000050775 12776662115 020350 0ustar00neumannstaff000000 000000 package require nx ###################################################################### # The code engine ###################################################################### nsf::proc generate {threadingType:class} { set suffix [string trimleft ${threadingType} :] set dirName [file dirname [info script]] foreach {var value} [${threadingType} generate] { set $var $value } set template [readFile $dirName/asmExecuteTemplate$suffix.c] writeFile $dirName/nsfAsmExecute$suffix.c [subst -nocommand -nobackslash $template] set template [readFile $dirName/asmAssembleTemplate.c] writeFile $dirName/nsfAsmAssemble.c [subst -nocommand -nobackslash $template] } nsf::proc readFile {fn} {set f [open $fn]; set content [read $f]; close $f; return $content} nsf::proc writeFile {fn content} { puts stderr "writing $fn" set f [open $fn w]; puts -nonewline $f $content; close $f } ###################################################################### # Basic Class for Instructions and Declarations ###################################################################### nx::Class create Statement { :property {name "[namespace tail [self]]"} :property {mustContainPairs true} :property {argTypes NULL} :property {minArgs 0} :property {maxArgs 0} :property {cArgs 0} :property {asmCheckCode ""} :property {asmEmitCode ""} :public method cName {} { # prepend asm and capitalize first character return asm[string toupper [string range ${:name} 0 0]][string range ${:name} 1 end] } :public method getAsmEmitCode {} { return ${:asmEmitCode} } :public class method "generate assembler" {} { set statementIndex {} set statementNames {} set (ASSEMBLE_EMIT_CODE) "" foreach s [lsort [Statement info instances -closure]] { if {[$s maxArgs] == 0} { puts stderr "ignore statement $s" continue } lappend statementIndex [$s cName]Idx lappend statementNames \"[$s name]\" set emitCode [$s getAsmEmitCode] if {$emitCode ne ""} { append (ASSEMBLE_EMIT_CODE) " case [$s cName]Idx:\n$emitCode\n break;\n\n" } set flags 0 if {[$s info has type ::Declaration]} { lappend flags ASM_INFO_DECL } if {[$s mustContainPairs]} { lappend flags ASM_INFO_PAIRS } lappend statementInfo \ "/* [$s cName] */\n {[join $flags |], [$s argTypes], [$s minArgs], [$s maxArgs], [$s cArgs]}" } array set {} [list \ STATEMENT_INDICES [join $statementIndex ",\n "] \ STATEMENT_NAMES [join $statementNames ",\n "] \ STATEMENT_INFO [join $statementInfo ",\n "] \ ASSEMBLE_CHECK_CODE ""] return [array get {}] } } ###################################################################### # Basic Class for Instructions and Declarations ###################################################################### nx::Class create Declaration -superclass Statement { } ###################################################################### # Basic Class for defining Instructions independent of the code # generator (label threading, call threading) ###################################################################### nx::Class create Instruction -superclass Statement { :property {execCode ""} :property {isJump false} :property {returnsResult false} # The property "execNeedsProc" is just needed for call threading, # where we have to pass proc via inst->clientData :property {execNeedsProc false} :public method getAsmEmitCode {} { # # For every instruction, the C-code allocates an instruction record # append . \ "\n\tinst = AsmInstructionNew(proc, [:cName], cArgs);" \ "\n\tif (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);}" \ [:asmEmitCode] } :method "code clear" {} { set :cCode "" } :method "code get" {} { return ${:cCode} } :method "code append" {value} { append :cCode $value } :method "code mustAssign" {value} { if {![regexp "\\m${value}\\M\\s*=" ${:cCode}]} { error "code does not assign variable '$value': ${:cCode}" } } :method "code mustContain" {value} { if {![regexp ${value} ${:cCode}]} { error "code does not contain '$value': ${:cCode}" } } } ###################################################################### # Code Generator for Label Threading ###################################################################### nx::Class create LabelThreading { :public class method generate {} { Instruction mixin add [self]::Instruction set instructions [lsort [Instruction info instances]] set labels {} set indices {} foreach instruction $instructions { append (GENERATED_INSTRUCTIONS) [$instruction generate] \n lappend labels &&[$instruction labelName] lappend indices IDX_[$instruction cName] } array set {} [list \ INSTRUCTION_LABELS [join $labels ",\n "] \ INSTRUCTION_INDICES [join $indices ",\n "] \ {*}[Statement generate assembler]] Instruction mixin delete [self]::Instruction return [array get {}] } nx::Class create [self]::Instruction { # # This Class is designed as a mixin class for Instruction # :public method labelName {} { return INST_[:cName] } :method nextInstruction {} { if {[:isJump]} { :code mustContain NsfAsmJump :code append "\n goto *instructionLabel\[ip->labelIdx];\n" } else { :code append "\n ip++;\n goto *instructionLabel\[ip->labelIdx];\n" } } :public method "code generate" {} { :code append ${:execCode} if {[:returnsResult]} { :code mustAssign result :code append " goto EXEC_RESULT_CODE_HANDLER;\n" } } :public method generate {} { :code clear :code append [:labelName]:\n :code generate :nextInstruction return [:code get] } } } ###################################################################### # Code Generator for Call Threading ###################################################################### nx::Class create CallThreading { :public class method generate {} { Instruction mixin add [self]::Instruction Statement mixin add [self]::Statement foreach instruction [lsort [Instruction info instances]] { append (GENERATED_INSTRUCTIONS) [$instruction generate] \n } array set {} [Statement generate assembler] Instruction mixin delete [self]::Instruction Statement mixin delete [self]::Statement return [array get {}] } nx::Class create [self]::Statement { :public method asmEmitCode {} { set asmEmitCode ${:asmEmitCode} if {[:execNeedsProc]} { append asmEmitCode "\n\tinst->clientData = proc;\n" } return $asmEmitCode } } nx::Class create [self]::Instruction { # # This Class is designed as a mixin class for Instruction # :public method "code generate" {} { set code ${:execCode} regsub -all {\mip->argv\M} $code argv code regsub -all {\mip->argc\M} $code argc code regsub -all {\mip->clientData\M} $code clientData code if {[:isJump]} { regsub -all {\mip\s*= } $code "proc->ip = " code regsub -all {\mip\s*[+][+]} $code "proc->ip++" code } if {[:returnsResult]} { :code append " int result;\n" :code append $code :code mustAssign result :code append " return result;\n" } else { :code append $code :code append " return TCL_OK;\n" } } :public method generate {} { :code clear :code append \ "static int [:cName](ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *argv\[]) \{\n" if {[:execNeedsProc]} { :code append " AsmCompiledProc *proc = clientData;\n" } :code generate :code append "\}\n" return [:code get] } } } namespace eval ::asm { ###################################################################### # Declarations ###################################################################### # {obj a} Declaration create obj \ -mustContainPairs false \ -minArgs 2 -maxArgs 2 \ -asmEmitCode { proc->slots[currentSlot] = argv[1]; Tcl_IncrRefCount(proc->slots[currentSlot]); proc->slotFlags[currentSlot] |= ASM_SLOT_MUST_DECR; currentSlot ++; } # {var obj 0} # obj is intended to be the varname, but currently ignored Declaration create var \ -minArgs 3 -maxArgs 3 -argTypes asmStatementObjType \ -asmEmitCode { proc->slots[currentSlot] = NULL; currentSlot ++; } # {integer int 0} Declaration create integer \ -minArgs 3 -maxArgs 3 -argTypes asmStatementIntType \ -asmEmitCode { { int intValue; Tcl_GetIntFromObj(interp, argv[2], &intValue); proc->slots[currentSlot] = INT2PTR(intValue); //fprintf(stderr, "setting slots [%d] = %d\n", currentSlot, intValue); proc->slotFlags[currentSlot] |= ASM_SLOT_IS_INTEGER; currentSlot ++; } } ###################################################################### # Instructions ###################################################################### # {noop} Instruction create noop \ -mustContainPairs false \ -minArgs 1 -maxArgs 1 # {eval obj 0 obj 1 obj 2} Instruction create dispatch \ -name "eval" \ -minArgs 3 -maxArgs -1 -cArgs NR_PAIRS -argTypes asmStatementCmdType \ -returnsResult true \ -execCode { result = Tcl_EvalObjv(interp, ip->argc, ip->argv, 0); } # {methodDelegateDispatch obj 0 obj 1 obj 2} Instruction create methodDelegateDispatch \ -name "methodDelegateDispatch" \ -minArgs 5 -maxArgs -1 -cArgs NR_PAIRS -argTypes asmStatementCmdType \ -asmEmitCode { { Tcl_Command cmd = NULL; NsfObject *object = NULL; AsmResolverInfo *resInfo; if (strncmp(ObjStr(inst->argv[1]), "::nsf::methods::", 16) == 0) { cmd = Tcl_GetCommandFromObj(interp, inst->argv[1]); //fprintf(stderr, "%s: asmMethod cmd '%s' => %p\n", procName, ObjStr(inst->argv[1]), cmd); } if (strncmp(ObjStr(inst->argv[0]), "::nx::", 6) == 0) { GetObjectFromObj(interp, inst->argv[0], &object); //fprintf(stderr, "%s: asmMethod object '%s' => %p\n", procName, ObjStr(inst->argv[0]), object); } if (cmd && object) { // experimental: bind obj and method resInfo = NEW(AsmResolverInfo); // TODO: LEAK resInfo->cmd = cmd; resInfo->object = object; inst->clientData = resInfo; AsmInstructionSetCmd(inst, asmMethodDelegateDispatch11); } else if (cmd != NULL) { inst->clientData = cmd; } else { inst->clientData = NULL; } } } \ -returnsResult true \ -execCode { { Tcl_Command cmd = NULL; NsfObject *object; // obj and method are unresolved result = GetObjectFromObj(interp, ip->argv[0], &object); if (likely(ip->clientData != NULL)) { cmd = ip->clientData; } else { cmd = Tcl_GetCommandFromObj(interp, ip->argv[1]); } //fprintf(stderr, "cmd %p object %p\n", cmd, object); result = MethodDispatch(object, interp, ip->argc-1, ip->argv+1, cmd, object, NULL, ObjStr(ip->argv[1]), 0, 0); } } # methodDelegateDispatch11 is an optimized variant of # methodDelegateDispatch, emitted alternatively by the assembler for # the above instruction. Instruction create methodDelegateDispatch11 \ -returnsResult true \ -execCode { // obj and method are resolved { AsmResolverInfo *resInfo = ip->clientData; result = MethodDispatch(resInfo->object, interp, ip->argc-1, ip->argv+1, resInfo->cmd, resInfo->object, NULL, ObjStr(ip->argv[1]), 0, 0); } } # {methodSelfDispatch obj 0 obj 1 obj 2} Instruction create methodSelfDispatch \ -minArgs 3 -maxArgs -1 -cArgs NR_PAIRS -argTypes asmStatementCmdType \ -asmEmitCode { { Tcl_Command cmd = NULL; AsmResolverInfo *resInfo; if (strncmp(ObjStr(inst->argv[0]), "::nsf::methods::", 16) == 0) { cmd = Tcl_GetCommandFromObj(interp, inst->argv[0]); if (cmd != NULL) { //fprintf(stderr, "%s: asmMethodSelfCmdDispatch cmd '%s' => %p\n", procName, ObjStr(inst->argv[0]), cmd); AsmInstructionSetCmd(inst, asmMethodSelfCmdDispatch); } } else { //fprintf(stderr, "%s: asmMethodSelfDispatch cmd '%s'\n", procName, ObjStr(inst->argv[0])); } resInfo = NEW(AsmResolverInfo); // TODO: LEAK resInfo->cmd = cmd; resInfo->proc = proc; inst->clientData = resInfo; } } \ -returnsResult true \ -execCode { { AsmResolverInfo *resInfo = ip->clientData; Tcl_Command cmd = (resInfo->cmd != NULL) ? resInfo->cmd : Tcl_GetCommandFromObj(interp, ip->argv[0]); result = MethodDispatch(resInfo->proc->currentObject, interp, ip->argc, ip->argv, cmd, resInfo->proc->currentObject, NULL, ObjStr(ip->argv[0]), 0, 0); } } # methodSelfCmdDispatch is an optimized variant of # methodSelfDispatch, emitted alternatively by the assembler for the # above instruction. Instruction create methodSelfCmdDispatch \ -returnsResult true \ -execCode { { AsmResolverInfo *resInfo = ip->clientData; assert(resInfo->cmd != NULL); result = Tcl_NRCallObjProc(interp, Tcl_Command_objProc(resInfo->cmd), resInfo->proc->currentObject, ip->argc, ip->argv); } } # {self} Instruction create self \ -minArgs 1 -maxArgs 1 \ -execNeedsProc true \ -execCode { Tcl_SetObjResult(interp, proc->currentObject->cmdName); } # {jump instruction 2} # TODO: maybe define later jump labels in asm source Instruction create jump \ -minArgs 3 -maxArgs 3 -cArgs 1 -argTypes asmStatementInstructionType \ -execNeedsProc true \ -isJump true \ -execCode { //fprintf(stderr, "asmJump oc %d instructionIndex %d\n", ip->argc, PTR2INT(ip->argv[0])); NsfAsmJump(PTR2INT(ip->argv[0])); } # {jumpTrue instruction 6} # TODO: maybe define later jump labels in asm source Instruction create jumpTrue \ -minArgs 3 -maxArgs 3 -cArgs 1 -argTypes asmStatementInstructionType \ -execNeedsProc true \ -isJump true \ -execCode { if (proc->status != 0) { //fprintf(stderr, "asmJumpTrue jump oc %d instructionIndex %d\n", ip->argc, PTR2INT(ip->argv[0])); NsfAsmJump(PTR2INT(ip->argv[0])); } else { //fprintf(stderr, "asmJumpTrue fall through\n"); NsfAsmJumpNext(); } } # {leIntObj slot 4 slot 7} Instruction create leIntObj \ -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmStatementSlotType \ -execNeedsProc true \ -execCode { { int value1, value2; Tcl_Obj *obj; //fprintf(stderr, "leIntObj oc %d op1 %p op2 %p\n", ip->argc, ip->argv[0], ip->argv[1]); // for the time being, we compare two int values obj = proc->slots[PTR2INT(ip->argv[0])]; if (likely(obj->typePtr == Nsf_OT_intType)) { value1 = obj->internalRep.longValue; } else { Tcl_GetIntFromObj(interp, obj, &value1); } obj = proc->slots[PTR2INT(ip->argv[1])]; if (likely(obj->typePtr == Nsf_OT_intType)) { value2 = obj->internalRep.longValue; } else { Tcl_GetIntFromObj(interp, obj, &value2); } //fprintf(stderr, "asmLeScalar oc %d op1 %d op2 %d => %d\n", ip->argc, value1, value2, value1 <= value2); proc->status = value1 <= value2; } } # {leInt slot 4 slot 7} Instruction create leInt \ -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmStatementSlotType \ -execNeedsProc true \ -execCode { { int value1, value2; value1 = PTR2INT(proc->slots[PTR2INT(ip->argv[0])]); value2 = PTR2INT(proc->slots[PTR2INT(ip->argv[1])]); proc->status = value1 <= value2; } } # {duplicateObj slot 6 obj 2} # TODO: should force first arg "slot" Instruction create duplicateObj \ -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmStatementSlotObjArgType \ -execNeedsProc true \ -execCode { { int indexValue = PTR2INT(ip->argv[0]); //fprintf(stderr, "duplicateObj var[%d] = %s\n", indexValue, ObjStr(ip->argv[1])); if (proc->slots[indexValue]) { Tcl_DecrRefCount(proc->slots[indexValue]); } proc->slots[indexValue] = Tcl_DuplicateObj(ip->argv[1]); Tcl_IncrRefCount(proc->slots[indexValue]); proc->slotFlags[indexValue] |= ASM_SLOT_MUST_DECR; } } # {setObj slot 2 arg 0} # TODO: should force first arg "slot" Instruction create setObj \ -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmStatementSlotObjArgType \ -execNeedsProc true \ -execCode { //fprintf(stderr, "setObj var[%d] = %s\n", PTR2INT(ip->argv[0]), ObjStr(ip->argv[1])); proc->slots[PTR2INT(ip->argv[0])] = ip->argv[1]; } # {setInt slot 6 int 0} # TODO: should force first arg "slot" Instruction create setInt \ -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmStatementSlotIntType \ -execNeedsProc true \ -execCode { proc->slots[PTR2INT(ip->argv[0])] = ip->argv[1]; } # {setObjToResult slot 5} Instruction create setObjToResult \ -minArgs 3 -maxArgs 3 -cArgs 2 -argTypes asmStatementSlotType \ -execNeedsProc true \ -execCode { //fprintf(stderr, "setObjToResult var[%d] = %s\n", PTR2INT(ip->argv[0]), ObjStr(ip->argv[1])); proc->slots[PTR2INT(ip->argv[0])] = Tcl_GetObjResult(interp); } # {setResult slot 6} Instruction create setResult \ -minArgs 3 -maxArgs 3 -cArgs 1 -argTypes asmStatementSlotType \ -execNeedsProc true \ -execCode { Tcl_SetObjResult(interp, proc->slots[PTR2INT(ip->argv[0])]); } # {setResultInt slot 6} Instruction create setResultInt \ -minArgs 3 -maxArgs 3 -cArgs 1 -argTypes asmStatementSlotType \ -execNeedsProc true \ -execCode { Tcl_SetObjResult(interp, Tcl_NewIntObj(PTR2INT(proc->slots[PTR2INT(ip->argv[0])]))); } # {store code 4 argv 2} Instruction create storeResult \ -minArgs 5 -maxArgs 5 -cArgs 0 -argTypes asmStatementStoreType \ -asmEmitCode { codeIndex = -1; argvIndex = -1; for (j = offset; j < argc; j += 2) { int argIndex, intValue; Tcl_GetIndexFromObj(interp, argv[j], asmStatementArgType, "asm internal arg type", 0, &argIndex); Tcl_GetIntFromObj(interp, argv[j+1], &intValue); switch (argIndex) { case asmStatementArgTypeInstructionIdx: codeIndex = intValue; break; case asmStatementArgTypeArgvIdx: argvIndex = intValue; break; } } // TODO: CHECK codeIndex, argvIndex (>0, reasonable values) //fprintf(stderr, "%p setting instruction %d => %d %d\n", patches, currentAsmInstruction, codeIndex, argvIndex); patches->targetAsmInstruction = currentAsmInstruction; patches->sourceAsmInstruction = codeIndex; patches->argvIndex = argvIndex; patches++; } -execCode { ip->argv[0] = Tcl_GetObjResult(interp); Tcl_IncrRefCount(ip->argv[0]); } # {incrObj slot 6 slot 7} Instruction create incrObj \ -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmStatementSlotType \ -execNeedsProc true \ -execCode { { int intValue, incrValue; Tcl_Obj *intObj, *incrObj; //fprintf(stderr, "asmIncrScalar var[%d] incr var[%d], ", PTR2INT(ip->argv[0]), PTR2INT(ip->argv[1])); intObj = proc->slots[PTR2INT(ip->argv[0])]; incrObj = proc->slots[PTR2INT(ip->argv[1])]; if (likely(intObj->typePtr == Nsf_OT_intType)) { intValue = intObj->internalRep.longValue; } else { Tcl_GetIntFromObj(interp, intObj, &intValue); } if (likely(incrObj->typePtr == Nsf_OT_intType)) { incrValue = incrObj->internalRep.longValue; } else { Tcl_GetIntFromObj(interp, incrObj, &incrValue); } //fprintf(stderr, "%d + %d = %d,", intValue, incrValue, intValue + incrValue); Tcl_InvalidateStringRep(intObj); intObj->internalRep.longValue = (long)(intValue + incrValue); //fprintf(stderr, "updated %p var[%d] %p\n", intObj, PTR2INT(ip->argv[0]), proc->slots[PTR2INT(ip->argv[0])]); //Tcl_SetObjResult(interp, intObj); } } # {incrInt slot 6 slot 7} Instruction create incrInt \ -minArgs 5 -maxArgs 5 -cArgs 2 -argTypes asmStatementSlotType \ -execNeedsProc true \ -execCode { { int intValue, incrValue; //fprintf(stderr, "incrInt var[%d] incr var[%d]\n", PTR2INT(ip->argv[0]), PTR2INT(ip->argv[1])); intValue = PTR2INT(proc->slots[PTR2INT(ip->argv[0])]); incrValue = PTR2INT(proc->slots[PTR2INT(ip->argv[1])]); //fprintf(stderr, ".... intValue %d incr Value %d\n", intValue, incrValue); proc->slots[PTR2INT(ip->argv[0])] = INT2PTR(intValue + incrValue); //fprintf(stderr, ".... [%d] => %d\n", PTR2INT(ip->argv[0]), intValue + incrValue); } } } ###################################################################### # generate the code ###################################################################### generate ::LabelThreading generate ::CallThreading ./nsf2.4.0/generic/asm/nsfAsmAssemble.c000644 000766 000024 00000041553 13774105235 020452 0ustar00neumannstaff000000 000000 enum asmStatementIndex { asmObjProcIdx, asmEvalIdx, asmDuplicateObjIdx, asmIncrIntIdx, asmIncrObjIdx, asmIntegerIdx, asmJumpIdx, asmJumpTrueIdx, asmLeIntIdx, asmLeIntObjIdx, asmMethodDelegateDispatchIdx, asmMethodSelfDispatchIdx, asmNoopIdx, asmObjIdx, asmSelfIdx, asmSetIntIdx, asmSetObjIdx, asmSetObjToResultIdx, asmSetResultIdx, asmSetResultIntIdx, asmStoreResultIdx, asmVarIdx }; static CONST char *asmStatementNames[] = { "cmd", "eval", "duplicateObj", "incrInt", "incrObj", "integer", "jump", "jumpTrue", "leInt", "leIntObj", "methodDelegateDispatch", "methodSelfDispatch", "noop", "obj", "self", "setInt", "setObj", "setObjToResult", "setResult", "setResultInt", "storeResult", "var", NULL }; enum asmStatementArgTypeIndex { asmStatementArgTypeArgIdx, asmStatementArgTypeArgvIdx, asmStatementArgTypeInstructionIdx, asmStatementArgTypeIntIdx, asmStatementArgTypeObjIdx, asmStatementArgTypeResultIdx, asmStatementArgTypeSlotIdx, asmStatementArgTypeVarIdx }; static CONST char *asmStatementArgType[] = { "arg", "argv", "instruction", "int", "obj", "result", "slot", "var", NULL}; static CONST char *asmStatementCmdType[] = {"arg", "obj", "result", "var", NULL}; static CONST char *asmStatementInstructionType[] = {"instruction", NULL}; static CONST char *asmStatementIntType[] = {"int", NULL}; static CONST char *asmStatementObjType[] = {"obj", NULL}; static CONST char *asmStatementSlotObjArgType[] = {"slot", "obj", "arg", NULL}; static CONST char *asmStatementSlotType[] = {"slot", NULL}; static CONST char *asmStatementSlotIntType[] = {"slot", "int", NULL}; static CONST char *asmStatementStoreType[] = {"instruction", "argv", NULL}; static AsmStatementInfo asmStatementInfo[] = { /* asmObjProcIdx, */ {ASM_INFO_PAIRS|ASM_INFO_SKIP1, NULL, 2, -1, NR_PAIRS1}, /* asmEval */ {0|ASM_INFO_PAIRS, asmStatementCmdType, 3, -1, NR_PAIRS}, /* asmDuplicateObj */ {0|ASM_INFO_PAIRS, asmStatementSlotObjArgType, 5, 5, 2}, /* asmIncrInt */ {0|ASM_INFO_PAIRS, asmStatementSlotType, 5, 5, 2}, /* asmIncrObj */ {0|ASM_INFO_PAIRS, asmStatementSlotType, 5, 5, 2}, /* asmInteger */ {0|ASM_INFO_DECL|ASM_INFO_PAIRS, asmStatementIntType, 3, 3, 0}, /* asmJump */ {0|ASM_INFO_PAIRS, asmStatementInstructionType, 3, 3, 1}, /* asmJumpTrue */ {0|ASM_INFO_PAIRS, asmStatementInstructionType, 3, 3, 1}, /* asmLeInt */ {0|ASM_INFO_PAIRS, asmStatementSlotType, 5, 5, 2}, /* asmLeIntObj */ {0|ASM_INFO_PAIRS, asmStatementSlotType, 5, 5, 2}, /* asmMethodDelegateDispatch */ {0|ASM_INFO_PAIRS, asmStatementCmdType, 5, -1, NR_PAIRS}, /* asmMethodSelfDispatch */ {0|ASM_INFO_PAIRS, asmStatementCmdType, 3, -1, NR_PAIRS}, /* asmNoop */ {0, NULL, 1, 1, 0}, /* asmObj */ {0|ASM_INFO_DECL, NULL, 2, 2, 0}, /* asmSelf */ {0|ASM_INFO_PAIRS, NULL, 1, 1, 0}, /* asmSetInt */ {0|ASM_INFO_PAIRS, asmStatementSlotIntType, 5, 5, 2}, /* asmSetObj */ {0|ASM_INFO_PAIRS, asmStatementSlotObjArgType, 5, 5, 2}, /* asmSetObjToResult */ {0|ASM_INFO_PAIRS, asmStatementSlotType, 3, 3, 2}, /* asmSetResult */ {0|ASM_INFO_PAIRS, asmStatementSlotType, 3, 3, 1}, /* asmSetResultInt */ {0|ASM_INFO_PAIRS, asmStatementSlotType, 3, 3, 1}, /* asmStoreResult */ {0|ASM_INFO_PAIRS, asmStatementStoreType, 5, 5, 0}, /* asmVar */ {0|ASM_INFO_DECL|ASM_INFO_PAIRS, asmStatementObjType, 3, 3, 0} }; /* *---------------------------------------------------------------------- * AsmAssemble -- * * The assmbler, takes an assembly script in the form of a nested * list and emits the internal representation for the execution * engine. * *---------------------------------------------------------------------- */ static int AsmAssemble(ClientData cd, Tcl_Interp *interp, Tcl_Obj *nameObj, int nrArgs, Tcl_Obj *asmObj, AsmCompiledProc **retAsmProc) { AsmPatches patchArray[100], *patches = &patchArray[0], *patchPtr; // TODO: make me dynamic Tcl_Command cmd; AsmCompiledProc *proc; AsmInstruction *inst; int i, result, nrAsmInstructions, nrLocalObjs, totalArgvArgs; int oc, currentAsmInstruction, currentSlot; Tcl_Obj **ov; CONST char *procName; assert(nameObj != NULL); procName = ObjStr(nameObj); if (Tcl_ListObjGetElements(interp, asmObj, &oc, &ov) != TCL_OK) { return NsfPrintError(interp, "Asm code is not a valid list"); } /* * First Iteration: check wellformedness, determine sizes */ nrAsmInstructions = 0; nrLocalObjs = 0; totalArgvArgs = 0; for (i = 0; i < oc; i++) { int index, offset, wordOc; Tcl_Obj *lineObj = ov[i], **wordOv; if (Tcl_ListObjGetElements(interp, lineObj, &wordOc, &wordOv) != TCL_OK) { return NsfPrintError(interp, "Asm: line is not a well-formed asm instruction: %s", ObjStr(lineObj)); } result = Tcl_GetIndexFromObj(interp, wordOv[0], asmStatementNames, "asm instruction", 0, &index); if (result != TCL_OK) { return NsfPrintError(interp, "Asm: line is not a valid asm instruction: word %s, line %s", ObjStr(wordOv[0]), ObjStr(lineObj)); } offset = (asmStatementInfo[index].flags & ASM_INFO_SKIP1) ? 2 : 1; if ((asmStatementInfo[index].flags & ASM_INFO_PAIRS) && (wordOc-offset) % 2 == 1) { return NsfPrintError(interp, "Asm: argument list of cmd must contain pairs: %s", ObjStr(lineObj)); } if (asmStatementInfo[index].minArgs > -1 && wordOc < asmStatementInfo[index].minArgs) { return NsfPrintError(interp, "Asm: statement must contain at least %d words: %s", asmStatementInfo[index].minArgs, ObjStr(lineObj)); } if (asmStatementInfo[index].maxArgs > -1 && wordOc > asmStatementInfo[index].maxArgs) { return NsfPrintError(interp, "Asm: statement must contain at most %d words: %s", asmStatementInfo[index].maxArgs, ObjStr(lineObj)); } if (asmStatementInfo[index].argTypes) { result = AsmInstructionArgvCheck(interp, offset, wordOc, asmStatementInfo[index].argTypes, nrLocalObjs, oc, wordOv, lineObj); if (unlikely(result != TCL_OK)) {return result;} } if ((asmStatementInfo[index].flags & ASM_INFO_DECL) == 0) { int cArgs = asmStatementInfo[index].cArgs; /* * Determine the actual number of arguments passed to the * emitted instruction. This number might be determine by the * instruction type, or by the actual instruction being * processed (and later maybe for {*} etc.). */ if (cArgs == NR_PAIRS) { cArgs = (wordOc-offset) / 2; } else if (cArgs == NR_PAIRS1) { cArgs = 1 + (wordOc-offset) / 2; } //fprintf(stderr, "instruction %s need argvargs %d\n", ObjStr(lineObj), cArgs); totalArgvArgs += cArgs; nrAsmInstructions++; } else { /* currently obj and var from the same pool, will change... */ nrLocalObjs ++; } /* * optional, per-statement check operations */ switch (index) { case asmObjProcIdx: /* {cmd ::set slot 0 slot 2} */ cmd = Tcl_GetCommandFromObj(interp, wordOv[1]); if (cmd == NULL) { return NsfPrintError(interp, "Asm: cmd is not a valid Tcl command: %s\n", Tcl_GetString( wordOv[1])); } break; /* begin generated code */ /* end generated code */ default: break; } } nrAsmInstructions ++; fprintf(stderr, "%s: nrAsmInstructions %d nrLocalObjs %d nrArgs %d argvArgs %d => data %d\n", procName, nrAsmInstructions, nrLocalObjs, nrArgs, totalArgvArgs, nrLocalObjs + nrArgs + totalArgvArgs ); /* * Allocate structures */ proc = (AsmCompiledProc *)ckalloc(sizeof(AsmCompiledProc)); proc->code = (AsmInstruction *)ckalloc(sizeof(AsmInstruction) * nrAsmInstructions); memset(proc->slotFlags, 0, sizeof(int) * NSF_ASM_NR_STATIC_SLOTS); proc->ip = proc->code; /* points to the first writable instructon */ proc->firstObj = proc->staticObjs; /* point to the first free obj */ proc->locals = proc->staticObjs; /* locals is just an alias */ proc->nrAsmArgReferences = 0; proc->slots = proc->locals + nrArgs; //fprintf(stderr, "args = %ld\n", proc->slots - proc->locals); AsmLocalsAlloc(proc, nrArgs + nrLocalObjs); /* when freeing, we need something like for (i=0; i < nrArgs + nrLocalObjs; i++) { if (proc->slotFlags[i] & ASM_SLOT_MUST_DECR) {Tcl_DecrRefCount(proc->slots[i]); } } */ /* * Second Iteration: emit code */ currentSlot = 0; currentAsmInstruction = 0; for (i = 0; i < oc; i++) { int index, offset, cArgs, argc, codeIndex, argvIndex, j; Tcl_Obj *lineObj = ov[i], **argv; Tcl_ListObjGetElements(interp, lineObj, &argc, &argv); Tcl_GetIndexFromObj(interp, argv[0], asmStatementNames, "asm instruction", 0, &index); offset = (asmStatementInfo[index].flags & ASM_INFO_SKIP1) ? 2 : 1; cArgs = asmStatementInfo[index].cArgs; if (cArgs == NR_PAIRS) { cArgs = (argc-offset) / 2; } else if (cArgs == NR_PAIRS1) { cArgs = 1 + (argc-offset) / 2; } switch (index) { case asmObjProcIdx: /* {cmd ::set slot 0 slot 2} */ cmd = Tcl_GetCommandFromObj(interp, argv[1]); #if defined(LABEL_THREADING) inst = AsmInstructionNew(proc, objProc, cArgs); inst->cmd = ((Command *)cmd)->objProc; #else inst = AsmInstructionNew(proc, ((Command *)cmd)->objProc, cArgs); #endif inst->clientData = ((Command *)cmd)->objClientData; /* use the assembly word as cmd name; should be ok when we keep assembly around */ inst->argv[0] = argv[1]; /*fprintf(stderr, "[%d] %s/%d\n", currentAsmInstruction, Tcl_GetString(argv[1]), 1+((argc-offset)/2));*/ AsmInstructionArgvSet(interp, offset, argc, 1, inst, proc, argv, 0); break; /* begin generated code */ case asmEvalIdx: inst = AsmInstructionNew(proc, asmEval, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} break; case asmDuplicateObjIdx: inst = AsmInstructionNew(proc, asmDuplicateObj, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} inst->clientData = proc; break; case asmIncrIntIdx: inst = AsmInstructionNew(proc, asmIncrInt, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} inst->clientData = proc; break; case asmIncrObjIdx: inst = AsmInstructionNew(proc, asmIncrObj, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} inst->clientData = proc; break; case asmIntegerIdx: { int intValue; Tcl_GetIntFromObj(interp, argv[2], &intValue); proc->slots[currentSlot] = INT2PTR(intValue); //fprintf(stderr, "setting slots [%d] = %d\n", currentSlot, intValue); proc->slotFlags[currentSlot] |= ASM_SLOT_IS_INTEGER; currentSlot ++; } break; case asmJumpIdx: inst = AsmInstructionNew(proc, asmJump, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} inst->clientData = proc; break; case asmJumpTrueIdx: inst = AsmInstructionNew(proc, asmJumpTrue, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} inst->clientData = proc; break; case asmLeIntIdx: inst = AsmInstructionNew(proc, asmLeInt, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} inst->clientData = proc; break; case asmLeIntObjIdx: inst = AsmInstructionNew(proc, asmLeIntObj, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} inst->clientData = proc; break; case asmMethodDelegateDispatchIdx: inst = AsmInstructionNew(proc, asmMethodDelegateDispatch, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} { Tcl_Command cmd = NULL; NsfObject *object = NULL; AsmResolverInfo *resInfo; if (strncmp(ObjStr(inst->argv[1]), "::nsf::methods::", 16) == 0) { cmd = Tcl_GetCommandFromObj(interp, inst->argv[1]); //fprintf(stderr, "%s: asmMethod cmd '%s' => %p\n", procName, ObjStr(inst->argv[1]), cmd); } if (strncmp(ObjStr(inst->argv[0]), "::nx::", 6) == 0) { GetObjectFromObj(interp, inst->argv[0], &object); //fprintf(stderr, "%s: asmMethod object '%s' => %p\n", procName, ObjStr(inst->argv[0]), object); } if (cmd && object) { // experimental: bind obj and method resInfo = NEW(AsmResolverInfo); // TODO: LEAK resInfo->cmd = cmd; resInfo->object = object; inst->clientData = resInfo; AsmInstructionSetCmd(inst, asmMethodDelegateDispatch11); } else if (cmd != 0) { inst->clientData = cmd; } else { inst->clientData = NULL; } } break; case asmMethodSelfDispatchIdx: inst = AsmInstructionNew(proc, asmMethodSelfDispatch, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} { Tcl_Command cmd = NULL; AsmResolverInfo *resInfo; if (strncmp(ObjStr(inst->argv[0]), "::nsf::methods::", 16) == 0) { cmd = Tcl_GetCommandFromObj(interp, inst->argv[0]); if (cmd != 0) { //fprintf(stderr, "%s: asmMethodSelfCmdDispatch cmd '%s' => %p\n", procName, ObjStr(inst->argv[0]), cmd); AsmInstructionSetCmd(inst, asmMethodSelfCmdDispatch); } } else { //fprintf(stderr, "%s: asmMethodSelfDispatch cmd '%s'\n", procName, ObjStr(inst->argv[0])); } resInfo = NEW(AsmResolverInfo); // TODO: LEAK resInfo->cmd = cmd; resInfo->proc = proc; inst->clientData = resInfo; } break; case asmNoopIdx: inst = AsmInstructionNew(proc, asmNoop, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} break; case asmObjIdx: proc->slots[currentSlot] = argv[1]; Tcl_IncrRefCount(proc->slots[currentSlot]); proc->slotFlags[currentSlot] |= ASM_SLOT_MUST_DECR; currentSlot ++; break; case asmSelfIdx: inst = AsmInstructionNew(proc, asmSelf, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} inst->clientData = proc; break; case asmSetIntIdx: inst = AsmInstructionNew(proc, asmSetInt, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} inst->clientData = proc; break; case asmSetObjIdx: inst = AsmInstructionNew(proc, asmSetObj, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} inst->clientData = proc; break; case asmSetObjToResultIdx: inst = AsmInstructionNew(proc, asmSetObjToResult, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} inst->clientData = proc; break; case asmSetResultIdx: inst = AsmInstructionNew(proc, asmSetResult, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} inst->clientData = proc; break; case asmSetResultIntIdx: inst = AsmInstructionNew(proc, asmSetResultInt, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} inst->clientData = proc; break; case asmStoreResultIdx: inst = AsmInstructionNew(proc, asmStoreResult, cArgs); if (cArgs > 0) {AsmInstructionArgvSet(interp, offset, argc, 0, inst, proc, argv, 0);} codeIndex = -1; argvIndex = -1; for (j = offset; j < argc; j += 2) { int argIndex, intValue; Tcl_GetIndexFromObj(interp, argv[j], asmStatementArgType, "asm internal arg type", 0, &argIndex); Tcl_GetIntFromObj(interp, argv[j+1], &intValue); switch (argIndex) { case asmStatementArgTypeInstructionIdx: codeIndex = intValue; break; case asmStatementArgTypeArgvIdx: argvIndex = intValue; break; } } // TODO: CHECK codeIndex, argvIndex (>0, reasonable values) //fprintf(stderr, "%p setting instruction %d => %d %d\n", patches, currentAsmInstruction, codeIndex, argvIndex); patches->targetAsmInstruction = currentAsmInstruction; patches->sourceAsmInstruction = codeIndex; patches->argvIndex = argvIndex; patches++; break; case asmVarIdx: proc->slots[currentSlot] = NULL; currentSlot ++; break; /* end generated code */ } if ((asmStatementInfo[index].flags & ASM_INFO_DECL) == 0) { currentAsmInstruction ++; } } /* * add END instruction */ inst = AsmInstructionNew(proc, NULL, 0); /* * All addresses are determined, apply the argv patches triggered * from above. */ for (patchPtr = &patchArray[0]; patchPtr < patches; patchPtr++) { fprintf(stderr, "want to patch code[%d]->argv = code[%d]->argv[%d]\n", patchPtr->targetAsmInstruction, patchPtr->sourceAsmInstruction, patchPtr->argvIndex); /* set the argument vector of code[1] to the address of code[4]->argv[1] */ (&proc->code[patchPtr->targetAsmInstruction])->argv = &(&proc->code[patchPtr->sourceAsmInstruction])->argv[patchPtr->argvIndex]; } *retAsmProc = proc; return TCL_OK; } ./nsf2.4.0/generic/asm/README000644 000766 000024 00000022374 13322632446 016261 0ustar00neumannstaff000000 000000 The current implementation of the Tcl-byte-code engine is built around a large switch statement (the technique is called switch-threading). It is actually quite hard to understand and to de-mangle, since there are many goto-operations for optimization, etc. There exists several other implementation techniques for execution engines coming from the field of direct threaded code. In particular i invested into differences between switch-threading, call-threading and label threading. implementation mechanisms around, namely call-threading and label-threading (direct threading). First of all, threaded.c is a short introductory example, showing in a small concise program the differences of these techniques. On my machine i got the following results: 1: 0 seconds, 94591 usec 2: 0 seconds, 84749 usec 3: 0 seconds, 59811 usec [1] switch threading [2] call threading [3] label threading This experiment shows that the implementation of switch-threading is the slowest, followed by call threading and label threading. However, the implementation of label-threading depends on a non-standard C extension (label address operator) needed for computed gotos. However, the label address operator is supported by at least three different compilers (supported on GCC, clang and IBM's XL C/C++). Based on this study i built an experimental new code-engine for tcl (integrated in nsf/nx) based on the following ideas: - Use Tcl's basic implementation elements as base elements of the execution-engine: Tcl_Obj, Tcl_ObjCmdProc (objProcs). - Instead of defining a "byte code", implement the code essentially as an array of objProcs, were as well the argument vectors of the objProcs are built as far as possible at compile time. This makes it possible to implement quickly an execution engine for all of Tcl. - By using objProcs as basic mechanism, every tcl-command implementation will become effectively an "instruction" of the code engine. By defining new objProcs, the command set of the engine will be extended automatically. Specialized instructions with the same format can be registered depending on syntactic properties of the source (e.g. not all argument test will be required, part of the syntax errors can be caught at compile time, on could implement specialized versions for Tcl's "set" for setting and reading variables, etc.). - The code engine is designed for allowing different resolving strategies for cmds (objProcs): come commands could be resolved at compile-time, some commands must be resolved at runtime. Similar experiments can be made in the object oriented case for objects and methods. It is not completely clear, if the binding time flexibility should be an option for a production version of the execution engine, since this would cause differences in the semantics of Tcl (when commands are redefined). However, this option provides some good evidence for potential speedups. - The current byte code engine performs double dispatches on object oriented calls (one dispatch on the object, a second dispatch on the method). The new execution engine allows direct dispatch on methods. - Exploit typing information: NSF/NX provides "optionally typing" information (e.g. x:int). This optional typing information can be used at runtime as well for optimizing the code. - Provide an intermediate representation ("Tcl assembler") instead of "hard wiring" instructions to Tcl commands as implemented in Tcl. The Tcl assembler makes it easier to implement high-level optimizations to provide different implementations for e.g. a sequence of tcl instructions. Note that a Tcl compiler (a program translating Tcl source into Tcl assembler) can be implemented in Tcl as well. Furthermore, for some high-performance requirements, it is possible to simply write Tcl assembly code by hand (this is at least an alternative to C-coding). Note that the Tcl assembler is not machine dependent, the instructions are those of the "abstract Tcl machine". Currently, the syntax of the Tcl assembler is a nested Tcl list. - As explained above, label-threading is the fastest implementation technique of the compared approaches, but it is not supported by all c-compilers. Implemented execution engines are sufficiently different to make maintenance of two (or more) execution engines hard. In order to address this issue, i implemented an assembly code generator and an execution code generator in NX from a common, declarative source. The assembly code and the execution engines can be included in the source. Depending on the C-compiler, the "right" include can be chosen. Note that it is certainly possible to implement some more different (optimized) execution engines as well. - Replacing for Tcl the complete byte-code engine is quite a large task. In order to experiment with the new execution engines i implemented asm-proc and asm-method as counterparts of "proc" and "method", which will take in their body the tcl assembly language. When such a command is called, the appropriate execution engine is called. This way, the new execution engine can co-exist with Tcl's classical byte-code engine, it should not be as well quite easy to follow this approach in jimtcl. - In cases where the new tcl-compilation and assembly generation fails, one could fall back to the basic implementation (e.g. tcl byte code engine). Some preliminary results: - If one executes just the objProcs (e.g. for "set" Tcl_SetObjCmd), the old code engine is faster, but the new ones "work" as well. It is certainly possible to provide new optimized instructions for certain tasks (accessing/setting variables, increment operations etc.) using the same format. - Using such instructions, both new execution engines (for call-threading and label-threading) show to be much faster than Tcl's current bytecode engine. - The current implementation based on call-threading is for the example below up to about three times faster than the Tcl-implementation, the label-threading variant is about 5 times faster. Current shortcomings / work in progress: - The current implementation is not re-entrant (no stack integration, proc local variables are currently stored in the assembly proc structure, not on the stack). - For allowing "uplevels" and "upvars" and compiled locals, we will need in Tcl the proc call frames, which will certainly cost some performance. For high-performance situations, these frames could be made optional (these are not available if one would code the procs straightforward in C). Note that the example below with the for loop and incr, reentrancy and stack frames are not required/needed at all (since the code does neither call a proc (or eval) and the code is not recursive - it is not clear, how often such optimization would be possible). - The instruction set is just sufficient for the about 30 examples in my current regression test set. The instruction set is just experimental, and not sufficiently thoughtfully designed. - The assembly language is very primitive: one has a set of "slot" declarations which are constants or variables. Later references address these slots via their indices (starting with 0). Similarly, the instructions are numbered as well (the code is a C array of instructions). A "goto" simply addresses the next instruction via the array index. All "declarations" of local vars have to be written before the "instructions". - It is not clear, how much Tcl compatibility is needed or wanted (interface to compiled locals, variable-/call-traces, etc.) - No effort so far on compiling Tcl source into Tcl assembly. Below is a short example in Tcl (and the Tcl byte code engine) and in Tcl assembly in two implementation variants, one with Tcl_Objs, one with integers (in case the typing information is available or inferable from the Tcl source). The timing results based on clang under macOS: Call Threading: asm/t.001: 6.64 asm/t.002: 4.04 asm/t.003: 2.46 Label Threading: asm/t.001: 6.58 asm/t.002: 2.74 asm/t.003: 1.33 I'll push the version over the holidays to our public git repository. All the best -gustaf ================================================== package req nx::test nx::Test parameter count 100000 proc sum10.tcl {} { set sum 0 for {set i 0} {$i < 100} {incr i} { incr sum $i } return $sum } # Implementation in Tcl assembly, using tcl-objs for "sum", "i" and # the constants nsf::asm::proc sum10.asm1 {} { {obj sum} {obj i} {obj 0} {obj 1} {obj 100} {obj 0} {var obj 0} {var obj 1} {duplicateObj slot 6 obj 2} {duplicateObj slot 7 obj 5} {leIntObj slot 4 slot 7} {jumpTrue instruction 7} {incrObj slot 6 slot 7} {incrObj slot 7 slot 3} {jump instruction 2} {setResult slot 6} } # Implementation in Tcl assembly, using integers for "sum", "i" and # the constants nsf::asm::proc sum10.asm2 {} { {obj sum} {obj i} {integer int 1} {integer int 100} {integer int 0} {integer int 0} {setInt slot 4 int 0} {setInt slot 5 int 0} {leInt slot 3 slot 5} {jumpTrue instruction 7} {incrInt slot 4 slot 5} {incrInt slot 5 slot 2} {jump instruction 2} {setResultInt slot 4} } ? {sum10.tcl} "4950" ? {sum10.asm1} "4950" ? {sum10.asm2} "4950" ./nsf2.4.0/generic/asm/asmExecuteTemplateLabelThreading.c000644 000766 000024 00000002656 13774055744 024146 0ustar00neumannstaff000000 000000 enum instructionIdx { IDX_objProc, $INSTRUCTION_INDICES, IDX_NULL }; /* *---------------------------------------------------------------------- * AsmExecute -- * * Define the execution engine for the code * *---------------------------------------------------------------------- */ int AsmExecute(ClientData cd, Tcl_Interp *interp, AsmCompiledProc *proc, int argc, Tcl_Obj *CONST argv[]) { int i, result = TCL_OK; AsmInstruction *ip; static void *instructionLabel[] = { &&INST_objProc, $INSTRUCTION_LABELS, &&INST_NULL }; /* * Place a copy of the actual argument into locals. */ for (i=1; i < argc; i++) { proc->locals[i-1] = argv[i]; } /* * Update all references to compiled arguments. */ for (i=0; i < proc->nrAsmArgReferences; i++) { AsmArgReference *arPtr = &proc->argReferences[i]; *(arPtr->objPtr) = proc->locals[arPtr->argNr]; } /* * Set the instruction pointer to the begin of the code. */ ip = proc->code; proc->status = 0; //fprintf(stderr, "AsmExecute jumps to %p\n", ip); goto *instructionLabel[ip->labelIdx]; INST_NULL: return result; EXEC_RESULT_CODE_HANDLER: if (likely(result == TCL_OK)) { ip++; goto *instructionLabel[ip->labelIdx]; } else { return result; } INST_objProc: result = (*ip->cmd)(ip->clientData, interp, ip->argc, ip->argv); goto EXEC_RESULT_CODE_HANDLER; $GENERATED_INSTRUCTIONS } ./nsf2.4.0/generic/asm/nsfAsmExecuteLabelThreading.c000644 000766 000024 00000021627 13774056066 023116 0ustar00neumannstaff000000 000000 enum instructionIdx { IDX_objProc, IDX_asmEval, IDX_asmDuplicateObj, IDX_asmIncrInt, IDX_asmIncrObj, IDX_asmJump, IDX_asmJumpTrue, IDX_asmLeInt, IDX_asmLeIntObj, IDX_asmMethodDelegateDispatch, IDX_asmMethodDelegateDispatch11, IDX_asmMethodSelfCmdDispatch, IDX_asmMethodSelfDispatch, IDX_asmNoop, IDX_asmSelf, IDX_asmSetInt, IDX_asmSetObj, IDX_asmSetObjToResult, IDX_asmSetResult, IDX_asmSetResultInt, IDX_asmStoreResult, IDX_NULL }; /* *---------------------------------------------------------------------- * AsmExecute -- * * Define the execution engine for the code * *---------------------------------------------------------------------- */ int AsmExecute(ClientData cd, Tcl_Interp *interp, AsmCompiledProc *proc, int argc, Tcl_Obj *CONST argv[]) { int i, result = TCL_OK; AsmInstruction *ip; static void *instructionLabel[] = { &&INST_objProc, &&INST_asmEval, &&INST_asmDuplicateObj, &&INST_asmIncrInt, &&INST_asmIncrObj, &&INST_asmJump, &&INST_asmJumpTrue, &&INST_asmLeInt, &&INST_asmLeIntObj, &&INST_asmMethodDelegateDispatch, &&INST_asmMethodDelegateDispatch11, &&INST_asmMethodSelfCmdDispatch, &&INST_asmMethodSelfDispatch, &&INST_asmNoop, &&INST_asmSelf, &&INST_asmSetInt, &&INST_asmSetObj, &&INST_asmSetObjToResult, &&INST_asmSetResult, &&INST_asmSetResultInt, &&INST_asmStoreResult, &&INST_NULL }; /* * Place a copy of the actual argument into locals. */ for (i=1; i < argc; i++) { proc->locals[i-1] = argv[i]; } /* * Update all references to compiled arguments. */ for (i=0; i < proc->nrAsmArgReferences; i++) { AsmArgReference *arPtr = &proc->argReferences[i]; *(arPtr->objPtr) = proc->locals[arPtr->argNr]; } /* * Set the instruction pointer to the begin of the code. */ ip = proc->code; proc->status = 0; //fprintf(stderr, "AsmExecute jumps to %p\n", ip); goto *instructionLabel[ip->labelIdx]; INST_NULL: return result; EXEC_RESULT_CODE_HANDLER: if (likely(result == TCL_OK)) { ip++; goto *instructionLabel[ip->labelIdx]; } else { return result; } INST_objProc: result = (*ip->cmd)(ip->clientData, interp, ip->argc, ip->argv); goto EXEC_RESULT_CODE_HANDLER; INST_asmEval: result = Tcl_EvalObjv(interp, ip->argc, ip->argv, 0); goto EXEC_RESULT_CODE_HANDLER; ip++; goto *instructionLabel[ip->labelIdx]; INST_asmDuplicateObj: { int indexValue = PTR2INT(ip->argv[0]); //fprintf(stderr, "duplicateObj var[%d] = %s\n", indexValue, ObjStr(ip->argv[1])); if (proc->slots[indexValue]) { Tcl_DecrRefCount(proc->slots[indexValue]); } proc->slots[indexValue] = Tcl_DuplicateObj(ip->argv[1]); Tcl_IncrRefCount(proc->slots[indexValue]); proc->slotFlags[indexValue] |= ASM_SLOT_MUST_DECR; } ip++; goto *instructionLabel[ip->labelIdx]; INST_asmIncrInt: { int intValue, incrValue; //fprintf(stderr, "incrInt var[%d] incr var[%d]\n", PTR2INT(ip->argv[0]), PTR2INT(ip->argv[1])); intValue = PTR2INT(proc->slots[PTR2INT(ip->argv[0])]); incrValue = PTR2INT(proc->slots[PTR2INT(ip->argv[1])]); //fprintf(stderr, ".... intValue %d incr Value %d\n", intValue, incrValue); proc->slots[PTR2INT(ip->argv[0])] = INT2PTR(intValue + incrValue); //fprintf(stderr, ".... [%d] => %d\n", PTR2INT(ip->argv[0]), intValue + incrValue); } ip++; goto *instructionLabel[ip->labelIdx]; INST_asmIncrObj: { int intValue, incrValue; Tcl_Obj *intObj, *incrObj; //fprintf(stderr, "asmIncrScalar var[%d] incr var[%d], ", PTR2INT(ip->argv[0]), PTR2INT(ip->argv[1])); intObj = proc->slots[PTR2INT(ip->argv[0])]; incrObj = proc->slots[PTR2INT(ip->argv[1])]; if (likely(intObj->typePtr == Nsf_OT_intType)) { intValue = intObj->internalRep.longValue; } else { Tcl_GetIntFromObj(interp, intObj, &intValue); } if (likely(incrObj->typePtr == Nsf_OT_intType)) { incrValue = incrObj->internalRep.longValue; } else { Tcl_GetIntFromObj(interp, incrObj, &incrValue); } //fprintf(stderr, "%d + %d = %d,", intValue, incrValue, intValue + incrValue); Tcl_InvalidateStringRep(intObj); intObj->internalRep.longValue = (long)(intValue + incrValue); //fprintf(stderr, "updated %p var[%d] %p\n", intObj, PTR2INT(ip->argv[0]), proc->slots[PTR2INT(ip->argv[0])]); //Tcl_SetObjResult(interp, intObj); } ip++; goto *instructionLabel[ip->labelIdx]; INST_asmJump: //fprintf(stderr, "asmJump oc %d instructionIndex %d\n", ip->argc, PTR2INT(ip->argv[0])); NsfAsmJump(PTR2INT(ip->argv[0])); goto *instructionLabel[ip->labelIdx]; INST_asmJumpTrue: if (proc->status != 0) { //fprintf(stderr, "asmJumpTrue jump oc %d instructionIndex %d\n", ip->argc, PTR2INT(ip->argv[0])); NsfAsmJump(PTR2INT(ip->argv[0])); } else { //fprintf(stderr, "asmJumpTrue fall through\n"); NsfAsmJumpNext(); } goto *instructionLabel[ip->labelIdx]; INST_asmLeInt: { int value1, value2; value1 = PTR2INT(proc->slots[PTR2INT(ip->argv[0])]); value2 = PTR2INT(proc->slots[PTR2INT(ip->argv[1])]); proc->status = value1 <= value2; } ip++; goto *instructionLabel[ip->labelIdx]; INST_asmLeIntObj: { int value1, value2; Tcl_Obj *obj; //fprintf(stderr, "leIntObj oc %d op1 %p op2 %p\n", ip->argc, ip->argv[0], ip->argv[1]); // for the time being, we compare two int values obj = proc->slots[PTR2INT(ip->argv[0])]; if (likely(obj->typePtr == Nsf_OT_intType)) { value1 = obj->internalRep.longValue; } else { Tcl_GetIntFromObj(interp, obj, &value1); } obj = proc->slots[PTR2INT(ip->argv[1])]; if (likely(obj->typePtr == Nsf_OT_intType)) { value2 = obj->internalRep.longValue; } else { Tcl_GetIntFromObj(interp, obj, &value2); } //fprintf(stderr, "asmLeScalar oc %d op1 %d op2 %d => %d\n", ip->argc, value1, value2, value1 <= value2); proc->status = value1 <= value2; } ip++; goto *instructionLabel[ip->labelIdx]; INST_asmMethodDelegateDispatch: { Tcl_Command cmd = NULL; NsfObject *object; // obj and method are unresolved result = GetObjectFromObj(interp, ip->argv[0], &object); if (likely(ip->clientData != NULL)) { cmd = ip->clientData; } else { cmd = Tcl_GetCommandFromObj(interp, ip->argv[1]); } //fprintf(stderr, "cmd %p object %p\n", cmd, object); result = MethodDispatch(object, interp, ip->argc-1, ip->argv+1, cmd, object, NULL, ObjStr(ip->argv[1]), 0, 0); } goto EXEC_RESULT_CODE_HANDLER; ip++; goto *instructionLabel[ip->labelIdx]; INST_asmMethodDelegateDispatch11: // obj and method are resolved { AsmResolverInfo *resInfo = ip->clientData; result = MethodDispatch(resInfo->object, interp, ip->argc-1, ip->argv+1, resInfo->cmd, resInfo->object, NULL, ObjStr(ip->argv[1]), 0, 0); } goto EXEC_RESULT_CODE_HANDLER; ip++; goto *instructionLabel[ip->labelIdx]; INST_asmMethodSelfCmdDispatch: { AsmResolverInfo *resInfo = ip->clientData; assert(resInfo->cmd != NULL); result = Tcl_NRCallObjProc(interp, Tcl_Command_objProc(resInfo->cmd), resInfo->proc->currentObject, ip->argc, ip->argv); } goto EXEC_RESULT_CODE_HANDLER; ip++; goto *instructionLabel[ip->labelIdx]; INST_asmMethodSelfDispatch: { AsmResolverInfo *resInfo = ip->clientData; Tcl_Command cmd = (resInfo->cmd != NULL) ? resInfo->cmd : Tcl_GetCommandFromObj(interp, ip->argv[0]); result = MethodDispatch(resInfo->proc->currentObject, interp, ip->argc, ip->argv, cmd, resInfo->proc->currentObject, NULL, ObjStr(ip->argv[0]), 0, 0); } goto EXEC_RESULT_CODE_HANDLER; ip++; goto *instructionLabel[ip->labelIdx]; INST_asmNoop: ip++; goto *instructionLabel[ip->labelIdx]; INST_asmSelf: Tcl_SetObjResult(interp, proc->currentObject->cmdName); ip++; goto *instructionLabel[ip->labelIdx]; INST_asmSetInt: proc->slots[PTR2INT(ip->argv[0])] = ip->argv[1]; ip++; goto *instructionLabel[ip->labelIdx]; INST_asmSetObj: //fprintf(stderr, "setObj var[%d] = %s\n", PTR2INT(ip->argv[0]), ObjStr(ip->argv[1])); proc->slots[PTR2INT(ip->argv[0])] = ip->argv[1]; ip++; goto *instructionLabel[ip->labelIdx]; INST_asmSetObjToResult: //fprintf(stderr, "setObjToResult var[%d] = %s\n", PTR2INT(ip->argv[0]), ObjStr(ip->argv[1])); proc->slots[PTR2INT(ip->argv[0])] = Tcl_GetObjResult(interp); ip++; goto *instructionLabel[ip->labelIdx]; INST_asmSetResult: Tcl_SetObjResult(interp, proc->slots[PTR2INT(ip->argv[0])]); ip++; goto *instructionLabel[ip->labelIdx]; INST_asmSetResultInt: Tcl_SetObjResult(interp, Tcl_NewIntObj(PTR2INT(proc->slots[PTR2INT(ip->argv[0])]))); ip++; goto *instructionLabel[ip->labelIdx]; INST_asmStoreResult: ip->argv[0] = Tcl_GetObjResult(interp); Tcl_IncrRefCount(ip->argv[0]); ip++; goto *instructionLabel[ip->labelIdx]; } ./nsf2.4.0/generic/asm/nsfAssemble.c000644 000766 000024 00000034775 13774064156 020027 0ustar00neumannstaff000000 000000 /* * nsfAssemble.c -- * * Support for the experimental assemble feature. This file is * only included in the source when NSF_ASSEMBLE is turned on. * * Copyright (C) 2011-2014 Gustaf Neumann */ //#define LABEL_THREADING #if defined(LABEL_THREADING) typedef void (* InstLabel)(); #endif #define ASM_INFO_DECL 0x0001 #define ASM_INFO_PAIRS 0x0002 #define ASM_INFO_SKIP1 0x0004 #define ASM_SLOT_MUST_DECR 0x0001 #define ASM_SLOT_IS_INTEGER 0x0010 typedef struct AsmStatementInfo { int flags; CONST char **argTypes; int minArgs; int maxArgs; int cArgs; } AsmStatementInfo; typedef struct AsmInstruction { Tcl_ObjCmdProc *cmd; ClientData clientData; int argc; Tcl_Obj **argv; #if defined(LABEL_THREADING) int labelIdx; #endif } AsmInstruction; typedef struct AsmArgReference { int argNr; Tcl_Obj **objPtr; } AsmArgReference; #define NSF_ASM_NR_STATIC_SLOTS 30 typedef struct AsmCompiledProc { struct AsmInstruction *ip; /* pointer to the next writable instruction */ struct AsmInstruction *code; NsfObject *currentObject; int status; int nrLocals; Tcl_Obj **firstObj; /* pointer to staticObjs */ Tcl_Obj **locals; /* pointer to staticObjs */ Tcl_Obj **slots; /* pointer to staticObjs */ int slotFlags[NSF_ASM_NR_STATIC_SLOTS]; /* same size as allocated slots */ Tcl_Obj *staticObjs[NSF_ASM_NR_STATIC_SLOTS]; // static objs for the time being TODO overflows/dynamic int nrAsmArgReferences; struct AsmArgReference argReferences[10]; // for the time being TODO overflows/dynamic } AsmCompiledProc; typedef struct AsmPatches { int targetAsmInstruction; int sourceAsmInstruction; int argvIndex; } AsmPatches; typedef struct AsmProcClientData { NsfObject *object; /* common field of TclCmdClientData */ AsmCompiledProc *proc; NsfParamDefs *paramDefs; int with_ad; int with_checkAlways; } AsmProcClientData; typedef struct AsmResolverInfo { Tcl_Command cmd; NsfObject *object; AsmCompiledProc *proc; } AsmResolverInfo; #if defined(LABEL_THREADING) # define AsmInstructionNew(proc, instruction, argc) AsmInstructionNewLT(proc, IDX_ ## instruction, argc) # define AsmInstructionSetCmd(inst, name) inst->labelIdx = IDX_ ## name # define NsfAsmJump(index) ip = &proc->code[(index)] # define NsfAsmJumpNext() ip++ AsmInstruction *AsmInstructionNewLT(AsmCompiledProc *proc, int labelIdx, int argc) { proc->ip->labelIdx = labelIdx; proc->ip->cmd = NULL; proc->ip->argc = argc; proc->ip->argv = proc->firstObj; proc->firstObj += argc; return proc->ip++; } #else # define AsmInstructionNew(proc, instruction, argc) AsmInstructionNewCT(proc, (Tcl_ObjCmdProc*)instruction, argc) # define AsmInstructionSetCmd(inst, name) inst->cmd = (Tcl_ObjCmdProc*)name # define NsfAsmJump(index) proc->ip = &proc->code[(index)-1] # define NsfAsmJumpNext() AsmInstruction *AsmInstructionNewCT(AsmCompiledProc *proc, Tcl_ObjCmdProc *objProc, int argc) { proc->ip->cmd = objProc; proc->ip->argc = argc; proc->ip->argv = proc->firstObj; proc->firstObj += argc; return proc->ip++; } #endif void AsmLocalsAlloc(AsmCompiledProc *proc, int nrLocals) { proc->nrLocals = nrLocals; proc->firstObj += nrLocals; } void AsmArgSet(AsmCompiledProc *proc, int argNr, Tcl_Obj **addr) { AsmArgReference *arPtr = &proc->argReferences[proc->nrAsmArgReferences]; arPtr->argNr = argNr; arPtr->objPtr = addr; proc->nrAsmArgReferences ++; } void AsmInstructionPrint(AsmInstruction *ip) { int i; fprintf(stderr, "(%d) ", ip->argc); for (i=0; iargc; i++) {fprintf(stderr, "%s ", ObjStr(ip->argv[i]));} fprintf(stderr, "\n"); } /* *---------------------------------------------------------------------- * AsmExecute, AsmAssemble -- * * Define the execution engine for the code * *---------------------------------------------------------------------- */ #define NR_PAIRS -1 #define NR_PAIRS1 -2 /* * Prototypes needed for the execution engines included below */ static int AsmInstructionArgvCheck(Tcl_Interp *interp, int from, int to, CONST char **argType, int nrObjs, int nrStatements, Tcl_Obj **wordOv, Tcl_Obj *lineObj); static void AsmInstructionArgvSet(Tcl_Interp *interp, int from, int to, int currentArg, AsmInstruction *inst, AsmCompiledProc *asmProc, Tcl_Obj **wordOv, int verbose); #if defined(LABEL_THREADING) # include "asm/nsfAsmExecuteLabelThreading.c" #else # include "asm/nsfAsmExecuteCallThreading.c" #endif #include "asm/nsfAsmAssemble.c" /* *---------------------------------------------------------------------- * AsmInstructionArgvCheck -- * * Check the argument types of an assemble statement. * *---------------------------------------------------------------------- */ static int AsmInstructionArgvCheck(Tcl_Interp *interp, int from, int to, CONST char **argType, int nrSlots, int nrStatements, Tcl_Obj **wordOv, Tcl_Obj *lineObj) { int j; for (j = from; j < to; j += 2) { int argIndex, typesIndex, intValue, result; //fprintf(stderr, "check arg type %s\n", ObjStr(wordOv[j])); result = Tcl_GetIndexFromObj(interp, wordOv[j], asmStatementArgType, "asm statement arg type", 0, &typesIndex); if (result != TCL_OK) { return NsfPrintError(interp, "Asm: unknown arg type %s, line '%s'", ObjStr(wordOv[j]), ObjStr(lineObj)); } result = Tcl_GetIndexFromObj(interp, wordOv[j], argType, "asm internal arg type", 0, &argIndex); if (result != TCL_OK) { return NsfPrintError(interp, "Asm: instruction argument has invalid type: '%s', line %s\n", ObjStr(wordOv[j]), ObjStr(lineObj)); } //fprintf(stderr, "check arg value %s\n", ObjStr(wordOv[j+1])); if (Tcl_GetIntFromObj(interp, wordOv[j+1], &intValue) != TCL_OK || intValue < 0) { return NsfPrintError(interp, "Asm: instruction argument of type %s must have numeric index >= 0," " got '%s', line '%s'", ObjStr(wordOv[j]), ObjStr(wordOv[j+1]), ObjStr(lineObj)); } if (( typesIndex == asmStatementArgTypeObjIdx || typesIndex == asmStatementArgTypeSlotIdx ) && intValue > nrSlots) { return NsfPrintError(interp, "Asm: instruction argument value must be less than %d," " got '%s', line '%s'", nrSlots, ObjStr(wordOv[j+1]), ObjStr(lineObj)); } /* we assume, that every declaration results in exactly one slot */ if ((typesIndex == asmStatementArgTypeInstructionIdx) && intValue > (nrStatements - nrSlots)) { return NsfPrintError(interp, "Asm: instruction argument value must be less than %d," " got '%s', line '%s'", nrStatements - nrSlots, ObjStr(wordOv[j+1]), ObjStr(lineObj)); } } return TCL_OK; } /* *---------------------------------------------------------------------- * AsmInstructionArgvSet -- * * Set argument to be passed to an instruction of the assemble * code. * *---------------------------------------------------------------------- */ static void AsmInstructionArgvSet(Tcl_Interp *interp, int from, int to, int currentArg, AsmInstruction *inst, AsmCompiledProc *asmProc, Tcl_Obj **wordOv, int verbose) { int j; for (j = from; j < to; j += 2, currentArg++) { int argIndex, intValue; Tcl_GetIndexFromObj(interp, wordOv[j], asmStatementArgType, "asm cmd arg type", 0, &argIndex); Tcl_GetIntFromObj(interp, wordOv[j+1], &intValue); if (verbose != 0) { fprintf(stderr, "AsmInstructionArgvSet (type %d) arg[%d] := %s[%s]\n", argIndex, currentArg, ObjStr(wordOv[j]), ObjStr(wordOv[j+1])); } switch (argIndex) { case asmStatementArgTypeObjIdx: inst->argv[currentArg] = asmProc->slots[intValue]; break; case asmStatementArgTypeArgIdx: AsmArgSet(asmProc, intValue, &inst->argv[currentArg]); break; case asmStatementArgTypeResultIdx: inst->argv[currentArg] = NULL; break; case asmStatementArgTypeSlotIdx: case asmStatementArgTypeInstructionIdx: case asmStatementArgTypeIntIdx: inst->argv[currentArg] = INT2PTR(intValue); break; case asmStatementArgTypeVarIdx: fprintf(stderr, ".... var set [%d] = %s\n", currentArg, ObjStr(wordOv[j+1])); inst->argv[currentArg] = wordOv[j+1]; Tcl_IncrRefCount(inst->argv[currentArg]); // TODO: DECR missing break; } /*fprintf(stderr, "[%d] inst %p name %s arg[%d] %s\n", currentAsmInstruction, inst, ObjStr(inst->argv[0]), currentArg, inst->argv[currentArg] ? ObjStr(inst->argv[currentArg]) : "NULL");*/ } } /* *---------------------------------------------------------------------- * NsfAsmProcDeleteProc -- * * Tcl_CmdDeleteProc for NsfAsmProcDeleteProc. Is called, whenever a * NsfAsmProcDeleteProc is deleted and frees the associated client data. * * Results: * None. * * Side effects: * Frees client-data * *---------------------------------------------------------------------- */ static void NsfAsmProcDeleteProc(ClientData clientData) { AsmProcClientData *cd = clientData; /*fprintf(stderr, "NsfAsmProcDeleteProc received %p\n", clientData);*/ fprintf(stderr, "NsfAsmProcDeleteProc: TODO free asmProc\n"); if (cd->paramDefs != 0) { /* tcd->paramDefs is freed by NsfProcDeleteProc() */ fprintf(stderr, "NsfAsmProcDeleteProc: TODO free paramDefs\n"); } FREE(AsmProcClientData, cd); } /* *---------------------------------------------------------------------- * NsfAsmProc -- * * Tcl_ObjCmdProc implementing Asm procs. This function processes * the argument list in accordance with the parameter definitions * and calls in case of success the asm proc body. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ extern int NsfAsmProc(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { AsmProcClientData *cd = clientData; int result; assert(cd != NULL); assert(cd->proc); //fprintf(stderr, "NsfAsmProcStub %s is called, tcd %p object %p\n", ObjStr(objv[0]), cd, cd->object); if (likely(cd->paramDefs && cd->paramDefs->paramsPtr)) { ALLOC_ON_STACK(Tcl_Obj*, objc, tov); fprintf(stderr, "not implemented yet\n"); #if 0 { ParseContext *pcPtr; pcPtr = (ParseContext *) NsfTclStackAlloc(interp, sizeof(ParseContext), "parse context"); /* * We have to substitute the first element of objv with the name * of the function to be called. Since objv is immutable, we have * to copy the full argument vector and replace the element on * position [0] */ memcpy(tov, objv, sizeof(Tcl_Obj *)*(objc)); //tov[0] = tcd->procName; /* If the argument parsing is ok, the body will be called */ result = ProcessMethodArguments(pcPtr, interp, NULL, 0, cd->paramDefs, objv[0], objc, tov); if (likely(result == TCL_OK)) { result = InvokeShadowedProc(interp, cd->procName, cd->cmd, pcPtr); } else { /*Tcl_Obj *resultObj = Tcl_GetObjResult(interp); fprintf(stderr, "NsfProcStub: incorrect arguments (%s)\n", ObjStr(resultObj));*/ ParseContextRelease(pcPtr); NsfTclStackFree(interp, pcPtr, "release parse context"); } } #endif /*fprintf(stderr, "NsfProcStub free on stack %p\n", tov);*/ FREE_ON_STACK(Tcl_Obj *, tov); } else { int requiredArgs = cd->proc->slots - cd->proc->locals; //fprintf(stderr, "no compiled parameters\n"); if (unlikely(requiredArgs != objc-1)) { return NsfPrintError(interp, "wrong # of arguments"); } cd->proc->currentObject = cd->object; result = AsmExecute(NULL, interp, cd->proc, objc, objv); } return result; } static int NsfAsmProcAddParam(Tcl_Interp *interp, NsfParsedParam *parsedParamPtr, Tcl_Obj *nameObj, Tcl_Obj *bodyObj, int with_ad) { fprintf(stderr, "NsfAsmProcAddParam not implemented yet\n"); //CONST char *procName = ObjStr(nameObj); return TCL_OK; } static int NsfAsmProcAddArgs(Tcl_Interp *interp, Tcl_Obj *argumentsObj, Tcl_Obj *nameObj, Tcl_Obj *bodyObj, int with_ad, int with_checkAlways) { int argc, result; Tcl_Obj **argv; AsmCompiledProc *asmProc; AsmProcClientData *cd; CONST char *procName = ObjStr(nameObj); if (unlikely(Tcl_ListObjGetElements(interp, argumentsObj, &argc, &argv) != TCL_OK)) { return NsfPrintError(interp, "argument list invalid '%s'", ObjStr(argumentsObj)); } result = AsmAssemble(NULL, interp, nameObj, argc, bodyObj, &asmProc); if (unlikely(result != TCL_OK)) { return result; } cd = NEW(AsmProcClientData); cd->object = NULL; cd->proc = asmProc; cd->paramDefs = NULL; cd->with_ad = with_ad; cd->with_checkAlways = (with_checkAlways != 0) ? NSF_ARGPARSE_CHECK : 0; Tcl_CreateObjCommand(interp, procName, NsfAsmProc, cd, NsfAsmProcDeleteProc); return TCL_OK; } /* cmd method::asmcreate NsfAsmMethodCreateCmd { {-argName "object" -required 1 -type object} {-argName "-checkalways" -required 0 -nrargs 0 -type switch} {-argName "-inner-namespace" -nrargs 0} {-argName "-per-object" -nrargs 0} {-argName "-reg-object" -required 0 -nrargs 1 -type object} {-argName "name" -required 1 -type tclobj} {-argName "arguments" -required 1 -type tclobj} {-argName "body" -required 1 -type tclobj} } */ static int NsfAsmMethodCreateCmd(Tcl_Interp *interp, NsfObject *defObject, int withInner_namespace, int withPer_object, NsfObject *regObject, Tcl_Obj *nameObj, Tcl_Obj *argumentsObj, Tcl_Obj *bodyObj) { int argc, result; Tcl_Obj **argv; AsmCompiledProc *asmProc; AsmProcClientData *cd; NsfClass *cl = (withPer_object || ! NsfObjectIsClass(defObject)) ? NULL : (NsfClass *)defObject; // not handled: // * withInner_namespace, // * regObject, // * pre and post-conditions // * withCheckAlways ? NSF_ARGPARSE_CHECK : 0 if (cl == 0) { RequireObjNamespace(interp, defObject); } if (unlikely(Tcl_ListObjGetElements(interp, argumentsObj, &argc, &argv) != TCL_OK)) { return NsfPrintError(interp, "argument list invalid '%s'", ObjStr(argumentsObj)); } result = AsmAssemble(NULL, interp, nameObj, argc, bodyObj, &asmProc); if (unlikely(result != TCL_OK)) { return result; } cd = NEW(AsmProcClientData); cd->proc = asmProc; cd->paramDefs = NULL; cd->with_ad = 0; if (cl == NULL) { result = NsfAddObjectMethod(interp, (Nsf_Object *)defObject, ObjStr(nameObj), (Tcl_ObjCmdProc *)NsfAsmProc, cd, NsfAsmProcDeleteProc, 0); } else { result = NsfAddClassMethod(interp, (Nsf_Class *)cl, ObjStr(nameObj), (Tcl_ObjCmdProc *)NsfAsmProc, cd, NsfAsmProcDeleteProc, 0); } return result; } ./nsf2.4.0/generic/asm/asm.tcl000644 000766 000024 00000014403 12501766547 016667 0ustar00neumannstaff000000 000000 package req nx::test nx::Test parameter count 100000 #nx::Test parameter count 10 proc sum10.tcl {} { set sum 0 for {set i 0} {$i < 100} {incr i} { incr sum $i } return $sum } # implementation in assembly, using tcl-objs for # "sum", "i" and the constants nsf::asm::proc sum10.asm1 {} { {obj sum} {obj i} {obj 0} {obj 1} {obj 100} {obj 0} {var obj 0} {var obj 1} {duplicateObj slot 6 obj 2} {duplicateObj slot 7 obj 5} {leIntObj slot 4 slot 7} {jumpTrue instruction 7} {incrObj slot 6 slot 7} {incrObj slot 7 slot 3} {jump instruction 2} {setResult slot 6} } # implementation in assembly, using tcl-objs for # "sum", "i" and the constants nsf::asm::proc sum10.asm2 {} { {obj sum} {obj i} {integer int 1} {integer int 100} {integer int 0} {integer int 0} {setInt slot 4 int 0} {setInt slot 5 int 0} {leInt slot 3 slot 5} {jumpTrue instruction 7} {incrInt slot 4 slot 5} {incrInt slot 5 slot 2} {jump instruction 2} {setResultInt slot 4} } ? {sum10.tcl} "4950" ? {sum10.asm1} "4950" ? {sum10.asm2} "4950" #exit proc incr1.tcl {x} { incr x } # currently we have to set the local var of the argument nsf::asm::proc incr1.asm1 {x} { {obj x} {obj 1} {cmd ::set obj 0 arg 0} {cmd ::incr obj 0 obj 1} } nsf::asm::proc incr1.asm2 {x} { {obj x} {obj 1} {var obj 0} {setObj slot 2 arg 0} {incrObj slot 2 slot 1} {setResult slot 2} } ? {incr1.tcl 10} "11" ? {incr1.asm1 10} "11" ? {incr1.asm2 10} "11" proc incr2.tcl {x} { set a $x incr a } nsf::asm::proc incr2.asm1 {x} { {obj a} {obj 1} {cmd ::set obj 0 arg 0} {cmd ::incr obj 0 obj 1} } nsf::asm::proc incr2.asm2 {x} { {obj a} {obj 1} {var obj 0} {setObj slot 2 arg 0} {incrObj slot 2 slot 1} {setResult slot 2} } ? {incr2.tcl 13} "14" ? {incr2.asm1 13} "14" ? {incr2.asm2 13} "14" proc foo.tcl {x} { set a 1 set b $x incr a [incr b] return $a } nsf::asm::proc foo.asm1 {x} { {obj a} {obj b} {obj 1} {cmd ::set obj 0 obj 2} {cmd ::set obj 1 arg 0} {cmd ::incr obj 1} {store instruction 4 argv 2} {cmd ::incr obj 0 result 3} {cmd ::set obj 0} } nsf::asm::proc foo.asm2 {x} { {obj a} {obj b} {obj 1} {var obj 0} {var obj 1} {var obj 2} {setObj slot 3 obj 2} {setObj slot 4 arg 0} {incrObj slot 4 slot 2} {setObjToResult slot 5} {incrObj slot 3 slot 5} {cmd ::set obj 0} } ? {foo.tcl 100} "102" ? {foo.asm1 100} "102" ? {foo.asm2 100} "102" #exit proc bar.tcl {x} {concat [format %c 64] - [format %c 65] - $x} nsf::asm::proc bar.asm {x} { {obj %c} {obj -} {obj 64} {obj 65} {cmd ::format obj 0 obj 2} {store instruction 4 argv 1} {cmd ::format obj 0 obj 3} {store instruction 4 argv 3} {cmd ::concat result 1 obj 1 result 3 obj 1 arg 0} } #puts [bar.asm 123] ? {bar.tcl 123} "@ - A - 123" ? {bar.asm 123} "@ - A - 123" proc create1.tcl {} {nx::Object create o1} nsf::asm::proc create1.asm1 {} { {obj ::nx::Object} {obj create} {obj o1} {eval obj 0 obj 1 obj 2} } nsf::asm::proc create1.asm2 {} { {obj create} {obj o1} {cmd ::nx::Object obj 0 obj 1} } nsf::asm::proc create1.asm3 {} { {obj nx::Object} {obj ::nsf::methods::class::create} {obj o1} {methodDelegateDispatch obj 0 obj 1 obj 2} } nsf::asm::proc create1.asm4 {} { {obj ::nx::Object} {obj ::nsf::methods::class::create} {obj o1} {methodDelegateDispatch obj 0 obj 1 obj 2} } ? {create1.tcl} "::o1" ? {create1.asm1} "::o1" ? {create1.asm2} "::o1" ? {create1.asm3} "::o1" ? {create1.asm4} "::o1" proc create2.tcl {} {nx::Object create o1;o1 destroy;::nsf::object::exists o1} nsf::asm::proc create2.asm1 {} { {obj create} {obj o1} {obj destroy} {cmd ::nx::Object obj 0 obj 1} {eval obj 1 obj 2} {cmd ::nsf::object::exists obj 1} } nsf::asm::proc create2.asm2 {} { {obj o1} {obj nx::Object} {obj ::nsf::methods::class::create} {obj ::nsf::methods::object::destroy} {methodDelegateDispatch obj 1 obj 2 obj 0} {methodDelegateDispatch obj 0 obj 3} {cmd ::nsf::object::exists obj 0} } nsf::asm::proc create2.asm3 {} { {obj o1} {obj ::nx::Object} {obj ::nsf::methods::class::create} {obj ::nsf::methods::object::destroy} {methodDelegateDispatch obj 1 obj 2 obj 0} {methodDelegateDispatch obj 0 obj 3} {cmd ::nsf::object::exists obj 0} } ? {create2.tcl} 0 ? {create2.asm1} 0 ? {create2.asm2} 0 ? {create2.asm3} 0 proc check_obj.tcl {} {::nsf::object::exists o1} nsf::asm::proc check_obj.asm1 {} { {obj o1} {cmd ::nsf::object::exists obj 0} } nsf::asm::proc check_obj.asm2 {} { {obj o1} {obj ::nsf::object::exists} {eval obj 1 obj 0} } ? {check_obj.tcl} 0 ? {check_obj.asm1} 0 ? {check_obj.asm2} 0 nx::Object create o { set :x 1 } nsf::method::create o check_obj.tcl {} {::nsf::object::exists o1} nsf::method::asmcreate o check_obj.asm1 {} { {obj o1} {cmd ::nsf::object::exists obj 0} } nsf::method::asmcreate o check_obj.asm2 {} { {obj o1} {obj ::nsf::object::exists} {eval obj 1 obj 0} } ? {o check_obj.tcl} 0 ? {o check_obj.asm1} 0 ? {o check_obj.asm2} 0 # info exists is byte-compiled nsf::method::create o check_var1.tcl {} {info exists :x} nsf::method::asmcreate o check_var1.asm1 {} { {obj exists} {obj :x} {cmd ::info obj 0 obj 1} } ? {o check_var1.tcl} 1 ? {o check_var1.asm1} 1 # check for existence via method nsf::method::create o check_var2.tcl {} { : ::nsf::methods::object::exists x } nsf::method::asmcreate o check_var2.asm1 {} { {obj :} {obj ::nsf::methods::object::exists} {obj x} {eval obj 0 obj 1 obj 2} } nsf::method::asmcreate o check_var2.asm2 {} { {obj ::o} {obj ::nsf::methods::object::exists} {obj x} {methodDelegateDispatch obj 0 obj 1 obj 2} } nsf::method::asmcreate o check_var2.asm3 {} { {obj nsf::methods::object::exists} {obj x} {methodSelfDispatch obj 0 obj 1} } nsf::method::asmcreate o check_var2.asm4 {} { {obj ::nsf::methods::object::exists} {obj x} {methodSelfDispatch obj 0 obj 1} } ? {o check_var2.tcl} 1 ? {o check_var2.asm1} 1 ? {o check_var2.asm2} 1 ? {o check_var2.asm3} 1 ? {o check_var2.asm4} 1 # # self # nsf::method::create o self.tcl {} { self } nsf::method::asmcreate o self.asm1 {} { {obj self} {eval obj 0} } nsf::method::asmcreate o self.asm2 {} { {cmd self} } nsf::method::asmcreate o self.asm3 {} { {self} } ? {o self.tcl} ::o ? {o self.asm1} ::o ? {o self.asm2} ::o ? {o self.asm3} ::o ./nsf2.4.0/generic/asm/threaded.c000644 000766 000024 00000012654 13774056240 017330 0ustar00neumannstaff000000 000000 /* * threaded.c -- * * A small study on implementation techniques for threaded code. * * As example a small program stacking two values on to the stack * and adding the result is taken (example from wikipedia). This * program uses the abstract machine instructions PUSH_A, PUSH_B, * ADD, and END. These instructions are coded in different ways: * * * switch_threading(): realizing instructions as C enum * values, the program is represented as an array of enums, * placed in a large surrounding switch statement. * * * call_threading(): realizing instructions as C functions, the * program is represented an array of C functions. * * * label_threading(): realizing instructions as labels, the * program is represented an array of labels. * * The test show, that label_threading is clearly the winner in * terms of performance, but this depends on a non standard C * extension, which is implemented in at least three different * compilers (supported on GCC, clang and IBM's XL C/C++). It * would be interesting to define the instructions in some * e.g. scripting language and to produce different * implementations from the same source to address the * portability issue. * * Most probably, one needs a larger program-code with more * instructions to provide more meaningful results. * * Compile e.g. with: * cc -O3 -Wall threaded.c -o threaded * * Gustaf Neumann (Nov 2011) */ #include #include /* *---------------------------------------------------------------------- * DiffTime -- * * Compute the time difference between two timevals. * *---------------------------------------------------------------------- */ static void DiffTime(struct timeval *t1, struct timeval *t0, struct timeval *diffPtr) { diffPtr->tv_sec = t1->tv_sec - t0->tv_sec; diffPtr->tv_usec = t1->tv_usec - t0->tv_usec; if (diffPtr->tv_usec < 0) { diffPtr->tv_sec += (diffPtr->tv_usec / 1000000L) - 1; diffPtr->tv_usec = (diffPtr->tv_usec % 1000000L) + 1000000L; } else if (diffPtr->tv_usec > 1000000L) { diffPtr->tv_sec += diffPtr->tv_usec / 1000000L; diffPtr->tv_usec = diffPtr->tv_usec % 1000000L; } } /* *---------------------------------------------------------------------- * timeit -- * * Run a function multiple times and measure the performance. * *---------------------------------------------------------------------- */ static void timeit( void (* fn)() ) { struct timeval start, end, diff; int i; gettimeofday(&start, NULL); for (i=0; i<10000000; i++) { (*fn)(); } gettimeofday(&end, NULL); DiffTime(&end, &start, &diff); printf("%d seconds, %d usec\n", (int) diff.tv_sec, (int) diff.tv_usec); } int *sp; int stack[100]; /* *---------------------------------------------------------------------- * switch_threading -- * * Define an enum for the instructions and use a switch to select * the instructions. * *---------------------------------------------------------------------- */ void switch_threading() { typedef enum {INST_PUSH_A, INST_PUSH_B, INST_ADD, INST_END} InstEnum; static InstEnum mycode[] = {INST_PUSH_A, INST_PUSH_B, INST_ADD, INST_END}; int a, b; InstEnum *ip; ip = &mycode[0]; sp = &stack[0]; for (;;) { switch (*ip++) { case INST_PUSH_A: *sp++ = 100; continue; case INST_PUSH_B: *sp++ = 200; continue; case INST_ADD: a = *--sp; b = *--sp; *sp++ = a + b; continue; case INST_END: //fprintf(stderr, "end %d\n", *(sp-1)); return; } } } /* *---------------------------------------------------------------------- * call_threading -- * * Define for every instruction a function, the program consists of * an array of function pointers. * *---------------------------------------------------------------------- */ typedef void (* InstFn)(); void pushA () { *sp++ = 100; } void pushB () { *sp++ = 200; } void add () { int a = *--sp; int b = *--sp; *sp++ = a + b; } void call_threading() { static InstFn mycode[] = {&pushA, &pushB, &add, NULL}; InstFn *ip; sp = &stack[0]; ip = &mycode[0]; while (*ip) { (*ip++)(); } //fprintf(stderr, "end %d\n", *(sp-1)); } /* *---------------------------------------------------------------------- * label_threading -- * * Define for every instruction a label, the code is a sequence of * labels. This works with gcc, clang and IBM's XL C, but not on * every compiler. * *---------------------------------------------------------------------- */ typedef void (* InstLabel)(); void label_threading() { static InstLabel mycode[] = {&&INST_PUSH_A, &&INST_PUSH_B, &&INST_ADD, &&INST_END}; InstLabel *ip; int a, b; sp = &stack[0]; ip = &mycode[0]; INST_PUSH_A: *sp++ = 100; goto **ip++; INST_PUSH_B: *sp++ = 200; goto **ip++; INST_ADD: a = *--sp; b = *--sp; *sp++ = a + b; goto **ip++; INST_END: //fprintf(stderr, "end %d\n", *(sp-1)); return; } /* *---------------------------------------------------------------------- * main -- * * Just call the testcases with timing. * *---------------------------------------------------------------------- */ int main() { timeit( switch_threading ); timeit( call_threading ); timeit( label_threading ); return 0; } ./nsf2.4.0/generic/nsfUtil.c000644 000766 000024 00000016205 13774057440 016413 0ustar00neumannstaff000000 000000 /* * nsfUtil.c -- * * Utility functions of the Next Scripting Framework. * * Copyright (C) 2001-2017 Gustaf Neumann * Copyright (C) 2001-2007 Uwe Zdun * * Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #include "nsfInt.h" /* *---------------------------------------------------------------------- * strnstr -- * * Implementation of strnstr() for platforms not providing it via their C * library. The function strnstr locates the first occurrence of a * substring in a null-terminated string. * * Results: * Strbstring or NULL * * Side effects: * None. * *---------------------------------------------------------------------- */ #ifndef HAVE_STRNSTR char * strnstr(const char *buffer, const char *needle, size_t buffer_len) { char *result = NULL; if (*needle == '\0') { result = (char *)buffer; } else { size_t remainder, needle_len; char *p; needle_len = strlen(needle); for (p = (char *)buffer, remainder = buffer_len; p != NULL; p = memchr(p + 1, *needle, remainder-1)) { remainder = buffer_len - (size_t)(p - buffer); if (remainder < needle_len) { break; } if (*p == *needle && strncmp(p, needle, needle_len) == 0) { result = p; break; } } } return result; } #endif /* *---------------------------------------------------------------------- * Nsf_ltoa -- * * Convert a long value into a string; this function is a fast * version of sprintf(buf, "%ld", l); * * Results: * String containing decimal value of the provided parameter. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * Nsf_ltoa(char *buf, long i, int *lengthPtr) { int nr_written, negative; char tmp[LONG_AS_STRING], *pointer = &tmp[1], *string, *p; nonnull_assert(buf != NULL); nonnull_assert(lengthPtr != NULL); tmp[0] = 0; if (i < 0) { i = -i; negative = nr_written = 1; } else { nr_written = negative = 0; } /* * Convert the binary value to a digit string in reversed order to the tmp * buffer since we do not know the length. */ do { nr_written++; *pointer++ = (char)((i % 10) + '0'); i /= 10; } while (i); p = string = buf; if (negative != 0) { *p++ = '-'; } /* * Copy number (reversed) from tmp to buf. */ while ((*p++ = *--pointer)) { ; } *lengthPtr = nr_written; return string; } /* *---------------------------------------------------------------------- * NsfStringIncr -- * * Increment a value on a number system with the provided alphabet. The * intention of the function is to generate compact new symbols. * * Results: * New symbol in form of a string. * * Side effects: * None. * *---------------------------------------------------------------------- */ static const char *alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; static size_t blockIncrement = 8u; /* static char *alphabet = "ab"; static int blockIncrement = 2; */ static unsigned char chartable[255] = {0}; char * NsfStringIncr(NsfStringIncrStruct *iss) { char newch, *currentChar; nonnull_assert(iss != NULL); currentChar = iss->buffer + iss->bufSize - 2; newch = *(alphabet + chartable[(unsigned)*currentChar]); while (1) { if (newch != '\0') { /* no overflow */ *currentChar = newch; break; } else { /* overflow */ *currentChar = *alphabet; /* use first char from alphabet */ currentChar--; assert(currentChar >= iss->buffer); newch = *(alphabet + chartable[(unsigned)*currentChar]); if (currentChar < iss->start) { iss->length++; if (currentChar == iss->buffer) { size_t newBufSize = iss->bufSize + blockIncrement; char *newBuffer = ckalloc((unsigned)newBufSize); currentChar = newBuffer+blockIncrement; /*memset(newBuffer, 0, blockIncrement);*/ memcpy(currentChar, iss->buffer, iss->bufSize); *currentChar = newch; iss->start = currentChar; ckfree(iss->buffer); iss->buffer = newBuffer; iss->bufSize = newBufSize; } else { iss->start = currentChar; } } } } assert(iss->buffer[iss->bufSize-1] == 0); assert(iss->buffer[iss->bufSize-2] != 0); assert(iss->length < iss->bufSize); assert(iss->start + iss->length + 1 == iss->buffer + iss->bufSize); return iss->start; } /* *---------------------------------------------------------------------- * NsfStringIncrInit, NsfStringIncrFree -- * * Support function for NsfStringIncr(). NsfStringIncrInit() function is * called before NsfStringIncr() can be used on this buffer, * NsfStringIncrFree() terminates usage. * * Results: * None. * * Side effects: * Initializes the . * *---------------------------------------------------------------------- */ void NsfStringIncrInit(NsfStringIncrStruct *iss) { const char *p; int i = 0; const size_t bufSize = blockIncrement; /* * The static variable blockIncrement is always large than 2, otherwise we * would have to use: * * const size_t bufSize = (blockIncrement > 2) ? blockIncrement : 2; */ nonnull_assert(iss != NULL); for (p=alphabet; *p != '\0'; p++) { chartable[(int)*p] = (unsigned char)(++i); } iss->buffer = ckalloc((unsigned)bufSize); memset(iss->buffer, 0, bufSize); iss->start = iss->buffer + bufSize-2; iss->bufSize = bufSize; iss->length = 1; /* for (i = 1; i < 50; i++) { NsfStringIncr(iss); fprintf(stderr, "string '%s' (%d)\n", iss->start, iss->length); } */ } void NsfStringIncrFree(NsfStringIncrStruct *iss) { nonnull_assert(iss != NULL); ckfree(iss->buffer); } /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * End: */ ./nsf2.4.0/generic/predefined_part1.tcl000644 000766 000024 00000014433 13773660660 020547 0ustar00neumannstaff000000 000000 # -*- Tcl -*- # # Define a basic set of predefined Tcl commands and definitions for # the Next Scripting Framework. This file will be transformed by # mk_predefined.tcl into "predefined.h", which in included in nsf.c. # # Copyright (C) 2009-2021 Gustaf Neumann # Copyright (C) 2010 Stefan Sobernig # # The predefined code has to be split into 2 parts due to a string # literal limitation in ISO C99, that requires compilers to support # only strings up to 4095 bytes. # # This is part 1. # namespace eval ::nsf { # # get frequenly used primitiva into the ::nsf namespace # # Symbols reused in the next scripting language namespace export \ next current self configure finalize interp is my relation dispatch namespace eval ::nsf::method::create {namespace export alias} # # support for method provide and method require # proc ::nsf::method::provide {require_name definition {script ""}} { set ::nsf::methodIndex($require_name) [list definition $definition script $script] } proc ::nsf::method::require {object name {per_object 0}} { # # On a method require, the optional script is evaluated and the # "definition" gets inserted # - on posiiton 1 the actual object # - on posiiton 2 optionally "-per-object" # # The definition cmd must return the method handle. # set key ::nsf::methodIndex($name) if {[info exists $key]} { array set "" [set $key] if {$(script) ne ""} { eval $(script) } if {$per_object} { set cmd [linsert $(definition) 1 -per-object] return [eval [linsert $cmd 1 $object]] } else { return [eval [linsert $(definition) 1 $object]] } } else { error "cannot require method $name for $object, method unknown" } } # # The following helper proc is used e.g. in OpenACS to pair # introspection with nsf::procs. # ::proc strip_proc_name {name} { if {[string match ::nsf::procs::* $name]} { return [string range $name 12 end] } elseif {[string match nsf::procs::* $name]} { return [string range $name 12 end] } else { return $name } } # # ::nsf::mixin # # Provide a similar interface as for ::nsf::method::create, ::nsf::method::alias, # etc.. Semantically, ::nsf::mixin behaves like a "mixin add", but # can be used as well for deleting the mixin list (empty last # argument). # ::nsf::proc ::nsf::mixin {object -per-object:switch classes} { set rel [expr {${per-object} ? "object-mixin" : "class-mixin"}] if {[lindex $classes 0] ne ""} { set oldSetting [::nsf::relation::get $object $rel] # use uplevel to avoid namespace surprises uplevel [list ::nsf::relation::set $object $rel [linsert $oldSetting 0 $classes]] } else { uplevel [list ::nsf::relation::set $object $rel ""] } } # # provide some popular methods for "method require" # ::nsf::method::provide autoname {::nsf::method::alias autoname ::nsf::methods::object::autoname} ::nsf::method::provide exists {::nsf::method::alias exists ::nsf::methods::object::exists} ::nsf::method::provide volatile {::nsf::method::alias volatile ::nsf::methods::object::volatile} ###################################################################### # unknown handler for objects and classes # proc ::nsf::object::unknown {name} { foreach {key handler} [array get ::nsf::object::unknown] { set result [uplevel [list {*}$handler $name]] if {$result ne ""} { return $result } } return "" } namespace eval ::nsf::object::unknown { proc add {key handler} {set ::nsf::object::unknown($key) $handler} proc get {key} {return $::nsf::object::unknown($key)} proc delete {key} {array unset ::nsf::object::unknown($key)} proc keys {} {array names ::nsf::object::unknown} } # Example unknown handler: # ::nsf::object::unknown::add xotcl {::xotcl::Class __unknown} namespace eval ::nsf::argument {} proc ::nsf::argument::unknown {args} { #puts stderr "??? ::nsf::argument::unknown <$args> [info frame -1]" return "" } ###################################################################### # exit handlers # proc ::nsf::exithandler {args} { lassign $args op value switch $op { set {::proc ::nsf::__exithandler {} $value} get {::info body ::nsf::__exithandler} unset {proc ::nsf::__exithandler args {;}} default {error "syntax: ::nsf::exithandler $::nsf::parameter::syntax(::nsf::exithandler)"} } } # initialize exit handler ::nsf::exithandler unset # # logger # if {[info command ::ns_log] ne ""} { proc ::nsf::log {level msg} { # The function might be called in situations in # aolserver/NaviServer, where ns_log is not available. if {[info command ::ns_log] ne ""} { ::ns_log $level "nsf: $msg" } else { puts stderr "$level: $msg" } } } else { proc ::nsf::log {level msg} { puts stderr "$level: $msg" } } # # debug::call and debug::exit command # namespace eval ::nsf::debug {} proc ::nsf::debug::call {level objectInfo methodInfo arglist} { nsf::log Debug "call($level) - $objectInfo $methodInfo $arglist" } proc ::nsf::debug::exit {level objectInfo methodInfo result usec} { nsf::log Debug "exit($level) - $objectInfo $methodInfo $usec usec -> $result" } # # deprecated command # proc ::nsf::deprecated {what oldCmd newCmd} { set msg "*** $what $oldCmd is deprecated." if {$newCmd ne ""} {append msg " use $newCmd instead."} #append msg "\n**\n" nsf::log Warning $msg } # # determine platform aware temp directory # proc tmpdir {} { foreach e [list TMPDIR TEMP TMP] { if {[info exists ::env($e)] \ && [file isdirectory $::env($e)] \ && [file writable $::env($e)]} { return $::env($e) } } if {$::tcl_platform(platform) eq "windows"} { foreach d [list "C:\\TEMP" "C:\\TMP" "\\TEMP" "\\TMP"] { if {[file isdirectory $d] && [file writable $d]} { return $d } } } return /tmp } namespace export tmpdir # if HOME is not set, and ~ is resolved, Tcl chokes on that if {![info exists ::env(HOME)]} {set ::env(HOME) /root} } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/generic/nsfPointer.c000644 000766 000024 00000026143 14271251043 017104 0ustar00neumannstaff000000 000000 /* * nsfPointer.c -- * * Provide API for accessing mallocated data via Tcl. * This is used e.g. via the MongoDB interface. * * Copyright (C) 2011-2017 Gustaf Neumann * * Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "nsfInt.h" static Tcl_HashTable pointerHashTable, *pointerHashTablePtr = &pointerHashTable; static int pointerTableRefCount = 0; static NsfMutex pointerMutex = 0; /* *---------------------------------------------------------------------- * * Nsf_PointerAdd -- * * Add an entry to our locally maintained hash table and set its * value to the provided valuePtr. The keys are generated based on * the passed type and the counter obtained from the type * registration. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_PointerAdd(Tcl_Interp *interp, char *buffer, size_t size, const char *typeName, void *valuePtr) { int *counterPtr; nonnull_assert(interp != NULL); nonnull_assert(buffer != NULL); nonnull_assert(typeName != NULL); nonnull_assert(valuePtr != NULL); counterPtr = Nsf_PointerTypeLookup(typeName); if (counterPtr != NULL) { Tcl_DString ds, *dsPtr = &ds; Tcl_HashEntry *hPtr; int isNew; Tcl_DStringInit(dsPtr); Tcl_DStringAppend(dsPtr, typeName, TCL_INDEX_NONE); Tcl_DStringAppend(dsPtr, ":%d", 3); NsfMutexLock(&pointerMutex); snprintf(buffer, size, Tcl_DStringValue(dsPtr), (*counterPtr)++); hPtr = Tcl_CreateHashEntry(pointerHashTablePtr, buffer, &isNew); NsfMutexUnlock(&pointerMutex); Tcl_SetHashValue(hPtr, valuePtr); /*fprintf(stderr, "Nsf_PointerAdd key '%s' prefix '%s' => %p value %p\n", buffer, typeName, hPtr, valuePtr);*/ Tcl_DStringFree(dsPtr); } else { return NsfPrintError(interp, "no type converter for %s registered", typeName); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Nsf_PointerGet -- * * Get an entry to our locally maintained hash table and make sure * that the prefix matches (this ensures that the right type of * entry is obtained). If the prefix does not match, or there is no * such entry in the table, the function returns NULL. * * Results: * valuePtr or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void * Nsf_PointerGet(char *key, const char *prefix) nonnull(1) nonnull(2); static void * Nsf_PointerGet(char *key, const char *prefix) { void *valuePtr = NULL; nonnull_assert(key != NULL); nonnull_assert(prefix != NULL); /* make sure to return the right type of hash entry */ if (strncmp(prefix, key, strlen(prefix)) == 0) { Tcl_HashEntry *hPtr; NsfMutexLock(&pointerMutex); hPtr = Tcl_CreateHashEntry(pointerHashTablePtr, key, NULL); if (hPtr != NULL) { valuePtr = Tcl_GetHashValue(hPtr); } NsfMutexUnlock(&pointerMutex); } return valuePtr; } /* *---------------------------------------------------------------------- * * Nsf_PointerGetHptr -- * * Find for a pointer the associated key for a valuePtr (reverse * lookup). The current implementation is quite slow in case there * are a high number of pointer values registered (which should not * be the case for the current usage patterns). It could certainly * be improved by a second hash table. The function should be run * under a callers mutex. * * Results: * key or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_HashEntry * Nsf_PointerGetHptr(const void *valuePtr) nonnull(1); static Tcl_HashEntry * Nsf_PointerGetHptr(const void *valuePtr) { Tcl_HashEntry *hPtr; Tcl_HashSearch hSrch; nonnull_assert(valuePtr != NULL); for (hPtr = Tcl_FirstHashEntry(pointerHashTablePtr, &hSrch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { void *ptr = Tcl_GetHashValue(hPtr); if (ptr == valuePtr) { return hPtr; } } return NULL; } /* *---------------------------------------------------------------------- * * Nsf_PointerDelete -- * * Delete a hash entry from the locally maintained hash table and * free the associated memory, if the hash entry is * found. Normally, the key should be provided. If the key is not * available, we perform a reverse lookup from the hash table. * * Results: * valuePtr or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_PointerDelete(const char *key, void *valuePtr, int free) { Tcl_HashEntry *hPtr; int result; nonnull_assert(valuePtr != NULL); NsfMutexLock(&pointerMutex); hPtr = (key != NULL) ? Tcl_CreateHashEntry(pointerHashTablePtr, key, NULL) : Nsf_PointerGetHptr(valuePtr); if (hPtr != NULL) { if (free != 0) { ckfree((char *)valuePtr); } Tcl_DeleteHashEntry(hPtr); result = TCL_OK; } else { result = TCL_ERROR; } NsfMutexUnlock(&pointerMutex); return result; } /* *---------------------------------------------------------------------- * Nsf_ConvertToPointer -- * * Nsf_TypeConverter setting the client data (passed to C functions) * to the valuePtr of the opaque structure. This nsf type converter * checks the passed value via the internally maintained pointer hash * table. * * Results: * Tcl result code, *clientData and **outObjPtr * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_ConvertToPointer(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(5); int Nsf_ConvertToPointer(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { void *valuePtr; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(clientData != NULL); nonnull_assert(outObjPtr != NULL); *outObjPtr = objPtr; valuePtr = Nsf_PointerGet(ObjStr(objPtr), pPtr->type); if (valuePtr != NULL) { *clientData = valuePtr; return TCL_OK; } return NsfObjErrType(interp, NULL, objPtr, pPtr->type, (Nsf_Param *)pPtr); } /* *---------------------------------------------------------------------- * Nsf_PointerTypeRegister -- * * Register a pointer type which is identified by the type string * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_PointerTypeRegister(Tcl_Interp *interp, const char* typeName, int *counterPtr) { Tcl_HashEntry *hPtr; int isNew; nonnull_assert(interp != NULL); nonnull_assert(typeName != NULL); nonnull_assert(counterPtr != NULL); NsfMutexLock(&pointerMutex); hPtr = Tcl_CreateHashEntry(pointerHashTablePtr, typeName, &isNew); NsfMutexUnlock(&pointerMutex); if (isNew != 0) { Tcl_SetHashValue(hPtr, counterPtr); return TCL_OK; } else { return NsfPrintError(interp, "type converter %s is already registered", typeName); } } /* *---------------------------------------------------------------------- * Nsf_PointerTypeLookup -- * * Lookup of type name. If the type name is registered, return the * converter or NULL otherwise. * * Results: * TypeConverter on success or NULL * * Side effects: * None. * *---------------------------------------------------------------------- */ void * Nsf_PointerTypeLookup(const char* typeName) { const Tcl_HashEntry *hPtr; nonnull_assert(typeName != NULL); NsfMutexLock(&pointerMutex); hPtr = Tcl_CreateHashEntry(pointerHashTablePtr, typeName, NULL); NsfMutexUnlock(&pointerMutex); if (hPtr != NULL) { return Tcl_GetHashValue(hPtr); } return NULL; } /* *---------------------------------------------------------------------- * Nsf_PointerInit -- * * Initialize the Pointer converter. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Nsf_PointerInit(void) { NsfMutexLock(&pointerMutex); if (pointerTableRefCount == 0) { Tcl_InitHashTable(pointerHashTablePtr, TCL_STRING_KEYS); } pointerTableRefCount++; /* fprintf(stderr, "Nsf_PointerInit pointerTableRefCount == %d\n", pointerTableRefCount);*/ NsfMutexUnlock(&pointerMutex); } /* *---------------------------------------------------------------------- * Nsf_PointerExit -- * * Exit handler for the Pointer converter * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Nsf_PointerExit(Tcl_Interp *interp) { nonnull_assert(interp != NULL); NsfMutexLock(&pointerMutex); if (--pointerTableRefCount == 0) { if (RUNTIME_STATE(interp)->logSeverity == NSF_LOG_DEBUG) { Tcl_HashSearch hSrch; const Tcl_HashEntry *hPtr; for (hPtr = Tcl_FirstHashEntry(pointerHashTablePtr, &hSrch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { const char *key = Tcl_GetHashKey(pointerHashTablePtr, hPtr); const void *valuePtr = Tcl_GetHashValue(hPtr); /* * We can't use NsfLog here any more, since the Tcl procs are * already deleted. */ fprintf(stderr, "Nsf_PointerExit: we have still an entry %s with value %p\n", key, valuePtr); } } Tcl_DeleteHashTable(pointerHashTablePtr); } /*fprintf(stderr, "Nsf_PointerExit pointerTableRefCount == %d\n", pointerTableRefCount);*/ NsfMutexUnlock(&pointerMutex); } /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * End: */ ./nsf2.4.0/generic/nsfObj.c000644 000766 000024 00000062445 14260302652 016204 0ustar00neumannstaff000000 000000 /* * nsfObj.c -- * * Tcl_Obj types provided by the Next Scripting Framework. * * Copyright (C) 1999-2017 Gustaf Neumann * Copyright (C) 2016 Stefan Sobernig * * Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #include "nsfInt.h" #include "nsfAccessInt.h" /* *---------------------------------------------------------------------- * * NsfMethodObjType Tcl_Obj type -- * * The NsfMethodObjType is a Tcl_Obj type carrying the result of * a method lookup. We define two types (NsfInstanceMethodObjType * and NsfObjectMethodObjType) sharing their implementation. The * type setting function NsfMethodObjSet() receives the intended * type. * *---------------------------------------------------------------------- */ static Tcl_FreeInternalRepProc MethodFreeInternalRep; static Tcl_DupInternalRepProc MethodDupInternalRep; Tcl_ObjType NsfInstanceMethodObjType = { "nsfInstanceMethod", /* name */ MethodFreeInternalRep, /* freeIntRepProc */ MethodDupInternalRep, /* dupIntRepProc */ NULL, /* updateStringProc */ NULL /* setFromAnyProc */ }; Tcl_ObjType NsfObjectMethodObjType = { "nsfObjectMethod", /* name */ MethodFreeInternalRep, /* freeIntRepProc */ MethodDupInternalRep, /* dupIntRepProc */ NULL, /* updateStringProc */ NULL /* setFromAnyProc */ }; /* *---------------------------------------------------------------------- * * MethodFreeInternalRep -- * * Frees internal representation. Implementation of * freeIntRepProc. * *---------------------------------------------------------------------- */ static void MethodFreeInternalRep( register Tcl_Obj *objPtr /* Tcl_Obj structure object with internal * representation to free. */ ) { NsfMethodContext *mcPtr = (NsfMethodContext *)objPtr->internalRep.twoPtrValue.ptr1; if (mcPtr != NULL) { #if defined(METHOD_OBJECT_TRACE) fprintf(stderr, "MethodFreeInternalRep %p methodContext %p methodEpoch %d type <%s>\n", (void*)objPtr, (void*)mcPtr, mcPtr->methodEpoch, (objPtr->typePtr != NULL) ? objPtr->typePtr->name : "none"); #endif /* * ... and free structure */ FREE(NsfMethodContext, mcPtr); objPtr->internalRep.twoPtrValue.ptr1 = NULL; objPtr->typePtr = NULL; } } /* *---------------------------------------------------------------------- * * MethodDupInternalRep -- * * Duplicates internal representation. Implementation of * dupIntRepProc. * *---------------------------------------------------------------------- */ static void MethodDupInternalRep( Tcl_Obj *srcObjPtr, Tcl_Obj *dstObjPtr ) { register NsfMethodContext *srcMcPtr = srcObjPtr->internalRep.twoPtrValue.ptr1, *dstMcPtr; #if defined(METHOD_OBJECT_TRACE) fprintf(stderr, "MethodDupInternalRep src %p dst %p\n", (void *)srcObjPtr, (void *)dstObjPtr); #endif dstMcPtr = NEW(NsfMethodContext); /*fprintf(stderr, "MethodDupInternalRep allocated NsfMethodContext %p for %s\n", dstMcPtr, ObjStr(srcObjPtr));*/ memcpy(dstMcPtr, srcMcPtr, sizeof(NsfMethodContext)); dstObjPtr->typePtr = srcObjPtr->typePtr; dstObjPtr->internalRep.twoPtrValue.ptr1 = dstMcPtr; } /* *---------------------------------------------------------------------- * * NsfMethodObjSet -- * * Converts the provided Tcl_Obj into the type of NsfMethodContext. * *---------------------------------------------------------------------- */ int NsfMethodObjSet( Tcl_Interp *UNUSED(interp), /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr, /* The object to convert. */ const Tcl_ObjType *objectType, void *context, /* context (to avoid over-eager sharing) */ unsigned int methodEpoch, /* methodEpoch */ Tcl_Command cmd, /* the Tcl command behind the method */ NsfClass *cl, /* the object/class where the method was defined */ unsigned int flags /* flags */ ) { NsfMethodContext *mcPtr; #if defined(METHOD_OBJECT_TRACE) fprintf(stderr, "... NsfMethodObjSet %p %s context %p methodEpoch %d " "cmd %p cl %p %s old obj type <%s> flags %.6x\n", (void *)objPtr, ObjStr(objPtr), context, methodEpoch, (void *)cmd, (void *)cl, (cl != NULL) ? ClassName(cl) : "obj", (objPtr->typePtr != NULL) ? objPtr->typePtr->name : "none", flags); #endif /* * Free or reuse the old internal representation and store own * structure as internal representation. */ if (objPtr->typePtr != objectType) { #if defined(METHOD_OBJECT_TRACE) fprintf(stderr, "... NsfMethodObjSet frees old int rep %s\n", (objPtr->typePtr != NULL) ? objPtr->typePtr->name : "none"); #endif TclFreeInternalRep(objPtr); mcPtr = NEW(NsfMethodContext); /*fprintf(stderr, "NsfMethodObjSet allocated NsfMethodContext %p for %s\n", mcPtr, ObjStr(objPtr));*/ objPtr->internalRep.twoPtrValue.ptr1 = (void *)mcPtr; objPtr->internalRep.twoPtrValue.ptr2 = NULL; objPtr->typePtr = objectType; #if defined(METHOD_OBJECT_TRACE) fprintf(stderr, "alloc %p methodContext %p methodEpoch %d type <%s> %s refCount %d\n", (void *)objPtr, (void *)mcPtr, methodEpoch, objectType->name, ObjStr(objPtr), objPtr->refCount); #endif } else { mcPtr = (NsfMethodContext *)objPtr->internalRep.twoPtrValue.ptr1; #if defined(METHOD_OBJECT_TRACE) fprintf(stderr, "... NsfMethodObjSet %p reuses internal rep, serial (%d/%d) refCount %d\n", (void *)objPtr, mcPtr->methodEpoch, methodEpoch, objPtr->refCount); #endif } assert(mcPtr != NULL); /* * add values to the structure */ mcPtr->context = context; mcPtr->methodEpoch = methodEpoch; mcPtr->cmd = cmd; mcPtr->cl = cl; mcPtr->flags = flags; return TCL_OK; } /* *---------------------------------------------------------------------- * * The NsfFlagObjType is a Tcl_Obj type carrying the result of a flag * lookup. * *---------------------------------------------------------------------- */ static Tcl_FreeInternalRepProc FlagFreeInternalRep; static Tcl_DupInternalRepProc FlagDupInternalRep; Tcl_ObjType NsfFlagObjType = { "nsfFlag", /* name */ FlagFreeInternalRep, /* freeIntRepProc */ FlagDupInternalRep, /* dupIntRepProc */ NULL, /* updateStringProc */ NULL /* setFromAnyProc */ }; /* *---------------------------------------------------------------------- * * FlagFreeInternalRep -- * * Frees internal representation. Implementation of * freeIntRepProc. * *---------------------------------------------------------------------- */ static void FlagFreeInternalRep( Tcl_Obj *objPtr /* Tcl_Obj structure object with internal * representation to free. */ ) { register NsfFlag *flagPtr = (NsfFlag *)objPtr->internalRep.twoPtrValue.ptr1; if (flagPtr != NULL) { /*fprintf(stderr, "FlagFreeInternalRep %p flagPtr %p serial (%d) payload %p\n", objPtr, flagPtr, flagPtr->serial, flagPtr->payload);*/ /* * Decrement refCounts; same as in NsfFlagSet() in the reuse branch */ if (flagPtr->payload != NULL) { DECR_REF_COUNT2("flagPtr->payload", flagPtr->payload); } /* * ... and free structure */ FREE(NsfFlag, flagPtr); objPtr->internalRep.twoPtrValue.ptr1 = NULL; } } /* *---------------------------------------------------------------------- * * FlagDupInternalRep -- * * Duplicates internal representation. Implementation of * dupIntRepProc. * *---------------------------------------------------------------------- */ static void FlagDupInternalRep( Tcl_Obj *srcObjPtr, Tcl_Obj *dstObjPtr ) { register NsfFlag *srcPtr = (NsfFlag *)srcObjPtr->internalRep.twoPtrValue.ptr1, *dstPtr; #if defined(METHOD_OBJECT_TRACE) fprintf(stderr, "FlagDupInternalRepx src %p dst %p\n", (void *)srcObjPtr,(void *)dstObjPtr); #endif dstPtr = NEW(NsfFlag); /*fprintf(stderr, "FlagDupInternalRep allocated NsfFlag %p for %s\n", dstPtr, ObjStr(srcObjPtr));*/ memcpy(dstPtr, srcPtr, sizeof(NsfFlag)); dstObjPtr->typePtr = srcObjPtr->typePtr; dstObjPtr->internalRep.twoPtrValue.ptr1 = dstPtr; } /* *---------------------------------------------------------------------- * * NsfFlagObjSet -- * * Convert the provided Tcl_Obj into the type of an NSF flag. * *---------------------------------------------------------------------- */ int NsfFlagObjSet( Tcl_Interp *UNUSED(interp), /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr, /* The object to convert. */ Nsf_Param const *baseParamPtr, /* the full parameter block */ int serial, /* interface serial */ Nsf_Param const *paramPtr, /* a single parameter */ Tcl_Obj *payload, /* payload */ unsigned int flags /* detail infos */ ) { NsfFlag *flagPtr; /*fprintf(stderr, "NsfFlagObjSet %p %s signature %p (%d) param %p payload %p flags %.4x\n", objPtr, ObjStr(objPtr), baseParamPtr, serial, paramPtr, payload, flags);*/ /* * Free or reuse the old internal representation and store own * structure as internal representation. */ if (objPtr->typePtr != &NsfFlagObjType) { TclFreeInternalRep(objPtr); flagPtr = NEW(NsfFlag); assert(flagPtr != NULL); /*fprintf(stderr, "NsfFlagObjSet allocated NsfFlag %p for %s\n", flagPtr, ObjStr(objPtr));*/ objPtr->internalRep.twoPtrValue.ptr1 = (void *)flagPtr; objPtr->internalRep.twoPtrValue.ptr2 = NULL; objPtr->typePtr = &NsfFlagObjType; } else { flagPtr = (NsfFlag *)objPtr->internalRep.twoPtrValue.ptr1; assert(flagPtr != NULL); /*fprintf(stderr, "NsfFlagObjSet %p reuses internal rep, serial (%d/%d)\n", objPtr, flagPtr->serial, serial);*/ if (flagPtr->payload != NULL) { DECR_REF_COUNT2("flagPtr->payload", flagPtr->payload); } } /* * add values to the structure */ flagPtr->signature = baseParamPtr; flagPtr->serial = serial; flagPtr->paramPtr = paramPtr; flagPtr->payload = payload; if (payload != NULL) {INCR_REF_COUNT2("flagPtr->payload", flagPtr->payload);} flagPtr->flags = flags; return TCL_OK; } /* *---------------------------------------------------------------------- * * Mixinreg Tcl_Obj type -- * * The mixin registration type is a Tcl_Obj type carrying a * class and a guard object. The string representation might have * the form "/cls/" or "/cls/ -guard /expr/". When no guard * expression is provided (first form), the guard entry is NULL. * *---------------------------------------------------------------------- */ typedef struct { NsfClass *mixin; Tcl_Obj *guardObj; } Mixinreg; static Tcl_FreeInternalRepProc MixinregFreeInternalRep; static Tcl_SetFromAnyProc MixinregSetFromAny; static Tcl_DupInternalRepProc MixinregDupInternalRep; Tcl_ObjType NsfMixinregObjType = { "nsfMixinreg", /* name */ MixinregFreeInternalRep, /* freeIntRepProc */ MixinregDupInternalRep, /* dupIntRepProc */ NULL, /* updateStringProc */ MixinregSetFromAny /* setFromAnyProc */ }; /* *---------------------------------------------------------------------- * * MixinregFreeInternalRep -- * * Frees internal representation. Implementation of * freeIntRepProc. * *---------------------------------------------------------------------- */ static void MixinregFreeInternalRep( register Tcl_Obj *objPtr /* Mixinreg structure object with internal * representation to free. */ ) { Mixinreg *mixinRegPtr = (Mixinreg *)objPtr->internalRep.twoPtrValue.ptr1; nonnull_assert(mixinRegPtr != NULL); /*fprintf(stderr, "MixinregFreeInternalRep freeing mixinReg %p class %p guard %p refcount before decr %d\n", mixinRegPtr, mixinRegPtr->mixin, mixinRegPtr->guardObj, (&(mixinRegPtr->mixin)->object)->refCount);*/ /* * Decrement refCounts */ NsfCleanupObject(&(mixinRegPtr->mixin)->object, "MixinregFreeInternalRep"); if (mixinRegPtr->guardObj != NULL) {DECR_REF_COUNT2("mixinRegPtr->guardObj", mixinRegPtr->guardObj);} /* * ... and free structure */ FREE(Mixinreg, mixinRegPtr); objPtr->internalRep.twoPtrValue.ptr1 = NULL; objPtr->typePtr = NULL; } /* *---------------------------------------------------------------------- * * MixinregDupInternalRep -- * * Duplicates internal representation. Implementation of * dupIntRepProc. * *---------------------------------------------------------------------- */ static void MixinregDupInternalRep( Tcl_Obj *srcObjPtr, Tcl_Obj *dstObjPtr ) { register Mixinreg *srcPtr = (Mixinreg *)srcObjPtr->internalRep.twoPtrValue.ptr1, *dstPtr; nonnull_assert(srcPtr != NULL); #if defined(METHOD_OBJECT_TRACE) fprintf(stderr, "MixinregDupInternalRep src %p dst %p\n", (void *)srcObjPtr, (void *)dstObjPtr); #endif dstPtr = NEW(Mixinreg); memcpy(dstPtr, srcPtr, sizeof(Mixinreg)); /* * Increment refcounts. */ NsfObjectRefCountIncr(&(srcPtr->mixin)->object); if (srcPtr->guardObj != NULL) { INCR_REF_COUNT2("mixinRegPtr->guardObj", srcPtr->guardObj); } /* * Update destination obj. */ dstObjPtr->typePtr = srcObjPtr->typePtr; dstObjPtr->internalRep.twoPtrValue.ptr1 = dstPtr; } /* *---------------------------------------------------------------------- * * MixinregSetFromAny -- * * Sets the type and internal representation when converting to * this object type. Implementation of setFromAnyProc. * *---------------------------------------------------------------------- */ static int MixinregSetFromAny( Tcl_Interp *interp, /* Used for error reporting if not NULL. */ Tcl_Obj *objPtr /* The object to convert. */ ) { NsfClass *mixin = NULL; int oc, result; Tcl_Obj **ov; result = Tcl_ListObjGetElements(interp, objPtr, &oc, &ov); if (likely(result == TCL_OK)) { Tcl_Obj *guardObj, *nameObj; /* * objPtr holds a valid Tcl list */ if (oc == 1) { nameObj = ov[0]; guardObj = NULL; } else if (oc == 3 && !strcmp(ObjStr(ov[1]), NsfGlobalStrings[NSF_GUARD_OPTION])) { nameObj = ov[0]; guardObj = ov[2]; } else { nameObj = objPtr; guardObj = NULL; } /* * Syntax was ok. Try to lookup mixin classes: */ if (NsfGetClassFromObj(interp, nameObj, &mixin, 1) != TCL_OK) { result = NsfObjErrType(interp, "mixin", nameObj, "a class as mixin", NULL); } else { Mixinreg *mixinRegPtr; assert(mixin != NULL); /* * Conversion was ok. * Allocate structure ... */ mixinRegPtr = NEW(Mixinreg); mixinRegPtr->mixin = mixin; mixinRegPtr->guardObj = guardObj; /* * ... and increment refCounts */ NsfObjectRefCountIncr((&mixin->object)); if (guardObj != NULL) {INCR_REF_COUNT2("mixinRegPtr->guardObj", guardObj);} /* * Build list of Tcl_Objs per mixin class for invalidation. */ { NsfClassOpt *clOpt = NsfRequireClassOpt(mixin); if (clOpt->mixinRegObjs == NULL) { clOpt->mixinRegObjs = Tcl_NewListObj(1, &objPtr); INCR_REF_COUNT2("mixinRegObjs", clOpt->mixinRegObjs); } else { Tcl_ListObjAppendElement(interp, clOpt->mixinRegObjs, objPtr); } } /*fprintf(stderr, "MixinregSetFromAny alloc mixinReg %p class %p guard %p object->refCount %d\n", mixinRegPtr, mixinRegPtr->mixin, mixinRegPtr->guardObj, ((&mixin->object)->refCount));*/ /* * Free the old internal representation and store own structure as internal * representation. */ TclFreeInternalRep(objPtr); objPtr->internalRep.twoPtrValue.ptr1 = (void *)mixinRegPtr; objPtr->internalRep.twoPtrValue.ptr2 = NULL; objPtr->typePtr = &NsfMixinregObjType; } } return result; } /* *---------------------------------------------------------------------- * * NsfMixinregGet -- * * Return the internal representation of a Mixinreg Tcl_Obj to * keep it local to this file. * * Results: * Tcl result code, arg two and three on success. * * Side effects: * None. * *---------------------------------------------------------------------- */ int NsfMixinregGet( Tcl_Interp *interp, Tcl_Obj *obj, NsfClass **classPtr, Tcl_Obj **guardObj ) { nonnull_assert(interp != NULL); nonnull_assert(obj != NULL); nonnull_assert(classPtr != NULL); nonnull_assert(guardObj != NULL); if (obj->typePtr == &NsfMixinregObjType) { Mixinreg *mixinRegPtr = obj->internalRep.twoPtrValue.ptr1; /* * We got a mixin with an included cmd, but both might have been deleted already. */ if ((mixinRegPtr->mixin->object.flags & NSF_DELETED) != 0u || TclIsCommandDeleted(mixinRegPtr->mixin->object.id)) { /* * The cmd is deleted. Try to refetch it. */ /*fprintf(stderr, "### we have to refetch internal rep of obj %p refCount %d\n", obj, obj->refCount);*/ if (MixinregSetFromAny(interp, obj) == TCL_OK) { mixinRegPtr = obj->internalRep.twoPtrValue.ptr1; } else { return TCL_ERROR; } } *guardObj = mixinRegPtr->guardObj; *classPtr = mixinRegPtr->mixin; return TCL_OK; } return TCL_ERROR; } /* *---------------------------------------------------------------------- * * NsfMixinregInvalidate -- * * MixinClasses keep a list of Tcl_Objs of type Mixinreg. * When a class is deleted, this call makes sure that * non-of these have the chance to point to a stale entry. * * Results: * A standard Tcl result. * * Side effects: * Freeing internal rep of Tcl_Objs. * *---------------------------------------------------------------------- */ int NsfMixinregInvalidate( Tcl_Interp *interp, Tcl_Obj *obj ) { int i, result, oc = 0; Tcl_Obj **objv; result = Tcl_ListObjGetElements(interp, obj, &oc, &objv); for (i= 0; i < oc; i++) { if (objv[i]->typePtr == &NsfMixinregObjType) { MixinregFreeInternalRep((objv[i])); } } return result; } /* *---------------------------------------------------------------------- * * Filterreg Tcl_Obj type -- * * The filter registration type is a Tcl_Obj type carrying the * name of a filter and a guard object. The string representation * might have the form "/filter/" or "/filter/ -guard * /expr/". When no guard expression is provided (first form), * the guard entry is NULL. The primary purpose of this converter * is to provide symmetry to Mixinregs and to provide meaningful * type names for introspection. * *---------------------------------------------------------------------- */ typedef struct { Tcl_Obj *filterObj; Tcl_Obj *guardObj; } Filterreg; static Tcl_FreeInternalRepProc FilterregFreeInternalRep; static Tcl_DupInternalRepProc FilterregDupInternalRep; static Tcl_SetFromAnyProc FilterregSetFromAny; Tcl_ObjType NsfFilterregObjType = { "nsfFilterreg", /* name */ FilterregFreeInternalRep, /* freeIntRepProc */ FilterregDupInternalRep, /* dupIntRepProc */ NULL, /* updateStringProc */ FilterregSetFromAny /* setFromAnyProc */ }; /* *---------------------------------------------------------------------- * * FilterregFreeInternalRep -- * * Frees internal representation. Implementation of * freeIntRepProc. * *---------------------------------------------------------------------- */ static void FilterregFreeInternalRep( register Tcl_Obj *objPtr /* Filterreg structure object with internal * representation to free. */ ) { Filterreg *filterregPtr = (Filterreg *)objPtr->internalRep.twoPtrValue.ptr1; nonnull_assert(filterregPtr != NULL); /*fprintf(stderr, "FilterregFreeInternalRep freeing filterreg %p class %p guard %p\n", filterregPtr, filterregPtr->class, filterregPtr->guardObj);*/ /* * Decrement refCounts */ DECR_REF_COUNT2("filterregPtr->filterObj", filterregPtr->filterObj); if (filterregPtr->guardObj != NULL) {DECR_REF_COUNT2("filterregPtr->guardObj", filterregPtr->guardObj);} /* * ... and free structure */ FREE(Filterreg, filterregPtr); objPtr->internalRep.twoPtrValue.ptr1 = NULL; objPtr->typePtr = NULL; } /* *---------------------------------------------------------------------- * * FilterregDupInternalRep -- * * Duplicates internal representation. Implementation of * dupIntRepProc. * *---------------------------------------------------------------------- */ static void FilterregDupInternalRep( Tcl_Obj *srcObjPtr, Tcl_Obj *dstObjPtr ) { register Filterreg *srcPtr, *dstPtr; assert(srcObjPtr != NULL); assert(dstObjPtr != NULL); srcPtr = (Filterreg *)srcObjPtr->internalRep.twoPtrValue.ptr1; assert(srcPtr != NULL); #if defined(METHOD_OBJECT_TRACE) fprintf(stderr, "FilterregDupInternalRep src %p dst %p\n", (void *)srcObjPtr, (void *)dstObjPtr); #endif dstPtr = NEW(Filterreg); memcpy(dstPtr, srcPtr, sizeof(Filterreg)); /* * Increment refcounts */ INCR_REF_COUNT2("filterregPtr->filterObj", srcPtr->filterObj); if (srcPtr->guardObj != NULL) {INCR_REF_COUNT2("FilterregPtr->guardObj", srcPtr->guardObj);} /* * Update destination Tcl_Obj. */ dstObjPtr->typePtr = srcObjPtr->typePtr; dstObjPtr->internalRep.twoPtrValue.ptr1 = dstPtr; } /* *---------------------------------------------------------------------- * * FilterregSetFromAny -- * * Sets the type and internal representation when converting to * this object type. Implementation of setFromAnyProc. * *---------------------------------------------------------------------- */ static int FilterregSetFromAny( Tcl_Interp *interp, /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr /* The object to convert. */ ) { Tcl_Obj *guardObj = NULL, *filterObj; Filterreg *filterregPtr; int oc; Tcl_Obj **ov; if (Tcl_ListObjGetElements(interp, objPtr, &oc, &ov) == TCL_OK) { if (oc == 1) { filterObj = ov[0]; /* } else if (oc == 2) { filterObj = ov[0]; guardObj = ov[1];*/ } else if (oc == 3 && !strcmp(ObjStr(ov[1]), NsfGlobalStrings[NSF_GUARD_OPTION])) { filterObj = ov[0]; guardObj = ov[2]; } else { return TCL_ERROR; } } else { return TCL_ERROR; } /* * Conversion was ok. * Allocate structure ... */ filterregPtr = NEW(Filterreg); filterregPtr->filterObj = filterObj; filterregPtr->guardObj = guardObj; /* * ... and increment refCounts */ INCR_REF_COUNT2("filterregPtr->filterObj", filterObj); if (guardObj != NULL) {INCR_REF_COUNT2("filterregPtr->guardObj", guardObj);} /*fprintf(stderr, "FilterregSetFromAny alloc filterreg %p class %p guard %p\n", filterregPtr, filterregPtr->filterObj, filterregPtr->guardObj);*/ /* * Free the old internal representation and store own structure as internal * representation. */ TclFreeInternalRep(objPtr); objPtr->internalRep.twoPtrValue.ptr1 = (void *)filterregPtr; objPtr->internalRep.twoPtrValue.ptr2 = NULL; objPtr->typePtr = &NsfFilterregObjType; return TCL_OK; } /* *---------------------------------------------------------------------- * * NsfFilterregGet -- * * Return the internal representation of a Filterreg Tcl_Obj to * keep it local to this file. * * Results: * Tcl result code, arg two and three on success. * * Side effects: * None. * *---------------------------------------------------------------------- */ int NsfFilterregGet( Tcl_Interp *UNUSED(interp), Tcl_Obj *obj, Tcl_Obj **filterObj, Tcl_Obj **guardObj ) { int result; nonnull_assert(obj != NULL); nonnull_assert(filterObj != NULL); nonnull_assert(guardObj != NULL); if (obj->typePtr == &NsfFilterregObjType) { Filterreg *filterregPtr = obj->internalRep.twoPtrValue.ptr1; *filterObj = filterregPtr->filterObj; *guardObj = filterregPtr->guardObj; result = TCL_OK; } else { result = TCL_ERROR; } return result; } /* * Filterreg type end */ /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * eval: (c-guess) * End: */ ./nsf2.4.0/generic/predefined.h000644 000766 000024 00000011547 13774072574 017112 0ustar00neumannstaff000000 000000 /* Generated by mk_predefined.tcl */ static char predefined_part1[] = "# -*- Tcl -*-\n" "namespace eval ::nsf {\n" "namespace export \\\n" "next current self configure finalize interp is my relation dispatch\n" "namespace eval ::nsf::method::create {namespace export alias}\n" "proc ::nsf::method::provide {require_name definition {script \"\"}} {\n" "set ::nsf::methodIndex($require_name) [list definition $definition script $script]}\n" "proc ::nsf::method::require {object name {per_object 0}} {\n" "set key ::nsf::methodIndex($name)\n" "if {[info exists $key]} {\n" "array set \"\" [set $key]\n" "if {$(script) ne \"\"} {\n" "eval $(script)}\n" "if {$per_object} {\n" "set cmd [linsert $(definition) 1 -per-object]\n" "return [eval [linsert $cmd 1 $object]]} else {\n" "return [eval [linsert $(definition) 1 $object]]}} else {\n" "error \"cannot require method $name for $object, method unknown\"}}\n" "::proc strip_proc_name {name} {\n" "if {[string match ::nsf::procs::* $name]} {\n" "return [string range $name 12 end]} elseif {[string match nsf::procs::* $name]} {\n" "return [string range $name 12 end]} else {\n" "return $name}}\n" "::nsf::proc ::nsf::mixin {object -per-object:switch classes} {\n" "set rel [expr {${per-object} ? \"object-mixin\" : \"class-mixin\"}]\n" "if {[lindex $classes 0] ne \"\"} {\n" "set oldSetting [::nsf::relation::get $object $rel]\n" "uplevel [list ::nsf::relation::set $object $rel [linsert $oldSetting 0 $classes]]} else {\n" "uplevel [list ::nsf::relation::set $object $rel \"\"]}}\n" "::nsf::method::provide autoname {::nsf::method::alias autoname ::nsf::methods::object::autoname}\n" "::nsf::method::provide exists {::nsf::method::alias exists ::nsf::methods::object::exists}\n" "::nsf::method::provide volatile {::nsf::method::alias volatile ::nsf::methods::object::volatile}\n" "proc ::nsf::object::unknown {name} {\n" "foreach {key handler} [array get ::nsf::object::unknown] {\n" "set result [uplevel [list {*}$handler $name]]\n" "if {$result ne \"\"} {\n" "return $result}}\n" "return \"\"}\n" "namespace eval ::nsf::object::unknown {\n" "proc add {key handler} {set ::nsf::object::unknown($key) $handler}\n" "proc get {key} {return $::nsf::object::unknown($key)}\n" "proc delete {key} {array unset ::nsf::object::unknown($key)}\n" "proc keys {} {array names ::nsf::object::unknown}}\n" "namespace eval ::nsf::argument {}\n" "proc ::nsf::argument::unknown {args} {\n" "return \"\"}\n" "proc ::nsf::exithandler {args} {\n" "lassign $args op value\n" "switch $op {\n" "set {::proc ::nsf::__exithandler {} $value}\n" "get {::info body ::nsf::__exithandler}\n" "unset {proc ::nsf::__exithandler args {;}}\n" "default {error \"syntax: ::nsf::exithandler $::nsf::parameter::syntax(::nsf::exithandler)\"}}}\n" "::nsf::exithandler unset\n" "if {[info command ::ns_log] ne \"\"} {\n" "proc ::nsf::log {level msg} {\n" "if {[info command ::ns_log] ne \"\"} {\n" "::ns_log $level \"nsf: $msg\"} else {\n" "puts stderr \"$level: $msg\"}}} else {\n" "proc ::nsf::log {level msg} {\n" "puts stderr \"$level: $msg\"}}\n" "namespace eval ::nsf::debug {}\n" "proc ::nsf::debug::call {level objectInfo methodInfo arglist} {\n" "nsf::log Debug \"call($level) - $objectInfo $methodInfo $arglist\"}\n" "proc ::nsf::debug::exit {level objectInfo methodInfo result usec} {\n" "nsf::log Debug \"exit($level) - $objectInfo $methodInfo $usec usec -> $result\"}\n" "proc ::nsf::deprecated {what oldCmd newCmd} {\n" "set msg \"*** $what $oldCmd is deprecated.\"\n" "if {$newCmd ne \"\"} {append msg \" use $newCmd instead.\"}\n" "nsf::log Warning $msg}\n" "proc tmpdir {} {\n" "foreach e [list TMPDIR TEMP TMP] {\n" "if {[info exists ::env($e)] \\\n" "&& [file isdirectory $::env($e)] \\\n" "&& [file writable $::env($e)]} {\n" "return $::env($e)}}\n" "if {$::tcl_platform(platform) eq \"windows\"} {\n" "foreach d [list \"C:\\\\TEMP\" \"C:\\\\TMP\" \"\\\\TEMP\" \"\\\\TMP\"] {\n" "if {[file isdirectory $d] && [file writable $d]} {\n" "return $d}}}\n" "return /tmp}\n" "namespace export tmpdir\n" "if {![info exists ::env(HOME)]} {set ::env(HOME) /root}}\n" ""; static char predefined_part2[] = "# -*- Tcl -*-\n" "namespace eval ::nsf {\n" "namespace eval ::nsf::parameter {}\n" "proc ::nsf::parameter::filter {defs pattern} {\n" "set result {}\n" "foreach def $defs {\n" "if {[string match $pattern [::nsf::parameter::info name $def]]} {\n" "lappend result $def}}\n" "return $result}\n" "set ::nsf::parameter::syntax(::nsf::xotclnext) \"?--noArgs? ?/arg .../?\"\n" "set ::nsf::parameter::syntax(::nsf::__unset_unknown_args) \"\"\n" "set ::nsf::parameter::syntax(::nsf::exithandler) \"?get?|?set /cmds/?|?unset?\"\n" "if {[info commands ::nsf::pkgconfig] ne \"\"} {\n" "foreach c {version commit patchLevel} {\n" "set ::nsf::$c [::nsf::pkgconfig get $c]}\n" "foreach c {development memcount memtrace profile dtrace assertions} {\n" "set ::nsf::config($c) [::nsf::pkgconfig get $c]}\n" "unset -nocomplain c}}\n" ""; ./nsf2.4.0/generic/predefined_part2.tcl000644 000766 000024 00000003032 13773660677 020551 0ustar00neumannstaff000000 000000 # -*- Tcl -*- # # Define a basic set of predefined Tcl commands and definitions for # the Next Scripting Framework. This file will be transformed by # mk_predefined.tcl into "predefined.h", which in included in nsf.c. # # Copyright (C) 2009-2021 Gustaf Neumann # Copyright (C) 2010 Stefan Sobernig # # The predefined code has to be split into 2 parts due to a string # literal limitation in ISO C99, that requires compilers to support # only strings up to 4095 bytes. # # This is part 2. # namespace eval ::nsf { # # parameter support # namespace eval ::nsf::parameter {} proc ::nsf::parameter::filter {defs pattern} { set result {} foreach def $defs { if {[string match $pattern [::nsf::parameter::info name $def]]} { lappend result $def } } return $result } set ::nsf::parameter::syntax(::nsf::xotclnext) "?--noArgs? ?/arg .../?" set ::nsf::parameter::syntax(::nsf::__unset_unknown_args) "" set ::nsf::parameter::syntax(::nsf::exithandler) "?get?|?set /cmds/?|?unset?" # # Provide the build-time configuration settings via namespaced # variables, for backward compatibility. # if {[info commands ::nsf::pkgconfig] ne ""} { foreach c {version commit patchLevel} { set ::nsf::$c [::nsf::pkgconfig get $c] } foreach c {development memcount memtrace profile dtrace assertions} { set ::nsf::config($c) [::nsf::pkgconfig get $c] } unset -nocomplain c } } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/generic/aolstub.c.ast.sh000644 000766 000024 00000000751 13543460715 017633 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.977f01.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/generic/aolstub.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/generic/aolstub.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/generic/aolstub.c.ast.bdump./nsf2.4.0/generic/nsfUtil.c.ast.sh000644 000766 000024 00000000751 13543460710 017601 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.3658ea.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfUtil.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/generic/nsfUtil.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfUtil.c.ast.bdump./nsf2.4.0/generic/nsfCompile.c000644 000766 000024 00000014226 13463617571 017071 0ustar00neumannstaff000000 000000 /* * nsfCompile.c -- * * Support for Bytecode in XOTcl/Nsf. This code was written for Tcl 8.4 * and required a small change for Tcl 8.4 (available from www.xotcl.org, * but not part of the Tcl Toolkit). This file was adopted only slightly * for naming changes etc., but requires more work to be revived. The * code is currently deactivated. * * Copyright (C) 2005-2015 Gustaf Neumann * * Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "nsfInt.h" #ifdef NSF_BYTECODE #include static CompileProc initProcNsCompile, nextCompile, selfCompile, selfDispatchCompile; static InstructionDesc instructionTable[] = { {"initProc", 1, 0, {OPERAND_NONE}}, {"next", 1, 0, {OPERAND_NONE}}, {"self", 1, 0, {OPERAND_NONE}}, {"dispatch", 2, 1, {OPERAND_UINT1}}, }; static NsfCompEnv instructions[] = { {0, 0, initProcNsCompile, NsfInitProcNSCmd}, {0, 0, nextCompile, NsfNextObjCmd}, {0, 0, selfCompile, NsfGetSelfObjCmd}, {0, 0, selfDispatchCompile, /*NsfSelfDispatchCmd*/NsfDirectSelfDispatch}, 0 }; NsfCompEnv * NsfGetCompEnv(void) { return &instructions[0]; } static int initProcNsCompile(Tcl_Interp *interp, Tcl_Parse *parsePtr, CompileEnv *envPtr) nonnull(1) nonnull(2) nonnull(3); static int initProcNsCompile(Tcl_Interp *interp, Tcl_Parse *parsePtr, CompileEnv *envPtr) { assert(interp != NULL); assert(parsePtr != NULL); assert(envPtr != NULL); if (parsePtr->numWords != 1) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "wrong # args: should be '::nsf::initProcNS'", -1); envPtr->maxStackDepth = 0; return TCL_ERROR; } TclEmitOpcode(instructions[INST_INITPROC].bytecode, envPtr); envPtr->maxStackDepth = 0; return TCL_OK; } static int nextCompile(Tcl_Interp *interp, Tcl_Parse *parsePtr, CompileEnv *envPtr) nonnull(1) nonnull(2) nonnull(3); static int nextCompile(Tcl_Interp *interp, Tcl_Parse *parsePtr, CompileEnv *envPtr) { assert(interp != NULL); assert(parsePtr != NULL); assert(envPtr != NULL); if (parsePtr->numWords != 1) { return TCL_OUT_LINE_COMPILE; } TclEmitOpcode(instructions[INST_NEXT].bytecode, envPtr); envPtr->maxStackDepth = 0; return TCL_OK; } static int selfCompile(Tcl_Interp *interp, Tcl_Parse *parsePtr, CompileEnv *envPtr) nonnull(1) nonnull(2) nonnull(3); static int selfCompile(Tcl_Interp *interp, Tcl_Parse *parsePtr, CompileEnv *envPtr) { assert(interp != NULL); assert(parsePtr != NULL); assert(envPtr != NULL); if (parsePtr->numWords != 1) { return TCL_OUT_LINE_COMPILE; } TclEmitOpcode(instructions[INST_SELF].bytecode, envPtr); envPtr->maxStackDepth = 0; return TCL_OK; } static int selfDispatchCompile(Tcl_Interp *interp, Tcl_Parse *parsePtr, CompileEnv *envPtr) nonnull(1) nonnull(2) nonnull(3); static int selfDispatchCompile(Tcl_Interp *interp, Tcl_Parse *parsePtr, CompileEnv *envPtr) { Tcl_Token *tokenPtr; int code, wordIdx; assert(interp != NULL); assert(parsePtr != NULL); assert(envPtr != NULL); /* fprintf(stderr, "****** selfDispatchCompile words=%d tokens=%d, avail=%d\n", parsePtr->numWords, parsePtr->numTokens, parsePtr->tokensAvailable); */ if (parsePtr->numWords > 255) { return TCL_OUT_LINE_COMPILE; } /*TclEmitOpcode(instructions[INST_SELF].bytecode, envPtr);*/ for (wordIdx=0, tokenPtr = parsePtr->tokenPtr + 0; wordIdx < parsePtr->numWords; wordIdx++, tokenPtr += (tokenPtr->numComponents + 1)) { /* fprintf(stderr, " %d: %p token type=%d size=%d\n", wordIdx, tokenPtr, tokenPtr->type, tokenPtr->size ); */ if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { TclEmitPush(TclRegisterLiteral(envPtr, tokenPtr->start, tokenPtr->size, 0), envPtr); envPtr->maxStackDepth = 1; /* fprintf(stderr, " %d: simple '%s' components=%d\n", wordIdx, tokenPtr->start, tokenPtr->numComponents); */ } else { /* fprintf(stderr, " %d NOT simple '%s' components=%d\n", wordIdx, tokenPtr->start, tokenPtr->numComponents); */ code = TclCompileTokens(interp, tokenPtr+1, tokenPtr->numComponents, envPtr); if (code != TCL_OK) { return code; } } } /*fprintf(stderr, "maxdepth=%d, onStack=%d\n", envPtr->maxStackDepth, wordIdx); */ TclEmitInstInt1(instructions[INST_SELF_DISPATCH].bytecode, wordIdx, envPtr); envPtr->maxStackDepth = 0; return TCL_OK; } void NsfBytecodeInit(void) { int i; for(i=0; iobjClientData))) { instructions[i].cmdPtr->compileProc = instructions[i].compileProc; } } /*tclTraceCompile = 2;*/ } #endif /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * End: */ ./nsf2.4.0/generic/nsfProfile.c.ast.sh000644 000766 000024 00000000762 13543460707 020274 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.710d58.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfProfile.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/generic/nsfProfile.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfProfile.c.ast.bdump./nsf2.4.0/generic/nsf.h000644 000766 000024 00000036204 14275240432 015553 0ustar00neumannstaff000000 000000 /* * Next Scripting Framework * * Copyright (C) 1999-2021 Gustaf Neumann (a) (b) * Copyright (C) 1999-2007 Uwe Zdun (a) (b) * Copyright (C) 2007-2008 Martin Matuska (b) * Copyright (C) 2010-2017 Stefan Sobernig (b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1090, Augasse 2-6 * Vienna, Austria * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #ifndef NSF_INCLUDED_nsf_h_ #define NSF_INCLUDED_nsf_h_ #include "tcl.h" #undef TCL_STORAGE_CLASS #ifdef BUILD_nsf # define TCL_STORAGE_CLASS DLLEXPORT #else # ifdef USE_NSF_STUBS # define TCL_STORAGE_CLASS # else # define TCL_STORAGE_CLASS DLLIMPORT # endif #endif /* * prevent old TCL-versions */ #if TCL_MAJOR_VERSION < 8 # error Tcl distribution is TOO OLD, we require at least tcl8.5 #endif #if TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION<5 # error Tcl distribution is TOO OLD, we require at least tcl8.5 #endif #if TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION<6 # define PRE86 #endif #if TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION<7 # define PRE87 #endif #if TCL_MAJOR_VERSION==8 # define PRE9 #endif #if defined(PRE86) # define Tcl_GetErrorLine(interp) (interp)->errorLine #else # define NRE #endif #ifdef PRE9 # if !defined(Tcl_LibraryInitProc) # define Tcl_LibraryInitProc Tcl_PackageInitProc # endif # if !defined(Tcl_GetChild) # define Tcl_GetChild Tcl_GetSlave # define Tcl_GetParent Tcl_GetMaster # endif #endif #ifdef PRE9 # define TCL_SIZE_T int #else # define TCL_SIZE_T size_t #endif #ifndef TCL_INDEX_NONE # define TCL_INDEX_NONE -1 #endif /* * Feature activation/deactivation */ /* * The following features are controlled via * configure flags * * --with-dtrace * --enable-development * --enable-profile * --enable-memcount=yes|trace * --enable-assertions * * Are we developing? * #define NSF_DEVELOPMENT 1 * * Activate/deactivate profiling information * #define NSF_PROFILE 1 * * Compile with dtrace support * #define NSF_DTRACE 1 * * Scripting level assertions * #define NSF_WITH_ASSERTIONS 1 * * Activate/deactivate memory tracing * #define NSF_MEM_TRACE 1 #define NSF_MEM_COUNT 1 * * Activate/deactivate valgrind support * #define NSF_VALGRIND 1 */ /* Activate bytecode support #define NSF_BYTECODE */ /* Activate/deactivate C-level assert() Activated automatically when NSF_DEVELOPMENT is set #define NDEBUG 1 */ /* Experimental language feature #define NSF_WITH_INHERIT_NAMESPACES 1 #define NSF_WITH_TCL_OBJ_TYPES_AS_CONVERTER 1 */ #define NSF_WITH_OS_RESOLVER 1 #define NSF_WITH_VALUE_WARNINGS 1 /* turn tracing output on/off #define NSFOBJ_TRACE 1 #define NAMESPACE_TRACE 1 #define OBJDELETION_TRACE 1 #define STACK_TRACE 1 #define PARSE_TRACE 1 #define PARSE_TRACE_FULL 1 #define CONFIGURE_ARGS_TRACE 1 #define TCL_STACK_ALLOC_TRACE 1 #define VAR_RESOLVER_TRACE 1 #define CMD_RESOLVER_TRACE 1 #define NRE_CALLBACK_TRACE 1 #define METHOD_OBJECT_TRACE 1 #define NSF_LINEARIZER_TRACE 1 #define NSF_STACKCHECK 1 #define NSF_CLASSLIST_PRINT 1 #define NSF_PRINT_OBJV 1 */ #define PER_OBJECT_PARAMETER_CACHING 1 /* * Sanity checks and dependencies for optional compile flags */ #if defined(PARSE_TRACE_FULL) # define PARSE_TRACE 1 #endif #ifdef NSF_MEM_COUNT # define DO_FULL_CLEANUP 1 #endif #ifdef AOL_SERVER # ifndef TCL_THREADS # define TCL_THREADS # endif #endif #ifdef TCL_THREADS # define DO_CLEANUP #endif #ifdef DO_FULL_CLEANUP # define DO_CLEANUP #endif #ifdef NSF_LINEARIZER_TRACE # if !defined(NSF_CLASSLIST_PRINT) # define NSF_CLASSLIST_PRINT 1 # endif #endif #ifdef NSF_DTRACE # define NSF_DTRACE_METHOD_RETURN_PROBE(cscPtr,retCode) \ if (cscPtr->cmdPtr && NSF_DTRACE_METHOD_RETURN_ENABLED()) { \ NSF_DTRACE_METHOD_RETURN(ObjectName((cscPtr)->self), \ (cscPtr)->cl ? ClassName((cscPtr)->cl) : ObjectName((cscPtr)->self), \ (char *)(cscPtr)->methodName, \ (retCode)); \ } #else # define NSF_DTRACE_METHOD_RETURN_PROBE(cscPtr,retCode) {} #endif /* * When intense developent is activated, make sure that also the base * level development mode is activated. */ #if defined(NSF_DEVELOPMENT_TEST) && !defined(NSF_DEVELOPMENT) # define NSF_DEVELOPMENT 1 #endif #ifdef NSF_DEVELOPMENT /* * The activation counts checking is best performed via the MEM_COUNT * macros. In case, the MEM_COUNT macros indicate a problem, setting * CHECK_ACTIVATION_COUNTS might help to locate the problem more * precisely. The CHECK_ACTIVATION_COUNTS tester might however still * report false positives. */ /*# define CHECK_ACTIVATION_COUNTS 1*/ # define NsfCleanupObject(object,string) \ /*fprintf(stderr, "NsfCleanupObject %p %s\n",object,string);*/ \ NsfCleanupObject_((object)) # define CscFinish(interp,cscPtr,retCode,string) \ /*fprintf(stderr, "CscFinish %p %s\n",cscPtr,string); */ \ NSF_DTRACE_METHOD_RETURN_PROBE((cscPtr),(retCode)); \ CscFinish_((interp), (cscPtr)) #else # define NsfCleanupObject(object,string) \ NsfCleanupObject_((object)) # define CscFinish(interp,cscPtr,retCode,string) \ NSF_DTRACE_METHOD_RETURN_PROBE(cscPtr,retCode); \ CscFinish_((interp), (cscPtr)) #endif #if defined(NSF_MEM_TRACE) && !defined(NSF_MEM_COUNT) # define NSF_MEM_COUNT 1 #endif /* if ((cmd) != NULL) {fprintf(stderr, "METHOD %s cmd %p flags %.8x (%.8x)\n", (method), (cmd), Tcl_Command_flags((cmd)), NSF_CMD_DEPRECATED_METHOD);} */ #if defined(NSF_PROFILE) # define CscInit(cscPtr, object, cl, cmd, frametype, flags, method) \ CscInit_((cscPtr), (object), (cl), (cmd), (frametype), (flags)); (cscPtr)->methodName = (method); \ NsfProfileTraceCall((interp), (object), (cl), (method)); #else # if defined(NSF_DTRACE) # define CscInit(cscPtr, object, cl, cmd, frametype, flags, method) \ CscInit_((cscPtr), (object), (cl), (cmd), (frametype), (flags)); (cscPtr)->methodName = (method); # else # define CscInit(cscPtr, object, cl, cmd, frametype, flags, methodName) \ CscInit_((cscPtr), (object), (cl), (cmd), (frametype), (flags)) # endif #endif #if !defined(CHECK_ACTIVATION_COUNTS) # define CscListAdd(interp, cscPtr) # define CscListRemove(interp, cscPtr, cscListPtr) #endif #if defined(TCL_THREADS) # define NsfMutex Tcl_Mutex # define NsfMutexLock(a) Tcl_MutexLock((a)) # define NsfMutexUnlock(a) Tcl_MutexUnlock((a)) #else # define NsfMutex int # define NsfMutexLock(a) (*(a))++ # define NsfMutexUnlock(a) (*(a))-- #endif /* * A special definition used to allow this header file to be included * in resource files so that they can get obtain version information from * this file. Resource compilers don't like all the C stuff, like typedefs * and procedure declarations, that occur below. */ #ifndef RC_INVOKED /* * The structures Nsf_Object and Nsf_Class define mostly opaque * data structures for the internal use structures NsfObject and * NsfClass (both defined in NsfInt.h). Modification of elements * visible elements must be mirrored in both incarnations. * * Warning: These structures are just containing a few public * fields. These structures must not be used for querying the size or * allocating the data structures. */ typedef struct Nsf_Object { Tcl_Obj *cmdName; } Nsf_Object; typedef struct Nsf_Class { struct Nsf_Object object; } Nsf_Class; typedef struct Nsf_ParseContext { ClientData *clientData; int status; } Nsf_ParseContext; struct Nsf_Param; typedef int (Nsf_TypeConverter)(Tcl_Interp *interp, Tcl_Obj *obj, struct Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); typedef struct { Nsf_TypeConverter *converter; const char *domain; } Nsf_EnumeratorConverterEntry; typedef struct Nsf_ObjvTable { const char *key; unsigned int value; } Nsf_ObjvTable; EXTERN Nsf_TypeConverter Nsf_ConvertToBoolean, Nsf_ConvertToClass, Nsf_ConvertToInteger, Nsf_ConvertToInt32, Nsf_ConvertToObject, Nsf_ConvertToParameter, Nsf_ConvertToString, Nsf_ConvertToSwitch, Nsf_ConvertToTclobj, Nsf_ConvertToPointer; typedef struct Nsf_Param { const char *name; unsigned int flags; int nrArgs; Nsf_TypeConverter *converter; Tcl_Obj *converterArg; Tcl_Obj *defaultValue; const char *type; Tcl_Obj *nameObj; Tcl_Obj *converterName; Tcl_Obj *paramObj; Tcl_Obj *slotObj; Tcl_Obj *method; } Nsf_Param; /* Argument parse processing flags */ #define NSF_ARGPARSE_CHECK 0x0001 #define NSF_ARGPARSE_FORCE_REQUIRED 0x0002 #define NSF_ARGPARSE_BUILTIN (NSF_ARGPARSE_CHECK|NSF_ARGPARSE_FORCE_REQUIRED) #define NSF_ARGPARSE_START_ZERO 0x0010 /* Special flags for process method arguments */ #define NSF_ARGPARSE_METHOD_PUSH 0x0100 /* flags for NsfParams */ #define NSF_ARG_REQUIRED 0x00000001u #define NSF_ARG_MULTIVALUED 0x00000002u #define NSF_ARG_NOARG 0x00000004u #define NSF_ARG_NOCONFIG 0x00000008u #define NSF_ARG_CURRENTLY_UNKNOWN 0x00000010u #define NSF_ARG_SUBST_DEFAULT 0x00000020u #define NSF_ARG_ALLOW_EMPTY 0x00000040u #define NSF_ARG_INITCMD 0x00000080u #define NSF_ARG_CMD 0x00000100u #define NSF_ARG_ALIAS 0x00000200u #define NSF_ARG_FORWARD 0x00000400u #define NSF_ARG_SWITCH 0x00000800u #define NSF_ARG_BASECLASS 0x00001000u #define NSF_ARG_METACLASS 0x00002000u #define NSF_ARG_HAS_DEFAULT 0x00004000u #define NSF_ARG_IS_CONVERTER 0x00008000u #define NSF_ARG_IS_ENUMERATION 0x00010000u #define NSF_ARG_CHECK_NONPOS 0x00020000u #define NSF_ARG_SET 0x00040000u #define NSF_ARG_WARN 0x00080000u #define NSF_ARG_UNNAMED 0x00100000u #define NSF_ARG_IS_RETURNVALUE 0x00200000u #define NSF_ARG_NODASHALNUM 0x00400000u #define NSF_ARG_SLOTSET 0x00800000u #define NSF_ARG_SLOTINITIALIZE 0x01000000u #define NSF_ARG_SUBST_DEFAULT_COMMANDS 0x10000000u #define NSF_ARG_SUBST_DEFAULT_VARIABLES 0x20000000u #define NSF_ARG_SUBST_DEFAULT_BACKSLASHES 0x40000000u #define NSF_ARG_SUBST_DEFAULT_ALL 0x70000000u #if defined __GNUC__ && defined __GNUC_MINOR__ # define NSF__GNUC_PREREQ(maj, min) \ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) #else # define NSF__GNUC_PREREQ(maj, min) (0) #endif #if NSF__GNUC_PREREQ(3, 3) # define NSF_nonnull(ARGS) __attribute__((__nonnull__(ARGS))) #else # define NSF_nonnull(ARGS) #endif #if NSF__GNUC_PREREQ(6, 0) # define NSF_nonnull_assert(assertion) #else # define NSF_nonnull_assert(assertion) assert((assertion)) #endif #if NSF__GNUC_PREREQ(2, 96) # define NSF_pure __attribute__((pure)) #else # define NSF_pure #endif /* * Unfortunately, we can't combine NSF_attribute_format() with * functions called via stubs. */ #if NSF__GNUC_PREREQ(3, 4) # define NSF_attribute_format(ARGS) __attribute__((__format__ ARGS)) #else # define NSF_attribute_format(ARGS) #endif #if NSF__GNUC_PREREQ(7, 0) # define NSF_FALL_THROUGH __attribute__((fallthrough)) #else # define NSF_FALL_THROUGH ((void)0) #endif /* EXTERN int NsfArgumentError(Tcl_Interp *interp, const char *errorMsg, Nsf_Param const *paramPtr, Tcl_Obj *cmdNameObj, Tcl_Obj *methodPathObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); */ EXTERN int NsfDispatchClientDataError(Tcl_Interp *interp, ClientData clientData, const char *what, const char *methodName) NSF_nonnull(1) NSF_nonnull(3) NSF_nonnull(4); EXTERN int NsfNoCurrentObjectError(Tcl_Interp *interp, const char *methodName) NSF_nonnull(1); EXTERN int NsfUnexpectedArgumentError(Tcl_Interp *interp, const char *argumentString, Nsf_Object *object, Nsf_Param const *paramPtr, Tcl_Obj *methodPathObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4) NSF_nonnull(5); EXTERN int NsfUnexpectedNonposArgumentError(Tcl_Interp *interp, const char *argumentString, Nsf_Object *object, Nsf_Param const *currentParamPtr, Nsf_Param const *paramPtr, Tcl_Obj *methodPathObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4) NSF_nonnull(5) NSF_nonnull(6); /* * logging severities */ #define NSF_LOG_ERROR 3 #define NSF_LOG_WARN 2 #define NSF_LOG_NOTICE 1 #define NSF_LOG_DEBUG 0 EXTERN void NsfLog(Tcl_Interp *interp, int requiredLevel, const char *fmt, ...) NSF_nonnull(1) NSF_nonnull(3) NSF_attribute_format((printf,3,4)); /* * Nsf Pointer converter interface */ EXTERN int Nsf_PointerAdd(Tcl_Interp *interp, char *buffer, size_t size, const char *typeName, void *valuePtr) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4) NSF_nonnull(5); EXTERN int Nsf_PointerDelete(const char *key, void *valuePtr, int free) NSF_nonnull(2); EXTERN void Nsf_PointerInit(void); EXTERN void Nsf_PointerExit(Tcl_Interp *interp) NSF_nonnull(1); EXTERN void *Nsf_PointerTypeLookup(const char* typeName) NSF_nonnull(1); EXTERN int Nsf_PointerTypeRegister(Tcl_Interp *interp, const char* typeName, int *counterPtr) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); /* * methodDefinition */ typedef struct Nsf_methodDefinition { const char *methodName; Tcl_ObjCmdProc *proc; int nrParameters; Nsf_Param paramDefs[12]; } Nsf_methodDefinition; /* * Nsf Enumeration type interface */ #if 0 EXTERN int Nsf_EnumerationTypeRegister(Tcl_Interp *interp, Nsf_EnumeratorConverterEntry *typeRecords) NSF_nonnull(1) NSF_nonnull(2); /* * Nsf Cmd definition interface */ EXTERN int Nsf_CmdDefinitionRegister(Tcl_Interp *interp, Nsf_methodDefinition *definitionRecords) NSF_nonnull(1) NSF_nonnull(2); #endif /* * Include the public function declarations that are accessible via * the stubs table. */ #if defined(NRE) # if defined(PRE9) # include "stubs8.6/nsfDecls.h" # else # include "stubs9.0/nsfDecls.h" # endif #else # include "stubs8.5/nsfDecls.h" #endif /* * Nsf_InitStubs is used by extensions that can be linked * against the nsf stubs library. If we are not using stubs * then this reduces to package require. */ #ifdef USE_NSF_STUBS # ifdef __cplusplus EXTERN "C" # endif const char * Nsf_InitStubs(Tcl_Interp *interp, const char *version, int exact); #else # define Nsf_InitStubs(interp, version, exact) \ Tcl_PkgRequire(interp, "nx", version, exact) #endif #endif /* RC_INVOKED */ /* #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT */ #endif /* NSF_INCLUDED_nsf_h_ */ ./nsf2.4.0/generic/stubs9.0/nsfStubInit.c000644 000766 000024 00000007270 14260520102 020605 0ustar00neumannstaff000000 000000 /* * nsfStubInit.c -- * * This file contains the initializers for the stub vectors of the Next * Scripting Framework. * * Copyright (C) 1999-2014 Gustaf Neumann (a, b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #include "nsfInt.h" /* * Remove macros that will interfere with the definitions below. */ /* * WARNING: The contents of this file is automatically generated by the * tools/genStubs.tcl script. Any modifications to the function declarations * below should be made in the generic/tcl.decls script. */ #if defined(PRE86) EXTERN NsfStubs nsfStubs; # else MODULE_SCOPE const NsfStubs nsfStubs; #endif /* !BEGIN!: Do not edit below this line. */ static const NsfIntStubs nsfIntStubs = { TCL_STUB_MAGIC, 0, }; static const NsfStubHooks nsfStubHooks = { &nsfIntStubs }; const NsfStubs nsfStubs = { TCL_STUB_MAGIC, &nsfStubHooks, Nsf_Init, /* 0 */ 0, /* 1 */ NsfIsClass, /* 2 */ NsfGetObject, /* 3 */ NsfGetClass, /* 4 */ NsfDeleteObject, /* 5 */ NsfRemoveObjectMethod, /* 6 */ NsfRemoveClassMethod, /* 7 */ Nsf_ObjSetVar2, /* 8 */ Nsf_ObjGetVar2, /* 9 */ Nsf_UnsetVar2, /* 10 */ NsfDStringVPrintf, /* 11 */ NsfPrintError, /* 12 */ NsfErrInProc, /* 13 */ NsfObjErrType, /* 14 */ NsfStackDump, /* 15 */ NsfSetObjClientData, /* 16 */ NsfGetObjClientData, /* 17 */ NsfSetClassClientData, /* 18 */ NsfGetClassClientData, /* 19 */ NsfRequireObjNamespace, /* 20 */ NsfCallMethodWithArgs, /* 21 */ NsfAddObjectMethod, /* 22 */ NsfAddClassMethod, /* 23 */ NsfCreate, /* 24 */ Nsf_ArgumentParse, /* 25 */ NsfLog, /* 26 */ Nsf_PointerAdd, /* 27 */ Nsf_PointerDelete, /* 28 */ Nsf_PointerTypeRegister, /* 29 */ Nsf_ConvertToBoolean, /* 30 */ Nsf_ConvertToClass, /* 31 */ Nsf_ConvertToInt32, /* 32 */ Nsf_ConvertToInteger, /* 33 */ Nsf_ConvertToObject, /* 34 */ Nsf_ConvertToPointer, /* 35 */ Nsf_ConvertToString, /* 36 */ Nsf_ConvertToTclobj, /* 37 */ Nsf_EnumerationTypeRegister, /* 38 */ Nsf_CmdDefinitionRegister, /* 39 */ NsfArgumentError, /* 40 */ Nsf_DStringPrintf, /* 41 */ }; /* !END!: Do not edit above this line. */ /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * End: */ ./nsf2.4.0/generic/stubs9.0/nsfDecls.h000644 000766 000024 00000036504 14260520102 020105 0ustar00neumannstaff000000 000000 /* * nsfDecls.h -- * * Declarations of functions in the platform independent public Nsf API. * * This file is part of the Next Scripting Framework. * * Copyright (C) 1999-2014 Gustaf Neumann (a, b) * Copyright (C) 1999-2007 Uwe Zdun (a, b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1090, Augasse 2-6 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #ifndef NSF_INCLUDED_NSFDECLS #define NSF_INCLUDED_NSFDECLS /* * WARNING: This file is automatically generated by the tools/genStubs.tcl * script. Any modifications to the function declarations below should be made * in the nsf.decls script. */ /* !BEGIN!: Do not edit below this line. */ #ifdef __cplusplus extern "C" { #endif /* * Exported function declarations: */ /* 0 */ EXTERN int Nsf_Init(Tcl_Interp *interp); /* Slot 1 is reserved */ /* 2 */ EXTERN struct Nsf_Class * NsfIsClass(Tcl_Interp *interp, ClientData cd); /* 3 */ EXTERN struct Nsf_Object * NsfGetObject(Tcl_Interp *interp, const char *name); /* 4 */ EXTERN struct Nsf_Class * NsfGetClass(Tcl_Interp *interp, const char *name); /* 5 */ EXTERN int NsfDeleteObject(Tcl_Interp *interp, struct Nsf_Object *object); /* 6 */ EXTERN int NsfRemoveObjectMethod(Tcl_Interp *interp, struct Nsf_Object *object, const char *methodName); /* 7 */ EXTERN int NsfRemoveClassMethod(Tcl_Interp *interp, struct Nsf_Class *class, const char *methodName); /* 8 */ EXTERN Tcl_Obj * Nsf_ObjSetVar2(struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, Tcl_Obj *valueObj, unsigned int flags); /* 9 */ EXTERN Tcl_Obj * Nsf_ObjGetVar2(struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, unsigned int flags); /* 10 */ EXTERN int Nsf_UnsetVar2(struct Nsf_Object *object, Tcl_Interp *interp, const char *name1, const char *name2, unsigned int flags); /* 11 */ EXTERN void NsfDStringVPrintf(Tcl_DString *dsPtr, const char *fmt, va_list argPtr); /* 12 */ EXTERN int NsfPrintError(Tcl_Interp *interp, const char *fmt, ...); /* 13 */ EXTERN int NsfErrInProc(Tcl_Interp *interp, Tcl_Obj *objName, Tcl_Obj *clName, const char *procName); /* 14 */ EXTERN int NsfObjErrType(Tcl_Interp *interp, const char *context, Tcl_Obj *value, const char *type, Nsf_Param const *NsfObjErrType); /* 15 */ EXTERN void NsfStackDump(Tcl_Interp *interp); /* 16 */ EXTERN void NsfSetObjClientData(Tcl_Interp *interp, Nsf_Object *object, ClientData data); /* 17 */ EXTERN ClientData NsfGetObjClientData(Tcl_Interp *interp, Nsf_Object *object); /* 18 */ EXTERN void NsfSetClassClientData(Tcl_Interp *interp, Nsf_Class *cl, ClientData data); /* 19 */ EXTERN ClientData NsfGetClassClientData(Tcl_Interp *interp, Nsf_Class *cl); /* 20 */ EXTERN void NsfRequireObjNamespace(Tcl_Interp *interp, Nsf_Object *object); /* 21 */ EXTERN int NsfCallMethodWithArgs(Tcl_Interp *interp, Nsf_Object *object, Tcl_Obj *methodObj, Tcl_Obj *arg1, int givenObjc, Tcl_Obj *const objv[], unsigned int flags); /* 22 */ EXTERN int NsfAddObjectMethod(Tcl_Interp *interp, struct Nsf_Object *object, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); /* 23 */ EXTERN int NsfAddClassMethod(Tcl_Interp *interp, struct Nsf_Class *class, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); /* 24 */ EXTERN int NsfCreate(Tcl_Interp *interp, Nsf_Class *class, Tcl_Obj *nameObj, int objc, Tcl_Obj *const objv[]); /* 25 */ EXTERN int Nsf_ArgumentParse(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Nsf_Object *object, Tcl_Obj *procNameObj, Nsf_Param const *paramPtr, int nrParams, int serial, unsigned int processFlags, Nsf_ParseContext *pcPtr); /* 26 */ EXTERN void NsfLog(Tcl_Interp *interp, int requiredLevel, const char *fmt, ...); /* 27 */ EXTERN int Nsf_PointerAdd(Tcl_Interp *interp, char *buffer, size_t size, const char *typeName, void *valuePtr); /* 28 */ EXTERN int Nsf_PointerDelete(const char *key, void *valuePtr, int free); /* 29 */ EXTERN int Nsf_PointerTypeRegister(Tcl_Interp *interp, const char*typeName, int *counterPtr); /* 30 */ EXTERN int Nsf_ConvertToBoolean(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 31 */ EXTERN int Nsf_ConvertToClass(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 32 */ EXTERN int Nsf_ConvertToInt32(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 33 */ EXTERN int Nsf_ConvertToInteger(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 34 */ EXTERN int Nsf_ConvertToObject(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 35 */ EXTERN int Nsf_ConvertToPointer(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 36 */ EXTERN int Nsf_ConvertToString(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 37 */ EXTERN int Nsf_ConvertToTclobj(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 38 */ EXTERN int Nsf_EnumerationTypeRegister(Tcl_Interp *interp, Nsf_EnumeratorConverterEntry *typeRecords); /* 39 */ EXTERN int Nsf_CmdDefinitionRegister(Tcl_Interp *interp, Nsf_methodDefinition *definitionRecords); /* 40 */ EXTERN int NsfArgumentError(Tcl_Interp *interp, const char *errorMsg, Nsf_Param const *paramPtr, Tcl_Obj *cmdNameObj, Tcl_Obj *methodPathObj); /* 41 */ EXTERN void Nsf_DStringPrintf(Tcl_DString *dsPtr, const char *fmt, ...); typedef struct { const struct NsfIntStubs *nsfIntStubs; } NsfStubHooks; typedef struct NsfStubs { int magic; const NsfStubHooks *hooks; int (*nsf_Init) (Tcl_Interp *interp); /* 0 */ void (*reserved1)(void); struct Nsf_Class * (*nsfIsClass) (Tcl_Interp *interp, ClientData cd); /* 2 */ struct Nsf_Object * (*nsfGetObject) (Tcl_Interp *interp, const char *name); /* 3 */ struct Nsf_Class * (*nsfGetClass) (Tcl_Interp *interp, const char *name); /* 4 */ int (*nsfDeleteObject) (Tcl_Interp *interp, struct Nsf_Object *object); /* 5 */ int (*nsfRemoveObjectMethod) (Tcl_Interp *interp, struct Nsf_Object *object, const char *methodName); /* 6 */ int (*nsfRemoveClassMethod) (Tcl_Interp *interp, struct Nsf_Class *class, const char *methodName); /* 7 */ Tcl_Obj * (*nsf_ObjSetVar2) (struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, Tcl_Obj *valueObj, unsigned int flags); /* 8 */ Tcl_Obj * (*nsf_ObjGetVar2) (struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, unsigned int flags); /* 9 */ int (*nsf_UnsetVar2) (struct Nsf_Object *object, Tcl_Interp *interp, const char *name1, const char *name2, unsigned int flags); /* 10 */ void (*nsfDStringVPrintf) (Tcl_DString *dsPtr, const char *fmt, va_list argPtr); /* 11 */ int (*nsfPrintError) (Tcl_Interp *interp, const char *fmt, ...); /* 12 */ int (*nsfErrInProc) (Tcl_Interp *interp, Tcl_Obj *objName, Tcl_Obj *clName, const char *procName); /* 13 */ int (*nsfObjErrType) (Tcl_Interp *interp, const char *context, Tcl_Obj *value, const char *type, Nsf_Param const *NsfObjErrType); /* 14 */ void (*nsfStackDump) (Tcl_Interp *interp); /* 15 */ void (*nsfSetObjClientData) (Tcl_Interp *interp, Nsf_Object *object, ClientData data); /* 16 */ ClientData (*nsfGetObjClientData) (Tcl_Interp *interp, Nsf_Object *object); /* 17 */ void (*nsfSetClassClientData) (Tcl_Interp *interp, Nsf_Class *cl, ClientData data); /* 18 */ ClientData (*nsfGetClassClientData) (Tcl_Interp *interp, Nsf_Class *cl); /* 19 */ void (*nsfRequireObjNamespace) (Tcl_Interp *interp, Nsf_Object *object); /* 20 */ int (*nsfCallMethodWithArgs) (Tcl_Interp *interp, Nsf_Object *object, Tcl_Obj *methodObj, Tcl_Obj *arg1, int givenObjc, Tcl_Obj *const objv[], unsigned int flags); /* 21 */ int (*nsfAddObjectMethod) (Tcl_Interp *interp, struct Nsf_Object *object, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); /* 22 */ int (*nsfAddClassMethod) (Tcl_Interp *interp, struct Nsf_Class *class, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); /* 23 */ int (*nsfCreate) (Tcl_Interp *interp, Nsf_Class *class, Tcl_Obj *nameObj, int objc, Tcl_Obj *const objv[]); /* 24 */ int (*nsf_ArgumentParse) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Nsf_Object *object, Tcl_Obj *procNameObj, Nsf_Param const *paramPtr, int nrParams, int serial, unsigned int processFlags, Nsf_ParseContext *pcPtr); /* 25 */ void (*nsfLog) (Tcl_Interp *interp, int requiredLevel, const char *fmt, ...); /* 26 */ int (*nsf_PointerAdd) (Tcl_Interp *interp, char *buffer, size_t size, const char *typeName, void *valuePtr); /* 27 */ int (*nsf_PointerDelete) (const char *key, void *valuePtr, int free); /* 28 */ int (*nsf_PointerTypeRegister) (Tcl_Interp *interp, const char*typeName, int *counterPtr); /* 29 */ int (*nsf_ConvertToBoolean) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 30 */ int (*nsf_ConvertToClass) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 31 */ int (*nsf_ConvertToInt32) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 32 */ int (*nsf_ConvertToInteger) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 33 */ int (*nsf_ConvertToObject) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 34 */ int (*nsf_ConvertToPointer) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 35 */ int (*nsf_ConvertToString) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 36 */ int (*nsf_ConvertToTclobj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 37 */ int (*nsf_EnumerationTypeRegister) (Tcl_Interp *interp, Nsf_EnumeratorConverterEntry *typeRecords); /* 38 */ int (*nsf_CmdDefinitionRegister) (Tcl_Interp *interp, Nsf_methodDefinition *definitionRecords); /* 39 */ int (*nsfArgumentError) (Tcl_Interp *interp, const char *errorMsg, Nsf_Param const *paramPtr, Tcl_Obj *cmdNameObj, Tcl_Obj *methodPathObj); /* 40 */ void (*nsf_DStringPrintf) (Tcl_DString *dsPtr, const char *fmt, ...); /* 41 */ } NsfStubs; extern const NsfStubs *nsfStubsPtr; #ifdef __cplusplus } #endif #if defined(USE_NSF_STUBS) /* * Inline function declarations: */ #define Nsf_Init \ (nsfStubsPtr->nsf_Init) /* 0 */ /* Slot 1 is reserved */ #define NsfIsClass \ (nsfStubsPtr->nsfIsClass) /* 2 */ #define NsfGetObject \ (nsfStubsPtr->nsfGetObject) /* 3 */ #define NsfGetClass \ (nsfStubsPtr->nsfGetClass) /* 4 */ #define NsfDeleteObject \ (nsfStubsPtr->nsfDeleteObject) /* 5 */ #define NsfRemoveObjectMethod \ (nsfStubsPtr->nsfRemoveObjectMethod) /* 6 */ #define NsfRemoveClassMethod \ (nsfStubsPtr->nsfRemoveClassMethod) /* 7 */ #define Nsf_ObjSetVar2 \ (nsfStubsPtr->nsf_ObjSetVar2) /* 8 */ #define Nsf_ObjGetVar2 \ (nsfStubsPtr->nsf_ObjGetVar2) /* 9 */ #define Nsf_UnsetVar2 \ (nsfStubsPtr->nsf_UnsetVar2) /* 10 */ #define NsfDStringVPrintf \ (nsfStubsPtr->nsfDStringVPrintf) /* 11 */ #define NsfPrintError \ (nsfStubsPtr->nsfPrintError) /* 12 */ #define NsfErrInProc \ (nsfStubsPtr->nsfErrInProc) /* 13 */ #define NsfObjErrType \ (nsfStubsPtr->nsfObjErrType) /* 14 */ #define NsfStackDump \ (nsfStubsPtr->nsfStackDump) /* 15 */ #define NsfSetObjClientData \ (nsfStubsPtr->nsfSetObjClientData) /* 16 */ #define NsfGetObjClientData \ (nsfStubsPtr->nsfGetObjClientData) /* 17 */ #define NsfSetClassClientData \ (nsfStubsPtr->nsfSetClassClientData) /* 18 */ #define NsfGetClassClientData \ (nsfStubsPtr->nsfGetClassClientData) /* 19 */ #define NsfRequireObjNamespace \ (nsfStubsPtr->nsfRequireObjNamespace) /* 20 */ #define NsfCallMethodWithArgs \ (nsfStubsPtr->nsfCallMethodWithArgs) /* 21 */ #define NsfAddObjectMethod \ (nsfStubsPtr->nsfAddObjectMethod) /* 22 */ #define NsfAddClassMethod \ (nsfStubsPtr->nsfAddClassMethod) /* 23 */ #define NsfCreate \ (nsfStubsPtr->nsfCreate) /* 24 */ #define Nsf_ArgumentParse \ (nsfStubsPtr->nsf_ArgumentParse) /* 25 */ #define NsfLog \ (nsfStubsPtr->nsfLog) /* 26 */ #define Nsf_PointerAdd \ (nsfStubsPtr->nsf_PointerAdd) /* 27 */ #define Nsf_PointerDelete \ (nsfStubsPtr->nsf_PointerDelete) /* 28 */ #define Nsf_PointerTypeRegister \ (nsfStubsPtr->nsf_PointerTypeRegister) /* 29 */ #define Nsf_ConvertToBoolean \ (nsfStubsPtr->nsf_ConvertToBoolean) /* 30 */ #define Nsf_ConvertToClass \ (nsfStubsPtr->nsf_ConvertToClass) /* 31 */ #define Nsf_ConvertToInt32 \ (nsfStubsPtr->nsf_ConvertToInt32) /* 32 */ #define Nsf_ConvertToInteger \ (nsfStubsPtr->nsf_ConvertToInteger) /* 33 */ #define Nsf_ConvertToObject \ (nsfStubsPtr->nsf_ConvertToObject) /* 34 */ #define Nsf_ConvertToPointer \ (nsfStubsPtr->nsf_ConvertToPointer) /* 35 */ #define Nsf_ConvertToString \ (nsfStubsPtr->nsf_ConvertToString) /* 36 */ #define Nsf_ConvertToTclobj \ (nsfStubsPtr->nsf_ConvertToTclobj) /* 37 */ #define Nsf_EnumerationTypeRegister \ (nsfStubsPtr->nsf_EnumerationTypeRegister) /* 38 */ #define Nsf_CmdDefinitionRegister \ (nsfStubsPtr->nsf_CmdDefinitionRegister) /* 39 */ #define NsfArgumentError \ (nsfStubsPtr->nsfArgumentError) /* 40 */ #define Nsf_DStringPrintf \ (nsfStubsPtr->nsf_DStringPrintf) /* 41 */ #endif /* defined(USE_NSF_STUBS) */ /* !END!: Do not edit above this line. */ #endif /* NSF_INCLUDED_NSFDECLS */ ./nsf2.4.0/generic/stubs9.0/nsfIntDecls.h000644 000766 000024 00000004767 14260520102 020566 0ustar00neumannstaff000000 000000 /* * nsfIntDecls.h -- * * This file contains the declarations for all unsupported * functions that are exported by the Tcl library. These * interfaces are not guaranteed to remain the same between * versions. Use at your own risk. * * Copyright (C) 1998-2008 Uwe Zdun (a, b) * Copyright (C) 1998-2014 Gustaf Neumann (a, b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #ifndef NSF_INCLUDED_NSFINTDECLS #define NSF_INCLUDED_NSFINTDECLS /* * WARNING: This file is automatically generated by the tools/genStubs.tcl * script. Any modifications to the function declarations below should be made * in the nsfInt.decls script. */ /* !BEGIN!: Do not edit below this line. */ #ifdef __cplusplus extern "C" { #endif /* * Exported function declarations: */ typedef struct NsfIntStubs { int magic; void *hooks; } NsfIntStubs; extern const NsfIntStubs *nsfIntStubsPtr; #ifdef __cplusplus } #endif #if defined(USE_NSF_STUBS) /* * Inline function declarations: */ #endif /* defined(USE_NSF_STUBS) */ /* !END!: Do not edit above this line. */ #endif /* NSF_INCLUDED_NSFINTDECLS */ ./nsf2.4.0/generic/nsfAPI.h000644 000766 000024 00000543573 14260520564 016122 0ustar00neumannstaff000000 000000 /* * This source code file was generated by the C-code generator gentclAPI.tcl, * part of the Next Scripting Framework. */ #if defined(USE_NSF_STUBS) int Nsf_ConvertTo_Boolean(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToBoolean(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Class(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToClass(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Int32(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToInt32(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Integer(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToInteger(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Object(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToObject(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Pointer(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToPointer(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_String(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToString(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Tclobj(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToTclobj(interp, objPtr, pPtr, clientData, outObjPtr); } #else # define Nsf_ConvertTo_Boolean Nsf_ConvertToBoolean # define Nsf_ConvertTo_Class Nsf_ConvertToClass # define Nsf_ConvertTo_Int32 Nsf_ConvertToInt32 # define Nsf_ConvertTo_Integer Nsf_ConvertToInteger # define Nsf_ConvertTo_Object Nsf_ConvertToObject # define Nsf_ConvertTo_Pointer Nsf_ConvertToPointer # define Nsf_ConvertTo_String Nsf_ConvertToString # define Nsf_ConvertTo_Tclobj Nsf_ConvertToTclobj #endif #if !defined(likely) # if defined(__GNUC__) && __GNUC__ > 2 /* Use gcc branch prediction hint to minimize cost of e.g. DTrace * ENABLED checks. */ # define unlikely(x) (__builtin_expect((x), 0)) # define likely(x) (__builtin_expect((x), 1)) # else # define unlikely(x) (x) # define likely(x) (x) # endif #endif typedef enum {InfomethodsubcmdNULL=0x0u, InfomethodsubcmdArgsIdx=1, InfomethodsubcmdBodyIdx=2, InfomethodsubcmdDefinitionIdx=3, InfomethodsubcmdExistsIdx=4, InfomethodsubcmdRegistrationhandleIdx=5, InfomethodsubcmdDefinitionhandleIdx=6, InfomethodsubcmdOriginIdx=7, InfomethodsubcmdParameterIdx=8, InfomethodsubcmdSyntaxIdx=9, InfomethodsubcmdTypeIdx=10, InfomethodsubcmdPreconditionIdx=11, InfomethodsubcmdPostconditionIdx=12, InfomethodsubcmdSubmethodsIdx=13, InfomethodsubcmdReturnsIdx=14, InfomethodsubcmdDisassembleIdx=15} InfomethodsubcmdIdx_t; static int ConvertToInfomethodsubcmd(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; static const Nsf_ObjvTable opts[] = { {"args", 1}, {"body", 2}, {"definition", 3}, {"exists", 4}, {"registrationhandle", 5}, {"definitionhandle", 6}, {"origin", 7}, {"parameter", 8}, {"syntax", 9}, {"type", 10}, {"precondition", 11}, {"postcondition", 12}, {"submethods", 13}, {"returns", 14}, {"disassemble", 15}, {NULL, 0u} }; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, opts, sizeof(Nsf_ObjvTable), "infomethodsubcmd", 0, &pos); *clientData = (ClientData) INT2PTR(opts[pos].value); *outObjPtr = objPtr; return result; } typedef enum {CallprotectionNULL=0x0u, CallprotectionAllIdx=1, CallprotectionPublicIdx=2, CallprotectionProtectedIdx=3, CallprotectionPrivateIdx=4} CallprotectionIdx_t; static int ConvertToCallprotection(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; static const Nsf_ObjvTable opts[] = { {"all", 1}, {"public", 2}, {"protected", 3}, {"private", 4}, {NULL, 0u} }; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, opts, sizeof(Nsf_ObjvTable), "callprotection", 0, &pos); *clientData = (ClientData) INT2PTR(opts[pos].value); *outObjPtr = objPtr; return result; } typedef enum {MethodtypeNULL=0x0u, MethodtypeAllIdx=NSF_METHODTYPE_ALL, MethodtypeScriptedIdx=NSF_METHODTYPE_SCRIPTED, MethodtypeBuiltinIdx=NSF_METHODTYPE_BUILTIN, MethodtypeAliasIdx=NSF_METHODTYPE_ALIAS, MethodtypeForwarderIdx=NSF_METHODTYPE_FORWARDER, MethodtypeObjectIdx=NSF_METHODTYPE_OBJECT, MethodtypeSetterIdx=NSF_METHODTYPE_SETTER, MethodtypeNsfprocIdx=NSF_METHODTYPE_NSFPROC} MethodtypeIdx_t; static int ConvertToMethodtype(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; static const Nsf_ObjvTable opts[] = { {"all", NSF_METHODTYPE_ALL}, {"scripted", NSF_METHODTYPE_SCRIPTED}, {"builtin", NSF_METHODTYPE_BUILTIN}, {"alias", NSF_METHODTYPE_ALIAS}, {"forwarder", NSF_METHODTYPE_FORWARDER}, {"object", NSF_METHODTYPE_OBJECT}, {"setter", NSF_METHODTYPE_SETTER}, {"nsfproc", NSF_METHODTYPE_NSFPROC}, {NULL, 0u} }; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, opts, sizeof(Nsf_ObjvTable), "methodtype", 0, &pos); *clientData = (ClientData) INT2PTR(opts[pos].value); *outObjPtr = objPtr; return result; } typedef enum {DefinitionsourceNULL=0x0u, DefinitionsourceAllIdx=1, DefinitionsourceApplicationIdx=2, DefinitionsourceSystemIdx=3} DefinitionsourceIdx_t; static int ConvertToDefinitionsource(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; static const Nsf_ObjvTable opts[] = { {"all", 1}, {"application", 2}, {"system", 3}, {NULL, 0u} }; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, opts, sizeof(Nsf_ObjvTable), "definitionsource", 0, &pos); *clientData = (ClientData) INT2PTR(opts[pos].value); *outObjPtr = objPtr; return result; } typedef enum {MixinscopeNULL=0x0u, MixinscopeAllIdx=1, MixinscopeClassIdx=2, MixinscopeObjectIdx=3} MixinscopeIdx_t; static int ConvertToMixinscope(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; static const Nsf_ObjvTable opts[] = { {"all", 1}, {"class", 2}, {"object", 3}, {NULL, 0u} }; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, opts, sizeof(Nsf_ObjvTable), "mixinscope", 0, &pos); *clientData = (ClientData) INT2PTR(opts[pos].value); *outObjPtr = objPtr; return result; } typedef enum {ConfigureoptionNULL=0x0u, ConfigureoptionDebugIdx=1, ConfigureoptionDtraceIdx=2, ConfigureoptionFilterIdx=3, ConfigureoptionSoftrecreateIdx=4, ConfigureoptionObjectsystemsIdx=5, ConfigureoptionKeepcmdsIdx=6, ConfigureoptionCheckresultsIdx=7, ConfigureoptionCheckargumentsIdx=8} ConfigureoptionIdx_t; const Nsf_ObjvTable Nsf_Configureoption[] = { {"debug", 1}, {"dtrace", 2}, {"filter", 3}, {"softrecreate", 4}, {"objectsystems", 5}, {"keepcmds", 6}, {"checkresults", 7}, {"checkarguments", 8}, {NULL, 0u} }; static int ConvertToConfigureoption(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, Nsf_Configureoption, sizeof(Nsf_ObjvTable), "configureoption", 0, &pos); *clientData = (ClientData) INT2PTR(Nsf_Configureoption[pos].value); *outObjPtr = objPtr; return result; } typedef enum {CurrentoptionNULL=0x0u, CurrentoptionActivelevelIdx=1, CurrentoptionActivemixinIdx=2, CurrentoptionArgsIdx=3, CurrentoptionCalledclassIdx=4, CurrentoptionCalledmethodIdx=5, CurrentoptionCalledprocIdx=6, CurrentoptionCallingclassIdx=7, CurrentoptionCallinglevelIdx=8, CurrentoptionCallingmethodIdx=9, CurrentoptionCallingobjectIdx=10, CurrentoptionCallingprocIdx=11, CurrentoptionClassIdx=12, CurrentoptionFilterregIdx=13, CurrentoptionIsnextcallIdx=14, CurrentoptionLevelIdx=15, CurrentoptionMethodpathIdx=16, CurrentoptionMethodIdx=17, CurrentoptionNextmethodIdx=18, CurrentoptionObjectIdx=19, CurrentoptionProcIdx=20} CurrentoptionIdx_t; static int ConvertToCurrentoption(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; static const Nsf_ObjvTable opts[] = { {"activelevel", 1}, {"activemixin", 2}, {"args", 3}, {"calledclass", 4}, {"calledmethod", 5}, {"calledproc", 6}, {"callingclass", 7}, {"callinglevel", 8}, {"callingmethod", 9}, {"callingobject", 10}, {"callingproc", 11}, {"class", 12}, {"filterreg", 13}, {"isnextcall", 14}, {"level", 15}, {"methodpath", 16}, {"method", 17}, {"nextmethod", 18}, {"object", 19}, {"proc", 20}, {NULL, 0u} }; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, opts, sizeof(Nsf_ObjvTable), "currentoption", 0, &pos); *clientData = (ClientData) INT2PTR(opts[pos].value); *outObjPtr = objPtr; return result; } typedef enum {FrameNULL=0x0u, FrameMethodIdx=1, FrameObjectIdx=2, FrameDefaultIdx=3} FrameIdx_t; static int ConvertToFrame(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; static const Nsf_ObjvTable opts[] = { {"method", 1}, {"object", 2}, {"default", 3}, {NULL, 0u} }; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, opts, sizeof(Nsf_ObjvTable), "frame", 0, &pos); *clientData = (ClientData) INT2PTR(opts[pos].value); *outObjPtr = objPtr; return result; } typedef enum {ForwardpropertyNULL=0x0u, ForwardpropertyPrefixIdx=1, ForwardpropertyTargetIdx=2, ForwardpropertyVerboseIdx=3} ForwardpropertyIdx_t; static int ConvertToForwardproperty(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; static const Nsf_ObjvTable opts[] = { {"prefix", 1}, {"target", 2}, {"verbose", 3}, {NULL, 0u} }; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, opts, sizeof(Nsf_ObjvTable), "forwardProperty", 0, &pos); *clientData = (ClientData) INT2PTR(opts[pos].value); *outObjPtr = objPtr; return result; } typedef enum {ProtectionNULL=0x0u, ProtectionCall_protectedIdx=1, ProtectionRedefine_protectedIdx=2, ProtectionNoneIdx=3} ProtectionIdx_t; static int ConvertToProtection(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; static const Nsf_ObjvTable opts[] = { {"call-protected", 1}, {"redefine-protected", 2}, {"none", 3}, {NULL, 0u} }; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, opts, sizeof(Nsf_ObjvTable), "protection", 0, &pos); *clientData = (ClientData) INT2PTR(opts[pos].value); *outObjPtr = objPtr; return result; } typedef enum {AssertionsubcmdNULL=0x0u, AssertionsubcmdCheckIdx=1, AssertionsubcmdObject_invarIdx=2, AssertionsubcmdClass_invarIdx=3} AssertionsubcmdIdx_t; static int ConvertToAssertionsubcmd(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; static const Nsf_ObjvTable opts[] = { {"check", 1}, {"object-invar", 2}, {"class-invar", 3}, {NULL, 0u} }; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, opts, sizeof(Nsf_ObjvTable), "assertionsubcmd", 0, &pos); *clientData = (ClientData) INT2PTR(opts[pos].value); *outObjPtr = objPtr; return result; } typedef enum {MethodpropertyNULL=0x0u, MethodpropertyClass_onlyIdx=1, MethodpropertyCall_privateIdx=2, MethodpropertyCall_protectedIdx=3, MethodpropertyDebugIdx=4, MethodpropertyDeprecatedIdx=5, MethodpropertyExistsIdx=6, MethodpropertyRedefine_protectedIdx=7, MethodpropertyReturnsIdx=8} MethodpropertyIdx_t; static int ConvertToMethodproperty(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; static const Nsf_ObjvTable opts[] = { {"class-only", 1}, {"call-private", 2}, {"call-protected", 3}, {"debug", 4}, {"deprecated", 5}, {"exists", 6}, {"redefine-protected", 7}, {"returns", 8}, {NULL, 0u} }; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, opts, sizeof(Nsf_ObjvTable), "methodProperty", 0, &pos); *clientData = (ClientData) INT2PTR(opts[pos].value); *outObjPtr = objPtr; return result; } typedef enum {ObjectpropertyNULL=0x0u, ObjectpropertyInitializedIdx=1, ObjectpropertyClassIdx=2, ObjectpropertyRootmetaclassIdx=3, ObjectpropertyRootclassIdx=4, ObjectpropertyVolatileIdx=5, ObjectpropertyAutonamedIdx=6, ObjectpropertySlotcontainerIdx=7, ObjectpropertyHasperobjectslotsIdx=8, ObjectpropertyKeepcallerselfIdx=9, ObjectpropertyPerobjectdispatchIdx=10} ObjectpropertyIdx_t; static int ConvertToObjectproperty(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; static const Nsf_ObjvTable opts[] = { {"initialized", 1}, {"class", 2}, {"rootmetaclass", 3}, {"rootclass", 4}, {"volatile", 5}, {"autonamed", 6}, {"slotcontainer", 7}, {"hasperobjectslots", 8}, {"keepcallerself", 9}, {"perobjectdispatch", 10}, {NULL, 0u} }; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, opts, sizeof(Nsf_ObjvTable), "objectProperty", 0, &pos); *clientData = (ClientData) INT2PTR(opts[pos].value); *outObjPtr = objPtr; return result; } typedef enum {ParametersubcmdNULL=0x0u, ParametersubcmdDefaultIdx=1, ParametersubcmdListIdx=2, ParametersubcmdNameIdx=3, ParametersubcmdSyntaxIdx=4, ParametersubcmdTypeIdx=5} ParametersubcmdIdx_t; static int ConvertToParametersubcmd(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; static const Nsf_ObjvTable opts[] = { {"default", 1}, {"list", 2}, {"name", 3}, {"syntax", 4}, {"type", 5}, {NULL, 0u} }; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, opts, sizeof(Nsf_ObjvTable), "parametersubcmd", 0, &pos); *clientData = (ClientData) INT2PTR(opts[pos].value); *outObjPtr = objPtr; return result; } typedef enum {RelationtypeNULL=0x0u, RelationtypeObject_mixinIdx=1, RelationtypeClass_mixinIdx=2, RelationtypeObject_filterIdx=3, RelationtypeClass_filterIdx=4, RelationtypeClassIdx=5, RelationtypeSuperclassIdx=6, RelationtypeRootclassIdx=7} RelationtypeIdx_t; static int ConvertToRelationtype(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; static const Nsf_ObjvTable opts[] = { {"object-mixin", 1}, {"class-mixin", 2}, {"object-filter", 3}, {"class-filter", 4}, {"class", 5}, {"superclass", 6}, {"rootclass", 7}, {NULL, 0u} }; (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, opts, sizeof(Nsf_ObjvTable), "relationtype", 0, &pos); *clientData = (ClientData) INT2PTR(opts[pos].value); *outObjPtr = objPtr; return result; } static Nsf_EnumeratorConverterEntry enumeratorConverterEntries[] = { {ConvertToInfomethodsubcmd, "args|body|definition|exists|registrationhandle|definitionhandle|origin|parameter|syntax|type|precondition|postcondition|submethods|returns|disassemble"}, {ConvertToCallprotection, "all|public|protected|private"}, {ConvertToMethodtype, "all|scripted|builtin|alias|forwarder|object|setter|nsfproc"}, {ConvertToFrame, "method|object|default"}, {ConvertToCurrentoption, "activelevel|activemixin|args|calledclass|calledmethod|calledproc|callingclass|callinglevel|callingmethod|callingobject|callingproc|class|filterreg|isnextcall|level|methodpath|method|nextmethod|object|proc"}, {ConvertToMethodproperty, "class-only|call-private|call-protected|debug|deprecated|exists|redefine-protected|returns"}, {ConvertToRelationtype, "object-mixin|class-mixin|object-filter|class-filter|class|superclass|rootclass"}, {ConvertToDefinitionsource, "all|application|system"}, {ConvertToForwardproperty, "prefix|target|verbose"}, {ConvertToConfigureoption, "debug|dtrace|filter|softrecreate|objectsystems|keepcmds|checkresults|checkarguments"}, {ConvertToObjectproperty, "initialized|class|rootmetaclass|rootclass|volatile|autonamed|slotcontainer|hasperobjectslots|keepcallerself|perobjectdispatch"}, {ConvertToAssertionsubcmd, "check|object-invar|class-invar"}, {ConvertToParametersubcmd, "default|list|name|syntax|type"}, {ConvertToMixinscope, "all|class|object"}, {ConvertToProtection, "call-protected|redefine-protected|none"}, {NULL, NULL} }; /* just to define the symbol */ static Nsf_methodDefinition method_definitions[121]; static const char *method_command_namespace_names[] = { "::nsf::methods::object::info", "::nsf::methods::object", "::nsf::methods::class::info", "::nsf::methods::class" }; static int NsfCAllocMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfCCreateMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfCDeallocMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfCFilterGuardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfCGetCachendParametersMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfCMixinGuardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfCNewMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfCRecreateMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfCSuperclassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfClassInfoFilterguardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfClassInfoFiltersMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfClassInfoForwardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfClassInfoHeritageMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfClassInfoInstancesMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfClassInfoMethodMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfClassInfoMethodsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfClassInfoMixinOfMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfClassInfoMixinguardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfClassInfoMixinsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfClassInfoSlotobjectsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfClassInfoSubclassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfClassInfoSuperclassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfAsmMethodCreateCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfAsmProcCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfCallgrindDumpStatsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfCallgrindStartInstrumentationCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfCallgrindStopInstrumentationCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfCallgrindToggleCollectCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfCallgrindZeroStatsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfCmdInfoCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfColonCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfConfigureCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfCurrentCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfDebugCompileEpochStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfDebugGetDictStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfDebugRunAssertionsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfDebugShowObjStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfDefinitionNamespaceCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfDirectDispatchCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfDispatchCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfFinalizeCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfForwardPropertyCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfInterpObjCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfIsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMethodAliasCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMethodAssertionCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMethodCreateCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMethodDeleteCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMethodForwardCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMethodPropertyCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMethodRegisteredCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMethodSetterCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfMyCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfNSCopyVarsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfNextCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjectAllocCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjectExistsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjectPropertyCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjectQualifyCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjectSystemCreateCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfParameterCacheClassInvalidateCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfParameterCacheObjectInvalidateCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfParameterInfoCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfParameterSpecsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfParseArgsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfProcCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfProfileClearDataStubStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfProfileGetDataStubStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfProfileTraceStubStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfRelationGetCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfRelationSetCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfSelfCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfShowStackCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfUnsetUnknownArgsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfVarExistsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfVarGetCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfVarImportCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfVarSetCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfVarUnsetCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfOAutonameMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfOCgetMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfOClassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfOCleanupMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfOConfigureMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfODestroyMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfOExistsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfOFilterGuardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfOInstvarMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfOMixinGuardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfONoinitMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfORequireNamespaceMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfOResidualargsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfOUplevelMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfOUpvarMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfOVolatile1MethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfOVolatileMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoBaseclassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoChildrenMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoClassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoFilterguardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoFiltersMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoForwardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoHasMixinMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoHasTypeMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoHasnamespaceMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoLookupFilterMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoLookupFiltersMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoLookupMethodMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoLookupMethodsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoLookupMixinsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoLookupSlotsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoMethodMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoMethodsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoMixinguardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoMixinsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoNameMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoParentMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoPrecedenceMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoSlotobjectsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoVarsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfCAllocMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *objectNameObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfCCreateMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *objectNameObj, int trailingObjc, Tcl_Obj *const* trailingObjv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfCDeallocMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *objectObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfCFilterGuardMethod(Tcl_Interp *interp, NsfClass *class, const char *filter, Tcl_Obj *guardObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3) NSF_nonnull(4); static int NsfCGetCachendParametersMethod(Tcl_Interp *interp, NsfClass *class) NSF_nonnull(1) NSF_nonnull(2); static int NsfCMixinGuardMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *mixinObj, Tcl_Obj *guardObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3) NSF_nonnull(4); static int NsfCNewMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *childofObj, int trailingObjc, Tcl_Obj *const* trailingObjv) NSF_nonnull(1) NSF_nonnull(2); static int NsfCRecreateMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *objectNameObj, int trailingObjc, Tcl_Obj *const* trailingObjv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfCSuperclassMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *superclassesObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfClassInfoFilterguardMethod(Tcl_Interp *interp, NsfClass *class, const char *filter) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfClassInfoFiltersMethod(Tcl_Interp *interp, NsfClass *class, int withGuards, const char *pattern) NSF_nonnull(1) NSF_nonnull(2); static int NsfClassInfoForwardMethod(Tcl_Interp *interp, NsfClass *class, int withDefinition, const char *pattern) NSF_nonnull(1) NSF_nonnull(2); static int NsfClassInfoHeritageMethod(Tcl_Interp *interp, NsfClass *class, const char *pattern) NSF_nonnull(1) NSF_nonnull(2); static int NsfClassInfoInstancesMethod(Tcl_Interp *interp, NsfClass *class, int withClosure, const char *patternString, NsfObject *patternObject) NSF_nonnull(1) NSF_nonnull(2); static int NsfClassInfoMethodMethod(Tcl_Interp *interp, NsfClass *class, InfomethodsubcmdIdx_t subcmd, Tcl_Obj *nameObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfClassInfoMethodsMethod(Tcl_Interp *interp, NsfClass *class, CallprotectionIdx_t withCallprotection, int withClosure, MethodtypeIdx_t withType, int withPath, DefinitionsourceIdx_t withSource, const char *pattern) NSF_nonnull(1) NSF_nonnull(2); static int NsfClassInfoMixinOfMethod(Tcl_Interp *interp, NsfClass *class, int withClosure, MixinscopeIdx_t withScope, const char *patternString, NsfObject *patternObject) NSF_nonnull(1) NSF_nonnull(2); static int NsfClassInfoMixinguardMethod(Tcl_Interp *interp, NsfClass *class, const char *mixin) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfClassInfoMixinsMethod(Tcl_Interp *interp, NsfClass *class, int withClosure, int withGuards, int withHeritage, const char *patternString, NsfObject *patternObject) NSF_nonnull(1) NSF_nonnull(2); static int NsfClassInfoSlotobjectsMethod(Tcl_Interp *interp, NsfClass *class, int withClosure, DefinitionsourceIdx_t withSource, NsfClass *typeClass, const char *pattern) NSF_nonnull(1) NSF_nonnull(2); static int NsfClassInfoSubclassMethod(Tcl_Interp *interp, NsfClass *class, int withClosure, int withDependent, const char *patternString, NsfObject *patternObject) NSF_nonnull(1) NSF_nonnull(2); static int NsfClassInfoSuperclassMethod(Tcl_Interp *interp, NsfClass *class, int withClosure, Tcl_Obj *patternObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfAsmMethodCreateCmd(Tcl_Interp *interp, NsfObject *object, int withCheckalways, int withInner_namespace, int withPer_object, NsfObject *regObject, Tcl_Obj *methodNameObj, Tcl_Obj *argumentsObj, Tcl_Obj *bodyObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(7) NSF_nonnull(8) NSF_nonnull(9); static int NsfAsmProcCmd(Tcl_Interp *interp, int withAd, int withCheckalways, Tcl_Obj *procNameObj, Tcl_Obj *argumentsObj, Tcl_Obj *bodyObj) NSF_nonnull(1) NSF_nonnull(4) NSF_nonnull(5) NSF_nonnull(6); static int NsfCallgrindDumpStatsCmd(Tcl_Interp *interp, const char *withName) NSF_nonnull(1); static int NsfCallgrindStartInstrumentationCmd(Tcl_Interp *interp) NSF_nonnull(1); static int NsfCallgrindStopInstrumentationCmd(Tcl_Interp *interp) NSF_nonnull(1); static int NsfCallgrindToggleCollectCmd(Tcl_Interp *interp) NSF_nonnull(1); static int NsfCallgrindZeroStatsCmd(Tcl_Interp *interp) NSF_nonnull(1); static int NsfCmdInfoCmd(Tcl_Interp *interp, InfomethodsubcmdIdx_t subcmd, NsfObject *contextObject, Tcl_Obj *methodNameObj, const char *pattern) NSF_nonnull(1) NSF_nonnull(4); static int NsfColonCmd(Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) NSF_nonnull(1); static int NsfConfigureCmd(Tcl_Interp *interp, ConfigureoptionIdx_t option, Tcl_Obj *valueObj) NSF_nonnull(1); static int NsfCurrentCmd(Tcl_Interp *interp, CurrentoptionIdx_t option) NSF_nonnull(1); static int NsfDebugCompileEpoch(Tcl_Interp *interp) NSF_nonnull(1); static int NsfDebugGetDict(Tcl_Interp *interp, Tcl_Obj *obj) NSF_nonnull(1) NSF_nonnull(2); static int NsfDebugRunAssertionsCmd(Tcl_Interp *interp) NSF_nonnull(1); static int NsfDebugShowObj(Tcl_Interp *interp, Tcl_Obj *obj) NSF_nonnull(1) NSF_nonnull(2); static int NsfDefinitionNamespaceCmd(Tcl_Interp *interp) NSF_nonnull(1); static int NsfDirectDispatchCmd(Tcl_Interp *interp, NsfObject *object, FrameIdx_t withFrame, Tcl_Obj *commandObj, int trailingObjc, Tcl_Obj *const* trailingObjv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfDispatchCmd(Tcl_Interp *interp, NsfObject *object, int withIntrinsic, int withSystem, Tcl_Obj *commandObj, int trailingObjc, Tcl_Obj *const* trailingObjv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(5); static int NsfFinalizeCmd(Tcl_Interp *interp, int withKeepvars) NSF_nonnull(1); static int NsfForwardPropertyCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, Tcl_Obj *methodNameObj, ForwardpropertyIdx_t forwardProperty, Tcl_Obj *valueObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfInterpObjCmd(Tcl_Interp *interp, const char *name, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2); static int NsfIsCmd(Tcl_Interp *interp, int withComplain, int withConfigure, const char *withName, Tcl_Obj *constraintObj, Tcl_Obj *valueObj) NSF_nonnull(1) NSF_nonnull(5) NSF_nonnull(6); static int NsfMethodAliasCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, const char *methodName, FrameIdx_t withFrame, ProtectionIdx_t withProtection, Tcl_Obj *cmdNameObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4) NSF_nonnull(7); static int NsfMethodAssertionCmd(Tcl_Interp *interp, NsfObject *object, AssertionsubcmdIdx_t subcmd, Tcl_Obj *argObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfMethodCreateCmd(Tcl_Interp *interp, NsfObject *object, int withCheckalways, int withInner_namespace, int withPer_object, NsfObject *regObject, Tcl_Obj *methodNameObj, Tcl_Obj *argumentsObj, Tcl_Obj *bodyObj, Tcl_Obj *preconditionObj, Tcl_Obj *postconditionObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(7) NSF_nonnull(8) NSF_nonnull(9); static int NsfMethodDeleteCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, Tcl_Obj *methodNameObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfMethodForwardCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, Tcl_Obj *methodObj, Tcl_Obj *defaultObj, int withEarlybinding, Tcl_Obj *onerrorObj, Tcl_Obj *prefixObj, FrameIdx_t withFrame, int withVerbose, Tcl_Obj *targetObj, int trailingObjc, Tcl_Obj *const* trailingObjv) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfMethodPropertyCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, Tcl_Obj *methodNameObj, MethodpropertyIdx_t methodProperty, Tcl_Obj *valueObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfMethodRegisteredCmd(Tcl_Interp *interp, Tcl_Obj *handleObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfMethodSetterCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, Tcl_Obj *parameterObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfMyCmd(Tcl_Interp *interp, int withIntrinsic, int withLocal, int withSystem, Tcl_Obj *methodNameObj, int trailingObjc, Tcl_Obj *const* trailingObjv) NSF_nonnull(1) NSF_nonnull(5); static int NsfNSCopyVarsCmd(Tcl_Interp *interp, Tcl_Obj *fromNsObj, Tcl_Obj *toNsObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfNextCmd(Tcl_Interp *interp, Tcl_Obj *argumentsObj) NSF_nonnull(1); static int NsfObjectAllocCmd(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *nameObj, Tcl_Obj *initcmdObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfObjectExistsCmd(Tcl_Interp *interp, Tcl_Obj *valueObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjectPropertyCmd(Tcl_Interp *interp, NsfObject *object, ObjectpropertyIdx_t objectProperty, Tcl_Obj *valueObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjectQualifyCmd(Tcl_Interp *interp, Tcl_Obj *objectNameObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjectSystemCreateCmd(Tcl_Interp *interp, Tcl_Obj *rootClassObj, Tcl_Obj *rootMetaClassObj, Tcl_Obj *systemMethodsObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfParameterCacheClassInvalidateCmd(Tcl_Interp *interp, NsfClass *class) NSF_nonnull(1) NSF_nonnull(2); static int NsfParameterCacheObjectInvalidateCmd(Tcl_Interp *interp, NsfObject *object) NSF_nonnull(1) NSF_nonnull(2); static int NsfParameterInfoCmd(Tcl_Interp *interp, ParametersubcmdIdx_t subcmd, Tcl_Obj *specObj, Tcl_Obj *varnameObj) NSF_nonnull(1) NSF_nonnull(3); static int NsfParameterSpecsCmd(Tcl_Interp *interp, int withConfigure, int withNonposargs, Tcl_Obj *slotobjsObj) NSF_nonnull(1) NSF_nonnull(4); static int NsfParseArgsCmd(Tcl_Interp *interp, int withAsdict, Tcl_Obj *argspecObj, Tcl_Obj *arglistObj) NSF_nonnull(1) NSF_nonnull(3) NSF_nonnull(4); static int NsfProcCmd(Tcl_Interp *interp, int withAd, int withCheckalways, int withDebug, int withDeprecated, Tcl_Obj *procNameObj, Tcl_Obj *argumentsObj, Tcl_Obj *bodyObj) NSF_nonnull(1) NSF_nonnull(6) NSF_nonnull(7) NSF_nonnull(8); static int NsfProfileClearDataStub(Tcl_Interp *interp) NSF_nonnull(1); static int NsfProfileGetDataStub(Tcl_Interp *interp) NSF_nonnull(1); static int NsfProfileTraceStub(Tcl_Interp *interp, int withEnable, int withVerbose, int withDontsave, Tcl_Obj *builtinsObj) NSF_nonnull(1); static int NsfRelationGetCmd(Tcl_Interp *interp, NsfObject *object, RelationtypeIdx_t type) NSF_nonnull(1) NSF_nonnull(2); static int NsfRelationSetCmd(Tcl_Interp *interp, NsfObject *object, RelationtypeIdx_t type, Tcl_Obj *valueObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfSelfCmd(Tcl_Interp *interp) NSF_nonnull(1); static int NsfShowStackCmd(Tcl_Interp *interp) NSF_nonnull(1); static int NsfUnsetUnknownArgsCmd(Tcl_Interp *interp) NSF_nonnull(1); static int NsfVarExistsCmd(Tcl_Interp *interp, int withArray, NsfObject *object, const char *varName) NSF_nonnull(1) NSF_nonnull(3) NSF_nonnull(4); static int NsfVarGetCmd(Tcl_Interp *interp, int withArray, int withNotrace, NsfObject *object, Tcl_Obj *varNameObj) NSF_nonnull(1) NSF_nonnull(4) NSF_nonnull(5); static int NsfVarImportCmd(Tcl_Interp *interp, NsfObject *object, int trailingObjc, Tcl_Obj *const* trailingObjv) NSF_nonnull(1) NSF_nonnull(2); static int NsfVarSetCmd(Tcl_Interp *interp, int withArray, int withNotrace, NsfObject *object, Tcl_Obj *varNameObj, Tcl_Obj *valueObj) NSF_nonnull(1) NSF_nonnull(4) NSF_nonnull(5); static int NsfVarUnsetCmd(Tcl_Interp *interp, int withNocomplain, NsfObject *object, Tcl_Obj *varNameObj) NSF_nonnull(1) NSF_nonnull(3) NSF_nonnull(4); static int NsfOAutonameMethod(Tcl_Interp *interp, NsfObject *object, int withInstance, int withReset, Tcl_Obj *nameObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(5); static int NsfOCgetMethod(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *nameObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfOClassMethod(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *classObj) NSF_nonnull(1) NSF_nonnull(2); static int NsfOCleanupMethod(Tcl_Interp *interp, NsfObject *object) NSF_nonnull(1) NSF_nonnull(2); static int NsfOConfigureMethod(Tcl_Interp *interp, NsfObject *object, int trailingObjc, Tcl_Obj *const* trailingObjv, Tcl_Obj *objv0) NSF_nonnull(1) NSF_nonnull(2); static int NsfODestroyMethod(Tcl_Interp *interp, NsfObject *object) NSF_nonnull(1) NSF_nonnull(2); static int NsfOExistsMethod(Tcl_Interp *interp, NsfObject *object, const char *varName) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfOFilterGuardMethod(Tcl_Interp *interp, NsfObject *object, const char *filter, Tcl_Obj *guardObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3) NSF_nonnull(4); static int NsfOInstvarMethod(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2); static int NsfOMixinGuardMethod(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *mixinObj, Tcl_Obj *guardObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3) NSF_nonnull(4); static int NsfONoinitMethod(Tcl_Interp *interp, NsfObject *object) NSF_nonnull(1) NSF_nonnull(2); static int NsfORequireNamespaceMethod(Tcl_Interp *interp, NsfObject *object) NSF_nonnull(1) NSF_nonnull(2); static int NsfOResidualargsMethod(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2); static int NsfOUplevelMethod(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2); static int NsfOUpvarMethod(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const* objv) NSF_nonnull(1) NSF_nonnull(2); static int NsfOVolatile1Method(Tcl_Interp *interp, NsfObject *object) NSF_nonnull(1) NSF_nonnull(2); static int NsfOVolatileMethod(Tcl_Interp *interp, NsfObject *object) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoBaseclassMethod(Tcl_Interp *interp, NsfObject *object) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoChildrenMethod(Tcl_Interp *interp, NsfObject *object, NsfClass *typeClass, const char *pattern) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoClassMethod(Tcl_Interp *interp, NsfObject *object) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoFilterguardMethod(Tcl_Interp *interp, NsfObject *object, const char *filter) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfObjInfoFiltersMethod(Tcl_Interp *interp, NsfObject *object, int withGuards, const char *pattern) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoForwardMethod(Tcl_Interp *interp, NsfObject *object, int withDefinition, const char *pattern) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoHasMixinMethod(Tcl_Interp *interp, NsfObject *object, NsfClass *class) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfObjInfoHasTypeMethod(Tcl_Interp *interp, NsfObject *object, NsfClass *class) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfObjInfoHasnamespaceMethod(Tcl_Interp *interp, NsfObject *object) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoLookupFilterMethod(Tcl_Interp *interp, NsfObject *object, const char *filter) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfObjInfoLookupFiltersMethod(Tcl_Interp *interp, NsfObject *object, int withGuards, const char *pattern) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoLookupMethodMethod(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *nameObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfObjInfoLookupMethodsMethod(Tcl_Interp *interp, NsfObject *object, CallprotectionIdx_t withCallprotection, int withIncontext, MethodtypeIdx_t withType, int withNomixins, int withPath, DefinitionsourceIdx_t withSource, const char *pattern) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoLookupMixinsMethod(Tcl_Interp *interp, NsfObject *object, int withGuards, const char *patternString, NsfObject *patternObject) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoLookupSlotsMethod(Tcl_Interp *interp, NsfObject *object, DefinitionsourceIdx_t withSource, NsfClass *typeClass, const char *pattern) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoMethodMethod(Tcl_Interp *interp, NsfObject *object, InfomethodsubcmdIdx_t subcmd, Tcl_Obj *nameObj) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfObjInfoMethodsMethod(Tcl_Interp *interp, NsfObject *object, CallprotectionIdx_t withCallprotection, MethodtypeIdx_t withType, int withPath, const char *pattern) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoMixinguardMethod(Tcl_Interp *interp, NsfObject *object, const char *mixin) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfObjInfoMixinsMethod(Tcl_Interp *interp, NsfObject *object, int withGuards, const char *patternString, NsfObject *patternObject) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoNameMethod(Tcl_Interp *interp, NsfObject *object) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoParentMethod(Tcl_Interp *interp, NsfObject *object) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoPrecedenceMethod(Tcl_Interp *interp, NsfObject *object, int withIntrinsic, const char *pattern) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoSlotobjectsMethod(Tcl_Interp *interp, NsfObject *object, NsfClass *typeClass, const char *pattern) NSF_nonnull(1) NSF_nonnull(2); static int NsfObjInfoVarsMethod(Tcl_Interp *interp, NsfObject *object, const char *pattern) NSF_nonnull(1) NSF_nonnull(2); EXTERN enum { NsfCAllocMethodIdx, NsfCCreateMethodIdx, NsfCDeallocMethodIdx, NsfCFilterGuardMethodIdx, NsfCGetCachendParametersMethodIdx, NsfCMixinGuardMethodIdx, NsfCNewMethodIdx, NsfCRecreateMethodIdx, NsfCSuperclassMethodIdx, NsfClassInfoFilterguardMethodIdx, NsfClassInfoFiltersMethodIdx, NsfClassInfoForwardMethodIdx, NsfClassInfoHeritageMethodIdx, NsfClassInfoInstancesMethodIdx, NsfClassInfoMethodMethodIdx, NsfClassInfoMethodsMethodIdx, NsfClassInfoMixinOfMethodIdx, NsfClassInfoMixinguardMethodIdx, NsfClassInfoMixinsMethodIdx, NsfClassInfoSlotobjectsMethodIdx, NsfClassInfoSubclassMethodIdx, NsfClassInfoSuperclassMethodIdx, NsfAsmMethodCreateCmdIdx, NsfAsmProcCmdIdx, NsfCallgrindDumpStatsCmdIdx, NsfCallgrindStartInstrumentationCmdIdx, NsfCallgrindStopInstrumentationCmdIdx, NsfCallgrindToggleCollectCmdIdx, NsfCallgrindZeroStatsCmdIdx, NsfCmdInfoCmdIdx, NsfColonCmdIdx, NsfConfigureCmdIdx, NsfCurrentCmdIdx, NsfDebugCompileEpochIdx, NsfDebugGetDictIdx, NsfDebugRunAssertionsCmdIdx, NsfDebugShowObjIdx, NsfDefinitionNamespaceCmdIdx, NsfDirectDispatchCmdIdx, NsfDispatchCmdIdx, NsfFinalizeCmdIdx, NsfForwardPropertyCmdIdx, NsfInterpObjCmdIdx, NsfIsCmdIdx, NsfMethodAliasCmdIdx, NsfMethodAssertionCmdIdx, NsfMethodCreateCmdIdx, NsfMethodDeleteCmdIdx, NsfMethodForwardCmdIdx, NsfMethodPropertyCmdIdx, NsfMethodRegisteredCmdIdx, NsfMethodSetterCmdIdx, NsfMyCmdIdx, NsfNSCopyVarsCmdIdx, NsfNextCmdIdx, NsfObjectAllocCmdIdx, NsfObjectExistsCmdIdx, NsfObjectPropertyCmdIdx, NsfObjectQualifyCmdIdx, NsfObjectSystemCreateCmdIdx, NsfParameterCacheClassInvalidateCmdIdx, NsfParameterCacheObjectInvalidateCmdIdx, NsfParameterInfoCmdIdx, NsfParameterSpecsCmdIdx, NsfParseArgsCmdIdx, NsfProcCmdIdx, NsfProfileClearDataStubIdx, NsfProfileGetDataStubIdx, NsfProfileTraceStubIdx, NsfRelationGetCmdIdx, NsfRelationSetCmdIdx, NsfSelfCmdIdx, NsfShowStackCmdIdx, NsfUnsetUnknownArgsCmdIdx, NsfVarExistsCmdIdx, NsfVarGetCmdIdx, NsfVarImportCmdIdx, NsfVarSetCmdIdx, NsfVarUnsetCmdIdx, NsfOAutonameMethodIdx, NsfOCgetMethodIdx, NsfOClassMethodIdx, NsfOCleanupMethodIdx, NsfOConfigureMethodIdx, NsfODestroyMethodIdx, NsfOExistsMethodIdx, NsfOFilterGuardMethodIdx, NsfOInstvarMethodIdx, NsfOMixinGuardMethodIdx, NsfONoinitMethodIdx, NsfORequireNamespaceMethodIdx, NsfOResidualargsMethodIdx, NsfOUplevelMethodIdx, NsfOUpvarMethodIdx, NsfOVolatile1MethodIdx, NsfOVolatileMethodIdx, NsfObjInfoBaseclassMethodIdx, NsfObjInfoChildrenMethodIdx, NsfObjInfoClassMethodIdx, NsfObjInfoFilterguardMethodIdx, NsfObjInfoFiltersMethodIdx, NsfObjInfoForwardMethodIdx, NsfObjInfoHasMixinMethodIdx, NsfObjInfoHasTypeMethodIdx, NsfObjInfoHasnamespaceMethodIdx, NsfObjInfoLookupFilterMethodIdx, NsfObjInfoLookupFiltersMethodIdx, NsfObjInfoLookupMethodMethodIdx, NsfObjInfoLookupMethodsMethodIdx, NsfObjInfoLookupMixinsMethodIdx, NsfObjInfoLookupSlotsMethodIdx, NsfObjInfoMethodMethodIdx, NsfObjInfoMethodsMethodIdx, NsfObjInfoMixinguardMethodIdx, NsfObjInfoMixinsMethodIdx, NsfObjInfoNameMethodIdx, NsfObjInfoParentMethodIdx, NsfObjInfoPrecedenceMethodIdx, NsfObjInfoSlotobjectsMethodIdx, NsfObjInfoVarsMethodIdx } NsfMethods; static int NsfCAllocMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (objc != 2) { return NsfArgumentError(interp, "wrong # of arguments:", method_definitions[NsfCAllocMethodIdx].paramDefs, NULL, objv[0]); } return NsfCAllocMethod(interp, class, objv[1]); } static int NsfCCreateMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfCCreateMethodIdx].paramDefs, method_definitions[NsfCCreateMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { Tcl_Obj *objectNameObj = (Tcl_Obj *)pc.clientData[0]; assert(pc.status == 0); return NsfCCreateMethod(interp, class, objectNameObj, objc - pc.lastObjc, objv + pc.lastObjc); } else { return TCL_ERROR; } } static int NsfCDeallocMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (objc != 2) { return NsfArgumentError(interp, "wrong # of arguments:", method_definitions[NsfCDeallocMethodIdx].paramDefs, NULL, objv[0]); } return NsfCDeallocMethod(interp, class, objv[1]); } static int NsfCFilterGuardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfCFilterGuardMethodIdx].paramDefs, method_definitions[NsfCFilterGuardMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { const char *filter = (const char *)pc.clientData[0]; Tcl_Obj *guardObj = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); return NsfCFilterGuardMethod(interp, class, filter, guardObj); } else { return TCL_ERROR; } } static int NsfCGetCachendParametersMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfCGetCachendParametersMethodIdx].paramDefs, NULL, objv[0]); } return NsfCGetCachendParametersMethod(interp, class); } static int NsfCMixinGuardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfCMixinGuardMethodIdx].paramDefs, method_definitions[NsfCMixinGuardMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { Tcl_Obj *mixinObj = (Tcl_Obj *)pc.clientData[0]; Tcl_Obj *guardObj = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); return NsfCMixinGuardMethod(interp, class, mixinObj, guardObj); } else { return TCL_ERROR; } } static int NsfCNewMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfCNewMethodIdx].paramDefs, method_definitions[NsfCNewMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { Tcl_Obj *childofObj = (Tcl_Obj *)pc.clientData[0]; assert(pc.status == 0); return NsfCNewMethod(interp, class, childofObj, objc - pc.lastObjc, objv + pc.lastObjc); } else { return TCL_ERROR; } } static int NsfCRecreateMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfCRecreateMethodIdx].paramDefs, method_definitions[NsfCRecreateMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { Tcl_Obj *objectNameObj = (Tcl_Obj *)pc.clientData[0]; assert(pc.status == 0); return NsfCRecreateMethod(interp, class, objectNameObj, objc - pc.lastObjc, objv + pc.lastObjc); } else { return TCL_ERROR; } } static int NsfCSuperclassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (objc < 1 || objc > 2) { return NsfArgumentError(interp, "wrong # of arguments:", method_definitions[NsfCSuperclassMethodIdx].paramDefs, NULL, objv[0]); } return NsfCSuperclassMethod(interp, class, objc == 2 ? objv[1] : NULL); } static int NsfClassInfoFilterguardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfClassInfoFilterguardMethodIdx].paramDefs, method_definitions[NsfClassInfoFilterguardMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { const char *filter = (const char *)pc.clientData[0]; assert(pc.status == 0); return NsfClassInfoFilterguardMethod(interp, class, filter); } else { return TCL_ERROR; } } static int NsfClassInfoFiltersMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfClassInfoFiltersMethodIdx].paramDefs, method_definitions[NsfClassInfoFiltersMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withGuards = (int )PTR2INT(pc.clientData[0]); const char *pattern = (const char *)pc.clientData[1]; assert(pc.status == 0); return NsfClassInfoFiltersMethod(interp, class, withGuards, pattern); } else { return TCL_ERROR; } } static int NsfClassInfoForwardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfClassInfoForwardMethodIdx].paramDefs, method_definitions[NsfClassInfoForwardMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withDefinition = (int )PTR2INT(pc.clientData[0]); const char *pattern = (const char *)pc.clientData[1]; assert(pc.status == 0); return NsfClassInfoForwardMethod(interp, class, withDefinition, pattern); } else { return TCL_ERROR; } } static int NsfClassInfoHeritageMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfClassInfoHeritageMethodIdx].paramDefs, method_definitions[NsfClassInfoHeritageMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { const char *pattern = (const char *)pc.clientData[0]; assert(pc.status == 0); return NsfClassInfoHeritageMethod(interp, class, pattern); } else { return TCL_ERROR; } } static int NsfClassInfoInstancesMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfClassInfoInstancesMethodIdx].paramDefs, method_definitions[NsfClassInfoInstancesMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withClosure = (int )PTR2INT(pc.clientData[0]); const char *patternString = NULL; NsfObject *patternObject = NULL; Tcl_Obj *pattern = (Tcl_Obj *)pc.clientData[1]; int returnCode; if (GetMatchObject(interp, pattern, objc>1 ? objv[1] : NULL, &patternObject, &patternString) == -1) { if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return TCL_OK; } assert(pc.status == 0); returnCode = NsfClassInfoInstancesMethod(interp, class, withClosure, patternString, patternObject); if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return returnCode; } else { Tcl_Obj *pattern = (Tcl_Obj *)pc.clientData[1]; if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return TCL_ERROR; } } static int NsfClassInfoMethodMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfClassInfoMethodMethodIdx].paramDefs, method_definitions[NsfClassInfoMethodMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { InfomethodsubcmdIdx_t subcmd = (InfomethodsubcmdIdx_t )PTR2INT(pc.clientData[0]); Tcl_Obj *nameObj = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); return NsfClassInfoMethodMethod(interp, class, subcmd, nameObj); } else { return TCL_ERROR; } } static int NsfClassInfoMethodsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfClassInfoMethodsMethodIdx].paramDefs, method_definitions[NsfClassInfoMethodsMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { CallprotectionIdx_t withCallprotection = (CallprotectionIdx_t )PTR2INT(pc.clientData[0]); int withClosure = (int )PTR2INT(pc.clientData[1]); MethodtypeIdx_t withType = (MethodtypeIdx_t )PTR2INT(pc.clientData[2]); int withPath = (int )PTR2INT(pc.clientData[3]); DefinitionsourceIdx_t withSource = (DefinitionsourceIdx_t )PTR2INT(pc.clientData[4]); const char *pattern = (const char *)pc.clientData[5]; assert(pc.status == 0); return NsfClassInfoMethodsMethod(interp, class, withCallprotection, withClosure, withType, withPath, withSource, pattern); } else { return TCL_ERROR; } } static int NsfClassInfoMixinOfMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfClassInfoMixinOfMethodIdx].paramDefs, method_definitions[NsfClassInfoMixinOfMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withClosure = (int )PTR2INT(pc.clientData[0]); MixinscopeIdx_t withScope = (MixinscopeIdx_t )PTR2INT(pc.clientData[1]); const char *patternString = NULL; NsfObject *patternObject = NULL; Tcl_Obj *pattern = (Tcl_Obj *)pc.clientData[2]; int returnCode; if (GetMatchObject(interp, pattern, objc>2 ? objv[2] : NULL, &patternObject, &patternString) == -1) { if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return TCL_OK; } assert(pc.status == 0); returnCode = NsfClassInfoMixinOfMethod(interp, class, withClosure, withScope, patternString, patternObject); if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return returnCode; } else { Tcl_Obj *pattern = (Tcl_Obj *)pc.clientData[2]; if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return TCL_ERROR; } } static int NsfClassInfoMixinguardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfClassInfoMixinguardMethodIdx].paramDefs, method_definitions[NsfClassInfoMixinguardMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { const char *mixin = (const char *)pc.clientData[0]; assert(pc.status == 0); return NsfClassInfoMixinguardMethod(interp, class, mixin); } else { return TCL_ERROR; } } static int NsfClassInfoMixinsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfClassInfoMixinsMethodIdx].paramDefs, method_definitions[NsfClassInfoMixinsMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withClosure = (int )PTR2INT(pc.clientData[0]); int withGuards = (int )PTR2INT(pc.clientData[1]); int withHeritage = (int )PTR2INT(pc.clientData[2]); const char *patternString = NULL; NsfObject *patternObject = NULL; Tcl_Obj *pattern = (Tcl_Obj *)pc.clientData[3]; int returnCode; if (GetMatchObject(interp, pattern, objc>3 ? objv[3] : NULL, &patternObject, &patternString) == -1) { if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return TCL_OK; } assert(pc.status == 0); returnCode = NsfClassInfoMixinsMethod(interp, class, withClosure, withGuards, withHeritage, patternString, patternObject); if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return returnCode; } else { Tcl_Obj *pattern = (Tcl_Obj *)pc.clientData[3]; if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return TCL_ERROR; } } static int NsfClassInfoSlotobjectsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfClassInfoSlotobjectsMethodIdx].paramDefs, method_definitions[NsfClassInfoSlotobjectsMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withClosure = (int )PTR2INT(pc.clientData[0]); DefinitionsourceIdx_t withSource = (DefinitionsourceIdx_t )PTR2INT(pc.clientData[1]); NsfClass *typeClass = (NsfClass *)pc.clientData[2]; const char *pattern = (const char *)pc.clientData[3]; assert(pc.status == 0); return NsfClassInfoSlotobjectsMethod(interp, class, withClosure, withSource, typeClass, pattern); } else { return TCL_ERROR; } } static int NsfClassInfoSubclassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfClassInfoSubclassMethodIdx].paramDefs, method_definitions[NsfClassInfoSubclassMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withClosure = (int )PTR2INT(pc.clientData[0]); int withDependent = (int )PTR2INT(pc.clientData[1]); const char *patternString = NULL; NsfObject *patternObject = NULL; Tcl_Obj *pattern = (Tcl_Obj *)pc.clientData[2]; int returnCode; if (GetMatchObject(interp, pattern, objc>2 ? objv[2] : NULL, &patternObject, &patternString) == -1) { if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return TCL_OK; } assert(pc.status == 0); returnCode = NsfClassInfoSubclassMethod(interp, class, withClosure, withDependent, patternString, patternObject); if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return returnCode; } else { Tcl_Obj *pattern = (Tcl_Obj *)pc.clientData[2]; if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return TCL_ERROR; } } static int NsfClassInfoSuperclassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfClass *class; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); class = NsfObjectToClass(clientData); if (unlikely(class == NULL)) { return NsfDispatchClientDataError(interp, clientData, "class", ObjStr(objv[0])); } if (likely(ArgumentParse(interp, objc, objv, (NsfObject *) class, objv[0], method_definitions[NsfClassInfoSuperclassMethodIdx].paramDefs, method_definitions[NsfClassInfoSuperclassMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withClosure = (int )PTR2INT(pc.clientData[0]); Tcl_Obj *patternObj = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); return NsfClassInfoSuperclassMethod(interp, class, withClosure, patternObj); } else { return TCL_ERROR; } } static int NsfAsmMethodCreateCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfAsmMethodCreateCmdIdx].paramDefs, method_definitions[NsfAsmMethodCreateCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; int withCheckalways = (int )PTR2INT(pc.clientData[1]); int withInner_namespace = (int )PTR2INT(pc.clientData[2]); int withPer_object = (int )PTR2INT(pc.clientData[3]); NsfObject *regObject = (NsfObject *)pc.clientData[4]; Tcl_Obj *methodNameObj = (Tcl_Obj *)pc.clientData[5]; Tcl_Obj *argumentsObj = (Tcl_Obj *)pc.clientData[6]; Tcl_Obj *bodyObj = (Tcl_Obj *)pc.clientData[7]; assert(pc.status == 0); return NsfAsmMethodCreateCmd(interp, object, withCheckalways, withInner_namespace, withPer_object, regObject, methodNameObj, argumentsObj, bodyObj); } else { return TCL_ERROR; } } static int NsfAsmProcCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfAsmProcCmdIdx].paramDefs, method_definitions[NsfAsmProcCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withAd = (int )PTR2INT(pc.clientData[0]); int withCheckalways = (int )PTR2INT(pc.clientData[1]); Tcl_Obj *procNameObj = (Tcl_Obj *)pc.clientData[2]; Tcl_Obj *argumentsObj = (Tcl_Obj *)pc.clientData[3]; Tcl_Obj *bodyObj = (Tcl_Obj *)pc.clientData[4]; assert(pc.status == 0); return NsfAsmProcCmd(interp, withAd, withCheckalways, procNameObj, argumentsObj, bodyObj); } else { return TCL_ERROR; } } static int NsfCallgrindDumpStatsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfCallgrindDumpStatsCmdIdx].paramDefs, method_definitions[NsfCallgrindDumpStatsCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { const char *withName = (const char *)pc.clientData[0]; assert(pc.status == 0); return NsfCallgrindDumpStatsCmd(interp, withName); } else { return TCL_ERROR; } } static int NsfCallgrindStartInstrumentationCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfCallgrindStartInstrumentationCmdIdx].paramDefs, NULL, objv[0]); } return NsfCallgrindStartInstrumentationCmd(interp); } static int NsfCallgrindStopInstrumentationCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfCallgrindStopInstrumentationCmdIdx].paramDefs, NULL, objv[0]); } return NsfCallgrindStopInstrumentationCmd(interp); } static int NsfCallgrindToggleCollectCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfCallgrindToggleCollectCmdIdx].paramDefs, NULL, objv[0]); } return NsfCallgrindToggleCollectCmd(interp); } static int NsfCallgrindZeroStatsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfCallgrindZeroStatsCmdIdx].paramDefs, NULL, objv[0]); } return NsfCallgrindZeroStatsCmd(interp); } static int NsfCmdInfoCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfCmdInfoCmdIdx].paramDefs, method_definitions[NsfCmdInfoCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { InfomethodsubcmdIdx_t subcmd = (InfomethodsubcmdIdx_t )PTR2INT(pc.clientData[0]); NsfObject *contextObject = (NsfObject *)pc.clientData[1]; Tcl_Obj *methodNameObj = (Tcl_Obj *)pc.clientData[2]; const char *pattern = (const char *)pc.clientData[3]; assert(pc.status == 0); return NsfCmdInfoCmd(interp, subcmd, contextObject, methodNameObj, pattern); } else { return TCL_ERROR; } } static int NsfColonCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; return NsfColonCmd(interp, objc, objv); } static int NsfConfigureCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfConfigureCmdIdx].paramDefs, method_definitions[NsfConfigureCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { ConfigureoptionIdx_t option = (ConfigureoptionIdx_t )PTR2INT(pc.clientData[0]); Tcl_Obj *valueObj = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); return NsfConfigureCmd(interp, option, valueObj); } else { return TCL_ERROR; } } static int NsfCurrentCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfCurrentCmdIdx].paramDefs, method_definitions[NsfCurrentCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { CurrentoptionIdx_t option = (CurrentoptionIdx_t )PTR2INT(pc.clientData[0]); assert(pc.status == 0); return NsfCurrentCmd(interp, option); } else { return TCL_ERROR; } } static int NsfDebugCompileEpochStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfDebugCompileEpochIdx].paramDefs, NULL, objv[0]); } return NsfDebugCompileEpoch(interp); } static int NsfDebugGetDictStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (objc != 2) { return NsfArgumentError(interp, "wrong # of arguments:", method_definitions[NsfDebugGetDictIdx].paramDefs, NULL, objv[0]); } return NsfDebugGetDict(interp, objv[1]); } static int NsfDebugRunAssertionsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfDebugRunAssertionsCmdIdx].paramDefs, NULL, objv[0]); } return NsfDebugRunAssertionsCmd(interp); } static int NsfDebugShowObjStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (objc != 2) { return NsfArgumentError(interp, "wrong # of arguments:", method_definitions[NsfDebugShowObjIdx].paramDefs, NULL, objv[0]); } return NsfDebugShowObj(interp, objv[1]); } static int NsfDefinitionNamespaceCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfDefinitionNamespaceCmdIdx].paramDefs, NULL, objv[0]); } return NsfDefinitionNamespaceCmd(interp); } static int NsfDirectDispatchCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfDirectDispatchCmdIdx].paramDefs, method_definitions[NsfDirectDispatchCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; FrameIdx_t withFrame = (FrameIdx_t )PTR2INT(pc.clientData[1]); Tcl_Obj *commandObj = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); return NsfDirectDispatchCmd(interp, object, withFrame, commandObj, objc - pc.lastObjc, objv + pc.lastObjc); } else { return TCL_ERROR; } } static int NsfDispatchCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfDispatchCmdIdx].paramDefs, method_definitions[NsfDispatchCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; int withIntrinsic = (int )PTR2INT(pc.clientData[1]); int withSystem = (int )PTR2INT(pc.clientData[2]); Tcl_Obj *commandObj = (Tcl_Obj *)pc.clientData[3]; assert(pc.status == 0); return NsfDispatchCmd(interp, object, withIntrinsic, withSystem, commandObj, objc - pc.lastObjc, objv + pc.lastObjc); } else { return TCL_ERROR; } } static int NsfFinalizeCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfFinalizeCmdIdx].paramDefs, method_definitions[NsfFinalizeCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withKeepvars = (int )PTR2INT(pc.clientData[0]); assert(pc.status == 0); return NsfFinalizeCmd(interp, withKeepvars); } else { return TCL_ERROR; } } static int NsfForwardPropertyCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfForwardPropertyCmdIdx].paramDefs, method_definitions[NsfForwardPropertyCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; int withPer_object = (int )PTR2INT(pc.clientData[1]); Tcl_Obj *methodNameObj = (Tcl_Obj *)pc.clientData[2]; ForwardpropertyIdx_t forwardProperty = (ForwardpropertyIdx_t )PTR2INT(pc.clientData[3]); Tcl_Obj *valueObj = (Tcl_Obj *)pc.clientData[4]; assert(pc.status == 0); return NsfForwardPropertyCmd(interp, object, withPer_object, methodNameObj, forwardProperty, valueObj); } else { return TCL_ERROR; } } static int NsfInterpObjCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfInterpObjCmdIdx].paramDefs, method_definitions[NsfInterpObjCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { const char *name = (const char *)pc.clientData[0]; assert(pc.status == 0); return NsfInterpObjCmd(interp, name, objc, objv); } else { return TCL_ERROR; } } static int NsfIsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfIsCmdIdx].paramDefs, method_definitions[NsfIsCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withComplain = (int )PTR2INT(pc.clientData[0]); int withConfigure = (int )PTR2INT(pc.clientData[1]); const char *withName = (const char *)pc.clientData[2]; Tcl_Obj *constraintObj = (Tcl_Obj *)pc.clientData[3]; Tcl_Obj *valueObj = (Tcl_Obj *)pc.clientData[4]; assert(pc.status == 0); return NsfIsCmd(interp, withComplain, withConfigure, withName, constraintObj, valueObj); } else { return TCL_ERROR; } } static int NsfMethodAliasCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMethodAliasCmdIdx].paramDefs, method_definitions[NsfMethodAliasCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; int withPer_object = (int )PTR2INT(pc.clientData[1]); const char *methodName = (const char *)pc.clientData[2]; FrameIdx_t withFrame = (FrameIdx_t )PTR2INT(pc.clientData[3]); ProtectionIdx_t withProtection = (ProtectionIdx_t )PTR2INT(pc.clientData[4]); Tcl_Obj *cmdNameObj = (Tcl_Obj *)pc.clientData[5]; assert(pc.status == 0); return NsfMethodAliasCmd(interp, object, withPer_object, methodName, withFrame, withProtection, cmdNameObj); } else { return TCL_ERROR; } } static int NsfMethodAssertionCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMethodAssertionCmdIdx].paramDefs, method_definitions[NsfMethodAssertionCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; AssertionsubcmdIdx_t subcmd = (AssertionsubcmdIdx_t )PTR2INT(pc.clientData[1]); Tcl_Obj *argObj = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); return NsfMethodAssertionCmd(interp, object, subcmd, argObj); } else { return TCL_ERROR; } } static int NsfMethodCreateCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMethodCreateCmdIdx].paramDefs, method_definitions[NsfMethodCreateCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; int withCheckalways = (int )PTR2INT(pc.clientData[1]); int withInner_namespace = (int )PTR2INT(pc.clientData[2]); int withPer_object = (int )PTR2INT(pc.clientData[3]); NsfObject *regObject = (NsfObject *)pc.clientData[4]; Tcl_Obj *methodNameObj = (Tcl_Obj *)pc.clientData[5]; Tcl_Obj *argumentsObj = (Tcl_Obj *)pc.clientData[6]; Tcl_Obj *bodyObj = (Tcl_Obj *)pc.clientData[7]; Tcl_Obj *preconditionObj = (Tcl_Obj *)pc.clientData[8]; Tcl_Obj *postconditionObj = (Tcl_Obj *)pc.clientData[9]; assert(pc.status == 0); return NsfMethodCreateCmd(interp, object, withCheckalways, withInner_namespace, withPer_object, regObject, methodNameObj, argumentsObj, bodyObj, preconditionObj, postconditionObj); } else { return TCL_ERROR; } } static int NsfMethodDeleteCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMethodDeleteCmdIdx].paramDefs, method_definitions[NsfMethodDeleteCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; int withPer_object = (int )PTR2INT(pc.clientData[1]); Tcl_Obj *methodNameObj = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); return NsfMethodDeleteCmd(interp, object, withPer_object, methodNameObj); } else { return TCL_ERROR; } } static int NsfMethodForwardCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMethodForwardCmdIdx].paramDefs, method_definitions[NsfMethodForwardCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; int withPer_object = (int )PTR2INT(pc.clientData[1]); Tcl_Obj *methodObj = (Tcl_Obj *)pc.clientData[2]; Tcl_Obj *defaultObj = (Tcl_Obj *)pc.clientData[3]; int withEarlybinding = (int )PTR2INT(pc.clientData[4]); Tcl_Obj *onerrorObj = (Tcl_Obj *)pc.clientData[5]; Tcl_Obj *prefixObj = (Tcl_Obj *)pc.clientData[6]; FrameIdx_t withFrame = (FrameIdx_t )PTR2INT(pc.clientData[7]); int withVerbose = (int )PTR2INT(pc.clientData[8]); Tcl_Obj *targetObj = (Tcl_Obj *)pc.clientData[9]; assert(pc.status == 0); return NsfMethodForwardCmd(interp, object, withPer_object, methodObj, defaultObj, withEarlybinding, onerrorObj, prefixObj, withFrame, withVerbose, targetObj, objc - pc.lastObjc, objv + pc.lastObjc); } else { return TCL_ERROR; } } static int NsfMethodPropertyCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMethodPropertyCmdIdx].paramDefs, method_definitions[NsfMethodPropertyCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; int withPer_object = (int )PTR2INT(pc.clientData[1]); Tcl_Obj *methodNameObj = (Tcl_Obj *)pc.clientData[2]; MethodpropertyIdx_t methodProperty = (MethodpropertyIdx_t )PTR2INT(pc.clientData[3]); Tcl_Obj *valueObj = (Tcl_Obj *)pc.clientData[4]; assert(pc.status == 0); return NsfMethodPropertyCmd(interp, object, withPer_object, methodNameObj, methodProperty, valueObj); } else { return TCL_ERROR; } } static int NsfMethodRegisteredCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (objc != 2) { return NsfArgumentError(interp, "wrong # of arguments:", method_definitions[NsfMethodRegisteredCmdIdx].paramDefs, NULL, objv[0]); } return NsfMethodRegisteredCmd(interp, objv[1]); } static int NsfMethodSetterCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMethodSetterCmdIdx].paramDefs, method_definitions[NsfMethodSetterCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; int withPer_object = (int )PTR2INT(pc.clientData[1]); Tcl_Obj *parameterObj = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); return NsfMethodSetterCmd(interp, object, withPer_object, parameterObj); } else { return TCL_ERROR; } } static int NsfMyCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMyCmdIdx].paramDefs, method_definitions[NsfMyCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withIntrinsic = (int )PTR2INT(pc.clientData[0]); int withLocal = (int )PTR2INT(pc.clientData[1]); int withSystem = (int )PTR2INT(pc.clientData[2]); Tcl_Obj *methodNameObj = (Tcl_Obj *)pc.clientData[3]; assert(pc.status == 0); return NsfMyCmd(interp, withIntrinsic, withLocal, withSystem, methodNameObj, objc - pc.lastObjc, objv + pc.lastObjc); } else { return TCL_ERROR; } } static int NsfNSCopyVarsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfNSCopyVarsCmdIdx].paramDefs, method_definitions[NsfNSCopyVarsCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { Tcl_Obj *fromNsObj = (Tcl_Obj *)pc.clientData[0]; Tcl_Obj *toNsObj = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); return NsfNSCopyVarsCmd(interp, fromNsObj, toNsObj); } else { return TCL_ERROR; } } static int NsfNextCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (objc < 1 || objc > 2) { return NsfArgumentError(interp, "wrong # of arguments:", method_definitions[NsfNextCmdIdx].paramDefs, NULL, objv[0]); } return NsfNextCmd(interp, objc == 2 ? objv[1] : NULL); } static int NsfObjectAllocCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfObjectAllocCmdIdx].paramDefs, method_definitions[NsfObjectAllocCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfClass *class = (NsfClass *)pc.clientData[0]; Tcl_Obj *nameObj = (Tcl_Obj *)pc.clientData[1]; Tcl_Obj *initcmdObj = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); return NsfObjectAllocCmd(interp, class, nameObj, initcmdObj); } else { return TCL_ERROR; } } static int NsfObjectExistsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (objc != 2) { return NsfArgumentError(interp, "wrong # of arguments:", method_definitions[NsfObjectExistsCmdIdx].paramDefs, NULL, objv[0]); } return NsfObjectExistsCmd(interp, objv[1]); } static int NsfObjectPropertyCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfObjectPropertyCmdIdx].paramDefs, method_definitions[NsfObjectPropertyCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; ObjectpropertyIdx_t objectProperty = (ObjectpropertyIdx_t )PTR2INT(pc.clientData[1]); Tcl_Obj *valueObj = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); return NsfObjectPropertyCmd(interp, object, objectProperty, valueObj); } else { return TCL_ERROR; } } static int NsfObjectQualifyCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (objc != 2) { return NsfArgumentError(interp, "wrong # of arguments:", method_definitions[NsfObjectQualifyCmdIdx].paramDefs, NULL, objv[0]); } return NsfObjectQualifyCmd(interp, objv[1]); } static int NsfObjectSystemCreateCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfObjectSystemCreateCmdIdx].paramDefs, method_definitions[NsfObjectSystemCreateCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { Tcl_Obj *rootClassObj = (Tcl_Obj *)pc.clientData[0]; Tcl_Obj *rootMetaClassObj = (Tcl_Obj *)pc.clientData[1]; Tcl_Obj *systemMethodsObj = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); return NsfObjectSystemCreateCmd(interp, rootClassObj, rootMetaClassObj, systemMethodsObj); } else { return TCL_ERROR; } } static int NsfParameterCacheClassInvalidateCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfParameterCacheClassInvalidateCmdIdx].paramDefs, method_definitions[NsfParameterCacheClassInvalidateCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfClass *class = (NsfClass *)pc.clientData[0]; assert(pc.status == 0); return NsfParameterCacheClassInvalidateCmd(interp, class); } else { return TCL_ERROR; } } static int NsfParameterCacheObjectInvalidateCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfParameterCacheObjectInvalidateCmdIdx].paramDefs, method_definitions[NsfParameterCacheObjectInvalidateCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; assert(pc.status == 0); return NsfParameterCacheObjectInvalidateCmd(interp, object); } else { return TCL_ERROR; } } static int NsfParameterInfoCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfParameterInfoCmdIdx].paramDefs, method_definitions[NsfParameterInfoCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { ParametersubcmdIdx_t subcmd = (ParametersubcmdIdx_t )PTR2INT(pc.clientData[0]); Tcl_Obj *specObj = (Tcl_Obj *)pc.clientData[1]; Tcl_Obj *varnameObj = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); return NsfParameterInfoCmd(interp, subcmd, specObj, varnameObj); } else { return TCL_ERROR; } } static int NsfParameterSpecsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfParameterSpecsCmdIdx].paramDefs, method_definitions[NsfParameterSpecsCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withConfigure = (int )PTR2INT(pc.clientData[0]); int withNonposargs = (int )PTR2INT(pc.clientData[1]); Tcl_Obj *slotobjsObj = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); return NsfParameterSpecsCmd(interp, withConfigure, withNonposargs, slotobjsObj); } else { return TCL_ERROR; } } static int NsfParseArgsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfParseArgsCmdIdx].paramDefs, method_definitions[NsfParseArgsCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withAsdict = (int )PTR2INT(pc.clientData[0]); Tcl_Obj *argspecObj = (Tcl_Obj *)pc.clientData[1]; Tcl_Obj *arglistObj = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); return NsfParseArgsCmd(interp, withAsdict, argspecObj, arglistObj); } else { return TCL_ERROR; } } static int NsfProcCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfProcCmdIdx].paramDefs, method_definitions[NsfProcCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withAd = (int )PTR2INT(pc.clientData[0]); int withCheckalways = (int )PTR2INT(pc.clientData[1]); int withDebug = (int )PTR2INT(pc.clientData[2]); int withDeprecated = (int )PTR2INT(pc.clientData[3]); Tcl_Obj *procNameObj = (Tcl_Obj *)pc.clientData[4]; Tcl_Obj *argumentsObj = (Tcl_Obj *)pc.clientData[5]; Tcl_Obj *bodyObj = (Tcl_Obj *)pc.clientData[6]; assert(pc.status == 0); return NsfProcCmd(interp, withAd, withCheckalways, withDebug, withDeprecated, procNameObj, argumentsObj, bodyObj); } else { return TCL_ERROR; } } static int NsfProfileClearDataStubStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfProfileClearDataStubIdx].paramDefs, NULL, objv[0]); } return NsfProfileClearDataStub(interp); } static int NsfProfileGetDataStubStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfProfileGetDataStubIdx].paramDefs, NULL, objv[0]); } return NsfProfileGetDataStub(interp); } static int NsfProfileTraceStubStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfProfileTraceStubIdx].paramDefs, method_definitions[NsfProfileTraceStubIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withEnable = (int )PTR2INT(pc.clientData[0]); int withVerbose = (int )PTR2INT(pc.clientData[1]); int withDontsave = (int )PTR2INT(pc.clientData[2]); Tcl_Obj *builtinsObj = (Tcl_Obj *)pc.clientData[3]; assert(pc.status == 0); return NsfProfileTraceStub(interp, withEnable, withVerbose, withDontsave, builtinsObj); } else { return TCL_ERROR; } } static int NsfRelationGetCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfRelationGetCmdIdx].paramDefs, method_definitions[NsfRelationGetCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; RelationtypeIdx_t type = (RelationtypeIdx_t )PTR2INT(pc.clientData[1]); assert(pc.status == 0); return NsfRelationGetCmd(interp, object, type); } else { return TCL_ERROR; } } static int NsfRelationSetCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfRelationSetCmdIdx].paramDefs, method_definitions[NsfRelationSetCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; RelationtypeIdx_t type = (RelationtypeIdx_t )PTR2INT(pc.clientData[1]); Tcl_Obj *valueObj = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); return NsfRelationSetCmd(interp, object, type, valueObj); } else { return TCL_ERROR; } } static int NsfSelfCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfSelfCmdIdx].paramDefs, NULL, objv[0]); } return NsfSelfCmd(interp); } static int NsfShowStackCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfShowStackCmdIdx].paramDefs, NULL, objv[0]); } return NsfShowStackCmd(interp); } static int NsfUnsetUnknownArgsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { (void)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfUnsetUnknownArgsCmdIdx].paramDefs, NULL, objv[0]); } return NsfUnsetUnknownArgsCmd(interp); } static int NsfVarExistsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfVarExistsCmdIdx].paramDefs, method_definitions[NsfVarExistsCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withArray = (int )PTR2INT(pc.clientData[0]); NsfObject *object = (NsfObject *)pc.clientData[1]; const char *varName = (const char *)pc.clientData[2]; assert(pc.status == 0); return NsfVarExistsCmd(interp, withArray, object, varName); } else { return TCL_ERROR; } } static int NsfVarGetCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfVarGetCmdIdx].paramDefs, method_definitions[NsfVarGetCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withArray = (int )PTR2INT(pc.clientData[0]); int withNotrace = (int )PTR2INT(pc.clientData[1]); NsfObject *object = (NsfObject *)pc.clientData[2]; Tcl_Obj *varNameObj = (Tcl_Obj *)pc.clientData[3]; assert(pc.status == 0); return NsfVarGetCmd(interp, withArray, withNotrace, object, varNameObj); } else { return TCL_ERROR; } } static int NsfVarImportCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfVarImportCmdIdx].paramDefs, method_definitions[NsfVarImportCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfObject *object = (NsfObject *)pc.clientData[0]; assert(pc.status == 0); return NsfVarImportCmd(interp, object, objc - pc.lastObjc, objv + pc.lastObjc); } else { return TCL_ERROR; } } static int NsfVarSetCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfVarSetCmdIdx].paramDefs, method_definitions[NsfVarSetCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withArray = (int )PTR2INT(pc.clientData[0]); int withNotrace = (int )PTR2INT(pc.clientData[1]); NsfObject *object = (NsfObject *)pc.clientData[2]; Tcl_Obj *varNameObj = (Tcl_Obj *)pc.clientData[3]; Tcl_Obj *valueObj = (Tcl_Obj *)pc.clientData[4]; assert(pc.status == 0); return NsfVarSetCmd(interp, withArray, withNotrace, object, varNameObj, valueObj); } else { return TCL_ERROR; } } static int NsfVarUnsetCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; (void)clientData; if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfVarUnsetCmdIdx].paramDefs, method_definitions[NsfVarUnsetCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withNocomplain = (int )PTR2INT(pc.clientData[0]); NsfObject *object = (NsfObject *)pc.clientData[1]; Tcl_Obj *varNameObj = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); return NsfVarUnsetCmd(interp, withNocomplain, object, varNameObj); } else { return TCL_ERROR; } } static int NsfOAutonameMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfOAutonameMethodIdx].paramDefs, method_definitions[NsfOAutonameMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withInstance = (int )PTR2INT(pc.clientData[0]); int withReset = (int )PTR2INT(pc.clientData[1]); Tcl_Obj *nameObj = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); return NsfOAutonameMethod(interp, object, withInstance, withReset, nameObj); } else { return TCL_ERROR; } } static int NsfOCgetMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (objc != 2) { return NsfArgumentError(interp, "wrong # of arguments:", method_definitions[NsfOCgetMethodIdx].paramDefs, NULL, objv[0]); } return NsfOCgetMethod(interp, object, objv[1]); } static int NsfOClassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (objc < 1 || objc > 2) { return NsfArgumentError(interp, "wrong # of arguments:", method_definitions[NsfOClassMethodIdx].paramDefs, NULL, objv[0]); } return NsfOClassMethod(interp, object, objc == 2 ? objv[1] : NULL); } static int NsfOCleanupMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfOCleanupMethodIdx].paramDefs, NULL, objv[0]); } return NsfOCleanupMethod(interp, object); } static int NsfOConfigureMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfOConfigureMethodIdx].paramDefs, method_definitions[NsfOConfigureMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { return NsfOConfigureMethod(interp, object, objc - pc.lastObjc, objv + pc.lastObjc, objv[0]); } else { return TCL_ERROR; } } static int NsfODestroyMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfODestroyMethodIdx].paramDefs, NULL, objv[0]); } return NsfODestroyMethod(interp, object); } static int NsfOExistsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfOExistsMethodIdx].paramDefs, method_definitions[NsfOExistsMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { const char *varName = (const char *)pc.clientData[0]; assert(pc.status == 0); return NsfOExistsMethod(interp, object, varName); } else { return TCL_ERROR; } } static int NsfOFilterGuardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfOFilterGuardMethodIdx].paramDefs, method_definitions[NsfOFilterGuardMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { const char *filter = (const char *)pc.clientData[0]; Tcl_Obj *guardObj = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); return NsfOFilterGuardMethod(interp, object, filter, guardObj); } else { return TCL_ERROR; } } static int NsfOInstvarMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfOInstvarMethodIdx].paramDefs, method_definitions[NsfOInstvarMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { return NsfOInstvarMethod(interp, object, objc, objv); } else { return TCL_ERROR; } } static int NsfOMixinGuardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfOMixinGuardMethodIdx].paramDefs, method_definitions[NsfOMixinGuardMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { Tcl_Obj *mixinObj = (Tcl_Obj *)pc.clientData[0]; Tcl_Obj *guardObj = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); return NsfOMixinGuardMethod(interp, object, mixinObj, guardObj); } else { return TCL_ERROR; } } static int NsfONoinitMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfONoinitMethodIdx].paramDefs, NULL, objv[0]); } return NsfONoinitMethod(interp, object); } static int NsfORequireNamespaceMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfORequireNamespaceMethodIdx].paramDefs, NULL, objv[0]); } return NsfORequireNamespaceMethod(interp, object); } static int NsfOResidualargsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfOResidualargsMethodIdx].paramDefs, method_definitions[NsfOResidualargsMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { return NsfOResidualargsMethod(interp, object, objc, objv); } else { return TCL_ERROR; } } static int NsfOUplevelMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfOUplevelMethodIdx].paramDefs, method_definitions[NsfOUplevelMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { return NsfOUplevelMethod(interp, object, objc, objv); } else { return TCL_ERROR; } } static int NsfOUpvarMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfOUpvarMethodIdx].paramDefs, method_definitions[NsfOUpvarMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { return NsfOUpvarMethod(interp, object, objc, objv); } else { return TCL_ERROR; } } static int NsfOVolatile1MethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfOVolatile1MethodIdx].paramDefs, NULL, objv[0]); } return NsfOVolatile1Method(interp, object); } static int NsfOVolatileMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfOVolatileMethodIdx].paramDefs, NULL, objv[0]); } return NsfOVolatileMethod(interp, object); } static int NsfObjInfoBaseclassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfObjInfoBaseclassMethodIdx].paramDefs, NULL, objv[0]); } return NsfObjInfoBaseclassMethod(interp, object); } static int NsfObjInfoChildrenMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoChildrenMethodIdx].paramDefs, method_definitions[NsfObjInfoChildrenMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfClass *typeClass = (NsfClass *)pc.clientData[0]; const char *pattern = (const char *)pc.clientData[1]; assert(pc.status == 0); return NsfObjInfoChildrenMethod(interp, object, typeClass, pattern); } else { return TCL_ERROR; } } static int NsfObjInfoClassMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfObjInfoClassMethodIdx].paramDefs, NULL, objv[0]); } return NsfObjInfoClassMethod(interp, object); } static int NsfObjInfoFilterguardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoFilterguardMethodIdx].paramDefs, method_definitions[NsfObjInfoFilterguardMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { const char *filter = (const char *)pc.clientData[0]; assert(pc.status == 0); return NsfObjInfoFilterguardMethod(interp, object, filter); } else { return TCL_ERROR; } } static int NsfObjInfoFiltersMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoFiltersMethodIdx].paramDefs, method_definitions[NsfObjInfoFiltersMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withGuards = (int )PTR2INT(pc.clientData[0]); const char *pattern = (const char *)pc.clientData[1]; assert(pc.status == 0); return NsfObjInfoFiltersMethod(interp, object, withGuards, pattern); } else { return TCL_ERROR; } } static int NsfObjInfoForwardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoForwardMethodIdx].paramDefs, method_definitions[NsfObjInfoForwardMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withDefinition = (int )PTR2INT(pc.clientData[0]); const char *pattern = (const char *)pc.clientData[1]; assert(pc.status == 0); return NsfObjInfoForwardMethod(interp, object, withDefinition, pattern); } else { return TCL_ERROR; } } static int NsfObjInfoHasMixinMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoHasMixinMethodIdx].paramDefs, method_definitions[NsfObjInfoHasMixinMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfClass *class = (NsfClass *)pc.clientData[0]; assert(pc.status == 0); return NsfObjInfoHasMixinMethod(interp, object, class); } else { return TCL_ERROR; } } static int NsfObjInfoHasTypeMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoHasTypeMethodIdx].paramDefs, method_definitions[NsfObjInfoHasTypeMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfClass *class = (NsfClass *)pc.clientData[0]; assert(pc.status == 0); return NsfObjInfoHasTypeMethod(interp, object, class); } else { return TCL_ERROR; } } static int NsfObjInfoHasnamespaceMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfObjInfoHasnamespaceMethodIdx].paramDefs, NULL, objv[0]); } return NsfObjInfoHasnamespaceMethod(interp, object); } static int NsfObjInfoLookupFilterMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoLookupFilterMethodIdx].paramDefs, method_definitions[NsfObjInfoLookupFilterMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { const char *filter = (const char *)pc.clientData[0]; assert(pc.status == 0); return NsfObjInfoLookupFilterMethod(interp, object, filter); } else { return TCL_ERROR; } } static int NsfObjInfoLookupFiltersMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoLookupFiltersMethodIdx].paramDefs, method_definitions[NsfObjInfoLookupFiltersMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withGuards = (int )PTR2INT(pc.clientData[0]); const char *pattern = (const char *)pc.clientData[1]; assert(pc.status == 0); return NsfObjInfoLookupFiltersMethod(interp, object, withGuards, pattern); } else { return TCL_ERROR; } } static int NsfObjInfoLookupMethodMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (objc != 2) { return NsfArgumentError(interp, "wrong # of arguments:", method_definitions[NsfObjInfoLookupMethodMethodIdx].paramDefs, NULL, objv[0]); } return NsfObjInfoLookupMethodMethod(interp, object, objv[1]); } static int NsfObjInfoLookupMethodsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoLookupMethodsMethodIdx].paramDefs, method_definitions[NsfObjInfoLookupMethodsMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { CallprotectionIdx_t withCallprotection = (CallprotectionIdx_t )PTR2INT(pc.clientData[0]); int withIncontext = (int )PTR2INT(pc.clientData[1]); MethodtypeIdx_t withType = (MethodtypeIdx_t )PTR2INT(pc.clientData[2]); int withNomixins = (int )PTR2INT(pc.clientData[3]); int withPath = (int )PTR2INT(pc.clientData[4]); DefinitionsourceIdx_t withSource = (DefinitionsourceIdx_t )PTR2INT(pc.clientData[5]); const char *pattern = (const char *)pc.clientData[6]; assert(pc.status == 0); return NsfObjInfoLookupMethodsMethod(interp, object, withCallprotection, withIncontext, withType, withNomixins, withPath, withSource, pattern); } else { return TCL_ERROR; } } static int NsfObjInfoLookupMixinsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoLookupMixinsMethodIdx].paramDefs, method_definitions[NsfObjInfoLookupMixinsMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withGuards = (int )PTR2INT(pc.clientData[0]); const char *patternString = NULL; NsfObject *patternObject = NULL; Tcl_Obj *pattern = (Tcl_Obj *)pc.clientData[1]; int returnCode; if (GetMatchObject(interp, pattern, objc>1 ? objv[1] : NULL, &patternObject, &patternString) == -1) { if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return TCL_OK; } assert(pc.status == 0); returnCode = NsfObjInfoLookupMixinsMethod(interp, object, withGuards, patternString, patternObject); if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return returnCode; } else { Tcl_Obj *pattern = (Tcl_Obj *)pc.clientData[1]; if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return TCL_ERROR; } } static int NsfObjInfoLookupSlotsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoLookupSlotsMethodIdx].paramDefs, method_definitions[NsfObjInfoLookupSlotsMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { DefinitionsourceIdx_t withSource = (DefinitionsourceIdx_t )PTR2INT(pc.clientData[0]); NsfClass *typeClass = (NsfClass *)pc.clientData[1]; const char *pattern = (const char *)pc.clientData[2]; assert(pc.status == 0); return NsfObjInfoLookupSlotsMethod(interp, object, withSource, typeClass, pattern); } else { return TCL_ERROR; } } static int NsfObjInfoMethodMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoMethodMethodIdx].paramDefs, method_definitions[NsfObjInfoMethodMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { InfomethodsubcmdIdx_t subcmd = (InfomethodsubcmdIdx_t )PTR2INT(pc.clientData[0]); Tcl_Obj *nameObj = (Tcl_Obj *)pc.clientData[1]; assert(pc.status == 0); return NsfObjInfoMethodMethod(interp, object, subcmd, nameObj); } else { return TCL_ERROR; } } static int NsfObjInfoMethodsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoMethodsMethodIdx].paramDefs, method_definitions[NsfObjInfoMethodsMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { CallprotectionIdx_t withCallprotection = (CallprotectionIdx_t )PTR2INT(pc.clientData[0]); MethodtypeIdx_t withType = (MethodtypeIdx_t )PTR2INT(pc.clientData[1]); int withPath = (int )PTR2INT(pc.clientData[2]); const char *pattern = (const char *)pc.clientData[3]; assert(pc.status == 0); return NsfObjInfoMethodsMethod(interp, object, withCallprotection, withType, withPath, pattern); } else { return TCL_ERROR; } } static int NsfObjInfoMixinguardMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoMixinguardMethodIdx].paramDefs, method_definitions[NsfObjInfoMixinguardMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { const char *mixin = (const char *)pc.clientData[0]; assert(pc.status == 0); return NsfObjInfoMixinguardMethod(interp, object, mixin); } else { return TCL_ERROR; } } static int NsfObjInfoMixinsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoMixinsMethodIdx].paramDefs, method_definitions[NsfObjInfoMixinsMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withGuards = (int )PTR2INT(pc.clientData[0]); const char *patternString = NULL; NsfObject *patternObject = NULL; Tcl_Obj *pattern = (Tcl_Obj *)pc.clientData[1]; int returnCode; if (GetMatchObject(interp, pattern, objc>1 ? objv[1] : NULL, &patternObject, &patternString) == -1) { if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return TCL_OK; } assert(pc.status == 0); returnCode = NsfObjInfoMixinsMethod(interp, object, withGuards, patternString, patternObject); if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return returnCode; } else { Tcl_Obj *pattern = (Tcl_Obj *)pc.clientData[1]; if (pattern) { DECR_REF_COUNT2("patternObj", pattern); } return TCL_ERROR; } } static int NsfObjInfoNameMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfObjInfoNameMethodIdx].paramDefs, NULL, objv[0]); } return NsfObjInfoNameMethod(interp, object); } static int NsfObjInfoParentMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[NsfObjInfoParentMethodIdx].paramDefs, NULL, objv[0]); } return NsfObjInfoParentMethod(interp, object); } static int NsfObjInfoPrecedenceMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoPrecedenceMethodIdx].paramDefs, method_definitions[NsfObjInfoPrecedenceMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { int withIntrinsic = (int )PTR2INT(pc.clientData[0]); const char *pattern = (const char *)pc.clientData[1]; assert(pc.status == 0); return NsfObjInfoPrecedenceMethod(interp, object, withIntrinsic, pattern); } else { return TCL_ERROR; } } static int NsfObjInfoSlotobjectsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoSlotobjectsMethodIdx].paramDefs, method_definitions[NsfObjInfoSlotobjectsMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { NsfClass *typeClass = (NsfClass *)pc.clientData[0]; const char *pattern = (const char *)pc.clientData[1]; assert(pc.status == 0); return NsfObjInfoSlotobjectsMethod(interp, object, typeClass, pattern); } else { return TCL_ERROR; } } static int NsfObjInfoVarsMethodStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; NsfObject *object; NSF_nonnull_assert(clientData != NULL); assert(objc > 0); object = (NsfObject *)clientData; if (likely(ArgumentParse(interp, objc, objv, object, objv[0], method_definitions[NsfObjInfoVarsMethodIdx].paramDefs, method_definitions[NsfObjInfoVarsMethodIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { const char *pattern = (const char *)pc.clientData[0]; assert(pc.status == 0); return NsfObjInfoVarsMethod(interp, object, pattern); } else { return TCL_ERROR; } } static Nsf_methodDefinition method_definitions[121] = { {"::nsf::methods::class::alloc", NsfCAllocMethodStub, 1, { {"objectName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::create", NsfCCreateMethodStub, 2, { {"objectName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"args", 0, 1, ConvertToNothing, NULL,NULL,"virtualclassargs",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::dealloc", NsfCDeallocMethodStub, 1, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::filterguard", NsfCFilterGuardMethodStub, 2, { {"filter", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"guard", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::getCachedParameters", NsfCGetCachendParametersMethodStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::mixinguard", NsfCMixinGuardMethodStub, 2, { {"mixin", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"guard", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::new", NsfCNewMethodStub, 2, { {"-childof", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"args", 0, 1, ConvertToNothing, NULL,NULL,"virtualclassargs",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::recreate", NsfCRecreateMethodStub, 2, { {"objectName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"args", 0, 1, ConvertToNothing, NULL,NULL,"virtualclassargs",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::superclass", NsfCSuperclassMethodStub, 1, { {"superclasses", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::info::filterguard", NsfClassInfoFilterguardMethodStub, 1, { {"filter", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::info::filters", NsfClassInfoFiltersMethodStub, 2, { {"-guards", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::info::forward", NsfClassInfoForwardMethodStub, 2, { {"-definition", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::info::heritage", NsfClassInfoHeritageMethodStub, 1, { {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::info::instances", NsfClassInfoInstancesMethodStub, 2, { {"-closure", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, ConvertToObjpattern, NULL,NULL,"objpattern",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::info::method", NsfClassInfoMethodMethodStub, 2, { {"subcmd", NSF_ARG_REQUIRED|NSF_ARG_IS_ENUMERATION, 1, ConvertToInfomethodsubcmd, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"name", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::info::methods", NsfClassInfoMethodsMethodStub, 6, { {"-callprotection", NSF_ARG_IS_ENUMERATION, 1, ConvertToCallprotection, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-closure", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-type", NSF_ARG_IS_ENUMERATION, 1, ConvertToMethodtype, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-path", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-source", NSF_ARG_IS_ENUMERATION, 1, ConvertToDefinitionsource, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::info::mixinof", NsfClassInfoMixinOfMethodStub, 3, { {"-closure", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-scope", NSF_ARG_IS_ENUMERATION, 1, ConvertToMixinscope, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, ConvertToObjpattern, NULL,NULL,"objpattern",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::info::mixinguard", NsfClassInfoMixinguardMethodStub, 1, { {"mixin", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::info::mixins", NsfClassInfoMixinsMethodStub, 4, { {"-closure", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-guards", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-heritage", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, ConvertToObjpattern, NULL,NULL,"objpattern",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::info::slotobjects", NsfClassInfoSlotobjectsMethodStub, 4, { {"-closure", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-source", NSF_ARG_IS_ENUMERATION, 1, ConvertToDefinitionsource, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-type", 0, 1, Nsf_ConvertTo_Class, NULL,NULL,"class",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::info::subclass", NsfClassInfoSubclassMethodStub, 3, { {"-closure", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-dependent", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"pattern", NSF_ARG_NODASHALNUM, 1, ConvertToObjpattern, NULL,NULL,"objpattern",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::class::info::superclass", NsfClassInfoSuperclassMethodStub, 2, { {"-closure", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::method::asmcreate", NsfAsmMethodCreateCmdStub, 8, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"-checkalways", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-inner-namespace", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-per-object", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-reg-object", 0, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"methodName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"arguments", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"body", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::asm::proc", NsfAsmProcCmdStub, 5, { {"-ad", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-checkalways", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"procName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"arguments", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"body", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::__callgrind_dump_stats", NsfCallgrindDumpStatsCmdStub, 1, { {"-name", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::__callgrind_start_instrumentation", NsfCallgrindStartInstrumentationCmdStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::__callgrind_stop_instrumentation", NsfCallgrindStopInstrumentationCmdStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::__callgrind_toggle_collect", NsfCallgrindToggleCollectCmdStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::__callgrind_zero_stats", NsfCallgrindZeroStatsCmdStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::cmd::info", NsfCmdInfoCmdStub, 4, { {"subcmd", NSF_ARG_REQUIRED|NSF_ARG_IS_ENUMERATION, 1, ConvertToInfomethodsubcmd, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-context", 0, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"methodName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::colon", NsfColonCmdStub, 1, { {"args", 0, 1, ConvertToNothing, NULL,NULL,"allargs",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::configure", NsfConfigureCmdStub, 2, { {"option", NSF_ARG_REQUIRED|NSF_ARG_IS_ENUMERATION, 1, ConvertToConfigureoption, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"value", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::current", NsfCurrentCmdStub, 1, { {"option", NSF_ARG_IS_ENUMERATION, 1, ConvertToCurrentoption, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::__db_compile_epoch", NsfDebugCompileEpochStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::__db_get_obj", NsfDebugGetDictStub, 1, { {"obj", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::__db_run_assertions", NsfDebugRunAssertionsCmdStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::__db_show_obj", NsfDebugShowObjStub, 1, { {"obj", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::definitionnamespace", NsfDefinitionNamespaceCmdStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::directdispatch", NsfDirectDispatchCmdStub, 4, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"-frame", NSF_ARG_IS_ENUMERATION, 1, ConvertToFrame, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"command", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"args", 0, 1, ConvertToNothing, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::dispatch", NsfDispatchCmdStub, 5, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"-intrinsic", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-system", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"command", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"args", 0, 1, ConvertToNothing, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::finalize", NsfFinalizeCmdStub, 1, { {"-keepvars", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::method::forward::property", NsfForwardPropertyCmdStub, 5, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"-per-object", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"methodName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"forwardProperty", NSF_ARG_REQUIRED|NSF_ARG_IS_ENUMERATION, 1, ConvertToForwardproperty, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"value", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::interp", NsfInterpObjCmdStub, 2, { {"name", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"args", 0, 1, ConvertToNothing, NULL,NULL,"allargs",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::is", NsfIsCmdStub, 5, { {"-complain", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-configure", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-name", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"constraint", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"value", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::method::alias", NsfMethodAliasCmdStub, 6, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"-per-object", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"methodName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-frame", NSF_ARG_IS_ENUMERATION, 1, ConvertToFrame, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-protection", NSF_ARG_IS_ENUMERATION, 1, ConvertToProtection, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"cmdName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::method::assertion", NsfMethodAssertionCmdStub, 3, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"subcmd", NSF_ARG_REQUIRED|NSF_ARG_IS_ENUMERATION, 1, ConvertToAssertionsubcmd, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"arg", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::method::create", NsfMethodCreateCmdStub, 10, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"-checkalways", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-inner-namespace", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-per-object", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-reg-object", 0, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"methodName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"arguments", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"body", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-precondition", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-postcondition", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::method::delete", NsfMethodDeleteCmdStub, 3, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"-per-object", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"methodName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::method::forward", NsfMethodForwardCmdStub, 11, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"-per-object", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"method", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-default", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-earlybinding", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-onerror", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-prefix", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-frame", NSF_ARG_IS_ENUMERATION, 1, ConvertToFrame, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-verbose", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"target", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"args", 0, 1, ConvertToNothing, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::method::property", NsfMethodPropertyCmdStub, 5, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"-per-object", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"methodName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"methodProperty", NSF_ARG_REQUIRED|NSF_ARG_IS_ENUMERATION, 1, ConvertToMethodproperty, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"value", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::method::registered", NsfMethodRegisteredCmdStub, 1, { {"handle", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::method::setter", NsfMethodSetterCmdStub, 3, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"-per-object", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"parameter", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::my", NsfMyCmdStub, 5, { {"-intrinsic", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-local", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-system", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"methodName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"args", 0, 1, ConvertToNothing, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::nscopyvars", NsfNSCopyVarsCmdStub, 2, { {"fromNs", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"toNs", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::next", NsfNextCmdStub, 1, { {"arguments", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::object::alloc", NsfObjectAllocCmdStub, 3, { {"class", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Class, NULL,NULL,"class",NULL,NULL,NULL,NULL,NULL}, {"name", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"initcmd", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::object::exists", NsfObjectExistsCmdStub, 1, { {"value", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::object::property", NsfObjectPropertyCmdStub, 3, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"objectProperty", NSF_ARG_REQUIRED|NSF_ARG_IS_ENUMERATION, 1, ConvertToObjectproperty, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"value", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::object::qualify", NsfObjectQualifyCmdStub, 1, { {"objectName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::objectsystem::create", NsfObjectSystemCreateCmdStub, 3, { {"rootClass", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"rootMetaClass", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"systemMethods", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::parameter::cache::classinvalidate", NsfParameterCacheClassInvalidateCmdStub, 1, { {"class", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Class, NULL,NULL,"class",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::parameter::cache::objectinvalidate", NsfParameterCacheObjectInvalidateCmdStub, 1, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::parameter::info", NsfParameterInfoCmdStub, 3, { {"subcmd", NSF_ARG_REQUIRED|NSF_ARG_IS_ENUMERATION, 1, ConvertToParametersubcmd, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"spec", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"varname", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::parameter::specs", NsfParameterSpecsCmdStub, 3, { {"-configure", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-nonposargs", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"slotobjs", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::parseargs", NsfParseArgsCmdStub, 3, { {"-asdict", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"argspec", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"arglist", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::proc", NsfProcCmdStub, 7, { {"-ad", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-checkalways", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-debug", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-deprecated", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"procName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"arguments", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"body", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::__profile_clear", NsfProfileClearDataStubStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::__profile_get", NsfProfileGetDataStubStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::__profile_trace", NsfProfileTraceStubStub, 4, { {"-enable", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Boolean, NULL,NULL,"boolean",NULL,NULL,NULL,NULL,NULL}, {"-verbose", 0, 1, Nsf_ConvertTo_Boolean, NULL,NULL,"boolean",NULL,NULL,NULL,NULL,NULL}, {"-dontsave", 0, 1, Nsf_ConvertTo_Boolean, NULL,NULL,"boolean",NULL,NULL,NULL,NULL,NULL}, {"-builtins", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::relation::get", NsfRelationGetCmdStub, 2, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"type", NSF_ARG_REQUIRED|NSF_ARG_IS_ENUMERATION, 1, ConvertToRelationtype, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::relation::set", NsfRelationSetCmdStub, 3, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"type", NSF_ARG_REQUIRED|NSF_ARG_IS_ENUMERATION, 1, ConvertToRelationtype, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"value", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::self", NsfSelfCmdStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::__db_show_stack", NsfShowStackCmdStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::__unset_unknown_args", NsfUnsetUnknownArgsCmdStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::var::exists", NsfVarExistsCmdStub, 3, { {"-array", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"varName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::var::get", NsfVarGetCmdStub, 4, { {"-array", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-notrace", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"varName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::var::import", NsfVarImportCmdStub, 2, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"args", 0, 1, ConvertToNothing, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::var::set", NsfVarSetCmdStub, 5, { {"-array", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-notrace", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"varName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"value", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::var::unset", NsfVarUnsetCmdStub, 3, { {"-nocomplain", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"varName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::autoname", NsfOAutonameMethodStub, 3, { {"-instance", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-reset", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"name", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::cget", NsfOCgetMethodStub, 1, { {"name", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::class", NsfOClassMethodStub, 1, { {"class", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::cleanup", NsfOCleanupMethodStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::configure", NsfOConfigureMethodStub, 1, { {"args", 0, 1, ConvertToNothing, NULL,NULL,"virtualobjectargs",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::destroy", NsfODestroyMethodStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::exists", NsfOExistsMethodStub, 1, { {"varName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::filterguard", NsfOFilterGuardMethodStub, 2, { {"filter", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"guard", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::instvar", NsfOInstvarMethodStub, 1, { {"args", 0, 1, ConvertToNothing, NULL,NULL,"allargs",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::mixinguard", NsfOMixinGuardMethodStub, 2, { {"mixin", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"guard", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::noinit", NsfONoinitMethodStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::requirenamespace", NsfORequireNamespaceMethodStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::residualargs", NsfOResidualargsMethodStub, 1, { {"args", 0, 1, ConvertToNothing, NULL,NULL,"allargs",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::uplevel", NsfOUplevelMethodStub, 1, { {"args", 0, 1, ConvertToNothing, NULL,NULL,"allargs",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::upvar", NsfOUpvarMethodStub, 1, { {"args", 0, 1, ConvertToNothing, NULL,NULL,"allargs",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::volatile1", NsfOVolatile1MethodStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::volatile", NsfOVolatileMethodStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::baseclass", NsfObjInfoBaseclassMethodStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::children", NsfObjInfoChildrenMethodStub, 2, { {"-type", 0, 1, Nsf_ConvertTo_Class, NULL,NULL,"class",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::class", NsfObjInfoClassMethodStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::filterguard", NsfObjInfoFilterguardMethodStub, 1, { {"filter", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::filters", NsfObjInfoFiltersMethodStub, 2, { {"-guards", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::forward", NsfObjInfoForwardMethodStub, 2, { {"-definition", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::hasmixin", NsfObjInfoHasMixinMethodStub, 1, { {"class", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Class, NULL,NULL,"class",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::hastype", NsfObjInfoHasTypeMethodStub, 1, { {"class", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Class, NULL,NULL,"class",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::hasnamespace", NsfObjInfoHasnamespaceMethodStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::lookupfilter", NsfObjInfoLookupFilterMethodStub, 1, { {"filter", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::lookupfilters", NsfObjInfoLookupFiltersMethodStub, 2, { {"-guards", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::lookupmethod", NsfObjInfoLookupMethodMethodStub, 1, { {"name", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::lookupmethods", NsfObjInfoLookupMethodsMethodStub, 7, { {"-callprotection", NSF_ARG_IS_ENUMERATION, 1, ConvertToCallprotection, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-incontext", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-type", NSF_ARG_IS_ENUMERATION, 1, ConvertToMethodtype, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-nomixins", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-path", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"-source", NSF_ARG_IS_ENUMERATION, 1, ConvertToDefinitionsource, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::lookupmixins", NsfObjInfoLookupMixinsMethodStub, 2, { {"-guards", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, ConvertToObjpattern, NULL,NULL,"objpattern",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::lookupslots", NsfObjInfoLookupSlotsMethodStub, 3, { {"-source", NSF_ARG_IS_ENUMERATION, 1, ConvertToDefinitionsource, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-type", 0, 1, Nsf_ConvertTo_Class, NULL,NULL,"class",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::method", NsfObjInfoMethodMethodStub, 2, { {"subcmd", NSF_ARG_REQUIRED|NSF_ARG_IS_ENUMERATION, 1, ConvertToInfomethodsubcmd, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"name", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::methods", NsfObjInfoMethodsMethodStub, 4, { {"-callprotection", NSF_ARG_IS_ENUMERATION, 1, ConvertToCallprotection, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-type", NSF_ARG_IS_ENUMERATION, 1, ConvertToMethodtype, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-path", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::mixinguard", NsfObjInfoMixinguardMethodStub, 1, { {"mixin", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::mixins", NsfObjInfoMixinsMethodStub, 2, { {"-guards", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, ConvertToObjpattern, NULL,NULL,"objpattern",NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::name", NsfObjInfoNameMethodStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::parent", NsfObjInfoParentMethodStub, 0, { {NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::precedence", NsfObjInfoPrecedenceMethodStub, 2, { {"-intrinsic", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::slotobjects", NsfObjInfoSlotobjectsMethodStub, 2, { {"-type", 0, 1, Nsf_ConvertTo_Class, NULL,NULL,"class",NULL,NULL,NULL,NULL,NULL}, {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::nsf::methods::object::info::vars", NsfObjInfoVarsMethodStub, 1, { {"pattern", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {NULL, NULL, 0, {{NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}}} }; ./nsf2.4.0/generic/nsfEnumerationType.c000644 000766 000024 00000013451 13774061267 020630 0ustar00neumannstaff000000 000000 /* * nsfEnumerationType.c -- * * Provide an API for registering enumeration types and obtaining their * domains. Enumeration types are shared by all threads/interps. Access * is governed by a mutex lock. * * Copyright (C) 2014 Gustaf Neumann * Copyright (C) 2016 Stefan Sobernig * * Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #include "nsfInt.h" static Tcl_HashTable enumerationHashTable, *enumerationHashTablePtr = &enumerationHashTable; static int enumerationTypeRefCount = 0; static NsfMutex enumerationMutex = 0; static int Register(const char *domain, Nsf_TypeConverter *converter) nonnull(2); /* *---------------------------------------------------------------------- * Nsf_EnumerationTypeInit -- * * Initialize a hash table to keep the enumeration-type converters. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Nsf_EnumerationTypeInit(void) { NsfMutexLock(&enumerationMutex); if (enumerationTypeRefCount == 0) { Nsf_InitFunPtrHashTable(enumerationHashTablePtr); } enumerationTypeRefCount++; NsfMutexUnlock(&enumerationMutex); } /* *---------------------------------------------------------------------- * Nsf_EnumerationTypeRelease -- * * Release and, eventually, delete the hash table for enumeration-type * converters. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Nsf_EnumerationTypeRelease(void) { NsfMutexLock(&enumerationMutex); if (--enumerationTypeRefCount < 1) { Tcl_DeleteHashTable(enumerationHashTablePtr); } NsfMutexUnlock(&enumerationMutex); } /* *---------------------------------------------------------------------- * Nsf_EnumerationTypeRegister -- * * Registers an array of enumeration types upon NSF initialization. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_EnumerationTypeRegister(Tcl_Interp *UNUSED(interp), Nsf_EnumeratorConverterEntry *typeRecords) { Nsf_EnumeratorConverterEntry *ePtr; nonnull_assert(typeRecords != NULL); for (ePtr = typeRecords; ePtr->converter; ePtr++) { int result = Register(ePtr->domain, ePtr->converter); if (unlikely(result != TCL_OK)) { return result; } } return TCL_OK; } /* *---------------------------------------------------------------------- * Nsf_EnumerationTypeGetDomain -- * * Obtain the domain (i.e., the permitted enumeration literals) for a given * enumeration-type converter. * * Results: * Domain of permitted enumeration literals as a string or NULL, if * not successful. * * Side effects: * Sets a mutex lock. * *---------------------------------------------------------------------- */ const char * Nsf_EnumerationTypeGetDomain(Nsf_TypeConverter *converter) { Tcl_HashEntry *hPtr; /* Tcl_HashSearch hSrch; */ const char* domain = NULL; nonnull_assert(converter != NULL); NsfMutexLock(&enumerationMutex); hPtr = Nsf_FindFunPtrHashEntry(enumerationHashTablePtr, (Nsf_AnyFun *)converter); NsfMutexUnlock(&enumerationMutex); if (hPtr != NULL) { domain = Tcl_GetHashValue(hPtr); } return domain; } /* *---------------------------------------------------------------------- * Register -- * * Register an enumeration-type converter and its domain. * * Results: * A standard Tcl result. * * Side effects: * Sets a mutex lock. * *---------------------------------------------------------------------- */ static int Register(const char *domain, Nsf_TypeConverter *converter) { Tcl_HashEntry *hPtr; int isNew; nonnull_assert(converter != NULL); NsfMutexLock(&enumerationMutex); hPtr = Nsf_CreateFunPtrHashEntry(enumerationHashTablePtr, (Nsf_AnyFun *)converter, &isNew); NsfMutexUnlock(&enumerationMutex); if (isNew != 0) { Tcl_SetHashValue(hPtr, domain); } else { /* * In general, it would make sense to return an error here, but for * multiple interps (e.g. slave interps) the register happens per * interp. So, not even a warning seems here appropriate */ /*return NsfPrintError(interp, "type converter %s is already registered", domain); NsfLog(interp, NSF_LOG_WARN, "type converter %s is already registered", domain); */ } return TCL_OK; } /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * End: */ ./nsf2.4.0/generic/nsfDTrace.h000644 000766 000024 00000007473 13244511101 016631 0ustar00neumannstaff000000 000000 /* * Generated by dtrace(1M). */ #ifndef _NSFDTRACE_H #define _NSFDTRACE_H #include #ifdef __cplusplus extern "C" { #endif #define NSF_STABILITY "___dtrace_stability$nsf$v1$5_5_5_1_1_5_1_1_5_5_5_5_5_5_5" #define NSF_TYPEDEFS "___dtrace_typedefs$nsf$v2$54636c5f4f626a" #if !defined(DTRACE_PROBES_DISABLED) || !DTRACE_PROBES_DISABLED #define NSF_CONFIGURE_PROBE(arg0, arg1) \ do { \ __asm__ volatile(".reference " NSF_TYPEDEFS); \ __dtrace_probe$nsf$configure__probe$v1$63686172202a$63686172202a(arg0, arg1); \ __asm__ volatile(".reference " NSF_STABILITY); \ } while (0) #define NSF_CONFIGURE_PROBE_ENABLED() \ ({ int _r = __dtrace_isenabled$nsf$configure__probe$v1(); \ __asm__ volatile(""); \ _r; }) #define NSF_METHOD_ENTRY(arg0, arg1, arg2, arg3, arg4) \ do { \ __asm__ volatile(".reference " NSF_TYPEDEFS); \ __dtrace_probe$nsf$method__entry$v1$63686172202a$63686172202a$63686172202a$696e74$54636c5f4f626a202a2a(arg0, arg1, arg2, arg3, arg4); \ __asm__ volatile(".reference " NSF_STABILITY); \ } while (0) #define NSF_METHOD_ENTRY_ENABLED() \ ({ int _r = __dtrace_isenabled$nsf$method__entry$v1(); \ __asm__ volatile(""); \ _r; }) #define NSF_METHOD_RETURN(arg0, arg1, arg2, arg3) \ do { \ __asm__ volatile(".reference " NSF_TYPEDEFS); \ __dtrace_probe$nsf$method__return$v1$63686172202a$63686172202a$63686172202a$696e74(arg0, arg1, arg2, arg3); \ __asm__ volatile(".reference " NSF_STABILITY); \ } while (0) #define NSF_METHOD_RETURN_ENABLED() \ ({ int _r = __dtrace_isenabled$nsf$method__return$v1(); \ __asm__ volatile(""); \ _r; }) #define NSF_OBJECT_ALLOC(arg0, arg1) \ do { \ __asm__ volatile(".reference " NSF_TYPEDEFS); \ __dtrace_probe$nsf$object__alloc$v1$63686172202a$63686172202a(arg0, arg1); \ __asm__ volatile(".reference " NSF_STABILITY); \ } while (0) #define NSF_OBJECT_ALLOC_ENABLED() \ ({ int _r = __dtrace_isenabled$nsf$object__alloc$v1(); \ __asm__ volatile(""); \ _r; }) #define NSF_OBJECT_FREE(arg0, arg1) \ do { \ __asm__ volatile(".reference " NSF_TYPEDEFS); \ __dtrace_probe$nsf$object__free$v1$63686172202a$63686172202a(arg0, arg1); \ __asm__ volatile(".reference " NSF_STABILITY); \ } while (0) #define NSF_OBJECT_FREE_ENABLED() \ ({ int _r = __dtrace_isenabled$nsf$object__free$v1(); \ __asm__ volatile(""); \ _r; }) extern void __dtrace_probe$nsf$configure__probe$v1$63686172202a$63686172202a(const char *, const char *); extern int __dtrace_isenabled$nsf$configure__probe$v1(void); extern void __dtrace_probe$nsf$method__entry$v1$63686172202a$63686172202a$63686172202a$696e74$54636c5f4f626a202a2a(const char *, const char *, const char *, int, Tcl_Obj **); extern int __dtrace_isenabled$nsf$method__entry$v1(void); extern void __dtrace_probe$nsf$method__return$v1$63686172202a$63686172202a$63686172202a$696e74(const char *, const char *, const char *, int); extern int __dtrace_isenabled$nsf$method__return$v1(void); extern void __dtrace_probe$nsf$object__alloc$v1$63686172202a$63686172202a(const char *, const char *); extern int __dtrace_isenabled$nsf$object__alloc$v1(void); extern void __dtrace_probe$nsf$object__free$v1$63686172202a$63686172202a(const char *, const char *); extern int __dtrace_isenabled$nsf$object__free$v1(void); #else #define NSF_CONFIGURE_PROBE(arg0, arg1) \ do { \ } while (0) #define NSF_CONFIGURE_PROBE_ENABLED() (0) #define NSF_METHOD_ENTRY(arg0, arg1, arg2, arg3, arg4) \ do { \ } while (0) #define NSF_METHOD_ENTRY_ENABLED() (0) #define NSF_METHOD_RETURN(arg0, arg1, arg2, arg3) \ do { \ } while (0) #define NSF_METHOD_RETURN_ENABLED() (0) #define NSF_OBJECT_ALLOC(arg0, arg1) \ do { \ } while (0) #define NSF_OBJECT_ALLOC_ENABLED() (0) #define NSF_OBJECT_FREE(arg0, arg1) \ do { \ } while (0) #define NSF_OBJECT_FREE_ENABLED() (0) #endif /* !defined(DTRACE_PROBES_DISABLED) || !DTRACE_PROBES_DISABLED */ #ifdef __cplusplus } #endif #endif /* _NSFDTRACE_H */ ./nsf2.4.0/generic/nsfCmdPtr.c000644 000766 000024 00000005556 13463617540 016674 0ustar00neumannstaff000000 000000 /* * nsfCmdPtr.c -- * * Conversion from CmdPtr to Class / Object * * Copyright (C) 2014-2018 Gustaf Neumann * * Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /* * nsfInt is just needed for NSF_INLINE */ #include static NSF_INLINE NsfObject* NsfGetObjectFromCmdPtr(const Tcl_Command cmd) nonnull(1); static NSF_INLINE ClientData NsfGetClientDataFromCmdPtr(const Tcl_Command cmd) nonnull(1); #ifdef NSF_C static NSF_INLINE NsfClass* NsfGetClassFromCmdPtr(const Tcl_Command cmd) nonnull(1); #endif static NSF_INLINE ClientData NsfGetClientDataFromCmdPtr(const Tcl_Command cmd) { ClientData result; nonnull_assert(cmd != NULL); /*fprintf(stderr, "objProc=%p %p\n", Tcl_Command_objProc(cmd), NsfObjDispatch);*/ if (likely(Tcl_Command_objProc(cmd) == NsfObjDispatch)) { result = Tcl_Command_objClientData(cmd); } else { Tcl_Command cmd1 = TclGetOriginalCommand(cmd); if (likely(cmd1 != NULL) && unlikely(Tcl_Command_objProc(cmd1) == NsfObjDispatch)) { result = Tcl_Command_objClientData(cmd1); } else { result = NULL; } } return result; } #ifdef NSF_C static NSF_INLINE NsfClass* NsfGetClassFromCmdPtr(const Tcl_Command cmd) { ClientData cd; NsfClass *result; nonnull_assert(cmd != NULL); cd = NsfGetClientDataFromCmdPtr(cmd); /*fprintf(stderr, "cd=%p\n", cd);*/ if (likely(cd != NULL)) { result = NsfObjectToClass(cd); } else { result = NULL; } return result; } #endif static NSF_INLINE NsfObject* NsfGetObjectFromCmdPtr(const Tcl_Command cmd) { nonnull_assert(cmd != NULL); return (NsfObject*) NsfGetClientDataFromCmdPtr(cmd); } ./nsf2.4.0/generic/aolstub.c000644 000766 000024 00000015204 13774107504 016433 0ustar00neumannstaff000000 000000 /* * aolstub.c -- * * This file provides the stubs needed for the AOLserver, to load NSF. * Please note that at least AOLserver 4.* or NaviServer 4.99.4 or newer * are required. Might have to have to apply a small patch to the * AOLserver as well (available from www.xotcl.org) in order to get it * working. * * Copyright (C) 2006-2013 Zoran Vasiljevic (a) * Copyright (C) 2006-2014 Gustaf Neumann (b) * * (a) Archiware Inc. * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #ifdef AOL_SERVER #include "nsf.h" #include NS_EXPORT int Ns_ModuleVersion = 1; #if NS_MAJOR_VERSION>=4 # define AOL4 #endif /* *---------------------------------------------------------------------------- * * NsNsf_Init -- * * Loads the package for the first time, i.e. in the startup thread. * * Results: * A standard Tcl result. * * Side effects: * Package initialized. Tcl commands created. * *---------------------------------------------------------------------------- */ static int NsNsf_Init(Tcl_Interp *interp, void *context) { static int firsttime = 1; int ret; ret = Nsf_Init(interp); if (firsttime != 0) { if (ret != TCL_OK) { Ns_Log(Warning, "can't load module %s: %s", (char *)context, Tcl_GetStringResult(interp)); } else { Ns_Log(Notice, "%s module version %s", (char*)context, NSF_PATCHLEVELL); /* * Import the Nsf namespace only for the shell after * predefined is through */ Tcl_Import(interp, Tcl_GetGlobalNamespace(interp), "nsf::*", 0); } firsttime = 0; } return ret; } /* *---------------------------------------------------------------------------- * * NsNsf_Init1 -- * * Loads the package in each thread-interpreter. * This is needed since Nsf Class/Object commands are not copied * from the startup thread to the connection (or any other) thread. * during AOLserver initialization and/or thread creation times. * * Why ? * * Simply because these two commands declare a delete callback which is * unsafe to call in any other thread but in the one which created them. * * To understand this, you may need to get yourself acquainted with the * mechanics of the AOLserver, more precisely, with the way Tcl interps * are initialized (dive into nsd/tclinit.c in AOLserver distro). * * So, we made sure (by patching the AOLserver code) that no commands with * delete callbacks declared, are ever copied from the startup thread. * Additionally, we also made sure that AOLserver properly invokes any * AtCreate callbacks. So, instead of activating those callbacks *after* * running the Tcl-initialization script (which is the standard behavior) * we activate them *before*. So we may get a chance to configure the * interpreter correctly for any commands within the init script. * * Proper Nsf usage would be to declare all resources (classes, objects) * at server initialization time and let AOLserver machinery to copy them * (or re-create them, better yet) in each new thread. * Resources created within a thread are automatically garbage-collected * on thread-exit time, so don't create any Nsf resources there. * Create them in the startup thread and they will automatically be copied * for you. * Look in /modules/tcl/nsf for a simple example. * * Results: * A standard Tcl result. * * Side effects: * Tcl commands created. * *---------------------------------------------------------------------------- */ static int NsNsf_Init1(Tcl_Interp *interp, void *notUsed) { int result; #ifndef AOL4 result = Nsf_Init(interp); #else result = TCL_OK; #endif /* * Import the Nsf namespace only for the shell after * predefined is through */ Tcl_Import(interp, Tcl_GetGlobalNamespace(interp), "nsf::*", 1); return result; } /* *---------------------------------------------------------------------------- * * Ns_ModuleInit -- * * Called by the AOLserver when loading shared object file. * * Results: * Standard AOLserver result * * Side effects: * Many. Depends on the package. * *---------------------------------------------------------------------------- */ int Ns_ModuleInit(char *hServer, char *hModule) nonnull(1) nonnull(2); int Ns_ModuleInit(char *hServer, char *hModule) { int ret; assert(hServer != NULL); assert(hModule != NULL); /*Ns_Log(Notice, "+++ ModuleInit", "INIT");*/ ret = Ns_TclInitInterps(hServer, NsNsf_Init, (void*)hModule); if (ret == TCL_OK) { /* * See discussion for NsNsf_Init1 procedure. * Note that you need to patch AOLserver for this to work! * The patch basically forbids copying of C-level commands with * declared delete callbacks. It also runs all AtCreate callbacks * BEFORE AOLserver runs the Tcl script for initializing new interps. * These callbacks are then responsible for setting up the stage * for correct (Nsf) extension startup (including copying any * Nsf resources (classes, objects) created in the startup thread. */ Ns_TclRegisterAtCreate((Ns_TclInterpInitProc *)NsNsf_Init1, NULL); } return ret == TCL_OK ? NS_OK : NS_ERROR; } #else /* avoid empty translation unit */ typedef void empty; #endif /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * End: */ ./nsf2.4.0/generic/nsfError.c.ast.sh000644 000766 000024 00000000754 13543460705 017764 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.1f1226.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfError.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/generic/nsfError.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfError.c.ast.bdump./nsf2.4.0/generic/nsfStubLib.c000644 000766 000024 00000011243 14270742650 017033 0ustar00neumannstaff000000 000000 /* * nsfStubLib.c -- * * Stub object that will be statically linked into extensions of the Next * Scripting Framework. * * Copyright (C) 1998 Paul Duffin * Copyright (C) 2001-2017 Gustaf Neumann (a) * Copyright (C) 2001-2007 Uwe Zdun (a) * * (a) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * The original work by Paul Duffin was licensed as: * * "See the file "tcl-license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES." * * See also https://www.tcl-lang.org/software/tcltk/license.html. * */ /* * We need to ensure that we use the stub macros so that this file contains * no references to any of the stub functions. This will make it possible * to build an extension that references Tcl_InitStubs but doesn't end up * including the rest of the stub functions. */ #ifndef USE_TCL_STUBS # define USE_TCL_STUBS #endif #undef USE_TCL_STUB_PROCS /* * This ensures that the Nsf_InitStubs has a prototype in * nsf.h and is not the macro that turns it into Tcl_PkgRequire */ #ifndef USE_NSF_STUBS # define USE_NSF_STUBS #endif #include "nsfInt.h" #if defined(PRE86) extern NsfStubs *nsfStubsPtr; NsfStubs *nsfStubsPtr = NULL; NsfIntStubs *nsfIntStubsPtr = NULL; #else CONST86 NsfStubs *nsfStubsPtr = NULL; CONST86 NsfIntStubs *nsfIntStubsPtr = NULL; #endif /* *---------------------------------------------------------------------- * * Nsf_InitStubs -- * * Tries to initialize the stub table pointers and ensures that * the correct version of nsf is loaded. * * Results: * The actual version of nsf that satisfies the request, or * NULL to indicate that an error occurred. * * Side effects: * Sets the stub table pointers. * *---------------------------------------------------------------------- */ const char * Nsf_InitStubs(Tcl_Interp *interp, const char *version, int exact) { const char *actualVersion, *packageName = "nsf"; ClientData clientData = NULL; actualVersion = Tcl_PkgRequireEx(interp, "nsf", version, exact, &clientData); if (clientData == NULL) { /* * When the "package require" for NSF fails, we can't use * any NSF calls, like e.g. NsfPrintError(). */ Tcl_ResetResult(interp); Tcl_AppendResult(interp, "Error loading ", packageName, " package: " "package not present, incomplete or misconfigured. " "Maybe NSF was not compiled with COMPILE_NSF_STUBS enabled?", (char*) 0L); actualVersion = NULL; } else { #ifdef PRE86 NsfStubs *stubsPtr; #else CONST86 NsfStubs *stubsPtr; #endif if (actualVersion != NULL) { stubsPtr = clientData; if (stubsPtr->hooks == NULL) { static const char *errMsg = "missing stubInt table pointer"; NsfPrintError(interp, "Error loading package %s: " "(requested version '%s', loaded version '%s'): %s", packageName, version, actualVersion, errMsg); actualVersion = NULL; } else { #ifdef PRE86 NsfIntStubs *intStubsPtr; #else CONST86 NsfIntStubs *intStubsPtr; #endif intStubsPtr = stubsPtr->hooks->nsfIntStubs; nsfStubsPtr = stubsPtr; nsfIntStubsPtr = intStubsPtr; } } } return actualVersion; } /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * End: */ ./nsf2.4.0/generic/nsfAccessInt.h000644 000766 000024 00000015115 14270751353 017352 0ustar00neumannstaff000000 000000 /* * Macros to abstract access to Tcl internals where possible. * This file is part of the Next Scripting Framework * * Copyright (C) 2010-2014 Gustaf Neumann * * Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #define Tcl_Interp_numLevels(interp) ((Interp *)(interp))->numLevels #define Tcl_Interp_framePtr(interp) ((Tcl_CallFrame *)((Interp *)(interp))->framePtr) #define Tcl_Interp_varFramePtr(interp) (((Interp *)(interp))->varFramePtr) #define Tcl_Interp_cmdFramePtr(interp) (((Interp *)(interp))->cmdFramePtr) #define Tcl_Interp_globalNsPtr(interp) ((Tcl_Namespace *)((Interp *)(interp))->globalNsPtr) #define Tcl_Interp_flags(interp) ((Interp *)(interp))->flags #define Tcl_Interp_threadId(interp) ((Interp *)(interp))->threadId #define Tcl_CallFrame_callerPtr(cf) ((Tcl_CallFrame*)((CallFrame *)(cf))->callerPtr) #define Tcl_CallFrame_procPtr(cf) ((CallFrame *)(cf))->procPtr #define Tcl_CallFrame_varTablePtr(cf) ((CallFrame *)(cf))->varTablePtr #define Tcl_CallFrame_level(cf) ((CallFrame *)(cf))->level #define Tcl_CallFrame_isProcCallFrame(cf) ((CallFrame *)(cf))->isProcCallFrame #define Tcl_CallFrame_compiledLocals(cf) ((CallFrame *)(cf))->compiledLocals #define Tcl_CallFrame_numCompiledLocals(cf) ((CallFrame *)(cf))->numCompiledLocals #define Tcl_CallFrame_callerVarPtr(cf) ((Tcl_CallFrame*)((CallFrame *)(cf))->callerVarPtr) #define Tcl_CallFrame_objc(cf) ((CallFrame *)(cf))->objc #define Tcl_CallFrame_objv(cf) ((CallFrame *)(cf))->objv #define Tcl_CallFrame_clientData(cf) ((CallFrame *)(cf))->clientData #define Tcl_CallFrame_nsPtr(cf) ((Tcl_Namespace *)((CallFrame *)(cf))->nsPtr) #define Tcl_Namespace_cmdTablePtr(nsPtr) &((Namespace *)(nsPtr))->cmdTable #define Tcl_Namespace_varTablePtr(nsPtr) &((Namespace *)(nsPtr))->varTable #define Tcl_Namespace_childTablePtr(nsPtr) &((Namespace *)(nsPtr))->childTable #define Tcl_Namespace_activationCount(nsPtr) ((Namespace *)(nsPtr))->activationCount #define Tcl_Namespace_deleteProc(nsPtr) ((Namespace *)(nsPtr))->deleteProc #define Tcl_Namespace_parentPtr(nsPtr) ((Namespace *)(nsPtr))->parentPtr #define Tcl_Namespace_commandPathLength(nsPtr) ((Namespace *)(nsPtr))->commandPathLength #define Tcl_Namespace_commandPathArray(nsPtr) ((Namespace *)(nsPtr))->commandPathArray #define Tcl_Namespace_refCount(nsPtr) ((Namespace *)(nsPtr))->refCount #define Tcl_Namespace_flags(nsPtr) ((Namespace *)(nsPtr))->flags #define Tcl_Command_refCount(cmd) ((Command *)(cmd))->refCount #define Tcl_Command_cmdEpoch(cmd) ((Command *)(cmd))->cmdEpoch #define Tcl_Command_flags(cmd) ((Command *)(cmd))->flags /* the following items could be obtained from Tcl_GetCommandInfoFromToken(cmd, infoPtr) */ #define Tcl_Command_nsPtr(cmd) ((Tcl_Namespace*)(((Command *)(cmd))->nsPtr)) #define Tcl_Command_objProc(cmd) ((Command *)(cmd))->objProc #if defined(NRE) # define Tcl_Command_nreProc(cmd) ((Command *)(cmd))->nreProc #endif #define Tcl_Command_objClientData(cmd) ((Command *)(cmd))->objClientData #define Tcl_Command_proc(cmd) ((Command *)(cmd))->proc #define Tcl_Command_clientData(cmd) ((Command *)(cmd))->clientData #define Tcl_Command_deleteProc(cmd) ((Command *)(cmd))->deleteProc #define Tcl_Command_deleteData(cmd) ((Command *)(cmd))->deleteData /* * The offsetof() macro is an ANSI C library feature. * Workaround for platforms missing offsetof(), e.g. VC++ 6.0 */ #ifndef offsetof # define offsetof(type, field) ((size_t) ((char *) &((type *) 0)->field)) #endif /* * Var Reform Compatibility support. * * Definitions for accessing Tcl variable structures after varreform * in Tcl 8.5. */ #define TclIsCompiledLocalArgument(compiledLocalPtr) ((compiledLocalPtr)->flags & VAR_ARGUMENT) #define TclIsCompiledLocalTemporary(compiledLocalPtr) ((compiledLocalPtr)->flags & VAR_TEMPORARY) #define TclVarHashGetValue(hPtr) ((Var *) ((char *)(hPtr) - offsetof(VarInHash, entry))) #define TclVarHashGetKey(varPtr) (((VarInHash *)(varPtr))->entry.key.objPtr) #define TclVarHashTablePtr(varTablePtr) &(varTablePtr)->table #define TclVarValue(type, varPtr, field) (type *)(varPtr)->value.field #if !defined(Tcl_HashSize) # define Tcl_HashSize(tablePtr) ((tablePtr)->numEntries) #endif /* * Starting with [ebe34426255bef25], in Sep 2020, the macro * CMD_IS_DELETED has been replaced by CMD_DYING. * * See also: * * https://core.tcl-lang.org/tcl/info/ebe34426255bef25 * * https://github.com/tcltk/tcl/commit/23d0bb6cb4e614f464b8e217aa4c7891479e29ff#diff-f9e920c8cca3df7e99caa9e277d717cd736481f4bc54d7df5014a59712ca6397L1731 * */ #if TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION<7 && defined(CMD_IS_DELETED) #define TclIsCommandDeleted(cmdPtr) (((unsigned int)Tcl_Command_flags((cmdPtr)) & CMD_IS_DELETED) != 0u) #else #define TclIsCommandDeleted(cmdPtr) (((unsigned int)Tcl_Command_flags((cmdPtr)) & CMD_DYING) != 0u) #endif /* * Introduced by a name reform in [a722c92a11], in Oct 2021, the macro * TclFreeIntRep has been replaced by TclFreeInternalRep. * * See also: * * https://core.tcl-lang.org/tcl/info/a722c92a1142be4f * * For Tcl 8.7+, we should better switch to using the public interface * to manipulating the internal rep of Tcl_Objs. */ #if defined(PRE9) && !defined(TclFreeInternalRep) # define TclFreeInternalRep(objPtr) TclFreeIntRep((objPtr)) #endif ./nsf2.4.0/generic/stubs8.6/nsfStubInit.c000644 000766 000024 00000007270 14260520102 020612 0ustar00neumannstaff000000 000000 /* * nsfStubInit.c -- * * This file contains the initializers for the stub vectors of the Next * Scripting Framework. * * Copyright (C) 1999-2014 Gustaf Neumann (a, b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #include "nsfInt.h" /* * Remove macros that will interfere with the definitions below. */ /* * WARNING: The contents of this file is automatically generated by the * tools/genStubs.tcl script. Any modifications to the function declarations * below should be made in the generic/tcl.decls script. */ #if defined(PRE86) EXTERN NsfStubs nsfStubs; # else MODULE_SCOPE const NsfStubs nsfStubs; #endif /* !BEGIN!: Do not edit below this line. */ static const NsfIntStubs nsfIntStubs = { TCL_STUB_MAGIC, 0, }; static const NsfStubHooks nsfStubHooks = { &nsfIntStubs }; const NsfStubs nsfStubs = { TCL_STUB_MAGIC, &nsfStubHooks, Nsf_Init, /* 0 */ 0, /* 1 */ NsfIsClass, /* 2 */ NsfGetObject, /* 3 */ NsfGetClass, /* 4 */ NsfDeleteObject, /* 5 */ NsfRemoveObjectMethod, /* 6 */ NsfRemoveClassMethod, /* 7 */ Nsf_ObjSetVar2, /* 8 */ Nsf_ObjGetVar2, /* 9 */ Nsf_UnsetVar2, /* 10 */ NsfDStringVPrintf, /* 11 */ NsfPrintError, /* 12 */ NsfErrInProc, /* 13 */ NsfObjErrType, /* 14 */ NsfStackDump, /* 15 */ NsfSetObjClientData, /* 16 */ NsfGetObjClientData, /* 17 */ NsfSetClassClientData, /* 18 */ NsfGetClassClientData, /* 19 */ NsfRequireObjNamespace, /* 20 */ NsfCallMethodWithArgs, /* 21 */ NsfAddObjectMethod, /* 22 */ NsfAddClassMethod, /* 23 */ NsfCreate, /* 24 */ Nsf_ArgumentParse, /* 25 */ NsfLog, /* 26 */ Nsf_PointerAdd, /* 27 */ Nsf_PointerDelete, /* 28 */ Nsf_PointerTypeRegister, /* 29 */ Nsf_ConvertToBoolean, /* 30 */ Nsf_ConvertToClass, /* 31 */ Nsf_ConvertToInt32, /* 32 */ Nsf_ConvertToInteger, /* 33 */ Nsf_ConvertToObject, /* 34 */ Nsf_ConvertToPointer, /* 35 */ Nsf_ConvertToString, /* 36 */ Nsf_ConvertToTclobj, /* 37 */ Nsf_EnumerationTypeRegister, /* 38 */ Nsf_CmdDefinitionRegister, /* 39 */ NsfArgumentError, /* 40 */ Nsf_DStringPrintf, /* 41 */ }; /* !END!: Do not edit above this line. */ /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * End: */ ./nsf2.4.0/generic/stubs8.6/nsfDecls.h000644 000766 000024 00000036504 14260520102 020112 0ustar00neumannstaff000000 000000 /* * nsfDecls.h -- * * Declarations of functions in the platform independent public Nsf API. * * This file is part of the Next Scripting Framework. * * Copyright (C) 1999-2014 Gustaf Neumann (a, b) * Copyright (C) 1999-2007 Uwe Zdun (a, b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1090, Augasse 2-6 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #ifndef NSF_INCLUDED_NSFDECLS #define NSF_INCLUDED_NSFDECLS /* * WARNING: This file is automatically generated by the tools/genStubs.tcl * script. Any modifications to the function declarations below should be made * in the nsf.decls script. */ /* !BEGIN!: Do not edit below this line. */ #ifdef __cplusplus extern "C" { #endif /* * Exported function declarations: */ /* 0 */ EXTERN int Nsf_Init(Tcl_Interp *interp); /* Slot 1 is reserved */ /* 2 */ EXTERN struct Nsf_Class * NsfIsClass(Tcl_Interp *interp, ClientData cd); /* 3 */ EXTERN struct Nsf_Object * NsfGetObject(Tcl_Interp *interp, const char *name); /* 4 */ EXTERN struct Nsf_Class * NsfGetClass(Tcl_Interp *interp, const char *name); /* 5 */ EXTERN int NsfDeleteObject(Tcl_Interp *interp, struct Nsf_Object *object); /* 6 */ EXTERN int NsfRemoveObjectMethod(Tcl_Interp *interp, struct Nsf_Object *object, const char *methodName); /* 7 */ EXTERN int NsfRemoveClassMethod(Tcl_Interp *interp, struct Nsf_Class *class, const char *methodName); /* 8 */ EXTERN Tcl_Obj * Nsf_ObjSetVar2(struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, Tcl_Obj *valueObj, unsigned int flags); /* 9 */ EXTERN Tcl_Obj * Nsf_ObjGetVar2(struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, unsigned int flags); /* 10 */ EXTERN int Nsf_UnsetVar2(struct Nsf_Object *object, Tcl_Interp *interp, const char *name1, const char *name2, unsigned int flags); /* 11 */ EXTERN void NsfDStringVPrintf(Tcl_DString *dsPtr, const char *fmt, va_list argPtr); /* 12 */ EXTERN int NsfPrintError(Tcl_Interp *interp, const char *fmt, ...); /* 13 */ EXTERN int NsfErrInProc(Tcl_Interp *interp, Tcl_Obj *objName, Tcl_Obj *clName, const char *procName); /* 14 */ EXTERN int NsfObjErrType(Tcl_Interp *interp, const char *context, Tcl_Obj *value, const char *type, Nsf_Param const *NsfObjErrType); /* 15 */ EXTERN void NsfStackDump(Tcl_Interp *interp); /* 16 */ EXTERN void NsfSetObjClientData(Tcl_Interp *interp, Nsf_Object *object, ClientData data); /* 17 */ EXTERN ClientData NsfGetObjClientData(Tcl_Interp *interp, Nsf_Object *object); /* 18 */ EXTERN void NsfSetClassClientData(Tcl_Interp *interp, Nsf_Class *cl, ClientData data); /* 19 */ EXTERN ClientData NsfGetClassClientData(Tcl_Interp *interp, Nsf_Class *cl); /* 20 */ EXTERN void NsfRequireObjNamespace(Tcl_Interp *interp, Nsf_Object *object); /* 21 */ EXTERN int NsfCallMethodWithArgs(Tcl_Interp *interp, Nsf_Object *object, Tcl_Obj *methodObj, Tcl_Obj *arg1, int givenObjc, Tcl_Obj *const objv[], unsigned int flags); /* 22 */ EXTERN int NsfAddObjectMethod(Tcl_Interp *interp, struct Nsf_Object *object, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); /* 23 */ EXTERN int NsfAddClassMethod(Tcl_Interp *interp, struct Nsf_Class *class, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); /* 24 */ EXTERN int NsfCreate(Tcl_Interp *interp, Nsf_Class *class, Tcl_Obj *nameObj, int objc, Tcl_Obj *const objv[]); /* 25 */ EXTERN int Nsf_ArgumentParse(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Nsf_Object *object, Tcl_Obj *procNameObj, Nsf_Param const *paramPtr, int nrParams, int serial, unsigned int processFlags, Nsf_ParseContext *pcPtr); /* 26 */ EXTERN void NsfLog(Tcl_Interp *interp, int requiredLevel, const char *fmt, ...); /* 27 */ EXTERN int Nsf_PointerAdd(Tcl_Interp *interp, char *buffer, size_t size, const char *typeName, void *valuePtr); /* 28 */ EXTERN int Nsf_PointerDelete(const char *key, void *valuePtr, int free); /* 29 */ EXTERN int Nsf_PointerTypeRegister(Tcl_Interp *interp, const char*typeName, int *counterPtr); /* 30 */ EXTERN int Nsf_ConvertToBoolean(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 31 */ EXTERN int Nsf_ConvertToClass(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 32 */ EXTERN int Nsf_ConvertToInt32(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 33 */ EXTERN int Nsf_ConvertToInteger(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 34 */ EXTERN int Nsf_ConvertToObject(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 35 */ EXTERN int Nsf_ConvertToPointer(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 36 */ EXTERN int Nsf_ConvertToString(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 37 */ EXTERN int Nsf_ConvertToTclobj(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 38 */ EXTERN int Nsf_EnumerationTypeRegister(Tcl_Interp *interp, Nsf_EnumeratorConverterEntry *typeRecords); /* 39 */ EXTERN int Nsf_CmdDefinitionRegister(Tcl_Interp *interp, Nsf_methodDefinition *definitionRecords); /* 40 */ EXTERN int NsfArgumentError(Tcl_Interp *interp, const char *errorMsg, Nsf_Param const *paramPtr, Tcl_Obj *cmdNameObj, Tcl_Obj *methodPathObj); /* 41 */ EXTERN void Nsf_DStringPrintf(Tcl_DString *dsPtr, const char *fmt, ...); typedef struct { const struct NsfIntStubs *nsfIntStubs; } NsfStubHooks; typedef struct NsfStubs { int magic; const NsfStubHooks *hooks; int (*nsf_Init) (Tcl_Interp *interp); /* 0 */ void (*reserved1)(void); struct Nsf_Class * (*nsfIsClass) (Tcl_Interp *interp, ClientData cd); /* 2 */ struct Nsf_Object * (*nsfGetObject) (Tcl_Interp *interp, const char *name); /* 3 */ struct Nsf_Class * (*nsfGetClass) (Tcl_Interp *interp, const char *name); /* 4 */ int (*nsfDeleteObject) (Tcl_Interp *interp, struct Nsf_Object *object); /* 5 */ int (*nsfRemoveObjectMethod) (Tcl_Interp *interp, struct Nsf_Object *object, const char *methodName); /* 6 */ int (*nsfRemoveClassMethod) (Tcl_Interp *interp, struct Nsf_Class *class, const char *methodName); /* 7 */ Tcl_Obj * (*nsf_ObjSetVar2) (struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, Tcl_Obj *valueObj, unsigned int flags); /* 8 */ Tcl_Obj * (*nsf_ObjGetVar2) (struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, unsigned int flags); /* 9 */ int (*nsf_UnsetVar2) (struct Nsf_Object *object, Tcl_Interp *interp, const char *name1, const char *name2, unsigned int flags); /* 10 */ void (*nsfDStringVPrintf) (Tcl_DString *dsPtr, const char *fmt, va_list argPtr); /* 11 */ int (*nsfPrintError) (Tcl_Interp *interp, const char *fmt, ...); /* 12 */ int (*nsfErrInProc) (Tcl_Interp *interp, Tcl_Obj *objName, Tcl_Obj *clName, const char *procName); /* 13 */ int (*nsfObjErrType) (Tcl_Interp *interp, const char *context, Tcl_Obj *value, const char *type, Nsf_Param const *NsfObjErrType); /* 14 */ void (*nsfStackDump) (Tcl_Interp *interp); /* 15 */ void (*nsfSetObjClientData) (Tcl_Interp *interp, Nsf_Object *object, ClientData data); /* 16 */ ClientData (*nsfGetObjClientData) (Tcl_Interp *interp, Nsf_Object *object); /* 17 */ void (*nsfSetClassClientData) (Tcl_Interp *interp, Nsf_Class *cl, ClientData data); /* 18 */ ClientData (*nsfGetClassClientData) (Tcl_Interp *interp, Nsf_Class *cl); /* 19 */ void (*nsfRequireObjNamespace) (Tcl_Interp *interp, Nsf_Object *object); /* 20 */ int (*nsfCallMethodWithArgs) (Tcl_Interp *interp, Nsf_Object *object, Tcl_Obj *methodObj, Tcl_Obj *arg1, int givenObjc, Tcl_Obj *const objv[], unsigned int flags); /* 21 */ int (*nsfAddObjectMethod) (Tcl_Interp *interp, struct Nsf_Object *object, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); /* 22 */ int (*nsfAddClassMethod) (Tcl_Interp *interp, struct Nsf_Class *class, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); /* 23 */ int (*nsfCreate) (Tcl_Interp *interp, Nsf_Class *class, Tcl_Obj *nameObj, int objc, Tcl_Obj *const objv[]); /* 24 */ int (*nsf_ArgumentParse) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Nsf_Object *object, Tcl_Obj *procNameObj, Nsf_Param const *paramPtr, int nrParams, int serial, unsigned int processFlags, Nsf_ParseContext *pcPtr); /* 25 */ void (*nsfLog) (Tcl_Interp *interp, int requiredLevel, const char *fmt, ...); /* 26 */ int (*nsf_PointerAdd) (Tcl_Interp *interp, char *buffer, size_t size, const char *typeName, void *valuePtr); /* 27 */ int (*nsf_PointerDelete) (const char *key, void *valuePtr, int free); /* 28 */ int (*nsf_PointerTypeRegister) (Tcl_Interp *interp, const char*typeName, int *counterPtr); /* 29 */ int (*nsf_ConvertToBoolean) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 30 */ int (*nsf_ConvertToClass) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 31 */ int (*nsf_ConvertToInt32) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 32 */ int (*nsf_ConvertToInteger) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 33 */ int (*nsf_ConvertToObject) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 34 */ int (*nsf_ConvertToPointer) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 35 */ int (*nsf_ConvertToString) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 36 */ int (*nsf_ConvertToTclobj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 37 */ int (*nsf_EnumerationTypeRegister) (Tcl_Interp *interp, Nsf_EnumeratorConverterEntry *typeRecords); /* 38 */ int (*nsf_CmdDefinitionRegister) (Tcl_Interp *interp, Nsf_methodDefinition *definitionRecords); /* 39 */ int (*nsfArgumentError) (Tcl_Interp *interp, const char *errorMsg, Nsf_Param const *paramPtr, Tcl_Obj *cmdNameObj, Tcl_Obj *methodPathObj); /* 40 */ void (*nsf_DStringPrintf) (Tcl_DString *dsPtr, const char *fmt, ...); /* 41 */ } NsfStubs; extern const NsfStubs *nsfStubsPtr; #ifdef __cplusplus } #endif #if defined(USE_NSF_STUBS) /* * Inline function declarations: */ #define Nsf_Init \ (nsfStubsPtr->nsf_Init) /* 0 */ /* Slot 1 is reserved */ #define NsfIsClass \ (nsfStubsPtr->nsfIsClass) /* 2 */ #define NsfGetObject \ (nsfStubsPtr->nsfGetObject) /* 3 */ #define NsfGetClass \ (nsfStubsPtr->nsfGetClass) /* 4 */ #define NsfDeleteObject \ (nsfStubsPtr->nsfDeleteObject) /* 5 */ #define NsfRemoveObjectMethod \ (nsfStubsPtr->nsfRemoveObjectMethod) /* 6 */ #define NsfRemoveClassMethod \ (nsfStubsPtr->nsfRemoveClassMethod) /* 7 */ #define Nsf_ObjSetVar2 \ (nsfStubsPtr->nsf_ObjSetVar2) /* 8 */ #define Nsf_ObjGetVar2 \ (nsfStubsPtr->nsf_ObjGetVar2) /* 9 */ #define Nsf_UnsetVar2 \ (nsfStubsPtr->nsf_UnsetVar2) /* 10 */ #define NsfDStringVPrintf \ (nsfStubsPtr->nsfDStringVPrintf) /* 11 */ #define NsfPrintError \ (nsfStubsPtr->nsfPrintError) /* 12 */ #define NsfErrInProc \ (nsfStubsPtr->nsfErrInProc) /* 13 */ #define NsfObjErrType \ (nsfStubsPtr->nsfObjErrType) /* 14 */ #define NsfStackDump \ (nsfStubsPtr->nsfStackDump) /* 15 */ #define NsfSetObjClientData \ (nsfStubsPtr->nsfSetObjClientData) /* 16 */ #define NsfGetObjClientData \ (nsfStubsPtr->nsfGetObjClientData) /* 17 */ #define NsfSetClassClientData \ (nsfStubsPtr->nsfSetClassClientData) /* 18 */ #define NsfGetClassClientData \ (nsfStubsPtr->nsfGetClassClientData) /* 19 */ #define NsfRequireObjNamespace \ (nsfStubsPtr->nsfRequireObjNamespace) /* 20 */ #define NsfCallMethodWithArgs \ (nsfStubsPtr->nsfCallMethodWithArgs) /* 21 */ #define NsfAddObjectMethod \ (nsfStubsPtr->nsfAddObjectMethod) /* 22 */ #define NsfAddClassMethod \ (nsfStubsPtr->nsfAddClassMethod) /* 23 */ #define NsfCreate \ (nsfStubsPtr->nsfCreate) /* 24 */ #define Nsf_ArgumentParse \ (nsfStubsPtr->nsf_ArgumentParse) /* 25 */ #define NsfLog \ (nsfStubsPtr->nsfLog) /* 26 */ #define Nsf_PointerAdd \ (nsfStubsPtr->nsf_PointerAdd) /* 27 */ #define Nsf_PointerDelete \ (nsfStubsPtr->nsf_PointerDelete) /* 28 */ #define Nsf_PointerTypeRegister \ (nsfStubsPtr->nsf_PointerTypeRegister) /* 29 */ #define Nsf_ConvertToBoolean \ (nsfStubsPtr->nsf_ConvertToBoolean) /* 30 */ #define Nsf_ConvertToClass \ (nsfStubsPtr->nsf_ConvertToClass) /* 31 */ #define Nsf_ConvertToInt32 \ (nsfStubsPtr->nsf_ConvertToInt32) /* 32 */ #define Nsf_ConvertToInteger \ (nsfStubsPtr->nsf_ConvertToInteger) /* 33 */ #define Nsf_ConvertToObject \ (nsfStubsPtr->nsf_ConvertToObject) /* 34 */ #define Nsf_ConvertToPointer \ (nsfStubsPtr->nsf_ConvertToPointer) /* 35 */ #define Nsf_ConvertToString \ (nsfStubsPtr->nsf_ConvertToString) /* 36 */ #define Nsf_ConvertToTclobj \ (nsfStubsPtr->nsf_ConvertToTclobj) /* 37 */ #define Nsf_EnumerationTypeRegister \ (nsfStubsPtr->nsf_EnumerationTypeRegister) /* 38 */ #define Nsf_CmdDefinitionRegister \ (nsfStubsPtr->nsf_CmdDefinitionRegister) /* 39 */ #define NsfArgumentError \ (nsfStubsPtr->nsfArgumentError) /* 40 */ #define Nsf_DStringPrintf \ (nsfStubsPtr->nsf_DStringPrintf) /* 41 */ #endif /* defined(USE_NSF_STUBS) */ /* !END!: Do not edit above this line. */ #endif /* NSF_INCLUDED_NSFDECLS */ ./nsf2.4.0/generic/stubs8.6/nsfIntDecls.h000644 000766 000024 00000004767 14260520102 020573 0ustar00neumannstaff000000 000000 /* * nsfIntDecls.h -- * * This file contains the declarations for all unsupported * functions that are exported by the Tcl library. These * interfaces are not guaranteed to remain the same between * versions. Use at your own risk. * * Copyright (C) 1998-2008 Uwe Zdun (a, b) * Copyright (C) 1998-2014 Gustaf Neumann (a, b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #ifndef NSF_INCLUDED_NSFINTDECLS #define NSF_INCLUDED_NSFINTDECLS /* * WARNING: This file is automatically generated by the tools/genStubs.tcl * script. Any modifications to the function declarations below should be made * in the nsfInt.decls script. */ /* !BEGIN!: Do not edit below this line. */ #ifdef __cplusplus extern "C" { #endif /* * Exported function declarations: */ typedef struct NsfIntStubs { int magic; void *hooks; } NsfIntStubs; extern const NsfIntStubs *nsfIntStubsPtr; #ifdef __cplusplus } #endif #if defined(USE_NSF_STUBS) /* * Inline function declarations: */ #endif /* defined(USE_NSF_STUBS) */ /* !END!: Do not edit above this line. */ #endif /* NSF_INCLUDED_NSFINTDECLS */ ./nsf2.4.0/generic/nsfValgrind.c000644 000766 000024 00000000603 14271251157 017231 0ustar00neumannstaff000000 000000 #include /* cmd __valgrind_toggle NsfValgrindToggleCmd {} */ int NsfValgrindToggleCmd(Tcl_Interp *interp) { nonnull_assert(interp != NULL); //Tcl_SetObjResult(interp, Tcl_NewIntObj((int)(((Interp *)interp)->compileEpoch))); return TCL_OK; } /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * End: */ ./nsf2.4.0/generic/mk_predefined.tcl000644 000766 000024 00000004125 13221734221 020103 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh # # A small script file that creates a static array from a Tcl- # script for inclusion in c programs # # Copyright (C) 2010-2014 Gustaf Neumann # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. puts "/* Generated by mk_predefined.tcl */" foreach file $argv { set f [open $file] set content [read $f] close $f regsub -all {\\} $content && content regsub -all "\"" $content {\"} content regsub -all "\[ \]+\n" $content \n content ;# remove trailing space regsub -all "\n\[ \t\]+" $content \n content ;# remove leading space while {[regsub -all "\n#\[^\n\]*\n" $content \n content] > 0} { ;# remove comment lines } regsub -all "\n#\[^\n\]*\n" $content \n content ;# remove comment lines regsub -all "\[\n\]+" $content \n content ;# remove empty lines regsub -all "\n\}" $content "\}" content ;# newlines btwn braces regsub -all "\n" $content "\\n\"\n\"" content puts "static char [file root $file]\[\] =" puts "\"$content\";" } puts "" # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/generic/nsfInt.decls000644 000766 000024 00000003703 13454166031 017067 0ustar00neumannstaff000000 000000 # -*- Tcl -*- # # nsfInt.decls -- # # This file contains the declarations for all internal # functions that are exported by the Next Scripting Framework # (NSF) library via stubs tables. This file is used to # generate nsfIntDecls.h. # # Copyright (C) 1999-2014 Gustaf Neumann (a, b) # Copyright (C) 1999-2007 Uwe Zdun (a, b) # # (a) University of Essen # Specification of Software Systems # Altendorferstrasse 97-101 # D-45143 Essen, Germany # # (b) Vienna University of Economics and Business # Institute of Information Systems and New Media # A-1020, Welthandelsplatz 1 # Vienna, Austria # # This work is licensed under the MIT License https://www.opensource.org/licenses/MIT # # Copyright: # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. # library nsf # Define the unsupported generic interfaces. interface nsfInt # # Functions used within the package, but not considered "public" # #declare 0 generic { #} #declare 1 generic { #} ./nsf2.4.0/generic/stubs8.7/nsfStubInit.c000644 000766 000024 00000007270 14260520102 020613 0ustar00neumannstaff000000 000000 /* * nsfStubInit.c -- * * This file contains the initializers for the stub vectors of the Next * Scripting Framework. * * Copyright (C) 1999-2014 Gustaf Neumann (a, b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #include "nsfInt.h" /* * Remove macros that will interfere with the definitions below. */ /* * WARNING: The contents of this file is automatically generated by the * tools/genStubs.tcl script. Any modifications to the function declarations * below should be made in the generic/tcl.decls script. */ #if defined(PRE86) EXTERN NsfStubs nsfStubs; # else MODULE_SCOPE const NsfStubs nsfStubs; #endif /* !BEGIN!: Do not edit below this line. */ static const NsfIntStubs nsfIntStubs = { TCL_STUB_MAGIC, 0, }; static const NsfStubHooks nsfStubHooks = { &nsfIntStubs }; const NsfStubs nsfStubs = { TCL_STUB_MAGIC, &nsfStubHooks, Nsf_Init, /* 0 */ 0, /* 1 */ NsfIsClass, /* 2 */ NsfGetObject, /* 3 */ NsfGetClass, /* 4 */ NsfDeleteObject, /* 5 */ NsfRemoveObjectMethod, /* 6 */ NsfRemoveClassMethod, /* 7 */ Nsf_ObjSetVar2, /* 8 */ Nsf_ObjGetVar2, /* 9 */ Nsf_UnsetVar2, /* 10 */ NsfDStringVPrintf, /* 11 */ NsfPrintError, /* 12 */ NsfErrInProc, /* 13 */ NsfObjErrType, /* 14 */ NsfStackDump, /* 15 */ NsfSetObjClientData, /* 16 */ NsfGetObjClientData, /* 17 */ NsfSetClassClientData, /* 18 */ NsfGetClassClientData, /* 19 */ NsfRequireObjNamespace, /* 20 */ NsfCallMethodWithArgs, /* 21 */ NsfAddObjectMethod, /* 22 */ NsfAddClassMethod, /* 23 */ NsfCreate, /* 24 */ Nsf_ArgumentParse, /* 25 */ NsfLog, /* 26 */ Nsf_PointerAdd, /* 27 */ Nsf_PointerDelete, /* 28 */ Nsf_PointerTypeRegister, /* 29 */ Nsf_ConvertToBoolean, /* 30 */ Nsf_ConvertToClass, /* 31 */ Nsf_ConvertToInt32, /* 32 */ Nsf_ConvertToInteger, /* 33 */ Nsf_ConvertToObject, /* 34 */ Nsf_ConvertToPointer, /* 35 */ Nsf_ConvertToString, /* 36 */ Nsf_ConvertToTclobj, /* 37 */ Nsf_EnumerationTypeRegister, /* 38 */ Nsf_CmdDefinitionRegister, /* 39 */ NsfArgumentError, /* 40 */ Nsf_DStringPrintf, /* 41 */ }; /* !END!: Do not edit above this line. */ /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * End: */ ./nsf2.4.0/generic/stubs8.7/nsfDecls.h000644 000766 000024 00000036504 14260520102 020113 0ustar00neumannstaff000000 000000 /* * nsfDecls.h -- * * Declarations of functions in the platform independent public Nsf API. * * This file is part of the Next Scripting Framework. * * Copyright (C) 1999-2014 Gustaf Neumann (a, b) * Copyright (C) 1999-2007 Uwe Zdun (a, b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1090, Augasse 2-6 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #ifndef NSF_INCLUDED_NSFDECLS #define NSF_INCLUDED_NSFDECLS /* * WARNING: This file is automatically generated by the tools/genStubs.tcl * script. Any modifications to the function declarations below should be made * in the nsf.decls script. */ /* !BEGIN!: Do not edit below this line. */ #ifdef __cplusplus extern "C" { #endif /* * Exported function declarations: */ /* 0 */ EXTERN int Nsf_Init(Tcl_Interp *interp); /* Slot 1 is reserved */ /* 2 */ EXTERN struct Nsf_Class * NsfIsClass(Tcl_Interp *interp, ClientData cd); /* 3 */ EXTERN struct Nsf_Object * NsfGetObject(Tcl_Interp *interp, const char *name); /* 4 */ EXTERN struct Nsf_Class * NsfGetClass(Tcl_Interp *interp, const char *name); /* 5 */ EXTERN int NsfDeleteObject(Tcl_Interp *interp, struct Nsf_Object *object); /* 6 */ EXTERN int NsfRemoveObjectMethod(Tcl_Interp *interp, struct Nsf_Object *object, const char *methodName); /* 7 */ EXTERN int NsfRemoveClassMethod(Tcl_Interp *interp, struct Nsf_Class *class, const char *methodName); /* 8 */ EXTERN Tcl_Obj * Nsf_ObjSetVar2(struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, Tcl_Obj *valueObj, unsigned int flags); /* 9 */ EXTERN Tcl_Obj * Nsf_ObjGetVar2(struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, unsigned int flags); /* 10 */ EXTERN int Nsf_UnsetVar2(struct Nsf_Object *object, Tcl_Interp *interp, const char *name1, const char *name2, unsigned int flags); /* 11 */ EXTERN void NsfDStringVPrintf(Tcl_DString *dsPtr, const char *fmt, va_list argPtr); /* 12 */ EXTERN int NsfPrintError(Tcl_Interp *interp, const char *fmt, ...); /* 13 */ EXTERN int NsfErrInProc(Tcl_Interp *interp, Tcl_Obj *objName, Tcl_Obj *clName, const char *procName); /* 14 */ EXTERN int NsfObjErrType(Tcl_Interp *interp, const char *context, Tcl_Obj *value, const char *type, Nsf_Param const *NsfObjErrType); /* 15 */ EXTERN void NsfStackDump(Tcl_Interp *interp); /* 16 */ EXTERN void NsfSetObjClientData(Tcl_Interp *interp, Nsf_Object *object, ClientData data); /* 17 */ EXTERN ClientData NsfGetObjClientData(Tcl_Interp *interp, Nsf_Object *object); /* 18 */ EXTERN void NsfSetClassClientData(Tcl_Interp *interp, Nsf_Class *cl, ClientData data); /* 19 */ EXTERN ClientData NsfGetClassClientData(Tcl_Interp *interp, Nsf_Class *cl); /* 20 */ EXTERN void NsfRequireObjNamespace(Tcl_Interp *interp, Nsf_Object *object); /* 21 */ EXTERN int NsfCallMethodWithArgs(Tcl_Interp *interp, Nsf_Object *object, Tcl_Obj *methodObj, Tcl_Obj *arg1, int givenObjc, Tcl_Obj *const objv[], unsigned int flags); /* 22 */ EXTERN int NsfAddObjectMethod(Tcl_Interp *interp, struct Nsf_Object *object, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); /* 23 */ EXTERN int NsfAddClassMethod(Tcl_Interp *interp, struct Nsf_Class *class, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); /* 24 */ EXTERN int NsfCreate(Tcl_Interp *interp, Nsf_Class *class, Tcl_Obj *nameObj, int objc, Tcl_Obj *const objv[]); /* 25 */ EXTERN int Nsf_ArgumentParse(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Nsf_Object *object, Tcl_Obj *procNameObj, Nsf_Param const *paramPtr, int nrParams, int serial, unsigned int processFlags, Nsf_ParseContext *pcPtr); /* 26 */ EXTERN void NsfLog(Tcl_Interp *interp, int requiredLevel, const char *fmt, ...); /* 27 */ EXTERN int Nsf_PointerAdd(Tcl_Interp *interp, char *buffer, size_t size, const char *typeName, void *valuePtr); /* 28 */ EXTERN int Nsf_PointerDelete(const char *key, void *valuePtr, int free); /* 29 */ EXTERN int Nsf_PointerTypeRegister(Tcl_Interp *interp, const char*typeName, int *counterPtr); /* 30 */ EXTERN int Nsf_ConvertToBoolean(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 31 */ EXTERN int Nsf_ConvertToClass(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 32 */ EXTERN int Nsf_ConvertToInt32(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 33 */ EXTERN int Nsf_ConvertToInteger(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 34 */ EXTERN int Nsf_ConvertToObject(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 35 */ EXTERN int Nsf_ConvertToPointer(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 36 */ EXTERN int Nsf_ConvertToString(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 37 */ EXTERN int Nsf_ConvertToTclobj(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 38 */ EXTERN int Nsf_EnumerationTypeRegister(Tcl_Interp *interp, Nsf_EnumeratorConverterEntry *typeRecords); /* 39 */ EXTERN int Nsf_CmdDefinitionRegister(Tcl_Interp *interp, Nsf_methodDefinition *definitionRecords); /* 40 */ EXTERN int NsfArgumentError(Tcl_Interp *interp, const char *errorMsg, Nsf_Param const *paramPtr, Tcl_Obj *cmdNameObj, Tcl_Obj *methodPathObj); /* 41 */ EXTERN void Nsf_DStringPrintf(Tcl_DString *dsPtr, const char *fmt, ...); typedef struct { const struct NsfIntStubs *nsfIntStubs; } NsfStubHooks; typedef struct NsfStubs { int magic; const NsfStubHooks *hooks; int (*nsf_Init) (Tcl_Interp *interp); /* 0 */ void (*reserved1)(void); struct Nsf_Class * (*nsfIsClass) (Tcl_Interp *interp, ClientData cd); /* 2 */ struct Nsf_Object * (*nsfGetObject) (Tcl_Interp *interp, const char *name); /* 3 */ struct Nsf_Class * (*nsfGetClass) (Tcl_Interp *interp, const char *name); /* 4 */ int (*nsfDeleteObject) (Tcl_Interp *interp, struct Nsf_Object *object); /* 5 */ int (*nsfRemoveObjectMethod) (Tcl_Interp *interp, struct Nsf_Object *object, const char *methodName); /* 6 */ int (*nsfRemoveClassMethod) (Tcl_Interp *interp, struct Nsf_Class *class, const char *methodName); /* 7 */ Tcl_Obj * (*nsf_ObjSetVar2) (struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, Tcl_Obj *valueObj, unsigned int flags); /* 8 */ Tcl_Obj * (*nsf_ObjGetVar2) (struct Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, unsigned int flags); /* 9 */ int (*nsf_UnsetVar2) (struct Nsf_Object *object, Tcl_Interp *interp, const char *name1, const char *name2, unsigned int flags); /* 10 */ void (*nsfDStringVPrintf) (Tcl_DString *dsPtr, const char *fmt, va_list argPtr); /* 11 */ int (*nsfPrintError) (Tcl_Interp *interp, const char *fmt, ...); /* 12 */ int (*nsfErrInProc) (Tcl_Interp *interp, Tcl_Obj *objName, Tcl_Obj *clName, const char *procName); /* 13 */ int (*nsfObjErrType) (Tcl_Interp *interp, const char *context, Tcl_Obj *value, const char *type, Nsf_Param const *NsfObjErrType); /* 14 */ void (*nsfStackDump) (Tcl_Interp *interp); /* 15 */ void (*nsfSetObjClientData) (Tcl_Interp *interp, Nsf_Object *object, ClientData data); /* 16 */ ClientData (*nsfGetObjClientData) (Tcl_Interp *interp, Nsf_Object *object); /* 17 */ void (*nsfSetClassClientData) (Tcl_Interp *interp, Nsf_Class *cl, ClientData data); /* 18 */ ClientData (*nsfGetClassClientData) (Tcl_Interp *interp, Nsf_Class *cl); /* 19 */ void (*nsfRequireObjNamespace) (Tcl_Interp *interp, Nsf_Object *object); /* 20 */ int (*nsfCallMethodWithArgs) (Tcl_Interp *interp, Nsf_Object *object, Tcl_Obj *methodObj, Tcl_Obj *arg1, int givenObjc, Tcl_Obj *const objv[], unsigned int flags); /* 21 */ int (*nsfAddObjectMethod) (Tcl_Interp *interp, struct Nsf_Object *object, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); /* 22 */ int (*nsfAddClassMethod) (Tcl_Interp *interp, struct Nsf_Class *class, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags); /* 23 */ int (*nsfCreate) (Tcl_Interp *interp, Nsf_Class *class, Tcl_Obj *nameObj, int objc, Tcl_Obj *const objv[]); /* 24 */ int (*nsf_ArgumentParse) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Nsf_Object *object, Tcl_Obj *procNameObj, Nsf_Param const *paramPtr, int nrParams, int serial, unsigned int processFlags, Nsf_ParseContext *pcPtr); /* 25 */ void (*nsfLog) (Tcl_Interp *interp, int requiredLevel, const char *fmt, ...); /* 26 */ int (*nsf_PointerAdd) (Tcl_Interp *interp, char *buffer, size_t size, const char *typeName, void *valuePtr); /* 27 */ int (*nsf_PointerDelete) (const char *key, void *valuePtr, int free); /* 28 */ int (*nsf_PointerTypeRegister) (Tcl_Interp *interp, const char*typeName, int *counterPtr); /* 29 */ int (*nsf_ConvertToBoolean) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 30 */ int (*nsf_ConvertToClass) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 31 */ int (*nsf_ConvertToInt32) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 32 */ int (*nsf_ConvertToInteger) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 33 */ int (*nsf_ConvertToObject) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 34 */ int (*nsf_ConvertToPointer) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 35 */ int (*nsf_ConvertToString) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 36 */ int (*nsf_ConvertToTclobj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr); /* 37 */ int (*nsf_EnumerationTypeRegister) (Tcl_Interp *interp, Nsf_EnumeratorConverterEntry *typeRecords); /* 38 */ int (*nsf_CmdDefinitionRegister) (Tcl_Interp *interp, Nsf_methodDefinition *definitionRecords); /* 39 */ int (*nsfArgumentError) (Tcl_Interp *interp, const char *errorMsg, Nsf_Param const *paramPtr, Tcl_Obj *cmdNameObj, Tcl_Obj *methodPathObj); /* 40 */ void (*nsf_DStringPrintf) (Tcl_DString *dsPtr, const char *fmt, ...); /* 41 */ } NsfStubs; extern const NsfStubs *nsfStubsPtr; #ifdef __cplusplus } #endif #if defined(USE_NSF_STUBS) /* * Inline function declarations: */ #define Nsf_Init \ (nsfStubsPtr->nsf_Init) /* 0 */ /* Slot 1 is reserved */ #define NsfIsClass \ (nsfStubsPtr->nsfIsClass) /* 2 */ #define NsfGetObject \ (nsfStubsPtr->nsfGetObject) /* 3 */ #define NsfGetClass \ (nsfStubsPtr->nsfGetClass) /* 4 */ #define NsfDeleteObject \ (nsfStubsPtr->nsfDeleteObject) /* 5 */ #define NsfRemoveObjectMethod \ (nsfStubsPtr->nsfRemoveObjectMethod) /* 6 */ #define NsfRemoveClassMethod \ (nsfStubsPtr->nsfRemoveClassMethod) /* 7 */ #define Nsf_ObjSetVar2 \ (nsfStubsPtr->nsf_ObjSetVar2) /* 8 */ #define Nsf_ObjGetVar2 \ (nsfStubsPtr->nsf_ObjGetVar2) /* 9 */ #define Nsf_UnsetVar2 \ (nsfStubsPtr->nsf_UnsetVar2) /* 10 */ #define NsfDStringVPrintf \ (nsfStubsPtr->nsfDStringVPrintf) /* 11 */ #define NsfPrintError \ (nsfStubsPtr->nsfPrintError) /* 12 */ #define NsfErrInProc \ (nsfStubsPtr->nsfErrInProc) /* 13 */ #define NsfObjErrType \ (nsfStubsPtr->nsfObjErrType) /* 14 */ #define NsfStackDump \ (nsfStubsPtr->nsfStackDump) /* 15 */ #define NsfSetObjClientData \ (nsfStubsPtr->nsfSetObjClientData) /* 16 */ #define NsfGetObjClientData \ (nsfStubsPtr->nsfGetObjClientData) /* 17 */ #define NsfSetClassClientData \ (nsfStubsPtr->nsfSetClassClientData) /* 18 */ #define NsfGetClassClientData \ (nsfStubsPtr->nsfGetClassClientData) /* 19 */ #define NsfRequireObjNamespace \ (nsfStubsPtr->nsfRequireObjNamespace) /* 20 */ #define NsfCallMethodWithArgs \ (nsfStubsPtr->nsfCallMethodWithArgs) /* 21 */ #define NsfAddObjectMethod \ (nsfStubsPtr->nsfAddObjectMethod) /* 22 */ #define NsfAddClassMethod \ (nsfStubsPtr->nsfAddClassMethod) /* 23 */ #define NsfCreate \ (nsfStubsPtr->nsfCreate) /* 24 */ #define Nsf_ArgumentParse \ (nsfStubsPtr->nsf_ArgumentParse) /* 25 */ #define NsfLog \ (nsfStubsPtr->nsfLog) /* 26 */ #define Nsf_PointerAdd \ (nsfStubsPtr->nsf_PointerAdd) /* 27 */ #define Nsf_PointerDelete \ (nsfStubsPtr->nsf_PointerDelete) /* 28 */ #define Nsf_PointerTypeRegister \ (nsfStubsPtr->nsf_PointerTypeRegister) /* 29 */ #define Nsf_ConvertToBoolean \ (nsfStubsPtr->nsf_ConvertToBoolean) /* 30 */ #define Nsf_ConvertToClass \ (nsfStubsPtr->nsf_ConvertToClass) /* 31 */ #define Nsf_ConvertToInt32 \ (nsfStubsPtr->nsf_ConvertToInt32) /* 32 */ #define Nsf_ConvertToInteger \ (nsfStubsPtr->nsf_ConvertToInteger) /* 33 */ #define Nsf_ConvertToObject \ (nsfStubsPtr->nsf_ConvertToObject) /* 34 */ #define Nsf_ConvertToPointer \ (nsfStubsPtr->nsf_ConvertToPointer) /* 35 */ #define Nsf_ConvertToString \ (nsfStubsPtr->nsf_ConvertToString) /* 36 */ #define Nsf_ConvertToTclobj \ (nsfStubsPtr->nsf_ConvertToTclobj) /* 37 */ #define Nsf_EnumerationTypeRegister \ (nsfStubsPtr->nsf_EnumerationTypeRegister) /* 38 */ #define Nsf_CmdDefinitionRegister \ (nsfStubsPtr->nsf_CmdDefinitionRegister) /* 39 */ #define NsfArgumentError \ (nsfStubsPtr->nsfArgumentError) /* 40 */ #define Nsf_DStringPrintf \ (nsfStubsPtr->nsf_DStringPrintf) /* 41 */ #endif /* defined(USE_NSF_STUBS) */ /* !END!: Do not edit above this line. */ #endif /* NSF_INCLUDED_NSFDECLS */ ./nsf2.4.0/generic/stubs8.7/nsfIntDecls.h000644 000766 000024 00000004767 14260520102 020574 0ustar00neumannstaff000000 000000 /* * nsfIntDecls.h -- * * This file contains the declarations for all unsupported * functions that are exported by the Tcl library. These * interfaces are not guaranteed to remain the same between * versions. Use at your own risk. * * Copyright (C) 1998-2008 Uwe Zdun (a, b) * Copyright (C) 1998-2014 Gustaf Neumann (a, b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #ifndef NSF_INCLUDED_NSFINTDECLS #define NSF_INCLUDED_NSFINTDECLS /* * WARNING: This file is automatically generated by the tools/genStubs.tcl * script. Any modifications to the function declarations below should be made * in the nsfInt.decls script. */ /* !BEGIN!: Do not edit below this line. */ #ifdef __cplusplus extern "C" { #endif /* * Exported function declarations: */ typedef struct NsfIntStubs { int magic; void *hooks; } NsfIntStubs; extern const NsfIntStubs *nsfIntStubsPtr; #ifdef __cplusplus } #endif #if defined(USE_NSF_STUBS) /* * Inline function declarations: */ #endif /* defined(USE_NSF_STUBS) */ /* !END!: Do not edit above this line. */ #endif /* NSF_INCLUDED_NSFINTDECLS */ ./nsf2.4.0/generic/nsfError.c000644 000766 000024 00000041552 14260772560 016570 0ustar00neumannstaff000000 000000 /* * nsfError.c -- * * Error reporting functions for the Next Scripting Framework. * * Copyright (C) 1999-2018 Gustaf Neumann (a, b) * Copyright (C) 1999-2007 Uwe Zdun (a, b) * Copyright (C) 2011-2016 Stefan Sobernig (b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #include "nsfInt.h" /* function prototypes */ Tcl_Obj *NsfParamDefsSyntax( Tcl_Interp *interp, Nsf_Param const *paramsPtr, NsfObject *contextObject, const char *pattern ) nonnull(1) nonnull(2) returns_nonnull; /* *---------------------------------------------------------------------- * * NsfDStringVPrintf -- * * Appends a formatted value to a Tcl_DString. This function * continues until having allocated sufficient memory. * * Note: The current implementation assumes C99 compliant * implementations of vs*printf() for all runtimes other than * MSVC. For MSVC, the pre-C99 vs*printf() implementations are * explicitly set by Tcl internals (see tclInt.h). For * MinGW/MinGW-w64, __USE_MINGW_ANSI_STDIO must be set (see * nsfInt.h). * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void NsfDStringVPrintf(Tcl_DString *dsPtr, const char *fmt, va_list argPtr) { int result; TCL_SIZE_T avail, offset; va_list argPtrCopy; bool failure; /* * Tcl_DStringLength returns the current length *without* the * terminating character (NTC). */ offset = Tcl_DStringLength(dsPtr); #if defined(_MSC_VER) /* * Pre-C99: currently free storage, excluding NTC */ avail = dsPtr->spaceAvl - offset - 1; #else /* * C99: currently free storage, including NTC */ avail = dsPtr->spaceAvl - offset; #endif /* * 1) Copy va_list so that the caller's copy is untouched. * 2) Run vsnprintf() eagerly. */ va_copy(argPtrCopy, argPtr); result = vsnprintf(dsPtr->string + offset, (size_t)avail, fmt, argPtrCopy); va_end(argPtrCopy); #if defined(_MSC_VER) /* * vs*printf() in pre-C99 runtimes (MSVC up to VS13, VS15 and newer * in backward-compat mode) return -1 upon overflowing the buffer. * * Note: Tcl via tclInt.h precludes the use of pre-C99 mode even in * VS15 and newer (vsnprintf points to backwards compatible, pre-C99 * _vsnprintf). */ failure = (result == -1); #else /* * vs*printf() in C99 compliant runtimes (GCC, CLANG, MSVC in VS15 * and newer, MinGW/MinGW-w64 with __USE_MINGW_ANSI_STDIO) returns * the number of chars to be written if the buffer would be * sufficiently large (excluding NTC, the terminating null * character). A return value of -1 signals an encoding error. */ assert(result > -1); /* no encoding error */ failure = (result >= (int)avail); #endif if (likely(! failure)) { /* * vsnprintf() copied all content, adjust the Tcl_DString length. */ Tcl_DStringSetLength(dsPtr, offset + (TCL_SIZE_T)result); } else { TCL_SIZE_T addedStringLength; /* * vsnprintf() could not copy all content, content was truncated. * Determine the required length (for MSVC), adjust the Tcl_DString * size, and copy again. */ #if defined(_MSC_VER) va_copy(argPtrCopy, argPtr); addedStringLength = _vscprintf(fmt, argPtrCopy); va_end(argPtrCopy); #else addedStringLength = (TCL_SIZE_T)result; #endif Tcl_DStringSetLength(dsPtr, offset + addedStringLength); #if defined(_MSC_VER) /* * Pre-C99: currently free storage, excluding NTC */ avail = dsPtr->spaceAvl - offset - 1; #else /* * C99: currently free storage, including NTC */ avail = dsPtr->spaceAvl - offset; #endif va_copy(argPtrCopy, argPtr); result = vsnprintf(dsPtr->string + offset, (size_t)avail, fmt, argPtrCopy); va_end(argPtrCopy); #if defined(_MSC_VER) failure = (result == -1); #else failure = (result == -1 || (TCL_SIZE_T)result >= avail); #endif #if defined(NDEBUG) if (unlikely(failure)) { Tcl_Panic("writing string-formatting output to a dynamic Tcl string failed"); } #endif assert(! failure); } } /* *---------------------------------------------------------------------- * Nsf_DStringPrintf -- * * Append a sequence of values using a format string. * * Results: * Pointer to the current string value. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Nsf_DStringPrintf(Tcl_DString *dsPtr, const char *fmt, ...) { va_list ap; nonnull_assert(dsPtr != NULL); nonnull_assert(fmt != NULL); va_start(ap, fmt); NsfDStringVPrintf(dsPtr, fmt, ap); va_end(ap); } /* *---------------------------------------------------------------------- * * NsfDStringArgv -- * * Appends argument vector to an initialized Tcl_DString. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void NsfDStringArgv( Tcl_DString *dsPtr, int objc, Tcl_Obj *const objv[] ) { nonnull_assert(dsPtr != NULL); nonnull_assert(objv != NULL); if (objc > 0) { int i; Tcl_DStringAppendElement(dsPtr, NsfMethodName(objv[0])); for (i = 1; i < objc; i++) { Tcl_DStringAppendElement(dsPtr, ObjStr(objv[i])); } } } /* *---------------------------------------------------------------------- * * NsfPrintError -- * * Produce a formatted error message with a printf-like semantics. * * Results: * Returns always TCL_ERROR. * * Side effects: * Leaves an error message in the interpreter's result object. * *---------------------------------------------------------------------- */ int NsfPrintError(Tcl_Interp *interp, const char *fmt, ...) { va_list ap; Tcl_DString ds; Tcl_DStringInit(&ds); va_start(ap, fmt); NsfDStringVPrintf(&ds, fmt, ap); va_end(ap); Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds))); Tcl_DStringFree(&ds); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * NsfErrInProc -- * * Produce a general error message when an error occurs in a * scripted NSF method. * * Results: * Returns always TCL_ERROR. * * Side effects: * Leaves an error message in the interpreter's result object. * *---------------------------------------------------------------------- */ int NsfErrInProc( Tcl_Interp *interp, Tcl_Obj *objName, Tcl_Obj *clName, const char *procName ) { Tcl_DString errMsg; const char *cName, *space; Tcl_DStringInit(&errMsg); Tcl_DStringAppend(&errMsg, "\n ", TCL_INDEX_NONE); if (clName != NULL) { cName = ObjStr(clName); space = " "; } else { cName = ""; space = ""; } Tcl_DStringAppend(&errMsg, ObjStr(objName), TCL_INDEX_NONE); Tcl_DStringAppend(&errMsg, space, TCL_INDEX_NONE); Tcl_DStringAppend(&errMsg, cName, TCL_INDEX_NONE); Tcl_DStringAppend(&errMsg, "->", 2); Tcl_DStringAppend(&errMsg, procName, TCL_INDEX_NONE); Tcl_AddErrorInfo (interp, Tcl_DStringValue(&errMsg)); Tcl_DStringFree(&errMsg); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * NsfObjWrongArgs -- * * Produce a general error message when an NSF method is called with * an invalid argument list (wrong number of arguments). * * Results: * Returns always TCL_ERROR. * * Side effects: * Leaves an error message in the interpreter's result object. * *---------------------------------------------------------------------- */ int NsfObjWrongArgs( Tcl_Interp *interp, const char *msg, Tcl_Obj *cmdNameObj, Tcl_Obj *methodPathObj, const char *arglist ) { bool need_space = NSF_FALSE; Tcl_DString ds; nonnull_assert(interp != NULL); nonnull_assert(msg != NULL); Tcl_DStringInit(&ds); Nsf_DStringPrintf(&ds, "%s should be \"", msg); if (cmdNameObj != NULL) { Tcl_DStringAppend(&ds, ObjStr(cmdNameObj), TCL_INDEX_NONE); need_space = NSF_TRUE; } if (methodPathObj != NULL) { if (need_space) { Tcl_DStringAppend(&ds, " ", 1); } INCR_REF_COUNT(methodPathObj); Tcl_DStringAppend(&ds, ObjStr(methodPathObj), TCL_INDEX_NONE); DECR_REF_COUNT(methodPathObj); need_space = NSF_TRUE; } if (arglist != NULL) { if (need_space) { Tcl_DStringAppend(&ds, " ", 1); } Tcl_DStringAppend(&ds, arglist, TCL_INDEX_NONE); } Tcl_DStringAppend(&ds, "\"", 1); Tcl_SetObjResult(interp, Tcl_NewStringObj(ds.string, ds.length)); Tcl_DStringFree(&ds); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * NsfArgumentError -- * * Produce a wrong-number-of-arguments error based on a parameter * definition. * * Results: * Returns always TCL_ERROR. * * Side effects: * Leaves an error message in the interpreter's result object. * *---------------------------------------------------------------------- */ int NsfArgumentError( Tcl_Interp *interp, const char *errorMsg, Nsf_Param const *paramPtr, Tcl_Obj *cmdNameObj, Tcl_Obj *methodPathObj ) { Tcl_Obj *argStringObj = NsfParamDefsSyntax(interp, paramPtr, NULL, NULL); nonnull_assert(interp != NULL); nonnull_assert(errorMsg != NULL); nonnull_assert(paramPtr != NULL); NsfObjWrongArgs(interp, errorMsg, cmdNameObj, methodPathObj, ObjStr(argStringObj)); DECR_REF_COUNT2("paramDefsObj", argStringObj); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * NsfUnexpectedArgumentError -- * * Produce an error message on an unexpected argument (most likely, * too many arguments) * * Results: * Returns always TCL_ERROR. * * Side effects: * Leaves an error message in the interpreter's result object. * *---------------------------------------------------------------------- */ int NsfUnexpectedArgumentError(Tcl_Interp *interp, const char *argumentString, Nsf_Object *object, Nsf_Param const *paramPtr, Tcl_Obj *methodPathObj) { Tcl_DString ds, *dsPtr = &ds; nonnull_assert(interp != NULL); nonnull_assert(argumentString != NULL); nonnull_assert(paramPtr != NULL); nonnull_assert(methodPathObj != NULL); DSTRING_INIT(dsPtr); Nsf_DStringPrintf(dsPtr, "invalid argument '%s', maybe too many arguments;", argumentString); NsfArgumentError(interp, Tcl_DStringValue(dsPtr), paramPtr, (object != NULL) ? object->cmdName : NULL, methodPathObj); DSTRING_FREE(dsPtr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * NsfUnexpectedNonposArgumentError -- * * Produce an error message on an invalid non-positional argument. * * Results: * Returns always TCL_ERROR. * * Side effects: * Leaves an error message in the interpreter's result object. * *---------------------------------------------------------------------- */ int NsfUnexpectedNonposArgumentError( Tcl_Interp *interp, const char *argumentString, Nsf_Object *object, Nsf_Param const *currentParamPtr, Nsf_Param const *paramPtr, Tcl_Obj *methodPathObj ) { Tcl_DString ds, *dsPtr = &ds; const Nsf_Param *pPtr; nonnull_assert(interp != NULL); nonnull_assert(argumentString != NULL); nonnull_assert(currentParamPtr != NULL); nonnull_assert(paramPtr != NULL); nonnull_assert(methodPathObj != NULL); DSTRING_INIT(dsPtr); Nsf_DStringPrintf(dsPtr, "invalid non-positional argument '%s', valid are: ", argumentString); for (pPtr = currentParamPtr; (pPtr->name != NULL) && (*pPtr->name == '-'); pPtr ++) { if (pPtr->flags & NSF_ARG_NOCONFIG) { continue; } Tcl_DStringAppend(dsPtr, pPtr->name, TCL_INDEX_NONE); Tcl_DStringAppend(dsPtr, ", ", TCL_INDEX_NONE); } Tcl_DStringSetLength(dsPtr, Tcl_DStringLength(dsPtr) - 2); Tcl_DStringAppend(dsPtr, ";\n", 2); NsfArgumentError(interp, Tcl_DStringValue(dsPtr), paramPtr, (object != NULL) ? object->cmdName : NULL, methodPathObj); DSTRING_FREE(dsPtr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * NsfDispatchClientDataError -- * * Produce an error message when a method was not dispatched on an * object. * * Results: * Returns always TCL_ERROR. * * Side effects: * Leaves an error message in the interpreter's result object. * *---------------------------------------------------------------------- */ int NsfDispatchClientDataError( Tcl_Interp *interp, ClientData clientData, const char *what, const char *methodName ) { nonnull_assert(interp != NULL); nonnull_assert(what != NULL); nonnull_assert(methodName != NULL); if (clientData != NULL) { return NsfPrintError(interp, "method %s not dispatched on valid %s", methodName, what); } else { return NsfNoCurrentObjectError(interp, methodName); } } /* *---------------------------------------------------------------------- * * NsfNoCurrentObjectError -- * * Produce an error message when a method/command was called * outside the context of an object or a method. The passed in * methodName is NULL when e.g. "self" is called outside of an NSF * context. * * Results: * Returns always TCL_ERROR. * * Side effects: * Leaves an error message in the interpreter's result object. * *---------------------------------------------------------------------- */ int NsfNoCurrentObjectError(Tcl_Interp *interp, const char *methodName) { nonnull_assert(interp != NULL); return NsfPrintError(interp, "no current object; %s called outside the context of a Next Scripting method", (methodName != NULL) ? methodName : "command"); } /* *---------------------------------------------------------------------- * * NsfObjErrType -- * * Produce a general error message when an NSF method is called with * an invalid value for some argument. * * Results: * Returns always TCL_ERROR. * * Side effects: * Leaves an error message in the interpreter's result object. * *---------------------------------------------------------------------- */ int NsfObjErrType( Tcl_Interp *interp, const char *context, Tcl_Obj *value, const char *type, Nsf_Param const *NsfObjErrType ) { bool isNamed = (NsfObjErrType && (NsfObjErrType->flags & NSF_ARG_UNNAMED) == 0); int returnValue = !isNamed && NsfObjErrType && (NsfObjErrType->flags & NSF_ARG_IS_RETURNVALUE); TCL_SIZE_T errMsgLen; const char *prevErrMsg = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &errMsgLen); Tcl_DString ds; Tcl_DStringInit(&ds); if (errMsgLen > 0) { Tcl_DStringAppend(&ds, prevErrMsg, errMsgLen); Tcl_DStringAppend(&ds, " 2nd error: ", TCL_INDEX_NONE); } if (context != NULL) { Tcl_DStringAppend(&ds, context, TCL_INDEX_NONE); Tcl_DStringAppend(&ds, ": ", 2); } Nsf_DStringPrintf(&ds, "expected %s but got \"%s\"", type, ObjStr(value)); if (isNamed) { Nsf_DStringPrintf(&ds, " for parameter \"%s\"", NsfObjErrType->name); } else if (returnValue != 0) { Tcl_DStringAppend(&ds, " as return value", TCL_INDEX_NONE); } Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds))); Tcl_DStringFree(&ds); return TCL_ERROR; } /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 72 * indent-tabs-mode: nil * eval: (c-guess) * End: */ ./nsf2.4.0/generic/nsfObj.c.ast.sh000644 000766 000024 00000000746 13543460711 017403 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.5f5a3c.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfObj.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/generic/nsfObj.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfObj.c.ast.bdump./nsf2.4.0/generic/nsfInt.h000644 000766 000024 00000127701 14275243061 016232 0ustar00neumannstaff000000 000000 /* * nsfInt.h -- * * Declarations of the internally used API Functions of the Next * Scripting Framework. * * Copyright (C) 1999-2018 Gustaf Neumann (a, b) * Copyright (C) 1999-2007 Uwe Zdun (a, b) * Copyright (C) 2011-2018 Stefan Sobernig (b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License * https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #ifndef NSF_INCLUDE_nsf_int_h_ #define NSF_INCLUDE_nsf_int_h_ #ifndef EXTERN # ifdef __cplusplus # define EXTERN extern "C" TCL_STORAGE_CLASS # else # define EXTERN extern TCL_STORAGE_CLASS # endif #endif #ifndef CONST86 # define CONST86 const #endif /* * Well behaved compiler with C99 support should define __STDC_VERSION__ */ #if defined(__STDC_VERSION__) # if __STDC_VERSION__ >= 199901L # define NSF_HAVE_C99 # endif #endif /* * Starting with Visual Studio 2013, Microsoft provides C99 library support. */ #if (!defined(NSF_HAVE_C99)) && defined(_MSC_VER) && (_MSC_VER >= 1800) # define NSF_HAVE_C99 #endif #if defined(_MSC_VER) && _MSC_VER < 1800 # undef HAVE_INTTYPES_H #else # define HAVE_INTTYPES_H 1 #include #endif #if !defined(HAVE_INTTYPES_H) # if !defined(__PRIPTR_PREFIX) # if defined(_LP64) || defined(_I32LPx) || defined(HAVE_64BIT) || defined(_WIN64) || defined(_WIN32) # if defined(_WIN32) # define __PRIPTR_PREFIX "ll" # else # define __PRIPTR_PREFIX "l" # endif # else # define __PRIPTR_PREFIX # endif # endif # ifndef PRIxPTR # define PRIxPTR __PRIPTR_PREFIX "x" # endif #endif /* * Boolean type "bool" and constants */ #ifdef NSF_HAVE_C99 /* * C99 */ # include # define NSF_TRUE true # define NSF_FALSE false #else /* * Not C99 */ # if defined(__cplusplus) /* * C++ is similar to C99, but no include necessary */ # define NSF_TRUE true # define NSF_FALSE false # else /* * If everything fails, use int type and int values for bool */ typedef int bool; # define NSF_TRUE 1 # define NSF_FALSE 0 # endif #endif /* * MinGW and MinGW-w64 provide both MSCRT-compliant and ANSI-compliant * implementations of certain I/O operations (e.g., *printf()). By * setting __USE_MINGW_ANSI_STDIO to 1 explicitly, we can assume the * ANSI versions. * * Note: It is sufficient to test for __MINGW32__ to trap all MinGW * tool chains, including 64-bit versions. See * https://sourceforge.net/p/predef/wiki/Compilers/#mingw-and-mingw-w64 */ #if defined(__MINGW32__) && !defined(__USE_MINGW_ANSI_STDIO) # define __USE_MINGW_ANSI_STDIO 1 #endif #include #include "nsf.h" #include #include #include #if defined(HAVE_TCL_COMPILE_H) # include #endif #if NSF__GNUC_PREREQ(2, 95) /* Use gcc branch prediction hint to minimize cost of e.g. DTrace * ENABLED checks. */ # define unlikely(x) (__builtin_expect((x), 0)) # define likely(x) (__builtin_expect((x), 1)) #else # define unlikely(x) (x) # define likely(x) (x) #endif #if NSF__GNUC_PREREQ(3, 3) # define nonnull(ARGS) __attribute__((__nonnull__(ARGS))) #else # define nonnull(ARGS) #endif #if NSF__GNUC_PREREQ(4, 9) # define returns_nonnull __attribute__((returns_nonnull)) #else # define returns_nonnull #endif #define nonnull_assert(assertion) assert((assertion)) /* * Trie to use gcc __attribute__ unused and mangle the name, so the * attribute could not be used, if declared as unused. */ #ifdef UNUSED #elif NSF__GNUC_PREREQ(2, 7) # define UNUSED(x) UNUSED_ ## x __attribute__((unused)) #elif defined(__LCLINT__) # define UNUSED(x) /*@unused@*/ (x) #else # define UNUSED(x) (x) #endif #if defined(NSF_DTRACE) # include "nsfDTrace.h" # define NSF_DTRACE_METHOD_ENTRY_ENABLED() unlikely(NSF_METHOD_ENTRY_ENABLED()) # define NSF_DTRACE_METHOD_RETURN_ENABLED() unlikely(NSF_METHOD_RETURN_ENABLED()) # define NSF_DTRACE_OBJECT_ALLOC_ENABLED() unlikely(NSF_OBJECT_ALLOC_ENABLED()) # define NSF_DTRACE_OBJECT_FREE_ENABLED() unlikely(NSF_OBJECT_FREE_ENABLED()) # define NSF_DTRACE_CONFIGURE_PROBE_ENABLED() unlikely(NSF_CONFIGURE_PROBE_ENABLED()) # define NSF_DTRACE_METHOD_ENTRY(a0, a1, a2, a3, a4) NSF_METHOD_ENTRY((a0), (a1), (a2), (a3), (a4)) # define NSF_DTRACE_METHOD_RETURN(a0, a1, a2, a3) NSF_METHOD_RETURN((a0), (a1), (a2), (a3)) # define NSF_DTRACE_OBJECT_ALLOC(a0, a1) NSF_OBJECT_ALLOC((a0), (a1)) # define NSF_DTRACE_OBJECT_FREE(a0, a1) NSF_OBJECT_FREE((a0), (a1)) # define NSF_DTRACE_CONFIGURE_PROBE(a0, a1) NSF_CONFIGURE_PROBE((a0), (a1)) #else # define NSF_DTRACE_METHOD_ENTRY_ENABLED() 0 # define NSF_DTRACE_METHOD_RETURN_ENABLED() 0 # define NSF_DTRACE_OBJECT_ALLOC_ENABLED() 0 # define NSF_DTRACE_OBJECT_FREE_ENABLED() 0 # define NSF_DTRACE_CONFIGURE_PROBE_ENABLED() 0 # define NSF_DTRACE_METHOD_ENTRY(a0, a1, a2, a3, a4) {} # define NSF_DTRACE_METHOD_RETURN(a0, a1, a2, a3) {} # define NSF_DTRACE_OBJECT_ALLOC(a0, a1) {} # define NSF_DTRACE_OBJECT_FREE(a0, a1) {} # define NSF_DTRACE_CONFIGURE_PROBE(a0, a1) {} #endif #ifdef DMALLOC # include "dmalloc.h" #endif /* * Macros */ #if defined(PRE86) # define Tcl_NRCallObjProc(interp, proc, cd, objc, objv) \ (*(proc))((cd), (interp), (objc), (objv)) #endif #ifdef NSF_MEM_COUNT EXTERN int nsfMemCountInterpCounter; typedef struct NsfMemCounter { int peak; int count; } NsfMemCounter; # define MEM_COUNT_ALLOC(id,p) NsfMemCountAlloc((id), (p)) # define MEM_COUNT_FREE(id,p) NsfMemCountFree((id), (p)) # define MEM_COUNT_INIT() NsfMemCountInit() # define MEM_COUNT_RELEASE() NsfMemCountRelease() #else # define MEM_COUNT_ALLOC(id,p) # define MEM_COUNT_FREE(id,p) # define MEM_COUNT_INIT() # define MEM_COUNT_RELEASE() #endif # define STRING_NEW(target, p, l) {char *tempValue = ckalloc((unsigned)(l)+1u); strncpy((tempValue), (p), (l)+1u); *((tempValue)+(l)) = '\0'; target = tempValue; MEM_COUNT_ALLOC(#target, (target));} # define STRING_FREE(key, p) MEM_COUNT_FREE((key), (p)); ckfree((char*)(p)) #define DSTRING_INIT(dsPtr) Tcl_DStringInit(dsPtr); MEM_COUNT_ALLOC("DString",(dsPtr)) #define DSTRING_FREE(dsPtr) \ if ((dsPtr)->string != (dsPtr)->staticSpace) {Tcl_DStringFree(dsPtr);} MEM_COUNT_FREE("DString",(dsPtr)) #if defined(USE_ASSOC_DATA) # define RUNTIME_STATE(interp) ((NsfRuntimeState*)Tcl_GetAssocData((interp), "NsfRuntimeState", NULL)) #else # define RUNTIME_STATE(interp) ((NsfRuntimeState*)((Interp*)(interp))->globalNsPtr->clientData) #endif #define nr_elements(arr) ((int) (sizeof(arr) / sizeof((arr)[0]))) /* * Tcl 8.6 uses (unsigned) per default */ # define NEW(type) \ (type *)ckalloc((unsigned)sizeof(type)); MEM_COUNT_ALLOC(#type, NULL) # define NEW_ARRAY(type,n) \ (type *)ckalloc((unsigned)sizeof(type)*(unsigned)(n)); MEM_COUNT_ALLOC(#type "*", NULL) # define FREE(type, var) \ ckfree((char*) (var)); MEM_COUNT_FREE(#type,(var)) #define isAbsolutePath(m) (*(m) == ':' && (m)[1] == ':') #define isArgsString(m) (\ *(m) == 'a' && (m)[1] == 'r' && (m)[2] == 'g' && (m)[3] == 's' && \ (m)[4] == '\0') #define isBodyString(m) (\ *(m) == 'b' && (m)[1] == 'o' && (m)[2] == 'd' && (m)[3] == 'y' && \ (m)[4] == '\0') #define isCheckString(m) (\ *(m) == 'c' && (m)[1] == 'h' && (m)[2] == 'e' && (m)[3] == 'c' && \ (m)[4] == 'k' && (m)[5] == '\0') #define isCheckObjString(m) (\ *(m) == 'c' && (m)[1] == 'h' && (m)[2] == 'e' && (m)[3] == 'c' && \ (m)[4] == 'k' && (m)[5] == 'o' && (m)[6] == 'b' && (m)[7] == 'j' && \ (m)[8] == '\0') #define isCreateString(m) (\ *(m) == 'c' && (m)[1] == 'r' && (m)[2] == 'e' && (m)[3] == 'a' && \ (m)[4] == 't' && (m)[5] == 'e' && (m)[6] == '\0') #define isTypeString(m) (\ *(m) == 't' && (m)[1] == 'y' && (m)[2] == 'p' && (m)[3] == 'e' && \ (m)[4] == '\0') #define isObjectString(m) (\ *(m) == 'o' && (m)[1] == 'b' && (m)[2] == 'j' && (m)[3] == 'e' && \ (m)[4] == 'c' && (m)[5] == 't' && (m)[6] == '\0') #define isClassString(m) (\ *(m) == 'c' && (m)[1] == 'l' && (m)[2] == 'a' && (m)[3] == 's' && \ (m)[4] == 's' && (m)[5] == '\0') #if (defined(sun) || defined(__hpux)) && !defined(__GNUC__) # define USE_ALLOCA #endif #if defined(__IBMC__) && !defined(__GNUC__) # if __IBMC__ >= 0x0306 # define USE_ALLOCA # else # define USE_MALLOC # endif #endif #if defined(VISUAL_CC) # define USE_MALLOC #endif #if 1 # define NSF_STACK_ALLOCATED_OBJV 32 # define ALLOC_ON_STACK(type,n,var) \ type *(var); type stack_allocated_##var[NSF_STACK_ALLOCATED_OBJV]; \ if (likely((n) < NSF_STACK_ALLOCATED_OBJV)) { (var) = &stack_allocated_##var[0]; } else { (var) = NEW_ARRAY(type, (n)); } # define FREE_ON_STACK(type, var) \ if ((var) != &stack_allocated_##var[0]) { FREE(type *, var);} #elif defined(__GNUC__) && !defined(USE_ALLOCA) && !defined(USE_MALLOC) # if !defined(NDEBUG) # define ALLOC_ON_STACK(type,n,var) \ int __##var##_count = (n); type __##var[(n)+2]; \ type *(var) = __##var + 1; (var)[-1] = var[__##var##_count] = (type)0xdeadbeaf # define FREE_ON_STACK(type,var) \ assert((var)[-1] == (var)[__##var##_count] && (var)[-1] == (type)0xdeadbeaf) # else # define ALLOC_ON_STACK(type,n,var) type (var)[(n)] # define FREE_ON_STACK(type,var) # endif #elif defined(USE_ALLOCA) # define ALLOC_ON_STACK(type,n,var) type *(var) = (type *)alloca((n)*sizeof(type)) # define FREE_ON_STACK(type,var) #else # define ALLOC_ON_STACK(type,n,var) type *(var) = (type *)ckalloc((n)*sizeof(type)) # define FREE_ON_STACK(type,var) ckfree((char*)(var)) #endif #ifdef USE_ALLOCA # include #endif #ifdef PRE9 # define NSF_PLAUSIBLE_REFCOUNT(A) ((A)->refCount >= 0) # define NSF_PLAUSIBLE_LENGTH(A) ((A)->length >= 0) #else # define NSF_PLAUSIBLE_REFCOUNT(A) ((A)->refCount < (size_t)-100) # define NSF_PLAUSIBLE_LENGTH(A) ((A)->length < (size_t)-100) #endif #if !defined(NDEBUG) # define ISOBJ(o) ((o) != NULL && ISOBJ_(o)) # define ISOBJ_(o) ((o) != (void*)0xdeadbeaf && (((o)->typePtr != NULL) ? ((o)->typePtr->name != NULL) : ((o)->bytes != NULL)) && (((o)->bytes != NULL) ? NSF_PLAUSIBLE_LENGTH(o) : 1) && NSF_PLAUSIBLE_REFCOUNT(o)) #else # define ISOBJ(o) #endif #define NSF_ABBREV_MIN_CHARS 4 /* * This was defined to be inline for anything !sun or __IBMC__ >= 0x0306, * but __hpux should also be checked - switched to only allow in gcc - JH */ #if defined(__GNUC__) && !defined(__STRICT_ANSI__) # define NSF_INLINE inline #else # define NSF_INLINE #endif #ifdef USE_TCL_STUBS # define DECR_REF_COUNT(A) \ MEM_COUNT_FREE("INCR_REF_COUNT" #A,(A)); assert(NSF_PLAUSIBLE_REFCOUNT(A)); \ Tcl_DecrRefCount(A) # define DECR_REF_COUNT2(name,A) \ MEM_COUNT_FREE("INCR_REF_COUNT-" name,(A)); assert(NSF_PLAUSIBLE_REFCOUNT(A)); \ Tcl_DecrRefCount(A) #else # define DECR_REF_COUNT(A) \ MEM_COUNT_FREE("INCR_REF_COUNT" #A,(A)); TclDecrRefCount(A) # define DECR_REF_COUNT2(name,A) \ MEM_COUNT_FREE("INCR_REF_COUNT-" name,(A)); TclDecrRefCount(A) #endif #define INCR_REF_COUNT(A) MEM_COUNT_ALLOC("INCR_REF_COUNT" #A,(A)); Tcl_IncrRefCount((A)) #define INCR_REF_COUNT2(name,A) \ /*fprintf(stderr, "c '%s'\n", ObjStr(A));*/ \ MEM_COUNT_ALLOC("INCR_REF_COUNT-" name,(A)); Tcl_IncrRefCount((A)) #define ObjStr(obj) ((obj)->bytes) ? ((obj)->bytes) : Tcl_GetString(obj) #define ObjTypeStr(obj) (((obj)->typePtr != NULL) ? ((obj)->typePtr->name) : "NONE") #define ClassName(cl) (((cl) != NULL) ? ObjStr((cl)->object.cmdName) : "NULL") #define ClassName_(cl) (ObjStr((cl)->object.cmdName)) #define ObjectName(object) (((object) != NULL) ? ObjStr((object)->cmdName) : "NULL") #define ObjectName_(object) (ObjStr((object)->cmdName)) #ifdef OBJDELETION_TRACE # define PRINTOBJ(ctx,object) \ fprintf(stderr, " %s %p %s oid=%p teardown=%p destroyCalled=%d\n", \ (ctx),(void *)(object),(object)->teardown?ObjStr((object)->cmdName):"(deleted)", \ (void *)(object)->id, (void *)(object)->teardown, \ ((object)->flags & NSF_DESTROY_CALLED)) #else # define PRINTOBJ(ctx,object) #endif /* * When an integer is printed, it might take so many digits */ #define LONG_AS_STRING 32 /* TCL_CONTINUE is defined as 4, from 5 on we can use app-specific return codes */ #define NSF_CHECK_FAILED 6 /* The NsfConfigEnabled() macro allows for querying whether a configuration macro (NSF_*; see above) is actually defined (and whether it expands to 1). This macro can be used both in CPP expressions (e.g., "#if NsfConfigEnabled(...)") and in C expressions (e.g., "if(NsfConfigEnabled(...))") */ #define NsfConfigEnabled__NOOP(...) #define NsfConfigEnabled__open ( #define NsfConfigEnabled__close ) #define NsfConfigEnabled__caller(macro, args) macro args #define NsfConfigEnabled__helper_1 NsfConfigEnabled__close NsfConfigEnabled__open 1 #define NsfConfigEnabled__(x) (NsfConfigEnabled__caller(NsfConfigEnabled__NOOP, \ NsfConfigEnabled__open \ NsfConfigEnabled__helper_##x \ NsfConfigEnabled__close) + 0) #define NsfConfigEnabled_(x) NsfConfigEnabled__(x) #define NsfConfigEnabled(x) NsfConfigEnabled_(NSF_##x) /* * * Next Scripting Structures * */ /* * Filter structures */ typedef struct NsfFilterStack { Tcl_Command currentCmdPtr; Tcl_Obj *calledProc; struct NsfFilterStack *nextPtr; } NsfFilterStack; /* * Assertion structures */ typedef struct NsfTclObjList { Tcl_Obj *content; Tcl_Obj *payload; struct NsfTclObjList *nextPtr; } NsfTclObjList; typedef struct NsfProcAssertion { NsfTclObjList *pre; NsfTclObjList *post; } NsfProcAssertion; typedef struct NsfAssertionStore { NsfTclObjList *invariants; Tcl_HashTable procs; } NsfAssertionStore; typedef enum { /* powers of 2; add to ALL, if default; */ CHECK_NONE = 0, CHECK_CLINVAR = 1, CHECK_OBJINVAR = 2, CHECK_PRE = 4, CHECK_POST = 8, CHECK_INVAR = CHECK_CLINVAR + CHECK_OBJINVAR, CHECK_ALL = CHECK_INVAR + CHECK_PRE + CHECK_POST } CheckOptions; void NsfAssertionRename(Tcl_Interp *interp, Tcl_Command cmd, NsfAssertionStore *as, char *oldSimpleCmdName, char *newName); /* * mixins */ typedef struct NsfMixinStack { Tcl_Command currentCmdPtr; struct NsfMixinStack *nextPtr; } NsfMixinStack; /* * Generic command pointer list */ typedef struct NsfCmdList { Tcl_Command cmdPtr; ClientData clientData; struct NsfClass *clorobj; struct NsfCmdList *nextPtr; } NsfCmdList; typedef void (NsfFreeCmdListClientData) (NsfCmdList*); /* for incr string */ typedef struct NsfStringIncrStruct { char *buffer; char *start; size_t bufSize; size_t length; } NsfStringIncrStruct; /* * cmd flags */ #define NSF_CMD_CALL_PROTECTED_METHOD 0x00010000 #define NSF_CMD_CALL_PRIVATE_METHOD 0x00020000 #define NSF_CMD_REDEFINE_PROTECTED_METHOD 0x00040000 /* NSF_CMD_NONLEAF_METHOD is used to flag, if a Method implemented via cmd calls "next" */ #define NSF_CMD_NONLEAF_METHOD 0x00080000 #define NSF_CMD_CLASS_ONLY_METHOD 0x00100000 #define NSF_CMD_DEPRECATED_METHOD 0x00200000 #define NSF_CMD_DEBUG_METHOD 0x00400000 /* * traceEvalFlags controlling NsfDStringEval */ #define NSF_EVAL_SAVE 0x01u /* save interp context */ #define NSF_EVAL_NOPROFILE 0x02u /* no profile below this call */ #define NSF_EVAL_DEBUG 0x04u /* call is a debug call, prevent recursion */ #define NSF_EVAL_LOG 0x08u /* call is a log call, prevent recursion */ #define NSF_EVAL_DEPRECATED 0x10u /* call is a deprecated call, prevent recursion */ #define NSF_EVAL_PREVENT_RECURSION (NSF_EVAL_DEBUG|NSF_EVAL_LOG|NSF_EVAL_DEPRECATED) /* * object flags ... */ /* DESTROY_CALLED indicates that destroy was called on obj */ #define NSF_DESTROY_CALLED 0x0001u /* INIT_CALLED indicates that init was called on obj */ #define NSF_INIT_CALLED 0x0002u /* MIXIN_ORDER_VALID set when mixin order is valid */ #define NSF_MIXIN_ORDER_VALID 0x0004u /* MIXIN_ORDER_DEFINED set, when mixins are defined for obj */ #define NSF_MIXIN_ORDER_DEFINED 0x0008u #define NSF_MIXIN_ORDER_DEFINED_AND_VALID 0x000cu /* FILTER_ORDER_VALID set, when filter order is valid */ #define NSF_FILTER_ORDER_VALID 0x0010u /* FILTER_ORDER_DEFINED set, when filters are defined for obj */ #define NSF_FILTER_ORDER_DEFINED 0x0020u #define NSF_FILTER_ORDER_DEFINED_AND_VALID 0x0030u /* class and object properties for objects */ #define NSF_IS_CLASS 0x0040u #define NSF_IS_ROOT_META_CLASS 0x0080u #define NSF_IS_ROOT_CLASS 0x0100u #define NSF_IS_SLOT_CONTAINER 0x0200u #define NSF_KEEP_CALLER_SELF 0x0400u #define NSF_PER_OBJECT_DISPATCH 0x0800u #define NSF_HAS_PER_OBJECT_SLOTS 0x1000u #define NSF_IS_AUTONAMED 0x2000u /* deletion states */ #define NSF_DESTROY_CALLED_SUCCESS 0x010000u /* requires flags to be int, not short */ #define NSF_DURING_DELETE 0x020000u #define NSF_DELETED 0x040000u #define NSF_RECREATE 0x080000u #define NSF_TCL_DELETE 0x100000u /* method invocations */ #define NSF_ARG_METHOD_INVOCATION (NSF_ARG_ALIAS|NSF_ARG_FORWARD|NSF_ARG_INITCMD|NSF_ARG_CMD) #define NSF_ARG_METHOD_CALL (NSF_ARG_ALIAS|NSF_ARG_FORWARD) /* Disallowed parameter options */ #define NSF_DISALLOWED_ARG_METHOD_PARAMETER (NSF_ARG_METHOD_INVOCATION|NSF_ARG_NOCONFIG|NSF_ARG_SLOTSET|NSF_ARG_SLOTINITIALIZE) #define NSF_DISALLOWED_ARG_SETTER (NSF_ARG_SWITCH|NSF_ARG_SUBST_DEFAULT|NSF_DISALLOWED_ARG_METHOD_PARAMETER) /*#define NSF_DISALLOWED_ARG_OBJECT_PARAMETER (NSF_ARG_SWITCH)*/ #define NSF_DISALLOWED_ARG_OBJECT_PARAMETER 0 #define NSF_DISALLOWED_ARG_VALUECHECK (NSF_ARG_SUBST_DEFAULT|NSF_ARG_METHOD_INVOCATION|NSF_ARG_SWITCH|NSF_ARG_CURRENTLY_UNKNOWN|NSF_ARG_SLOTSET|NSF_ARG_SLOTINITIALIZE) /* flags for ParseContext */ #define NSF_PC_MUST_DECR 0x0001u #define NSF_PC_IS_DEFAULT 0x0002u #define NSF_PC_INVERT_DEFAULT 0x0010u #define NSF_PC_STATUS_MUST_DECR 0x0001u #define NSF_PC_STATUS_FREE_OBJV 0x0002u #define NSF_PC_STATUS_FREE_CD 0x0004u /* method types */ #define NSF_METHODTYPE_ALIAS 0x0001 #define NSF_METHODTYPE_SCRIPTED 0x0002 #define NSF_METHODTYPE_SETTER 0x0004 #define NSF_METHODTYPE_FORWARDER 0x0008 #define NSF_METHODTYPE_OBJECT 0x0010 #define NSF_METHODTYPE_NSFPROC 0x0020 #define NSF_METHODTYPE_OTHER 0x0100 #define NSF_METHODTYPE_BUILTIN NSF_METHODTYPE_ALIAS|NSF_METHODTYPE_SETTER|NSF_METHODTYPE_FORWARDER|NSF_METHODTYPE_OTHER #define NSF_METHODTYPE_ALL NSF_METHODTYPE_SCRIPTED|NSF_METHODTYPE_BUILTIN|NSF_METHODTYPE_OBJECT #define NsfObjectSetClass(object) \ (object)->flags |= NSF_IS_CLASS #define NsfObjectClearClass(object) \ (object)->flags &= ~NSF_IS_CLASS #define NsfObjectIsClass(object) \ ((object)->flags & NSF_IS_CLASS) #define NsfObjectToClass(object) \ (NsfClass *)((((NsfObject *)object)->flags & NSF_IS_CLASS) ? object : NULL) /* * object and class internals */ typedef struct NsfParamDefs { Nsf_Param *paramsPtr; int nrParams; int refCount; int serial; } NsfParamDefs; typedef struct NsfParsedParam { NsfParamDefs *paramDefs; int possibleUnknowns; } NsfParsedParam; typedef struct NsfObjectOpt { NsfAssertionStore *assertions; NsfCmdList *objFilters; NsfCmdList *objMixins; ClientData clientData; const char *volatileVarName; #if defined(PER_OBJECT_PARAMETER_CACHING) NsfParsedParam *parsedParamPtr; unsigned int classParamPtrEpoch; #endif CheckOptions checkoptions; } NsfObjectOpt; typedef struct NsfObject { Tcl_Obj *cmdName; Tcl_Command id; Tcl_Interp *teardown; struct NsfClass *cl; TclVarHashTable *varTablePtr; Tcl_Namespace *nsPtr; NsfObjectOpt *opt; struct NsfCmdList *filterOrder; struct NsfCmdList *mixinOrder; NsfFilterStack *filterStack; NsfMixinStack *mixinStack; int refCount; unsigned int flags; short activationCount; } NsfObject; typedef struct NsfClassOpt { NsfCmdList *classFilters; NsfCmdList *classMixins; NsfCmdList *isObjectMixinOf; NsfCmdList *isClassMixinOf; NsfAssertionStore *assertions; Tcl_Obj *mixinRegObjs; #ifdef NSF_OBJECTDATA Tcl_HashTable *objectdata; #endif Tcl_Command id; ClientData clientData; } NsfClassOpt; typedef struct NsfClass { struct NsfObject object; struct NsfClasses *super; struct NsfClasses *sub; struct NsfObjectSystem *osPtr; struct NsfClasses *order; Tcl_HashTable instances; Tcl_Namespace *nsPtr; NsfParsedParam *parsedParamPtr; NsfClassOpt *opt; short color; } NsfClass; typedef struct NsfClasses { struct NsfClass *cl; ClientData clientData; struct NsfClasses *nextPtr; } NsfClasses; /* * needed in nsf.c and in nsfShadow */ #define NSF_PROC_FLAG_AD 0x01u #define NSF_PROC_FLAG_CHECK_ALWAYS 0x02u typedef struct NsfProcClientData { Tcl_Obj *procName; Tcl_Command cmd; Tcl_Command wrapperCmd; NsfParamDefs *paramDefs; unsigned int flags; Tcl_Interp *interp; } NsfProcClientData; typedef enum SystemMethodsIdx { NSF_c_alloc_idx, NSF_c_create_idx, NSF_c_dealloc_idx, NSF_c_configureparameter_idx, NSF_c_recreate_idx, NSF_o_cleanup_idx, NSF_o_configure_idx, NSF_o_configureparameter_idx, NSF_o_defaultmethod_idx, NSF_o_destroy_idx, NSF_o_init_idx, NSF_o_move_idx, NSF_o_unknown_idx, NSF_s_get_idx, NSF_s_set_idx } SystemMethodsIdx; EXTERN const char *Nsf_SystemMethodOpts[]; #if defined(NSF_C) const char *Nsf_SystemMethodOpts[] = { "-class.alloc", "-class.create", "-class.dealloc", "-class.configureparameter", "-class.recreate", "-object.cleanup", "-object.configure", "-object.configureparameter", "-object.defaultmethod", "-object.destroy", "-object.init", "-object.move", "-object.unknown", "-slot.get", "-slot.set", NULL }; #endif typedef struct NsfObjectSystem { NsfClass *rootClass; NsfClass *rootMetaClass; unsigned int overloadedMethods; unsigned int definedMethods; Tcl_Obj *methods[NSF_s_set_idx+2]; const char *methodNames[NSF_s_set_idx+2]; Tcl_Obj *handles[NSF_s_set_idx+2]; struct NsfObjectSystem *nextPtr; char protected[NSF_s_set_idx+2]; } NsfObjectSystem; /* * Next Scripting global names and strings * * We provide enums for efficient lookup for corresponding string * names and Tcl_Objs via global arrays. The "constant" Tcl_Objs are * built at start-up-time via Nsf_Init(). */ typedef enum { NSF_EMPTY, NSF_ZERO, NSF_ONE, /* methods called internally */ NSF_CONFIGURE, NSF_INITIALIZE, NSF_GET_PARAMETER_SPEC, NSF_SLOT_GET, NSF_SLOT_SET, /* var names */ NSF_AUTONAMES, NSF_DEFAULTMETACLASS, NSF_DEFAULTSUPERCLASS, NSF_ARRAY_INITCMD, NSF_ARRAY_CMD, NSF_ARRAY_ALIAS, NSF_ARRAY_PARAMETERSYNTAX, NSF_POSITION, NSF_POSITIONAL, NSF_CONFIGURABLE, NSF_PARAMETERSPEC, /* object/class names */ NSF_METHOD_PARAMETER_SLOT_OBJ, /* constants */ NSF_ALIAS, NSF_ARGS, NSF_CMD, NSF_FILTER, NSF_FORWARD, NSF_METHOD, NSF_OBJECT, NSF_SETTER, NSF_SETTERNAME, NSF_VALUECHECK, NSF_GUARD_OPTION, NSF___UNKNOWN__, NSF_ARRAY, NSF_GET, NSF_SET, NSF_OPTION_STRICT, NSF_SCRIPT, NSF_OBJECT_UNKNOWN_HANDLER, NSF_ARGUMENT_UNKNOWN_HANDLER, NSF_PARSE_ARGS, /* Partly redefined Tcl commands; leave them together at the end */ NSF_EXPR, NSF_FORMAT, NSF_INFO_BODY, NSF_INFO_FRAME, NSF_INTERP, NSF_STRING_IS, NSF_EVAL, NSF_DISASSEMBLE, NSF_RENAME } NsfGlobalNames; EXTERN const char *NsfGlobalStrings[]; #if defined(NSF_C) const char *NsfGlobalStrings[] = { "", "0", "1", /* methods called internally */ "configure", "initialize", "getParameterSpec", "value=get", "value=set", /* var names */ "__autonames", "__default_metaclass", "__default_superclass", "__initcmd", "__cmd", "::nsf::alias", "::nsf::parameter::syntax", "position", "positional", "configurable", "parameterSpec", /* object/class names */ "::nx::methodParameterSlot", /* constants */ "alias", "args", "cmd", "filter", "forward", "method", "object", "setter", "settername", "valuecheck", "-guard", "__unknown__", "::array", "get", "set", "-strict", "script", /* nsf Tcl commands */ "::nsf::object::unknown", "::nsf::argument::unknown", "::nsf::parseargs", /* Tcl commands */ "expr", "format", "::tcl::info::body", "::tcl::info::frame", "interp", "::tcl::string::is", "::eval", "::tcl::unsupported::disassemble", "rename" }; #endif #define NsfGlobalObjs RUNTIME_STATE(interp)->methodObjNames /* * Interface for Tcl_Obj types */ EXTERN Tcl_ObjType NsfMixinregObjType; EXTERN int NsfMixinregGet(Tcl_Interp *interp, Tcl_Obj *obj, NsfClass **classPtr, Tcl_Obj **guardObj) nonnull(1) nonnull(2) nonnull(3) nonnull(4); EXTERN int NsfMixinregInvalidate(Tcl_Interp *interp, Tcl_Obj *obj) nonnull(1) nonnull(2); EXTERN Tcl_ObjType NsfFilterregObjType; EXTERN int NsfFilterregGet(Tcl_Interp *interp, Tcl_Obj *obj, Tcl_Obj **filterObj, Tcl_Obj **guardObj) nonnull(1) nonnull(2) nonnull(3) nonnull(4); EXTERN NsfClassOpt *NsfRequireClassOpt(NsfClass *class) nonnull(1) returns_nonnull; /* * Next Scripting ShadowTclCommands */ typedef struct NsfShadowTclCommandInfo { Tcl_ObjCmdProc *proc; ClientData clientData; int nrArgs; } NsfShadowTclCommandInfo; typedef enum {SHADOW_LOAD=1, SHADOW_UNLOAD=0, SHADOW_REFETCH=2} NsfShadowOperations; typedef enum {NSF_PARAMS_NAMES, NSF_PARAMS_LIST, NSF_PARAMS_PARAMETER, NSF_PARAMS_SYNTAX} NsfParamsPrintStyle; int NsfCallCommand(Tcl_Interp *interp, NsfGlobalNames name, int objc, Tcl_Obj *const objv[]) nonnull(1) nonnull(4); int NsfShadowTclCommands(Tcl_Interp *interp, NsfShadowOperations load) nonnull(1); Tcl_Obj *NsfMethodObj(const NsfObject *object, int methodIdx) nonnull(1) NSF_pure; int NsfReplaceCommandCleanup(Tcl_Interp *interp, Tcl_Obj *nameObj, NsfShadowTclCommandInfo *ti) nonnull(1) nonnull(2) nonnull(3); int NsfReplaceCommand(Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_ObjCmdProc *nsfReplacementProc, ClientData cd, NsfShadowTclCommandInfo *ti) nonnull(1) nonnull(2) nonnull(5); /* * Next Scripting CallStack */ typedef struct NsfCallStackContent { NsfObject *self; NsfClass *cl; Tcl_Command cmdPtr; NsfFilterStack *filterStackEntry; Tcl_Obj *const* objv; int objc; unsigned int flags; #if defined(NSF_PROFILE) || defined(NSF_DTRACE) long int startUsec; long int startSec; const char *methodName; #endif unsigned short frameType; } NsfCallStackContent; #define NSF_CSC_TYPE_PLAIN 0u #define NSF_CSC_TYPE_ACTIVE_MIXIN 1u #define NSF_CSC_TYPE_ACTIVE_FILTER 2u #define NSF_CSC_TYPE_INACTIVE 4u #define NSF_CSC_TYPE_INACTIVE_MIXIN 5u #define NSF_CSC_TYPE_INACTIVE_FILTER 6u #define NSF_CSC_TYPE_GUARD 0x10u #define NSF_CSC_TYPE_ENSEMBLE 0x20u #define NSF_CSC_CALL_IS_NEXT 1u #define NSF_CSC_CALL_IS_GUARD 2u #define NSF_CSC_CALL_IS_ENSEMBLE 4u #define NSF_CSC_CALL_IS_COMPILE 8u #define NSF_CSC_IMMEDIATE 0x000000100u #define NSF_CSC_FORCE_FRAME 0x000000200u #define NSF_CSC_CALL_NO_UNKNOWN 0x000000400u #define NSF_CSC_CALL_IS_NRE 0x000002000u #define NSF_CSC_MIXIN_STACK_PUSHED 0x000004000u #define NSF_CSC_FILTER_STACK_PUSHED 0x000008000u #define NSF_CSC_METHOD_IS_UNKNOWN 0x000010000u /* flags for call method */ #define NSF_CM_NO_UNKNOWN 0x000000001u #define NSF_CM_NO_SHIFT 0x000000002u #define NSF_CM_IGNORE_PERMISSIONS 0x000000004u #define NSF_CM_NO_OBJECT_METHOD 0x000000008u #define NSF_CM_SYSTEM_METHOD 0x000000010u #define NSF_CM_LOCAL_METHOD 0x000000020u #define NSF_CM_INTRINSIC_METHOD 0x000000040u #define NSF_CM_KEEP_CALLER_SELF 0x000000080u #define NSF_CM_ENSEMBLE_UNKNOWN 0x008000000u #define NSF_CSC_COPY_FLAGS (NSF_CSC_MIXIN_STACK_PUSHED|NSF_CSC_FILTER_STACK_PUSHED|NSF_CSC_IMMEDIATE|NSF_CSC_FORCE_FRAME|NSF_CM_LOCAL_METHOD) #define NSF_VAR_TRIGGER_TRACE 1 #define NSF_VAR_REQUIRE_DEFINED 2 #define NSF_VAR_ISARRAY 4 /* * Tcl uses 01 and 02, TclOO uses 04 and 08, so leave some space free * for further extensions of Tcl and tcloo... */ #define FRAME_IS_NSF_OBJECT 0x10000u #define FRAME_IS_NSF_METHOD 0x20000u #define FRAME_IS_NSF_CMETHOD 0x40000u #define FRAME_VAR_LOADED 0x80000u #if defined(NRE) # define NRE_SANE_PATCH 1 # define NsfImmediateFromCallerFlags(flags) \ (((flags) & (NSF_CSC_CALL_IS_NRE|NSF_CSC_IMMEDIATE)) == NSF_CSC_CALL_IS_NRE ? 0 : NSF_CSC_IMMEDIATE) # if defined(NRE_SANE_PATCH) # define NsfNRRunCallbacks(interp, result, rootPtr) TclNRRunCallbacks(interp, result, rootPtr) # if !defined(TclStackFree) # define TclStackFree(interp, ptr) ckfree(ptr) # define TclStackAlloc(interp, size) ckalloc(size) # endif # else # define NsfNRRunCallbacks(interp, result, rootPtr) TclNRRunCallbacks(interp, result, rootPtr, 0) # define TEOV_callback NRE_callback # endif #endif #if defined(NSF_PROFILE) typedef struct NsfProfile { long int overallTime; long int startSec; long int startUSec; Tcl_HashTable objectData; Tcl_HashTable methodData; Tcl_HashTable procData; Tcl_DString traceDs; int depth; int verbose; Tcl_Obj *shadowedObjs; NsfShadowTclCommandInfo *shadowedTi; int inmemory; } NsfProfile; # define NSF_PROFILE_TIME_DATA struct Tcl_Time profile_trt # define NSF_PROFILE_CALL(interp, object, methodName) \ Tcl_GetTime(&profile_trt); \ NsfProfileTraceCall(interp, object, NULL, methodName) # define NSF_PROFILE_EXIT(interp, object, methodName) \ NsfProfileTraceExit(interp, object, NULL, methodName, &profile_trt) #else # define NSF_PROFILE_TIME_DATA # define NSF_PROFILE_CALL(interp, object, methodName) # define NSF_PROFILE_EXIT(interp, object, methodName) #endif typedef struct NsfList { void *data; Tcl_Obj *obj; struct NsfList *nextPtr; } NsfList; typedef struct NsfDList { void **data; size_t size; size_t avail; void *static_data[30]; } NsfDList; typedef struct NsfRuntimeState { /* * The defined object systems */ struct NsfObjectSystem *objectSystems; /* * namespaces and cmds */ Tcl_Namespace *NsfNS; /* the ::nsf namespace */ Tcl_Namespace *NsfClassesNS; /* the ::nsf::classes namespace, where classes are created physically */ Tcl_ObjCmdProc *objInterpProc; /* cached result of TclGetObjInterpProc() */ Tcl_Command colonCmd; /* cmdPtr of cmd ":" to dispatch via cmdResolver */ Proc fakeProc; /* dummy proc structure, used for C-implemented methods with local scope */ Tcl_Command currentMixinCmdPtr; /* cmdPtr of currently active mixin, used for "info activemixin" */ unsigned int objectMethodEpoch; unsigned int instanceMethodEpoch; #if defined(PER_OBJECT_PARAMETER_CACHING) unsigned int classParamPtrEpoch; #endif unsigned int overloadedMethods; /* bit-array for tracking overloaded methods */ Tcl_Obj **methodObjNames; /* global objects of nsf */ struct NsfShadowTclCommandInfo *tclCommands; /* shadowed Tcl commands */ #if defined(CHECK_ACTIVATION_COUNTS) NsfClasses *cscList; #endif int errorCount; /* keep track of number of errors to avoid potential error loops */ int unknown; /* keep track whether an unknown method is currently called */ /* * Configure options. The following do*-flags could be moved into a * bit-array, but we have only one state per interp, so the win on * memory is very little. */ int logSeverity; int debugCallingDepth; unsigned int doCheckArguments; unsigned int doCheckResults; int doFilters; int doKeepcmds; int doProfile; int doTrace; unsigned int preventRecursionFlags; int doClassConverterOmitUnknown; int doSoftrecreate; int exitHandlerDestroyRound; /* shutdown handling */ Tcl_HashTable activeFilterTablePtr; /* keep track of defined filters */ NsfList *freeListPtr; /* list of elements to free when interp shuts down */ NsfDList freeDList; #if defined(NSF_PROFILE) NsfProfile profile; #endif #if defined(NSF_STACKCHECK) void *bottomOfStack; void *maxStack; #endif ClientData clientData; NsfStringIncrStruct iss; /* used for new to create new symbols */ short guardCount; /* keep track of guard invocations */ } NsfRuntimeState; #define NSF_EXITHANDLER_OFF 0 #define NSF_EXITHANDLER_ON_SOFT_DESTROY 1 #define NSF_EXITHANDLER_ON_PHYSICAL_DESTROY 2 #ifdef NSF_OBJECTDATA EXTERN void NsfSetObjectData(struct NsfObject *object, struct NsfClass *class, ClientData data) nonnull(1) nonnull(2) nonnull(3); EXTERN int NsfGetObjectData(struct NsfObject *object, struct NsfClass *class, ClientData *data) nonnull(1) nonnull(2) nonnull(3); EXTERN int NsfUnsetObjectData(struct NsfObject *object, struct NsfClass *class) nonnull(1) nonnull(2); EXTERN void NsfFreeObjectData(NsfClass *class) nonnull(1); #endif /* * Prototypes for method definitions */ EXTERN Tcl_ObjCmdProc NsfObjDispatch; /* * NsfObject Reference Accounting */ EXTERN void NsfCleanupObject_(NsfObject *object) nonnull(1); #if defined(NSFOBJ_TRACE) # define NsfObjectRefCountIncr(object) \ ((NsfObject *)(object))->refCount++; \ fprintf(stderr, "RefCountIncr %p count=%d %s\n", (void *)(object), ((NsfObject *)(object))->refCount, \ ((NsfObject *)object)->cmdName?ObjStr(((NsfObject *)(object))->cmdName):"no name"); \ MEM_COUNT_ALLOC("NsfObject.refCount", (object)) # define NsfObjectRefCountDecr(object) \ (object)->refCount--; \ fprintf(stderr, "RefCountDecr %p count=%d\n", (void *)(object), (object)->refCount); \ MEM_COUNT_FREE("NsfObject.refCount", (object)) #else # define NsfObjectRefCountIncr(object) \ (object)->refCount++; \ MEM_COUNT_ALLOC("NsfObject.refCount", (object)) # define NsfObjectRefCountDecr(object) \ (object)->refCount--; \ MEM_COUNT_FREE("NsfObject.refCount", (object)) #endif /* * * Internally used API functions * */ #if defined(NRE) # if defined(PRE9) # include "stubs8.6/nsfIntDecls.h" # else # include "stubs9.0/nsfIntDecls.h" # endif #else # include "stubs8.5/nsfIntDecls.h" #endif /* * Profiling functions */ EXTERN void NsfDeprecatedCmd(Tcl_Interp *interp, const char *what, const char *oldCmd, const char *newCmd) nonnull(1) nonnull(2) nonnull(3) nonnull(4); EXTERN void NsfProfileDeprecatedCall(Tcl_Interp *interp, NsfObject *object, NsfClass *class, const char *methodName, const char *altMethod) nonnull(1) nonnull(2) nonnull(4) nonnull(5); EXTERN void NsfProfileDebugCall(Tcl_Interp *interp, NsfObject *object, NsfClass *class, const char *methodName, int objc, Tcl_Obj **objv) nonnull(1) nonnull(4); EXTERN void NsfProfileDebugExit(Tcl_Interp *interp, NsfObject *object, NsfClass *class, const char *methodName, long startSec, long startUsec) nonnull(1) nonnull(4); #if defined(NSF_PROFILE) EXTERN void NsfProfileRecordMethodData(Tcl_Interp* interp, NsfCallStackContent *cscPtr) nonnull(1) nonnull(2); EXTERN void NsfProfileRecordProcData(Tcl_Interp *interp, const char *methodName, long startSec, long startUsec) nonnull(1) nonnull(2); EXTERN void NsfProfileInit(Tcl_Interp *interp) nonnull(1); EXTERN void NsfProfileFree(Tcl_Interp *interp) nonnull(1); EXTERN void NsfProfileClearData(Tcl_Interp *interp) nonnull(1); EXTERN void NsfProfileGetData(Tcl_Interp *interp) nonnull(1); EXTERN int NsfProfileTrace(Tcl_Interp *interp, int withEnable, int withVerbose, int withDontsave, Tcl_Obj *builtinObjs); EXTERN void NsfProfileTraceCall(Tcl_Interp *interp, NsfObject *object, NsfClass *class, const char *methodName) nonnull(1) nonnull(2) nonnull(4); EXTERN void NsfProfileTraceExit(Tcl_Interp *interp, NsfObject *object, NsfClass *class, const char *methodName, struct Tcl_Time *callTime) nonnull(1) nonnull(2) nonnull(4) nonnull(5); EXTERN void NsfProfileTraceCallAppend(Tcl_Interp *interp, const char *label) nonnull(1) nonnull(2); EXTERN void NsfProfileTraceExitAppend(Tcl_Interp *interp, const char *label, double duration) nonnull(1) nonnull(2); EXTERN NsfCallStackContent *NsfCallStackGetTopFrame(const Tcl_Interp *interp, Tcl_CallFrame **framePtrPtr) nonnull(1); #endif /* * MEM Counting */ #ifdef NSF_MEM_COUNT void NsfMemCountAlloc(const char *id, const void *p) nonnull(1); void NsfMemCountFree(const char *id, const void *p) nonnull(1); void NsfMemCountInit(void); void NsfMemCountRelease(void); #endif /* NSF_MEM_COUNT */ /* * TCL_STACK_ALLOC_TRACE */ #if defined(TCL_STACK_ALLOC_TRACE) # define NsfTclStackFree(interp,ptr,msg) \ fprintf(stderr, "---- TclStackFree %p %s\n", (void *)ptr, msg);\ TclStackFree(interp,ptr) static char * NsfTclStackAlloc(Tcl_Interp *interp, size_t size, const char *msg) { char *ptr = TclStackAlloc(interp, (int)size); fprintf(stderr, "---- TclStackAlloc %p %s\n", (void *)ptr, msg); return ptr; } #else # define NsfTclStackFree(interp,ptr,msg) TclStackFree(interp,ptr) # define NsfTclStackAlloc(interp,size,msg) TclStackAlloc(interp,size) #endif /* * bytecode support */ #ifdef NSF_BYTECODE typedef struct NsfCompEnv { int bytecode; Command *cmdPtr; CompileProc *compileProc; Tcl_ObjCmdProc *callProc; } NsfCompEnv; typedef enum {INST_INITPROC, INST_NEXT, INST_SELF, INST_SELF_DISPATCH, LAST_INSTRUCTION} NsfByteCodeInstructions; Tcl_ObjCmdProc NsfInitProcNSCmd, NsfSelfDispatchCmd, NsfNextObjCmd, NsfGetSelfObjCmd; EXTERN NsfCompEnv *NsfGetCompEnv(void); int NsfDirectSelfDispatch(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) nonnull(1) nonnull(2); #endif EXTERN int NsfGetClassFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, NsfClass **classPtr, bool withUnknown) nonnull(1) nonnull(2) nonnull(3); EXTERN int NsfObjWrongArgs(Tcl_Interp *interp, const char *msg, Tcl_Obj *cmdNameObj, Tcl_Obj *methodPathObj, const char *arglist) nonnull(1) nonnull(2); EXTERN const char *NsfMethodName(Tcl_Obj *methodObj) nonnull(1) returns_nonnull; EXTERN void NsfInitPkgConfig(Tcl_Interp *interp) nonnull(1); EXTERN void NsfDStringArgv(Tcl_DString *dsPtr, int objc, Tcl_Obj *const objv[]) nonnull(1) nonnull(3); EXTERN Tcl_Obj *NsfMethodNamePath(Tcl_Interp *interp, Tcl_CallFrame *framePtr, const char *methodName) nonnull(1) nonnull(3) returns_nonnull; EXTERN int NsfDStringEval(Tcl_Interp *interp, Tcl_DString *dsPtr, const char *context, unsigned int traceEvalFlags) nonnull(1) nonnull(2) nonnull(3); /* * Definition of methodEpoch macros */ #if defined(METHOD_OBJECT_TRACE) # define NsfInstanceMethodEpochIncr(msg) \ RUNTIME_STATE(interp)->instanceMethodEpoch++; \ fprintf(stderr, "+++ instanceMethodEpoch %d %s\n", RUNTIME_STATE(interp)->instanceMethodEpoch, msg) # define NsfObjectMethodEpochIncr(msg) \ RUNTIME_STATE(interp)->objectMethodEpoch++; \ fprintf(stderr, "+++ objectMethodEpoch %d %s\n", RUNTIME_STATE(interp)->objectMethodEpoch, msg) #else # define NsfInstanceMethodEpochIncr(msg) RUNTIME_STATE(interp)->instanceMethodEpoch++ # define NsfObjectMethodEpochIncr(msg) RUNTIME_STATE(interp)->objectMethodEpoch++ #endif #if defined(PER_OBJECT_PARAMETER_CACHING) # define NsfClassParamPtrEpochIncr(msg) RUNTIME_STATE(interp)->classParamPtrEpoch++ #else # define NsfClassParamPtrEpochIncr(msg) #endif /* * NsfFlag type */ EXTERN Tcl_ObjType NsfFlagObjType; EXTERN int NsfFlagObjSet(Tcl_Interp *UNUSED(interp), Tcl_Obj *objPtr, Nsf_Param const *baseParamPtr, int serial, Nsf_Param const *paramPtr, Tcl_Obj *payload, unsigned int flags); typedef struct { const Nsf_Param *signature; Nsf_Param const *paramPtr; Tcl_Obj *payload; int serial; unsigned int flags; } NsfFlag; #define NSF_FLAG_DASHDAH 0x01 #define NSF_FLAG_CONTAINS_VALUE 0x02 /* * NsfMethodContext type */ EXTERN Tcl_ObjType NsfInstanceMethodObjType; EXTERN Tcl_ObjType NsfObjectMethodObjType; EXTERN int NsfMethodObjSet( Tcl_Interp *UNUSED(interp), Tcl_Obj *objPtr, const Tcl_ObjType *objectType, void *context, unsigned int methodEpoch, Tcl_Command cmd, NsfClass *class, unsigned int flags ) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(6); typedef struct { void *context; Tcl_Command cmd; NsfClass *cl; unsigned int methodEpoch; unsigned int flags; } NsfMethodContext; /* functions from nsfUtil.c */ char *Nsf_ltoa(char *buf, long i, int *lengthPtr) nonnull(1) nonnull(3); char *NsfStringIncr(NsfStringIncrStruct *iss) nonnull(1); void NsfStringIncrInit(NsfStringIncrStruct *iss) nonnull(1); void NsfStringIncrFree(NsfStringIncrStruct *iss) nonnull(1); /* * Interface for NSF's custom hash tables supporting function * pointers as keys. * */ typedef void (Nsf_AnyFun)(void); EXTERN void Nsf_InitFunPtrHashTable(Tcl_HashTable *tablePtr) nonnull(1); EXTERN Tcl_HashEntry *Nsf_CreateFunPtrHashEntry(Tcl_HashTable *tablePtr, Nsf_AnyFun *key, int *isNew) nonnull(1) nonnull(2); EXTERN Tcl_HashEntry *Nsf_FindFunPtrHashEntry(Tcl_HashTable *tablePtr, Nsf_AnyFun *key) nonnull(1) nonnull(2); /* * NSF enumeration-type interface */ EXTERN void Nsf_EnumerationTypeInit(void); EXTERN void Nsf_EnumerationTypeRelease(void); EXTERN const char *Nsf_EnumerationTypeGetDomain(Nsf_TypeConverter *converter) nonnull(1); /* * NSF command definitions interface */ EXTERN void Nsf_CmdDefinitionInit(void); EXTERN void Nsf_CmdDefinitionRelease(void); EXTERN Nsf_methodDefinition *Nsf_CmdDefinitionGet(Tcl_ObjCmdProc *proc) nonnull(1); #ifndef HAVE_STRNSTR char *strnstr(const char *buffer, const char *needle, size_t buffer_len) NSF_pure; #endif /* In ANSI mode (ISO C89/90) compilers such as gcc and clang do not define the va_copy macro. However, they *do* in reasonably recent versions provide a prefixed (__*) one. The by-feature test below falls back to the prefixed version, if available, and provides a more general fallback to a simple assignment; this is primarily for MSVC; admittedly, this simplification is not generally portable to platform/compiler combos other than x86, but the best I can think of right now. One might constrain the assignment-fallback to a platform and leave va_copy undefined in uncaught platform cases (?). */ #ifndef va_copy #ifdef __va_copy #define va_copy(dest,src) __va_copy((dest),(src)) #else #define va_copy(dest,src) ((dest) = (src)) #endif #endif /* In Tcl 8.6 (tclInt.h), vsnprintf is mapped to _vsnprintf. In Tcl 8.5, this is missing from tclInt.h. So ... */ #if defined(PRE86) && defined(_MSC_VER) #define vsnprintf _vsnprintf #endif /* * There are six whitespace characters in Tcl, which serve as element * separators in string representations of Tcl lists. See tclUtil.c */ #define NsfHasTclSpace(str) \ (strpbrk((str), " \t\n\r\v\f") != NULL) #define NsfMax(a,b) ((a) > (b) ? a : b) #define NsfMin(a,b) ((a) < (b) ? a : b) #define NsfCallStackFindLastInvocation(interp, offset, framePtrPtr) \ NsfCallStackFindCallingContext((interp), (offset), (framePtrPtr), NULL) EXTERN const Nsf_ObjvTable Nsf_Configureoption[]; #endif /* NSF_INCLUDE_nsf_int_h_ */ ./nsf2.4.0/generic/nsfShadow.c.ast.sh000644 000766 000024 00000000757 13543460714 020123 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.929267.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfShadow.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/generic/nsfShadow.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfShadow.c.ast.bdump./nsf2.4.0/generic/nsfDebug.c.ast.sh000644 000766 000024 00000000754 13543460710 017715 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.478827.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfDebug.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/generic/nsfDebug.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfDebug.c.ast.bdump./nsf2.4.0/generic/nsfObjectData.c000644 000766 000024 00000006247 13773664100 017477 0ustar00neumannstaff000000 000000 /* * nsfObjectData.c -- * * NSF object data assumes NSF_OBJECTDATA to be compiled in. When * specified, it can be used to equip every object with an * additional payload from C. * * Copyright (C) 1999-2015 Gustaf Neumann (a, b) * Copyright (C) 1999-2007 Uwe Zdun (a, b) * Copyright (C) 2011 Stefan Sobernig (b) * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #include "nsfInt.h" #ifdef NSF_OBJECTDATA EXTERN void NsfFreeObjectData(NsfClass* cl) { if (cl->opt && cl->opt->objectdata) { Tcl_DeleteHashTable(cl->opt->objectdata); ckfree((char*)cl->opt->objectdata); cl->opt->objectdata = 0; } } EXTERN void NsfSetObjectData(NsfObject* obj, NsfClass* cl, ClientData data) { Tcl_HashEntry *hPtr; int nw; NsfRequireClassOpt(cl); if (cl->opt->objectdata == 0) { cl->opt->objectdata = (Tcl_HashTable*)ckalloc(sizeof(Tcl_HashTable)); Tcl_InitHashTable(cl->opt->objectdata, TCL_ONE_WORD_KEYS); } hPtr = Tcl_CreateHashEntry(cl->opt->objectdata, (char*)obj, &nw); Tcl_SetHashValue(hPtr, data); } EXTERN int NsfGetObjectData(NsfObject* obj, NsfClass* cl, ClientData* data) { Tcl_HashEntry *hPtr; if (!cl->opt || !cl->opt->objectdata) { return 0; } hPtr = Tcl_FindHashEntry(cl->opt->objectdata, (char*)obj); if (data != NULL) { *data = (hPtr != NULL) ? Tcl_GetHashValue(hPtr) : 0; } return hPtr != NULL; } EXTERN int NsfUnsetObjectData(NsfObject* obj, NsfClass* cl) { Tcl_HashEntry *hPtr; if (!cl->opt || !cl->opt->objectdata) { return 0; } hPtr = Tcl_FindHashEntry(cl->opt->objectdata, (char*)obj); if (hPtr != NULL) { Tcl_DeleteHashEntry(hPtr); } return hPtr != NULL; } #endif /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * End: */ ./nsf2.4.0/generic/aol-xotcl.tcl000644 000766 000024 00000004753 13076710402 017223 0ustar00neumannstaff000000 000000 # # Load Next Scripting Framework, XOTcl and some related packages for # AOLserver 4.* and NaviServer. # # - AOLserver: rewrite essentially _ns_savenamespaces to include the # serialized objects # # - NaviServer: just needed for the package require # the serialization logic resides in ns/tcl/nstrace.tcl # # We expect to find the package in standard Tcl package search path # (the auto_path var) The simplest location is to put them under the # "lib" directory within the AOLserver tree. # package require XOTcl 2.0; namespace import -force ::xotcl::* package require nx::serializer ns_log notice "XOTcl version $::xotcl::version$::xotcl::patchlevel loaded" if {[ns_info name] ne "NaviServer"} { # # We are loading into aolserver. # # Overload procedure defined in bin/init.tcl. # It is now XOTcl-savvy in how it treats some # special namespaces. # proc _ns_savenamespaces {} { set script [_ns_getpackages] set import "" set nslist "" _ns_getnamespaces namespaces foreach n $namespaces { if {$n ne "::nsf" && $n ne "::xotcl" && $n ne "::nx" && ![string match "::nsf::*" $n] && ![::nsf::object::exists $n]} { lappend nslist $n } } foreach n $nslist { foreach {ns_script ns_import} [_ns_getscript $n] { append script [list namespace eval $n $ns_script] \n if {$ns_import ne ""} { append import [list namespace eval $n $ns_import] \n } } } if {[catch {::Serializer all} objects]} { ns_log notice "XOTcl extension not loaded; will not copy objects\ (error: $objects; $::errorInfo)." set objects "" } ns_ictl save [append script \n \ $objects \n $import] # just for debugging purposes if {0} { set f [open [::xotcl::tmpdir]/__aolserver-blueprint-[ns_info server].tcl w] puts $f $script close $f } } # # Source XOTcl files from shared/private library # the way AOLserver does for plain Tcl files. # proc _my_sourcefiles {shared private} { set files "" foreach file [lsort [glob -nocomplain -directory $shared *.xotcl]] { if {[file exists [file join $private [file tail $file]]] == 0} { lappend files $file } } foreach file [lsort [glob -nocomplain -directory $private *.xotcl]] { lappend files $file } foreach file $files { _ns_sourcefile $file } } ns_eval { _my_sourcefiles [ns_library shared] [ns_library private] } } ./nsf2.4.0/generic/nsfDebug.c000644 000766 000024 00000026754 14271250740 016525 0ustar00neumannstaff000000 000000 /* * nsfDebug.c -- * * Debugging facilities for the Next Scripting Framework. * * Copyright (C) 1999-2017 Gustaf Neumann (a, b) * Copyright (C) 1999-2007 Uwe Zdun (a, b) * Copyright (C) 2016-2017 Stefan Sobernig (b) * * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "nsfInt.h" #include "nsfAccessInt.h" #define NsfConfigStr(x) (NsfConfigEnabled(x) ? "1" : "0") static Tcl_Config const cfg[] = { {"version", NSF_VERSION}, {"commit", NSF_COMMIT}, {"patchLevel", NSF_PATCHLEVEL}, {"development", NsfConfigStr(DEVELOPMENT)}, {"memcount", NsfConfigStr(MEM_COUNT)}, {"memtrace", NsfConfigStr(MEM_TRACE)}, {"profile", NsfConfigStr(PROFILE)}, {"dtrace", NsfConfigStr(DTRACE)}, {"assertions", NsfConfigStr(WITH_ASSERTIONS)}, {NULL, NULL} }; /* *---------------------------------------------------------------------- * NsfInitPkgConfig -- * * Registers NSF's build configuration according to TIP 59: * https://core.tcl-lang.org/tips/doc/trunk/tip/59.md. This way, the build * configuration is preserved in a non-destructible manner (from the script * level, at least) and can be queried via a common interface: * * ::nsf::pkgconfig list * ::nsf::pkgconfig get /key/ * * Results: * None. * * Side effects: * Creates the command ::nsf::pkgconfig, configuration data is * stored within a dict associated with a given interp. * *---------------------------------------------------------------------- */ void NsfInitPkgConfig(Tcl_Interp *interp) { Tcl_RegisterConfig(interp, "nsf", cfg, "iso8859-1"); } /* *---------------------------------------------------------------------- * NsfStackDump -- * * Write the current callstack with various debugging infos to stderr. This * function is primarily for debugging proposes of the C implementation of * nsf. * * Results: * None. * * Side effects: * Debugging output * *---------------------------------------------------------------------- */ void NsfStackDump(Tcl_Interp *interp) nonnull(1); void NsfStackDump(Tcl_Interp *interp) { Interp *iPtr; CallFrame *f, *v; Tcl_Obj *varCmdObj; nonnull_assert(interp != NULL); iPtr = (Interp *)interp; f = iPtr->framePtr; v = iPtr->varFramePtr; varCmdObj = Tcl_NewObj(); fprintf (stderr, " TCL STACK:\n"); if (f == NULL) { fprintf(stderr, "- "); } while (f != NULL) { Tcl_Obj *cmdObj = Tcl_NewObj(); fprintf(stderr, "\tFrame=%p ", (void *)f); if ((f->isProcCallFrame != 0) && (f->procPtr != NULL) && (f->procPtr->cmdPtr != NULL) ) { fprintf(stderr, "caller %p ", (void *)Tcl_CallFrame_callerPtr(f)); fprintf(stderr, "callerV %p ", (void *)Tcl_CallFrame_callerVarPtr(f)); Tcl_GetCommandFullName(interp, (Tcl_Command)f->procPtr->cmdPtr, cmdObj); fprintf(stderr, "%s (%p) lvl=%lu\n", ObjStr(cmdObj), (void *)f->procPtr->cmdPtr, (unsigned long)f->level); } else { if (f->varTablePtr != NULL) { fprintf(stderr, "var_table = %p ", (void *)f->varTablePtr); } fprintf(stderr, "- \n"); } DECR_REF_COUNT(cmdObj); f = f->callerPtr; } fprintf (stderr, " VARFRAME:\n"); fprintf(stderr, "\tFrame=%p ", (void *)v); if (v != NULL) { fprintf(stderr, "caller %p var_table %p ", (void *)v->callerPtr, (void *)v->varTablePtr); } if (v != NULL && v->isProcCallFrame && v->procPtr && v->procPtr->cmdPtr) { Tcl_GetCommandFullName(interp, (Tcl_Command) v->procPtr->cmdPtr, varCmdObj); fprintf(stderr, " %s (%lu)\n", ObjStr(varCmdObj), (unsigned long)v->level); } else { fprintf(stderr, "- \n"); } DECR_REF_COUNT(varCmdObj); } #ifdef NSF_PRINT_OBJV /* *---------------------------------------------------------------------- * NsfPrintObjv -- * * Print the provided argument vector to stderr. This function is primarily * for debugging proposes of the C implementation of nsf. * * Results: * None. * * Side effects: * Debugging output * *---------------------------------------------------------------------- */ void NsfPrintObjv(char *string, int objc, Tcl_Obj *CONST objv[]) nonnull(1) nonnull(3); void NsfPrintObjv(char *string, int objc, Tcl_Obj *CONST objv[]) { int j; nonnull_assert(string != NULL); nonnull_assert(objv != NULL); fprintf(stderr, "%s", string); for (j = 0; j < objc; j++) { /*fprintf(stderr, " objv[%d]=%s, ", j, objv[j] ? ObjStr(objv[j]) : "NULL");*/ fprintf(stderr, " objv[%d]=%s %p, ", j, objv[j] ? ObjStr(objv[j]) : "NULL", (void *)objv[j]); } fprintf(stderr, "\n"); } #endif #ifdef NSF_MEM_COUNT /* *---------------------------------------------------------------------- * NsfMemCountGetTable -- * * Obtain the hash table structure * * Results: * None. * * Side effects: * Updating Hash table * *---------------------------------------------------------------------- */ static Tcl_HashTable * NsfMemCountGetTable(int **initialized) nonnull(1); static Tcl_HashTable * NsfMemCountGetTable(int **initialized) { static Tcl_ThreadDataKey memCountTableKey; static Tcl_ThreadDataKey memCountFlagKey; Tcl_HashTable *tablePtr; nonnull_assert(initialized != NULL); tablePtr = (Tcl_HashTable *)Tcl_GetThreadData(&memCountTableKey, sizeof(Tcl_HashTable)); *initialized = (int *)Tcl_GetThreadData(&memCountFlagKey, sizeof(int)); return tablePtr; } /* *---------------------------------------------------------------------- * NsfMemCountAlloc -- * * Bookkeeping function for memory und refcount debugging. This function * records the allocation of memory resources. The accompanying function is * NsfMemCountFree(). * * Results: * None. * * Side effects: * Updating Hash table * *---------------------------------------------------------------------- */ void NsfMemCountAlloc(const char *id, const void *p) { int new, *tableInitialized; NsfMemCounter *entry; Tcl_HashTable *tablePtr = NsfMemCountGetTable(&tableInitialized); Tcl_HashEntry *hPtr; nonnull_assert(id != NULL); if (!*tableInitialized) { fprintf(stderr, "+++ alloc %s %p\n", id, p); return; } hPtr = Tcl_CreateHashEntry(tablePtr, id, &new); #ifdef NSF_MEM_TRACE fprintf(stderr, "+++ alloc %s %p\n", id, p); #endif if (new != 0) { entry = (NsfMemCounter*)ckalloc(sizeof(NsfMemCounter)); entry->count = 1; entry->peak = 1; Tcl_SetHashValue(hPtr, entry); } else { entry = (NsfMemCounter*) Tcl_GetHashValue(hPtr); entry->count++; if (entry->count > entry->peak) { entry->peak = entry->count; } } } /* *---------------------------------------------------------------------- * NsfMemCountFree -- * * Bookkeeping function for memory und refcount debugging. This function * records the deallocation of memory resources. The accompanying function * is NsfMemCountAlloc(). * * Results: * None. * * Side effects: * Updating Hash table * *---------------------------------------------------------------------- */ void NsfMemCountFree(const char *id, const void *p) { NsfMemCounter *entry; int *tableInitialized; Tcl_HashTable *tablePtr = NsfMemCountGetTable(&tableInitialized); Tcl_HashEntry *hPtr; nonnull_assert(id != NULL); if (!*tableInitialized) { fprintf(stderr, "+++ free %s %p !tableInitialized !\n", id, p); return; } #ifdef NSF_MEM_TRACE fprintf(stderr, "+++ free %s %p\n", id, p); #endif hPtr = Tcl_FindHashEntry(tablePtr, id); if (hPtr == NULL) { fprintf(stderr, "******** MEM COUNT ALERT: Trying to free %p <%s>, " "but was not allocated\n", p, id); return; } entry = (NsfMemCounter *)Tcl_GetHashValue(hPtr); entry->count--; } /* *---------------------------------------------------------------------- * NsfMemCountInit -- * * Initialize book-keeping for memory und refcount debugging. The * bookkeeping is realized via a per-interp hash table. * * Results: * None. * * Side effects: * Initializes a hash table * *---------------------------------------------------------------------- */ void NsfMemCountInit(void) { int *tableInitialized; Tcl_HashTable *tablePtr = NsfMemCountGetTable(&tableInitialized); if (!*tableInitialized) { Tcl_InitHashTable(tablePtr, TCL_STRING_KEYS); } (*tableInitialized) ++; } /* *---------------------------------------------------------------------- * NsfMemCountRelease -- * * Terminate book-keeping for memory und refcount debugging. This function * prints the resulting book-information to stderr, in case of paired * allocs/frees and incr-ref-counts and dec-ref-counts, the Overall count * should be 0. * * Results: * None. * * Side effects: * Deletes the book-keeping hash table, outputs to stderr * *---------------------------------------------------------------------- */ void NsfMemCountRelease(void) { int *tableInitialized; Tcl_HashTable *tablePtr = NsfMemCountGetTable(&tableInitialized); #ifdef NSF_MEM_TRACE fprintf(stderr, "+++ release count %d\n", *tableInitialized); #endif if (!*tableInitialized) { fprintf(stderr, "+++ release called on uninitialized/free hash table\n"); return; } if (*tableInitialized == 1) { Tcl_HashSearch search; Tcl_HashEntry *hPtr; int count = 0; fprintf(stderr, "******** NSF MEM Count *********\n* count peak\n"); for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { char *id = Tcl_GetHashKey(tablePtr, hPtr); NsfMemCounter *entry = (NsfMemCounter*) Tcl_GetHashValue(hPtr); count += entry->count; fprintf(stderr, "* %4d %6d %s\n", entry->count, entry->peak, id); ckfree ((char*) entry); } Tcl_DeleteHashTable(tablePtr); fprintf(stderr, "******** Count Overall = %d\n", count); } (*tableInitialized) --; } #endif /* * Local Variables: * mode: c * c-basic-offset: 2 * indent-tabs-mode: nil * fill-column: 78 * End: */ ./nsf2.4.0/generic/nsfObjectData.c.ast.sh000644 000766 000024 00000000773 13543460706 020675 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.a72a15.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfObjectData.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/generic/nsfObjectData.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfObjectData.c.ast.bdump./nsf2.4.0/generic/nsfPointer.c.ast.sh000644 000766 000024 00000000762 13543460712 020310 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.6d850e.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfPointer.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/generic/nsfPointer.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfPointer.c.ast.bdump./nsf2.4.0/generic/nsfEnumerationType.c.ast.sh000644 000766 000024 00000001012 13543460713 022006 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.579304.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfEnumerationType.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/generic/nsfEnumerationType.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfEnumerationType.c.ast.bdump./nsf2.4.0/generic/gentclAPI.tcl000644 000766 000024 00000056546 14260517173 017144 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh # -*- Tcl -*- # # C-Code generator to generate stubs to handle all objv-parsing from # a simple interface definition language. This guarantees consistent # handling of input argument types, consistent error messages in case # of failures and eases documentation. # # Copyright (C) 2009-2021 Gustaf Neumann # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # set ::converter "" set ::objCmdProc "(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv)" proc convertername {type typename} { if {[info exists ::registeredConverter($type)]} { set name $::registeredConverter($type) } else { set name [string totitle [string trimleft $typename -]] set ::registeredConverter($type) $name } return $name } proc createconverter {type typename isGlobal} { set name [convertername $type $typename] if {[info exists ::createdConverter($name)]} { return "" } set value 0; set values {}; set domain {}; set table {} foreach d [split $type |] { if {![regexp {^(.*)=(.*)$} $d . d v]} { set v [incr value] } lappend values $v lappend domain $d lappend table "{\"$d\", $v}" } lappend table "{NULL, 0u}" set localOpts [set globalOpts ""] if {!$isGlobal} { set storageClass "static " set optsName "opts" set scope "localOpts" } else { set storageClass "" set optsName "Nsf_${name}" set scope "globalOpts" } set $scope "${storageClass}const Nsf_ObjvTable $optsName\[\] = {\n [join $table ",\n "]\n };" set ::createdConverter($name) "ConvertTo${name}, \"[join $domain |]\"" # always add NULL entry set enums [list ${name}NULL=0x0u] foreach d $domain v $values { lappend enums $name[string totitle [string map [list - _] $d]]Idx=$v } set enums [join $enums {, }] set bindings [list @enums@ $enums @name@ $name @globalOpts@ $globalOpts \ @localOpts@ $localOpts @optsName@ $optsName @typeName@ $typename] string map $bindings { typedef enum {@enums@} @name@Idx_t; @globalOpts@ static int ConvertTo@name@(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int pos=0, result; @localOpts@ (void)pPtr; result = Tcl_GetIndexFromObjStruct(interp, objPtr, @optsName@, sizeof(Nsf_ObjvTable), "@typeName@", 0, &pos); *clientData = (ClientData) INT2PTR(@optsName@[pos].value); *outObjPtr = objPtr; return result; } } } proc addFlags {flags_var new} { upvar $flags_var flags if {$flags eq "0"} {set flags $new} {append flags "|$new"} } proc genifd {parameterDefinitions} { #puts stderr $parameterDefinitions set l [list] foreach parameterDefinition $parameterDefinitions { set p [dict merge {-flags 0 -global 0} $parameterDefinition] switch [dict get $p -type] { "" {set type NULL} default {set type [dict get $p -type]} } set flags [dict get $p -flags] if {[dict get $p -required]} { addFlags flags "NSF_ARG_REQUIRED" } set argName [dict get $p -argName] switch -glob $type { "NULL" {set converter String} "boolean" {set converter Boolean} "switch" {set converter Boolean} "int" {set converter Integer} "int32" {set converter Int32} "class" {set converter Class} "object" {set converter Object} "tclobj" {set converter Tclobj} "args" {set converter Nothing} "allargs" - "virtualobjectargs" - "virtualclassargs" {set converter Nothing} "objpattern" {set converter Objpattern} *|* { if {![dict exists $p -typeName]} { dict set p -typeName [dict get $p -argName] } set converter [convertername $type [dict get $p -typeName]] append ::converter [createconverter $type [dict get $p -typeName] [dict get $p -global]] addFlags flags "NSF_ARG_IS_ENUMERATION" } default { if {[info exists ::ptrConverter($type)]} { set converter Pointer } else { error "unknown type $type" } } } if {$converter in {Tclobj Integer Int32 Boolean String Class Object Pointer}} { set conv Nsf_ConvertTo_$converter } else { set conv ConvertTo$converter } switch -glob -- [dict get $p -type] { "*|*" - "tclobj" - "args" - "" {set typeString NULL} default { set typeString "\"[dict get $p -type]\"" } } lappend l "{\"$argName\", $flags, [dict get $p -nrargs], $conv, NULL,NULL,$typeString,NULL,NULL,NULL,NULL,NULL}" } if {[llength $l] == 0} { return "{NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}" } else { return [join $l ",\n "] } } proc varName {type name} { if {$type eq "tclobj" && $name ne "obj"} { set varName ${name}Obj } elseif {$type eq "object" && $name ne "object"} { regsub -all _object $name "" name set varName ${name}Object } elseif {$type eq "class" && $name ne "class"} { regsub -all _class $name "" name set varName ${name}Class } else { set varName $name } return $varName } proc gencall {methodName fn parameterDefinitions clientData cDefsVar ifDefVar arglistVar preVar postVar introVar nnVar cleanupVar } { upvar $cDefsVar cDefs $ifDefVar ifDef $arglistVar arglist $preVar pre $postVar post \ $introVar intro $nnVar nn $cleanupVar cleanup set c [list] set i 0 set pre ""; set post ""; set cleanup "" set intro "" switch $clientData { class { set a [list class] set if [list "NsfClass *class"] set argNum 3 append intro \ " NsfClass *class;" \n\n \ " assert(objc > 0);" \n\n \ " class = NsfObjectToClass(clientData);" \n \ " if (unlikely(class == NULL)) {" \n \ " return NsfDispatchClientDataError(interp, clientData, \"class\", ObjStr(objv\[0\]));" \n \ " }" \n } object { set a [list object] set if [list "NsfObject *object"] set argNum 3 append intro \ " NsfObject *object;" \n\n \ " assert(objc > 0);" \n\n \ " object = (NsfObject *)clientData;" } "" { append intro " (void)clientData;\n" set a [list] set if [list] set argNum 2 array set cd {arglist "" ifDefs ""} } } foreach parameterDefinition $parameterDefinitions { set p $parameterDefinition set ifSet 0 set cVar 1 dict set p -argName [string map [list - _] [dict get $p -argName]] if {[regexp {^_(.*)$} [dict get $p -argName] _ switchName]} { # # non positional args # set varName [varName [dict get $p -type] $switchName] if {$varName eq $switchName} { set varName with[string totitle $switchName] } set calledArg $varName set type "int " if {[dict get $p -nrargs] == 1} { switch -glob [dict get $p -type] { "" {set type "const char *"} "class" {set type "NsfClass *"} "object" {set type "NsfObject *"} "tclobj" {set type "Tcl_Obj *"} "int" {set type "Tcl_Obj *"} "int32" {set type "int "} "boolean" {set type "int "} "*|*" { if {![dict exists $p -typeName]} { dict set p -typeName [dict get $p -argName] } set type "[convertername [dict get $p -type] [dict get $p -typeName]]Idx_t " #puts stderr "nonpos: -typeName <[dict get $p -typeName]> -type <[dict get $p -type]> ==> type=<$type>" } default {error "type '[dict get $p -type]' not allowed for parameter"} } } } else { # # positionals # set varName [varName [dict get $p -type] [dict get $p -argName]] set calledArg $varName switch -glob [dict get $p -type] { "" {set type "const char *"} "boolean" {set type "int "} "int32" {set type "int "} "class" {set type "NsfClass *"} "object" {set type "NsfObject *"} "tclobj" {set type "Tcl_Obj *"} "virtualobjectargs" - "virtualclassargs" - "args" { set type "int " set calledArg "objc - pc.lastObjc, objv + pc.lastObjc" lappend if "int trailingObjc" "Tcl_Obj *const* trailingObjv" set ifSet 1 set cVar 0 } "allargs" { set type "int " set calledArg "objc, objv" lappend if "int objc" "Tcl_Obj *const* objv" set ifSet 1 set cVar 0 } "objpattern" { set type "Tcl_Obj *" lappend c "const char *${varName}String = NULL;" "NsfObject *${varName}Object = NULL;" set calledArg "${varName}String, ${varName}Object" lappend if "const char *${varName}String" "NsfObject *${varName}Object" set ifSet 1 append pre [subst -nocommands { if (GetMatchObject(interp, ${varName}, objc>$i ? objv[$i] : NULL, &${varName}Object, &${varName}String) == -1) { if (${varName}) { DECR_REF_COUNT2("patternObj", ${varName}); } return TCL_OK; } }] append post [subst -nocommands { if (${varName}) { DECR_REF_COUNT2("patternObj", ${varName}); } }] set cleanup [subst -nocommands {$type$varName = ($type)pc.clientData[$i];}] append cleanup \n$post # end of obj pattern } *|* { if {![dict exists $p -typeName]} {dict set p -typeName [dict get $p -argName]} set type "[convertername [dict get $p -type] [dict get $p -typeName]]Idx_t " } default { if {[info exists ::ptrConverter([dict get $p -type])]} { set type "[dict get $p -type] *" set varName "${varName}Ptr" set calledArg $varName if {[dict get $p -withObj]} { append calledArg [subst -nocommands {,pc.objv[$i]}] lappend if "$type$varName" "Tcl_Obj *[dict get $p -argName]Obj" set ifSet 1 } } else { error "type '[dict get $p -type]' not allowed for argument" } } } } if {[string match {*[*]*} $type] && [dict get $p -required]} { append nn " NSF_nonnull($argNum)" } if {!$ifSet} { lappend if "$type$varName" } if {$cVar} { if {$type eq "int " || [string match "*Idx_t " $type]} { lappend c [subst -nocommands {$type$varName = ($type)PTR2INT(pc.clientData[$i]);}] } else { lappend c [subst -nocommands {$type$varName = ($type)pc.clientData[$i];}] } } lappend a $calledArg incr i incr argNum } set ifDef [join $if ", "] set cDefs [join $c "\n "] set arglist [join $a ", "] } proc genStub {stub intro obj idx cDefs pre call post cleanup} { # Tiny optimization for calls without parameters; # ParseContextExtendObjv() is just called for procs, so no need to # free non-static objvs. Actually, the API for c-methods does # not allow one to generate structures which have to be freed. # we assert this in the code. if {$cDefs ne ""} { set releasePC "ParseContextRelease(&pc);" set releasePC "assert(pc.status == 0);" } else { set releasePC "" } return [subst -nocommands { static int ${stub}(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { ParseContext pc; $intro if (likely(ArgumentParse(interp, objc, objv, $obj, objv[0], method_definitions[$idx].paramDefs, method_definitions[$idx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { $cDefs $pre $releasePC $call $post } else { $cleanup return TCL_ERROR; } } }]} proc genSimpleStub {stub intro idx cDefs pre call post cleanup} { if {$cleanup ne ""} {error "$stub cleanup code '$cleanup' must be empty"} return [subst -nocommands { static int ${stub}(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const* objv) { $intro $cDefs $pre $call $post } }]} proc implArgList {implementation prefix arglist} { if {$arglist ne ""} { return "${implementation}(${prefix}interp, $arglist)" } return "${implementation}(${prefix}interp)" } proc genstubs {} { set stubDecls "" set decls "" set enums [list] set ifds [list] foreach key [lsort [array names ::definitions]] { array set d $::definitions($key) lappend enums $d(idx) set nrParams [llength $d(parameterDefinitions)] set nn "" gencall $d(methodName) $d(stub) $d(parameterDefinitions) $d(clientData) \ cDefs ifDef arglist pre post intro nn cleanup # # Check, if spec tells us to pass the original "objv[0]" as an # argument. For unstacked entries this is the only way to # determine the name, under which the cmd was called. # if {[dict get $d(options) -objv0]} { append ifDef ", Tcl_Obj *objv0" append arglist ", objv\[0\]" } if {[dict get $::definitions($key) clientData] ne ""} { set stubNN "NSF_nonnull(1) " set NN " NSF_nonnull(2)" regsub \n\n $intro "\n\n NSF_nonnull_assert(clientData != NULL);\n" intro } else { set stubNN "" set NN "" } set stubDecl "static int $d(stub)$::objCmdProc\n ${stubNN}NSF_nonnull(2) NSF_nonnull(4);\n" set ifd "{\"$d(ns)::$d(methodName)\", $d(stub), $nrParams, {\n [genifd $d(parameterDefinitions)]}\n}" append decls "static int [implArgList $d(implementation) {Tcl_Interp *} $ifDef]\n NSF_nonnull(1)${NN}${nn};\n" if {$post ne ""} { append cDefs "\n int returnCode;" set call "returnCode = [implArgList $d(implementation) {} $arglist];" set post [string trimright $post] append post "\n return returnCode;" } else { set call "return [implArgList $d(implementation) {} $arglist];" } #if {$nrParams == 1} { puts stderr "$d(stub) => '$arglist' cDefs=$cDefs ifd=$ifDef" } if {$nrParams == 1 && $arglist eq "objc, objv"} { # TODO we would not need to generate a stub at all.... #set ifd "{\"$d(ns)::$d(methodName)\", $d(implementation), $nrParams, {\n [genifd $d(parameterDefinitions)]}\n}" append fns [genSimpleStub $d(stub) $intro $d(idx) $cDefs $pre $call $post $cleanup] } elseif {$nrParams == 1 && $arglist eq "obj, objc, objv"} { # no need to call objv parser #puts stderr "$d(stub) => '$arglist'" append fns [genSimpleStub $d(stub) $intro $d(idx) $cDefs $pre $call $post $cleanup] } elseif {$nrParams == 0} { append pre [subst -nocommands { if (unlikely(objc != 1)) { return NsfArgumentError(interp, "too many arguments:", method_definitions[$d(idx)].paramDefs, NULL, objv[0]); } }] append fns [genSimpleStub $d(stub) $intro $d(idx) $cDefs $pre $call $post $cleanup] } elseif {$nrParams == 1 && [string match "Tcl_Obj *" $cDefs]} { array set defs [list -required 0] array set defs [lindex $d(parameterDefinitions) 0] if {$defs(-required)} { set op "objc != 2" set newArg {objv[1]} } else { set op "objc < 1 || objc > 2" set newArg {objc == 2 ? objv[1] : NULL} } append pre [subst -nocommands { if ($op) { return NsfArgumentError(interp, "wrong # of arguments:", method_definitions[$d(idx)].paramDefs, NULL, objv[0]); } }] if {[regexp {^(.*),(.*)$} $arglist _ arg1]} { set newArglist "$arg1, $newArg" } else { set newArglist $newArg } regsub ", $arglist\\)" $call ", $newArglist\)" call append fns [genSimpleStub $d(stub) $intro $d(idx) "" $pre $call $post $cleanup] } else { switch $d(methodType) { objectMethod {set obj "object"} classMethod {set obj "(NsfObject *) class"} default {set obj "NULL"} } append fns [genStub $d(stub) $intro $obj $d(idx) $cDefs $pre $call $post $cleanup] } lappend ifds $ifd append stubDecls $stubDecl } puts $::converter set entries [list] foreach c [array names ::createdConverter] {lappend entries "\{$::createdConverter($c)\}"} if {[llength $entries]>0} { puts [subst { static Nsf_EnumeratorConverterEntry enumeratorConverterEntries\[\] = { [join $entries ",\n "], {NULL, NULL} }; }] } set nrIfds [expr {[llength $ifds]+1}] puts [subst -nocommands { /* just to define the symbol */ static Nsf_methodDefinition method_definitions[$nrIfds]; }] set namespaces [list] foreach {key value} [array get ::ns] { # no need to create the ::nsf namespace if {$value eq "::nsf"} continue lappend namespaces "\"$value\"" } set namespaceString [join $namespaces ",\n "] puts "static const char *method_command_namespace_names\[\] = {\n $namespaceString\n};" puts $stubDecls puts $decls set enumString [join $enums ",\n "] puts "EXTERN enum {\n $enumString\n} NsfMethods;\n" puts $fns set definitionString [join $ifds ",\n"] set terminator {NULL, NULL, 0, {{NULL, 0, 0, NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}}} puts "static Nsf_methodDefinition method_definitions\[$nrIfds\] = \{\n$definitionString,\n{$terminator}\n\};\n" } proc methodDefinition {methodName methodType implementation parameterDefinitions options} { array set opts [list -ns $::ns($methodType) -nxdoc 0 -objv0 0] array set opts $options set d(methodName) $methodName set d(implementation) $implementation set d(stub) ${implementation}Stub set d(idx) ${implementation}Idx set d(methodType) $methodType set d(ns) $opts(-ns) set d(options) [array get opts] switch $methodType { classMethod {set d(clientData) class} objectMethod {set d(clientData) object} default {set d(clientData) ""} } set completed [list] foreach parameterDefinition $parameterDefinitions { set p [dict merge {-required 0 -nrargs 1 -type "" -withObj 0} $parameterDefinition] if {[string match {$::*} [dict get $p -type]]} { dict set p -type [subst [dict get $p -type]] } lappend completed $p } set d(parameterDefinitions) $completed set ::definitions($d(methodType)-$d(implementation)-$d(methodName)) [array get d] # puts $::nxdocIndex [list set ::nxdoc::include($d(ns)::$d(methodName)) $opts(-nxdoc)] } proc checkMethod {methodName implementation parameterDefinitions {options ""}} { methodDefinition type=$methodName checkMethod $implementation $parameterDefinitions $options } proc classMethod {methodName implementation parameterDefinitions {options ""}} { methodDefinition $methodName classMethod $implementation $parameterDefinitions $options } proc objectMethod {methodName implementation parameterDefinitions {options ""}} { methodDefinition $methodName objectMethod $implementation $parameterDefinitions $options } proc objectInfoMethod {methodName implementation parameterDefinitions {options ""}} { lappend options -ns $::ns(objectInfoMethod) methodDefinition $methodName objectMethod $implementation $parameterDefinitions $options } proc classInfoMethod {methodName implementation parameterDefinitions {options ""}} { lappend options -ns $::ns(classInfoMethod) methodDefinition $methodName classMethod $implementation $parameterDefinitions $options } proc cmd {methodName implementation parameterDefinitions {options ""}} { methodDefinition $methodName cmd $implementation $parameterDefinitions $options } if {[llength $argv] == 1} {set decls $argv} {set decls generic/gentclAPI.decls} # set ::nxdocIndex [open [file root $decls].nxdocindex w] source $decls # close $::nxdocIndex puts { /* * This source code file was generated by the C-code generator gentclAPI.tcl, * part of the Next Scripting Framework. */ #if defined(USE_NSF_STUBS) int Nsf_ConvertTo_Boolean(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToBoolean(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Class(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToClass(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Int32(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToInt32(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Integer(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToInteger(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Object(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToObject(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Pointer(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToPointer(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_String(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToString(interp, objPtr, pPtr, clientData, outObjPtr); } int Nsf_ConvertTo_Tclobj(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { return Nsf_ConvertToTclobj(interp, objPtr, pPtr, clientData, outObjPtr); } #else # define Nsf_ConvertTo_Boolean Nsf_ConvertToBoolean # define Nsf_ConvertTo_Class Nsf_ConvertToClass # define Nsf_ConvertTo_Int32 Nsf_ConvertToInt32 # define Nsf_ConvertTo_Integer Nsf_ConvertToInteger # define Nsf_ConvertTo_Object Nsf_ConvertToObject # define Nsf_ConvertTo_Pointer Nsf_ConvertToPointer # define Nsf_ConvertTo_String Nsf_ConvertToString # define Nsf_ConvertTo_Tclobj Nsf_ConvertToTclobj #endif #if !defined(likely) # if defined(__GNUC__) && __GNUC__ > 2 /* Use gcc branch prediction hint to minimize cost of e.g. DTrace * ENABLED checks. */ # define unlikely(x) (__builtin_expect((x), 0)) # define likely(x) (__builtin_expect((x), 1)) # else # define unlikely(x) (x) # define likely(x) (x) # endif #endif } genstubs puts stderr "[array size ::definitions] parsing stubs generated" # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/generic/nsf.c000644 000766 000024 00004241564 14275704072 015566 0ustar00neumannstaff000000 000000 /* * nsf.c -- * * Basic Machinery of the Next Scripting Framework, a Tcl-based framework * for supporting language-oriented programming. For details, see * https://next-scripting.org/. * * Copyright (C) 1999-2021 Gustaf Neumann (a) (b) * Copyright (C) 1999-2007 Uwe Zdun (a) (b) * Copyright (C) 2007-2008 Martin Matuska (b) * Copyright (C) 2010-2019 Stefan Sobernig (b) * * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License * https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * * This software is based upon MIT Object Tcl by David Wetherall and * Christopher J. Lindblad, that contains the following copyright * message: * * "Copyright 1993 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this * software and its documentation for any purpose is hereby granted * without fee, provided that the above copyright notice appear in * all copies and that both that copyright notice and this * permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity * pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about * the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty." */ #define NSF_FORWARD_WITH_ONERROR 1 #define NSF_C 1 #include "nsfInt.h" #include "nsfAccessInt.h" #ifdef COMPILE_NSF_STUBS # if defined(PRE86) EXTERN NsfStubs nsfStubs; # else MODULE_SCOPE const NsfStubs nsfStubs; # endif #endif #ifdef USE_TCL_STUBS # define Nsf_ExprObjCmd(clientData, interp, objc, objv) \ NsfCallCommand(interp, NSF_EXPR, objc, objv) #else # define Nsf_ExprObjCmd(clientData, interp, objc, objv) \ Tcl_ExprObjCmd(clientData, interp, objc, objv) #endif /* * Call Stack specific definitions */ typedef enum { CALLING_LEVEL, ACTIVE_LEVEL } CallStackLevel; typedef struct callFrameContext { Tcl_CallFrame *framePtr; Tcl_CallFrame *varFramePtr; bool frameSaved; } callFrameContext; /* #define COLON_CMD_STATS 1 */ typedef struct { void *context; Tcl_Command cmd; NsfClass *class; unsigned int methodEpoch; unsigned int flags; #if defined(COLON_CMD_STATS) size_t hits; size_t invalidates; size_t requiredRefetches; Tcl_Obj *obj; #endif } NsfColonCmdContext; typedef struct NsfProcContext { ClientData oldDeleteData; Tcl_CmdDeleteProc *oldDeleteProc; NsfParamDefs *paramDefs; long *colonLocalVarCache; unsigned int checkAlwaysFlag; Tcl_Namespace *execNsPtr; Tcl_Obj *returnsObj; } NsfProcContext; /* * TclCmdClientdata is an incomplete type containing the common * field(s) of ForwardCmdClientData, AliasCmdClientData and * SetterCmdClientData used for filling in at run time the actual * object. */ typedef struct TclCmdClientData { NsfObject *object; } TclCmdClientData; typedef struct SetterCmdClientData { NsfObject *object; Nsf_Param *paramsPtr; } SetterCmdClientData; typedef struct ForwardCmdClientData { NsfObject *object; Tcl_Obj *cmdName; Tcl_ObjCmdProc *objProc; ClientData clientData; bool passthrough; bool needobjmap; bool verbose; bool hasNonposArgs; Tcl_Obj *args; int nr_args; int frame; #if defined(NSF_FORWARD_WITH_ONERROR) Tcl_Obj *onerror; #endif Tcl_Obj *prefix; Tcl_Obj *subcommands; int nr_subcommands; } ForwardCmdClientData; typedef struct AliasCmdClientData { NsfObject *object; Tcl_Obj *cmdName; Tcl_ObjCmdProc *objProc; ClientData clientData; NsfClass *class; Tcl_Interp *interp; Tcl_Command aliasedCmd; Tcl_Command aliasCmd; } AliasCmdClientData; /* * When NSF_MEM_COUNT is set, we want to trace as well the mem-count frees * associated with the interp. Therefore, we need in this case a special * client data structure. */ #ifdef NSF_MEM_COUNT typedef struct NsfNamespaceClientData { NsfObject *object; Tcl_Namespace *nsPtr; Tcl_Interp *interp; } NsfNamespaceClientData; #endif /* * Argv parsing specific definitions */ #define PARSE_CONTEXT_PREALLOC 20 typedef struct { ClientData *clientData; /* 4 members pointer to the actual parse context data */ Tcl_Obj **objv; Tcl_Obj **full_objv; /* contains method as well */ unsigned int *flags; ClientData clientData_static[PARSE_CONTEXT_PREALLOC]; /* 3 preallocated parse context data */ Tcl_Obj *objv_static[PARSE_CONTEXT_PREALLOC+1]; unsigned int flags_static[PARSE_CONTEXT_PREALLOC+1]; unsigned int status; int lastObjc; /* points to the first "unprocessed" argument */ int objc; NsfObject *object; bool varArgs; /* does the parameter end with some kind of "args" */ } ParseContext; static Nsf_TypeConverter ConvertToNothing, ConvertViaCmd, ConvertToObjpattern; static const char *autonamePrefix = "::nsf::__#"; static const size_t autonamePrefixLength = 10u; static const char * nsfClassesPrefix = "::nsf::classes"; static const size_t nsfClassesPrefixLength = 14u; /* * Tcl_Obj Types for Next Scripting Objects */ static Tcl_ObjType CONST86 *Nsf_OT_byteCodeType = NULL, *Nsf_OT_tclCmdNameType = NULL, *Nsf_OT_listType = NULL, *Nsf_OT_doubleType = NULL, *Nsf_OT_intType = NULL, *Nsf_OT_parsedVarNameType = NULL, *Nsf_OT_byteArrayType = NULL, *Nsf_OT_properByteArrayType = NULL, *Nsf_OT_bignumType = NULL; /* * Function prototypes */ /* * Prototypes for method definitions */ static Tcl_ObjCmdProc NsfForwardMethod; static Tcl_ObjCmdProc NsfObjscopedMethod; static Tcl_ObjCmdProc NsfSetterMethod; static Tcl_ObjCmdProc NsfProcAliasMethod; static Tcl_ObjCmdProc NsfAsmProc; Tcl_ObjCmdProc NsfProcStub; /* * Prototypes for interpreter life-cyle */ EXTERN Tcl_LibraryInitProc Nsf_SafeInit; EXTERN Tcl_LibraryInitProc Nsf_Init; static Tcl_ExitProc Nsf_ExitProc; static Tcl_ExitProc ExitHandler; #if defined(TCL_THREADS) static Tcl_ExitProc Nsf_ThreadExitProc; #endif /* * Prototypes for methods called directly when CallDirectly() returns NULL */ static int NsfCAllocMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *nameObj) nonnull(1) nonnull(2); static int NsfCAllocMethod_(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *nameObj, Tcl_Namespace *parentNsPtr) nonnull(1) nonnull(2) nonnull(3); static int NsfCCreateMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *nameObj, int objc, Tcl_Obj *const objv[]) nonnull(1) nonnull(2) nonnull(3) nonnull(5); static int NsfOCleanupMethod(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); static int NsfOConfigureMethod(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const objv[], Tcl_Obj *objv0) nonnull(1) nonnull(2) nonnull(4) nonnull(5); static int NsfODestroyMethod(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); static int MethodDispatch( Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Tcl_Command cmd, NsfObject *object, NsfClass *class, const char *methodName, unsigned short frameType, unsigned int flags ) nonnull(1) nonnull(3) nonnull(4) nonnull(5) nonnull(7); static int DispatchDefaultMethod(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *obj, unsigned int flags) nonnull(1) nonnull(2) nonnull(3); static int DispatchDestroyMethod(Tcl_Interp *interp, NsfObject *object, unsigned int flags) nonnull(1) nonnull(2); static int DispatchUnknownMethod( Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const objv[], Tcl_Obj *callInfoObj, Tcl_Obj *methodObj, unsigned int flags ) nonnull(1) nonnull(2) nonnull(4) nonnull(6); NSF_INLINE static int ObjectDispatch( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], unsigned int flags ) nonnull(1) nonnull(2) nonnull(4); NSF_INLINE static int ObjectDispatchFinalize( Tcl_Interp *interp, NsfCallStackContent *cscPtr, int result /*, const char *string , const char *methodName*/ ) nonnull(1) nonnull(2); /* * Prototypes for object life-cycle management */ static int RecreateObject(Tcl_Interp *interp, NsfClass *class, NsfObject *object, int objc, Tcl_Obj *const objv[]) nonnull(1) nonnull(2) nonnull(3) nonnull(5); static void FinalObjectDeletion(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); #if defined(DO_CLEANUP) static void FreeAllNsfObjectsAndClasses(Tcl_Interp *interp, NsfCmdList **instances) nonnull(1) nonnull(2); #endif static void CallStackDestroyObject(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); static void PrimitiveCDestroy(ClientData clientData) nonnull(1); static void PrimitiveODestroy(ClientData clientData) nonnull(1); static void PrimitiveDestroy(ClientData clientData) nonnull(1); static int VolatileMethod(Tcl_Interp *interp, NsfObject *object, bool shallow) nonnull(1) nonnull(2); /* * Prototypes for object and command lookup */ static NsfObject *GetObjectFromString(Tcl_Interp *interp, const char *name) nonnull(1) nonnull(2); static NsfClass *GetClassFromString(Tcl_Interp *interp, const char *name) nonnull(1) nonnull(2); static int GetClassFromObj(Tcl_Interp *interp, register Tcl_Obj *objPtr, NsfClass **classPtr, bool withUnknown) nonnull(1) nonnull(2) nonnull(3); static void GetAllInstances(Tcl_Interp *interp, NsfCmdList **instances, NsfClass *startClass) nonnull(1) nonnull(2) nonnull(3); NSF_INLINE static Tcl_Command FindMethod( const Tcl_Namespace *nsPtr, const char *methodName ) nonnull(1) nonnull(2); NSF_INLINE static NsfClasses *PrecedenceOrder( NsfClass *class ) nonnull(1); /* * Prototypes for namespace specific calls */ static Tcl_Obj *NameInNamespaceObj(const char *name, Tcl_Namespace *nsPtr) nonnull(1) nonnull(2); static Tcl_Namespace *CallingNameSpace(Tcl_Interp *interp) nonnull(1) returns_nonnull; NSF_INLINE static Tcl_Command NSFindCommand(Tcl_Interp *interp, const char *name) nonnull(1) nonnull(2); static Tcl_Namespace *NSGetFreshNamespace(Tcl_Interp *interp, NsfObject *object, const char *name) nonnull(1) nonnull(2) nonnull(3); static Tcl_Namespace *RequireObjNamespace(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); static int NSDeleteCmd(Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *methodName) nonnull(1) nonnull(2) nonnull(3); static void NSNamespaceDeleteProc(ClientData clientData) nonnull(1); static void NSNamespacePreserve(Tcl_Namespace *nsPtr) nonnull(1); static void NSNamespaceRelease(Tcl_Namespace *nsPtr) nonnull(1); /* * Prototypes for filters and mixins */ static void FilterComputeDefined(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); static void MixinComputeDefined(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); NSF_INLINE static void GuardAdd(NsfCmdList *guardList, Tcl_Obj *guardObj) nonnull(1) nonnull(2); static int GuardCall(NsfObject *object, Tcl_Interp *interp, Tcl_Obj *guardObj, NsfCallStackContent *cscPtr) nonnull(1) nonnull(2) nonnull(3); static void GuardDel(NsfCmdList *guardList) nonnull(1); /* * Prototypes for forwarders */ static void ForwardCmdDeleteProc(ClientData clientData) nonnull(1); static int ForwardProcessOptions( Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_Obj *withDefault, int withEarlybinding, Tcl_Obj *withOnerror, Tcl_Obj *withMethodprefix, int withFrame, bool withVerbose, Tcl_Obj *target, int objc, Tcl_Obj * const objv[], ForwardCmdClientData **tcdPtr ) nonnull(1) nonnull(2) nonnull(11); /* * Properties of objects and classes */ static bool IsRootClass( const NsfClass *class ) nonnull(1) NSF_pure; static bool IsRootMetaClass( const NsfClass *class ) nonnull(1) NSF_pure; static bool IsBaseClass( const NsfObject *object ) nonnull(1) NSF_pure; static bool IsMetaClass( Tcl_Interp *interp, NsfClass *class, bool withMixins ) nonnull(1) nonnull(2); static bool IsSubType( NsfClass *subClass, const NsfClass *class ) nonnull(1) nonnull(2); static NsfClass *DefaultSuperClass( Tcl_Interp *interp, const NsfClass *class, const NsfClass *metaClass, bool isMeta ) nonnull(1) nonnull(2) nonnull(3); /* * Prototypes for call stack specific calls */ NSF_INLINE static void CscInit_( NsfCallStackContent *cscPtr, NsfObject *object, NsfClass *class, const Tcl_Command cmd, unsigned short frameType, unsigned int flags ) nonnull(1) nonnull(2); NSF_INLINE static void CscFinish_(Tcl_Interp *interp, NsfCallStackContent *cscPtr) nonnull(1) nonnull(2); NSF_INLINE static void CallStackDoDestroy(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); static void NsfShowStack(Tcl_Interp *interp) nonnull(1); /* * Prototypes for parameter and argument management */ static int NsfParameterCacheClassInvalidateCmd(Tcl_Interp *interp, NsfClass *class) nonnull(1) nonnull(2); static int ProcessMethodArguments( ParseContext *pcPtr, Tcl_Interp *interp, NsfObject *object, unsigned int processFlags, NsfParamDefs *paramDefs, Tcl_Obj *methodNameObj, int objc, Tcl_Obj *const objv[] ) nonnull(1) nonnull(2) nonnull(5) nonnull(6) nonnull(8); static int ParameterCheck( Tcl_Interp *interp, Tcl_Obj *paramObjPtr, Tcl_Obj *valueObj, const char *argNamePrefix, unsigned int doCheckArguments, bool isNamed, bool doConfigureParameter, Nsf_Param **paramPtrPtr, const char *qualifier ) nonnull(1) nonnull(2) nonnull(3); static void ParamDefsRefCountIncr(NsfParamDefs *paramDefs) nonnull(1); static void ParamDefsRefCountDecr( NsfParamDefs *paramDefs ) nonnull(1); static void ParsedParamFree( NsfParsedParam *parsedParamPtr ) nonnull(1); NSF_INLINE static NsfParamDefs *ParamDefsGet( const Tcl_Command cmdPtr, unsigned int *checkAlwaysFlagPtr, Tcl_Namespace **execNsPtrPtr ) nonnull(1); NSF_INLINE static NsfProcContext *ProcContextGet( const Tcl_Command cmdPtr ) nonnull(1) NSF_pure; static NsfProcContext *ProcContextRequire( Tcl_Command cmd ) nonnull(1); static int ArgumentParse( Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], NsfObject *object, Tcl_Obj *procNameObj, const Nsf_Param *paramPtr, int nrParams, int serial, unsigned int processFlags, ParseContext *pcPtr ) nonnull(1) nonnull(5) nonnull(6) nonnull(10); static int ArgumentCheck( Tcl_Interp *interp, Tcl_Obj *objPtr, const struct Nsf_Param *pPtr, unsigned int doCheckArguments, unsigned int *flags, ClientData *clientData, Tcl_Obj **outObjPtr ) nonnull(1) nonnull(2) nonnull(3) nonnull(5) nonnull(6) nonnull(7); static int GetMatchObject( Tcl_Interp *interp, Tcl_Obj *patternObj, Tcl_Obj *origObj, NsfObject **matchObjectPtr, const char **patternPtr ) nonnull(1) nonnull(4) nonnull(5); static void NsfProcDeleteProc(ClientData clientData) nonnull(1); static int NsfParameterCacheObjectInvalidateCmd( Tcl_Interp *interp, NsfObject *object ) nonnull(1) nonnull(2); static int GetObjectParameterDefinition( Tcl_Interp *interp, Tcl_Obj *procNameObj, NsfObject *object, NsfClass *class, NsfParsedParam *parsedParamPtr ) nonnull(1) nonnull(2) nonnull(5); typedef Tcl_Obj *(NsfFormatFunction)( Tcl_Interp *interp, const Nsf_Param *paramsPtr, NsfObject *contextObject, const char *pattern ); static Tcl_Obj *NsfParamDefsVirtualFormat( Tcl_Interp *interp, const Nsf_Param *pPtr, NsfObject *contextObject, const char *pattern, NsfFormatFunction formatFunction ) nonnull(1) nonnull(2) nonnull(3) nonnull(5); static bool NsfParamDefsAppendVirtual( Tcl_Interp *interp, Tcl_Obj *listObj, const Nsf_Param *paramsPtr, NsfObject *contextObject, const char *pattern, NsfFormatFunction formatFunction ) nonnull(1) nonnull(2) nonnull(3) nonnull(6); /* * Prototypes for methods. */ static const char *MethodName(Tcl_Obj *methodObj) nonnull(1) returns_nonnull; /* * Prototypes for alias management. */ static int AliasDelete(Tcl_Interp *interp, Tcl_Obj *cmdName, const char *methodName, bool withPer_object) nonnull(1) nonnull(2) nonnull(3); static Tcl_Obj *AliasGet(Tcl_Interp *interp, Tcl_Obj *cmdName, const char *methodName, bool withPer_object, bool leaveError) nonnull(1) nonnull(2) nonnull(3); static bool AliasDeleteObjectReference(Tcl_Interp *interp, Tcl_Command cmd) nonnull(1) nonnull(2); static int AliasRefetch(Tcl_Interp *interp, NsfObject *object, const char *methodName, AliasCmdClientData *tcd) nonnull(1) nonnull(2) nonnull(3) nonnull(4); NSF_INLINE static Tcl_Command AliasDereference(Tcl_Interp *interp, NsfObject *object, const char *methodName, Tcl_Command cmd) nonnull(1) nonnull(2) nonnull(3) nonnull(4); /* * Prototypes for (class) list handling */ static NsfClasses ** NsfClassListAdd(NsfClasses **firstPtrPtr, NsfClass *class, ClientData clientData) nonnull(1) returns_nonnull; /* * Misc prototypes */ static int SetInstVar(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *nameObj, Tcl_Obj *valueObj, unsigned int flags) nonnull(1) nonnull(2) nonnull(3); static int UnsetInstVar(Tcl_Interp *interp, int withNocomplain, NsfObject *object, const char *name) nonnull(1) nonnull(3) nonnull(4); static int NextSearchAndInvoke( Tcl_Interp *interp, const char *methodName, int objc, Tcl_Obj *const objv[], NsfCallStackContent *cscPtr, bool freeArgumentVector ) nonnull(1) nonnull(2) nonnull(5); static void CmdListFree(NsfCmdList **cmdList, NsfFreeCmdListClientData *freeFct) nonnull(1); static void NsfCommandPreserve(Tcl_Command cmd) nonnull(1); static void NsfCommandRelease(Tcl_Command cmd) nonnull(1); static Tcl_Command GetOriginalCommand(Tcl_Command cmd) nonnull(1) returns_nonnull; EXTERN void NsfDStringArgv(Tcl_DString *dsPtr, int objc, Tcl_Obj *const objv[]) nonnull(1) nonnull(3); static NsfObjectOpt *NsfRequireObjectOpt(NsfObject *object) nonnull(1) returns_nonnull; static int ObjectSystemsCheckSystemMethod( Tcl_Interp *interp, const char *methodName, const NsfObject *object, unsigned int flags ) nonnull(1) nonnull(2) nonnull(3); #ifdef DO_CLEANUP static void DeleteNsfProcs(Tcl_Interp *interp, Tcl_Namespace *nsPtr) nonnull(1); #endif #if defined(NSF_WITH_ASSERTIONS) static void AssertionRemoveProc(NsfAssertionStore *aStore, const char *name) nonnull(1) nonnull(2); #endif #ifdef DO_FULL_CLEANUP static void DeleteProcsAndVars(Tcl_Interp *interp, Tcl_Namespace *nsPtr, bool withKeepvars) nonnull(1) nonnull(2); #endif /* *---------------------------------------------------------------------- * * NsfDListInit -- * * Function similar to Tcl_DStringInit, but works on (void*) * elements instead of chars. * * In general, the NsfDList* operations work on static data as long * the space is sufficient, and doubles in size afterwards. In the * worst case, half of the data is unused, but that is the same * size of overhead like for a single linked list. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void NsfDListInit(NsfDList *dlPtr) { dlPtr->data = &dlPtr->static_data[0]; dlPtr->avail = nr_elements(dlPtr->static_data); dlPtr->size = 0u; } /* *---------------------------------------------------------------------- * * NsfDListAppend -- * * Function similar to Tcl_DStringAppend, but works on (void*) * elements instead of chars. * * Results: * None. * * Side effects: * Potentially allocating/reallocating memory. * *---------------------------------------------------------------------- */ static void NsfDListAppend(NsfDList *dlPtr, void *element) { if (dlPtr->avail < 1) { size_t requiredSize = dlPtr->size * 2u; if (dlPtr->data != &dlPtr->static_data[0]) { dlPtr->data = (void **)ckrealloc((char *)dlPtr->data, sizeof(dlPtr->data[0]) * requiredSize); } else { dlPtr->data = (void **)ckalloc(sizeof(dlPtr->data[0]) * requiredSize); memcpy(dlPtr->data, &dlPtr->static_data[0], dlPtr->size * sizeof(dlPtr->data[0])); } dlPtr->avail = requiredSize - dlPtr->size; } dlPtr->avail --; dlPtr->data[dlPtr->size] = element; dlPtr->size ++; } /* *---------------------------------------------------------------------- * * NsfDListFree -- * * Functions similar to Tcl_DStringFree, but but works on (void*) * elements instead of chars. * * Results: * None. * * Side effects: * Potentially freeing memory. * *---------------------------------------------------------------------- */ #ifdef DO_CLEANUP static void NsfDListFree(NsfDList *dlPtr) { if (dlPtr->data != &dlPtr->static_data[0]) { ckfree((char*)dlPtr->data); } NsfDListInit(dlPtr); } #endif /* *---------------------------------------------------------------------- * * NsfErrorContext -- * * Print the current errorCode and errorInfo to stderr. This * should be used as the last resort, when e.g. logging fails * * Results: * None. * * Side effects: * Output to stderr * *---------------------------------------------------------------------- */ static void NsfErrorContext( Tcl_Interp *interp, const char *context ) nonnull(1) nonnull(2); static void NsfErrorContext( Tcl_Interp *interp, const char *context ) { Tcl_DString ds, *dsPtr = &ds; nonnull_assert(interp != NULL); nonnull_assert(context != NULL); Tcl_DStringInit(dsPtr); Tcl_DStringAppend(dsPtr, "puts stderr \"Error in ", TCL_INDEX_NONE); Tcl_DStringAppend(dsPtr, context, TCL_INDEX_NONE); Tcl_DStringAppend(dsPtr, ":\n$::errorCode $::errorInfo\"", TCL_INDEX_NONE); Tcl_EvalEx(interp, Tcl_DStringValue(dsPtr), Tcl_DStringLength(dsPtr), 0); Tcl_DStringFree(dsPtr); } #if 0 static char * NsfErrorInfo( Tcl_Interp *interp ) { Tcl_Obj *valueObj; nonnull_assert(interp != NULL); valueObj = Tcl_GetVar2Ex(interp, "::errorInfo", NULL, TCL_GLOBAL_ONLY); if (valueObj != NULL) { return ObjStr(valueObj); } return NULL; } #endif /* *---------------------------------------------------------------------- * * NsfDStringEval -- * * Evaluate the provided Tcl_DString as a Tcl command and output * the error stack in case of a failure. * * Results: * A standard Tcl result. * * Side effects: * Output to stderr possible. * *---------------------------------------------------------------------- */ int NsfDStringEval( Tcl_Interp *interp, Tcl_DString *dsPtr, const char *context, unsigned int traceEvalFlags ) { Tcl_InterpState state = NULL; NsfRuntimeState *rst; int result, prevDoProfile; unsigned int prevPreventRecursionFlags; nonnull_assert(interp != NULL); nonnull_assert(dsPtr != NULL); nonnull_assert(context != NULL); rst = RUNTIME_STATE(interp); if ((traceEvalFlags & NSF_EVAL_PREVENT_RECURSION) != 0u) { /* * We do not want to debug the debug statements, since this would * cause an infinite recursion. Check whether we allow execution of * the eval call. */ if ((rst->preventRecursionFlags & traceEvalFlags) != 0) { /* * Recursive case, do NOT execute the cmd and return silently. */ return TCL_OK; } prevPreventRecursionFlags = rst->preventRecursionFlags; rst->preventRecursionFlags |= traceEvalFlags; } else { prevPreventRecursionFlags = 0u; } if ((traceEvalFlags & NSF_EVAL_NOPROFILE) && rst->doProfile == 1) { /* * Profiling should be deactivated for the eval. */ prevDoProfile = 1; rst->doProfile = 0; } else { prevDoProfile = 0; } if ((traceEvalFlags & NSF_EVAL_SAVE) != 0u) { state = Tcl_SaveInterpState(interp, TCL_OK); } result = Tcl_EvalEx(interp, Tcl_DStringValue(dsPtr), Tcl_DStringLength(dsPtr), 0); if (unlikely(result == TCL_ERROR)) { NsfErrorContext(interp, context); } if ((traceEvalFlags & NSF_EVAL_SAVE) != 0u) { Tcl_RestoreInterpState(interp, state); } if ((traceEvalFlags & NSF_EVAL_PREVENT_RECURSION) != 0u) { rst->preventRecursionFlags = prevPreventRecursionFlags; } if (prevDoProfile == 1) { rst->doProfile = 1; } return result; } /* *---------------------------------------------------------------------- * * NsfLog -- * * Produce a formatted warning by calling an external function * ::nsf::log. It is defined static to allow for inlining. * * Results: * None. * * Side effects: * Output of the warning. * *---------------------------------------------------------------------- */ void NsfLog( Tcl_Interp *interp, int requiredLevel, const char *fmt, ... ) { nonnull_assert(interp != NULL); nonnull_assert(fmt != NULL); if (requiredLevel >= RUNTIME_STATE(interp)->logSeverity) { int destroyRound = RUNTIME_STATE(interp)->exitHandlerDestroyRound; Tcl_DString cmdString, ds; const char *level; va_list ap; switch (requiredLevel) { case NSF_LOG_DEBUG: level = "Debug"; break; case NSF_LOG_NOTICE: level = "Notice"; break; default: level = "Warning"; break; } Tcl_DStringInit(&ds); va_start(ap, fmt); NsfDStringVPrintf(&ds, fmt, ap); va_end(ap); Tcl_DStringInit(&cmdString); Tcl_DStringAppendElement(&cmdString, "::nsf::log"); Tcl_DStringAppendElement(&cmdString, level); Tcl_DStringAppendElement(&cmdString, Tcl_DStringValue(&ds)); if (destroyRound != NSF_EXITHANDLER_ON_PHYSICAL_DESTROY) { NsfDStringEval(interp, &cmdString, "log command", (NSF_EVAL_LOG|NSF_EVAL_NOPROFILE)); } else { /* * On physical destroy, we can't rely on NsfDStringEval() working * properly. */ fprintf(stderr, "%s", cmdString.string); } Tcl_DStringFree(&cmdString); Tcl_DStringFree(&ds); } } /* *---------------------------------------------------------------------- * * NsfDeprecatedCmd -- * * Provide a warning about a deprecated command or method. The * message is produced via calling the external Tcl function * ::nsf::deprecated. In case, profiling is turned on, it is * deactivated temporarily. Saving the interp result should not be * an issue, since the command is called before the body of the * command is executed. * * Results: * None. * * Side effects: * Output of the warning. * *---------------------------------------------------------------------- */ void NsfDeprecatedCmd( Tcl_Interp *interp, const char *what, const char *oldCmd, const char *newCmd ) { Tcl_DString ds, *dsPtr = &ds; nonnull_assert(interp != NULL); nonnull_assert(newCmd != NULL); nonnull_assert(what != NULL); nonnull_assert(oldCmd != NULL); Tcl_DStringInit(dsPtr); Tcl_DStringAppendElement(dsPtr, "::nsf::deprecated"); Tcl_DStringAppendElement(dsPtr, what); Tcl_DStringAppendElement(dsPtr, oldCmd); Tcl_DStringAppendElement(dsPtr, newCmd); NsfDStringEval(interp, dsPtr, "deprecated command", (NSF_EVAL_DEPRECATED|NSF_EVAL_NOPROFILE)); Tcl_DStringFree(dsPtr); } /*********************************************************************** * argv parsing ***********************************************************************/ /* *---------------------------------------------------------------------- * * ParseContextInit -- * * Initialize a ParseContext with default values and allocate * memory if needed. Every ParseContext has to be initialized * before usage and has to be freed with ParseContextRelease(). * * Results: * None. * * Side effects: * Allocate potentially memory. * *---------------------------------------------------------------------- */ static void ParseContextInit( ParseContext *pcPtr, int objc, NsfObject *object, Tcl_Obj *procName ) nonnull(1) nonnull(4); static void ParseContextInit( ParseContext *pcPtr, int objc, NsfObject *object, Tcl_Obj *procName ) { nonnull_assert(pcPtr != NULL); nonnull_assert(procName != NULL); if (likely(objc < PARSE_CONTEXT_PREALLOC)) { /* * The single larger memset below .... */ memset(pcPtr, 0, sizeof(ParseContext)); /* * ... is faster than the two smaller memsets below. */ /* memset(pcPtr->clientData_static, 0, sizeof(ClientData)*(objc)); memset(pcPtr->objv_static, 0, sizeof(Tcl_Obj *)*(objc+1));*/ pcPtr->full_objv = &pcPtr->objv_static[0]; pcPtr->clientData = &pcPtr->clientData_static[0]; pcPtr->flags = &pcPtr->flags_static[0]; } else { pcPtr->full_objv = (Tcl_Obj **)ckalloc((int)sizeof(Tcl_Obj *) * ((unsigned)objc+1u)); pcPtr->flags = (unsigned *)ckalloc((unsigned)sizeof(int) * ((unsigned)objc+1u)); MEM_COUNT_ALLOC("pcPtr.objv", pcPtr->full_objv); pcPtr->clientData = (ClientData *)ckalloc((unsigned)sizeof(ClientData) * (unsigned)objc); MEM_COUNT_ALLOC("pcPtr.clientData", pcPtr->clientData); /*fprintf(stderr, "ParseContextMalloc %d objc, %p %p\n", objc, pcPtr->full_objv, pcPtr->clientData);*/ memset(pcPtr->full_objv, 0, sizeof(Tcl_Obj *) * (size_t)(objc+1)); memset(pcPtr->flags, 0, sizeof(int) * (size_t)(objc+1)); memset(pcPtr->clientData, 0, sizeof(ClientData) * (size_t)objc); pcPtr->status = NSF_PC_STATUS_FREE_OBJV|NSF_PC_STATUS_FREE_CD; pcPtr->varArgs = NSF_FALSE; pcPtr->objc = 0; } pcPtr->objv = &pcPtr->full_objv[1]; pcPtr->full_objv[0] = procName; pcPtr->object = object; } /* *---------------------------------------------------------------------- * * ParseContextExtendObjv -- * * Extend Tcl_Obj array at run time, when more elements are * needed. This function is called to extend an already * initialized ParseContext. * * Results: * None. * * Side effects: * Allocate potentially memory. * *---------------------------------------------------------------------- */ static void ParseContextExtendObjv( ParseContext *pcPtr, unsigned from, unsigned elts, Tcl_Obj *const source[] ) nonnull(1) nonnull(4); static void ParseContextExtendObjv( ParseContext *pcPtr, unsigned from, unsigned elts, Tcl_Obj *const source[] ) { unsigned requiredSize = from + elts + 1; nonnull_assert(pcPtr != NULL); nonnull_assert(source != NULL); /*NsfPrintObjv("BEFORE: ", pcPtr->objc, pcPtr->full_objv);*/ if (unlikely(requiredSize >= PARSE_CONTEXT_PREALLOC)) { if (pcPtr->objv == &pcPtr->objv_static[1]) { /* * Realloc from preallocated memory */ pcPtr->full_objv = (Tcl_Obj **)ckalloc((int)sizeof(Tcl_Obj *) * requiredSize); pcPtr->flags = (unsigned *)ckalloc((int)sizeof(int) * requiredSize); MEM_COUNT_ALLOC("pcPtr.objv", pcPtr->full_objv); memcpy(pcPtr->full_objv, &pcPtr->objv_static[0], sizeof(Tcl_Obj *) * PARSE_CONTEXT_PREALLOC); memcpy(pcPtr->flags, &pcPtr->flags_static[0], sizeof(int) * PARSE_CONTEXT_PREALLOC); /* fprintf(stderr, "ParseContextExtendObjv: extend %p alloc %d new objv=%p pcPtr %p\n", pcPtr, requiredSize, pcPtr->full_objv, pcPtr);*/ pcPtr->status |= NSF_PC_STATUS_FREE_OBJV; } else { /* * Realloc from mallocated memory */ pcPtr->full_objv = (Tcl_Obj **)ckrealloc((char *)pcPtr->full_objv, (unsigned)sizeof(Tcl_Obj *) * requiredSize); pcPtr->flags = (unsigned *)ckrealloc((char *)pcPtr->flags, (unsigned)sizeof(int) * requiredSize); /*fprintf(stderr, "ParseContextExtendObjv: extend %p realloc %d new objv=%p pcPtr %p\n", pcPtr, requiredSize, pcPtr->full_objv, pcPtr);*/ } pcPtr->objv = &pcPtr->full_objv[1]; } memcpy(pcPtr->objv + from, source, sizeof(Tcl_Obj *) * (size_t)elts); memset(pcPtr->flags + from, 0, sizeof(int) * (size_t)elts); pcPtr->objc = pcPtr->objc + (int)elts; /*NsfPrintObjv("AFTER: ", pcPtr->objc, pcPtr->full_objv);*/ } /* *---------------------------------------------------------------------- * * ParseContextRelease -- * * Release (and potentially free) the content of a * ParseContext. This function is the counterpart of * ParseContextInit(), * * Results: * None. * * Side effects: * Free potentially memory. * *---------------------------------------------------------------------- */ static void ParseContextRelease(ParseContext *pcPtr) nonnull(1); static void ParseContextRelease(ParseContext *pcPtr) { unsigned int status; nonnull_assert(pcPtr != NULL); status = pcPtr->status; /*fprintf(stderr, "ParseContextRelease %p status %.6x %d elements\n", pcPtr, status, pcPtr->objc);*/ #if defined(NSF_DEVELOPMENT_TEST) { /* * Perform a general consistency check: although the contents of the parse * context are at release time sometimes only partially initialized, the * following holds true for ensuring correct release of Tcl_Objs: * * 1) if one of the objv-flags has NSF_PC_MUST_DECR set, * then the status flag NSF_PC_STATUS_MUST_DECR has to * be set as well. * * 2) if objc > 0 then for all objv entries having a flag * different from 0 must have a * TCL_OBJ in the vector. * * 3) for preallocated objvs, all elements of the objv * after the argument vector must be 0 or * NSF_PC_IS_DEFAULT (sanity check) */ /* * (1) make sure that the status correctly reflects MUST_DECR. */ int i; if (status == 0u || (status & NSF_PC_STATUS_MUST_DECR) == 0u) { for (i = 0; i < pcPtr->objc - 1; i++) { assert((pcPtr->flags[i] & NSF_PC_MUST_DECR) == 0); } } /* * (2) make sure, Tcl_Objs are set when needed for reclaiming memory. */ if (pcPtr->objc > 0) { /*fprintf(stderr, "%s ", ObjStr(pcPtr->full_objv[0]));*/ for (i = 0; i < pcPtr->objc; i++) { if (pcPtr->flags[i] != 0u) { assert(pcPtr->objv[i]); /*fprintf(stderr, "[%d]%s %.6x ", i, ObjStr(pcPtr->objv[i]), pcPtr->flags[i]);*/ } } } /* * (3) All later flags must be empty or DEFAULT. */ if (pcPtr->full_objv == &pcPtr->objv_static[0] && pcPtr->objc > 0) { for (i = pcPtr->objc; i < PARSE_CONTEXT_PREALLOC; i++) { assert(pcPtr->flags[i] == 0u || pcPtr->flags[i] == NSF_PC_IS_DEFAULT); } } } #endif if (unlikely(status != 0u)) { if ((status & NSF_PC_STATUS_MUST_DECR) != 0u) { int i; /*fprintf(stderr, "ParseContextRelease %p loop from 0 to %d\n", pcPtr, pcPtr->objc-1);*/ for (i = 0; i < pcPtr->objc; i++) { /*fprintf(stderr, "ParseContextRelease %p check [%d] obj %p flags %.6x & %p\n", pcPtr, i, pcPtr->objv[i], pcPtr->flags[i], &(pcPtr->flags[i]));*/ if ((pcPtr->flags[i] & NSF_PC_MUST_DECR) != 0u) { assert(pcPtr->objv[i]); assert(pcPtr->objv[i]->refCount > 0); /*fprintf(stderr, "... decr ref count on %p\n", pcPtr->objv[i]);*/ DECR_REF_COUNT2("valueObj", pcPtr->objv[i]); } } } /* * Objv can be separately extended; also flags are extend when this * happens. */ if (unlikely((status & NSF_PC_STATUS_FREE_OBJV) != 0u)) { /*fprintf(stderr, "ParseContextRelease %p free %p %p\n", pcPtr, pcPtr->full_objv, pcPtr->clientData);*/ MEM_COUNT_FREE("pcPtr.objv", pcPtr->full_objv); ckfree((char *)pcPtr->full_objv); ckfree((char *)pcPtr->flags); } /* * If the parameter definition was extended at creation time also * clientData is extended. */ if ((status & NSF_PC_STATUS_FREE_CD) != 0u) { /*fprintf(stderr, "free client-data for %p\n", pcPtr);*/ MEM_COUNT_FREE("pcPtr.clientData", pcPtr->clientData); ckfree((char *)pcPtr->clientData); } } } /* *---------------------------------------------------------------------- * * CallMethod -- * * Call a Next Scripting method. The provided "clientData" has to * contain the object, on which the method is to be dispatched, * "methodDobj" denotes the method, "objc" (which has to be >=2) * and "objv" denotes the argument vector. * * Results: * A standard Tcl result. * * Side effects: * potentially via the called method. * *---------------------------------------------------------------------- */ /* * call a Next Scripting method */ static int CallMethod(ClientData clientData, Tcl_Interp *interp, Tcl_Obj *methodObj, int objc, Tcl_Obj *const objv[], unsigned int flags) nonnull(1) nonnull(2) nonnull(3); static int CallMethod(ClientData clientData, Tcl_Interp *interp, Tcl_Obj *methodObj, int objc, Tcl_Obj *const objv[], unsigned int flags) { NsfObject *object; int result; ALLOC_ON_STACK(Tcl_Obj*, objc, tov); nonnull_assert(clientData != NULL); nonnull_assert(interp != NULL); nonnull_assert(methodObj != NULL); assert(objc > 1); object = (NsfObject *) clientData; tov[0] = object->cmdName; tov[1] = methodObj; if (likely(objc > 2)) { memcpy(tov+2, objv, sizeof(Tcl_Obj *) * ((size_t)objc - 2u)); } /*fprintf(stderr, "%%%% CallMethod cmdName=%s, method=%s, objc=%d\n", ObjStr(tov[0]), ObjStr(tov[1]), objc); {int i; fprintf(stderr, "\t CALL: %s ", ObjStr(methodObj));for(i = 0; i < objc-2; i++) { fprintf(stderr, "%s ", ObjStr(objv[i]));} fprintf(stderr, "\n");}*/ result = ObjectDispatch(clientData, interp, objc, tov, flags); FREE_ON_STACK(Tcl_Obj*, tov); return result; } /* *---------------------------------------------------------------------- * * NsfCallMethodWithArgs -- * * Call method (passed in methodObj) on the object, with the often * provided arg1 and the optional remaining args (passed vis objv). * This way, we save the memcpy in case no argument or a single * argument are provided (common cases). * * Results: * A standard Tcl result. * * Side effects: * Called method might side effect. * *---------------------------------------------------------------------- */ int NsfCallMethodWithArgs(Tcl_Interp *interp, Nsf_Object *object, Tcl_Obj *methodObj, Tcl_Obj *arg1, int givenObjc, Tcl_Obj *const objv[], unsigned int flags) nonnull(1) nonnull(2) nonnull(3); int NsfCallMethodWithArgs(Tcl_Interp *interp, Nsf_Object *object, Tcl_Obj *methodObj, Tcl_Obj *arg1, int givenObjc, Tcl_Obj *const objv[], unsigned int flags) { int objc = givenObjc + 2; int result; ALLOC_ON_STACK(Tcl_Obj*, objc, tov); nonnull_assert(interp != NULL); nonnull_assert(object != NULL); assert(ISOBJ_(methodObj)); assert(objc > 1); tov[0] = object->cmdName; tov[1] = methodObj; if (objc > 2) { tov[2] = arg1; } if (objc > 3) { memcpy(tov+3, objv, sizeof(Tcl_Obj *) * ((size_t)objc - 3u)); } /*fprintf(stderr, "%%%% CallMethodWithArgs cmdName=%s, method=%s, arg1 %s objc=%d\n", ObjStr(tov[0]), ObjStr(tov[1]), (objc > 2) ? ObjStr(tov[2]) : "", objc);*/ result = ObjectDispatch(object, interp, objc, tov, flags); FREE_ON_STACK(Tcl_Obj*, tov); return result; } /* * Support for variable hash tables */ static NSF_INLINE Var *VarHashCreateVar(TclVarHashTable *tablePtr, const Tcl_Obj *key, int *newPtr) nonnull(1) nonnull(2); static NSF_INLINE Var * VarHashCreateVar(TclVarHashTable *tablePtr, const Tcl_Obj *key, int *newPtr) { Var *varPtr; const Tcl_HashEntry *hPtr; nonnull_assert(tablePtr != NULL); nonnull_assert(key != NULL); hPtr = Tcl_CreateHashEntry((Tcl_HashTable *) tablePtr, (char *) key, newPtr); if (likely(hPtr != NULL)) { varPtr = TclVarHashGetValue(hPtr); } else { varPtr = NULL; } return varPtr; } static NSF_INLINE TclVarHashTable * VarHashTableCreate(void) { TclVarHashTable *varTablePtr = (TclVarHashTable *) ckalloc((int)sizeof(TclVarHashTable)); TclInitVarHashTable(varTablePtr, NULL); return varTablePtr; } #include "nsfCmdPtr.c" #include "nsfStack.c" /*********************************************************************** * Value added replacements of Tcl functions ***********************************************************************/ /* *---------------------------------------------------------------------- * Nsf_NextHashEntry -- * * Function very similar to Tcl_NextHashEntry. If during the * iteration of hash entries some of these entries are removed, * Tcl_NextHashEntry() can lead to a valid looking but invalid * hPtr, when the next entry was already deleted. This seem to * occur only, when there are more than 12 hash entries in the * table (multiple buckets). Therefore, we use numEntries to check * whether it is sensible to return a hash entry. We can trigger * refetch of the hSrchPtr, when the number of expected entries * differs from the numbers of the actual entries. * * Results: * Hash Entry or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_HashEntry * Nsf_NextHashEntry(Tcl_HashTable *tablePtr, TCL_SIZE_T expected, Tcl_HashSearch *hSrchPtr) nonnull(1) nonnull(3); static Tcl_HashEntry * Nsf_NextHashEntry(Tcl_HashTable *tablePtr, TCL_SIZE_T expected, Tcl_HashSearch *hSrchPtr) { Tcl_HashEntry *result; nonnull_assert(tablePtr != NULL); nonnull_assert(hSrchPtr != NULL); /*fprintf(stderr, "Nsf_NextHashEntry %p expected %d numEntries %d\n", tablePtr, expected, tablePtr->numEntries);*/ if (tablePtr->numEntries < 1) { result = NULL; } else if (tablePtr->numEntries != expected) { result = Tcl_FirstHashEntry(tablePtr, hSrchPtr); } else { result = Tcl_NextHashEntry(hSrchPtr); } return result; } /* *---------------------------------------------------------------------- * NsfCommandPreserve -- * * Increment Tcl's command refCount * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void NsfCommandPreserve(Tcl_Command cmd) { nonnull_assert(cmd != NULL); Tcl_Command_refCount(cmd)++; MEM_COUNT_ALLOC("command.refCount", cmd); } /* *---------------------------------------------------------------------- * NsfCommandRelease -- * * Decrement Tcl command refCount and free it if necessary. * * Results: * None. * * Side effects: * Free potentially memory * *---------------------------------------------------------------------- */ static void NsfCommandRelease(Tcl_Command cmd) { nonnull_assert(cmd != NULL); /*fprintf(stderr, "NsfCommandRelease %p\n", cmd);*/ MEM_COUNT_FREE("command.refCount", cmd); TclCleanupCommandMacro((Command *)cmd); } /*********************************************************************** * EXTERN callable routines for the preliminary C interface ***********************************************************************/ Nsf_Object * NsfGetSelfObj(const Tcl_Interp *interp) nonnull(1) NSF_pure; Nsf_Object * NsfGetObject(Tcl_Interp *interp, const char *name) nonnull(1) nonnull(2); Nsf_Class * NsfGetClass(Tcl_Interp *interp, const char *name) nonnull(1) nonnull(2); Nsf_Class * NsfIsClass(Tcl_Interp *interp, ClientData clientData) nonnull(1) nonnull(2) NSF_pure; void NsfRequireObjNamespace(Tcl_Interp *interp, Nsf_Object *object) nonnull(1) nonnull(2); Tcl_Obj * Nsf_ObjSetVar2(Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, Tcl_Obj *valueObj, unsigned int flags) nonnull(1) nonnull(2) nonnull(3) nonnull(5); Tcl_Obj * Nsf_ObjGetVar2(Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, unsigned int flags) nonnull(1) nonnull(2) nonnull(3); int NsfCreate(Tcl_Interp *interp, Nsf_Class *class, Tcl_Obj *nameObj, int objc, Tcl_Obj *const objv[]) nonnull(1) nonnull(2) nonnull(3) nonnull(5); int NsfDeleteObject(Tcl_Interp *interp, Nsf_Object *object) nonnull(1) nonnull(2); int NsfRemoveObjectMethod(Tcl_Interp *interp, Nsf_Object *object, const char *methodName) nonnull(1) nonnull(2) nonnull(3); int NsfRemoveClassMethod(Tcl_Interp *interp, Nsf_Class *class, const char *methodName) nonnull(1) nonnull(2) nonnull(3); int Nsf_UnsetVar2(Nsf_Object *object, Tcl_Interp *interp, const char *name1, const char *name2, unsigned int flags) nonnull(1) nonnull(2) nonnull(4); void NsfSetObjClientData(Tcl_Interp *UNUSED(interp), Nsf_Object *object, ClientData data) nonnull(1) nonnull(2); ClientData NsfGetObjClientData(Tcl_Interp *UNUSED(interp), Nsf_Object *object) nonnull(1) nonnull(2) NSF_pure; void NsfSetClassClientData(Tcl_Interp *UNUSED(interp), Nsf_Class *class, ClientData data) nonnull(1) nonnull(2); ClientData NsfGetClassClientData(Tcl_Interp *UNUSED(interp), Nsf_Class *class) nonnull(1) nonnull(2) NSF_pure; Nsf_Object * NsfGetSelfObj(const Tcl_Interp *interp) { nonnull_assert(interp != NULL); return (Nsf_Object *) GetSelfObj(interp); } Nsf_Object * NsfGetObject(Tcl_Interp *interp, const char *name) { nonnull_assert(interp != NULL); nonnull_assert(name != NULL); return (Nsf_Object *) GetObjectFromString(interp, name); } Nsf_Class * NsfGetClass(Tcl_Interp *interp, const char *name) { nonnull_assert(interp != NULL); nonnull_assert(name != NULL); return (Nsf_Class *)GetClassFromString(interp, name); } Nsf_Class * NsfIsClass(Tcl_Interp *UNUSED(interp), ClientData clientData) { nonnull_assert(clientData != NULL); if (NsfObjectIsClass((NsfObject *)clientData)) { return (Nsf_Class *) clientData; } return NULL; } void NsfRequireObjNamespace(Tcl_Interp *interp, Nsf_Object *object) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); RequireObjNamespace(interp, (NsfObject *) object); } const char * NsfMethodName(Tcl_Obj *methodObj) { nonnull_assert(methodObj != NULL); return MethodName(methodObj); } Tcl_Obj * Nsf_ObjSetVar2(Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, Tcl_Obj *valueObj, unsigned int flags) { Tcl_Obj *result; CallFrame frame, *framePtr = &frame; nonnull_assert(object != NULL); nonnull_assert(interp != NULL); nonnull_assert(name1 != NULL); nonnull_assert(valueObj != NULL); #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, (NsfObject *)object, framePtr); #pragma GCC diagnostic pop if (((NsfObject *)object)->nsPtr != NULL) { flags |= TCL_NAMESPACE_ONLY; } result = Tcl_ObjSetVar2(interp, name1, name2, valueObj, (int)flags); Nsf_PopFrameObj(interp, framePtr); return result; } Tcl_Obj * Nsf_ObjGetVar2(Nsf_Object *object, Tcl_Interp *interp, Tcl_Obj *name1, Tcl_Obj *name2, unsigned int flags) { Tcl_Obj *result; CallFrame frame, *framePtr = &frame; nonnull_assert(object != NULL); nonnull_assert(interp != NULL); nonnull_assert(name1 != NULL); #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, (NsfObject *)object, framePtr); #pragma GCC diagnostic pop if (((NsfObject *)object)->nsPtr != NULL) { flags |= TCL_NAMESPACE_ONLY; } result = Tcl_ObjGetVar2(interp, name1, name2, (int)flags); Nsf_PopFrameObj(interp, framePtr); return result; } int Nsf_UnsetVar2(Nsf_Object *object, Tcl_Interp *interp, const char *name1, const char *name2, unsigned int flags) { CallFrame frame, *framePtr = &frame; NsfObject *o; int result; nonnull_assert(object != NULL); nonnull_assert(interp != NULL); nonnull_assert(name1 != NULL); nonnull_assert(name2 != NULL); o = (NsfObject *) object; #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, o, framePtr); #pragma GCC diagnostic pop if (o->nsPtr != NULL) { flags |= TCL_NAMESPACE_ONLY; } result = Tcl_UnsetVar2(interp, name1, name2, (int)flags); Nsf_PopFrameObj(interp, framePtr); return result; } int NsfCreate(Tcl_Interp *interp, Nsf_Class *class, Tcl_Obj *nameObj, int objc, Tcl_Obj *const objv[]) { NsfClass *cl = (NsfClass *) class; int result; ALLOC_ON_STACK(Tcl_Obj*, objc, tov); nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(nameObj != NULL); nonnull_assert(objv != NULL); INCR_REF_COUNT2("nameObj", nameObj); tov[0] = NULL; tov[1] = nameObj; if (objc > 0) { memcpy(tov+2, objv, sizeof(Tcl_Obj *) * (size_t)objc); } result = NsfCCreateMethod(interp, cl, nameObj, objc+2, tov); FREE_ON_STACK(Tcl_Obj*, tov); DECR_REF_COUNT2("nameObj", nameObj); return result; } int NsfDeleteObject(Tcl_Interp *interp, Nsf_Object *object) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); return DispatchDestroyMethod(interp, (NsfObject *)object, 0u); } int NsfRemoveObjectMethod(Tcl_Interp *interp, Nsf_Object *object, const char *methodName) { NsfObject *currentObject; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodName != NULL); currentObject = (NsfObject *) object; /*fprintf(stderr, "... NsfRemoveObjectMethod %s %s\n", ObjectName(currentObject), methodName);*/ NsfObjectMethodEpochIncr("NsfRemoveObjectMethod"); AliasDelete(interp, currentObject->cmdName, methodName, NSF_TRUE); #if defined(NSF_WITH_ASSERTIONS) if (currentObject->opt != NULL && currentObject->opt->assertions != NULL) { AssertionRemoveProc(currentObject->opt->assertions, methodName); } #endif if (currentObject->nsPtr != NULL) { int rc = NSDeleteCmd(interp, currentObject->nsPtr, methodName); if (rc < 0) { return NsfPrintError(interp, "%s: cannot delete object specific method '%s'", ObjectName_(currentObject), methodName); } } return TCL_OK; } int NsfRemoveClassMethod(Tcl_Interp *interp, Nsf_Class *class, const char *methodName) { const NsfClass *c; int rc; #if defined(NSF_WITH_ASSERTIONS) NsfClassOpt *opt; #endif nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(methodName != NULL); c = (NsfClass *)class; /*fprintf(stderr, "... NsfRemoveClassMethod %s %s\n", ClassName(class), methodName);*/ NsfInstanceMethodEpochIncr("NsfRemoveClassMethod"); AliasDelete(interp, class->object.cmdName, methodName, NSF_FALSE); #if defined(NSF_WITH_ASSERTIONS) opt = c->opt; if (opt != NULL && opt->assertions != NULL) { AssertionRemoveProc(opt->assertions, methodName); } #endif rc = NSDeleteCmd(interp, c->nsPtr, methodName); if (rc < 0) { return NsfPrintError(interp, "%s: cannot delete method '%s'", ClassName_(c), methodName); } return TCL_OK; } /* * obj/cl ClientData setter/getter */ void NsfSetObjClientData(Tcl_Interp *UNUSED(interp), Nsf_Object *object, ClientData data) { nonnull_assert(object != NULL); nonnull_assert(data != NULL); NsfRequireObjectOpt((NsfObject *) object) -> clientData = data; } ClientData NsfGetObjClientData(Tcl_Interp *UNUSED(interp), Nsf_Object *object) { NsfObject *object_; nonnull_assert(object != NULL); object_ = (NsfObject *) object; return (object_->opt != NULL) ? object_->opt->clientData : NULL; } void NsfSetClassClientData(Tcl_Interp *UNUSED(interp), Nsf_Class *class, ClientData data) { nonnull_assert(class != NULL); NsfRequireClassOpt((NsfClass *)class) -> clientData = data; } ClientData NsfGetClassClientData(Tcl_Interp *UNUSED(interp), Nsf_Class *class) { NsfClass *c; c = (NsfClass *) class; return (c->opt != NULL) ? c->opt->clientData : NULL; } /*********************************************************************** * Utility functions ***********************************************************************/ #if defined(NSFOBJ_TRACE) void ObjTrace(const char *string, NsfObject *object) nonnull(1) nonnull(2); void ObjTrace(const char *string, NsfObject *object) { nonnull_assert(string != NULL); nonnull_assert(object != NULL); fprintf(stderr, "--- %s Tcl %p %s (%d %p) nsf %p (%d) %s \n", string, (void *)object->cmdName, ObjTypeStr(object->cmdName), object->cmdName->refCount, object->cmdName->internalRep.twoPtrValue.ptr1, (void *)object, object->refCount, ObjectName(object)); } #else # define ObjTrace(a, b) #endif /* *---------------------------------------------------------------------- * NSTail -- * * Return the namespace tail of a name. * * Results: * String. * * Side effects: * None. * *---------------------------------------------------------------------- */ static const char * NSTail(const char *string) nonnull(1) NSF_pure; static const char * NSTail(const char *string) { register const char *p; nonnull_assert(string != NULL); p = string + strlen(string); while (p > string) { if (unlikely(*p == ':' && *(p-1) == ':')) { return p+1; } p--; } return string; } /* *---------------------------------------------------------------------- * IsClassNsName -- * * Check whether the provided string starts with the prefix of the * classes namespace. * * Results: * A Boolean value.. * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static bool IsClassNsName(const char *string, const char **cont) nonnull(1); NSF_INLINE static bool IsClassNsName(const char *string, const char **cont) { nonnull_assert(string != NULL); if (*string == ':' && strncmp(string, nsfClassesPrefix, nsfClassesPrefixLength) == 0) { if (cont != NULL) { *cont = string + nsfClassesPrefixLength; } return NSF_TRUE; } return NSF_FALSE; } /* *---------------------------------------------------------------------- * GetObjectFromNsName -- * * Get object or class from a fully qualified cmd name, such as * e.g. ::nsf::classes::X * * Results: * NsfObject and *fromClasses * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static NsfObject * GetObjectFromNsName(Tcl_Interp *interp, const char *string, bool *fromClassNS) nonnull(1) nonnull(2) nonnull(3); NSF_INLINE static NsfObject * GetObjectFromNsName(Tcl_Interp *interp, const char *string, bool *fromClassNS) { const char *className; nonnull_assert(interp != NULL); nonnull_assert(string != NULL); nonnull_assert(fromClassNS != NULL); if (IsClassNsName(string, &className)) { *fromClassNS = NSF_TRUE; return (NsfObject *)GetClassFromString(interp, className); } else { *fromClassNS = NSF_FALSE; return GetObjectFromString(interp, string); } } /* *---------------------------------------------------------------------- * DStringAppendQualName -- * * Append to initialized DString the name of the namespace followed * by a simple name (methodName, cmdName). * * Results: * String pointing to DString value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static char *DStringAppendQualName(Tcl_DString *dsPtr, const Tcl_Namespace *nsPtr, const char *name) nonnull(1) nonnull(2) nonnull(3); static char * DStringAppendQualName(Tcl_DString *dsPtr, const Tcl_Namespace *nsPtr, const char *name) { TCL_SIZE_T oldLength; nonnull_assert(dsPtr != NULL); nonnull_assert(nsPtr != NULL); nonnull_assert(name != NULL); oldLength = Tcl_DStringLength(dsPtr); Tcl_DStringAppend(dsPtr, nsPtr->fullName, TCL_INDEX_NONE); if (Tcl_DStringLength(dsPtr) > (oldLength + 2)) { Tcl_DStringAppend(dsPtr, "::", 2); } Tcl_DStringAppend(dsPtr, name, TCL_INDEX_NONE); return Tcl_DStringValue(dsPtr); } /* *---------------------------------------------------------------------- * NsfCleanupObject -- * * Delete an object physically (performing ckfree()) when its refCount * reaches 0 * * Results: * None. * * Side effects: * Frees memory. * *---------------------------------------------------------------------- */ void NsfCleanupObject_(NsfObject *object) { nonnull_assert(object != NULL); NsfObjectRefCountDecr(object); /*fprintf(stderr, "NsfCleanupObject obj refCount of %p after decr %d id %p interp %p flags %.6x\n", object, object->refCount, object->id, object->teardown, object->flags);*/ if (unlikely(object->refCount <= 0)) { /*fprintf(stderr, "NsfCleanupObject %p ref-count %d\n", object, object->refCount);*/ assert(object->refCount == 0); assert((object->flags & NSF_DELETED) != 0u); /* * During FinalObjectDeletion(), object->teardown is NULL, we cannot access * the object and class names anymore. */ if (object->teardown && NSF_DTRACE_OBJECT_FREE_ENABLED()) { NSF_DTRACE_OBJECT_FREE(ObjectName(object), ClassName(object->cl)); } MEM_COUNT_FREE("NsfObject/NsfClass", object); #if defined(NSFOBJ_TRACE) fprintf(stderr, "CKFREE Object %p refCount=%d\n", (void *)object, object->refCount); #endif #if !defined(NDEBUG) memset(object, 0, sizeof(NsfObject)); #endif ckfree((char *) object); } } /* * Tcl_Obj functions for objects */ /* *---------------------------------------------------------------------- * TclObjIsNsfObject -- * * Check whether the provided Tcl_Obj is bound to an NSF object. If * so, return the NsfObject in the third argument. * * Results: * A Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool TclObjIsNsfObject( Tcl_Interp *interp, Tcl_Obj *objPtr, NsfObject **objectPtr ) nonnull(1) nonnull(2) nonnull(3); static bool TclObjIsNsfObject(Tcl_Interp *interp, Tcl_Obj *objPtr, NsfObject **objectPtr) { Tcl_ObjType CONST86 *cmdType; bool result = NSF_FALSE; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(objectPtr != NULL); cmdType = objPtr->typePtr; if (cmdType == Nsf_OT_tclCmdNameType) { const Tcl_Command cmd = Tcl_GetCommandFromObj(interp, objPtr); if (likely(cmd != NULL)) { NsfObject *object = NsfGetObjectFromCmdPtr(cmd); if (object != NULL) { *objectPtr = object; result = NSF_TRUE; } } } return result; } /* *---------------------------------------------------------------------- * GetObjectFromObj -- * * Lookup a Next Scripting object from the given objPtr, preferably * from an object of type "cmdName". On success the NsfObject is * returned in the third argument. The objPtr might be converted by * this function. * * Results: * True or false, * * Side effects: * object type of objPtr might be changed * *---------------------------------------------------------------------- */ static int GetObjectFromObj( Tcl_Interp *interp, Tcl_Obj *objPtr, NsfObject **objectPtr ) nonnull(1) nonnull(2) nonnull(3); static int GetObjectFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, NsfObject **objectPtr) { NsfObject *object; const char *string; Tcl_Command cmd; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(objectPtr != NULL); /*fprintf(stderr, "GetObjectFromObj obj %p %s is of type %s\n", objPtr, ObjStr(objPtr), ObjTypeStr(objPtr));*/ /* * Use the standard Tcl_GetCommandFromObj() which might convert the objPtr * to type cmdName. */ cmd = Tcl_GetCommandFromObj(interp, objPtr); /*fprintf(stderr, "GetObjectFromObj obj %p %s (type %p) => cmd=%p (refCount %d)\n", objPtr, ObjStr(objPtr), objPtr->typePtr, cmd, (cmd != NULL) ? Tcl_Command_refCount(cmd) : TCL_INDEX_NONE);*/ if (cmd != NULL) { NsfObject *cmdObject; /* * Tcl returned us a command. At least in Tcl 8.7, we cannot trust that * the returned cmd is still valid. Unfortunately, we can't check more * details here, since "struct ResolvedCmdName" is defined locally in * generic/tclObj.c. For cmd epochs>0 we take the conservative approach * not to trust in internal representation and fetch the cmd new. */ cmdObject = NsfGetObjectFromCmdPtr(cmd); /* fprintf(stderr, "GetObjectFromObj obj %s, o is %p objProc %p NsfObjDispatch %p\n", ObjStr(objPtr), cmdObject, Tcl_Command_objProc(cmd), NsfObjDispatch);*/ if (likely(cmdObject != NULL)) { *objectPtr = cmdObject; return TCL_OK; } } /*fprintf(stderr, "GetObjectFromObj convertFromAny for %s type %p %s\n", ObjStr(objPtr), objPtr->typePtr, ObjTypeStr(objPtr));*/ /* * In case, we have to revolve via the CallingNameSpace (i.e. the argument * is not fully qualified), we retry here. */ string = ObjStr(objPtr); if (isAbsolutePath(string)) { object = NULL; } else { Tcl_Obj *tmpName = NameInNamespaceObj(string, CallingNameSpace(interp)); const char *nsString = ObjStr(tmpName); INCR_REF_COUNT(tmpName); object = GetObjectFromString(interp, nsString); /* fprintf(stderr, " RETRY, string '%s' returned %p\n", nsString, object);*/ DECR_REF_COUNT(tmpName); } if (likely(object != NULL)) { *objectPtr = object; return TCL_OK; } return TCL_ERROR; } /* *---------------------------------------------------------------------- * NsfCallObjectUnknownHandler -- * * Call ::nsf::object::unknown; this function is typically called, * when an unknown object or class is passed as an argument. * * Results: * A standard Tcl result. * * Side effects: * Called handler might side effect. * *---------------------------------------------------------------------- */ static int NsfCallObjectUnknownHandler( Tcl_Interp *interp, Tcl_Obj *nameObj ) nonnull(1) nonnull(2); static int NsfCallObjectUnknownHandler(Tcl_Interp *interp, Tcl_Obj *nameObj) { int result; Tcl_Obj *ov[3]; nonnull_assert(interp != NULL); nonnull_assert(nameObj != NULL); /*fprintf(stderr, "try ::nsf::object::unknown for '%s'\n", ObjStr(nameObj));*/ ov[0] = NsfGlobalObjs[NSF_OBJECT_UNKNOWN_HANDLER]; ov[1] = nameObj; INCR_REF_COUNT(ov[1]); result = Tcl_EvalObjv(interp, 2, ov, 0); DECR_REF_COUNT(ov[1]); return result; } #if defined(NSF_EXPERIMENTAL) static int NsfCallArgumentUnknownHandler( Tcl_Interp *interp, Tcl_Obj *methodObj, Tcl_Obj *argumentObj, NsfObject *object ) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static int NsfCallArgumentUnknownHandler( Tcl_Interp *interp, Tcl_Obj *methodObj, Tcl_Obj *argumentObj, NsfObject *object ) { Tcl_Obj *ov[4]; int result, oc = 3; nonnull_assert(interp != NULL); nonnull_assert(methodObj != NULL); nonnull_assert(argumentObj != NULL); nonnull_assert(object != NULL); /*fprintf(stderr, "try ::nsf::argument::unknown for '%s'\n", ObjStr(nameObj));*/ ov[0] = NsfGlobalObjs[NSF_ARGUMENT_UNKNOWN_HANDLER]; ov[1] = methodObj; ov[2] = argumentObj; if (object != NULL) { ov[3] = object->cmdName; oc ++; } INCR_REF_COUNT(ov[1]); result = Tcl_EvalObjv(interp, oc, ov, 0); DECR_REF_COUNT(ov[1]); return result; } #endif /* *---------------------------------------------------------------------- * GetClassFromObj -- * * Lookup a Next Scripting class from the given objPtr. If the * class could not be directly converted and withUnknown is true, * the function calls the unknown function (::nsf::object::unknown) * to fetch the class on demand and retries the conversion. On * success the NsfClass is returned in the third argument. The * objPtr might be converted by this function. * * Results: * True or false, * * Side effects: * object type of objPtr might be changed * *---------------------------------------------------------------------- */ static int GetClassFromObj(Tcl_Interp *interp, register Tcl_Obj *objPtr, NsfClass **classPtr, bool withUnknown) { NsfObject *object; NsfClass *class; const char *objName; Tcl_Command cmd; int result; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(classPtr != NULL); objName = ObjStr(objPtr); cmd = Tcl_GetCommandFromObj(interp, objPtr); /*fprintf(stderr, "GetClassFromObj %p %s unknown %d cmd %p\n", objPtr, objName, withUnknown, cmd);*/ if (likely(cmd != NULL)) { class = NsfGetClassFromCmdPtr(cmd); if (class == NULL) { /* * We have a cmd, but no class; namespace-imported classes are already * resolved, but we have to care, if a class is "imported" via "interp * alias". */ Tcl_Interp *alias_interp; const char *alias_cmd_name, *qualifiedObjName; Tcl_Obj *nameObj = objPtr; Tcl_Obj **alias_ov; int alias_oc = 0; if (!isAbsolutePath(objName)) { nameObj = NameInNamespaceObj(objName, CallingNameSpace(interp)); qualifiedObjName = ObjStr(nameObj); INCR_REF_COUNT(nameObj); } else { qualifiedObjName = objName; } result = Tcl_GetAliasObj(interp, qualifiedObjName, &alias_interp, &alias_cmd_name, &alias_oc, &alias_ov); Tcl_ResetResult(interp); /* * We only want interp-aliases with 0 args */ if (likely(result == TCL_OK) && likely(alias_oc == 0)) { cmd = NSFindCommand(interp, alias_cmd_name); /*fprintf(stderr, "..... alias arg 0 '%s' cmd %p\n", alias_cmd_name, cmd);*/ if (cmd != NULL) { class = NsfGetClassFromCmdPtr(cmd); } } /*fprintf(stderr, "..... final cmd %p, class %p\n", cmd , class);*/ if (nameObj != objPtr) { DECR_REF_COUNT(nameObj); } } if (likely(class != NULL)) { *classPtr = class; return TCL_OK; } } result = GetObjectFromObj(interp, objPtr, &object); if (likely(result == TCL_OK)) { class = NsfObjectToClass(object); if (likely(class != NULL)) { *classPtr = class; return TCL_OK; } else { /* * Flag, that we could not convert so far. */ result = TCL_ERROR; } } if (withUnknown) { /*fprintf(stderr, "**** withUnknown 1 obj %s is shared %d\n", ObjStr(objPtr), Tcl_IsShared(objPtr));*/ INCR_REF_COUNT(objPtr); result = NsfCallObjectUnknownHandler(interp, isAbsolutePath(objName) ? objPtr : NameInNamespaceObj(objName, CallingNameSpace(interp))); if (likely(result == TCL_OK)) { /* * Retry, but now, the last argument (withUnknown) has to be FALSE */ result = GetClassFromObj(interp, objPtr, classPtr, NSF_FALSE); } DECR_REF_COUNT(objPtr); /*fprintf(stderr, "... ::nsf::object::unknown for '%s', result %d cl %p\n", objName, result, cl);*/ } return result; } /* * Version of GetClassFromObj() with external symbol */ int NsfGetClassFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, NsfClass **classPtr, bool withUnknown) { nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(classPtr != NULL); return GetClassFromObj(interp, objPtr, classPtr, withUnknown); } /* *---------------------------------------------------------------------- * IsObjectOfType -- * * Check whether the provided NsfObject is of a certain type. The * arguments "what" and "objPtr" are just used for the error * messages. "objPtr" is the value from which the object was * converted from. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int IsObjectOfType( Tcl_Interp *interp, NsfObject *object, const char *what, Tcl_Obj *objPtr, const Nsf_Param *pPtr ) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(5); static int IsObjectOfType( Tcl_Interp *interp, NsfObject *object, const char *what, Tcl_Obj *objPtr, const Nsf_Param *pPtr ) { NsfClass *class; int result = TCL_ERROR; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(what != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); if (unlikely((pPtr->flags & NSF_ARG_BASECLASS) != 0u) && !IsBaseClass(object) ) { what = "baseclass"; } else if (unlikely((pPtr->flags & NSF_ARG_METACLASS) != 0u) && !IsMetaClass(interp, (NsfClass *)object, NSF_TRUE) ) { what = "metaclass"; } else if (likely(pPtr->converterArg == NULL)) { result = TCL_OK; } else if (likely((GetClassFromObj(interp, pPtr->converterArg, &class, NSF_FALSE) == TCL_OK)) && IsSubType(object->cl, class) ) { result = TCL_OK; } if (result == TCL_ERROR) { Tcl_DString ds, *dsPtr = &ds; DSTRING_INIT(dsPtr); Tcl_DStringAppend(dsPtr, what, TCL_INDEX_NONE); if (pPtr->converterArg != NULL) { Tcl_DStringAppend(dsPtr, " of type ", 9); Tcl_DStringAppend(dsPtr, ObjStr(pPtr->converterArg), TCL_INDEX_NONE); } NsfObjErrType(interp, NULL, objPtr, Tcl_DStringValue(dsPtr), (Nsf_Param *)pPtr); DSTRING_FREE(dsPtr); } return result; } /* *---------------------------------------------------------------------- * NameInNamespaceObj -- * * Create a fully qualified name in the provided namespace or in * the current namespace in form of a Tcl_Obj (with 0 refCount); * * Results: * Tcl_Obj containing fully qualified name * * Side effects: * Allocates fresh copies of list elements * *---------------------------------------------------------------------- */ static Tcl_Obj * NameInNamespaceObj(const char *name, Tcl_Namespace *nsPtr) { Tcl_Obj *objPtr; Tcl_DString ds, *dsPtr = &ds; nonnull_assert(name != NULL); nonnull_assert(nsPtr != NULL); /*fprintf(stderr, "NameInNamespaceObj %s (%p, %s) ", name, nsPtr, nsPtr->fullName);*/ DSTRING_INIT(dsPtr); DStringAppendQualName(dsPtr, nsPtr, name); objPtr = Tcl_NewStringObj(Tcl_DStringValue(dsPtr), Tcl_DStringLength(dsPtr)); /*fprintf(stderr, "returns %s\n", ObjStr(objPtr));*/ DSTRING_FREE(dsPtr); return objPtr; } /* *---------------------------------------------------------------------- * NewTclCommand -- * * Given a provided prefix in dsPtr, make it a name of a command * that does not exist. This function is used by the *new command, * when "anonymous" objects are created * * Results: * dsPtr will be complete to represent a new (unused) name of a command. * * Side effects: * None. * *---------------------------------------------------------------------- */ void NewTclCommand(Tcl_Interp *interp, Tcl_DString *dsPtr) nonnull(1) nonnull(2); void NewTclCommand(Tcl_Interp *interp, Tcl_DString *dsPtr) { TCL_SIZE_T prefixLength; NsfStringIncrStruct *iss; nonnull_assert(interp != NULL); nonnull_assert(dsPtr != NULL); prefixLength = dsPtr->length; iss = &RUNTIME_STATE(interp)->iss; while (1) { (void)NsfStringIncr(iss); Tcl_DStringAppend(dsPtr, iss->start, (TCL_SIZE_T)iss->length); if (!Tcl_FindCommand(interp, Tcl_DStringValue(dsPtr), NULL, TCL_GLOBAL_ONLY)) { break; } /* * In case the symbol existed already, reset prefix to the * original length. */ Tcl_DStringSetLength(dsPtr, prefixLength); } } /* *---------------------------------------------------------------------- * NsfReverseClasses -- * * Reverse class list. Caller is responsible for freeing data. * * Results: * Pointer to start of the reversed list * * Side effects: * Allocates fresh copies of list elements * *---------------------------------------------------------------------- */ static NsfClasses *NsfReverseClasses(NsfClasses *sl) nonnull(1) returns_nonnull; static NsfClasses * NsfReverseClasses(NsfClasses *sl) { NsfClasses *firstPtr = NULL; nonnull_assert(sl != NULL); do { NsfClasses *element = NEW(NsfClasses); element->cl = sl->cl; element->clientData = sl->clientData; element->nextPtr = firstPtr; firstPtr = element; sl = sl->nextPtr; } while (likely(sl != NULL)); return firstPtr; } /* *---------------------------------------------------------------------- * NsfClassListFree -- * * Frees all elements of the provided class list. * * Results: * None. * * Side effects: * Frees memory. * *---------------------------------------------------------------------- */ static void NsfClassListFree(NsfClasses *classList) nonnull(1); static void NsfClassListFree(NsfClasses *classList) { NsfClasses *nextPtr; nonnull_assert(classList != NULL); do { nextPtr = classList->nextPtr; FREE(NsfClasses, classList); classList = nextPtr; } while (likely(classList != NULL)); } /* *---------------------------------------------------------------------- * NsfClassListAdd -- * * Add class list entry to the specified list. In case the initial * list is empty, *firstPtrPtr is updated as well. * * Results: * Returns address of next-pointer. * * Side effects: * New list element is allocated. * *---------------------------------------------------------------------- */ static NsfClasses ** NsfClassListAdd(NsfClasses **firstPtrPtr, NsfClass *class, ClientData clientData) { NsfClasses *classListPtr, *element = NEW(NsfClasses); nonnull_assert(firstPtrPtr != NULL); element->cl = class; element->clientData = clientData; element->nextPtr = NULL; classListPtr = *firstPtrPtr; if (classListPtr != NULL) { while (classListPtr->nextPtr != NULL) { classListPtr = classListPtr->nextPtr; } classListPtr->nextPtr = element; } else { *firstPtrPtr = element; } return &(element->nextPtr); } /* *---------------------------------------------------------------------- * NsfClassListAddNoDup -- * * Add class list entry to the specified list without * duplicates. In case the initial list is empty, *firstPtrPtr is * updated as well. * * Results: * Returns address of next pointer. * * Side effects: * New list element is allocated. * *---------------------------------------------------------------------- */ static NsfClasses **NsfClassListAddNoDup(NsfClasses **firstPtrPtr, NsfClass *class, ClientData clientData) nonnull(1) nonnull(2); static NsfClasses ** NsfClassListAddNoDup(NsfClasses **firstPtrPtr, NsfClass *class, ClientData clientData) { NsfClasses *clPtr, **nextPtr; nonnull_assert(firstPtrPtr != NULL); nonnull_assert(class != NULL); clPtr = *firstPtrPtr; if (clPtr != NULL) { while ((clPtr->nextPtr != NULL) && (clPtr->cl != class)) { clPtr = clPtr->nextPtr; } nextPtr = &clPtr->nextPtr; } else { nextPtr = firstPtrPtr; } if (*nextPtr == NULL) { NsfClasses *element = NEW(NsfClasses); element->cl = class; element->clientData = clientData; element->nextPtr = NULL; *nextPtr = element; } return nextPtr; } /* *---------------------------------------------------------------------- * NsfClassListFind -- * * Find an element in the class list and return it if found. * * Results: * Found element or NULL * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfClasses *NsfClassListFind(NsfClasses *clPtr, const NsfClass *class) nonnull(2) NSF_pure; static NsfClasses * NsfClassListFind(NsfClasses *clPtr, const NsfClass *class) { nonnull_assert(class != NULL); for (; clPtr != NULL; clPtr = clPtr->nextPtr) { if (clPtr->cl == class) { break; } } return clPtr; } #if defined(NSF_CLASSLIST_PRINT) /* debugging purposes only */ /* *---------------------------------------------------------------------- * NsfClassListStats -- * * Print some statistics about generated Class List structures for * debugging purpose. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void NsfClassListStats(const char *title, NsfClasses *classList) nonnull(1); static void NsfClassListStats(const char *title, NsfClasses *classListPtr) { NsfClass *class; int count = 0; nonnull_assert(title != NULL); class = (classListPtr != NULL) ? classListPtr->cl : NULL; for (; classListPtr != NULL; classListPtr = classListPtr->nextPtr) { count++; } fprintf(stderr, "%s class list starting with %s has %d elements\n", title, (class != NULL) ? ClassName(class) : "none", count); } static void NsfClassListPrint(const char *title, const NsfClasses *clsList) nonnull(1); static void NsfClassListPrint(const char *title, const NsfClasses *clsList) { nonnull_assert(title != NULL); fprintf(stderr, "%s", title); /* fprintf(stderr, " %p:", clsList); */ while (clsList != NULL) { /* fprintf(stderr, " %p", clsList->cl); */ fprintf(stderr, " %p", (void *)clsList); fprintf(stderr, " %s", ClassName(clsList->cl)); clsList = clsList->nextPtr; } fprintf(stderr, "\n"); } #endif /* *---------------------------------------------------------------------- * NsfClassListUnlink -- * * Return removed item with matching key form nsfClasses. * Key is void to allow not only class pointers as keys. * * Results: * unlinked element or NULL. * In case the first element is unlinked, *firstPtrPtr * is updated. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfClasses *NsfClassListUnlink(NsfClasses **firstPtrPtr, const void *key) nonnull(1) nonnull(2); static NsfClasses * NsfClassListUnlink(NsfClasses **firstPtrPtr, const void *key) { NsfClasses *entryPtr; nonnull_assert(firstPtrPtr != NULL); nonnull_assert(key != NULL); if (*firstPtrPtr != NULL) { NsfClasses *prevPtr = NULL; /* * List is nonempty. */ for (entryPtr = *firstPtrPtr; entryPtr != NULL; prevPtr = entryPtr, entryPtr = entryPtr->nextPtr ) { if ((void *)entryPtr->cl == key) { /* * Found entry. */ if (prevPtr != NULL) { /* * Later item. */ prevPtr->nextPtr = entryPtr->nextPtr; } else { /* * First item. */ *firstPtrPtr = entryPtr->nextPtr; } entryPtr->nextPtr = NULL; break; } } } else { entryPtr = NULL; } return entryPtr; } /* * Functions for computing Precedence Order */ /* *---------------------------------------------------------------------- * TopoSortSub -- * * Performs a topological sort of the subclass hierarchy of a given * class. The resulting list contains no duplicates or cycles and * is returned in the class member "order". During computation, it * colors the processed nodes in WHITE, GRAY or BLACK. * * Results: * Boolean values indicating whether a cycle was detected * (NSF_FALSE) or not (NSF_TRUE); and, therefore, whether the sort * failed (NSF_FALSE) or succeeded (NSF_TRUE). * * Side effects: * Allocates class list. * *---------------------------------------------------------------------- */ enum colors { WHITE, GRAY, BLACK }; static bool TopoSortSub(NsfClass *class, NsfClass *baseClass, bool withMixinOfs) nonnull(1) nonnull(2); static bool TopoSortSub(NsfClass *class, NsfClass *baseClass, bool withMixinOfs) { NsfClasses *sl, *pl; bool isAcyclic = NSF_TRUE; nonnull_assert(class != NULL); nonnull_assert(baseClass != NULL); sl = class->sub; /* * Be careful to reset the color of unreported classes to * white in case we unwind with error, and on final exit * reset color of reported classes to WHITE. Meaning of colors: * * WHITE ... not processed * GRAY ... in work * BLACK ... done */ class->color = GRAY; for (; sl != NULL; sl = sl->nextPtr) { NsfClass *sc = sl->cl; if (sc->color == GRAY || unlikely(sc->color == WHITE && !TopoSortSub(sc, baseClass, withMixinOfs)) ) { isAcyclic = NSF_FALSE; break; } } if (isAcyclic && withMixinOfs) { NsfCmdList *classMixins = ((class->opt != NULL) ? class->opt->isClassMixinOf : NULL); for (; classMixins != NULL; classMixins = classMixins->nextPtr) { NsfClass *sc = NsfGetClassFromCmdPtr(classMixins->cmdPtr); if (likely(sc != NULL) && unlikely(sc->color == WHITE && !TopoSortSub(sc, baseClass, withMixinOfs))) { NsfLog(sc->object.teardown, NSF_LOG_WARN, "cycle in the mixin graph list detected for class %s", ClassName_(sc)); } } } class->color = BLACK; pl = NEW(NsfClasses); pl->cl = class; pl->nextPtr = baseClass->order; baseClass->order = pl; if (unlikely(class == baseClass)) { register const NsfClasses *pc; for (pc = class->order; pc != NULL; pc = pc->nextPtr) { pc->cl->color = WHITE; } assert(isAcyclic && baseClass->order != NULL); } return isAcyclic; } /* *---------------------------------------------------------------------- * MustBeBefore -- * * Check the partial ordering of classes based on precedence list * in the form of prior ordering from the topological sort. We * compare here orderings based the class hierarchies with single * inheritance and prior solved multiple inheritance orderings. The * test is true, if b must be before a. * * Results: * Boolean value indicating success. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool MustBeBefore(const NsfClass *aClass, const NsfClass *bClass, const NsfClasses *superClasses) nonnull(1) nonnull(2) nonnull(3) NSF_pure; static bool MustBeBefore(const NsfClass *aClass, const NsfClass *bClass, const NsfClasses *superClasses) { bool success; nonnull_assert(aClass != NULL); nonnull_assert(bClass != NULL); nonnull_assert(superClasses != NULL); assert(bClass->order != NULL); /* * Check whether "x" is in the precedence order of "y". E.g. * * x c1 object * y c2 x object * * If so then "y" must be before "x" to preserve the precedence order based on * single inheritance (monotonicity). */ success = (NsfClassListFind(bClass->order, aClass) != NULL); /* * When the partital ordering can't be decided based on the local order * test, we take the specified multiple inheritance ordering in superClasses * (e.g. coming from -superclass {x y}) which is not taken account by the * class hierarchy. */ if (!success) { const NsfClasses *sl; bool found = NSF_FALSE; #if defined(NSF_LINEARIZER_TRACE) fprintf(stderr, "--> check %s before %s?\n", ClassName(bClass), ClassName(aClass)); NsfClassListPrint("superClasses", superClasses); #endif for (sl = superClasses; sl != NULL; sl = sl->nextPtr) { if (sl->cl == bClass) { found = NSF_TRUE; } else if (found && sl->cl == aClass) { #if defined(NSF_LINEARIZER_TRACE) fprintf(stderr, "%s in inheritanceList before %s therefore a < b\n", ClassName(bClass), ClassName(aClass)); #endif success = NSF_TRUE; break; } } } #if defined(NSF_LINEARIZER_TRACE) fprintf(stderr, "compare a: %s %p b: %s %p -> %d\n", ClassName(aClass), (void *)aClass->order, ClassName(bClass), (void *)bClass->order, (int)success); NsfClassListPrint("\ta", aClass->order); NsfClassListPrint("\tb", bClass->order); #endif return success; } /* *---------------------------------------------------------------------- * ValidClassListTail -- * * Debug function to assure that the provided class lists are * valid. The tail of the class list must be a base class of the * current object system. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ #if defined(NSF_DEVELOPMENT_TEST) static void ValidClassListTail(const char *what, NsfClasses *classListPtr) { NsfClasses *sl, *tail; for (sl = classListPtr, tail = NULL; sl != NULL; sl = sl->nextPtr) { tail = sl; } if (tail != NULL) { /* fprintf(stderr, "check tail what %s %p\n", what, ClassName(tail->cl), tail->nextPtr);*/ assert(IsBaseClass(&tail->cl->object)); assert(tail->nextPtr == NULL); } } #else # define ValidClassListTail(what, classListPtr) #endif /* *---------------------------------------------------------------------- * MergeInheritanceLists -- * * Merge the PrecedenceOrders of class cl. This function is called, * when cl is defined with multiple inheritance. The precedence * orders of the specified classes are merged in an order * preserving manner to achieve monotonicity. * * Results: * precedence order. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfClasses *MergeInheritanceLists(NsfClasses *pl, NsfClass *class) nonnull(1) nonnull(2) returns_nonnull; static NsfClasses * MergeInheritanceLists(NsfClasses *pl, NsfClass *class) { NsfClasses *sl, *baseList, **plNext, *superClasses, *deletionList = NULL; nonnull_assert(pl != NULL); nonnull_assert(class != NULL); #if defined(NSF_LINEARIZER_TRACE) fprintf(stderr, "=== MergeInheritanceLists working on %s\n", ClassName(class)); #endif /* * The available multiple inheritance list is in reversed order so we have * to reverse it to obtain the specified superClasses in the provided order. */ superClasses = NsfReverseClasses(class->super); /* * We distinguish between a * * - baseList (which might be later a result of partial merges), and a * - mergeList, which is merged order-preserving into the baseList. * * The first baseList is the precedence list of the first element of the * specified superClasses. */ baseList = superClasses->cl->order; assert(baseList != NULL); #if defined(NSF_LINEARIZER_TRACE) fprintf(stderr, "=== baseList from %s = %p\n", ClassName(superClasses->cl), (void *)baseList); NsfClassListPrint("baseList", baseList); #endif /* * The first element of the result list of the merge operation is the first * element of the baseList. */ plNext = NsfClassListAdd(&pl, baseList->cl, NULL); /* * For every element but the first (which is already in baseList), we have to * perform the merge operation. For n elements in superClasses, the merge * operation is performed n-1 times. */ sl = superClasses->nextPtr; assert(superClasses->nextPtr != NULL); do { NsfClasses *mergeList = sl->cl->order, *baseListCurrent; #if defined(NSF_LINEARIZER_TRACE) NsfClassListPrint("mergeList", mergeList); #endif /* * Merge mergeList into baseList. We start with the 2nd (later probably * nth) entry of the baseList */ baseListCurrent = baseList->nextPtr; assert(baseListCurrent != NULL); while (mergeList != NULL) { NsfClass *addClass; ValidClassListTail("baseList", baseList); ValidClassListTail("mergeList", mergeList); assert(baseListCurrent != NULL); /* NsfClassListPrint("baseListCurrent", baseListCurrent); */ if (mergeList->cl == baseListCurrent->cl) { /* * The first element of mergeList and the current baseList element are * identical. The element is in the result, keep the element in the * result, advance in both lists. */ /* fprintf(stderr, "\t\tadvance both\n"); */ addClass = mergeList->cl; baseListCurrent = baseListCurrent->nextPtr; mergeList = mergeList->nextPtr; } else if (MustBeBefore(baseListCurrent->cl, mergeList->cl, superClasses)) { /* * Check whether current element of mergeList must be before the current * element of baseList. If so, insert current mergelist element before * baseListCurrent, */ addClass = mergeList->cl; mergeList = mergeList->nextPtr; /* fprintf(stderr, "\t\tadd from mergeList %s\n", ClassName(addClass)); */ } else { /* * Two cases above do not apply, add from baseList and advance * baseList pointer. */ addClass = baseListCurrent->cl; baseListCurrent = baseListCurrent->nextPtr; /* fprintf(stderr, "\t\tadd from baselist %s\n", ClassName(addClass)); */ } if (addClass != NULL) { /* * We have to add an element to the precedence list. When the class to * be added is already in the result list (which might happen just in * crippled cases) then delete it. In the final step it will be added * again to the end. */ NsfClasses *deletedElement = NsfClassListUnlink(&pl, addClass); if (deletedElement != NULL) { #if defined(NSF_LINEARIZER_TRACE) fprintf(stderr, "\t\t%s is redundant (in resultList)\n", ClassName(addClass)); #endif /* * When plNext points to the nextPtr of the deleted element, search * the list from the begin */ if (plNext == &(deletedElement->nextPtr)) { plNext = &pl; } NsfClassListFree(deletedElement); } /* * Add the new element. */ plNext = NsfClassListAdd(plNext, addClass, NULL); } #if defined(NSF_LINEARIZER_TRACE) NsfClassListPrint("pl:", pl); #endif } /* * mergeList is processed, we have a final precedence list in pl. In case * are at then of superClasses, we are done. Otherwise, use the resulting * pl as next baseList and continue with the next mergeList from * superClasses. */ #if defined(NSF_LINEARIZER_TRACE) NsfClassListPrint("plFinal:", pl); #endif if (sl->nextPtr != NULL) { /* * We are not at the end, use pl as new base list. */ baseList = pl; #if defined(NSF_LINEARIZER_TRACE) fprintf(stderr, "=== setting new baseList\n"); NsfClassListPrint("new baseList", baseList); #endif /* * Add old pl to deletion list; these entries are deleted once merging * is finished. */ NsfClassListAdd(&deletionList, NULL, pl); /* * Create a fresh pl for the next iteration. */ pl = NULL; plNext = NsfClassListAdd(&pl, class, NULL); } /* * Get next element from the list. */ sl = sl->nextPtr; } while (sl != NULL); for (sl = deletionList; sl != NULL; sl = sl->nextPtr) { /* fprintf(stderr, "delete from deletion list %p client data %p\n", sl, sl->clientData); */ NsfClassListFree(sl->clientData); } if (deletionList != NULL) { NsfClassListFree(deletionList); } NsfClassListFree(superClasses); return pl; } #if defined(NSF_DEVELOPMENT_TEST) static void AssertOrderIsWhite(NsfClasses *order) { register NsfClasses *pc; for (pc = order; pc != NULL; pc = pc->nextPtr) { assert(pc->cl->color == WHITE); } } #else # define AssertOrderIsWhite(arg) #endif /* *---------------------------------------------------------------------- * TopoSortSuper -- * * Compute the precedence order for baseClass based on the * superclasses. If the order is computable, update base class and * return NSF_TRUE. Otherwise return NSF_FALSE. * * Results: * Boolean value indicating success. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool TopoSortSuper(NsfClass *class, NsfClass *baseClass) nonnull(1) nonnull(2); static bool TopoSortSuper(NsfClass *class, NsfClass *baseClass) { NsfClasses *pl, *sl; nonnull_assert(class != NULL); nonnull_assert(baseClass != NULL); /* * Be careful to reset the color of unreported classes to * white in the caller on all exits to WHITE. * * WHITE ... not processed * GRAY ... in work * BLACK ... done */ class->color = GRAY; for (sl = class->super; likely(sl != NULL); sl = sl->nextPtr) { NsfClass *sc = sl->cl; if (sc->color == GRAY) { class->color = WHITE; return NSF_FALSE; } if (unlikely(sc->color == WHITE && !TopoSortSuper(sc, baseClass))) { class->color = WHITE; return NSF_FALSE; } } /* * Create a new precedence list containing cl. */ pl = NEW(NsfClasses); pl->cl = class; pl->nextPtr = NULL; /* * If we have multiple inheritance we merge the precomputed inheritance * orders of the involved classes in the provided order. */ if (likely(class->super != NULL) && unlikely(class->super->nextPtr != NULL)) { pl = MergeInheritanceLists(pl, class); if (baseClass->order != NULL) { NsfClassListFree(baseClass->order); /* * baseClass->order is reset below. */ } } else { /* * Add baseClass order to the end of the precedence list. */ assert(pl->nextPtr == NULL); pl->nextPtr = baseClass->order; } class->color = BLACK; /* * Set baseClass order to the newly computed list (the result of this * function). */ baseClass->order = pl; return NSF_TRUE; } /* *---------------------------------------------------------------------- * PrecedenceOrder -- * * Return a class list containing the transitive list of * superclasses starting with (and containing) the provided * class. The superclass list is cached in cl->order and has to be * invalidated by FlushPrecedences() in case the order changes. The * caller does not have to free the returned class list (like for * TransitiveSubClasses); * * Results: * Class list, NULL on error * * Side effects: * Updating cl->order. * *---------------------------------------------------------------------- */ NSF_INLINE static NsfClasses * PrecedenceOrder(NsfClass *class) { register const NsfClasses *sl; bool success, haveMultipleInheritance; nonnull_assert(class != NULL); /* * Check, of the superclass order is already cached. */ if (likely(class->order != NULL)) { return class->order; } /* * For multiple inheritance (more than one superclass), make sure that * required precedence orders are precomputed. But first check whether we * have to do this rather expensive operation now, or we can do it * lazily. We can't do this in MergeInheritanceLists() within * TopoSortSuper(), since there the class node coloring might be half done. */ haveMultipleInheritance = NSF_FALSE; for (sl = class->super; sl != NULL; sl = sl->cl->super) { if (sl != NULL && sl->nextPtr != NULL) { haveMultipleInheritance = NSF_TRUE; break; } } if (unlikely(haveMultipleInheritance)) { /* * In the class hierarchy is somewhere a place with multiple * inheritance. All precedence orders of superclasses must be computed, * otherwise merging of sublists will not work. */ for (sl = class->super; sl != NULL; sl = sl->nextPtr) { const NsfClasses *pl; #if defined(NSF_LINEARIZER_TRACE) fprintf(stderr, "====== PrecedenceOrder multiple inheritance: check %s %p \n", ClassName(sl->cl), (void *)sl->cl->order); #endif if (unlikely(sl->cl->order == NULL) && likely(class != sl->cl)) { #if defined(NSF_LINEARIZER_TRACE) fprintf(stderr, "====== PrecedenceOrder multiple inheritance computes required order for %s \n", ClassName(sl->cl)); #endif PrecedenceOrder(sl->cl); #if defined(NSF_LINEARIZER_TRACE) NsfClassListPrint("====== PrecedenceOrder multiple inheritance:", sl->cl->order); #endif } for (pl = sl->cl->order; pl != NULL; pl = pl->nextPtr) { #if defined(NSF_LINEARIZER_TRACE) fprintf(stderr, "====== PrecedenceOrder multiple inheritance: %s %p\n", ClassName(pl->cl), (void *)pl->cl->order); #endif if (pl->cl->order == NULL) { #if defined(NSF_LINEARIZER_TRACE) fprintf(stderr, "========== recurse\n"); #endif PrecedenceOrder(pl->cl); } } } } success = TopoSortSuper(class, class); /* * Reset the color of all nodes. */ for (sl = class->order; sl != NULL; sl = sl->nextPtr) { sl->cl->color = WHITE; } /* * If computation is successful, return cl->order. * Otherwise clear cl->order if necessary. */ if (likely(success)) { AssertOrderIsWhite(class->order); /* * TopoSortSuper succeeded, the cl-order is already set. */ } else if (class->order != NULL) { /* * TopoSortSuper failed, but there is a computed cl->order. Flush it. */ NsfClassListFree(class->order); class->order = NULL; } else { /* * TopoSortSuper failed, but there is no computed cl->order. Nothing to * do. */ } #if defined(NSF_LINEARIZER_TRACE) NsfClassListPrint("!!! PrecedenceOrder computed", class->order); #endif return class->order; } /* *---------------------------------------------------------------------- * GetSubClasses -- * * Return a class list containing the transitive or dependent * subclasses starting with (and containing) the provided * class. The caller has to free the returned class list. * * Results: * Class list, at least with one element (i.e., the provided class). * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static NsfClasses * GetSubClasses(NsfClass *class, bool withMixinOfs) nonnull(1) returns_nonnull; #define TransitiveSubClasses(class) \ GetSubClasses((class), NSF_FALSE) #define DependentSubClasses(class) \ GetSubClasses((class), NSF_TRUE) NSF_INLINE static NsfClasses * GetSubClasses(NsfClass *class, bool withMixinOfs) { NsfClasses *order, *savedOrder; nonnull_assert(class != NULL); /* * Since TopoSort() places its result in cl->order, we have to save the old * cl->order, perform the computation, and restore the old order. */ savedOrder = class->order; class->order = NULL; (void)TopoSortSub(class, class, withMixinOfs); order = class->order; assert(order != NULL); AssertOrderIsWhite(order); class->order = savedOrder; return order; } /* *---------------------------------------------------------------------- * FlushPrecedences -- * * This function iterations over the provided class list and * flushes (and frees) the superclass caches in cl->order for every * element. * * Results: * None. * * Side effects: * Freeing class lists cached in cl->order. * *---------------------------------------------------------------------- */ static void FlushPrecedences(const NsfClasses *subClasses) nonnull(1); static void FlushPrecedences(const NsfClasses *subClasses) { nonnull_assert(subClasses != NULL); do { if (subClasses->cl->order != NULL) { NsfClassListFree(subClasses->cl->order); } subClasses->cl->order = NULL; subClasses = subClasses->nextPtr; } while (subClasses != NULL); } /* *---------------------------------------------------------------------- * AddInstance -- * * Add an instance to a class. * * Results: * None. * * Side effects: * Add entry to children hash-table. * *---------------------------------------------------------------------- */ static void AddInstance(NsfObject *object, NsfClass *class) nonnull(1) nonnull(2); static void AddInstance(NsfObject *object, NsfClass *class) { int isNewItem; nonnull_assert(object != NULL); nonnull_assert(class != NULL); object->cl = class; (void) Tcl_CreateHashEntry(&class->instances, (char *)object, &isNewItem); /*if (newItem == 0) { fprintf(stderr, "instance %p %s was already an instance of %p %s\n", (void *)object, ObjectName(object), (void *)cl, ClassName(class)); }*/ assert(isNewItem != 0); } /* *---------------------------------------------------------------------- * RemoveInstance -- * * Remove an instance from a class. The function checks, whether * the entry is actually still an instance before it deletes it. * * Results: * None. * * Side effects: * Entry deleted from instances hash-table * *---------------------------------------------------------------------- */ static void RemoveInstance(const NsfObject *object, NsfClass *class) nonnull(1) nonnull(2); static void RemoveInstance(const NsfObject *object, NsfClass *class) { nonnull_assert(object != NULL); nonnull_assert(class != NULL); /* * If we are during a delete, which should not happen under normal * operations, prevent an abort due to a deleted hash table. */ if (unlikely(class->object.flags & NSF_DURING_DELETE) != 0u) { NsfLog(class->object.teardown, NSF_LOG_WARN, "The class %s, from which an instance is to be removed, is currently under deletion", ObjStr((class)->object.cmdName)); } else { Tcl_HashEntry *hPtr = Tcl_CreateHashEntry(&class->instances, (char *)object, NULL); /*if (hPtr == NULL) { fprintf(stderr, "instance %s is not an instance of %s\n", ObjectName(object), ClassName(class)); }*/ assert(hPtr != NULL); Tcl_DeleteHashEntry(hPtr); } } /* * superclass/subclass list maintenance */ static void AddSuper1(NsfClass *class, NsfClasses **sl) nonnull(1) nonnull(2); static void AddSuper(NsfClass *class, NsfClass *superClass) nonnull(1); static bool RemoveSuper1(NsfClass *class, NsfClasses **sl) nonnull(1) nonnull(2); static bool RemoveSuper(NsfClass *class, NsfClass *superClass) nonnull(1) nonnull(2); static void AddSuper1(NsfClass *class, NsfClasses **sl) { NsfClasses *sc = NEW(NsfClasses); nonnull_assert(class != NULL); nonnull_assert(sl != NULL); sc->cl = class; sc->nextPtr = *sl; *sl = sc; } static void AddSuper(NsfClass *class, NsfClass *superClass) { nonnull_assert(class != NULL); if (superClass != NULL) { /* * keep corresponding sub in step with super */ AddSuper1(superClass, &class->super); AddSuper1(class, &superClass->sub); } } static bool RemoveSuper1(NsfClass *class, NsfClasses **sl) { NsfClasses *l; bool result; nonnull_assert(class != NULL); nonnull_assert(sl != NULL); l = *sl; if (l == NULL) { result = NSF_FALSE; } else if (l->cl == class) { *sl = l->nextPtr; FREE(NsfClasses, l); result = NSF_TRUE; } else { while ((l->nextPtr != NULL) && (l->nextPtr->cl != class)) { l = l->nextPtr; } if (l->nextPtr != NULL) { NsfClasses *n = l->nextPtr->nextPtr; FREE(NsfClasses, l->nextPtr); l->nextPtr = n; result = NSF_TRUE; } else { result = NSF_FALSE; } } return result; } static bool RemoveSuper(NsfClass *class, NsfClass *superClass) { bool sp, sb; nonnull_assert(class != NULL); nonnull_assert(superClass != NULL); /* * Keep corresponding sub in step with super */ sp = RemoveSuper1(superClass, &class->super); sb = RemoveSuper1(class, &superClass->sub); return sp && sb; } /* * methods lookup */ /* *---------------------------------------------------------------------- * GetEnsembleObjectFromName -- * * Get an ensemble object from a method name. If the method name * is fully qualified, just use a Tcl lookup, otherwise get it from * the provided namespace. * * Results: * Ensemble object or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfObject *GetEnsembleObjectFromName( Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *nameObj, Tcl_Command *cmdPtr, bool *fromClassNS ) nonnull(1) nonnull(3) nonnull(4) nonnull(5); static NsfObject * GetEnsembleObjectFromName(Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *nameObj, Tcl_Command *cmdPtr, bool *fromClassNS) { Tcl_Command cmd; const char *nameString; NsfObject *result; nonnull_assert(interp != NULL); nonnull_assert(nameObj != NULL); nonnull_assert(cmdPtr != NULL); nonnull_assert(fromClassNS != NULL); nameString = ObjStr(nameObj); if (*nameString == ':') { cmd = Tcl_GetCommandFromObj(interp, nameObj); *fromClassNS = IsClassNsName(nameString, NULL); } else { cmd = (nsPtr != NULL) ? FindMethod(nsPtr, nameString) : NULL; } if (cmd != NULL) { *cmdPtr = cmd; result = NsfGetObjectFromCmdPtr(GetOriginalCommand(cmd)); } else { result = NULL; } return result; } /* *---------------------------------------------------------------------- * GetRegObject -- * * Try to get the object, on which the method was registered from a * fully qualified method handle. * * Results: * NsfObject * or NULL on failure. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfObject *GetRegObject(Tcl_Interp *interp, Tcl_Command cmd, const char *methodName, const char **methodName1, bool *fromClassNS) nonnull(1) nonnull(3) nonnull(5) nonnull(2); static NsfObject * GetRegObject(Tcl_Interp *interp, Tcl_Command cmd, const char *methodName, const char **methodName1, bool *fromClassNS) { NsfObject *regObject; const char *procName; size_t objNameLength; nonnull_assert(interp != NULL); nonnull_assert(cmd != NULL); nonnull_assert(methodName != NULL); assert(*methodName == ':'); nonnull_assert(fromClassNS != NULL); nonnull_assert(cmd != NULL); procName = Tcl_GetCommandName(interp, cmd); objNameLength = strlen(methodName) - strlen(procName) - 2; if (objNameLength > 0) { Tcl_DString ds, *dsPtr = &ds; /* * Obtain parent name. */ Tcl_DStringInit(dsPtr); Tcl_DStringAppend(dsPtr, methodName, (TCL_SIZE_T)objNameLength); regObject = GetObjectFromNsName(interp, Tcl_DStringValue(dsPtr), fromClassNS); if (regObject != NULL && methodName1 != NULL) { *methodName1 = procName; } Tcl_DStringFree(dsPtr); } else { regObject = NULL; } /*fprintf(stderr, "GetRegObject cmd %p methodName '%s' => %p\n", (void *)cmd, methodName, (void *)regObject);*/ return regObject; } /* *---------------------------------------------------------------------- * ResolveMethodName -- * * Resolve a method name relative to a provided namespace. * The method name can be * a) a fully qualified name * b) a list of method name and subcommands * c) a simple name * * Results: * Tcl_Command or NULL on failure * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Command ResolveMethodName( Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *methodObj, Tcl_DString *methodNameDs, NsfObject **regObject, NsfObject **defObject, const char **methodName1, bool *fromClassNS ) nonnull(1) nonnull(3) nonnull(8); static Tcl_Command ResolveMethodName( Tcl_Interp *interp, Tcl_Namespace *nsPtr, Tcl_Obj *methodObj, Tcl_DString *methodNameDs, NsfObject **regObject, NsfObject **defObject, const char **methodName1, bool *fromClassNS ) { const char *methodName; NsfObject *referencedObject; bool containsSpace, tailContainsSpace; Tcl_Command cmd; nonnull_assert(interp != NULL); nonnull_assert(methodObj != NULL); nonnull_assert(fromClassNS != NULL); methodName = ObjStr(methodObj); /*fprintf(stderr, "methodName '%s' comp %d type %s\n", methodName, strchr(methodName, ' ')>0, ObjTypeStr(methodObj));*/ if (methodObj->typePtr == Nsf_OT_listType) { int length; Tcl_ListObjLength(interp, methodObj, &length); containsSpace = (length > 1); } else if (methodObj->typePtr == Nsf_OT_tclCmdNameType) { containsSpace = NSF_FALSE; } else { containsSpace = NsfHasTclSpace(methodName); } if (containsSpace) { tailContainsSpace = NsfHasTclSpace(NSTail(methodName)); } else { tailContainsSpace = NSF_FALSE; } /*fprintf(stderr, "<%s> containsSpace %d tailContainsSpace %d\n", methodName, containsSpace, tailContainsSpace);*/ #if !defined(NDEBUG) if (containsSpace) { assert(NsfHasTclSpace(methodName)); } else { assert(!tailContainsSpace); } #endif if (tailContainsSpace) { const char *firstElementString; const Tcl_Namespace *parentNsPtr; const NsfObject *ensembleObject; Tcl_Obj *methodHandleObj, **ov; int oc, i; /* * When the methodName is required, we have to provide a methodNameDS as * well. */ assert(methodName1 == NULL || methodNameDs != NULL); /*fprintf(stderr, "name '%s' contains space \n", methodName);*/ if (likely(Tcl_ListObjGetElements(interp, methodObj, &oc, &ov) != TCL_OK) || ((referencedObject = GetEnsembleObjectFromName(interp, nsPtr, ov[0], &cmd, fromClassNS)) == NULL) ) { if (methodName1 != NULL) { *methodName1 = NULL; } if (regObject != NULL) { *regObject = NULL; } if (defObject != NULL) { *defObject = NULL; } return NULL; } /* * We have an ensemble object. First, figure out, on which * object/class the ensemble object was registered. We determine * the regObject on the first element of the list. If we can't, * then the current object is the regObject. */ firstElementString = ObjStr(ov[0]); if (*firstElementString == ':') { NsfObject *registrationObject; registrationObject = GetRegObject(interp, cmd, firstElementString, methodName1, fromClassNS); if (regObject != NULL) { *regObject = registrationObject; } } else { if (regObject != NULL) { *regObject = NULL; } } /*fprintf(stderr, "... regObject object '%s' reg %p, fromClassNS %d\n", ObjectName(referencedObject), (void *)*regObject, *fromClassNS);*/ /* * Build a fresh methodHandleObj to held method name and names of * subcmds. */ methodHandleObj = Tcl_DuplicateObj(referencedObject->cmdName); INCR_REF_COUNT(methodHandleObj); if (methodNameDs != NULL) { Tcl_DStringAppend(methodNameDs, Tcl_GetCommandName(interp, cmd), TCL_INDEX_NONE); } parentNsPtr = NULL; /* * Iterate over the objects and append to the methodNameDs and methodHandleObj */ for (i = 1; i < oc; i++) { cmd = Tcl_GetCommandFromObj(interp, methodHandleObj); ensembleObject = (cmd != NULL) ? NsfGetObjectFromCmdPtr(cmd) : NULL; if (ensembleObject == NULL) { DECR_REF_COUNT(methodHandleObj); if (methodName1 != NULL) { *methodName1 = NULL; } if (regObject != NULL) { *regObject = NULL; } if (defObject != NULL) { *defObject = NULL; } return NULL; } if (parentNsPtr != NULL && (Tcl_Command_nsPtr(ensembleObject->id) != parentNsPtr)) { /* fprintf(stderr, "*** parent change saved parent %p %s computed parent %p %s\n", (void *)parentNsPtr, parentNsPtr->fullName, Tcl_Command_nsPtr(ensembleObject->id), Tcl_Command_nsPtr(ensembleObject->id)->fullName);*/ DECR_REF_COUNT(methodHandleObj); methodHandleObj = Tcl_DuplicateObj(ensembleObject->cmdName); } parentNsPtr = ensembleObject->nsPtr; Tcl_AppendLimitedToObj(methodHandleObj, "::", 2, INT_MAX, NULL); Tcl_AppendLimitedToObj(methodHandleObj, ObjStr(ov[i]), TCL_INDEX_NONE, INT_MAX, NULL); if (methodNameDs != NULL) { Tcl_DStringAppendElement(methodNameDs, ObjStr(ov[i])); } } /* * cmd contains now the parent-obj, on which the method was * defined. Get from this cmd the defObj. */ if (defObject != NULL) { *defObject = NsfGetObjectFromCmdPtr(cmd); } /*fprintf(stderr, "... handle '%s' last cmd %p defObject %p\n", ObjStr(methodHandleObj), (void *)cmd, *defObject);*/ /* * Obtain the command from the method handle and report back the * final methodName, */ cmd = Tcl_GetCommandFromObj(interp, methodHandleObj); if (methodNameDs != NULL && methodName1 != NULL) { *methodName1 = Tcl_DStringValue(methodNameDs); } /*fprintf(stderr, "... methodname1 '%s' cmd %p\n", Tcl_DStringValue(methodNameDs), (void *)cmd);*/ DECR_REF_COUNT(methodHandleObj); } else if (*methodName == ':') { cmd = Tcl_GetCommandFromObj(interp, methodObj); if (likely(cmd != NULL)) { referencedObject = GetRegObject(interp, cmd, methodName, methodName1, fromClassNS); if (regObject != NULL) { *regObject = referencedObject; } if (defObject != NULL) { *defObject = referencedObject; } if (methodName1 && *methodName1 == NULL) { /* * The return value for the method name is required and was not * computed by GetRegObject() */ *methodName1 = Tcl_GetCommandName(interp, cmd); } } else { /* * The cmd was not registered on an object or class, but we * still report back the cmd (might be e.g. a primitive cmd). */ if (regObject != NULL) { *regObject = NULL; } if (defObject != NULL) { *defObject = NULL; } } } else { if (methodName1 != NULL) { *methodName1 = methodName; } cmd = (nsPtr != NULL) ? FindMethod(nsPtr, methodName) : NULL; if (regObject != NULL) { *regObject = NULL; } if (defObject != NULL) { *defObject = NULL; } } return cmd; } /* *---------------------------------------------------------------------- * CmdIsProc -- * * Check, whether the cmd is interpreted * * Results: * A Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static bool CmdIsProc(const Tcl_Command cmd) nonnull(1) NSF_pure; NSF_INLINE static bool CmdIsProc(const Tcl_Command cmd) { /* * In 8.6: TclIsProc((Command *)cmd) is not equivalent to the definition * below. */ nonnull_assert(cmd != NULL); return (Tcl_Command_objProc(cmd) == TclObjInterpProc); } /* *---------------------------------------------------------------------- * CmdIsNsfObject -- * * Check whether the provided cmd refers to an NsfObject or Class. * * Results: * A Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static bool CmdIsNsfObject(Tcl_Command cmd) nonnull(1) NSF_pure; NSF_INLINE static bool CmdIsNsfObject(Tcl_Command cmd) { nonnull_assert(cmd != NULL); return Tcl_Command_objProc(cmd) == NsfObjDispatch; } /* *---------------------------------------------------------------------- * GetTclProcFromCommand -- * * Check whether cmd refers to a Tcl proc, and if so, return the * proc definition. * * Results: * The found proc of cmd or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Proc *GetTclProcFromCommand(const Tcl_Command cmd) nonnull(1) NSF_pure; static Proc * GetTclProcFromCommand(const Tcl_Command cmd) { Tcl_ObjCmdProc *proc; Proc *result; nonnull_assert(cmd != NULL); proc = Tcl_Command_objProc(cmd); if (proc == TclObjInterpProc) { result = (Proc *)Tcl_Command_objClientData(cmd); } else { result = NULL; } return result; } /* *---------------------------------------------------------------------- * FindMethod -- * * Lookup the cmd for methodName in a namespace. * * Results: * The found cmd of the method or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static Tcl_Command FindMethod( const Tcl_Namespace *nsPtr, const char *methodName ) { register const Tcl_HashEntry *entryPtr; Tcl_Command result; nonnull_assert(nsPtr != NULL); nonnull_assert(methodName != NULL); if ((entryPtr = Tcl_CreateHashEntry(Tcl_Namespace_cmdTablePtr(nsPtr), methodName, NULL))) { result = (Tcl_Command) Tcl_GetHashValue(entryPtr); } else { result = NULL; } return result; } /* *---------------------------------------------------------------------- * FindProcMethod -- * * Lookup the proc for methodName in a namespace. * * Results: * The found proc of the method or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Proc * FindProcMethod(const Tcl_Namespace *nsPtr, const char *methodName) nonnull(1) nonnull(2); static Proc * FindProcMethod(const Tcl_Namespace *nsPtr, const char *methodName) { Tcl_Command cmd; nonnull_assert(nsPtr != NULL); nonnull_assert(methodName != NULL); cmd = FindMethod(nsPtr, methodName); return (cmd != NULL) ? GetTclProcFromCommand(cmd) : NULL; } /* *---------------------------------------------------------------------- * SearchPLMethod, SearchPLMethod0 -- * * Search a method along a provided class list. The methodName * must be simple (must not contain space). While SearchPLMethod() * allows one to specify a flag for filtering the command, * SearchPLMethod0() is a lightly optimized function without the * filtering option. * * Results: * The found class defining the method or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfClass * SearchPLMethod( register const NsfClasses *pl, const char *methodName, Tcl_Command *cmdPtr, unsigned int flags ) nonnull(1) nonnull(2) nonnull(3); static NsfClass * SearchPLMethod0( register const NsfClasses *pl, const char *methodName, Tcl_Command *cmdPtr ) nonnull(1) nonnull(2) nonnull(3); static NsfClass * SearchPLMethod0( register const NsfClasses *pl, const char *methodName, Tcl_Command *cmdPtr ) { nonnull_assert(pl != NULL); nonnull_assert(methodName != NULL); nonnull_assert(cmdPtr != NULL); /* * Search the precedence list (class hierarchy). */ do { register const Tcl_HashEntry *entryPtr = Tcl_CreateHashEntry(Tcl_Namespace_cmdTablePtr(pl->cl->nsPtr), methodName, NULL); if (entryPtr != NULL) { *cmdPtr = (Tcl_Command) Tcl_GetHashValue(entryPtr); return pl->cl; } pl = pl->nextPtr; } while (pl != NULL); return NULL; } static NsfClass * SearchPLMethod( register const NsfClasses *pl, const char *methodName, Tcl_Command *cmdPtr, unsigned int flags ) { nonnull_assert(pl != NULL); nonnull_assert(methodName != NULL); nonnull_assert(cmdPtr != NULL); /* * Search the precedence list (class hierarchy). */ do { register const Tcl_HashEntry *entryPtr = Tcl_CreateHashEntry(Tcl_Namespace_cmdTablePtr(pl->cl->nsPtr), methodName, NULL); if (entryPtr != NULL) { Tcl_Command cmd = (Tcl_Command) Tcl_GetHashValue(entryPtr); if (likely(((unsigned int)Tcl_Command_flags(cmd) & flags) == 0u)) { *cmdPtr = cmd; return pl->cl; } } pl = pl->nextPtr; } while (pl != NULL); return NULL; } /* *---------------------------------------------------------------------- * SearchCMethod -- * * Search a method along the superclass hierarchy of the provided * class. The methodObj must be simple (must not contain * space). The method has the interface for internal calls during * interpretation, while SearchSimpleCMethod() has the interface * with more overhead for introspection. * * Results: * The found class defining the method or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfClass * SearchCMethod(NsfClass *class, const char *methodName, Tcl_Command *cmdPtr) nonnull(1) nonnull(2) nonnull(3); static NsfClass * SearchCMethod(NsfClass *class, const char *methodName, Tcl_Command *cmdPtr) { nonnull_assert(methodName != NULL); nonnull_assert(cmdPtr != NULL); nonnull_assert(class != NULL); return SearchPLMethod0(PrecedenceOrder(class), methodName, cmdPtr); } /* *---------------------------------------------------------------------- * SearchSimpleCMethod -- * * Search a method along the superclass hierarchy of the provided * class. The methodObj must be simple (must not contain * space). The method has the same interface as * SearchComplexCMethod(). * * Results: * The found class defining the method or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfClass * SearchSimpleCMethod(Tcl_Interp *UNUSED(interp), NsfClass *class, Tcl_Obj *methodObj, Tcl_Command *cmdPtr) nonnull(2) nonnull(3) nonnull(4); static NsfClass * SearchSimpleCMethod( Tcl_Interp *UNUSED(interp), NsfClass *class, Tcl_Obj *methodObj, Tcl_Command *cmdPtr ) { nonnull_assert(class != NULL); nonnull_assert(methodObj != NULL); nonnull_assert(cmdPtr != NULL); return SearchPLMethod0(PrecedenceOrder(class), ObjStr(methodObj), cmdPtr); } /* *---------------------------------------------------------------------- * SearchComplexCMethod -- * * Search a method along the superclass hierarchy of the provided * class. The methodObj can refer to an ensemble object (can * contain space). The method has the same interface as * SearchSimpleCMethod(). * * Results: * The found class defining the method or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfClass * SearchComplexCMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *methodObj, Tcl_Command *cmdPtr) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static NsfClass * SearchComplexCMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *methodObj, Tcl_Command *cmdPtr) { NsfClasses *pl; bool fromClassNS = NSF_TRUE; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(methodObj != NULL); nonnull_assert(cmdPtr != NULL); for (pl = PrecedenceOrder(class); pl != NULL; pl = pl->nextPtr) { Tcl_Command cmd = ResolveMethodName(interp, pl->cl->nsPtr, methodObj, NULL, NULL, NULL, NULL, &fromClassNS); if (cmd != NULL) { *cmdPtr = cmd; return pl->cl; } } return NULL; } /* *---------------------------------------------------------------------- * ObjectFindMethod -- * * Find a method for a given object in the precedence path. The * provided methodObj might be an ensemble object. This function * tries to optimize access by calling different implementations * for simple and ensemble method names. * * Results: * Tcl command. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Command ObjectFindMethod(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *methodObj, NsfClass **classPtr) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static Tcl_Command ObjectFindMethod(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *methodObj, NsfClass **classPtr) { Tcl_Command cmd = NULL; NsfClass *(*lookupFunction)(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *methodObj, Tcl_Command *cmdPtr); nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodObj != NULL); nonnull_assert(classPtr != NULL); if (NsfHasTclSpace(ObjStr(methodObj))) { lookupFunction = SearchComplexCMethod; } else { lookupFunction = SearchSimpleCMethod; } if (unlikely(object->flags & NSF_MIXIN_ORDER_VALID) == 0u) { MixinComputeDefined(interp, object); } if ((object->flags & NSF_MIXIN_ORDER_DEFINED_AND_VALID) != 0u) { NsfCmdList *mixinList; for (mixinList = object->mixinOrder; mixinList; mixinList = mixinList->nextPtr) { NsfClass *mixin = NsfGetClassFromCmdPtr(mixinList->cmdPtr); if ((mixin != NULL) && (*classPtr = (*lookupFunction)(interp, mixin, methodObj, &cmd))) { if (((unsigned int)Tcl_Command_flags(cmd) & NSF_CMD_CLASS_ONLY_METHOD) != 0u && !NsfObjectIsClass(object) ) { cmd = NULL; continue; } break; } } } if ((cmd == NULL) && (object->nsPtr != NULL)) { bool fromClassNS = NSF_FALSE; cmd = ResolveMethodName(interp, object->nsPtr, methodObj, NULL, NULL, NULL, NULL, &fromClassNS); } if (cmd == NULL && object->cl != NULL) { *classPtr = (*lookupFunction)(interp, object->cl, methodObj, &cmd); } return cmd; } /* *---------------------------------------------------------------------- * GetObjectSystem -- * * Return the object system for which the object was defined * * Results: * Object system pointer * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfObjectSystem * GetObjectSystem(const NsfObject *object) nonnull(1) NSF_pure; static NsfObjectSystem * GetObjectSystem(const NsfObject *object) { nonnull_assert(object != NULL); if (NsfObjectIsClass(object)) { return ((NsfClass *)object)->osPtr; } assert(object->cl != NULL); return object->cl->osPtr; } /* *---------------------------------------------------------------------- * ObjectSystemFree -- * * Free a single object system structure including its root-classes. * * Results: * None. * * Side effects: * Free memory of structure, free the root-classes. * *---------------------------------------------------------------------- */ static void ObjectSystemFree(Tcl_Interp *interp, NsfObjectSystem *osPtr) nonnull(1) nonnull(2); static void ObjectSystemFree(Tcl_Interp *interp, NsfObjectSystem *osPtr) { int idx; nonnull_assert(interp != NULL); nonnull_assert(osPtr != NULL); for (idx = 0; idx <= NSF_s_set_idx; idx++) { if (osPtr->methods[idx]) { DECR_REF_COUNT(osPtr->methods[idx]); osPtr->methodNames[idx] = NULL; } if (osPtr->handles[idx]) { DECR_REF_COUNT(osPtr->handles[idx]); } } if (osPtr->rootMetaClass != NULL && osPtr->rootClass != NULL) { RemoveSuper(osPtr->rootMetaClass, osPtr->rootClass); RemoveInstance((NsfObject *)osPtr->rootMetaClass, osPtr->rootMetaClass); RemoveInstance((NsfObject *)osPtr->rootClass, osPtr->rootMetaClass); FinalObjectDeletion(interp, &osPtr->rootClass->object); FinalObjectDeletion(interp, &osPtr->rootMetaClass->object); } FREE(NsfObjectSystem, osPtr); } /* *---------------------------------------------------------------------- * ObjectSystemAdd -- * * Add and entry to the list of object systems of the interpreter. * * Results: * None. * * Side effects: * Updating the per interp list of object systems. * *---------------------------------------------------------------------- */ static void ObjectSystemAdd(Tcl_Interp *interp, NsfObjectSystem *osPtr) nonnull(1) nonnull(2); static void ObjectSystemAdd(Tcl_Interp *interp, NsfObjectSystem *osPtr) { nonnull_assert(interp != NULL); nonnull_assert(osPtr != NULL); osPtr->nextPtr = RUNTIME_STATE(interp)->objectSystems; RUNTIME_STATE(interp)->objectSystems = osPtr; } /* *---------------------------------------------------------------------- * ObjectSystemsCleanup -- * * Delete all objects from all defined object systems. This method * is to be called when a Next Scripting process or thread exists. * * Results: * None. * * Side effects: * All commands and objects are deleted, memory is freed. * *---------------------------------------------------------------------- */ static int ObjectSystemsCleanup(Tcl_Interp *interp, bool withKeepvars) nonnull(1); static int ObjectSystemsCleanup(Tcl_Interp *interp, bool withKeepvars) { NsfCmdList *instances = NULL, *entryPtr; NsfObjectSystem *osPtr; nonnull_assert(interp != NULL); /* * Deletion is performed in two rounds: * (a) SOFT DESTROY: invoke all user-defined destroy methods * without destroying objects * (b) PHYSICAL DESTROY: delete the objects and classes, * destroy methods are not invoked anymore * * This is to prevent that the destroy order causes classes to be * deleted before the methods invoked by destroy are executed. Note * that it is necessary to iterate over all object systems * simultaneous, since the might be dependencies between objects of * different object systems. */ /* * Collect all instances from all object systems */ for (osPtr = RUNTIME_STATE(interp)->objectSystems; osPtr != NULL; osPtr = osPtr->nextPtr) { GetAllInstances(interp, &instances, osPtr->rootClass); } /***** SOFT DESTROY *****/ RUNTIME_STATE(interp)->exitHandlerDestroyRound = NSF_EXITHANDLER_ON_SOFT_DESTROY; /*fprintf(stderr, "===CALL destroy on OBJECTS\n");*/ for (entryPtr = instances; entryPtr != NULL; entryPtr = entryPtr->nextPtr) { NsfObject *object = (NsfObject *)entryPtr->clorobj; /*fprintf(stderr, "key = %s %p %d flags %.6x\n", ObjectName(object), (void *)object, object && !NsfObjectIsClass(object), object->flags);*/ if (object != NULL && !NsfObjectIsClass(object) && ((object->flags & NSF_DESTROY_CALLED) == 0u) ) { DispatchDestroyMethod(interp, object, 0u); } } /*fprintf(stderr, "===CALL destroy on CLASSES\n");*/ for (entryPtr = instances; entryPtr != NULL; entryPtr = entryPtr->nextPtr) { const NsfClass *class = entryPtr->clorobj; if (class != NULL && ((class->object.flags & NSF_DESTROY_CALLED) == 0u) ) { DispatchDestroyMethod(interp, (NsfObject *)class, 0u); } } /* * Now turn off filters, all destroy callbacks are done. */ RUNTIME_STATE(interp)->doFilters = 0; (void)Tcl_RemoveInterpResolvers(interp, "nsf"); #ifdef DO_CLEANUP FreeAllNsfObjectsAndClasses(interp, &instances); # ifdef DO_FULL_CLEANUP DeleteProcsAndVars(interp, Tcl_GetGlobalNamespace(interp), withKeepvars); # endif #endif (void)withKeepvars; /* make sure, the variable is not reported as unused */ #ifdef DO_CLEANUP { NsfObjectSystem *nPtr; /* * Free all objects systems with their root-classes. */ for (osPtr = RUNTIME_STATE(interp)->objectSystems; osPtr != NULL; osPtr = nPtr) { nPtr = osPtr->nextPtr; ObjectSystemFree(interp, osPtr); } } /* * Finally, free all nsfprocs. */ DeleteNsfProcs(interp, NULL); #endif CmdListFree(&instances, NULL); return TCL_OK; } /* *---------------------------------------------------------------------- * CallDirectly -- * * Determine when it is possible/necessary to call a method * implementation directly or via method dispatch. * * Results: * NSF_TRUE is returned when command should be invoked directly, * NSF_FALSE otherwise. * * Side effects: * methodObjPtr is set with the Tcl_Obj of the name of the method, * if there is one defined. * *---------------------------------------------------------------------- */ static bool CallDirectly(Tcl_Interp *interp, NsfObject *object, int methodIdx, Tcl_Obj **methodObjPtr) nonnull(1) nonnull(2) nonnull(4); static bool CallDirectly(Tcl_Interp *interp, NsfObject *object, int methodIdx, Tcl_Obj **methodObjPtr) { /* * We can/must call a C-implemented method directly, when * * a) the object system has no such appropriate method defined * * b) the script does not contain a method with the appropriate * name, and * * c) filters are not active on the object */ NsfObjectSystem *osPtr = GetObjectSystem(object); bool callDirectly = NSF_TRUE; Tcl_Obj *methodObj; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodObjPtr != NULL); methodObj = osPtr->methods[methodIdx]; /*fprintf(stderr, "OS of %s is %s, method %s methodObj %p osPtr %p defined %.8x %.8x overloaded %.8x %.8x flags %.8x\n", ObjectName(object), ObjectName(&osPtr->rootClass->object), Nsf_SystemMethodOpts[methodIdx]+1, (void *)methodObj, (void *)osPtr, osPtr->definedMethods, osPtr->definedMethods & (1 << methodIdx), osPtr->overloadedMethods, osPtr->overloadedMethods & (1 << methodIdx), 1 << methodIdx );*/ if (methodObj != NULL) { unsigned int flag = 1u << methodIdx; if ((osPtr->overloadedMethods & flag) != 0u) { /* * The method is overloaded, we must dispatch. */ /*fprintf(stderr, "overloaded\n");*/ callDirectly = NSF_FALSE; } else if ((osPtr->definedMethods & flag) == 0u) { /* * The method is not defined, we must call directly. */ /*fprintf(stderr, "Warning: CallDirectly object %s idx %s not defined\n", ObjectName(object), Nsf_SystemMethodOpts[methodIdx]+1);*/ } else { #if defined(DISPATCH_ALWAYS_DEFINED_METHODS) callDirectly = NSF_FALSE; #else if ((object->flags & NSF_FILTER_ORDER_VALID) == 0u) { FilterComputeDefined(interp, object); } /*fprintf(stderr, "CallDirectly object %s idx %s object flags %.6x %.6x \n", ObjectName(object), Nsf_SystemMethodOpts[methodIdx]+1, (object->flags & NSF_FILTER_ORDER_DEFINED_AND_VALID), NSF_FILTER_ORDER_DEFINED_AND_VALID);*/ if ((object->flags & NSF_FILTER_ORDER_DEFINED_AND_VALID) == NSF_FILTER_ORDER_DEFINED_AND_VALID) { /*fprintf(stderr, "CallDirectly object %s idx %s has filter \n", ObjectName(object), Nsf_SystemMethodOpts[methodIdx]+1);*/ callDirectly = NSF_FALSE; } #endif } } /*fprintf(stderr, "CallDirectly object %s idx %d returns %s => %d\n", ObjectName(object), methodIdx, (methodObj != NULL) ? ObjStr(methodObj) : "(null)", callDirectly);*/ /* * Teturn the methodObj in every case. */ *methodObjPtr = methodObj; return callDirectly; } /* *---------------------------------------------------------------------- * NsfMethodObj -- * * Return the methodObj for a given method index. * * Results: * Returns Tcl_Obj* or NULL * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Obj * NsfMethodObj(const NsfObject *object, int methodIdx) { NsfObjectSystem *osPtr = GetObjectSystem(object); nonnull_assert(object != NULL); /* fprintf(stderr, "NsfMethodObj object %s os %p idx %d %s methodObj %p\n", ObjectName(object), (void *)osPtr, methodIdx, Nsf_SystemMethodOpts[methodIdx]+1, osPtr->methods[methodIdx]); */ return osPtr->methods[methodIdx]; } /* * Conditional memory allocations of optional storage */ /* *---------------------------------------------------------------------- * NsfRequireObjectOpt -- * * Makes sure that the provided object has the optional data member * set. * * Results: * Optional data for the object. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfObjectOpt * NsfRequireObjectOpt(NsfObject *object) { nonnull_assert(object != NULL); if (object->opt == NULL) { object->opt = NEW(NsfObjectOpt); memset(object->opt, 0, sizeof(NsfObjectOpt)); } return object->opt; } /* *---------------------------------------------------------------------- * NsfRequireClassOpt -- * * Makes sure that the provided class has the optional data member * set. * * Results: * Optional data for the class. * * Side effects: * None. * *---------------------------------------------------------------------- */ NsfClassOpt * NsfRequireClassOpt(NsfClass *class) { nonnull_assert(class != NULL); if (class->opt == NULL) { class->opt = NEW(NsfClassOpt); memset(class->opt, 0, sizeof(NsfClassOpt)); if ((class->object.flags & NSF_IS_CLASS) != 0u) { class->opt->id = class->object.id; /* probably a temporary solution */ } } return class->opt; } /* *---------------------------------------------------------------------- * MakeObjNamespace -- * * Creates for the object a namespace, if it does not exist. * already. * * Results: * None. * * Side effects: * Might create a namespace. * *---------------------------------------------------------------------- */ static void MakeObjNamespace(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); static void MakeObjNamespace(Tcl_Interp *interp, NsfObject *object) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); #ifdef NAMESPACE_TRACE fprintf(stderr, "+++ MakeObjNamespace for %s\n", ObjectName(object)); #endif if (object->nsPtr == NULL) { Tcl_Namespace *nsPtr; nsPtr = object->nsPtr = NSGetFreshNamespace(interp, object, ObjStr(object->cmdName)); assert(nsPtr != NULL); /* * Copy all obj variables to the newly created namespace */ if (object->varTablePtr != NULL) { Tcl_HashSearch search; Tcl_HashEntry *hPtr; TclVarHashTable *varTablePtr = Tcl_Namespace_varTablePtr(nsPtr); Tcl_HashTable *varHashTablePtr = TclVarHashTablePtr(varTablePtr); Tcl_HashTable *objHashTablePtr = TclVarHashTablePtr(object->varTablePtr); *varHashTablePtr = *objHashTablePtr; /* copy the table */ if (objHashTablePtr->buckets == objHashTablePtr->staticBuckets) { varHashTablePtr->buckets = varHashTablePtr->staticBuckets; } for (hPtr = Tcl_FirstHashEntry(varHashTablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { hPtr->tablePtr = varHashTablePtr; } CallStackReplaceVarTableReferences(interp, object->varTablePtr, (TclVarHashTable *)varHashTablePtr); ckfree((char *) object->varTablePtr); object->varTablePtr = NULL; } } } /* *---------------------------------------------------------------------- * CompiledLocalsLookup -- * * Lookup variable from the compiled locals. The function performs * a linear search in an unsorted list maintained by Tcl. This * function is just used for the rather deprecated "instvar" * method. * * Results: * Returns Tcl_Var (or NULL, when lookup is not successful). * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Var CompiledLocalsLookup(CallFrame *varFramePtr, const char *varName) nonnull(1) nonnull(2); static Tcl_Var CompiledLocalsLookup(CallFrame *varFramePtr, const char *varName) { TCL_SIZE_T localCt; nonnull_assert(varFramePtr != NULL); nonnull_assert(varName != NULL); localCt = varFramePtr->numCompiledLocals; if (localCt > 0) { Tcl_Obj **varNameObjPtr; TCL_SIZE_T i, nameLength; varNameObjPtr = &varFramePtr->localCachePtr->varName0; nameLength = (TCL_SIZE_T)strlen(varName); /* fprintf(stderr, "=== compiled local search #local vars %d for <%s> flags %.8x\n", localCt, varName, varFramePtr->isProcCallFrame); */ for (i = 0 ; i < localCt ; i++, varNameObjPtr++) { Tcl_Obj *varNameObj = *varNameObjPtr; TCL_SIZE_T len; if (likely(varNameObj != NULL)) { const char *localName = Tcl_GetStringFromObj(varNameObj, &len); /* fprintf(stderr, ".. [%d] varNameObj %p %p <%s>\n", i, (void *)varNameObj, (void *)varNameObj->typePtr, localName); */ if (unlikely(varName[0] == localName[0] && varName[1] == localName[1] && (TCL_SIZE_T)len == nameLength && memcmp(varName, localName, (size_t)len) == 0)) { return (Tcl_Var) &varFramePtr->compiledLocals[i]; } } } } return NULL; } /* *---------------------------------------------------------------------- * CompiledColonLocalsLookupBuildCache -- * * Helper function for CompiledColonLocalsLookup(): build up a * sorted cache consisting only of colon prefixed variables, such * that e.g. non-successful lookup can be performed in O(n/2). In * comparison to CompiledLocalsLookup() this function is about a * factor of 4 faster. * * Results: * Returns Tcl_Var (or NULL, when lookup is not successful). * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Var CompiledColonLocalsLookupBuildCache(CallFrame *varFramePtr, const char *varName, TCL_SIZE_T nameLength, Tcl_Obj **localNames, NsfProcContext *ctxPtr) nonnull(1) nonnull(2) nonnull(4) nonnull(5); static Tcl_Var CompiledColonLocalsLookupBuildCache(CallFrame *varFramePtr, const char *varName, TCL_SIZE_T nameLength, Tcl_Obj **localNames, NsfProcContext *ctxPtr) { int nrColonVars = 0, j; TCL_SIZE_T localCt, i; Tcl_Var result; Tcl_Obj **varNameObjPtr; nonnull_assert(varFramePtr != NULL); nonnull_assert(varName != NULL); nonnull_assert(localNames != NULL); nonnull_assert(ctxPtr != NULL); assert(ctxPtr->colonLocalVarCache == NULL); assert(varFramePtr->localCachePtr != NULL); localCt = varFramePtr->numCompiledLocals; varNameObjPtr = &varFramePtr->localCachePtr->varName0; /* * Count colonVars */ for (i = 0; i < localCt; i++, varNameObjPtr++) { Tcl_Obj *varNameObj = *varNameObjPtr; if (varNameObj != NULL) { const char *localName = TclGetString(varNameObj); if (localName[0] == ':') { nrColonVars ++; } } } /*fprintf(stderr, ".. build cache #local vars %d for <%s> flags %.8x ctxPtr %p colonvars %d\n", localCt, varName, varFramePtr->isProcCallFrame, (void *)ctxPtr, nrColonVars );*/ /* * Allocate colonLocalVarCache in the proper size (keep space for a * terminating element). */ ctxPtr->colonLocalVarCache = NEW_ARRAY(long, nrColonVars+1); varNameObjPtr = &varFramePtr->localCachePtr->varName0; /* * Fill colonLocalVarCache; since we have to go through the whole list, we * might find and return the variable. */ j = 0; result = NULL; for (i = 0; i < localCt ; i++, varNameObjPtr++) { Tcl_Obj *varNameObj = *varNameObjPtr; if (varNameObj != NULL) { TCL_SIZE_T len; const char *localName = Tcl_GetStringFromObj(varNameObj, &len); if (localName[0] == ':') { int k; Tcl_Var var = (Tcl_Var) &varFramePtr->compiledLocals[i]; if (varName[1] == localName[1] && len == nameLength && memcmp(varName, localName, (size_t)len) == 0) { result = var; } /* fprintf(stderr, ".. insert %s (%d) on pos %d; check j %d entries \n", localName, i, j, j); */ for (k = 0; k < j; k++) { int cmp; long idx; const char *cachedName; idx = ctxPtr->colonLocalVarCache[k]; cachedName = Tcl_GetStringFromObj(localNames[idx], &len); cmp = strcmp(localName, cachedName); /* fprintf(stderr, "... [%d] cmp newVarName <%s> (%d) with cachendName <%s> (%d) => %d\n", k, localName, i, cachedName, idx, cmp); */ if (cmp < 0) { int ii; /* * Make space on position k for inserting the new element. We * might uses memmove() instead. */ for (ii = j; ii > k; ii--) { ctxPtr->colonLocalVarCache[ii] = ctxPtr->colonLocalVarCache[ii - 1]; } break; } } ctxPtr->colonLocalVarCache[k] = (long)i; j++; if (j == nrColonVars) { break; } } } } /* * Terminate list of indices with -1 */ ctxPtr->colonLocalVarCache[j] = -1; /* fprintf(stderr, ".. search #local vars %d varName <%s> colonvars %d found %p\n", localCt, varName, nrColonVars, (void*)result); */ return result; } /* *---------------------------------------------------------------------- * CompiledColonLocalsLookup -- * * Lookup single colon prefixed variables from the compiled * locals. This function uses a cache consisting of colon prefixed * variables to speed up variable access. * * Results: * Returns Tcl_Var (or NULL, when lookup is not successful) * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Var CompiledColonLocalsLookup(CallFrame *varFramePtr, const char *varName) nonnull(1) nonnull(2); static Tcl_Var CompiledColonLocalsLookup(CallFrame *varFramePtr, const char *varName) { Tcl_Var result; nonnull_assert(varFramePtr != NULL); nonnull_assert(varName != NULL); if (varFramePtr->numCompiledLocals == 0) { result = NULL; } else { Tcl_Obj **localNames; TCL_SIZE_T nameLength; Tcl_Command cmd; NsfProcContext *ctxPtr; /* * Get the string table of the compiled locals and the length of the * variable to search for faster access into local variables. */ localNames = &varFramePtr->localCachePtr->varName0; nameLength = (TCL_SIZE_T)strlen(varName); cmd = (Tcl_Command )varFramePtr->procPtr->cmdPtr; ctxPtr = ProcContextRequire(cmd); /* * Check whether we have already a sorted cache (colonLocalVarCache). If not, * build the cache and check in the same step for the wanted variable. */ if (unlikely(ctxPtr->colonLocalVarCache == NULL)) { result = CompiledColonLocalsLookupBuildCache(varFramePtr, varName, nameLength, localNames, ctxPtr); } else { long i, j; /* * We have a colonLocalVarCache. * * Search the colonVarCache, which is alphabetically sorted to allow e.g. * termination after O(n/2) on failures. */ result = NULL; for (i = 0, j = ctxPtr->colonLocalVarCache[0]; j > -1; ++i, j = ctxPtr->colonLocalVarCache[i]) { TCL_SIZE_T len; const char *localName; localName = Tcl_GetStringFromObj(localNames[j], &len); /* fprintf(stderr, ".. [%d] varNameObj %p <%s> vs <%s>\n", j, (void *)varNameObj, localName, varName); */ /* * The first char of colon varName is always a colon, so we do not need to * compare. */ if (varName[1] < localName[1]) { break; } else if (varName[1] == localName[1]) { int cmp; /* * Even when the first character is identical, we call compare() only * when the lengths are equal. */ if (len != nameLength) { continue; } cmp = strcmp(varName, localName); if (cmp == 0) { result = (Tcl_Var) &varFramePtr->compiledLocals[j]; break; } else if (cmp < 0) { /* * We are past the place, where the variable should be, so give up. */ break; } } } #if 0 if (result != NULL) { fprintf(stderr, "... <%s> found -> [%d] %p\n", varName, j, (void *)result); } #endif } } return result; } /* *---------------------------------------------------------------------- * GetVarAndNameFromHash -- * * Convenience function to obtain variable and name from * a variable hash entry. * * Results: * Results are passed back in argument 2 and 3 * * Side effects: * None. * *---------------------------------------------------------------------- */ static void GetVarAndNameFromHash(const Tcl_HashEntry *hPtr, Var **val, Tcl_Obj **varNameObj) nonnull(1) nonnull(2) nonnull(3); static void GetVarAndNameFromHash(const Tcl_HashEntry *hPtr, Var **val, Tcl_Obj **varNameObj) { nonnull_assert(hPtr != NULL); nonnull_assert(val != NULL); nonnull_assert(varNameObj != NULL); *val = TclVarHashGetValue(hPtr); *varNameObj = TclVarHashGetKey(*val); } /********************************************************* * * Variable resolvers * *********************************************************/ #define FOR_COLON_RESOLVER(ptr) (*(ptr) == ':' && *((ptr)+1) != ':') /* *---------------------------------------------------------------------- * MethodName -- * * Return the methodName from a Tcl_Obj, strips potentially the * colon prefix * * Results: * method name * * Side effects: * None. * *---------------------------------------------------------------------- */ static const char * MethodName(Tcl_Obj *methodObj) { const char *methodName; nonnull_assert(methodObj != NULL); methodName = ObjStr(methodObj); if (FOR_COLON_RESOLVER(methodName)) { methodName ++; } return methodName; } /* *---------------------------------------------------------------------- * NsfMethodNamePath -- * * Compute the full method name for error messages containing the * ensemble root. * * Results: * Tcl_Obj of reference count 0, caller has to take care for * refcounting. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Obj * NsfMethodNamePath(Tcl_Interp *interp, Tcl_CallFrame *framePtr, const char *methodName) { Tcl_Obj *resultObj; nonnull_assert(interp != NULL); nonnull_assert(methodName != NULL); if (framePtr != NULL) { resultObj = CallStackMethodPath(interp, framePtr); } else { resultObj = Tcl_NewListObj(0, NULL); } Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(methodName, TCL_INDEX_NONE)); return resultObj; } /* *---------------------------------------------------------------------- * NsColonVarResolver -- * * Namespace resolver for namespace specific variable lookup. * colon prefix * * Results: * method name * * Side effects: * None. * *---------------------------------------------------------------------- */ static int NsColonVarResolver(Tcl_Interp *interp, const char *varName, Tcl_Namespace *UNUSED(nsPtr), int flags, Tcl_Var *varPtr) nonnull(1) nonnull(2) nonnull(5); static int NsColonVarResolver(Tcl_Interp *interp, const char *varName, Tcl_Namespace *UNUSED(nsPtr), int flags, Tcl_Var *varPtr) { Tcl_CallFrame *varFramePtr; TclVarHashTable *varTablePtr; NsfObject *object; int new; unsigned int frameFlags; Tcl_Obj *key; #if defined(NSF_DEVELOPMENT) nonnull_assert(interp != NULL); nonnull_assert(varName != NULL); nonnull_assert(varPtr != NULL); #endif #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, "NsColonVarResolver '%s' flags %.6x\n", varName, flags); #endif /* * Case 1: The variable is to be resolved in global scope, proceed in * resolver chain */ if (unlikely((flags & TCL_GLOBAL_ONLY) != 0u)) { /*fprintf(stderr, "global-scoped lookup for var '%s' in NS '%s'\n", varName, nsPtr->fullName);*/ return TCL_CONTINUE; } /* * Case 2: The lookup happens in a proc frame (lookup in compiled * locals and hash-table vars). We are not interested to handle * these cases here, so proceed in resolver chain. */ varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); assert(varFramePtr != NULL); frameFlags = (unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr); #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, "NsColonVarResolver '%s' frame flags %.6x\n", varName, Tcl_CallFrame_isProcCallFrame(varFramePtr)); #endif if ((frameFlags & FRAME_IS_PROC) != 0u) { #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, "...... forwarding to next resolver\n"); #endif /*fprintf(stderr, "proc-scoped var '%s' assumed, frame %p flags %.6x\n", name, (void *)varFramePtr, Tcl_CallFrame_isProcCallFrame(varFramePtr));*/ return TCL_CONTINUE; } /* * FRAME_IS_NSF_CMETHOD has always FRAME_IS_PROC set, so it is * handled already above */ assert((frameFlags & FRAME_IS_NSF_CMETHOD) == 0u); if ((frameFlags & FRAME_IS_NSF_OBJECT) == 0u) { /* * Case 3: we are not in a Next Scripting frame, so proceed as well */ return TCL_CONTINUE; } else { /* * Case 4: we are in a Next Scripting object frame */ if (*varName == ':') { if (*(varName+1) != ':') { /* * Case 4a: The variable name starts with a single ":". Skip * the char, but stay in the resolver. */ varName ++; } else { /* * Case 4b: Names starting with "::" are not for us */ return TCL_CONTINUE; } } else if (NSTail(varName) != varName) { /* * Case 4c: Names containing "::" are not for us */ return TCL_CONTINUE; } /* * Since we know that we are here always in an object frame, we * can blindly get the object from the client data . */ object = (NsfObject *)Tcl_CallFrame_clientData(varFramePtr); } /* * We have an object and create the variable if not found */ assert(object != NULL); varTablePtr = (object->nsPtr != NULL) ? Tcl_Namespace_varTablePtr(object->nsPtr) : object->varTablePtr; assert(varTablePtr != NULL); /* * Does the variable exist in the object's namespace? */ key = Tcl_NewStringObj(varName, TCL_INDEX_NONE); INCR_REF_COUNT(key); *varPtr = (Tcl_Var)VarHashCreateVar(varTablePtr, key, NULL); #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, "...... lookup of '%s' for object '%s' returns %p\n", varName, ObjectName(object), (void *)*varPtr); #endif if (*varPtr == NULL) { /* * We failed to find the variable so far, therefore, we create it * in this var table. Note that in several cases above, * TCL_CONTINUE takes care for variable creation. */ const Var *newVar = VarHashCreateVar(varTablePtr, key, &new); *varPtr = (Tcl_Var)newVar; } DECR_REF_COUNT(key); return likely(*varPtr != NULL) ? TCL_OK : TCL_ERROR; } /********************************************************* * * Begin of compiled var resolver * *********************************************************/ typedef struct NsfResolvedVarInfo { Tcl_ResolvedVarInfo vInfo; /* This must be the first element. */ NsfObject *lastObject; Tcl_Var var; Tcl_Obj *nameObj; } NsfResolvedVarInfo; /* *---------------------------------------------------------------------- * HashVarFree -- * * Free hashed variables based on refCount. * * Results: * None. * * Side effects: * Changed refCount or freed variable. * *---------------------------------------------------------------------- */ NSF_INLINE static void HashVarFree(Tcl_Var var) { if (unlikely(VarHashRefCount(var) < 2)) { /*fprintf(stderr, "#### free %p\n", (void *)var);*/ ckfree((char *) var); } else { VarHashRefCount(var)--; } } /* *---------------------------------------------------------------------- * CompiledColonVarFetch -- * * This function is the actual variable resolution handler for a * colon-prefixed (":/varName/") found in a compiled script * registered by the compiling var resolver (see * InterpCompiledColonVarResolver()). When initializing a call * frame, this handler is called, crawls the object's var table * (creating a variable, if needed), and returns a Var * structure. Based on this, a link variable ":/varName/" pointing * to this object variable (i.e., "varName") is created and is * stored in the compiled locals array of the call frame. Beware * that these link variables interact with the family of * link-creating commands ([variable], [global], [upvar]) by being * subject to "retargeting" upon name conflicts (see * tests/varresolutiontest.tcl for some examples). * * Results: * Tcl_Var containing value or NULL. * * Side effects: * Updates of Variable structure cache in necessary. * *---------------------------------------------------------------------- */ static Tcl_Var CompiledColonVarFetch(Tcl_Interp *interp, Tcl_ResolvedVarInfo *vinfoPtr) nonnull(1) nonnull(2); static Tcl_Var CompiledColonVarFetch(Tcl_Interp *interp, Tcl_ResolvedVarInfo *vinfoPtr) { NsfResolvedVarInfo *resVarInfo; NsfCallStackContent *cscPtr; NsfObject *object; Tcl_Var var; nonnull_assert(interp != NULL); nonnull_assert(vinfoPtr != NULL); resVarInfo = (NsfResolvedVarInfo *)vinfoPtr; var = resVarInfo->var; #if defined(VAR_RESOLVER_TRACE) { unsigned int flags = (var != NULL) ? (unsigned int)((Var *)var)->flags : 0u; fprintf(stderr, "CompiledColonVarFetch var '%s' var %p flags = %.4x dead? %.4x\n", ObjStr(resVarInfo->nameObj), (void *)var, flags, flags & VAR_DEAD_HASH); } #endif cscPtr = CallStackGetTopFrame0(interp); if (likely(cscPtr != NULL)) { object = cscPtr->self; } else { object = NULL; } /* * We cache lookups based on nsf objects; we have to care about * cases, where the instance variables are in some delete states. * */ if ((var != NULL) && ((object == resVarInfo->lastObject)) && (((((Var *)var)->flags) & VAR_DEAD_HASH) == 0u)) { /* * The variable is valid. */ #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, ".... cached var '%s' var %p flags = %.4x\n", ObjStr(resVarInfo->nameObj), (void *)var, ((Var *)var)->flags); #endif /* * return var; */ } else if (unlikely(object == NULL)) { var = NULL; } else { TclVarHashTable *varTablePtr; int new; if (var != NULL) { /* * The variable is not valid anymore. Clean it up. */ HashVarFree(var); } if (object->nsPtr != NULL) { varTablePtr = Tcl_Namespace_varTablePtr(object->nsPtr); } else if (object->varTablePtr != NULL) { varTablePtr = object->varTablePtr; } else { /* * In most situations, we have a varTablePtr through the clauses * above. However, if someone redefines e.g. the method "configure" or * "objectparameter", we might find an object with a still empty * varTable, since these are lazy initiated. */ varTablePtr = object->varTablePtr = VarHashTableCreate(); } assert(varTablePtr != NULL); resVarInfo->lastObject = object; #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, "Fetch var %s in object %s\n", TclGetString(resVarInfo->nameObj), ObjectName(object)); #endif resVarInfo->var = var = (Tcl_Var) VarHashCreateVar(varTablePtr, resVarInfo->nameObj, &new); /* * Increment the reference counter to avoid ckfree() of the variable * in Tcl's FreeVarEntry(); for cleanup, we provide our own * HashVarFree(); */ VarHashRefCount(var)++; #if defined(VAR_RESOLVER_TRACE) { const Var *v = (Var *)(resVarInfo->var); fprintf(stderr, ".... looked up existing var %s var %p flags = %.6x undefined %d\n", ObjStr(resVarInfo->nameObj), (void *)v, v->flags, TclIsVarUndefined(v)); } #endif } return var; } /* *---------------------------------------------------------------------- * CompiledColonVarFree -- * * DeleteProc of the compiled variable handler. * * Results: * None. * * Side effects: * Free compiled variable structure and variable. * *---------------------------------------------------------------------- */ static void CompiledColonVarFree(Tcl_ResolvedVarInfo *vInfoPtr) nonnull(1); static void CompiledColonVarFree(Tcl_ResolvedVarInfo *vInfoPtr) { NsfResolvedVarInfo *resVarInfo; nonnull_assert(vInfoPtr != NULL); resVarInfo = (NsfResolvedVarInfo *)vInfoPtr; #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, "CompiledColonVarFree %p for variable '%s'\n", (void *)resVarInfo, ObjStr(resVarInfo->nameObj)); #endif DECR_REF_COUNT(resVarInfo->nameObj); if (resVarInfo->var != NULL) { HashVarFree(resVarInfo->var); } FREE(NsfResolvedVarInfo, vInfoPtr); } /* *---------------------------------------------------------------------- * InterpCompiledColonVarResolver -- * * For colon-prefixed (":/varName/") variables, we provide our own * var resolver for compiling scripts and evaluating compiled * scripts (e.g., proc bodies). At the time of first compilation * (or re-compilation), this resolver is processed (see * tclProc.c:InitResolvedLocals()). It registers two handlers for a * given, colon-prefixed variable found in the script: the actual * variable fetcher and a variable cleanup handler. The variable * fetcher is executed whenever a Tcl call frame is initialized and * the array of compiled locals is constructed (see also * InitResolvedLocals()). * * The Tcl var resolver protocol dictates that per-namespace * compiling var resolvers take precedence over this per-interp * compiling var resolver. That is, per-namespace resolvers are * processed first and can effectively out-rule per-interp * resolvers by signaling TCL_OK or TCL_BREAK. * * Results: * TCL_OK or TCL_CONTINUE (according to Tcl's var resolver protocol) * * Side effects: * Registers per-variable resolution and cleanup handlers. * *---------------------------------------------------------------------- */ static int InterpCompiledColonVarResolver(Tcl_Interp *interp, const char *name, TCL_SIZE_T length, Tcl_Namespace *UNUSED(context), Tcl_ResolvedVarInfo **rPtr) nonnull(1) nonnull(2) nonnull(5); static int InterpCompiledColonVarResolver(Tcl_Interp *interp, const char *name, TCL_SIZE_T length, Tcl_Namespace *UNUSED(context), Tcl_ResolvedVarInfo **rPtr) { /* * The variable handler is registered, when we have an active Next * Scripting object and the variable starts with the appropriate * prefix. Note that getting the "self" object is a weak protection against * handling of wrong vars */ NsfObject *object; nonnull_assert(interp != NULL); nonnull_assert(name != NULL); nonnull_assert(rPtr != NULL); object = GetSelfObj(interp); #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, "compiled var resolver for %s, obj %p\n", name, (void *)object); #endif if (likely(object != NULL) && FOR_COLON_RESOLVER(name)) { NsfResolvedVarInfo *resVarInfo = NEW(NsfResolvedVarInfo); resVarInfo->vInfo.fetchProc = CompiledColonVarFetch; resVarInfo->vInfo.deleteProc = CompiledColonVarFree; /* if NULL, Tcl does a ckfree on proc clean up */ resVarInfo->lastObject = NULL; resVarInfo->var = NULL; resVarInfo->nameObj = Tcl_NewStringObj(name+1, (TCL_SIZE_T)length-1); INCR_REF_COUNT(resVarInfo->nameObj); #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, "... resVarInfo %p nameObj %p '%s' obj %p %s\n", (void *)resVarInfo, (void *)resVarInfo->nameObj, ObjStr(resVarInfo->nameObj), (void *)object, ObjectName(object)); #endif *rPtr = (Tcl_ResolvedVarInfo *)resVarInfo; return TCL_OK; } return TCL_CONTINUE; } /* *---------------------------------------------------------------------- * InterpGetFrameAndFlags -- * * Return for the provided interp the flags of the frame (returned * as result) and the actual varFrame (returned in the second * argument). In case, the top-level frame is a LAMBDA frame, skip * it. * * Results: * Frame flags, varFrame. * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static int InterpGetFrameAndFlags(Tcl_Interp *interp, CallFrame **framePtr) nonnull(1) nonnull(2); NSF_INLINE static int InterpGetFrameAndFlags(Tcl_Interp *interp, CallFrame **framePtr) { int frameFlags; nonnull_assert(interp != NULL); nonnull_assert(framePtr != NULL); *framePtr = Tcl_Interp_varFramePtr(interp); frameFlags = Tcl_CallFrame_isProcCallFrame(*framePtr); /* * If the resolver is called from a lambda frame, use always the parent frame */ if ((frameFlags & FRAME_IS_LAMBDA) != 0u) { *framePtr = (CallFrame *)Tcl_CallFrame_callerPtr(*framePtr); frameFlags = Tcl_CallFrame_isProcCallFrame(*framePtr); #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, "InterpColonVarResolver skip lambda frame flags %.6x\n", Tcl_CallFrame_isProcCallFrame(*framePtr)); #endif } #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, "... final frame flags %.6x\n", frameFlags); #endif return frameFlags; } /* *---------------------------------------------------------------------- * InterpColonVarResolver -- * * For accessing object (instance) variables using the colon-prefix * notation (":/varName/"), we provide our own var resolvers. This * function is the non-compiling var resolver; its services are * requested in two situations: a) when evaluating non-compiled * statements, b) when executing slow-path bytecode instructions, * with "slow path" referring to bytecode instructions not making * use of the compiled locals array (and, e.g., reverting to * TclObjLookupVar*() calls). * * The Tcl variable resolver protocol dictates that per-namespace, * non-compiling var resolvers take precedence over this per-interp * non-compiling var resolver. That is, per-namespace resolvers are * processed first and can effectively out-rule per-interp * resolvers by signaling TCL_OK or TCL_BREAK. See * e.g. TclLookupSimpleVar(). * * Results: * TCL_OK or TCL_CONTINUE (according to on Tcl's var resolver * protocol). * * Side effects: * If successful, return varPtr, pointing to instance variable. * *---------------------------------------------------------------------- */ static int InterpColonVarResolver(Tcl_Interp *interp, const char *varName, Tcl_Namespace *UNUSED(nsPtr), int flags, Tcl_Var *varPtr) nonnull(1) nonnull(2) nonnull(5); static int InterpColonVarResolver(Tcl_Interp *interp, const char *varName, Tcl_Namespace *UNUSED(nsPtr), int flags, Tcl_Var *varPtr) { int new; unsigned int frameFlags; CallFrame *varFramePtr; TclVarHashTable *varTablePtr; NsfObject *object; Tcl_Obj *keyObj; Tcl_Var var; nonnull_assert(interp != NULL); nonnull_assert(varName != NULL); nonnull_assert(varPtr != NULL); if (!FOR_COLON_RESOLVER(varName) || (flags & (TCL_NAMESPACE_ONLY)) != 0u) { /* * Ordinary names (not starting with our prefix) and namespace only * lookups are not for us. We cannot filter for TCL_GLOBAL_ONLY, since * "vwait :varName" is called with this flag. */ #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, "InterpColonVarResolver '%s' flags %.6x not for us\n", varName, flags); #endif return TCL_CONTINUE; } frameFlags = (unsigned int)InterpGetFrameAndFlags(interp, &varFramePtr); if (likely((frameFlags & FRAME_IS_NSF_METHOD) != 0u)) { /* varPtr = CompiledLocalsLookup(varFramePtr, varName); fprintf(stderr, "CompiledLocalsLookup for %p %s returned %p\n", (void *)varFramePtr, varName, (void *)*varPtr); */ if ((*varPtr = CompiledColonLocalsLookup(varFramePtr, varName))) { /* * This section is reached under notable circumstances and represents a * point of interaction between our resolvers for non-compiled (i.e., * InterpColonVarResolver()) and compiled script execution (i.e., * InterpCompiledColonVarResolver()). * * Expect this branch to be hit iff... * * 1. ... InterpCompiledColonVarResolver() is called from within the Tcl * bytecode interpreter when executing a bytecode-compiled script on a * *slow path* (i.e., involving a TclObjLookupVarEx() call) * * 2. ... the act of variable resolution (i.e., TclObjLookupVarEx()) has * not been restricted to an effective namespace (TCL_NAMESPACE_ONLY) * * 3. ..., resulting from the fact of participating in a bytecode * interpretation, CompiledColonVarFetch() stored a link variable * (pointing to the actual/real object variable, whether defined or not) * under the given varName value into the current call frame's array of * compiled locals (when initializing the call frame; see * tclProc.c:InitResolvedLocals()). */ #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, ".... found local %s varPtr %p flags %.6x\n", varName, (void *)*varPtr, flags); #endif /* * By looking up the compiled-local directly and signaling TCL_OK, we * optimize a little by avoiding further lookups down the Tcl var * resolution infrastructure. Note that signaling TCL_CONTINUE would * work too, however, it would involve extra resolution overhead. */ return TCL_OK; } object = ((NsfCallStackContent *)varFramePtr->clientData)->self; } else if ((frameFlags & FRAME_IS_NSF_CMETHOD) != 0u) { object = ((NsfCallStackContent *)varFramePtr->clientData)->self; } else if ((frameFlags & FRAME_IS_NSF_OBJECT) != 0u) { object = (NsfObject *)(varFramePtr->clientData); } else { #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, ".... not found %s\n", varName); #endif return TCL_CONTINUE; } /* * Trim the varName for the colon prefix (":"). */ varName ++; /* * We have an object and create the variable if not found */ assert(object != NULL); if (unlikely(object->nsPtr != NULL)) { varTablePtr = Tcl_Namespace_varTablePtr(object->nsPtr); } else if (likely(object->varTablePtr != NULL)) { varTablePtr = object->varTablePtr; } else { /* * In most situations, we have a varTablePtr through the clauses * above. However, if someone redefines e.g. the method "configure" or * "objectparameter", we might find an object with a still empty * varTable, since these are lazy initiated. */ varTablePtr = object->varTablePtr = VarHashTableCreate(); } assert(varTablePtr != NULL); /*fprintf(stderr, "Object Var Resolver, name=%s, obj %p, nsPtr %p, varTablePtr %p\n", varName, (void *)object, (void *)object->nsPtr, (void *)varTablePtr);*/ keyObj = Tcl_NewStringObj(varName, TCL_INDEX_NONE); INCR_REF_COUNT(keyObj); var = (Tcl_Var)VarHashCreateVar(varTablePtr, keyObj, NULL); if (likely(var != NULL)) { #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, ".... found in hash-table %s %p flags %.6x ns %p\n", varName, (void *)var, ((Var *)var)->flags, (void *)object->nsPtr); #endif /* * Make coverage analysis easier. */ assert(1); } else { /* * We failed to find the variable, therefore, we create it new */ var = (Tcl_Var)VarHashCreateVar(varTablePtr, keyObj, &new); #if defined(VAR_RESOLVER_TRACE) fprintf(stderr, ".... var %p %s created in hash-table %p\n", (void *)var, varName, (void *)varTablePtr); #endif } *varPtr = var; DECR_REF_COUNT(keyObj); return TCL_OK; } /********************************************************* * * End of var resolvers * *********************************************************/ /********************************************************* * * Begin of cmd resolver * *********************************************************/ /* *---------------------------------------------------------------------- * InterpColonCmdResolver -- * * Resolve command names. If the command starts with the Next * Scripting specific prefix and we are on a Next Scripting stack * frame, treat command as OO method. * * Results: * TCL_OK or TCL_CONTINUE (based on Tcl's command resolver protocol) * * Side effects: * If successful, return cmdPtr, pointing to method. * *---------------------------------------------------------------------- */ static int InterpColonCmdResolver(Tcl_Interp *interp, const char *cmdName, Tcl_Namespace *UNUSED(nsPtr), unsigned int flags, Tcl_Command *cmdPtr) nonnull(1) nonnull(2) nonnull(5); static int InterpColonCmdResolver(Tcl_Interp *interp, const char *cmdName, Tcl_Namespace *UNUSED(nsPtr), unsigned int flags, Tcl_Command *cmdPtr) { CallFrame *varFramePtr; unsigned int frameFlags; nonnull_assert(interp != NULL); nonnull_assert(cmdName != NULL); nonnull_assert(cmdPtr != NULL); /* fprintf(stderr, "InterpColonCmdResolver %s flags %.6x\n", cmdName, flags); */ if (likely((*cmdName == ':' && *(cmdName + 1) == ':') || (flags & TCL_GLOBAL_ONLY) != 0u)) { /* fully qualified names and global lookups are not for us */ /*fprintf(stderr, "... not for us %s flags %.6x\n", cmdName, flags);*/ return TCL_CONTINUE; } frameFlags = (unsigned int)InterpGetFrameAndFlags(interp, &varFramePtr); /* * The resolver is called as well, when a body of a method is * compiled. In these situations, Tcl stacks a non-proc frame, that * we have to skip. In order to safely identify such situations, we * stuff into the call flags of the proc frame during the * compilation step NSF_CSC_CALL_IS_COMPILE. */ if ((frameFlags == 0u) && (Tcl_CallFrame_callerPtr(varFramePtr) != NULL)) { ClientData clientData; varFramePtr = (CallFrame *)Tcl_CallFrame_callerPtr(varFramePtr); frameFlags = (unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr); clientData = varFramePtr->clientData; if ( (frameFlags != 0u) && (clientData != NULL) && ((((NsfCallStackContent *)clientData)->flags & NSF_CSC_CALL_IS_COMPILE) == 0u) ) { frameFlags = 0u; } else { #if defined(CMD_RESOLVER_TRACE) fprintf(stderr, "InterpColonCmdResolver got parent frame cmdName %s flags %.6x, frame flags %.6x\n", cmdName, flags, Tcl_CallFrame_isProcCallFrame(varFramePtr)); #endif } } #if defined(CMD_RESOLVER_TRACE) fprintf(stderr, "InterpColonCmdResolver cmdName %s flags %.6x, frame flags %.6x\n", cmdName, flags, frameFlags); #endif if ((frameFlags & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_OBJECT|FRAME_IS_NSF_CMETHOD)) != 0u) { if (*cmdName == ':') { #if defined(CMD_RESOLVER_TRACE) fprintf(stderr, " ... call colonCmd for %s\n", cmdName); #endif /* * We have a cmd starting with ':', we are in an NSF frame, so * forward to the colonCmd. */ *cmdPtr = RUNTIME_STATE(interp)->colonCmd; return TCL_OK; } else { #if defined(NSF_WITH_OS_RESOLVER) /* * Experimental Object-System specific resolver: If an un-prefixed * method name is found in a body of a method, we try to perform a * lookup for this method in the namespace of the object system for the * current object. If this lookup is not successful the standard lookups * are performed. The object-system specific resolver allows one to use * the "right" (un-prefixed) "self" or "next" calls without namespace * imports. */ NsfObject *object; NsfObjectSystem *osPtr; if ((frameFlags & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) != 0u) { const NsfCallStackContent *cscPtr = (NsfCallStackContent *)varFramePtr->clientData; assert(cscPtr != NULL); object = cscPtr->self; } else if ((frameFlags & (FRAME_IS_NSF_OBJECT)) != 0u) { object = (NsfObject *)(varFramePtr->clientData); } else { object = NULL; } if (object != NULL) { Tcl_HashEntry *entryPtr; Tcl_HashTable *cmdTablePtr; Tcl_Command cmd; osPtr = GetObjectSystem(object); cmd = osPtr->rootClass->object.id; cmdTablePtr = Tcl_Namespace_cmdTablePtr(((Command *)cmd)->nsPtr); entryPtr = Tcl_CreateHashEntry(cmdTablePtr, cmdName, NULL); /*fprintf(stderr, "InterpColonCmdResolver OS specific resolver tried to lookup %s for os %s in ns %s\n", cmdName, ClassName(osPtr->rootClass), ((Command *)cmd)->nsPtr->fullName);*/ if (entryPtr != NULL) { /*fprintf(stderr, "InterpColonCmdResolver OS specific resolver found %s::%s frameFlags %.6x\n", ((Command *)cmd)->nsPtr->fullName, cmdName, frameFlags);*/ *cmdPtr = Tcl_GetHashValue(entryPtr); return TCL_OK; } } #endif } } #if defined(CMD_RESOLVER_TRACE) fprintf(stderr, " ... not found %s\n", cmdName); NsfShowStack(interp); #endif return TCL_CONTINUE; } /********************************************************* * * End of cmd resolver * *********************************************************/ /* *---------------------------------------------------------------------- * NsfNamespaceInit -- * * Initialize a provided namespace by setting its resolvers and * namespace path * * Results: * None. * * Side effects: * Change behavior of NSF resolving. * *---------------------------------------------------------------------- */ static void NsfNamespaceInit(Tcl_Namespace *nsPtr) nonnull(1); static void NsfNamespaceInit(Tcl_Namespace *nsPtr) { nonnull_assert(nsPtr != NULL); /* * This puts a per-object namespace resolver into position upon * acquiring the namespace. Works for object-scoped commands/procs * and object-only ones (set, unset, ...) */ Tcl_SetNamespaceResolvers(nsPtr, (Tcl_ResolveCmdProc *)NULL, NsColonVarResolver, (Tcl_ResolveCompiledVarProc *)NULL); #if defined(NSF_WITH_INHERIT_NAMESPACES) /* * In case there is a namespace path set for the parent namespace, * apply this as well to the object namespace to avoid surprises * with "namespace path nx". */ { Namespace *parentNsPtr = Tcl_Namespace_parentPtr(nsPtr); int pathLength = Tcl_Namespace_commandPathLength(parentNsPtr); if (pathLength > 0) { Namespace **pathArray = (Namespace **)ckalloc((int)sizeof(Namespace *) * pathLength); NamespacePathEntry *tmpPathArray = Tcl_Namespace_commandPathArray(parentNsPtr); int i; for (i = 0; i < pathLength; i++) { pathArray[i] = tmpPathArray[i].nsPtr; } TclSetNsPath((Namespace *)nsPtr, pathLength, (Tcl_Namespace **)pathArray); ckfree((char *)pathArray); } } #endif } static NsfObject *NSNamespaceClientDataObject(ClientData clientData) nonnull(1) NSF_pure; static NsfObject * NSNamespaceClientDataObject(ClientData clientData) { #ifdef NSF_MEM_COUNT NsfNamespaceClientData *nsClientData = (NsfNamespaceClientData *)clientData; nonnull_assert(clientData != NULL); /*fprintf(stderr, "NSNamespaceDeleteProc cd %p\n", (void *)clientData); fprintf(stderr, "... nsPtr %p name '%s'\n", (void *)nsClientData->nsPtr, nsClientData->nsPtr->fullName);*/ return nsClientData->object; #else nonnull_assert(clientData != NULL); return (NsfObject *) clientData; #endif } /* *---------------------------------------------------------------------- * SlotContainerCmdResolver -- * * This is a specialized cmd resolver for slotcontainer. The * command resolver should be registered for a namespace and avoids * the lookup of childobjs for unqualified calls. This way, it is * e.g. possible to call in a slot-obj a method [list], even in * cases, where a property "list" is defined. * * Results: * Either TCL_CONTINUE or TCL_OK. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int SlotContainerCmdResolver(Tcl_Interp *interp, const char *cmdName, Tcl_Namespace *nsPtr, unsigned int flags, Tcl_Command *cmdPtr) nonnull(1) nonnull(2) nonnull(3) nonnull(5); static int SlotContainerCmdResolver(Tcl_Interp *interp, const char *cmdName, Tcl_Namespace *nsPtr, unsigned int flags, Tcl_Command *cmdPtr) { nonnull_assert(cmdName != NULL); nonnull_assert(nsPtr != NULL); nonnull_assert(cmdPtr != NULL); if (*cmdName == ':' || ((flags & TCL_GLOBAL_ONLY) != 0u)) { /* * Colon names (InterpColonCmdResolver) and global lookups are not for us. */ return TCL_CONTINUE; } /*fprintf(stderr, "SlotContainerCmdResolver called with %s ns %s ourNs %d clientData %p\n", cmdName, nsPtr->fullName, nsPtr->deleteProc == NSNamespaceDeleteProc, (void *)nsPtr->clientData);*/ /* * Check whether this already a namespace handled by NSF */ if (nsPtr->deleteProc == NSNamespaceDeleteProc && nsPtr->clientData) { NsfObject *parentObject = NSNamespaceClientDataObject(nsPtr->clientData); /*fprintf(stderr, "SlotContainerCmdResolver parentObject %p %s\n", (void *)parentObject, ObjectName(parentObject));*/ /* * Make global lookups when the parent is a slotcontainer */ /* parentObject = (NsfObject *) GetObjectFromString(interp, nsPtr->fullName);*/ if ((parentObject->flags & NSF_IS_SLOT_CONTAINER) != 0u) { Tcl_Command cmd = Tcl_FindCommand(interp, cmdName, NULL, TCL_GLOBAL_ONLY); if (likely(cmd != NULL)) { *cmdPtr = cmd; return TCL_OK; } } } return TCL_CONTINUE; } /* *---------------------------------------------------------------------- * RequireObjNamespace -- * * Obtain for an object a namespace if necessary and initialize it. * In this function, variables existing outside of the namespace * get copied over to the fresh namespace. * * Results: * Tcl_Namespace * * Side effects: * Allocate potentially a Tcl_Namespace * *---------------------------------------------------------------------- */ static Tcl_Namespace * RequireObjNamespace(Tcl_Interp *interp, NsfObject *object) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); if (object->nsPtr == NULL) { MakeObjNamespace(interp, object); NsfNamespaceInit(object->nsPtr); } assert(object->nsPtr != NULL); return object->nsPtr; } /* * Namespace related commands */ /* *---------------------------------------------------------------------- * NSNamespacePreserve -- * * Increment namespace refCount * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void NSNamespacePreserve(Tcl_Namespace *nsPtr) { nonnull_assert(nsPtr != NULL); MEM_COUNT_ALLOC("NSNamespace", nsPtr); Tcl_Namespace_refCount(nsPtr)++; } /* *---------------------------------------------------------------------- * NSNamespaceRelease -- * * Decrement namespace's "refCount" and free namespace if * necessary. * * Results: * None. * * Side effects: * Free potentially memory. * *---------------------------------------------------------------------- */ static void NSNamespaceRelease(Tcl_Namespace *nsPtr) { nonnull_assert(nsPtr != NULL); MEM_COUNT_FREE("NSNamespace", nsPtr); Tcl_Namespace_refCount(nsPtr)--; if (unlikely(Tcl_Namespace_refCount(nsPtr) == 0 && (Tcl_Namespace_flags(nsPtr) & NS_DEAD))) { /* * The namespace "refCount" has reached 0, we have to free * it. Unfortunately, NamespaceFree() is not exported. */ /*fprintf(stderr, "HAVE TO FREE namespace %p\n", (void *)nsPtr); */ /*NamespaceFree(nsPtr);*/ ckfree(nsPtr->fullName); ckfree(nsPtr->name); ckfree((char *)nsPtr); } } /* *---------------------------------------------------------------------- * NSDeleteCmd -- * * Delete the Tcl command for the provided methodName located in * the provided namespace. * * Results: * Tcl result or -1, if no such method exists int. * * Side effects: * Command is deleted. * *---------------------------------------------------------------------- */ static int NSDeleteCmd(Tcl_Interp *interp, Tcl_Namespace *nsPtr, const char *methodName) { Tcl_Command token; nonnull_assert(interp != NULL); nonnull_assert(nsPtr != NULL); nonnull_assert(methodName != NULL); if ((token = FindMethod(nsPtr, methodName))) { return Tcl_DeleteCommandFromToken(interp, token); } return -1; } /* *---------------------------------------------------------------------- * NSDeleteChild -- * * Delete a child of an object in cases, when the parent object is * deleted. It is designed to delete either objects or classes to * be a little bit more graceful on destructors. Not perfect yet. * * Results: * Boolean value indicating success. * * Side effects: * Might destroy an object. * *---------------------------------------------------------------------- */ static bool NSDeleteChild(Tcl_Interp *interp, Tcl_Command cmd, bool deleteObjectsOnly) nonnull(1) nonnull(2); static bool NSDeleteChild(Tcl_Interp *interp, Tcl_Command cmd, bool deleteObjectsOnly) { bool deleted; nonnull_assert(cmd != NULL); nonnull_assert(interp != NULL); /*fprintf(stderr, "NSDeleteChildren child %p flags %.6x epoch %d\n", (void *)cmd, Tcl_Command_flags(cmd), Tcl_Command_cmdEpoch(cmd));*/ /* * In some situations (e.g. small buckets, less than 12 entries), we * get from the cmd-table already deleted cmds; we had previously an * assert(Tcl_Command_cmdEpoch(cmd) == 0); * which will fail in such cases. */ if (Tcl_Command_cmdEpoch(cmd) != 0) { deleted = NSF_FALSE; } else { NsfObject *object = NsfGetObjectFromCmdPtr(cmd); /*fprintf(stderr, "NSDeleteChildren child %p (%s) epoch %d\n", (void *)cmd, Tcl_GetCommandName(interp, cmd), Tcl_Command_cmdEpoch(cmd));*/ if (object == NULL) { /* * This is just a plain Tcl command; let Tcl handle the * deletion. */ deleted = NSF_FALSE; } else if (object->id == cmd) { /* * delete here just true children */ if (deleteObjectsOnly && NsfObjectIsClass(object)) { deleted = NSF_FALSE; } else if (RUNTIME_STATE(interp)->exitHandlerDestroyRound == NSF_EXITHANDLER_ON_PHYSICAL_DESTROY) { /* * in the exit handler physical destroy --> directly call destroy */ PrimitiveDestroy(object); deleted = NSF_TRUE; } else { if (object->teardown && ((object->flags & NSF_DESTROY_CALLED) == 0u)) { int result; NsfObjectRefCountIncr(object); result = DispatchDestroyMethod(interp, object, 0u); if (unlikely(result != TCL_OK) && object->teardown != NULL) { /* * The destroy method failed. However, we have to remove * the command anyway, since its parent is currently being * deleted. */ /*fprintf(stderr, "==== NSDeleteChild DispatchDestroyMethod FAILED object %p (cmd %p) id %p teardown %p flags %.6x\n", (void *)object, (void *)cmd, (void *)object->id, (void *)object->teardown, object->flags);*/ NsfLog(interp, NSF_LOG_NOTICE, "Destroy failed for object %s %p %.6x, perform low-level deletion", (object->flags & NSF_DURING_DELETE) == NSF_DURING_DELETE ? "deleted-object" : ObjectName_(object), (void*)object, object->flags); CallStackDestroyObject(interp, object); } NsfCleanupObject(object, "NSDeleteChild"); deleted = NSF_TRUE; } else { deleted = NSF_FALSE; } } } else { /*fprintf(stderr, "NSDeleteChild remove alias %p %s\n", (void*)object, Tcl_GetCommandName(interp, cmd));*/ deleted = AliasDeleteObjectReference(interp, cmd); } } return deleted; } /* *---------------------------------------------------------------------- * NSDeleteChildren -- * * Delete the child objects of a namespace. * * Results: * None. * * Side effects: * Might destroy child objects. * *---------------------------------------------------------------------- */ static void NSDeleteChildren(Tcl_Interp *interp, const Tcl_Namespace *nsPtr) nonnull(1) nonnull(2); static void NSDeleteChildren(Tcl_Interp *interp, const Tcl_Namespace *nsPtr) { Tcl_HashTable *cmdTablePtr = Tcl_Namespace_cmdTablePtr(nsPtr); Tcl_HashSearch hSrch; const Tcl_HashEntry *hPtr; TCL_SIZE_T expected; nonnull_assert(interp != NULL); nonnull_assert(nsPtr != NULL); #ifdef OBJDELETION_TRACE fprintf(stderr, "NSDeleteChildren %p %s activationCount %d\n", (void *)nsPtr, nsPtr->fullName, Tcl_Namespace_activationCount(nsPtr)); #endif /* * First, get rid of namespace imported objects; don't delete the * object, but the reference. */ Tcl_ForgetImport(interp, (Tcl_Namespace*)nsPtr, "*"); /* don't destroy namespace imported objects */ #if defined(OBJDELETION_TRACE) /* * Deletion is always tricky. Show, what elements should be deleted * in this loop. The actually deleted elements might be actually * less, if a deletion of one item triggers the destroy of another * item. */ for (hPtr = Tcl_FirstHashEntry(cmdTablePtr, &hSrch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { Tcl_Command cmd = (Tcl_Command)Tcl_GetHashValue(hPtr); fprintf(stderr, "will destroy %p %s\n", (void *)cmd, Tcl_GetCommandName(interp, cmd)); } #endif /* * Second, delete the objects. */ /* * A destroy of one element of the hash-table can trigger the * destroy of another item of the same table. Therefore, we use * Nsf_NextHashEntry(), which handles this case. */ for (hPtr = Tcl_FirstHashEntry(cmdTablePtr, &hSrch); hPtr != NULL; hPtr = Nsf_NextHashEntry(cmdTablePtr, expected, &hSrch)) { /*Tcl_Command cmd = (Tcl_Command)Tcl_GetHashValue(hPtr); fprintf(stderr, "NSDeleteChild %p table %p numEntries before %d\n", cmd, hPtr->tablePtr, cmdTablePtr->numEntries );*/ expected = (NSDeleteChild(interp, (Tcl_Command)Tcl_GetHashValue(hPtr), NSF_TRUE) ? cmdTablePtr->numEntries - 1 : cmdTablePtr->numEntries); } /* * Finally, delete the classes. */ for (hPtr = Tcl_FirstHashEntry(cmdTablePtr, &hSrch); hPtr != NULL; hPtr = Nsf_NextHashEntry(cmdTablePtr, expected, &hSrch)) { expected = (NSDeleteChild(interp, (Tcl_Command)Tcl_GetHashValue(hPtr), NSF_FALSE) ? cmdTablePtr->numEntries - 1 : cmdTablePtr->numEntries); } } /* *---------------------------------------------------------------------- * UnsetTracedVars -- * * This is a helper function which, as a first pass, attempts to * unset traced object variables before TclDeleteVars() performs a * second pass. This two-pass deletion of object variables is * necessary because an unset trace might bring back the object * variable currently being deleted. A single pass risks leaking * so-revived Var structures. TclDeleteVars() requires variables * under deletion to be untraced. * * As Tcl does not provide access to the necessary lower-level Var * API to extensions (ideally: TclDeleteNamespaceVars or * TclPtrUnsetVar), we resort to a mix of navigating the variable * table and calling high-level unset operations (UnsetInstVar). * * With the fix to ticket * https://core.tcl-lang.org/tcl/info/4dbdd9af144dbdd9af14, Tcl * itself provides for two deletion passes for namespace variables * (see TclDeleteNamespaceVars). * * Results: * None. * * Side effects: * Triggers the unset traces, if any. * *---------------------------------------------------------------------- */ static void UnsetTracedVars(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); static void UnsetTracedVars( Tcl_Interp *interp, /* Interpreter to which object belongs. */ NsfObject *object) /* Object to which variables belong. */ { Tcl_HashSearch search; TclVarHashTable *varTablePtr; Interp *iPtr = (Interp *)interp; varTablePtr = (object->nsPtr != NULL) ? Tcl_Namespace_varTablePtr(object->nsPtr) : object->varTablePtr; if (varTablePtr != NULL) { Tcl_HashEntry *entryPtr; for (entryPtr = Tcl_FirstHashEntry((Tcl_HashTable *)varTablePtr, &search); entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { Tcl_Obj *nameObj; Var *varPtr; GetVarAndNameFromHash(entryPtr, &varPtr, &nameObj); if ((varPtr->flags & VAR_TRACED_UNSET) != 0u /* TclIsVarTraced(varPtr) */) { VarHashRefCount(varPtr)++; (void)UnsetInstVar(interp, 1 /* no error msg */, object, ObjStr(nameObj)); /* * The variable might have been brought back by an unset trace, plus * newly created unset traces; deactivate *all* traces on revived * vars. */ if (TclIsVarTraced(varPtr)) { Tcl_HashEntry *tPtr = Tcl_FindHashEntry(&iPtr->varTraces, (const char *)varPtr); VarTrace *tracePtr = Tcl_GetHashValue(tPtr); ActiveVarTrace *activePtr; while (tracePtr != NULL) { VarTrace *prevPtr = tracePtr; tracePtr = tracePtr->nextPtr; prevPtr->nextPtr = NULL; Tcl_EventuallyFree(prevPtr, TCL_DYNAMIC); } Tcl_DeleteHashEntry(tPtr); varPtr->flags &= ~VAR_ALL_TRACES; for (activePtr = iPtr->activeVarTracePtr; activePtr != NULL; activePtr = activePtr->nextPtr) { if (activePtr->varPtr == varPtr) { activePtr->nextTracePtr = NULL; } } } VarHashRefCount(varPtr)--; } } } } /* *---------------------------------------------------------------------- * NSCleanupNamespace -- * * Cleans up an object or class namespace by deleting 1) its * variables, 2) resetting the var table, and 3) deleting * user-defined namespace procs. * * For namespaces holding variables with possible unset traces, * make sure that UnsetTracedVars is called just before * NSCleanupNamespace(). * * Results: * None. * * Side effects: * Re-initializes the variable table of the cleaned-up namespace * (TclInitVarHashTable). * *---------------------------------------------------------------------- */ static void NSCleanupNamespace(Tcl_Interp *interp, Tcl_Namespace *nsPtr) nonnull(1) nonnull(2); static void NSCleanupNamespace(Tcl_Interp *interp, Tcl_Namespace *nsPtr) { TclVarHashTable *varTablePtr; Tcl_HashTable *cmdTablePtr; Tcl_HashSearch hSrch; const Tcl_HashEntry *hPtr; nonnull_assert(interp != NULL); nonnull_assert(nsPtr != NULL); varTablePtr = Tcl_Namespace_varTablePtr(nsPtr); cmdTablePtr = Tcl_Namespace_cmdTablePtr(nsPtr); #ifdef OBJDELETION_TRACE fprintf(stderr, "NSCleanupNamespace %p flags %.6x\n", (void *)nsPtr, Tcl_Namespace_flags(nsPtr)); fprintf(stderr, "NSCleanupNamespace %p %.6x varTablePtr %p\n", (void *)nsPtr, ((Namespace *)nsPtr)->flags, (void *)varTablePtr); #endif /* * Delete all variables and initialize var table again (TclDeleteVars frees * the var table). Any unset-traced variable has been deleted before * (UnsetTracedVars). */ TclDeleteVars((Interp *)interp, varTablePtr); TclInitVarHashTable(varTablePtr, (Namespace *)nsPtr); /* * Delete all user-defined procs in the namespace */ for (hPtr = Tcl_FirstHashEntry(cmdTablePtr, &hSrch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { Tcl_Command cmd = (Tcl_Command) Tcl_GetHashValue(hPtr); if (CmdIsNsfObject(cmd)) { /* * Sub-objects should not be deleted here to preserve children * deletion order. Just delete aliases. */ AliasDeleteObjectReference(interp, cmd); continue; } /*fprintf(stderr, "NSCleanupNamespace calls DeleteCommandFromToken for %p flags %.6x\n", cmd, ((Command *)cmd)->flags); fprintf(stderr, " cmd = %s\n", Tcl_GetCommandName(interp, cmd)); fprintf(stderr, " nsPtr = %p\n", ((Command *)cmd)->nsPtr); fprintf(stderr, " epoch = %d\n", Tcl_Command_cmdEpoch(cmd)); fprintf(stderr, " refCount = %d\n", Tcl_Command_refCount(cmd)); fprintf(stderr, " flags %.6x\n", ((Namespace *)((Command *)cmd)->nsPtr)->flags);*/ Tcl_DeleteCommandFromToken(interp, cmd); } } static void NSNamespaceDeleteProc(ClientData clientData) { NsfObject *object; nonnull_assert(clientData != NULL); object = NSNamespaceClientDataObject(clientData); assert(object != NULL); #ifdef NSF_MEM_COUNT ckfree((char *)clientData); #endif /*fprintf(stderr, "namespace delete-proc obj=%p ns=%p\n", clientData, (object != NULL) ? object->nsPtr : NULL);*/ MEM_COUNT_FREE("NSNamespace", object->nsPtr); object->nsPtr = NULL; } void Nsf_DeleteNamespace(Tcl_Interp *interp, Tcl_Namespace *nsPtr) nonnull(1) nonnull(2); void Nsf_DeleteNamespace(Tcl_Interp *interp, Tcl_Namespace *nsPtr) { #if defined(NSF_DEVELOPMENT_TEST) int activationCount = 0; Tcl_CallFrame *f = (Tcl_CallFrame *)Tcl_Interp_framePtr(interp); nonnull_assert(interp != NULL); nonnull_assert(nsPtr != NULL); /*fprintf(stderr, "Nsf_DeleteNamespace %p ", nsPtr);*/ while (f != NULL) { if (f->nsPtr == nsPtr) { activationCount++; } f = Tcl_CallFrame_callerPtr(f); } if (Tcl_Namespace_activationCount(nsPtr) != activationCount) { fprintf(stderr, "WE HAVE TO FIX ACTIVATIONCOUNT\n"); Tcl_Namespace_activationCount(nsPtr) = activationCount; } assert(Tcl_Namespace_activationCount(nsPtr) == activationCount); /*fprintf(stderr, "to %d. \n", ((Namespace *)nsPtr)->activationCount);*/ #else (void)interp; #endif if (Tcl_Namespace_deleteProc(nsPtr)) { /*fprintf(stderr, "calling deteteNamespace %s\n", nsPtr->fullName);*/ Tcl_DeleteNamespace(nsPtr); } } /* *---------------------------------------------------------------------- * NSValidObjectName -- * * Check the provided colons in an object name. If the name is * valid, the function NSF_TRUE. * * Results: * Returns boolean value indicating success. * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static bool NSValidObjectName(const char *name, size_t l) nonnull(1) NSF_pure; NSF_INLINE static bool NSValidObjectName(const char *name, size_t l) { register const char *n; bool result = NSF_TRUE; nonnull_assert(name != NULL); n = name; if (*n == '\0') { result = NSF_FALSE; /* empty name */ } else { /* * Compute size if not given. */ if (l == 0) { l = strlen(n); } /* * Check string */ if (*(n+l-1) == ':') { result = NSF_FALSE; /* name ends with : */ } else if (*n == ':' && *(n+1) != ':') { result = NSF_FALSE; /* name begins with single : */ } else { for (; *n != '\0'; n++) { if (*n == ':' && *(n+1) == ':' && *(n+2) == ':') { result = NSF_FALSE; /* more than 2 colons in series in a name */ break; } } } } return result; } /* *---------------------------------------------------------------------- * NSGetFreshNamespace -- * * Create an object namespace, provide a deleteProc (avoid * interference between object and namespace deletion order) and * keep the object as client data. * * Results: * Tcl_Namespace * * Side effects: * Might allocate a namespace. * *---------------------------------------------------------------------- */ static Tcl_Namespace* NSGetFreshNamespace(Tcl_Interp *interp, NsfObject *object, const char *name) { Namespace *dummy1Ptr, *dummy2Ptr, *nsPtr; const char *dummy; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(name != NULL); TclGetNamespaceForQualName(interp, name, NULL, TCL_FIND_ONLY_NS|TCL_CREATE_NS_IF_UNKNOWN, &nsPtr, &dummy1Ptr, &dummy2Ptr, &dummy); if (nsPtr->deleteProc != NSNamespaceDeleteProc) { /* * Avoid hijacking a namespace with different client data */ if (nsPtr->deleteProc || nsPtr->clientData) { Tcl_Panic("Namespace '%s' exists already with delProc 0x%" PRIxPTR " and clientData %p; " "Can only convert a plain Tcl namespace into an NSF namespace, my delete proc 0x%" PRIxPTR, name, (unsigned long)PTR2UINT(nsPtr->deleteProc), nsPtr->clientData, (unsigned long)PTR2UINT(NSNamespaceDeleteProc)); } { #ifdef NSF_MEM_COUNT NsfNamespaceClientData *nsClientData = (NsfNamespaceClientData *)ckalloc((int)sizeof(NsfNamespaceClientData)); nsClientData->object = object; nsClientData->nsPtr = (Tcl_Namespace *)nsPtr; nsPtr->clientData = nsClientData; /*fprintf(stderr, "Adding NsfNamespaceClientData nsPtr %p cd %p name '%s'\n", nsPtr, nsClientData, nsPtr->fullName);*/ #else nsPtr->clientData = object; #endif nsPtr->deleteProc = (Tcl_NamespaceDeleteProc *)NSNamespaceDeleteProc; } MEM_COUNT_ALLOC("NSNamespace", nsPtr); } else { fprintf(stderr, "NSGetFreshNamespace: reusing namespace %p %s\n", (void *)nsPtr, nsPtr->fullName); } return (Tcl_Namespace *)nsPtr; } /* *---------------------------------------------------------------------- * NSRequireParentObject -- * * Try to require a parent object (e.g. during ttrace). This function * tries to load a parent object via ::nsf::object::unknown. * * Results: * A standard Tcl result. * * Side effects: * Might create an object. * *---------------------------------------------------------------------- */ static int NSRequireParentObject(Tcl_Interp *interp, const char *parentName) nonnull(1) nonnull(2); static int NSRequireParentObject(Tcl_Interp *interp, const char *parentName) { int result; nonnull_assert(interp != NULL); nonnull_assert(parentName != NULL); result = NsfCallObjectUnknownHandler(interp, Tcl_NewStringObj(parentName, TCL_INDEX_NONE)); if (likely(result == TCL_OK)) { NsfObject *parentObj = (NsfObject *)GetObjectFromString(interp, parentName); if (parentObj != NULL) { RequireObjNamespace(interp, parentObj); } result = (Tcl_FindNamespace(interp, parentName, (Tcl_Namespace *) NULL, TCL_GLOBAL_ONLY) != NULL ? TCL_OK: TCL_ERROR); } return result; } /* *---------------------------------------------------------------------- * NSCheckNamespace -- * * Check whether a namespace with the given name exists. If not, * make sure that a potential parent object has already required a * namespace. If there is no parent namespace yet, try to create a * parent object via __unknown. * * If the provided parentNsPtr is not NULL, we know, that (a) the * provided name was relative and simple (contains no ":" * characters) and that (b) this namespace was used to build a * fully qualified name. In these cases, the parentNsPtr points * already to the parentName, containing potentially a parent * Object. In all other cases, the parent name is either obtained * from the full namespace, or from string operations working on * the provided name. * * Results: * Tcl_Namespace for the provided name. * * Side effects: * Might create parent objects. * *---------------------------------------------------------------------- */ NSF_INLINE static Tcl_Namespace *NSCheckNamespace( Tcl_Interp *interp, const char *nameString, Tcl_Namespace *parentNsPtr1 ) nonnull(1) nonnull(2); NSF_INLINE static Tcl_Namespace * NSCheckNamespace( Tcl_Interp *interp, const char *nameString, Tcl_Namespace *parentNsPtr1 ) { Namespace *nsPtr, *dummy1Ptr, *dummy2Ptr, *parentNsPtr = (Namespace *)parentNsPtr1; const char *parentName, *dummy; Tcl_DString ds, *dsPtr = &ds; nonnull_assert(interp != NULL); nonnull_assert(nameString != NULL); /*fprintf(stderr, "NSCheckNamespace %s parentNsPtr %p\n", nameString, parentNsPtr);*/ /* * Check whether there is an already a namespace for the full name. The * namespace will be only in rare cases, but we have to make this check in * every case. If there is a full namespace, we can use it to determine the * parent name. */ TclGetNamespaceForQualName(interp, nameString, NULL, TCL_GLOBAL_ONLY|TCL_FIND_ONLY_NS, &nsPtr, &dummy1Ptr, &dummy2Ptr, &dummy); /*fprintf(stderr, "before create calls TclGetNamespaceForQualName with %s => %p (%s) %p %s %p %s %p %s\n", nameString, nsPtr, (nsPtr != NULL) ? nsPtr->fullName : "", dummy1Ptr, (dummy1Ptr != NULL) ? dummy1Ptr->fullName : "", parentNsPtr, (parentNsPtr != NULL) ? parentNsPtr->fullName : "", dummy, (dummy != NULL) ? dummy : "");*/ /* * If there is a parentNs provided (or obtained from the full * namespace), we can determine the parent name from it. Otherwise, * we have to perform the string operations. */ if (parentNsPtr == NULL && nsPtr != NULL) { parentNsPtr = Tcl_Namespace_parentPtr(nsPtr); } if (parentNsPtr != NULL) { parentName = parentNsPtr->fullName; if (*(parentName + 2) == '\0') { parentName = NULL; } /*fprintf(stderr, "NSCheckNamespace parentNs %s parentName of '%s' => '%s'\n", parentNsPtr->fullName, nameString, parentName);*/ } else { TCL_SIZE_T parentNameLength; const char *n = nameString + strlen(nameString); /* * search for last '::' */ while ((*n != ':' || *(n-1) != ':') && n-1 > nameString) { n--; } if (*n == ':' && n > nameString && *(n-1) == ':') { n--; } parentNameLength = (TCL_SIZE_T)(n - nameString); if (parentNameLength > 0) { DSTRING_INIT(dsPtr); Tcl_DStringAppend(dsPtr, nameString, parentNameLength); parentName = Tcl_DStringValue(dsPtr); DSTRING_FREE(dsPtr); } else { parentName = NULL; } } if (parentName != NULL) { NsfObject *parentObj; parentObj = (NsfObject *) GetObjectFromString(interp, parentName); /*fprintf(stderr, "parentName %s parentObj %p\n", parentName, parentObj);*/ if (parentObj != NULL) { RequireObjNamespace(interp, parentObj); } else if (nsPtr == NULL && parentNsPtr == NULL) { TclGetNamespaceForQualName(interp, parentName, NULL, TCL_GLOBAL_ONLY|TCL_FIND_ONLY_NS, &parentNsPtr, &dummy1Ptr, &dummy2Ptr, &dummy); if (parentNsPtr == NULL) { /*fprintf(stderr, "===== calling NSRequireParentObject %s", parentName);*/ NSRequireParentObject(interp, parentName); } } } return (Tcl_Namespace *)nsPtr; } /* *---------------------------------------------------------------------- * NSFindCommand -- * * Find the "real" command belonging e.g. to a Next Scripting class * or object. Do not return cmds produced by Tcl_Import, but the * "real" cmd to which they point. * * Results: * Tcl_Command or NULL * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static Tcl_Command NSFindCommand(Tcl_Interp *interp, const char *name) nonnull(1) nonnull(2); NSF_INLINE static Tcl_Command NSFindCommand(Tcl_Interp *interp, const char *name) { Tcl_Command cmd; nonnull_assert(interp != NULL); nonnull_assert(name != NULL); assert(*name == ':' && *(name + 1) == ':'); cmd = Tcl_FindCommand(interp, name, NULL, TCL_GLOBAL_ONLY); if (likely(cmd != NULL)) { Tcl_Command importedCmd = TclGetOriginalCommand(cmd); if (unlikely(importedCmd != NULL)) { cmd = importedCmd; } } return cmd; } #if defined(NSF_DEVELOPMENT_TEST) /* *---------------------------------------------------------------------- * ReverseLookupCmdFromCmdTable -- * * Allows for looking up objects in command tables (e.g., namespace * cmd tables, the interp's hidden cmd table) based on their * command pointer (rather than their command name). * * Results: * Boolean result indicating success * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool ReverseLookupCmdFromCmdTable( const Tcl_Command searchCmdPtr, Tcl_HashTable *cmdTablePtr ) nonnull(1) nonnull(2); static bool ReverseLookupCmdFromCmdTable( const Tcl_Command searchCmdPtr, Tcl_HashTable *cmdTablePtr ) { Tcl_HashSearch search; const Tcl_HashEntry *hPtr; bool result = NSF_FALSE; nonnull_assert(searchCmdPtr != NULL); nonnull_assert(cmdTablePtr != NULL); for (hPtr = Tcl_FirstHashEntry(cmdTablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { Tcl_Command needleCmdPtr = (Tcl_Command)Tcl_GetHashValue(hPtr); if (needleCmdPtr == searchCmdPtr) { result = NSF_TRUE; break; } } return result; } /* *---------------------------------------------------------------------- * GetHiddenObjectFromCmd -- * * Obtains a hidden object for a specified cmd. The function uses a * reverse lookup of *hidden* object structures based on their * commands. This helper is needed for handling hidden and * re-exposed objects during the shutdown and the cleanup of object * systems. * * Results: * NsfObject* or NULL * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfObject *GetHiddenObjectFromCmd( Tcl_Interp *interp, const Tcl_Command cmdPtr ) nonnull(1); static NsfObject * GetHiddenObjectFromCmd( Tcl_Interp *interp, const Tcl_Command cmdPtr ) { Interp *iPtr = (Interp *) interp; NsfObject *screenedObject; nonnull_assert(cmdPtr != NULL); /* * We can provide a shortcut, knowing that a) exposed cmds have an epoch * counter > 0, and b) the commands originating namespace must be the global * one. See also Tcl_HideCommand() and Tcl_ExposeCommand(). */ if (Tcl_Command_cmdEpoch(cmdPtr) == 0 || ((Command *)cmdPtr)->nsPtr != iPtr->globalNsPtr) { screenedObject = NULL; } else { bool found; /* * Reverse lookup object in the interp's hidden command table. We start * off with the hidden cmds as we suspect their number being smaller than * the re-exposed ones, living in the global namespace */ found = ReverseLookupCmdFromCmdTable(cmdPtr, iPtr->hiddenCmdTablePtr); if (!found) { /* * Reverse lookup object in the interp's global command table. Most likely * needed due to hiding + exposing on a different name. */ found = ReverseLookupCmdFromCmdTable(cmdPtr, &iPtr->globalNsPtr->cmdTable); } screenedObject = found ? NsfGetObjectFromCmdPtr(cmdPtr) : NULL; #if !defined(NDEBUG) if (screenedObject != NULL) { NsfLog(interp, NSF_LOG_NOTICE, "screened object %s found: object %p (%s) cmd %p", Tcl_GetCommandName(interp, cmdPtr), (void *)screenedObject, ObjectName(screenedObject), (void *)cmdPtr); } #endif } return screenedObject; } #endif /* *---------------------------------------------------------------------- * GetObjectFromString -- * * Lookup an object from a given string. The function performs a * command lookup (every object is a command) and checks, if the * command is bound to an NSF object. * * Results: * NsfObject* or NULL * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfObject * GetObjectFromString(Tcl_Interp *interp, const char *name) { register Tcl_Command cmd; nonnull_assert(interp != NULL); nonnull_assert(name != NULL); /*fprintf(stderr, "GetObjectFromString name = '%s'\n", name);*/ cmd = NSFindCommand(interp, name); if (likely(cmd != NULL && CmdIsNsfObject(cmd))) { /*fprintf(stderr, "GetObjectFromString %s => %p\n", name, Tcl_Command_objClientData(cmd));*/ return (NsfObject *)Tcl_Command_objClientData(cmd); } /*fprintf(stderr, "GetObjectFromString %s => NULL\n", name);*/ return NULL; } /* *---------------------------------------------------------------------- * GetClassFromString -- * * Lookup a class from a given string. The function performs an * object lookup and checks, if the object is a class. * * Results: * NsfClass* or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfClass * GetClassFromString(Tcl_Interp *interp, const char *name) { NsfObject *object = GetObjectFromString(interp, name); nonnull_assert(interp != NULL); nonnull_assert(name != NULL); return (object != NULL && NsfObjectIsClass(object)) ? (NsfClass *)object : NULL; } /* *---------------------------------------------------------------------- * CanRedefineCmd -- * * This function tests, whether a method (provided as a string) is * allowed to be redefined in a provided namespace. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int CanRedefineCmd( Tcl_Interp *interp, const Tcl_Namespace *nsPtr, const NsfObject *object, const char *methodName, unsigned int flags ) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static int CanRedefineCmd( Tcl_Interp *interp, const Tcl_Namespace *nsPtr, const NsfObject *object, const char *methodName, unsigned int flags ) { int result; bool ok; Tcl_Command cmd; nonnull_assert(interp != NULL); nonnull_assert(nsPtr != NULL); nonnull_assert(object != NULL); nonnull_assert(methodName != NULL); cmd = FindMethod(nsPtr, methodName); if (cmd != NULL) { if ( NsfGetObjectFromCmdPtr(cmd) != NULL) { /* * Don't allow overwriting of an object with a method. */ return NsfPrintError(interp, "refuse to overwrite child object with method %s; delete/rename it before overwriting", methodName); } ok = (((unsigned int)Tcl_Command_flags(cmd) & NSF_CMD_REDEFINE_PROTECTED_METHOD) == 0u); } else { ok = NSF_TRUE; } if (likely(ok)) { result = TCL_OK; } else { /* * We could test, whether we are bootstrapping the "right" object * system, and allow only overwrites for the current bootstrap * object system, but this seems necessary by now. */ Tcl_Obj *bootstrapObj = Tcl_GetVar2Ex(interp, "::nsf::bootstrap", NULL, TCL_GLOBAL_ONLY); if (bootstrapObj == NULL) { result = NsfPrintError(interp, "refuse to overwrite protected method '%s'; " "derive e.g. a subclass!", methodName, ObjectName_(object)); } else { result = TCL_OK; } } if (likely(result == TCL_OK)) { result = ObjectSystemsCheckSystemMethod(interp, methodName, object, flags); } return result; } /* *---------------------------------------------------------------------- * NsfAddObjectMethod -- * * Externally callable function to register an object level method * for the provided object. * * Results: * A standard Tcl result. * * Side effects: * Newly created Tcl command. * *---------------------------------------------------------------------- */ int NsfAddObjectMethod( Tcl_Interp *interp, Nsf_Object *object, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags ) nonnull(1) nonnull(2) nonnull(3) nonnull(4); int NsfAddObjectMethod( Tcl_Interp *interp, Nsf_Object *object, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags ) { NsfObject *currentObject; Tcl_DString newCmdName, *dsPtr = &newCmdName; const Tcl_Namespace *ns; Tcl_Command newCmd; int result; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodName != NULL); nonnull_assert(proc != NULL); currentObject = (NsfObject *)object; ns = RequireObjNamespace(interp, currentObject); /* * Check whether we are allowed to redefine the method */ result = CanRedefineCmd(interp, currentObject->nsPtr, currentObject, (char *)methodName, flags); if (unlikely(result != TCL_OK)) { return result; } NsfObjectMethodEpochIncr("NsfAddObjectMethod"); /* * Delete an alias definition, if it exists. */ AliasDelete(interp, currentObject->cmdName, methodName, NSF_TRUE); Tcl_DStringInit(dsPtr); DStringAppendQualName(dsPtr, ns, methodName); newCmd = Tcl_CreateObjCommand(interp, Tcl_DStringValue(dsPtr), proc, clientData, dp); if (flags != 0u) { ((Command *) newCmd)->flags |= (int)flags; } Tcl_DStringFree(dsPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * NsfAddClassMethod -- * * Externally callable function to register a class level method * for the provided class. * * Results: * A standard Tcl result. * * Side effects: * Newly created Tcl command. * *---------------------------------------------------------------------- */ int NsfAddClassMethod( Tcl_Interp *interp, Nsf_Class *class, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags ) nonnull(1) nonnull(2) nonnull(3) nonnull(4); int NsfAddClassMethod( Tcl_Interp *interp, Nsf_Class *class, const char *methodName, Tcl_ObjCmdProc *proc, ClientData clientData, Tcl_CmdDeleteProc *dp, unsigned int flags ) { Tcl_DString newCmdName, *dsPtr = &newCmdName; Tcl_Command newCmd; NsfClass *c; int result; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(methodName != NULL); nonnull_assert(proc != NULL); c = (NsfClass *)class; assert(c->nsPtr != NULL); /* * Check whether we are allowed to redefine the method. */ result = CanRedefineCmd(interp, c->nsPtr, &c->object, (char *)methodName, flags); if (unlikely(result != TCL_OK)) { return result; } NsfInstanceMethodEpochIncr("NsfAddClassMethod"); /* * Delete the alias definition, if it exists already. */ AliasDelete(interp, class->object.cmdName, methodName, NSF_FALSE); Tcl_DStringInit(dsPtr); DStringAppendQualName(dsPtr, c->nsPtr, methodName); newCmd = Tcl_CreateObjCommand(interp, Tcl_DStringValue(dsPtr), proc, clientData, dp); if (flags != 0) { ((Command *) newCmd)->flags |= (int)flags; } Tcl_DStringFree(dsPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * AutonameIncr -- * * Returns a Tcl_Obj containing an autonamed (interpreter unique) * value. * * Results: * Tcl Obj. * * Side effects: * Maintains counters in global Tcl arrays. * *---------------------------------------------------------------------- */ static Tcl_Obj *AutonameIncr(Tcl_Interp *interp, Tcl_Obj *nameObj, NsfObject *object, int isInstanceOpt, int doResetOpt) nonnull(1) nonnull(2) nonnull(3); static Tcl_Obj * AutonameIncr(Tcl_Interp *interp, Tcl_Obj *nameObj, NsfObject *object, int isInstanceOpt, int doResetOpt) { Tcl_Obj *valueObj, *resultObj; CallFrame frame, *framePtr = &frame; int flogs = TCL_LEAVE_ERR_MSG; nonnull_assert(interp != NULL); nonnull_assert(nameObj != NULL); nonnull_assert(object != NULL); #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, object, framePtr); #pragma GCC diagnostic pop if (object->nsPtr != NULL) { flogs |= TCL_NAMESPACE_ONLY; } valueObj = Tcl_ObjGetVar2(interp, NsfGlobalObjs[NSF_AUTONAMES], nameObj, flogs); if (valueObj != NULL) { long autoname_counter; /* * The autoname counter can overflow, but this should cause no * troubles. */ Tcl_GetLongFromObj(interp, valueObj, &autoname_counter); autoname_counter++; if (Tcl_IsShared(valueObj)) { valueObj = Tcl_DuplicateObj(valueObj); } Tcl_SetLongObj(valueObj, autoname_counter); resultObj = Tcl_ObjSetVar2(interp, NsfGlobalObjs[NSF_AUTONAMES], nameObj, valueObj, flogs); if (unlikely(resultObj == NULL)) { return NULL; } } else { resultObj = NsfGlobalObjs[NSF_EMPTY]; } if (doResetOpt == 1) { if (valueObj != NULL) { /* * We have such a variable. The reset operation has to unset it. */ Tcl_UnsetVar2(interp, NsfGlobalStrings[NSF_AUTONAMES], ObjStr(nameObj), flogs); } resultObj = NsfGlobalObjs[NSF_EMPTY]; INCR_REF_COUNT2("autoname", resultObj); } else { bool mustCopy = NSF_TRUE, format = NSF_FALSE; const char *c; if (valueObj == NULL) { valueObj = Tcl_ObjSetVar2(interp, NsfGlobalObjs[NSF_AUTONAMES], nameObj, NsfGlobalObjs[NSF_ONE], flogs); } if (isInstanceOpt == 1) { char firstChar; const char *nextChars = ObjStr(nameObj); firstChar = *(nextChars ++); if (isupper((int)firstChar)) { char buffer[1]; buffer[0] = (char)tolower((int)firstChar); resultObj = Tcl_NewStringObj(buffer, 1); INCR_REF_COUNT2("autoname", resultObj); Tcl_AppendLimitedToObj(resultObj, nextChars, TCL_INDEX_NONE, INT_MAX, NULL); mustCopy = NSF_FALSE; } } if (mustCopy) { resultObj = Tcl_DuplicateObj(nameObj); INCR_REF_COUNT2("autoname", resultObj); /* fprintf(stderr, "*** copy %p %s = %p\n", name, ObjStr(name), resultObj); */ } /* * If there is a "%" in the autoname, use Tcl_FormatObjCmd to let the * autoname string be formatted, like Tcl "format" command, with the * value. E.g.: autoname a%06d --> a000000, a000001, a000002, ... */ for (c = ObjStr(resultObj); *c != '\0'; c++) { if (*c == '%') { if (*(c+1) != '%') { format = NSF_TRUE; break; } else { /* * When name contains "%%" format and then append autoname, e.g. * autoname a%% --> a%1, a%2, ... */ c++; } } } if (format) { Tcl_Obj *savedResultObj, *ov[3]; savedResultObj = Tcl_GetObjResult(interp); INCR_REF_COUNT(savedResultObj); ov[0] = NULL; ov[1] = resultObj; ov[2] = valueObj; if (NsfCallCommand(interp, NSF_FORMAT, 3, ov) != TCL_OK) { Nsf_PopFrameObj(interp, framePtr); DECR_REF_COUNT(savedResultObj); return NULL; } DECR_REF_COUNT(resultObj); resultObj = Tcl_DuplicateObj(Tcl_GetObjResult(interp)); INCR_REF_COUNT2("autoname", resultObj); Tcl_SetObjResult(interp, savedResultObj); DECR_REF_COUNT(savedResultObj); } else { const char *valueString = Tcl_GetString(valueObj); Tcl_AppendLimitedToObj(resultObj, valueString, valueObj->length, INT_MAX, NULL); } } Nsf_PopFrameObj(interp, framePtr); assert((doResetOpt == 1 && resultObj->refCount>=1) || (resultObj->refCount == 1)); return resultObj; } /* * Next Scripting CallStack functions */ /* *---------------------------------------------------------------------- * CallStackDoDestroy -- * * Deletion of objects has to take care on the callstack, * e.g. whether an object is active on the callstack or not. The * objects can only be deleted physically, when these are not * activate anymore. This logic is implemented by * CallStackDestroyObject() and CallStackDoDestroy(), where the * latter is responsible for the final deletion. * * Results: * None. * * Side effects: * Frees memory. * *---------------------------------------------------------------------- */ NSF_INLINE static void CallStackDoDestroy(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); NSF_INLINE static void CallStackDoDestroy(Tcl_Interp *interp, NsfObject *object) { Tcl_Command oid; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); /*fprintf(stderr, "CallStackDoDestroy %p flags %.6x\n", object, object->flags);*/ PRINTOBJ("CallStackDoDestroy", object); /* * Don't do anything, if a recursive DURING_DELETE is for some * reason active. */ if (unlikely((object->flags & NSF_DURING_DELETE) != 0u)) { return; } /*fprintf(stderr, "CallStackDoDestroy %p flags %.6x activation %d object->refCount %d cmd %p \n", object, object->flags, object->activationCount, object->refCount, object->id);*/ object->flags |= NSF_DURING_DELETE; oid = object->id; /* * The oid might be freed already, we can't even use * TclIsCommandDeleted(oid) */ if (object->teardown != NULL && oid != NULL) { /* * PrimitiveDestroy() has to be called before * DeleteCommandFromToken(), otherwise e.g. unset traces on this * object cannot be executed from Tcl. We make sure via refCounting * that the object structure is kept until after * DeleteCommandFromToken(). */ NsfObjectRefCountIncr(object); PrimitiveDestroy(object); if /*(object->teardown == NULL)*/ ((object->flags & NSF_TCL_DELETE) == 0u) { Tcl_Obj *savedResultObj = Tcl_GetObjResult(interp); INCR_REF_COUNT(savedResultObj); assert(object->teardown == NULL); /*fprintf(stderr, " before DeleteCommandFromToken %p object flags %.6x\n", (void *)oid, object->flags);*/ /*fprintf(stderr, "cmd dealloc %p refCount %d dodestroy \n", (void *)oid, Tcl_Command_refCount(oid));*/ Tcl_DeleteCommandFromToken(interp, oid); /* this can change the result */ /*fprintf(stderr, " after DeleteCommandFromToken %p %.6x\n", (void *)oid, ((Command *)oid)->flags);*/ Tcl_SetObjResult(interp, savedResultObj); DECR_REF_COUNT(savedResultObj); } NsfCleanupObject(object, "CallStackDoDestroy"); } } /* *---------------------------------------------------------------------- * CallStackDestroyObject -- * * See comments of CallStackDoDestroy() for the overall logic. The * function CallStackDestroyObject() checks, if an object is active * on the call stack (via the activation count). It deletes only * inactive objects via CallStackDoDestroy(). * * Results: * None. * * Side effects: * Might frees memory. * *---------------------------------------------------------------------- */ static void CallStackDestroyObject(Tcl_Interp *interp, NsfObject *object) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); #ifdef OBJDELETION_TRACE fprintf(stderr, "CallStackDestroyObject %p %s activationcount %d flags %.6x\n", (void *)object, ObjectName(object), object->activationCount, object->flags); #endif if ((object->flags & NSF_DESTROY_CALLED) == 0u) { int activationCount = object->activationCount; /* * If the destroy method was not called yet, do it now. */ #ifdef OBJDELETION_TRACE fprintf(stderr, " CallStackDestroyObject has to DispatchDestroyMethod %p activationCount %d\n", (void *)object, activationCount); #endif DispatchDestroyMethod(interp, object, 0u); if (activationCount == 0) { /* * We assume, the object is now freed. If the object is already * freed, we cannot access activation count, and we cannot call * CallStackDoDestroy. */ /*fprintf(stderr, " CallStackDestroyObject %p done\n", obj);*/ return; } } /* * If the object is not referenced on the call-stack anymore * we have to destroy it directly, because CscFinish won't * find the object destroy. */ if (object->activationCount == 0) { CallStackDoDestroy(interp, object); } else { /* * To preserve the deletion order, call delete children now such that * child destructors are called before parent destructors. */ if ((object->teardown != NULL) && (object->nsPtr != NULL)) { /*fprintf(stderr, " CallStackDestroyObject calls NSDeleteChildren\n");*/ NSDeleteChildren(interp, object->nsPtr); } } /*fprintf(stderr, " CallStackDestroyObject %p DONE\n", object);*/ } /* * cmd list handling */ /* *---------------------------------------------------------------------- * CmdListAdd -- * * Add an entry to a cmdlist. Optionally, the function checks for * duplicates (does not insert a duplicate) or it allows one to add new * entries to the end of the list. * * Results: * The newly inserted command list item or a found item (never null). * * Side effects: * Added List entry. * *---------------------------------------------------------------------- */ static NsfCmdList *CmdListAdd( NsfCmdList **cList, const Tcl_Command cmd, NsfClass *clorobj, bool noDuplicates, bool atEnd ) nonnull(1) nonnull(2) returns_nonnull; static NsfCmdList * CmdListAdd( NsfCmdList **cList, const Tcl_Command cmd, NsfClass *clorobj, bool noDuplicates, bool atEnd ) { NsfCmdList *l, *nextPtr, *new; nonnull_assert(cmd != NULL); nonnull_assert(cList != NULL); if (unlikely(atEnd)) { l = *cList; nextPtr = NULL; } else { l = NULL; nextPtr = *cList; } /* * Check for duplicates, if necessary. */ if (unlikely(noDuplicates)) { NsfCmdList *h = l, **end = NULL; while (h != NULL) { if (h->cmdPtr == cmd) { return h; } end = &(h->nextPtr); h = h->nextPtr; } if (end != NULL) { /* * No duplicates, no need to search below, we are at the end of the * list. */ cList = end; l = NULL; } } /* * Ok, we have no duplicates -> append NsfCmdList "new" to the end of the * list. */ new = NEW(NsfCmdList); new->cmdPtr = cmd; NsfCommandPreserve(new->cmdPtr); new->clientData = NULL; new->clorobj = clorobj; new->nextPtr = nextPtr; if (unlikely(l != NULL)) { /* * append new element at the end */ while (l->nextPtr != NULL) { l = l->nextPtr; } l->nextPtr = new; } else { /* * prepend new element */ *cList = new; } return new; } /* *---------------------------------------------------------------------- * CmdListAddSorted -- * * Add an entry to a cmdlist without duplicates. The order of the * entries is not supposed to be relevant. This function maintains * a sorted list to reduce cost to n/2. Can be improved be using * better data structures of needed. * * Results: * The newly inserted command list item or a found item. * * Side effects: * Added list entry. * *---------------------------------------------------------------------- */ static NsfCmdList *CmdListAddSorted(NsfCmdList **cList, Tcl_Command cmd, NsfClass *clorobj) nonnull(1) nonnull(2) returns_nonnull; static NsfCmdList * CmdListAddSorted(NsfCmdList **cList, Tcl_Command cmd, NsfClass *clorobj) { NsfCmdList *prev, *new, *h; nonnull_assert(cmd != NULL); nonnull_assert(cList != NULL); for (h = *cList, prev = NULL; h != NULL; prev = h, h = h->nextPtr) { if (h->cmdPtr == cmd) { return h; } else if (h->cmdPtr > cmd) { break; } } new = NEW(NsfCmdList); new->cmdPtr = cmd; NsfCommandPreserve(new->cmdPtr); new->clientData = NULL; new->clorobj = clorobj; new->nextPtr = h; if (prev != NULL) { prev->nextPtr = new; } else { *cList = new; } return new; } static void CmdListReplaceCmd(NsfCmdList *replace, Tcl_Command cmd, NsfClass *clorobj) nonnull(1) nonnull(3); static void CmdListReplaceCmd(NsfCmdList *replace, Tcl_Command cmd, NsfClass *clorobj) { Tcl_Command del; nonnull_assert(replace != NULL); nonnull_assert(clorobj != NULL); del = replace->cmdPtr; replace->cmdPtr = cmd; replace->clorobj = clorobj; NsfCommandPreserve(cmd); NsfCommandRelease(del); } #if defined(NSF_DEBUGGING) /** for debug purposes only */ static void CmdListPrint(Tcl_Interp *interp, const char *title, NsfCmdList *cmdList) nonnull(1) nonnull(3); static void CmdListPrint(Tcl_Interp *interp, const char *title, NsfCmdList *cmdList) { nonnull_assert(interp != NULL); nonnull_assert(cmdList != NULL); if (title != NULL) { fprintf(stderr, "%s %p:\n", title, cmdList); } while (cmdList != NULL) { fprintf(stderr, " CL=%p, cmdPtr=%p %s, clorobj %p, clientData=%p\n", cmdList, cmdList->cmdPtr, (interp != NULL) ? Tcl_GetCommandName(interp, cmdList->cmdPtr) : "", cmdList->clorobj, cmdList->clientData); cmdList = cmdList->nextPtr; } } #endif /* * physically delete an entry 'del' */ static void CmdListDeleteCmdListEntry(NsfCmdList *del, NsfFreeCmdListClientData *freeFct) nonnull(1); static void CmdListDeleteCmdListEntry(NsfCmdList *del, NsfFreeCmdListClientData *freeFct) { nonnull_assert(del != NULL); if (unlikely(freeFct != NULL)) { (*freeFct)(del); } NsfCommandRelease(del->cmdPtr); FREE(NsfCmdList, del); } /* * remove a command 'delCL' from a command list, but do not * free it ... returns the removed NsfCmdList* */ static NsfCmdList *CmdListRemoveFromList(NsfCmdList **cmdList, NsfCmdList *delCL) nonnull(1) nonnull(2); static NsfCmdList * CmdListRemoveFromList(NsfCmdList **cmdList, NsfCmdList *delCL) { register NsfCmdList *c; NsfCmdList *del = NULL; nonnull_assert(cmdList != NULL); nonnull_assert(delCL != NULL); c = *cmdList; if (likely(c != NULL)) { if (c == delCL) { *cmdList = c->nextPtr; del = c; } else { while ((c->nextPtr != NULL) && (c->nextPtr != delCL)) { c = c->nextPtr; } if (c->nextPtr == delCL) { del = delCL; c->nextPtr = delCL->nextPtr; } } } return del; } /* *---------------------------------------------------------------------- * CmdListRemoveDeleted -- * * Remove all command pointers from a command list which are marked * "deleted". The condition for deletion is the presence of the flag * CMD_DYING (previously, CMD_IS_DELETED), with the flag bit being set by * Tcl_DeleteCommandFromToken(). * * Results: * The cmd list filtered for non-deleted commands * * Side effects: * None. * *---------------------------------------------------------------------- */ static void CmdListRemoveDeleted(NsfCmdList **cmdList, NsfFreeCmdListClientData *freeFct) nonnull(1) nonnull(2); static void CmdListRemoveDeleted(NsfCmdList **cmdList, NsfFreeCmdListClientData *freeFct) { NsfCmdList *f, *del; nonnull_assert(cmdList != NULL); nonnull_assert(freeFct != NULL); f = *cmdList; while (f != NULL) { /* * HIDDEN OBJECTS: For supporting hidden mixins, we cannot rely on the * cmdEpoch as indicator of the deletion status of a cmd because the epoch * counters of hidden and re-exposed commands are bumped. Despite of this, * their object structures remain valid. We resort to the use of the * per-cmd flag CMD_DYING (previously, CMD_IS_DELETED), set upon * processing a command in Tcl_DeleteCommandFromToken(). */ if (TclIsCommandDeleted(f->cmdPtr)) { del = f; f = f->nextPtr; del = CmdListRemoveFromList(cmdList, del); CmdListDeleteCmdListEntry(del, freeFct); } else f = f->nextPtr; } } /* * Delete all cmds with given context class object */ static void CmdListRemoveContextClassFromList( NsfCmdList **cmdList, const NsfClass *clorobj, NsfFreeCmdListClientData *freeFct ) nonnull(1) nonnull(2) nonnull(3); static void CmdListRemoveContextClassFromList( NsfCmdList **cmdList, const NsfClass *clorobj, NsfFreeCmdListClientData *freeFct ) { NsfCmdList *c, *del = NULL; nonnull_assert(cmdList != NULL); nonnull_assert(clorobj != NULL); nonnull_assert(freeFct != NULL); /* CmdListRemoveDeleted(cmdList, freeFct); */ c = *cmdList; while (c != NULL && c->clorobj == clorobj) { del = c; *cmdList = c->nextPtr; CmdListDeleteCmdListEntry(del, freeFct); c = *cmdList; } while (c != NULL) { if (c->clorobj == clorobj) { del = c; c = *cmdList; while ((c->nextPtr != NULL) && (c->nextPtr != del)) { c = c->nextPtr; } if (c->nextPtr == del) { c->nextPtr = del->nextPtr; } CmdListDeleteCmdListEntry(del, freeFct); } c = c->nextPtr; } } /* * free the memory of a whole 'cmdList' */ static void CmdListFree(NsfCmdList **cmdList, NsfFreeCmdListClientData *freeFct) { nonnull_assert(cmdList != NULL); while (*cmdList != NULL) { NsfCmdList *del = *cmdList; *cmdList = (*cmdList)->nextPtr; CmdListDeleteCmdListEntry(del, freeFct); } } /* * simple list search proc to search a list of cmds * for a command ptr */ static NsfCmdList * CmdListFindCmdInList(const Tcl_Command cmd, NsfCmdList *l) nonnull(2) nonnull(1) NSF_pure; static NsfCmdList * CmdListFindCmdInList(const Tcl_Command cmd, NsfCmdList *l) { register NsfCmdList *h; nonnull_assert(cmd != NULL); nonnull_assert(l != NULL); for (h = l; h != NULL; h = h->nextPtr) { if (h->cmdPtr == cmd) { return h; } } return NULL; } /* * simple list search proc to search a list of cmds * for a simple Name */ static NsfCmdList * CmdListFindNameInList(Tcl_Interp *interp, const char *name, NsfCmdList *cmdList) nonnull(1) nonnull(2) nonnull(3); static NsfCmdList * CmdListFindNameInList(Tcl_Interp *interp, const char *name, NsfCmdList *cmdList) { nonnull_assert(interp != NULL); nonnull_assert(name != NULL); nonnull_assert(cmdList != NULL); do { const char *cmdName = Tcl_GetCommandName(interp, cmdList->cmdPtr); if (cmdName[0] == name[0] && strcmp(cmdName, name) == 0) { return cmdList; } cmdList = cmdList->nextPtr; } while (cmdList != NULL); return NULL; } /* *---------------------------------------------------------------------- * CheckConditionInScope -- * * Check a given condition in the current call-frame's scope. It is * the responsibility of the caller to push the intended call-frame. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int CheckConditionInScope(Tcl_Interp *interp, Tcl_Obj *condition) nonnull(1) nonnull(2); static int CheckConditionInScope(Tcl_Interp *interp, Tcl_Obj *condition) { int result, success; Tcl_Obj *ov[2] = {NULL, condition}; nonnull_assert(interp != NULL); nonnull_assert(condition != NULL); INCR_REF_COUNT(condition); result = Nsf_ExprObjCmd(NULL, interp, 2, ov); DECR_REF_COUNT(condition); if (likely(result == TCL_OK)) { result = Tcl_GetBooleanFromObj(interp, Tcl_GetObjResult(interp), &success); if (result == TCL_OK && success == 0) { result = NSF_CHECK_FAILED; } } return result; } /* * Generic Obj-List handling functions. */ /* *---------------------------------------------------------------------- * TclObjListFreeList -- * * Free the elements of the obj list. * * Results: * None. * * Side effects: * free memory. * *---------------------------------------------------------------------- */ static void TclObjListFreeList(NsfTclObjList *list) nonnull(1); static void TclObjListFreeList(NsfTclObjList *list) { nonnull_assert(list != NULL); do { NsfTclObjList *del = list; list = list->nextPtr; DECR_REF_COUNT2("listContent", del->content); if (del->payload != NULL) { DECR_REF_COUNT2("listPayload", del->payload); } FREE(NsfTclObjList, del); } while (list != NULL); } /* *---------------------------------------------------------------------- * TclObjListNewElement -- * * Add a new element to the obj list with an optional value (stored * in payload). * * Results: * None. * * Side effects: * allocate memory. * *---------------------------------------------------------------------- */ static Tcl_Obj * TclObjListNewElement(NsfTclObjList **list, Tcl_Obj *obj, Tcl_Obj *valueObj) nonnull(1) nonnull(2) returns_nonnull; static Tcl_Obj * TclObjListNewElement(NsfTclObjList **list, Tcl_Obj *obj, Tcl_Obj *valueObj) { NsfTclObjList *elt = NEW(NsfTclObjList); nonnull_assert(list != NULL); nonnull_assert(obj != NULL); INCR_REF_COUNT2("listContent", obj); elt->content = obj; elt->payload = valueObj; if (valueObj != NULL) { INCR_REF_COUNT2("listPayload", valueObj); } elt->nextPtr = *list; *list = elt; return obj; } /* *---------------------------------------------------------------------- * TclObjListAdd -- * * Add an NsfTclObjList element to the obj list indexed by a key * into a sorted list of elements. Duplicates are appended to the * payload elements. * * Results: * None. * * Side effects: * Add element to the obj-list. * *---------------------------------------------------------------------- */ static void TclObjListAdd(Tcl_Interp *interp, NsfTclObjList **list, Tcl_Obj *key, Tcl_Obj *value) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static void TclObjListAdd(Tcl_Interp *interp, NsfTclObjList **list, Tcl_Obj *key, Tcl_Obj *value) { NsfTclObjList *elt, **prevPtr; const char *keyString; nonnull_assert(interp != NULL); nonnull_assert(list != NULL); nonnull_assert(key != NULL); nonnull_assert(value != NULL); keyString = ObjStr(key); for (elt = *list, prevPtr = list; elt != NULL; prevPtr = &elt->nextPtr, elt = elt->nextPtr) { const char *eltString = ObjStr(elt->content); if (key == elt->content || strcmp(keyString, eltString) == 0) { /* * Found the element, append to it */ /* fprintf(stderr, "TclObjListAdd: insert %s/%s equal, append to %s\n", keyString, ObjStr(value), ObjStr(elt->payload));*/ Tcl_ListObjAppendElement(interp, elt->payload, value); return; } if (strcmp(keyString, eltString) < 0) { /* * Element not found, insert new before as a new entry. */ /*fprintf(stderr, "TclObjListAdd: insert %s/%s before %s isshared %d\n", keyString, ObjStr(value), eltString, Tcl_IsShared(key));*/ TclObjListNewElement(prevPtr, key, Tcl_IsShared(value) ? Tcl_DuplicateObj(value) : value); return; } } /* * Element not found, insert new as last entry. */ /* fprintf(stderr, "TclObjListAdd: insert last %s value %s\n", keyString, ObjStr(value)); */ TclObjListNewElement(prevPtr, key, Tcl_NewListObj(1, &value)); return; } /* *---------------------------------------------------------------------- * AddObjToTclList -- * * Add a Tcl_Obj to a potential not-existing Tcl list, which is * created on demand. * * Results: * None. * * Side effects: * Add Tcl_Obj to the Tcl list, potentially creating list. * *---------------------------------------------------------------------- */ static void AddObjToTclList( Tcl_Interp *interp, Tcl_Obj **listObjPtr, Tcl_Obj *obj ) nonnull(2) nonnull(3); static void AddObjToTclList( Tcl_Interp *interp, Tcl_Obj **listObjPtr, Tcl_Obj *obj ) { nonnull_assert(listObjPtr != NULL); nonnull_assert(obj != NULL); if (*listObjPtr == NULL) { *listObjPtr = Tcl_NewListObj(1, &obj); INCR_REF_COUNT2("AddObjToTclList", *listObjPtr); } else { Tcl_ListObjAppendElement(interp, *listObjPtr, obj); } } #if defined(NSF_WITH_ASSERTIONS) /********************************************************************* * Assertions **********************************************************************/ static NsfTclObjList * AssertionNewList(Tcl_Interp *interp, Tcl_Obj *aObj) nonnull(1); static NsfTclObjList * AssertionNewList(Tcl_Interp *interp, Tcl_Obj *aObj) { Tcl_Obj **ov; int oc; NsfTclObjList *last = NULL; nonnull_assert(interp != NULL); if (aObj && Tcl_ListObjGetElements(interp, aObj, &oc, &ov) == TCL_OK) { if (oc > 0) { int i; for (i = oc - 1; i >= 0; i--) { TclObjListNewElement(&last, ov[i], NULL); } } } return last; } static Tcl_Obj *AssertionList(Tcl_Interp *interp, NsfTclObjList *alist) nonnull(1); static Tcl_Obj * AssertionList(Tcl_Interp *interp, NsfTclObjList *alist) { Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); nonnull_assert(interp != NULL); for (; alist != NULL; alist = alist->nextPtr) { Tcl_ListObjAppendElement(interp, listObj, alist->content); } return listObj; } static int AssertionListCheckOption(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); static int AssertionListCheckOption(Tcl_Interp *interp, NsfObject *object) { NsfObjectOpt *opt; Tcl_Obj *resultObj; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); opt = object->opt; if (opt == NULL) { return TCL_OK; } resultObj = Tcl_GetObjResult(interp); if (opt->checkoptions & CHECK_OBJINVAR) { Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("object-invar", TCL_INDEX_NONE)); } if (opt->checkoptions & CHECK_CLINVAR) { Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("class-invar", TCL_INDEX_NONE)); } if (opt->checkoptions & CHECK_PRE) { Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("pre", TCL_INDEX_NONE)); } if (opt->checkoptions & CHECK_POST) { Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("post", TCL_INDEX_NONE)); } return TCL_OK; } static NsfProcAssertion *AssertionFindProcs(NsfAssertionStore *aStore, const char *name) nonnull(1) nonnull(2); static NsfProcAssertion * AssertionFindProcs(NsfAssertionStore *aStore, const char *name) { const Tcl_HashEntry *hPtr; nonnull_assert(aStore != NULL); nonnull_assert(name != NULL); hPtr = Tcl_CreateHashEntry(&aStore->procs, name, NULL); if (hPtr == NULL) { return NULL; } return (NsfProcAssertion *) Tcl_GetHashValue(hPtr); } static void AssertionRemoveProc(NsfAssertionStore *aStore, const char *name) nonnull(1) nonnull(2); static void AssertionRemoveProc(NsfAssertionStore *aStore, const char *name) { Tcl_HashEntry *hPtr; nonnull_assert(aStore != NULL); nonnull_assert(name != NULL); hPtr = Tcl_CreateHashEntry(&aStore->procs, name, NULL); if (hPtr != NULL) { NsfProcAssertion *procAss = (NsfProcAssertion *) Tcl_GetHashValue(hPtr); if (procAss->pre != NULL) { TclObjListFreeList(procAss->pre); } if (procAss->post != NULL) { TclObjListFreeList(procAss->post); } FREE(NsfProcAssertion, procAss); Tcl_DeleteHashEntry(hPtr); } } static void AssertionAddProc(Tcl_Interp *interp, const char *name, NsfAssertionStore *aStore, Tcl_Obj *pre, Tcl_Obj *post) nonnull(1) nonnull(2) nonnull(3); static void AssertionAddProc(Tcl_Interp *interp, const char *name, NsfAssertionStore *aStore, Tcl_Obj *pre, Tcl_Obj *post) { int isNew = 0; Tcl_HashEntry *hPtr; NsfProcAssertion *procs = NEW(NsfProcAssertion); nonnull_assert(interp != NULL); nonnull_assert(name != NULL); nonnull_assert(aStore != NULL); AssertionRemoveProc(aStore, name); procs->pre = AssertionNewList(interp, pre); procs->post = AssertionNewList(interp, post); hPtr = Tcl_CreateHashEntry(&aStore->procs, name, &isNew); if (isNew != 0) { Tcl_SetHashValue(hPtr, procs); } } static NsfAssertionStore *AssertionCreateStore(void) returns_nonnull; static NsfAssertionStore * AssertionCreateStore(void) { NsfAssertionStore *aStore = NEW(NsfAssertionStore); aStore->invariants = NULL; Tcl_InitHashTable(&aStore->procs, TCL_STRING_KEYS); MEM_COUNT_ALLOC("Tcl_InitHashTable", &aStore->procs); return aStore; } static void AssertionRemoveStore(NsfAssertionStore *aStore) nonnull(1); static void AssertionRemoveStore(NsfAssertionStore *aStore) { Tcl_HashSearch hSrch; const Tcl_HashEntry *hPtr; nonnull_assert(aStore != NULL); for (hPtr = Tcl_FirstHashEntry(&aStore->procs, &hSrch); hPtr != NULL; hPtr = Tcl_FirstHashEntry(&aStore->procs, &hSrch)) { /* * AssertionRemoveProc calls Tcl_DeleteHashEntry(hPtr), thus * we get the FirstHashEntry afterwards again to proceed */ AssertionRemoveProc(aStore, Tcl_GetHashKey(&aStore->procs, hPtr)); } Tcl_DeleteHashTable(&aStore->procs); MEM_COUNT_FREE("Tcl_InitHashTable", &aStore->procs); if (aStore->invariants != NULL) { TclObjListFreeList(aStore->invariants); } FREE(NsfAssertionStore, aStore); } static int AssertionCheckList(Tcl_Interp *interp, NsfObject *object, NsfTclObjList *alist, const char *methodName) nonnull(1) nonnull(2) nonnull(4); static int AssertionCheckList(Tcl_Interp *interp, NsfObject *object, NsfTclObjList *alist, const char *methodName) { NsfTclObjList *checkFailed = NULL; Tcl_Obj *savedResultObj; CheckOptions savedCheckoptions; int acResult = TCL_OK; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodName != NULL); /* * No obj->opt -> checkoption == CHECK_NONE */ if (object->opt == NULL) { return TCL_OK; } /* * Do not check assertion modifying methods, otherwise we cannot react in * catch on a run time assertion check failure */ #if 1 /* * TODO: the following check operations is XOTcl1 legacy and is not * generic. It should be replaced by another method-property. Most of the * is*String() definition are then obsolete and should be deleted from * nsfInt.h as well. */ if (isCheckString(methodName)) { return TCL_OK; } #endif savedResultObj = Tcl_GetObjResult(interp); INCR_REF_COUNT(savedResultObj); Tcl_ResetResult(interp); while (alist != NULL) { /* * Eval instead of IfObjCmd => the substitutions in the conditions will be * done by Tcl. */ const char *assStr = ObjStr(alist->content), *c = assStr; int comment = 0; for (; c && *c != '\0'; c++) { if (*c == '#') { comment = 1; break; } } if (comment == 0) { CallFrame frame, *framePtr = &frame; #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, (NsfObject *)object, framePtr); #pragma GCC diagnostic pop /* * Don't check assertions during the condition check. */ savedCheckoptions = object->opt->checkoptions; object->opt->checkoptions = CHECK_NONE; /* fprintf(stderr, "Checking Assertion %s ", assStr); */ /* * Now check the condition in the pushed call-frame's scope. */ acResult = CheckConditionInScope(interp, alist->content); if (acResult != TCL_OK) { checkFailed = alist; } object->opt->checkoptions = savedCheckoptions; /* fprintf(stderr, "...%s\n", (checkFailed != 0) ? "failed" : "ok"); */ Nsf_PopFrameObj(interp, framePtr); } if (checkFailed != 0) { break; } alist = alist->nextPtr; } if (unlikely(checkFailed != 0)) { DECR_REF_COUNT(savedResultObj); if (acResult == TCL_ERROR) { Tcl_Obj *sr = Tcl_GetObjResult(interp); INCR_REF_COUNT(sr); NsfPrintError(interp, "error in Assertion: {%s} in proc '%s'\n%s", ObjStr(checkFailed->content), methodName, ObjStr(sr)); DECR_REF_COUNT(sr); return TCL_ERROR; } return NsfPrintError(interp, "assertion failed check: {%s} in proc '%s'", ObjStr(checkFailed->content), methodName); } Tcl_SetObjResult(interp, savedResultObj); DECR_REF_COUNT(savedResultObj); return TCL_OK; } static int AssertionCheckInvars(Tcl_Interp *interp, NsfObject *object, const char *methodName, CheckOptions checkoptions) nonnull(1) nonnull(2) nonnull(3); static int AssertionCheckInvars(Tcl_Interp *interp, NsfObject *object, const char *methodName, CheckOptions checkoptions) { int result = TCL_OK; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodName != NULL); if (checkoptions & CHECK_OBJINVAR && object->opt->assertions) { result = AssertionCheckList(interp, object, object->opt->assertions->invariants, methodName); } if (result != TCL_ERROR && checkoptions & CHECK_CLINVAR) { NsfClasses *clPtr; clPtr = PrecedenceOrder(object->cl); while ((clPtr != NULL) && (result != TCL_ERROR)) { NsfAssertionStore *aStore = (clPtr->cl->opt != NULL) ? clPtr->cl->opt->assertions : NULL; if (aStore != NULL) { result = AssertionCheckList(interp, object, aStore->invariants, methodName); } clPtr = clPtr->nextPtr; } } return result; } static int AssertionCheck(Tcl_Interp *interp, NsfObject *object, NsfClass *class, const char *method, CheckOptions checkOption) nonnull(1) nonnull(2) nonnull(4); static int AssertionCheck(Tcl_Interp *interp, NsfObject *object, NsfClass *class, const char *method, CheckOptions checkOption) { int result = TCL_OK; NsfAssertionStore *aStore; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(method != NULL); assert(object->opt != NULL); if (class != NULL) { aStore = (class->opt != NULL) ? class->opt->assertions : NULL; } else { aStore = (object->opt != NULL) ? object->opt->assertions : NULL; } if ((aStore != NULL) && (checkOption & object->opt->checkoptions) ) { NsfProcAssertion *procs = AssertionFindProcs(aStore, method); if (procs != NULL) { switch (checkOption) { case CHECK_PRE: result = AssertionCheckList(interp, object, procs->pre, method); break; case CHECK_POST: result = AssertionCheckList(interp, object, procs->post, method); break; case CHECK_ALL: ;NSF_FALL_THROUGH; /* fall through */ case CHECK_NONE: ;NSF_FALL_THROUGH; /* fall through */ case CHECK_CLINVAR: ;NSF_FALL_THROUGH; /* fall through */ case CHECK_OBJINVAR: ;NSF_FALL_THROUGH; /* fall through */ case CHECK_INVAR: break; } } if (likely(result != TCL_ERROR)) { result = AssertionCheckInvars(interp, object, method, object->opt->checkoptions); } } return result; } static int AssertionSetCheckOptions(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *arg) nonnull(1) nonnull(2) nonnull(3); static int AssertionSetCheckOptions(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *arg) { NsfObjectOpt *opt; int ocArgs; Tcl_Obj **ovArgs; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(arg != NULL); opt = NsfRequireObjectOpt(object); opt->checkoptions = CHECK_NONE; if (Tcl_ListObjGetElements(interp, arg, &ocArgs, &ovArgs) == TCL_OK && ocArgs > 0) { int i; for (i = 0; i < ocArgs; i++) { const char *option = ObjStr(ovArgs[i]); if (option != NULL) { switch (*option) { case 'c': if (strcmp(option, "class-invar") == 0) { opt->checkoptions |= CHECK_CLINVAR; } break; case 'o': if (strcmp(option, "object-invar") == 0) { opt->checkoptions |= CHECK_OBJINVAR; } break; case 'p': if (strcmp(option, "pre") == 0) { opt->checkoptions |= CHECK_PRE; } else if (strcmp(option, "post") == 0) { opt->checkoptions |= CHECK_POST; } break; case 'a': if (strcmp(option, "all") == 0) { opt->checkoptions |= CHECK_ALL; } break; } } } } if (opt->checkoptions == CHECK_NONE && ocArgs > 0) { return NsfPrintError(interp, "unknown check option in command '%s' check %s, ", "valid: all pre post object-invar class-invar", ObjectName_(object), ObjStr(arg)); } return TCL_OK; } static void AssertionSetInvariants(Tcl_Interp *interp, NsfAssertionStore **assertions, Tcl_Obj *arg) nonnull(1) nonnull(2) nonnull(3); static void AssertionSetInvariants(Tcl_Interp *interp, NsfAssertionStore **assertions, Tcl_Obj *arg) { nonnull_assert(interp != NULL); nonnull_assert(assertions != NULL); nonnull_assert(arg != NULL); if (*assertions != NULL) { TclObjListFreeList((*assertions)->invariants); } else { *assertions = AssertionCreateStore(); } (*assertions)->invariants = AssertionNewList(interp, arg); } #endif /* NSF_WITH_ASSERTIONS */ /*********************************************************************** * Mixin support ***********************************************************************/ /* * push a mixin stack information on this object */ static void MixinStackPush(NsfObject *object) nonnull(1); static void MixinStackPush(NsfObject *object) { register NsfMixinStack *h = NEW(NsfMixinStack); nonnull_assert(object != NULL); h->currentCmdPtr = NULL; h->nextPtr = object->mixinStack; object->mixinStack = h; /*fprintf(stderr, "MixinStackPush %p %s\n", object, ObjectName(object));*/ } /* * Pop a mixin stack information on this object. */ static void MixinStackPop(NsfObject *object) nonnull(1); static void MixinStackPop(NsfObject *object) { register const NsfMixinStack *h; nonnull_assert(object != NULL); /*fprintf(stderr, "MixinStackPop %p %s\n", object, ObjectName(object));*/ h = object->mixinStack; object->mixinStack = h->nextPtr; FREE(NsfMixinStack, h); } /* * Appends NsfClasses (containing the mixin-classes and their * superclasses) to 'mixinClasses' list from a given mixinList. */ static void MixinComputeOrderFullList( Tcl_Interp *interp, NsfCmdList **mixinList, NsfClasses **mixinClasses, NsfClasses **checkList, int level ) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static void MixinComputeOrderFullList( Tcl_Interp *interp, NsfCmdList **mixinList, NsfClasses **mixinClasses, NsfClasses **checkList, int level ) { NsfCmdList *m; NsfClasses *pl, **clPtr = mixinClasses; nonnull_assert(interp != NULL); nonnull_assert(mixinList != NULL); nonnull_assert(mixinClasses != NULL); nonnull_assert(checkList != NULL); CmdListRemoveDeleted(mixinList, GuardDel); for (m = *mixinList; m != NULL; m = m->nextPtr) { NsfClass *mixinClass = NsfGetClassFromCmdPtr(m->cmdPtr); if (mixinClass != NULL) { for (pl = PrecedenceOrder(mixinClass); pl != NULL; pl = pl->nextPtr) { if (!IsRootClass(pl->cl)) { NsfClassOpt *opt = pl->cl->opt; /* fprintf(stderr, "find %p %s in checklist 1 %p\n", pl->cl, ClassName(pl->cl), *checkList);*/ if (*checkList != NULL && (NsfClassListFind(*checkList, pl->cl) != NULL)) { /*fprintf(stderr, "+++ never add %s\n", ClassName(pl->cl));*/ } else { if (opt != NULL && opt->classMixins != NULL) { /* * Compute transitively the (class) mixin-classes of this * added class. */ NsfClassListAdd(checkList, pl->cl, NULL); /*fprintf(stderr, "+++ transitive %s\n", ClassName(pl->cl));*/ MixinComputeOrderFullList(interp, &opt->classMixins, mixinClasses, checkList, level+1); } /*fprintf(stderr, "+++ add to mixinClasses %p path: %s clPtr %p\n", mixinClasses, ClassName(pl->cl), clPtr);*/ clPtr = NsfClassListAddNoDup(clPtr, pl->cl, m->clientData); } } } } } if (level == 0 && *checkList) { NsfClassListFree(*checkList); *checkList = NULL; } } /* *---------------------------------------------------------------------- * MixinResetOrder -- * * Free the mixin order of the provided object if it exists. * * Results: * None. * * Side effects: * Frees potentially the mixinOrder list. * *---------------------------------------------------------------------- */ static void MixinResetOrder(NsfObject *object) nonnull(1); static void MixinResetOrder(NsfObject *object) { nonnull_assert(object != NULL); CmdListFree(&object->mixinOrder, NULL /*GuardDel*/); object->mixinOrder = NULL; } /* *---------------------------------------------------------------------- * NsfClassListAddPerClassMixins -- * * Append the class mixins to the provided list. CheckList is used * to eliminate potential duplicates. * * Results: * None. * * Side effects: * Appends potentially elements to classListPtr and checkList. * *---------------------------------------------------------------------- */ static void NsfClassListAddPerClassMixins(Tcl_Interp *interp, NsfClass *class, NsfClasses **classListPtr, NsfClasses **checkList) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static void NsfClassListAddPerClassMixins(Tcl_Interp *interp, NsfClass *class, NsfClasses **classListPtr, NsfClasses **checkList) { NsfClasses *pl; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(classListPtr != NULL); nonnull_assert(checkList != NULL); for (pl = PrecedenceOrder(class); pl != NULL; pl = pl->nextPtr) { NsfClassOpt *clopt = pl->cl->opt; if (clopt != NULL && clopt->classMixins) { MixinComputeOrderFullList(interp, &clopt->classMixins, classListPtr, checkList, 1); } } } /* *---------------------------------------------------------------------- * MixinComputeOrder -- * * Compute a duplicate-free linearized order of per-object and * per-class mixins and the class inheritance. The precedence rule * is that the last occurrence makes it into the final list. * * Results: * None. * * Side effects: * object->mixinOrder is updated. * *---------------------------------------------------------------------- */ static void MixinComputeOrder(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); static void MixinComputeOrder(Tcl_Interp *interp, NsfObject *object) { NsfClasses *fullList, *checkList = NULL, *mixinClasses = NULL, *clPtr; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); if (object->mixinOrder != NULL) { MixinResetOrder(object); } /* * Append per-obj mixins. */ if (object->opt != NULL) { NsfCmdList *m; MixinComputeOrderFullList(interp, &object->opt->objMixins, &mixinClasses, &checkList, 1); /* * Add per-object mixins to checkList to avoid these classes in the * class mixins. * * TODO: we could add this already in MixinComputeOrderFullList() if we * provide an additional flag. */ for (m = object->opt->objMixins; m != NULL; m = m->nextPtr) { NsfClass *mixinClass = NsfGetClassFromCmdPtr(m->cmdPtr); if (mixinClass != NULL) { NsfClassListAddNoDup(&checkList, mixinClass, NULL); } } } /*fprintf(stderr, "%s ", ObjectName(object)); NsfClassListPrint("MixinComputeOrder poms", mixinClasses); NsfClassListPrint("MixinComputeOrder poms checkList", checkList);*/ /* * Append per-class mixins. */ NsfClassListAddPerClassMixins(interp, object->cl, &mixinClasses, &checkList); /*fprintf(stderr, "%s ", ObjectName(object)); NsfClassListPrint("MixinComputeOrder poms+pcms", mixinClasses); CmdListPrint(interp, "mixinOrder", object->mixinOrder);*/ if (checkList != NULL) { NsfClassListFree(checkList); } fullList = mixinClasses; /* * Don't add duplicates or classes of the precedence order to the resulting * list. */ for (clPtr = mixinClasses; clPtr != NULL; clPtr = clPtr->nextPtr) { const NsfClass *class = clPtr->cl; NsfClasses *checker; /*fprintf(stderr, "--- Work on %s\n", ClassName(cl)); CmdListPrint(interp, "mixinOrder", object->mixinOrder);*/ checker = NsfClassListFind(clPtr->nextPtr, class); /* * If checker is set, it is a duplicate and ignored. */ if (checker == NULL) { /* * Check object->cl hierarchy */ checker = NsfClassListFind(PrecedenceOrder(object->cl), class); /* * If checker is set, it was found in the class hierarchy and it is * ignored. */ } if (checker == NULL) { /* * Add the class to the mixinOrder list. */ NsfCmdList *new; /*fprintf(stderr, "--- adding to mixinOrder %s to cmdlist %p of object %s\n", ClassName(class), object->mixinOrder, ObjectName(object));*/ new = CmdListAdd(&object->mixinOrder, class->object.id, NULL, /*noDuplicates*/ NSF_FALSE, NSF_TRUE); /*CmdListPrint(interp, "mixinOrder", object->mixinOrder);*/ /* * We require the first matching guard of the full list in the new * client data */ checker = NsfClassListFind(fullList, class); if (checker != NULL) { new->clientData = checker->clientData; } } } /* * ... and free the memory of the full list. */ if (fullList != NULL) { NsfClassListFree(fullList); } /*CmdListPrint(interp, "mixin order\n", obj->mixinOrder);*/ } /* *---------------------------------------------------------------------- * MixinAdd -- * * Add a mixinreg (mixin-class with a potential guard) provided as * a Tcl_Obj* to 'mixinList' by appending it to the provided * cmdList. * * Results: * A standard Tcl result. * * Side effects: * Potentially allocating cmd list elements added to the mixinList. * *---------------------------------------------------------------------- */ static int MixinAdd(Tcl_Interp *interp, NsfCmdList **mixinList, Tcl_Obj *nameObj) nonnull(1) nonnull(2) nonnull(3); static int MixinAdd(Tcl_Interp *interp, NsfCmdList **mixinList, Tcl_Obj *nameObj) { int result; nonnull_assert(interp != NULL); nonnull_assert(mixinList != NULL); nonnull_assert(nameObj != NULL); /*fprintf(stderr, "MixinAdd gets obj %p type %p %s\n", nameObj, nameObj->typePtr, ObjTypeStr(nameObj));*/ /* * When the provided nameObj is of type NsfMixinregObjType, the nsf specific * converter was called already; otherwise call the converter here. */ if (nameObj->typePtr != &NsfMixinregObjType && Tcl_ConvertToType(interp, nameObj, &NsfMixinregObjType) != TCL_OK ) { result = TCL_ERROR; } else { Tcl_Obj *guardObj = NULL; NsfClass *mixinCl = NULL; result = NsfMixinregGet(interp, nameObj, &mixinCl, &guardObj); if (result == TCL_OK) { NsfCmdList *new; assert(mixinCl != NULL); assert(!TclIsCommandDeleted(mixinCl->object.id)); new = CmdListAdd(mixinList, mixinCl->object.id, NULL, /*noDuplicates*/ NSF_TRUE, NSF_TRUE); if (guardObj != NULL) { GuardAdd(new, guardObj); } else if (new->clientData != NULL) { GuardDel(new); } } } return result; } /* *---------------------------------------------------------------------- * AppendMatchingElement -- * * Call AppendElement to the resultObj for values matching the specified * pattern. * * Results: * None. * * Side effects: * Appends element to the result object * *---------------------------------------------------------------------- */ static void AppendMatchingElement( Tcl_Interp *interp, Tcl_Obj *resultObj, Tcl_Obj *nameObj, const char *pattern ) nonnull(1) nonnull(2) nonnull(3); static void AppendMatchingElement( Tcl_Interp *interp, Tcl_Obj *resultObj, Tcl_Obj *nameObj, const char *pattern ) { nonnull_assert(interp != NULL); nonnull_assert(resultObj != NULL); nonnull_assert(nameObj != NULL); if (pattern == NULL || Tcl_StringMatch( ObjStr(nameObj), pattern)) { Tcl_ListObjAppendElement(interp, resultObj, nameObj); } } /* *---------------------------------------------------------------------- * AppendMatchingElementsFromCmdList -- * * Apply AppendMatchingElement() to all elements of the passed * Cmdlist * * Results: * NSF_TRUE iff a matching object was provided and it was found; * NSF_FALSE otherwise * * Side effects: * Appends elements to the result * *---------------------------------------------------------------------- */ static bool AppendMatchingElementsFromCmdList( Tcl_Interp *interp, const NsfCmdList *cmdList, Tcl_Obj *resultObj, const char *pattern, NsfObject *matchObject ) nonnull(1) nonnull(2) nonnull(3); static bool AppendMatchingElementsFromCmdList( Tcl_Interp *interp, const NsfCmdList *cmdList, Tcl_Obj *resultObj, const char *pattern, NsfObject *matchObject ) { int success = NSF_FALSE; nonnull_assert(interp != NULL); nonnull_assert(cmdList != NULL); nonnull_assert(resultObj != NULL); do { NsfObject *object = NsfGetObjectFromCmdPtr(cmdList->cmdPtr); if (object != NULL) { if (matchObject == object) { return NSF_TRUE; } else { AppendMatchingElement(interp, resultObj, object->cmdName, pattern); } } cmdList = cmdList->nextPtr; } while (cmdList != NULL); return success; } /* *---------------------------------------------------------------------- * AppendMatchingElementsFromClasses -- * * Apply AppendMatchingElement() to all elements of the passed * class list * * Results: * NSF_TRUE iff a matching object was provided and it was found; * NSF_FALSE otherwise * * Side effects: * Appends elements to the result * *---------------------------------------------------------------------- */ static bool AppendMatchingElementsFromClasses( Tcl_Interp *interp, const NsfClasses *cls, const char *pattern, NsfObject *matchObject ) nonnull(1); static bool AppendMatchingElementsFromClasses( Tcl_Interp *interp, const NsfClasses *cls, const char *pattern, NsfObject *matchObject ) { Tcl_Obj *resultObj; nonnull_assert(interp != NULL); resultObj = Tcl_GetObjResult(interp); for ( ; cls != NULL; cls = cls->nextPtr) { NsfObject *object = (NsfObject *)cls->cl; if (object != NULL) { if (matchObject != NULL && object == matchObject) { /* * We have a matchObject and it is identical to obj, * just return true and don't continue search */ return NSF_TRUE; } else { AppendMatchingElement(interp, resultObj, object->cmdName, pattern); } } } return NSF_FALSE; } /* *---------------------------------------------------------------------- * GetAllInstances -- * * Get all instances of a class recursively into an initialized * String key hash-table. * * Results: * None. * * Side effects: * Passed hash-table contains instances. * *---------------------------------------------------------------------- */ static void GetAllInstances(Tcl_Interp *interp, NsfCmdList **instances, NsfClass *startClass) { NsfClasses *clPtr, *subClasses; nonnull_assert(interp != NULL); nonnull_assert(instances != NULL); nonnull_assert(startClass != NULL); subClasses = TransitiveSubClasses(startClass); for (clPtr = subClasses; clPtr != NULL; clPtr = clPtr->nextPtr) { Tcl_HashTable *tablePtr = &clPtr->cl->instances; Tcl_HashSearch search; const Tcl_HashEntry *hPtr; for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { NsfObject *inst = (NsfObject *)Tcl_GetHashKey(tablePtr, hPtr); Command *cmdPtr; assert(inst != NULL); if (unlikely((inst->flags & NSF_TCL_DELETE) != 0u)) { NsfLog(interp, NSF_LOG_NOTICE, "Object %s is apparently deleted", ObjectName(inst)); continue; } cmdPtr = (Command *)inst->id; assert(cmdPtr != NULL); if (unlikely((cmdPtr->nsPtr->flags & NS_DYING) != 0u)) { NsfLog(interp, NSF_LOG_WARN, "Namespace of %s is apparently deleted", ObjectName_(inst)); continue; } #if defined(NSF_DEVELOPMENT_TEST) { /* * Make sure, we can still lookup the object; the object has to be still * alive. */ NsfObject *object = GetObjectFromString(interp, ObjectName(inst)); /* * HIDDEN OBJECTS: Provide a fallback to a pointer-based lookup. This is * needed because objects can be hidden or re-exposed under a different * name which is not reported back to the object system by the [interp * hide|expose] mechanism. However, we still want to process hidden and * re-exposed objects during cleanup like ordinary, exposed ones. */ if (unlikely(object == NULL)) { object = GetHiddenObjectFromCmd(interp, inst->id); } assert(object != NULL); } #endif /*fprintf (stderr, " -- %p flags %.6x activation %d %s id %p id->flags %.6x " "nsPtr->flags %.6x (instance of %s)\n", inst, inst->flags, inst->activationCount, ObjectName(inst), inst->id, cmdPtr->flags, (cmdPtr->nsPtr != NULL) ? cmdPtr->nsPtr->flags : 0, ClassName(clPtr->cl));*/ CmdListAdd(instances, inst->id, (NsfClass *)inst, NSF_FALSE, NSF_FALSE); } } if (subClasses != NULL) { NsfClassListFree(subClasses); } } /* *---------------------------------------------------------------------- * AddToResultSet -- * * Helper function to add classes to the result set (implemented as * a hash-table), flagging test for matchObject as result. * * Results: * NSF_TRUE iff a matching object was provided and it was found; * NSF_FALSE otherwise * * Side effects: * Appends optionally element to the result object. * *---------------------------------------------------------------------- */ static bool AddToResultSet( Tcl_Interp *interp, Tcl_HashTable *destTablePtr, Tcl_Obj *resultSet, const NsfObject *object, int *isNewPtr, bool appendResult, const char *pattern, NsfObject *matchObject ) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(5); static bool AddToResultSet( Tcl_Interp *interp, Tcl_HashTable *destTablePtr, Tcl_Obj *resultSet, const NsfObject *object, int *isNewPtr, bool appendResult, const char *pattern, NsfObject *matchObject ) { nonnull_assert(interp != NULL); nonnull_assert(destTablePtr != NULL); nonnull_assert(resultSet != NULL); nonnull_assert(object != NULL); nonnull_assert(isNewPtr != NULL); Tcl_CreateHashEntry(destTablePtr, (char *)object, isNewPtr); if (*isNewPtr != 0) { if (matchObject != NULL && matchObject == object) { return NSF_TRUE; } if (appendResult) { AppendMatchingElement(interp, resultSet, object->cmdName, pattern); } } return NSF_FALSE; } /* *---------------------------------------------------------------------- * AddToResultSetWithGuards -- * * Helper function to add classes with guards to the result set * (implemented as a hash-table, full version as a Tcl list), * flagging test for matchObject as result. * * Results: * NSF_TRUE iff a matching object was provided and it was found; * NSF_FALSE otherwise * * Side effects: * Appends optionally element to the result object * *---------------------------------------------------------------------- */ static bool AddToResultSetWithGuards( Tcl_Interp *interp, Tcl_HashTable *destTablePtr, Tcl_Obj *resultSet, const NsfClass *class, ClientData clientData, int *isNewPtr, bool appendResult, const char *pattern, NsfObject *matchObject ) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(6) nonnull(5); static bool AddToResultSetWithGuards( Tcl_Interp *interp, Tcl_HashTable *destTablePtr, Tcl_Obj *resultSet, const NsfClass *class, ClientData clientData, int *isNewPtr, bool appendResult, const char *pattern, NsfObject *matchObject ) { bool result; nonnull_assert(clientData != NULL); nonnull_assert(interp != NULL); nonnull_assert(destTablePtr != NULL); nonnull_assert(class != NULL); nonnull_assert(resultSet != NULL); nonnull_assert(isNewPtr != NULL); Tcl_CreateHashEntry(destTablePtr, (char *)class, isNewPtr); if (*isNewPtr != 0 && appendResult) { if (pattern == NULL || Tcl_StringMatch(ClassName_(class), pattern)) { Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); Tcl_Obj *g = (Tcl_Obj *)clientData; INCR_REF_COUNT(listObj); Tcl_ListObjAppendElement(interp, listObj, class->object.cmdName); Tcl_ListObjAppendElement(interp, listObj, NsfGlobalObjs[NSF_GUARD_OPTION]); Tcl_ListObjAppendElement(interp, listObj, g); Tcl_ListObjAppendElement(interp, resultSet, listObj); DECR_REF_COUNT(listObj); } result = (matchObject != NULL && matchObject == (NsfObject *)class); } else { result = NSF_FALSE; } return result; } /* *---------------------------------------------------------------------- * GetAllObjectMixinsOf -- * * Computes a set of classes, into which this class was mixed in * via per object mixin. The function gets recursively all per * object mixins from a class and its subclasses/isClassMixinOf * and adds it into an initialized object ptr hash-table * (TCL_ONE_WORD_KEYS). * * Results: * Boolean value indicating when done. * * Side effects: * The set of classes is returned in the provided hash-table. * *---------------------------------------------------------------------- */ static bool GetAllObjectMixinsOf( Tcl_Interp *interp, Tcl_HashTable *destTablePtr, Tcl_Obj *resultSet, const NsfClass *startClass, bool isMixin, bool appendResult, const char *pattern, NsfObject *matchObject ) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static bool GetAllObjectMixinsOf( Tcl_Interp *interp, Tcl_HashTable *destTablePtr, Tcl_Obj *resultSet, const NsfClass *startClass, bool isMixin, bool appendResult, const char *pattern, NsfObject *matchObject ) { int isNew = 0; NsfClasses *sc; bool done = NSF_FALSE; nonnull_assert(interp != NULL); nonnull_assert(destTablePtr != NULL); nonnull_assert(resultSet != NULL); nonnull_assert(startClass != NULL); /*fprintf(stderr, "startClass = %s, opt %p, isMixin %d, pattern '%s', matchObject %p\n", ClassName(startClass), startClass->opt, isMixin, pattern, matchObject);*/ /* * check all subclasses of startCl for mixins */ for (sc = startClass->sub; sc != NULL; sc = sc->nextPtr) { done = GetAllObjectMixinsOf(interp, destTablePtr, resultSet, sc->cl, isMixin, appendResult, pattern, matchObject); if (done) { return done; } } /*fprintf(stderr, "check subclasses of %s done\n", ClassName(startClass));*/ if (startClass->opt != NULL) { NsfCmdList *m; /* * Check whether startCl has associated per-class mixins. */ for (m = startClass->opt->isClassMixinOf; m != NULL; m = m->nextPtr) { NsfClass *class; /* * There should be no deleted commands in the list. */ assert(!TclIsCommandDeleted(m->cmdPtr)); class = NsfGetClassFromCmdPtr(m->cmdPtr); assert(class != NULL); /*fprintf(stderr, "check %s mixinof %s\n", ClassName(class), ClassName((startClass)));*/ done = GetAllObjectMixinsOf(interp, destTablePtr, resultSet, class, isMixin, appendResult, pattern, matchObject); /* fprintf(stderr, "check %s mixinof %s done\n", ClassName(class), ClassName(startClass));*/ if (done) { return done; } } /* * Check whether startCl has associated per-object mixins. */ for (m = startClass->opt->isObjectMixinOf; m != NULL; m = m->nextPtr) { NsfObject *object; /* * There should not be deleted commands in the list. */ assert(!TclIsCommandDeleted(m->cmdPtr)); object = NsfGetObjectFromCmdPtr(m->cmdPtr); assert(object != NULL); done = AddToResultSet(interp, destTablePtr, resultSet, object, &isNew, appendResult, pattern, matchObject); if (done) { return done; } } } return done; } /* *---------------------------------------------------------------------- * AddClassListEntriesToMixinsOfSet -- * * Helper function of GetAllClassMixinsOf(). Iterate over the * provided class list (mixinOfs) and add every entry to the result * set. If the entry is new, GetAllClassMixinsOf() is called * recursively. * * Results: * Boolean value indicating when done. * * Side effects: * The set of classes is returned in the provided hash-table. * *---------------------------------------------------------------------- */ static bool AddClassListEntriesToMixinsOfSet( Tcl_Interp *interp, Tcl_HashTable *destTablePtr, Tcl_Obj *resultSet, const NsfCmdList *mixinOfs, bool appendResult, const char *pattern, NsfObject *matchObject ) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static bool GetAllClassMixinsOf( Tcl_Interp *interp, Tcl_HashTable *destTablePtr, Tcl_Obj *resultSet, NsfClass *startClass, bool isPCM, bool appendResult, const char *pattern, NsfObject *matchObject ) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static bool AddClassListEntriesToMixinsOfSet( Tcl_Interp *interp, Tcl_HashTable *destTablePtr, Tcl_Obj *resultSet, const NsfCmdList *mixinOfs, bool appendResult, const char *pattern, NsfObject *matchObject ) { const NsfCmdList *m; nonnull_assert(interp != NULL); nonnull_assert(destTablePtr != NULL); nonnull_assert(resultSet != NULL); nonnull_assert(mixinOfs != NULL); for (m = mixinOfs; m != NULL; m = m->nextPtr) { NsfClass *class; int isNew; bool done; /* * We must not have deleted commands in the list */ assert(!TclIsCommandDeleted(m->cmdPtr)); class = NsfGetClassFromCmdPtr(m->cmdPtr); assert(class != NULL); done = AddToResultSet(interp, destTablePtr, resultSet, &class->object, &isNew, appendResult, pattern, matchObject); if (done) { return done; } if (isNew != 0) { done = GetAllClassMixinsOf(interp, destTablePtr, resultSet, class, NSF_TRUE, appendResult, pattern, matchObject); if (done) { return done; } } } return NSF_FALSE; } /* *---------------------------------------------------------------------- * GetAllClassMixinsOf -- * * Computes a set of classes, into which this class was mixed in * via as a class mixin. The function gets recursively all per * class mixins from a class and its subclasses and adds it * into an initialized object ptr hash-table (TCL_ONE_WORD_KEYS) * * Results: * Boolean value indicating when done. * * Side effects: * The set of classes is returned in the provided hash-table * *---------------------------------------------------------------------- */ static bool GetAllClassMixinsOf( Tcl_Interp *interp, Tcl_HashTable *destTablePtr, Tcl_Obj *resultSet, NsfClass *startClass, bool isPCM, bool appendResult, const char *pattern, NsfObject *matchObject ) { NsfClasses *sc; int isNew = 0; bool done = NSF_FALSE; nonnull_assert(interp != NULL); nonnull_assert(destTablePtr != NULL); nonnull_assert(resultSet != NULL); nonnull_assert(startClass != NULL); /*fprintf(stderr, "GetAllClassMixinsOf startClass = %p %s, opt %p, isPCM %d\n", startClass, ClassName(startClass), startClass->opt, isPCM);*/ /* * If the startClass is a per class mixin, add it to the result set */ if (isPCM) { done = AddToResultSet(interp, destTablePtr, resultSet, &startClass->object, &isNew, appendResult, pattern, matchObject); if (done) { return done; } /* * check all subclasses of startClass for mixins */ for (sc = startClass->sub; sc != NULL; sc = sc->nextPtr) { #if !defined(NDEBUG) if (sc->cl == startClass) { /* * Sanity check: it seems that we can create via * __default_superclass a class which has itself as subclass! */ fprintf(stderr, "... STRANGE %p is subclass of %p %s, sub %p\n", (void *)sc->cl, (void *)startClass, ClassName_(startClass), (void *)startClass->sub); continue; } #endif assert(sc->cl != startClass); done = GetAllClassMixinsOf(interp, destTablePtr, resultSet, sc->cl, isPCM, appendResult, pattern, matchObject); if (done) { return done; } } } /* * Check whether "startClass" has a subclass which is a per-class mixin of some other * class(es) */ { NsfClasses *subClasses = TransitiveSubClasses(startClass), *subClass; for (subClass = subClasses; subClass; subClass = subClass->nextPtr) { const NsfClass *subSubClass = subClass->cl; /*fprintf(stderr, "... check subclass = %p %s, opt %p, isPCM %d\n", subSubClass, ClassName(subSubClass), subSubClass->opt, isPCM);*/ if (subSubClass->opt != NULL && subSubClass->opt->isClassMixinOf) { done = AddClassListEntriesToMixinsOfSet(interp, destTablePtr, resultSet, subSubClass->opt->isClassMixinOf, appendResult, pattern, matchObject); if (done) { goto subclassExit; } } } subclassExit: if (subClasses != NULL) { NsfClassListFree(subClasses); } if (done) { return done; } } /* * Check whether "startClass" is a per-class mixin of some other classes. */ if (startClass->opt != NULL && startClass->opt->isClassMixinOf) { done = AddClassListEntriesToMixinsOfSet(interp, destTablePtr, resultSet, startClass->opt->isClassMixinOf, appendResult, pattern, matchObject); } return done; } /* *---------------------------------------------------------------------- * GetAllClassMixins -- * * Computes a set class-mixins of a given class and handles * transitive cases. The classes are added it into an initialized * object ptr hash-table (TCL_ONE_WORD_KEYS) * * Results: * Boolean value indicating when done. * * Side effects: * The set of classes is returned in the provided hash-table * *---------------------------------------------------------------------- */ static bool GetAllClassMixins( Tcl_Interp *interp, Tcl_HashTable *destTablePtr, Tcl_Obj *resultObj, const NsfClass *startClass, bool withGuards, const char *pattern, NsfObject *matchObject ) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static bool GetAllClassMixins( Tcl_Interp *interp, Tcl_HashTable *destTablePtr, Tcl_Obj *resultObj, const NsfClass *startClass, bool withGuards, const char *pattern, NsfObject *matchObject ) { int isNew = 0; NsfClass *class; NsfClasses *sc; bool done = NSF_FALSE; nonnull_assert(interp != NULL); nonnull_assert(destTablePtr != NULL); nonnull_assert(resultObj != NULL); nonnull_assert(startClass != NULL); /* * check this class for class mixins. */ if (startClass->opt != NULL) { NsfCmdList *m; for (m = startClass->opt->classMixins; m != NULL; m = m->nextPtr) { /* * Make sure, there are no deleted commands in the list. */ assert(!TclIsCommandDeleted(m->cmdPtr)); class = NsfGetClassFromCmdPtr(m->cmdPtr); assert(class != NULL); /* fprintf(stderr, "class mixin found: %s\n", ClassName(class)); */ if (withGuards && (m->clientData)) { /* fprintf(stderr, "AddToResultSetWithGuards: %s\n", ClassName(class)); */ done = AddToResultSetWithGuards(interp, destTablePtr, resultObj, class, m->clientData, &isNew, NSF_TRUE, pattern, matchObject); } else { /* fprintf(stderr, "AddToResultSet: %s\n", ClassName(class)); */ done = AddToResultSet(interp, destTablePtr, resultObj, &class->object, &isNew, NSF_TRUE, pattern, matchObject); } if (done) { return done; } if (isNew != 0) { /* fprintf(stderr, "class mixin GetAllClassMixins for: %s (%s)\n", ClassName(class), ClassName(startClass)); */ done = GetAllClassMixins(interp, destTablePtr, resultObj, class, withGuards, pattern, matchObject); if (done) { return done; } } } } /* * Check all superClasses of startCl for class mixins. */ for (sc = startClass->super; sc != NULL; sc = sc->nextPtr) { /* fprintf(stderr, "Superclass GetAllClassMixins for %s (%s)\n", ClassName(sc->cl), ClassName(startClass)); */ done = GetAllClassMixins(interp, destTablePtr, resultObj, sc->cl, withGuards, pattern, matchObject); if (done) { return done; } } return done; } /* *---------------------------------------------------------------------- * RemoveFromClassMixinsOf -- * * Remove the class (provided as a cmd) from all isClassMixinOf * definitions from the provided classes (provided as cmdlist). * * Results: * None. * * Side effects: * Deletes potentially some entries in the isClassMixinOf lists. * *---------------------------------------------------------------------- */ static void RemoveFromClassMixinsOf(Tcl_Command cmd, NsfCmdList *cmdList) nonnull(1) nonnull(2); static void RemoveFromClassMixinsOf(Tcl_Command cmd, NsfCmdList *cmdList) { nonnull_assert(cmd != NULL); nonnull_assert(cmdList != NULL); do { const NsfClass *class = NsfGetClassFromCmdPtr(cmdList->cmdPtr); NsfClassOpt *nclopt = (class != NULL) ? class->opt : NULL; if (nclopt != NULL) { NsfCmdList *del = CmdListFindCmdInList(cmd, nclopt->isClassMixinOf); if (del != NULL) { /* fprintf(stderr, "Removing class %s from isClassMixinOf of class %s\n", ClassName(cl), ObjStr(NsfGetClassFromCmdPtr(cmdList->cmdPtr)->object.cmdName)); */ del = CmdListRemoveFromList(&nclopt->isClassMixinOf, del); CmdListDeleteCmdListEntry(del, GuardDel); } } cmdList = cmdList->nextPtr; } while (cmdList != NULL); } /* *---------------------------------------------------------------------- * RemoveFromObjectMixinsOf -- * * Remove the class (provided as a cmd) from all isObjectMixinOf * definitions from the provided classes (provided as cmdList). * * Results: * None. * * Side effects: * Deletes potentially some entries in the isObjectMixinOf lists. * *---------------------------------------------------------------------- */ static void RemoveFromObjectMixinsOf(Tcl_Command cmd, NsfCmdList *cmdList) nonnull(1) nonnull(2); static void RemoveFromObjectMixinsOf(Tcl_Command cmd, NsfCmdList *cmdList) { nonnull_assert(cmd != NULL); nonnull_assert(cmdList != NULL); do { const NsfClass *class = NsfGetClassFromCmdPtr(cmdList->cmdPtr); NsfClassOpt *clopt = (class != NULL) ? class->opt : NULL; if (clopt != NULL) { NsfCmdList *del = CmdListFindCmdInList(cmd, clopt->isObjectMixinOf); if (del != NULL) { /* fprintf(stderr, "Removing object %s from isObjectMixinOf of Class %s\n", ObjectName(object), ObjStr(NsfGetClassFromCmdPtr(cmdList->cmdPtr)->object.cmdName)); */ del = CmdListRemoveFromList(&clopt->isObjectMixinOf, del); CmdListDeleteCmdListEntry(del, GuardDel); } } /* else fprintf(stderr, "CleanupDestroyObject %s: NULL pointer in mixins!\n", ObjectName(object)); */ cmdList = cmdList->nextPtr; } while(likely(cmdList != NULL)); } /* *---------------------------------------------------------------------- * RemoveFromClassmixins -- * * Remove the class (provided as a cmd) from all class mixins lists * from the provided classes (provided as cmdList). * * Results: * None. * * Side effects: * Deletes potentially some entries in the class mixins lists. * *---------------------------------------------------------------------- */ static void RemoveFromClassmixins(Tcl_Command cmd, NsfCmdList *cmdList) nonnull(1) nonnull(2); static void RemoveFromClassmixins(Tcl_Command cmd, NsfCmdList *cmdList) { nonnull_assert(cmd != NULL); nonnull_assert(cmdList != NULL); do { NsfClass *class = NsfGetClassFromCmdPtr(cmdList->cmdPtr); NsfClassOpt *clopt = (class != NULL) ? class->opt : NULL; if (clopt != NULL) { NsfCmdList *del = CmdListFindCmdInList(cmd, clopt->classMixins); if (del != NULL) { /* fprintf(stderr, "Removing class %s from mixins of object %s\n", ClassName(class), ObjStr(NsfGetObjectFromCmdPtr(cmdList->cmdPtr)->cmdName)); */ del = CmdListRemoveFromList(&clopt->classMixins, del); CmdListDeleteCmdListEntry(del, GuardDel); if (class->object.mixinOrder != NULL) { MixinResetOrder(&class->object); } } } cmdList = cmdList->nextPtr; } while (likely(cmdList != NULL)); } /* *---------------------------------------------------------------------- * RemoveFromObjectMixins -- * * Remove the class (provided as a cmd) from all object mixin lists * from the provided classes (provided as cmdList). * * Results: * None. * * Side effects: * Deletes potentially some entries in the object mixins lists. * *---------------------------------------------------------------------- */ static void RemoveFromObjectMixins(Tcl_Command cmd, NsfCmdList *cmdList) nonnull(1) nonnull(2); static void RemoveFromObjectMixins(Tcl_Command cmd, NsfCmdList *cmdList) { nonnull_assert(cmd != NULL); nonnull_assert(cmdList != NULL); do { NsfObject *object = NsfGetObjectFromCmdPtr(cmdList->cmdPtr); NsfObjectOpt *objopt = (object != 0) ? object->opt : NULL; if (objopt != NULL) { NsfCmdList *del = CmdListFindCmdInList(cmd, objopt->objMixins); if (del != NULL) { /* fprintf(stderr, "Removing class %s from mixins of object %s\n", ClassName(del->clorobj), ObjStr(NsfGetObjectFromCmdPtr(cmdList->cmdPtr)->cmdName)); */ del = CmdListRemoveFromList(&objopt->objMixins, del); CmdListDeleteCmdListEntry(del, GuardDel); if (object->mixinOrder != NULL) { MixinResetOrder(object); } } } cmdList = cmdList->nextPtr; } while (likely(cmdList != NULL)); } /* *---------------------------------------------------------------------- * ResetOrderOfObjectsUsingThisClassAsObjectMixin -- * * Reset the per-object mixin order for all objects having this * class as per-object mixin. * * Results: * None. * * Side effects: * Deletes potentially the mixin list for the objects. * *---------------------------------------------------------------------- */ static void ResetOrderOfObjectsUsingThisClassAsObjectMixin(const NsfClass *class) nonnull(1); static void ResetOrderOfObjectsUsingThisClassAsObjectMixin(const NsfClass *class) { /*fprintf(stderr, "ResetOrderOfObjectsUsingThisClassAsObjectMixin %s - %p\n", ClassName(class), class->opt);*/ nonnull_assert(class != NULL); if (class->opt != NULL) { const NsfCmdList *ml; for (ml = class->opt->isObjectMixinOf; ml != NULL; ml = ml->nextPtr) { NsfObject *object = NsfGetObjectFromCmdPtr(ml->cmdPtr); if (object != NULL) { if (object->mixinOrder != NULL) { MixinResetOrder(object); } object->flags &= ~NSF_MIXIN_ORDER_VALID; } } } } /* *---------------------------------------------------------------------- * MixinInvalidateObjOrders -- * * Reset mixin order for all instances of the class and the * instances of its dependent subclasses. This function is * typically called, when the class hierarchy or the class * mixins have changed and invalidate mixin entries in all * dependent instances. * * Results: * None. * * Side effects: * Deletes potentially the mixin list for the objects and classes. * *---------------------------------------------------------------------- */ static void MixinInvalidateObjOrders(NsfClasses *subClasses) nonnull(1); static void MixinInvalidateObjOrders(NsfClasses *subClasses) { nonnull_assert(subClasses != NULL); /* * Iterate over the subclass hierarchy. */ do { Tcl_HashSearch hSrch; const Tcl_HashEntry *hPtr; Tcl_HashTable *instanceTablePtr; /* * Reset mixin order for all objects having this class as per object mixin */ ResetOrderOfObjectsUsingThisClassAsObjectMixin(subClasses->cl); if (subClasses->cl->parsedParamPtr != NULL) { ParsedParamFree(subClasses->cl->parsedParamPtr); subClasses->cl->parsedParamPtr = NULL; } instanceTablePtr = &subClasses->cl->instances; for (hPtr = Tcl_FirstHashEntry(instanceTablePtr, &hSrch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { NsfObject *object = (NsfObject *)Tcl_GetHashKey(instanceTablePtr, hPtr); assert(object != NULL); if (likely((object->flags & NSF_DURING_DELETE) == 0u) && ((object->flags & NSF_MIXIN_ORDER_DEFINED_AND_VALID) != 0u) ) { MixinResetOrder(object); object->flags &= ~NSF_MIXIN_ORDER_VALID; } } subClasses = subClasses->nextPtr; } while (subClasses != NULL); } /* *---------------------------------------------------------------------- * MixinComputeDefined -- * * This function computes the mixin order for the provided object * and adjusts the mixin flags accordingly. The mixin order is * either * * DEFINED (there are mixins on the instance), * NONE (there are no mixins for the instance), * or INVALID (a class restructuring has occurred. * It is not clear whether mixins are defined or not). * * If the mixin order is INVALID, MixinComputeDefined can be used * to compute the order and set the instance to DEFINED or NONE. * * Results: * None. * * Side effects: * Might alter the mixin order. * *---------------------------------------------------------------------- */ static void MixinComputeDefined(Tcl_Interp *interp, NsfObject *object) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); MixinComputeOrder(interp, object); object->flags |= NSF_MIXIN_ORDER_VALID; if (object->mixinOrder != NULL) { object->flags |= NSF_MIXIN_ORDER_DEFINED; } else { object->flags &= ~NSF_MIXIN_ORDER_DEFINED; } } /* *---------------------------------------------------------------------- * ComputePrecedenceList -- * * Returns the precedence list for the provided object. The * precedence list can optionally include the mixins and the * root-class. If pattern is provided, this is used as well for * filtering. The caller has to free the resulting list via * NsfClassListFree(); * * Results: * Precedence list in form of a class list, potentially NULL due to * filtering. * * Side effects: * Allocated class list. * *---------------------------------------------------------------------- */ static NsfClasses *ComputePrecedenceList(Tcl_Interp *interp, NsfObject *object, const char *pattern, bool withMixins, bool withRootClass) nonnull(1) nonnull(2); static NsfClasses * ComputePrecedenceList(Tcl_Interp *interp, NsfObject *object, const char *pattern, bool withMixins, bool withRootClass) { NsfClasses *precedenceList = NULL, *pcl, **npl = &precedenceList; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); if (withMixins) { if ((object->flags & NSF_MIXIN_ORDER_VALID) == 0u) { MixinComputeDefined(interp, object); } if ((object->flags & NSF_MIXIN_ORDER_DEFINED_AND_VALID) != 0u) { NsfCmdList *ml; for (ml = object->mixinOrder; ml; ml = ml->nextPtr) { NsfClass *mixin = NsfGetClassFromCmdPtr(ml->cmdPtr); if ((pattern != NULL) && (mixin != NULL) && !Tcl_StringMatch(ClassName(mixin), pattern)) { continue; } npl = NsfClassListAdd(npl, mixin, NULL); } } } pcl = PrecedenceOrder(object->cl); for (; pcl != NULL; pcl = pcl->nextPtr) { if (!withRootClass && IsRootClass(pcl->cl)) { continue; } if (pattern != NULL && !Tcl_StringMatch(ClassName(pcl->cl), pattern)) { continue; } npl = NsfClassListAdd(npl, pcl->cl, NULL); } return precedenceList; } /* *---------------------------------------------------------------------- * SeekCurrent -- * * Walk through the command list until the provided command is * reached. return the next entry. If the provided cmd is NULL, * then return the first entry. * * Results: * Command list pointer or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfCmdList *SeekCurrent(const Tcl_Command cmd, register NsfCmdList *cmdListPtr) nonnull(2) NSF_pure; static NsfCmdList * SeekCurrent(const Tcl_Command cmd, register NsfCmdList *cmdListPtr) { nonnull_assert(cmdListPtr != NULL); if (cmd != NULL) { do { if (cmdListPtr->cmdPtr == cmd) { return cmdListPtr->nextPtr; } cmdListPtr = cmdListPtr->nextPtr; } while likely(cmdListPtr != NULL); return NULL; } return cmdListPtr; } /* *---------------------------------------------------------------------- * CanInvokeMixinMethod -- * * Check, whether the provided cmd is allowed to be dispatch in a * mixin. * * Results: * A standard Tcl result or NSF_CHECK_FAILED in case, search should * continue. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int CanInvokeMixinMethod(Tcl_Interp *interp, NsfObject *object, Tcl_Command cmd, NsfCmdList *cmdList) nonnull(1) nonnull(2) nonnull(4); static int CanInvokeMixinMethod(Tcl_Interp *interp, NsfObject *object, Tcl_Command cmd, NsfCmdList *cmdList) { int result = TCL_OK; unsigned int cmdFlags = (unsigned int)Tcl_Command_flags(cmd); nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(cmdList != NULL); if ((cmdFlags & NSF_CMD_CALL_PRIVATE_METHOD) != 0u || ((cmdFlags & NSF_CMD_CLASS_ONLY_METHOD) != 0u && !NsfObjectIsClass(object))) { /* * The command is not applicable for objects (i.e. might crash, * since it expects a class record); therefore, skip it */ return NSF_CHECK_FAILED; } if ((cmdList->clientData != NULL) && !RUNTIME_STATE(interp)->guardCount) { /*fprintf(stderr, "guard call\n");*/ result = GuardCall(object, interp, (Tcl_Obj *)cmdList->clientData, NULL); } return result; } /* *---------------------------------------------------------------------- * MixinSearchProc -- * * Search for a method name in the mixin list of the provided * object. Depending on the state of the mixin stack, the search * starts at the beginning or at the last dispatched, shadowed * method on the mixin path. * * Results: * A standard Tcl result. * Returns as well always cmd (maybe NULL) in cmdPtr. * Returns on success as well the class and the currentCmdPointer * for continuation in next. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int MixinSearchProc( Tcl_Interp *interp, NsfObject *object, const char *methodName, NsfClass **classPtr, Tcl_Command *currentCmdPtr, Tcl_Command *cmdPtr ) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(5) nonnull(6); static int MixinSearchProc( Tcl_Interp *interp, NsfObject *object, const char *methodName, NsfClass **classPtr, Tcl_Command *currentCmdPtr, Tcl_Command *cmdPtr ) { Tcl_Command cmd = NULL; NsfCmdList *cmdList; NsfClass *class = NULL; int result = TCL_OK; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodName != NULL); nonnull_assert(classPtr != NULL); nonnull_assert(currentCmdPtr != NULL); nonnull_assert(cmdPtr != NULL); assert(object->mixinStack != NULL); /* * Ensure that the mixin order is valid. */ assert((object->flags & NSF_MIXIN_ORDER_VALID) != 0u); if (object->mixinOrder == NULL) { return TCL_OK; } cmdList = SeekCurrent(object->mixinStack->currentCmdPtr, object->mixinOrder); RUNTIME_STATE(interp)->currentMixinCmdPtr = (cmdList != NULL) ? cmdList->cmdPtr : NULL; /*fprintf(stderr, "searching for '%s' in %p\n", methodName, cmdList); CmdListPrint(interp, "MixinSearch CL = \n", cmdList);*/ if (unlikely((*classPtr != NULL) && (*cmdPtr != NULL))) { Tcl_Command lastCmdPtr = NULL; /*fprintf(stderr, "... new branch\n");*/ for (; cmdList != NULL; cmdList = cmdList->nextPtr) { NsfClass *class1; /* * Ignore deleted commands */ if (TclIsCommandDeleted(cmdList->cmdPtr)) { continue; } class1 = NsfGetClassFromCmdPtr(cmdList->cmdPtr); assert(class1 != NULL); lastCmdPtr = cmdList->cmdPtr; if (class1 == *classPtr) { /* * The wanted class was found. Check guards and permissions to * determine whether we can invoke this method. */ result = CanInvokeMixinMethod(interp, object, *cmdPtr, cmdList); if (likely(result == TCL_OK)) { class = class1; } else if (result == NSF_CHECK_FAILED) { result = TCL_OK; } /* * No matter, what the result is, stop the search through the mixin * classes here. */ break; } } if (class != NULL) { assert(cmdList != NULL); /* * On success: return class and cmdList->cmdPtr; */ *currentCmdPtr = cmdList->cmdPtr; /*fprintf(stderr, "... mixinsearch success returns %p (class %s)\n", cmd, ClassName(class));*/ } else { /* * We did not find the absolute entry in the mixins. Set the * currentCmdPtr (on the mixin stack) to the last entry to flag, that * the mixin list should not started again on a next. */ *cmdPtr = NULL; *currentCmdPtr = lastCmdPtr; /*fprintf(stderr, "... mixinsearch success failure %p (class %s)\n", cmd, ClassName(class));*/ } return result; } else { for (; cmdList; cmdList = cmdList->nextPtr) { /* * Ignore deleted commands */ if (TclIsCommandDeleted(cmdList->cmdPtr)) { continue; } class = NsfGetClassFromCmdPtr(cmdList->cmdPtr); assert(class != NULL); /* fprintf(stderr, "+++ MixinSearch %s->%s in %p cmdPtr %p clientData %p\n", ObjectName(object), methodName, cmdList, cmdList->cmdPtr, cmdList->clientData); */ cmd = FindMethod(class->nsPtr, methodName); if (cmd == NULL) { continue; } result = CanInvokeMixinMethod(interp, object, cmd, cmdList); if (unlikely(result == TCL_ERROR)) { return result; } else if (result == NSF_CHECK_FAILED) { result = TCL_OK; cmd = NULL; continue; } /* * cmd was found and is applicable. We return class and cmdPtr. */ *classPtr = class; *currentCmdPtr = cmdList->cmdPtr; /*fprintf(stderr, "mixinsearch returns %p (cl %s)\n", cmd, ClassName(class));*/ break; } } *cmdPtr = cmd; return result; } /* * info option for mixins and class mixins */ static int MixinInfo( Tcl_Interp *interp, const NsfCmdList *m, const char *pattern, bool withGuards, const NsfObject *matchObject ) nonnull(1); static int MixinInfo( Tcl_Interp *interp, const NsfCmdList *m, const char *pattern, bool withGuards, const NsfObject *matchObject ) { Tcl_Obj *list = Tcl_NewListObj(0, NULL); nonnull_assert(interp != NULL); /*fprintf(stderr, " mixin info m=%p, pattern %s, matchObject %p\n", m, pattern, matchObject);*/ while (m != NULL) { const NsfClass *mixinClass = NsfGetClassFromCmdPtr(m->cmdPtr); /* fprintf(stderr, " mixin info m=%p, next=%p, pattern %s, matchObject %p\n", m, m->next, pattern, matchObject);*/ if (mixinClass != NULL && (pattern == NULL || (matchObject != NULL && &(mixinClass->object) == matchObject) || (matchObject == NULL && Tcl_StringMatch(ObjStr(mixinClass->object.cmdName), pattern)))) { if (withGuards && (m->clientData != NULL)) { Tcl_Obj *l = Tcl_NewListObj(0, NULL); Tcl_Obj *g = (Tcl_Obj *) m->clientData; Tcl_ListObjAppendElement(interp, l, mixinClass->object.cmdName); Tcl_ListObjAppendElement(interp, l, NsfGlobalObjs[NSF_GUARD_OPTION]); Tcl_ListObjAppendElement(interp, l, g); Tcl_ListObjAppendElement(interp, list, l); } else { Tcl_ListObjAppendElement(interp, list, mixinClass->object.cmdName); } if (matchObject != NULL) { break; } } m = m->nextPtr; } Tcl_SetObjResult(interp, list); return TCL_OK; } /* * info option for mixinofs and isClassMixinOf */ static Tcl_Command MixinSearchMethodByName(NsfCmdList *mixinList, const char *name, NsfClass **classPtr) nonnull(1) nonnull(2) nonnull(3); static Tcl_Command MixinSearchMethodByName(NsfCmdList *mixinList, const char *name, NsfClass **classPtr) { Tcl_Command cmd; nonnull_assert(mixinList != NULL); nonnull_assert(name != NULL); nonnull_assert(classPtr != NULL); do { NsfClass *foundClass = NsfGetClassFromCmdPtr(mixinList->cmdPtr); if ((foundClass != NULL) && SearchCMethod(foundClass, name, &cmd)) { *classPtr = foundClass; return cmd; } mixinList = mixinList->nextPtr; } while (mixinList != NULL); return NULL; } /* * Filter-Commands */ /* * The search method implements filter search order for object and * class filter: first a given name is interpreted as fully qualified * method name. If no method is found, a proc is searched with fully * name. Otherwise the simple name is searched on the heritage order: * object (only for per-object filters), class, metaclass */ static Tcl_Command FilterSearch(const char *name, NsfObject *startingObject, NsfClass *startingClass, NsfClass **classPtr) nonnull(1) nonnull(4); static Tcl_Command FilterSearch(const char *name, NsfObject *startingObject, NsfClass *startingClass, NsfClass **classPtr) { Tcl_Command cmd = NULL; nonnull_assert(name != NULL); nonnull_assert(classPtr != NULL); if (startingObject != NULL) { NsfObjectOpt *opt = startingObject->opt; /* * the object-specific filter can also be defined on the object's * class, its hierarchy, or the respective class mixins; thus use the * object's class as start point for the class-specific search then ... */ startingClass = startingObject->cl; /* * search for filters on object mixins */ if (opt != NULL && opt->objMixins != NULL && (cmd = MixinSearchMethodByName(opt->objMixins, name, classPtr)) ) { return cmd; } } /* * Search for class filters on class mixins */ if (startingClass != NULL) { NsfClassOpt *opt = startingClass->opt; if (opt != NULL && opt->classMixins != NULL) { if ((cmd = MixinSearchMethodByName(opt->classMixins, name, classPtr))) { return cmd; } } } /* * Search for object procs that are used as filters */ if ((startingObject != NULL) && (startingObject->nsPtr != NULL)) { /*fprintf(stderr, "search filter %s as proc \n", name);*/ if ((cmd = FindMethod(startingObject->nsPtr, name))) { *classPtr = (NsfClass *)startingObject; return cmd; } } /* * Ok, no filter on obj or mixins -> search class */ if (startingClass != NULL) { *classPtr = SearchCMethod(startingClass, name, &cmd); if (*classPtr == NULL) { /* * If no filter is found yet -> search the metaclass */ *classPtr = SearchCMethod(startingClass->object.cl, name, &cmd); } } return cmd; } /* * Filter Guards */ /* *---------------------------------------------------------------------- * GuardCheck -- * * Check, a filter guard. * * Results: * A standard Tcl result or NSF_CHECK_FAILED in case, search should * continue. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int GuardCheck(Tcl_Interp *interp, Tcl_Obj *guardObj) nonnull(1) nonnull(2); static int GuardCheck(Tcl_Interp *interp, Tcl_Obj *guardObj) { NsfRuntimeState *rst; int result; nonnull_assert(interp != NULL); nonnull_assert(guardObj != NULL); /* * if there are more than one filter guard for this filter * (i.e. they are inherited), then they are OR combined * -> if one check succeeds => return TCL_OK */ /*fprintf(stderr, "checking guard **%s**\n", ObjStr(guardObj));*/ rst = RUNTIME_STATE(interp); rst->guardCount++; result = CheckConditionInScope(interp, guardObj); rst->guardCount--; /*fprintf(stderr, "checking guard **%s** returned rc=%d\n", ObjStr(guardObj), rc);*/ if (likely(result == TCL_OK)) { /* fprintf(stderr, " +++ OK\n"); */ } else if (unlikely(result == TCL_ERROR)) { Tcl_Obj *sr = Tcl_GetObjResult(interp); INCR_REF_COUNT(sr); NsfPrintError(interp, "Guard error: '%s'\n%s", ObjStr(guardObj), ObjStr(sr)); DECR_REF_COUNT(sr); } else { /* fprintf(stderr, " +++ FAILED\n"); */ result = NSF_CHECK_FAILED; } return result; } /* static void GuardPrint(Tcl_Interp *interp, ClientData clientData) { Tcl_Obj *guardObj = (Tcl_Obj *) clientData; fprintf(stderr, " +++ \n"); if (guardObj != NULL) { fprintf(stderr, " * %s \n", ObjStr(guardObj)); } fprintf(stderr, " +++ \n"); } */ static void GuardDel(NsfCmdList *guardList) { nonnull_assert(guardList != NULL); /*fprintf(stderr, "GuardDel %p clientData = %p\n", guardList, (guardList != NULL) ? guardList->clientData : NULL);*/ if (guardList->clientData != NULL) { DECR_REF_COUNT2("guardObj", (Tcl_Obj *)guardList->clientData); guardList->clientData = NULL; } } NSF_INLINE static void GuardAdd(NsfCmdList *guardList, Tcl_Obj *guardObj) { nonnull_assert(guardList != NULL); nonnull_assert(guardObj != NULL); GuardDel(guardList); if (strlen(ObjStr(guardObj)) > 0) { INCR_REF_COUNT2("guardObj", guardObj); guardList->clientData = guardObj; /*fprintf(stderr, "guard added to %p cmdPtr=%p, clientData= %p\n", guardList, guardList->cmdPtr, guardList->clientData); */ } } static int GuardCall(NsfObject *object, Tcl_Interp *interp, Tcl_Obj *guardObj, NsfCallStackContent *cscPtr) { int result = TCL_OK; Tcl_Obj *res = Tcl_GetObjResult(interp); /* save the result */ CallFrame frame, *framePtr = &frame; nonnull_assert(object != NULL); nonnull_assert(interp != NULL); nonnull_assert(guardObj != NULL); INCR_REF_COUNT(res); /* * For the guard push a fake call-frame on the Tcl stack so that * e.g. a "self calledproc" and other methods in the guard behave * like in the proc. */ if (cscPtr != NULL) { Nsf_PushFrameCsc(interp, cscPtr, framePtr); } else { #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, object, framePtr); #pragma GCC diagnostic pop } result = GuardCheck(interp, guardObj); if (cscPtr != NULL) { Nsf_PopFrameCsc(interp, framePtr); } else { Nsf_PopFrameObj(interp, framePtr); } if (result != TCL_ERROR) { Tcl_SetObjResult(interp, res); /* restore the result */ } DECR_REF_COUNT(res); return result; } /* *---------------------------------------------------------------------- * GuardAddFromDefinitionList -- * * Add a guard to the specified destination list (first arg) from a * list of definitions (last arg). If the provided cmd is found in * the list of definitions, it is added to the destination list if * it has non-null client data. * * Results: * Returns Boolean value depending on whether the cmd is part of the * definition list. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool GuardAddFromDefinitionList(NsfCmdList *dest, Tcl_Command interceptorCmd, NsfCmdList *interceptorDefList) nonnull(1) nonnull(2) nonnull(3); static bool GuardAddFromDefinitionList(NsfCmdList *dest, Tcl_Command interceptorCmd, NsfCmdList *interceptorDefList) { NsfCmdList *h; nonnull_assert(interceptorCmd != NULL); nonnull_assert(dest != NULL); nonnull_assert(interceptorDefList != NULL); h = CmdListFindCmdInList(interceptorCmd, interceptorDefList); if (h != NULL) { if (h->clientData != NULL) { GuardAdd(dest, (Tcl_Obj *) h->clientData); } return NSF_TRUE; } return NSF_FALSE; } /* *---------------------------------------------------------------------- * GuardAddInheritedGuards -- * * Add an inherited guards to the provided destination list. * * Results: * None. * * Side effects: * Updates potentially destination list * *---------------------------------------------------------------------- */ static void GuardAddInheritedGuards(Tcl_Interp *interp, NsfCmdList *dest, NsfObject *object, Tcl_Command filterCmd) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static void GuardAddInheritedGuards(Tcl_Interp *interp, NsfCmdList *dest, NsfObject *object, Tcl_Command filterCmd) { NsfClasses *pl; bool guardAdded = NSF_FALSE; NsfObjectOpt *opt; nonnull_assert(filterCmd != NULL); nonnull_assert(interp != NULL); nonnull_assert(dest != NULL); nonnull_assert(object != NULL); /* * Search guards for class filters registered on mixins. */ if (((object->flags & NSF_MIXIN_ORDER_VALID)) == 0u) { MixinComputeDefined(interp, object); } if ((object->flags & NSF_MIXIN_ORDER_DEFINED_AND_VALID) != 0u) { NsfCmdList *ml; for (ml = object->mixinOrder; ml != NULL && !guardAdded; ml = ml->nextPtr) { NsfClass *mixin = NsfGetClassFromCmdPtr(ml->cmdPtr); if (mixin != NULL && mixin->opt != NULL && mixin->opt->classFilters != NULL) { guardAdded = GuardAddFromDefinitionList(dest, filterCmd, mixin->opt->classFilters); } } } /* * Search per-object filters. */ opt = object->opt; if (!guardAdded && (opt != NULL) && (opt->objFilters != NULL)) { guardAdded = GuardAddFromDefinitionList(dest, filterCmd, opt->objFilters); } if (!guardAdded) { /* * Search per-class filters. */ for (pl = PrecedenceOrder(object->cl); !guardAdded && (pl != NULL); pl = pl->nextPtr) { NsfClassOpt *clopt = pl->cl->opt; if (clopt != NULL && clopt->classFilters != NULL) { guardAdded = GuardAddFromDefinitionList(dest, filterCmd, clopt->classFilters); } } /* * if this is not a registered filter, it is an inherited filter, like: * Class create A * A method f ... * Class create B -superclass A * B method {{f {}}} * B filter f * -> get the guard from the filter that inherits it (here B->f) */ if (!guardAdded) { NsfCmdList *registeredFilter = CmdListFindNameInList(interp, (char *) Tcl_GetCommandName(interp, filterCmd), object->filterOrder); if (registeredFilter && registeredFilter->clientData) { GuardAdd(dest, (Tcl_Obj *) registeredFilter->clientData); } } } } /* *---------------------------------------------------------------------- * GuardList -- * * Set interp result to a named guard in the provided * guardList. The variable "guardList" might be NULL. * * Results: * Sets the interpreter's result object. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int GuardList(Tcl_Interp *interp, NsfCmdList *guardList, const char *interceptorName) nonnull(1) nonnull(3); static int GuardList(Tcl_Interp *interp, NsfCmdList *guardList, const char *interceptorName) { nonnull_assert(interp != NULL); nonnull_assert(interceptorName != NULL); if (guardList != NULL) { /* * Try to find simple name first. */ NsfCmdList *h = CmdListFindNameInList(interp, interceptorName, guardList); if (h == NULL) { /* * Maybe it is a qualified name. */ Tcl_Command cmd = NSFindCommand(interp, interceptorName); if (cmd != NULL) { h = CmdListFindCmdInList(cmd, guardList); } } if (h != NULL) { Tcl_ResetResult(interp); if (h->clientData != NULL) { Tcl_Obj *g = (Tcl_Obj *) h->clientData; Tcl_SetObjResult(interp, g); } return TCL_OK; } } return NsfPrintError(interp, "info guard: can't find filter/mixin %s", interceptorName); } /* *---------------------------------------------------------------------- * FilterAddActive -- * * Add a method name to the set of methods, which were used as filters in * the current interp. * * TODO: let the set shrink, when filters are removed. * * Results: * None. * * Side effects: * Adding or updating of a hash entry * *---------------------------------------------------------------------- */ static void FilterAddActive(Tcl_Interp *interp, const char *methodName) nonnull(1) nonnull(2); static void FilterAddActive(Tcl_Interp *interp, const char *methodName) { Tcl_HashEntry *hPtr; int newItem; nonnull_assert(interp != NULL); nonnull_assert(methodName != NULL); hPtr = Tcl_CreateHashEntry(&RUNTIME_STATE(interp)->activeFilterTablePtr, methodName, &newItem); if (newItem != 0) { Tcl_SetHashValue(hPtr, INT2PTR(1)); } else { long count = PTR2INT(Tcl_GetHashValue(hPtr)); Tcl_SetHashValue(hPtr, INT2PTR(count+1)); } } /* *---------------------------------------------------------------------- * FilterIsActive -- * * Check, whether a method name is in the set of methods, which * were used as filters in the current interp. * * Results: * A Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool FilterIsActive(Tcl_Interp *interp, const char *methodName) nonnull(1) nonnull(2); static bool FilterIsActive(Tcl_Interp *interp, const char *methodName) { const Tcl_HashEntry *hPtr; nonnull_assert(interp != NULL); nonnull_assert(methodName != NULL); hPtr = Tcl_CreateHashEntry(&RUNTIME_STATE(interp)->activeFilterTablePtr, methodName, NULL); return (hPtr != NULL); } /* *---------------------------------------------------------------------- * FiltersDefined -- * * Return the number of defined distinct names of filters. * * Results: * Positive number. * * Side effects: * None. * *---------------------------------------------------------------------- */ static TCL_SIZE_T FiltersDefined(Tcl_Interp *interp) nonnull(1) NSF_pure; static TCL_SIZE_T FiltersDefined(Tcl_Interp *interp) { nonnull_assert(interp != NULL); return Tcl_HashSize(&RUNTIME_STATE(interp)->activeFilterTablePtr); } /* *---------------------------------------------------------------------- * FilterAdd -- * * Append a filter command to the 'filterList' of an obj/class * * Results: * A standard Tcl result. * * Side effects: * Sets the interpreter's result object in error cases. * *---------------------------------------------------------------------- */ static int FilterAdd(Tcl_Interp *interp, NsfCmdList **filterList, Tcl_Obj *filterregObj, NsfObject *startingObject, NsfClass *startingClass) nonnull(1) nonnull(2) nonnull(3); static int FilterAdd(Tcl_Interp *interp, NsfCmdList **filterList, Tcl_Obj *filterregObj, NsfObject *startingObject, NsfClass *startingClass) { Tcl_Obj *filterObj = NULL; Tcl_Obj *guardObj = NULL; Tcl_Command cmd = NULL; NsfClass *class = NULL; int result = TCL_OK; nonnull_assert(interp != NULL); nonnull_assert(filterList != NULL); nonnull_assert(filterregObj != NULL); /* * When the provided nameObj is of type NsfFilterregObjType, the nsf specific * converter was called already; otherwise call the converter here. */ if (filterregObj->typePtr != &NsfFilterregObjType) { /*fprintf(stderr, "FilterAdd: convert %s in FilterAdd\n", ObjStr(filterregObj));*/ if (Tcl_ConvertToType(interp, filterregObj, &NsfFilterregObjType) != TCL_OK) { result = TCL_ERROR; } } else { /*fprintf(stderr, "FilterAdd: %s already converted\n", ObjStr(filterregObj));*/ } if (result == TCL_OK) { result = NsfFilterregGet(interp, filterregObj, &filterObj, &guardObj); if (result == TCL_OK) { const char *filterName = ObjStr(filterObj); cmd = FilterSearch(filterName, startingObject, startingClass, &class); if (cmd == NULL) { if (startingObject != NULL) { result = NsfPrintError(interp, "object filter: can't find filterproc '%s' on %s ", filterName, ObjectName(startingObject)); } else { result = NsfPrintError(interp, "class filter: can't find filterproc '%s' on %s ", filterName, ClassName(startingClass)); } assert(result == TCL_ERROR); } } } if (result == TCL_OK) { NsfCmdList *new; /*fprintf(stderr, " +++ adding filter %s cl %p\n", ObjStr(nameObj), class);*/ new = CmdListAdd(filterList, cmd, class, /*noDuplicates*/ NSF_TRUE, NSF_TRUE); FilterAddActive(interp, ObjStr(filterObj)); if (guardObj != NULL) { GuardAdd(new, guardObj); } else if (new->clientData != NULL) { GuardDel(new); } } return result; } /* *---------------------------------------------------------------------- * FilterResetOrder -- * * Reset the filter order cached in obj->filterOrder * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void FilterResetOrder(NsfObject *object) nonnull(1); static void FilterResetOrder(NsfObject *object) { nonnull_assert(object != NULL); CmdListFree(&object->filterOrder, GuardDel); object->filterOrder = NULL; } /* *---------------------------------------------------------------------- * FilterSearchAgain -- * * Search the filter in the hierarchy again with FilterSearch, e.g. * upon changes in the class hierarchy or mixins that carry the * filter command, so that we can be sure it is still reachable. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void FilterSearchAgain(Tcl_Interp *interp, NsfCmdList **filters, NsfObject *startingObject, NsfClass *startingClass) nonnull(1) nonnull(2); static void FilterSearchAgain(Tcl_Interp *interp, NsfCmdList **filters, NsfObject *startingObject, NsfClass *startingClass) { NsfCmdList *cmdList; nonnull_assert(interp != NULL); nonnull_assert(filters != NULL); CmdListRemoveDeleted(filters, GuardDel); cmdList = *filters; while (cmdList != NULL) { NsfCmdList *del = NULL; NsfClass *class = NULL; const char *simpleName = Tcl_GetCommandName(interp, cmdList->cmdPtr); Tcl_Command cmd = FilterSearch(simpleName, startingObject, startingClass, &class); if (cmd == NULL) { del = CmdListRemoveFromList(filters, cmdList); /* * The actual deletion via CmdListDeleteCmdListEntry is deferred to the * end of the loop block, otherwise for del == cmdList, we risk running * into an invalid pointer access. */ } else if (cmd != cmdList->cmdPtr) { CmdListReplaceCmd(cmdList, cmd, class); } cmdList = cmdList->nextPtr; if (del != NULL) { CmdListDeleteCmdListEntry(del, GuardDel); } } } /* *---------------------------------------------------------------------- * FilterInvalidateObjOrders -- * * Invalidate filter entries in all dependent instances. This will * be e.g. necessary, when the class hierarchy or the class filters * have changed. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void FilterInvalidateObjOrders(Tcl_Interp *interp, NsfClasses *subClasses) nonnull(1) nonnull(2); static void FilterInvalidateObjOrders(Tcl_Interp *interp, NsfClasses *subClasses) { nonnull_assert(interp != NULL); nonnull_assert(subClasses != NULL); do { Tcl_HashSearch hSrch; const Tcl_HashEntry *hPtr; assert(subClasses->cl); hPtr = Tcl_FirstHashEntry(&subClasses->cl->instances, &hSrch); /* * Recalculate the commands of all class-filter registrations. */ if (subClasses->cl->opt != NULL) { FilterSearchAgain(interp, &subClasses->cl->opt->classFilters, NULL, subClasses->cl); } for (; hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { NsfObject *object = (NsfObject *)Tcl_GetHashKey(&subClasses->cl->instances, hPtr); FilterResetOrder(object); object->flags &= ~NSF_FILTER_ORDER_VALID; /* * Recalculate the commands of all object filter registrations. */ if (object->opt != NULL) { FilterSearchAgain(interp, &object->opt->objFilters, object, NULL); } } subClasses = subClasses->nextPtr; } while (likely(subClasses != NULL)); } /* *---------------------------------------------------------------------- * FilterRemoveDependentFilterCmds -- * * * Remove all filters from all subclasses that refer to * "removeClass". This function is e.g. used to remove filters * defined in superclass list from a dependent class. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* */ static void FilterRemoveDependentFilterCmds(NsfClass *removeClass, NsfClasses *subClasses) nonnull(1) nonnull(2); static void FilterRemoveDependentFilterCmds(NsfClass *removeClass, NsfClasses *subClasses) { nonnull_assert(removeClass != NULL); nonnull_assert(subClasses != NULL); /*fprintf(stderr, "FilterRemoveDependentFilterCmds removeClass %p %s\n", removeClass, ObjStr(removeClass->object.cmdName));*/ do { Tcl_HashSearch hSrch; const Tcl_HashEntry *hPtr; NsfClassOpt *opt; assert(subClasses->cl); hPtr = Tcl_FirstHashEntry(&subClasses->cl->instances, &hSrch); opt = subClasses->cl->opt; if (opt != NULL) { CmdListRemoveContextClassFromList(&opt->classFilters, removeClass, GuardDel); } for (; hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { NsfObject *object = (NsfObject *) Tcl_GetHashKey(&subClasses->cl->instances, hPtr); if (object->opt != NULL) { CmdListRemoveContextClassFromList(&object->opt->objFilters, removeClass, GuardDel); } } subClasses = subClasses->nextPtr; } while (subClasses != NULL); } /* *---------------------------------------------------------------------- * MethodHandleObj -- * * Builds a methodHandle from a method name. We assume, the * methodName is not fully qualified (i.e. it must not start with a * colon). * * Results: * fresh Tcl_Obj * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj * MethodHandleObj(NsfObject *object, int withPer_object, const char *methodName) nonnull(1) nonnull(3) returns_nonnull; static Tcl_Obj * MethodHandleObj(NsfObject *object, int withPer_object, const char *methodName) { Tcl_Obj *resultObj; nonnull_assert(object != NULL); nonnull_assert(methodName != NULL); assert(*methodName != ':'); if (withPer_object == 1) { resultObj = Tcl_NewStringObj("", 0); } else { resultObj = Tcl_NewStringObj(nsfClassesPrefix, (int)nsfClassesPrefixLength); } Tcl_AppendObjToObj(resultObj, object->cmdName); Tcl_AppendStringsToObj(resultObj, "::", methodName, (char *) NULL); return resultObj; } /* *---------------------------------------------------------------------- * FilterInfo -- * * Set the interp results with a Tcl list containing the content of * the filter list. The options withGuards and withMethodHandles * can be used for different output structures * * Results: * Standard Tcl results * * Side effects: * Sets the interpreter's result object. * *---------------------------------------------------------------------- */ static int FilterInfo(Tcl_Interp *interp, NsfCmdList *f, const char *pattern, bool withGuards, bool withMethodHandles) nonnull(1); static int FilterInfo(Tcl_Interp *interp, NsfCmdList *f, const char *pattern, bool withGuards, bool withMethodHandles) { Tcl_Obj *list = Tcl_NewListObj(0, NULL); nonnull_assert(interp != NULL); /* * Guard lists should only have unqualified filter lists when "withGuards" * is activated. "withMethodHandles" has no effect when "withGuards" is * specified. */ if (withGuards) { withMethodHandles = NSF_FALSE; } while (f != NULL) { const char *simpleName = Tcl_GetCommandName(interp, f->cmdPtr); if (pattern == NULL || Tcl_StringMatch(simpleName, pattern)) { if (withGuards && (f->clientData != NULL)) { Tcl_Obj *innerList = Tcl_NewListObj(0, NULL); Tcl_Obj *g = (Tcl_Obj *) f->clientData; Tcl_ListObjAppendElement(interp, innerList, Tcl_NewStringObj(simpleName, TCL_INDEX_NONE)); Tcl_ListObjAppendElement(interp, innerList, NsfGlobalObjs[NSF_GUARD_OPTION]); Tcl_ListObjAppendElement(interp, innerList, g); Tcl_ListObjAppendElement(interp, list, innerList); } else { if (withMethodHandles) { NsfClass *filterClass = f->clorobj; Tcl_ListObjAppendElement(interp, list, MethodHandleObj((NsfObject *)filterClass, !NsfObjectIsClass(&filterClass->object), simpleName)); } else { Tcl_ListObjAppendElement(interp, list, Tcl_NewStringObj(simpleName, TCL_INDEX_NONE)); } } } f = f->nextPtr; } Tcl_SetObjResult(interp, list); return TCL_OK; } /* *---------------------------------------------------------------------- * FilterComputeOrderFullList -- * * Compute a fresh list of filters and append it to the filterList. * * Results: * None. * * Side effects: * Updating filterList * *---------------------------------------------------------------------- */ static void FilterComputeOrderFullList( Tcl_Interp *interp, NsfCmdList **filters, NsfCmdList **filterList ) nonnull(1) nonnull(2) nonnull(3); static void FilterComputeOrderFullList( Tcl_Interp *interp, NsfCmdList **filters, NsfCmdList **filterList ) { const NsfCmdList *f ; const NsfClasses *pl; NsfClass *filterClass; nonnull_assert(interp != NULL); nonnull_assert(filters != NULL); nonnull_assert(filterList != NULL); /* * Ensure that no epoched command is in the filters list. */ CmdListRemoveDeleted(filters, GuardDel); for (f = *filters; f != NULL; f = f->nextPtr) { const char *simpleName = Tcl_GetCommandName(interp, f->cmdPtr); filterClass = f->clorobj; CmdListAdd(filterList, f->cmdPtr, filterClass, /*noDuplicates*/ NSF_FALSE, NSF_TRUE); if (filterClass != NULL && !NsfObjectIsClass(&filterClass->object)) { /* * Get the class from the object for per-object filter. */ filterClass = ((NsfObject *)filterClass)->cl; } /* * If we have a filter class -> search up the inheritance hierarchy. */ if (filterClass != NULL) { pl = PrecedenceOrder(filterClass); if (pl != NULL && pl->nextPtr != NULL) { /* * Don't search on the start class again. */ pl = pl->nextPtr; /* * Now go up the hierarchy. */ for(; pl != NULL; pl = pl->nextPtr) { Tcl_Command pi = FindMethod(pl->cl->nsPtr, simpleName); if (pi != NULL) { CmdListAdd(filterList, pi, pl->cl, /*noDuplicates*/ NSF_FALSE, NSF_TRUE); /* fprintf(stderr, " %s::%s, ", ClassName(pl->cl), simpleName); */ } } } } } /*CmdListPrint(interp, "FilterComputeOrderFullList....\n", *filterList);*/ } /* *---------------------------------------------------------------------- * FilterComputeOrder -- * * Computes a linearized order of object and class filter. Then * duplicates in the full list and with the class inheritance list * of 'obj' are eliminated. The precedence rule is that the last * occurrence makes it into the final list (object->filterOrder). * * Results: * None. * * Side effects: * Sets the interpreter's result object. * *---------------------------------------------------------------------- */ static void FilterComputeOrder(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); static void FilterComputeOrder(Tcl_Interp *interp, NsfObject *object) { NsfCmdList *filterList = NULL, *next, *checker, *newList; NsfClasses *pl; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); if (object->filterOrder != NULL) { FilterResetOrder(object); } /* fprintf(stderr, " List: ", ObjectName(object)); */ /* * Append class filters registered for mixins. */ if ((object->flags & NSF_MIXIN_ORDER_VALID) == 0u) { MixinComputeDefined(interp, object); } if ((object->flags & NSF_MIXIN_ORDER_DEFINED_AND_VALID) != 0u) { NsfCmdList *ml; for (ml = object->mixinOrder; ml != NULL; ml = ml->nextPtr) { NsfClass *mixin = NsfGetClassFromCmdPtr(ml->cmdPtr); if (mixin != NULL && mixin->opt != NULL && mixin->opt->classFilters != NULL) { FilterComputeOrderFullList(interp, &mixin->opt->classFilters, &filterList); } } } /* * Append per-obj filters. */ if (object->opt != NULL) { FilterComputeOrderFullList(interp, &object->opt->objFilters, &filterList); } /* * Append per-class filters. */ for (pl = PrecedenceOrder(object->cl); pl != NULL; pl = pl->nextPtr) { NsfClassOpt *clopt = pl->cl->opt; if (clopt != NULL && clopt->classFilters != NULL) { FilterComputeOrderFullList(interp, &clopt->classFilters, &filterList); } } /* * Use no duplicates & no classes of the precedence order * on the resulting list. */ while (filterList != NULL) { /* * Search for filterList->cmdPtr */ for (checker = next = filterList->nextPtr; checker != NULL; checker = checker->nextPtr) { if (checker->cmdPtr == filterList->cmdPtr) { break; } } if (checker == NULL) { /* * filterList->cmdPtr was found */ newList = CmdListAdd(&object->filterOrder, filterList->cmdPtr, filterList->clorobj, /*noDuplicates*/ NSF_FALSE, NSF_TRUE); GuardAddInheritedGuards(interp, newList, object, filterList->cmdPtr); /* GuardPrint(interp, newList->clientData); */ } CmdListDeleteCmdListEntry(filterList, GuardDel); filterList = next; } } /* *---------------------------------------------------------------------- * FilterComputeDefined -- * * Compute the state of the filter order. The filter order is either * * DEFINED (there are filter on the instance), * NONE (there are no filter for the instance), * or INVALID (a class restructuring has occurred, thus it is not clear whether filters are defined or not). * * If it is INVALID FilterComputeDefined can be used to compute the * order and set the instance to DEFINE or NONE. * * Results: * None. * * Side effects: * Updating object-flags * *---------------------------------------------------------------------- */ static void FilterComputeDefined(Tcl_Interp *interp, NsfObject *object) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); FilterComputeOrder(interp, object); object->flags |= NSF_FILTER_ORDER_VALID; if (object->filterOrder != NULL) { object->flags |= NSF_FILTER_ORDER_DEFINED; } else { object->flags &= ~NSF_FILTER_ORDER_DEFINED; } } /* *---------------------------------------------------------------------- * FilterStackPush -- * * Push a filter stack information on this object and initialize it with * calledProc. * * Results: * None. * * Side effects: * Updating object->filterStack * *---------------------------------------------------------------------- */ static void FilterStackPush(NsfObject *object, Tcl_Obj *calledProc) nonnull(1) nonnull(2); static void FilterStackPush(NsfObject *object, Tcl_Obj *calledProc) { register NsfFilterStack *h = NEW(NsfFilterStack); nonnull_assert(object != NULL); nonnull_assert(calledProc != NULL); h->currentCmdPtr = NULL; h->calledProc = calledProc; INCR_REF_COUNT(h->calledProc); h->nextPtr = object->filterStack; object->filterStack = h; } /* *---------------------------------------------------------------------- * FilterStackPush -- * * Pop filter stack information from the specified object * * Results: * None. * * Side effects: * Free filter stack info * *---------------------------------------------------------------------- */ static void FilterStackPop(NsfObject *object) nonnull(1); static void FilterStackPop(NsfObject *object) { register NsfFilterStack *h; nonnull_assert(object != NULL); h = object->filterStack; object->filterStack = h->nextPtr; /* * Free stack entry. */ DECR_REF_COUNT(h->calledProc); FREE(NsfFilterStack, h); } /* *---------------------------------------------------------------------- * FilterFindReg -- * * Search through the filter list on obj and class hierarchy for * registration of a cmdPtr as filter * * Results: * Returns a Tcl list with the filter registration, like: * " filter , " filter , * or an empty list, if not registered * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj * FilterFindReg(Tcl_Interp *interp, NsfObject *object, Tcl_Command cmd) nonnull(1) nonnull(2) nonnull(3) returns_nonnull; static Tcl_Obj * FilterFindReg(Tcl_Interp *interp, NsfObject *object, Tcl_Command cmd) { Tcl_Obj *list = Tcl_NewListObj(0, NULL); NsfClasses *pl; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(cmd != NULL); /* * Search per-object filters. */ if (object->opt != NULL && object->opt->objFilters != NULL && CmdListFindCmdInList(cmd, object->opt->objFilters)) { Tcl_ListObjAppendElement(interp, list, object->cmdName); Tcl_ListObjAppendElement(interp, list, NsfGlobalObjs[NSF_OBJECT]); Tcl_ListObjAppendElement(interp, list, NsfGlobalObjs[NSF_FILTER]); Tcl_ListObjAppendElement(interp, list, Tcl_NewStringObj(Tcl_GetCommandName(interp, cmd), TCL_INDEX_NONE)); return list; } /* * Search per-class filters. */ for (pl = PrecedenceOrder(object->cl); pl != NULL; pl = pl->nextPtr) { NsfClassOpt *opt = pl->cl->opt; if (opt != NULL && opt->classFilters != NULL) { if (CmdListFindCmdInList(cmd, opt->classFilters)) { Tcl_ListObjAppendElement(interp, list, pl->cl->object.cmdName); Tcl_ListObjAppendElement(interp, list, NsfGlobalObjs[NSF_FILTER]); Tcl_ListObjAppendElement(interp, list, Tcl_NewStringObj(Tcl_GetCommandName(interp, cmd), TCL_INDEX_NONE)); return list; } } } return list; } /* *---------------------------------------------------------------------- * FilterSearchProc -- * * FilterSearchProc seeks the current filter and the relevant calling * information (class and currentCmd). The function assumes to be called * with an existing filterStack. * * Results: * Tcl_Command or NULL * * Side effects: * Updates *currentCmd and **cl * *---------------------------------------------------------------------- */ /* */ static Tcl_Command FilterSearchProc(Tcl_Interp *interp, NsfObject *object, Tcl_Command *currentCmd, NsfClass **classPtr) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static Tcl_Command FilterSearchProc(Tcl_Interp *interp, NsfObject *object, Tcl_Command *currentCmd, NsfClass **classPtr) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(currentCmd != NULL); nonnull_assert(classPtr != NULL); assert(object->filterStack != NULL); /* * Ensure that the filter order is not invalid, otherwise compute order * FilterComputeDefined(interp, object); */ assert(object->flags & NSF_FILTER_ORDER_VALID); if (object->filterOrder != NULL) { NsfCmdList *cmdList; *currentCmd = NULL; cmdList = SeekCurrent(object->filterStack->currentCmdPtr, object->filterOrder); while (cmdList != NULL) { /*fprintf(stderr, "FilterSearchProc found %s\n", Tcl_GetCommandName(interp, (Tcl_Command)cmdList->cmdPtr));*/ if (Tcl_Command_cmdEpoch(cmdList->cmdPtr) != 0) { cmdList = cmdList->nextPtr; } else if (FilterActiveOnObj(interp, object, cmdList->cmdPtr)) { /* fprintf(stderr, "Filter <%s> -- Active on: %s\n", Tcl_GetCommandName(interp, (Tcl_Command)cmdList->cmdPtr), ObjectName(object)); */ object->filterStack->currentCmdPtr = cmdList->cmdPtr; cmdList = SeekCurrent(object->filterStack->currentCmdPtr, object->filterOrder); } else { /* * Ok, ee found it */ if (cmdList->clorobj && !NsfObjectIsClass(&cmdList->clorobj->object)) { *classPtr = NULL; } else { *classPtr = cmdList->clorobj; } *currentCmd = cmdList->cmdPtr; /* fprintf(stderr, "FilterSearchProc - found: %s, %p\n", Tcl_GetCommandName(interp, (Tcl_Command)cmdList->cmdPtr), cmdList->cmdPtr); */ return cmdList->cmdPtr; } } } return NULL; } /* *---------------------------------------------------------------------- * SuperclassAdd -- * * Add a list of superClasses (specified in the argument vector) to * the specified class. On the first call, the class has no previous * superClasses. * * Results: * A standard Tcl result. * * Side effects: * Rearranging the class relations, flushing previous precedence * orders. * *---------------------------------------------------------------------- */ static int SuperclassAdd(Tcl_Interp *interp, NsfClass *class, int oc, Tcl_Obj **ov, Tcl_Obj *arg) nonnull(1) nonnull(2) nonnull(4) nonnull(5); static int SuperclassAdd(Tcl_Interp *interp, NsfClass *class, int oc, Tcl_Obj **ov, Tcl_Obj *arg) { NsfClasses *superClasses, *subClasses, *osl = NULL; NsfObjectSystem *osPtr; NsfClass **classPtr; int i, j; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(ov != NULL); nonnull_assert(arg != NULL); superClasses = PrecedenceOrder(class); subClasses = DependentSubClasses(class); /* * We have to remove all dependent superclass filter referenced * by class or one of its subclasses. * * Do not check the class "cl" itself (first entry in * filterCheck class list). */ if (superClasses != NULL) { superClasses = superClasses->nextPtr; } for (; superClasses; superClasses = superClasses->nextPtr) { FilterRemoveDependentFilterCmds(superClasses->cl, subClasses); } /* * Invalidate all interceptors' orders of instances of this and of all * depended classes. */ MixinInvalidateObjOrders(subClasses); if (FiltersDefined(interp) > 0) { FilterInvalidateObjOrders(interp, subClasses); } /* * Build an array of superClasses from the argument vector. */ classPtr = NEW_ARRAY(NsfClass*, oc); for (i = 0; i < oc; i++) { if (GetClassFromObj(interp, ov[i], &classPtr[i], NSF_TRUE) != TCL_OK) { FREE(NsfClass**, classPtr); NsfClassListFree(subClasses); return NsfObjErrType(interp, "superclass", arg, "a list of classes", NULL); } } /* * Check that superClasses don't precede their classes. */ for (i = 0; i < oc; i++) { for (j = i+1; j < oc; j++) { NsfClasses *dl = PrecedenceOrder(classPtr[j]); dl = NsfClassListFind(dl, classPtr[i]); if (dl != NULL) { FREE(NsfClass**, classPtr); NsfClassListFree(subClasses); return NsfObjErrType(interp, "superclass", arg, "classes in dependence order", NULL); } } } /* * Ensure that the current class and new superClasses are from the * same object system. */ osPtr = GetObjectSystem(&class->object); for (i = 0; i < oc; i++) { if (osPtr != GetObjectSystem(&classPtr[i]->object)) { NsfPrintError(interp, "class \"%s\" has a different object system as class \"%s\"", ClassName_(class), ClassName(classPtr[i])); NsfClassListFree(subClasses); FREE(NsfClass**, classPtr); return TCL_ERROR; } } while (class->super != NULL) { /* * Build a backup of the old superclass list in case we need to revert. */ NsfClass *superClass = class->super->cl; NsfClasses *l = osl; osl = NEW(NsfClasses); osl->cl = superClass; osl->nextPtr = l; (void)RemoveSuper(class, class->super->cl); } for (i = 0; i < oc; i++) { AddSuper(class, classPtr[i]); } FlushPrecedences(subClasses); NsfClassListFree(subClasses); FREE(NsfClass**, classPtr); if (unlikely(!PrecedenceOrder(class))) { NsfClasses *l; /* * There is a cycle in the superclass graph, we have to revert and return * an error. */ while (class->super != NULL) { (void)RemoveSuper(class, class->super->cl); } for (l = osl; l != NULL; l = l->nextPtr) { AddSuper(class, l->cl); } if (osl != NULL) { NsfClassListFree(osl); } return NsfObjErrType(interp, "superclass", arg, "a cycle-free graph", NULL); } if (osl != NULL) { NsfClassListFree(osl); } assert(class->super != NULL); Tcl_ResetResult(interp); return TCL_OK; } /* *---------------------------------------------------------------------- * CheckVarName -- * * Check, whether the provided name is free of namespace markup. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int CheckVarName(Tcl_Interp *interp, const char *varNameString) nonnull(1) nonnull(2); static int CheckVarName(Tcl_Interp *interp, const char *varNameString) { nonnull_assert(interp != NULL); nonnull_assert(varNameString != NULL); /* * We want to have a plain variable name, since we do not want to * get interferences with namespace resolver and such. In a first * attempt, we disallowed occurrences of "::", but we have to deal as * well with e.g. arrayName(::x::y) * * TODO: more general and efficient solution to disallow e.g. a::b * (check for :: until parens) */ /*if (strstr(varNameString, "::") || *varNameString == ':') {*/ if (*varNameString == ':') { return NsfPrintError(interp, "variable name \"%s\" must not contain " "namespace separator or colon prefix", varNameString); } return TCL_OK; } /* *---------------------------------------------------------------------- * VarExists -- * * Check, whether the named variable exists on the specified object. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool VarExists( Tcl_Interp *interp, NsfObject *object, const char *name1, const char *name2, unsigned int flags ) nonnull(1) nonnull(2) nonnull(3); static bool VarExists( Tcl_Interp *interp, NsfObject *object, const char *name1, const char *name2, unsigned int flags ) { CallFrame frame, *framePtr = &frame; const Var *varPtr; Var *arrayPtr; bool result; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(name1 != NULL); #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, (NsfObject *)object, framePtr); #pragma GCC diagnostic pop if ((flags & NSF_VAR_TRIGGER_TRACE) != 0u) { varPtr = TclVarTraceExists(interp, name1); } else { varPtr = TclLookupVar(interp, name1, name2, 0, "access", /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr); } /* fprintf(stderr, "VarExists %s varPtr %p flags %.4x isundef %d\n", name1, varPtr, flags, (varPtr != NULL) ? TclIsVarUndefined(varPtr) : NULL); */ result = ((varPtr != NULL) && ((flags & NSF_VAR_REQUIRE_DEFINED) == 0u || !TclIsVarUndefined(varPtr))); if (result && ((flags & NSF_VAR_ISARRAY) != 0u) && !TclIsVarArray(varPtr)) { result = NSF_FALSE; } Nsf_PopFrameObj(interp, framePtr); return result; } #if defined(WITH_TCL_COMPILE) # include #endif /* *---------------------------------------------------------------------- * MakeProcError -- * * Function called internally from Tcl in case the definition of * the proc failed. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void MakeProcError( Tcl_Interp *interp, /* The interpreter in which the procedure was called. */ Tcl_Obj *procNameObj /* Name of the procedure. Used for error * messages and trace information. */ ) { int overflow; TCL_SIZE_T nameLen, limit = 60; const char *procName; /*fprintf(stderr, "MakeProcError %p type %p refCount %d\n", procNameObj, procNameObj->typePtr, procNameObj->refCount);*/ procName = Tcl_GetString(procNameObj); nameLen = procNameObj->length; overflow = (nameLen > limit); Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( "\n (procedure \"%.*s%s\" line %lu)", (int)((overflow != 0) ? limit : nameLen), procName, ((overflow != 0) ? "..." : ""), (unsigned long)Tcl_GetErrorLine(interp))); } /* *---------------------------------------------------------------------- * ByteCompiled -- * * Function to determine whether a proc is already byte compiled or * not. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ByteCompiled( Tcl_Interp *interp, unsigned int *flagsPtr, Proc *procPtr, Namespace *nsPtr, const char *procName ) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(5); static int ByteCompiled( Tcl_Interp *interp, unsigned int *flagsPtr, Proc *procPtr, Namespace *nsPtr, const char *procName ) { Tcl_Obj *bodyObj; nonnull_assert(interp != NULL); nonnull_assert(flagsPtr != NULL); nonnull_assert(procPtr != NULL); nonnull_assert(procName != NULL); nonnull_assert(nsPtr != NULL); bodyObj = procPtr->bodyPtr; if (likely(bodyObj->typePtr == Nsf_OT_byteCodeType)) { #if defined(HAVE_TCL_COMPILE_H) ByteCode *codePtr; Interp *iPtr = (Interp *) interp; /* * When we've got bytecode, this is the check for validity. That is, * the bytecode must be for the right interpreter (no cross-leaks!), * the code must be from the current epoch (so subcommand compilation * is up-to-date), the namespace must match (so variable handling * is right) and the resolverEpoch must match (so that new shadowed * commands and/or resolver changes are considered). */ codePtr = bodyObj->internalRep.otherValuePtr; if (unlikely(((Interp *) *codePtr->interpHandle != iPtr) || (codePtr->compileEpoch != iPtr->compileEpoch) || (codePtr->nsPtr != nsPtr) || (codePtr->nsEpoch != nsPtr->resolverEpoch))) { # if defined(VAR_RESOLVER_TRACE) fprintf(stderr, "ByteCompiled bytecode not valid proc %p cmd %p method %s\n", (void *)procPtr, (void *)procPtr->cmdPtr, Tcl_GetCommandName(interp, (Tcl_Command)procPtr->cmdPtr)); fprintf(stderr, " %d %d %d %d\n", ((Interp *) *codePtr->interpHandle != iPtr), (codePtr->compileEpoch != iPtr->compileEpoch), (codePtr->nsPtr != nsPtr), (codePtr->nsEpoch != nsPtr->resolverEpoch)); { CompiledLocal *localPtr = procPtr->firstLocalPtr; for (; localPtr != NULL; localPtr = localPtr->nextPtr) { fprintf(stderr, "... local %p '%s' resolveInfo %p deleteProc %p\n", (void *)localPtr, localPtr->name, (void *)localPtr->resolveInfo, (localPtr->resolveInfo != NULL) ? (void *)localPtr->resolveInfo->deleteProc : NULL); } } # endif /* dummy statement for coverage analysis */ assert(1); goto doCompilation; } #endif return TCL_OK; } else { int result; Namespace *definitionNsPtr; #if defined(HAVE_TCL_COMPILE_H) doCompilation: #endif *flagsPtr |= NSF_CSC_CALL_IS_COMPILE; /*fprintf(stderr, "compiling '%s' with ns %s\n", procName, nsPtr->name);*/ /* * Tcl's bytecode compiler (TclCompileScript & friends) will access the * proc command's namespace as resolution context for command lookups * (Tcl_FindCommand) when compiling the proc. We, therefore, have to patch * the proc command for the compilation step to point to the execution * namespace; and restore the definition namespace on leaving. */ definitionNsPtr = procPtr->cmdPtr->nsPtr; procPtr->cmdPtr->nsPtr = nsPtr; result = TclProcCompileProc(interp, procPtr, bodyObj, (Namespace *) nsPtr, "body of proc", procName); procPtr->cmdPtr->nsPtr = definitionNsPtr; /*fprintf(stderr, "compiling '%s' with ns %s DONE\n", procName, nsPtr->name);*/ *flagsPtr &= ~NSF_CSC_CALL_IS_COMPILE; return result; } } /* *---------------------------------------------------------------------- * PushProcCallFrame -- * * Set up and push a new call frame for the procedure invocation. * call-frame. The proc is passed via clientData. * * Results: * A standard Tcl result. * * Side effects: * compiles body conditionally * *---------------------------------------------------------------------- */ static int PushProcCallFrame( Proc *procPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Tcl_Namespace *execNsPtr, NsfCallStackContent *cscPtr ) nonnull(1) nonnull(2) nonnull(4) nonnull(6); static int PushProcCallFrame( Proc *procPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Tcl_Namespace *execNsPtr, NsfCallStackContent *cscPtr ) { Tcl_CallFrame *framePtr; int result; nonnull_assert(procPtr != NULL); nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); nonnull_assert(cscPtr != NULL); /* * Set up and push a new call frame for the new procedure invocation. * This call frame will execute either in the provided execNs or in * the proc's namespace, which might be different than the current * namespace. The proc's namespace is that of its command, which can * change when the command is renamed from one namespace to another. */ if (execNsPtr == NULL) { execNsPtr = (Tcl_Namespace *) procPtr->cmdPtr->nsPtr; } /* * TODO: We could use Tcl_PushCallFrame(), if we would allocate the * Tcl stack frame earlier. */ result = TclPushStackFrame(interp, (Tcl_CallFrame **)&framePtr, execNsPtr, (FRAME_IS_PROC|FRAME_IS_NSF_METHOD)); if (likely(result == TCL_OK)) { Tcl_CallFrame_objc(framePtr) = (TCL_SIZE_T)objc; Tcl_CallFrame_objv(framePtr) = objv; Tcl_CallFrame_procPtr(framePtr) = procPtr; Tcl_CallFrame_clientData(framePtr) = cscPtr; /*fprintf(stderr, "Stack Frame %p procPtr %p compiledLocals %p firstLocal %p\n", (void *)framePtr, (void *)procPtr, (void *)Tcl_CallFrame_compiledLocals(framePtr), (void *)procPtr->firstLocalPtr);*/ result = ByteCompiled(interp, &cscPtr->flags, procPtr, (Namespace *)execNsPtr, ObjStr(objv[0])); } return result; } #include "nsfAPI.h" /* *---------------------------------------------------------------------- * ObjectSystemsCheckSystemMethod -- * * Mark the specified method as (potentially) 'overloaded' in all object * systems and declare it 'defined' in the specified object system. * * Results: * A standard Tcl result. * * Side effects: * Updates the object system structure(s). * *---------------------------------------------------------------------- */ static int ObjectSystemsCheckSystemMethod( Tcl_Interp *interp, const char *methodName, const NsfObject *object, unsigned int flags ) { NsfObjectSystem *osPtr, *defOsPtr; char firstChar; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodName != NULL); firstChar = *methodName; defOsPtr = GetObjectSystem(object); for (osPtr = RUNTIME_STATE(interp)->objectSystems; osPtr != NULL; osPtr = osPtr->nextPtr) { int i, isRootClassMethod; unsigned int flag = 0u; NsfObject *defObject; const char **methodStrings = osPtr->methodNames; for (i = 0; i <= NSF_s_set_idx; i++) { const char *methodString = *methodStrings ++; if (likely(methodString != NULL) && unlikely(*methodString == firstChar) && strcmp(methodName, methodString) == 0) { flag = 1u << i; break; } } if (flag == 0u) { continue; } isRootClassMethod = *(Nsf_SystemMethodOpts[i]+1) == 'o'; defObject = (isRootClassMethod == 1) ? &osPtr->rootClass->object : &osPtr->rootMetaClass->object; if (osPtr->handles[i] && osPtr->protected[i]) { if (defObject == object && (flags & NSF_CMD_REDEFINE_PROTECTED_METHOD) == 0u) { return NsfPrintError(interp, "refuse to overwrite protected method %s on %s", methodName, ObjectName(defObject)); } } if ((osPtr->definedMethods & flag) != 0u) { /* * If for some reason base methods become redefined (e.g. in a reload), * do not count them as overloads. */ if ((isRootClassMethod == 1 && object == &defOsPtr->rootClass->object) || (isRootClassMethod == 0 && object == &defOsPtr->rootMetaClass->object) ) { /*fprintf(stderr, "+++ %s %.6x NOT overloading %s.%s %s (is root %d, is meta %d)\n", ClassName(defOsPtr->rootClass), osPtr->overloadedMethods, ObjectName(object), methodName, Nsf_SystemMethodOpts[i], object == &defOsPtr->rootClass->object, object == &defOsPtr->rootMetaClass->object);*/ } else { osPtr->overloadedMethods |= flag; /*fprintf(stderr, "+++ %s %.6x overloading %s.%s %s (is root %d, is meta %d)\n", ClassName(defOsPtr->rootClass), osPtr->overloadedMethods, ObjectName(object), methodName, Nsf_SystemMethodOpts[i], object == &defOsPtr->rootClass->object, object == &defOsPtr->rootMetaClass->object);*/ } } if ((osPtr == defOsPtr) && ((osPtr->definedMethods & flag) == 0u) ) { /* * Mark the method as defined. */ osPtr->definedMethods |= flag; /*fprintf(stderr, "+++ %s %.6x defining %s.%s %s osPtr %p defined %.8x flag %.8x handle %p\n", ClassName(defOsPtr->rootClass), osPtr->definedMethods, ObjectName(object), methodName, Nsf_SystemMethodOpts[i], (void *)osPtr, osPtr->definedMethods, flag, (void *)osPtr->handles[i]);*/ /* * If there is a method handle provided for this system method, register * it as a fallback; unless the method is to be defined at the root * class. */ if (osPtr->handles[i]) { if (defObject != object) { int result; NsfLog(interp, NSF_LOG_DEBUG, "Define automatically alias %s for %s", ObjStr(osPtr->handles[i]), Nsf_SystemMethodOpts[i]); result = NsfMethodAliasCmd(interp, defObject, 0, methodName, 0, ProtectionRedefine_protectedIdx, osPtr->handles[i]); if (unlikely(result != TCL_OK)) { /* * Alias definition failed. */ NsfLog(interp, NSF_LOG_WARN, "Could not define alias %s for %s", ObjStr(osPtr->handles[i]), Nsf_SystemMethodOpts[i]); return TCL_ERROR; } else { /* * Alias definition succeeded. */ Tcl_Obj *methodObj = Tcl_GetObjResult(interp); Tcl_Command cmd = Tcl_GetCommandFromObj(interp, methodObj); /* * Since the defObject is not equal to the overloaded method, the * definition above is effectively an overload of the alias. */ osPtr->overloadedMethods |= flag; /* * Set method protection. */ if (cmd != NULL) { Tcl_Command_flags(cmd) |= NSF_CMD_CALL_PROTECTED_METHOD; if (osPtr->protected[i]) { Tcl_Command_flags(cmd) |= NSF_CMD_REDEFINE_PROTECTED_METHOD; } } Tcl_ResetResult(interp); } } } } } return TCL_OK; } /*---------------------------------------------------------------------- * ParamsNew -- * * Allocate an array of Nsf_Param structures * * Results: * Pointer to allocated memory * * Side effects: * Allocation of memory. * *---------------------------------------------------------------------- */ static Nsf_Param * ParamsNew(size_t nr) { Nsf_Param *paramsPtr = NEW_ARRAY(Nsf_Param, nr+1); memset(paramsPtr, 0, sizeof(Nsf_Param) * (nr+1)); return paramsPtr; } /*---------------------------------------------------------------------- * ParamFree -- * * Deallocate the contents of a single Nsf_Param* * * Results: * None. * * Side effects: * Free the parameter definition. * *---------------------------------------------------------------------- */ static void ParamFree(Nsf_Param *paramPtr) nonnull(1); static void ParamFree(Nsf_Param *paramPtr) { nonnull_assert(paramPtr != NULL); /*fprintf(stderr, "ParamFree %p\n", (void *)paramPtr);*/ if (paramPtr->name != NULL) {STRING_FREE("paramPtr->name", paramPtr->name);} if (paramPtr->nameObj != NULL) {DECR_REF_COUNT(paramPtr->nameObj);} if (paramPtr->defaultValue != NULL) {DECR_REF_COUNT(paramPtr->defaultValue);} if (paramPtr->converterName != NULL) {DECR_REF_COUNT2("converterNameObj", paramPtr->converterName);} if (paramPtr->converterArg != NULL) {DECR_REF_COUNT(paramPtr->converterArg);} if (paramPtr->paramObj != NULL) {DECR_REF_COUNT(paramPtr->paramObj);} if (paramPtr->slotObj != NULL) {DECR_REF_COUNT(paramPtr->slotObj);} if (paramPtr->method != NULL) {DECR_REF_COUNT(paramPtr->method);} } /*---------------------------------------------------------------------- * ParamsFree -- * * Deallocate a block of multiple Nsf_Param* * * Results: * None. * * Side effects: * Free the parameter definition. * *---------------------------------------------------------------------- */ static void ParamsFree(Nsf_Param *paramsPtr) nonnull(1); static void ParamsFree(Nsf_Param *paramsPtr) { Nsf_Param *paramPtr; nonnull_assert(paramsPtr != NULL); /*fprintf(stderr, "ParamsFree %p\n", (void *)paramsPtr);*/ for (paramPtr = paramsPtr; paramPtr->name != NULL; paramPtr++) { ParamFree(paramPtr); } FREE(Nsf_Param*, paramsPtr); } /*---------------------------------------------------------------------- * ParamDefsGet -- * * Obtain parameter definitions for a cmdPtr; Optionally, this command * returns as well a flag for ProcessMethodArguments to indicate if the * parameter have to checked always. * * Results: * Parameter definitions or NULL * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static NsfParamDefs * ParamDefsGet( const Tcl_Command cmdPtr, unsigned int *checkAlwaysFlagPtr, Tcl_Namespace **execNsPtrPtr ) { NsfParamDefs *result; nonnull_assert(cmdPtr != NULL); if (likely(Tcl_Command_deleteProc(cmdPtr) == NsfProcDeleteProc)) { NsfProcContext *ctx = (NsfProcContext *)Tcl_Command_deleteData(cmdPtr); if (checkAlwaysFlagPtr != NULL) { *checkAlwaysFlagPtr = ctx->checkAlwaysFlag; } if (execNsPtrPtr != NULL) { *execNsPtrPtr = ctx->execNsPtr; } result = ctx->paramDefs; } else { result = NULL; } return result; } /*---------------------------------------------------------------------- * ParamDefsGetReturns -- * * Obtain the "returns" value from NsfProcContext. * * Results: * Tcl_Obj or NULL * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static Tcl_Obj *ParamDefsGetReturns( const Tcl_Command cmdPtr ) nonnull(1) NSF_pure; NSF_INLINE static Tcl_Obj * ParamDefsGetReturns(const Tcl_Command cmdPtr) { const NsfProcContext *pCtx; Tcl_Obj *resultObj; nonnull_assert(cmdPtr != NULL); pCtx = ProcContextGet(cmdPtr); if (pCtx != NULL) { resultObj = pCtx->returnsObj; } else { resultObj = NULL; } return resultObj; } /*---------------------------------------------------------------------- * NsfParamDefsNonposLookup -- * * Process a list of ParamDefs look for a non-pos args. If there is no exact * match, look for an abbreviated match having at least * NSF_ABBREV_MIN_CHARS leading chars which are identical. * * Results: * Standard Tcl result; might set paramPtrPtr; * * Side effects: * None. * *---------------------------------------------------------------------- */ static int NsfParamDefsNonposLookup( Tcl_Interp *interp, const char *nameString, const Nsf_Param *paramsPtr, const Nsf_Param **paramPtrPtr ) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static int NsfParamDefsNonposLookup( Tcl_Interp *interp, const char *nameString, const Nsf_Param *paramsPtr, const Nsf_Param **paramPtrPtr ) { const Nsf_Param *paramPtr; char ch1; size_t length; nonnull_assert(interp != NULL); nonnull_assert(nameString != NULL); nonnull_assert(paramsPtr != NULL); nonnull_assert(paramPtrPtr != NULL); /* * The provided paramsPtr must point to a block starting with a non-pos arg. */ assert(paramsPtr->name != NULL); assert(*paramsPtr->name == '-'); /* * The provided nameString starts as well with a leading dash. */ assert(*nameString == '-'); ch1 = nameString[2]; for (paramPtr = paramsPtr; likely(paramPtr->name != NULL) && *paramPtr->name == '-'; paramPtr++) { if (unlikely((paramPtr->flags & NSF_ARG_NOCONFIG) != 0u)) { continue; } if (ch1 == paramPtr->name[2] && strcmp(nameString, paramPtr->name) == 0) { *paramPtrPtr = paramPtr; return TCL_OK; } } length = strlen(nameString); if (length >= NSF_ABBREV_MIN_CHARS) { for (paramPtr = paramsPtr; likely(paramPtr->name != NULL) && *paramPtr->name == '-'; paramPtr++) { if (unlikely((paramPtr->flags & NSF_ARG_NOCONFIG) != 0u)) { continue; } if (ch1 == paramPtr->name[2] && strncmp(nameString, paramPtr->name, length) == 0) { const Nsf_Param *pPtr; /* fprintf(stderr, "... <%s> is an abbrev of <%s>\n", nameString, paramPtr->name); */ /* * Check whether the abbreviation is unique. */ for (pPtr = paramPtr + 1; likely(pPtr->name != NULL) && *pPtr->name == '-'; pPtr++) { if (unlikely((pPtr->flags & NSF_ARG_NOCONFIG) != 0u)) { continue; } if (ch1 == pPtr->name[2] && strncmp(nameString, pPtr->name, length) == 0) { /* * The abbreviation is not unique */ *paramPtrPtr = NULL; return NsfPrintError(interp, "the provided argument %s is an abbreviation for %s and %s", nameString, paramPtr->name, pPtr->name); } } /* * The abbreviation is unique */ *paramPtrPtr = paramPtr; return TCL_OK; } } } *paramPtrPtr = NULL; return TCL_OK; } /* *---------------------------------------------------------------------- * CGetParamLookup -- * * Obtain the parameter definition for a Tcl_Obj starting with a "-". It * can return an error, when the specified parameter is ambiguous. * * Results: * A standard Tcl result, on success paramPtr in last argument * * Side effects: * None. * *---------------------------------------------------------------------- */ static int CGetParamLookup( Tcl_Interp *interp, Tcl_Obj *nameObj, NsfParamDefs *paramDefs, const Nsf_Param **paramPtrPtr ) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static int CGetParamLookup(Tcl_Interp *interp, Tcl_Obj *nameObj, NsfParamDefs *paramDefs, const Nsf_Param **paramPtrPtr) { const char *nameString; int result = TCL_OK; nonnull_assert(interp != NULL); nonnull_assert(nameObj != NULL); nonnull_assert(paramDefs != NULL); nonnull_assert(paramPtrPtr != NULL); /* * Does provided value start with a dash? */ nameString = ObjStr(nameObj); if (unlikely(*nameString != '-')) { result = NsfPrintError(interp, "cget: parameter must start with a '-': %s", nameString); } else { NsfFlag *flagPtr = nameObj->internalRep.twoPtrValue.ptr1; if ((nameObj->typePtr == &NsfFlagObjType) && (flagPtr->signature == paramDefs->paramsPtr) && (flagPtr->serial == paramDefs->serial) ) { *paramPtrPtr = flagPtr->paramPtr; } else { Nsf_Param *paramPtr; /* * Skip leading parameters from the definition, which are no non-pos args * (very unlikely). */ for (paramPtr = paramDefs->paramsPtr; (paramPtr->name != NULL) && (*paramPtr->name != '-'); paramPtr++) { ; } /* * Perform the lookup from the group starting with paramPtr. */ result = NsfParamDefsNonposLookup(interp, nameString, paramPtr, paramPtrPtr); if (unlikely(result == TCL_OK)) { /* * Set the flag value. Probably, we should prohibit conversion on some * types. */ NsfFlagObjSet(interp, nameObj, paramDefs->paramsPtr, paramDefs->serial, *paramPtrPtr, NULL, 0u); } } } return result; } /* *---------------------------------------------------------------------- * NsfProcDeleteProc -- * * FreeProc for procs with associated parameter definitions. * * Results: * None. * * Side effects: * Freeing memory. * *---------------------------------------------------------------------- */ static void NsfProcDeleteProc( ClientData clientData ) { const NsfProcContext *ctxPtr; nonnull_assert(clientData != NULL); ctxPtr = (NsfProcContext *)clientData; if (ctxPtr->oldDeleteProc != NULL) { (*ctxPtr->oldDeleteProc)(ctxPtr->oldDeleteData); } if (ctxPtr->paramDefs != NULL) { /*fprintf(stderr, "free ParamDefs %p\n", (void*)ctxPtr->paramDefs);*/ ParamDefsRefCountDecr(ctxPtr->paramDefs); } if (ctxPtr->colonLocalVarCache != NULL) { /*fprintf(stderr, "free colonLocalVarCache %p\n", (void*)ctxPtr->colonLocalVarCache);*/ FREE(int*, ctxPtr->colonLocalVarCache); } if (ctxPtr->returnsObj != NULL) { DECR_REF_COUNT2("returnsObj", ctxPtr->returnsObj); } if (ctxPtr->execNsPtr != NULL) { /* * Balances increment in ParamDefsStore. */ NSNamespaceRelease(ctxPtr->execNsPtr); } /*fprintf(stderr, "free %p\n", (void *)ctxPtr);*/ FREE(NsfProcContext, ctxPtr); } /* *---------------------------------------------------------------------- * ProcContextRequire -- * * Obtain an NsfProcContext for the given cmd. Create a new one, if it does * not exist, or return the existing one. * * Results: * NsfProcContext * * * Side effects: * Might allocate memory * *---------------------------------------------------------------------- */ static NsfProcContext * ProcContextRequire( Tcl_Command cmd ) { NsfProcContext *ctxPtr; Command *cmdPtr; nonnull_assert(cmd != NULL); cmdPtr = (Command *)cmd; if (cmdPtr->deleteProc != NsfProcDeleteProc) { ctxPtr = NEW(NsfProcContext); /*fprintf(stderr, "ParamDefsStore %p replace deleteProc %p by %p\n", (void *)paramDefs, (void *)cmdPtr->deleteProc, (void *)NsfProcDeleteProc);*/ ctxPtr->oldDeleteData = (Proc *)cmdPtr->deleteData; ctxPtr->oldDeleteProc = cmdPtr->deleteProc; cmdPtr->deleteProc = NsfProcDeleteProc; cmdPtr->deleteData = ctxPtr; ctxPtr->paramDefs = NULL; ctxPtr->checkAlwaysFlag = 0; ctxPtr->execNsPtr = NULL; ctxPtr->colonLocalVarCache = NULL; ctxPtr->returnsObj = NULL; } else { ctxPtr = (NsfProcContext *)Tcl_Command_deleteData(cmdPtr); } return ctxPtr; } /* *---------------------------------------------------------------------- * ProcContextGet -- * * Obtain an NsfProcContext for the given cmd when it is defined. * * Results: * NsfProcContext * or NULL * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static NsfProcContext * ProcContextGet( const Tcl_Command cmdPtr ) { NsfProcContext *result; nonnull_assert(cmdPtr != NULL); if (likely(Tcl_Command_deleteProc(cmdPtr) == NsfProcDeleteProc)) { result = (NsfProcContext *)Tcl_Command_deleteData(cmdPtr); } else { result = NULL; } return result; } /* *---------------------------------------------------------------------- * ParamDefsStore -- * * Store the provided parameter definitions in the provided * command. It stores a new deleteProc which will call the original * delete proc automatically. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void ParamDefsStore( Tcl_Command cmd, NsfParamDefs *paramDefs, unsigned int checkAlwaysFlag, Tcl_Namespace *execNsPtr ) nonnull(1); static void ParamDefsStore( Tcl_Command cmd, NsfParamDefs *paramDefs, unsigned int checkAlwaysFlag, Tcl_Namespace *execNsPtr ) { NsfProcContext *ctxPtr; nonnull_assert(cmd != NULL); ctxPtr = ProcContextRequire(cmd); /* * We assume, that this never called for overwriting paramDefs */ assert(ctxPtr->paramDefs == NULL); /* fprintf(stderr, "ParamDefsStore paramDefs %p called: NS %s\n", (void *)paramDefs, execNsPtr ? execNsPtr->fullName : "na");*/ ctxPtr->paramDefs = paramDefs; ctxPtr->checkAlwaysFlag = checkAlwaysFlag; ctxPtr->execNsPtr = execNsPtr; if (ctxPtr->execNsPtr != NULL) { /* * Balanced by decrement in NsfProcDeleteProc. */ NSNamespacePreserve(ctxPtr->execNsPtr); } } /* *---------------------------------------------------------------------- * ParamDefsNew -- * * Allocate a new paramDefs structure and initialize it with zeros. The * allocated structure should be freed with ParamDefsFree(). * * Results: * pointer to paramDefs structure * * Side effects: * Allocating memory * *---------------------------------------------------------------------- */ static NsfParamDefs * ParamDefsNew(void) { NsfParamDefs *paramDefs; static NsfMutex serialMutex = 0; static int serial = 0; paramDefs = NEW(NsfParamDefs); memset(paramDefs, 0, sizeof(NsfParamDefs)); /* * We could keep the serial as well in thread local storage. */ NsfMutexLock(&serialMutex); paramDefs->serial = serial++; NsfMutexUnlock(&serialMutex); /*fprintf(stderr, "ParamDefsNew %p\n", (void *)paramDefs);*/ return paramDefs; } /* *---------------------------------------------------------------------- * ParamDefsFree -- * * Free the parameter definitions. Since the parameter definitions are * ref-counted, this function should be just called via * ParamDefsRefCountDecr. * * Results: * None. * * Side effects: * Free the parameter definitions. * *---------------------------------------------------------------------- */ static void ParamDefsFree(NsfParamDefs *paramDefs) nonnull(1); static void ParamDefsFree(NsfParamDefs *paramDefs) { /* fprintf(stderr, "ParamDefsFree %p \n", (void *)paramDefs, paramDefs);*/ nonnull_assert(paramDefs != NULL); if (paramDefs->paramsPtr != NULL) { ParamsFree(paramDefs->paramsPtr); } FREE(NsfParamDefs, paramDefs); } /* *---------------------------------------------------------------------- * ParamDefsRefCountIncr -- * ParamDefsRefCountDecr -- * * Perform book keeping on the parameter definitions. RefCounting is * necessary, since it might be possible that during the processing of the * e.g. object parameters, these might be redefined (when an object * parameter calls a method, redefining the structures). * ParamDefsRefCountDecr() is responsible for actually freeing the * structure. * * Results: * None. * * Side effects: * No direct. * *---------------------------------------------------------------------- */ static void ParamDefsRefCountIncr(NsfParamDefs *paramDefs) { nonnull_assert(paramDefs != NULL); paramDefs->refCount ++; } static void ParamDefsRefCountDecr(NsfParamDefs *paramDefs) { nonnull_assert(paramDefs != NULL); paramDefs->refCount --; if (paramDefs->refCount < 1) { ParamDefsFree(paramDefs); } } /* *---------------------------------------------------------------------- * ParamDefsFormatOption -- * * Append a parameter option to the nameStringObj representing the * syntax of the parameter definition. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void ParamDefsFormatOption( Tcl_Obj *nameStringObj, const char *option, TCL_SIZE_T optionLength, int *colonWritten, int *firstOption ) nonnull(1) nonnull(2) nonnull(4) nonnull(5); static void ParamDefsFormatOption( Tcl_Obj *nameStringObj, const char *option, TCL_SIZE_T optionLength, int *colonWritten, int *firstOption ) { nonnull_assert(nameStringObj != NULL); nonnull_assert(option != NULL); nonnull_assert(colonWritten != NULL); nonnull_assert(firstOption != NULL); if (!*colonWritten) { Tcl_AppendLimitedToObj(nameStringObj, ":", 1, INT_MAX, NULL); *colonWritten = 1; } if (*firstOption) { *firstOption = 0; } else { Tcl_AppendLimitedToObj(nameStringObj, ",", 1, INT_MAX, NULL); } Tcl_AppendLimitedToObj(nameStringObj, option, (TCL_SIZE_T)optionLength, INT_MAX, NULL); } /* *---------------------------------------------------------------------- * ParamDefsFormat -- * * Produce a Tcl_Obj representing a single parameter in the syntax * of the parameter definition. * * Results: * Tcl_Obj * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj *ParamDefsFormat( Tcl_Interp *interp, const Nsf_Param *paramsPtr, NsfObject *contextObject, const char *pattern ) nonnull(1) nonnull(2) returns_nonnull; static int ParamsDefMatchPattern(const Nsf_Param *paramsPtr, const char *pattern) { if (paramsPtr->nameObj != NULL) { return Tcl_StringMatch(ObjStr(paramsPtr->nameObj), pattern); } else { return Tcl_StringMatch(paramsPtr->name, pattern); } } static Tcl_Obj * ParamDefsFormat( Tcl_Interp *interp, const Nsf_Param *paramsPtr, NsfObject *contextObject, const char *pattern ) { int first, colonWritten; Tcl_Obj *listObj = Tcl_NewListObj(0, NULL), *innerListObj, *nameStringObj; nonnull_assert(interp != NULL); nonnull_assert(paramsPtr != NULL); INCR_REF_COUNT2("paramDefsObj", listObj); for (; likely(paramsPtr->name != NULL); paramsPtr++) { if ((paramsPtr->flags & NSF_ARG_NOCONFIG) != 0u) { continue; } if (paramsPtr->paramObj != NULL) { if (pattern != NULL && !ParamsDefMatchPattern(paramsPtr, pattern)) { continue; } innerListObj = paramsPtr->paramObj; } else { /* * We need this part only for C-defined parameter definitions, * defined via genTclAPI. * * TODO: we could streamline this by defining as well C-API via * the same syntax as for accepted for Tcl obj types "nsfParam" */ int isNonpos = *paramsPtr->name == '-'; int outputRequired = (isNonpos && ((paramsPtr->flags & NSF_ARG_REQUIRED) != 0u)); int outputOptional = (!isNonpos && ((paramsPtr->flags & NSF_ARG_REQUIRED) == 0u) && !paramsPtr->defaultValue && paramsPtr->converter != ConvertToNothing); first = 1; colonWritten = 0; if (NsfParamDefsAppendVirtual(interp, listObj, paramsPtr, contextObject, pattern, ParamDefsFormat)) { continue; } if (pattern != NULL && !ParamsDefMatchPattern(paramsPtr, pattern)) { continue; } nameStringObj = Tcl_NewStringObj(paramsPtr->name, TCL_INDEX_NONE); if (paramsPtr->type != NULL) { ParamDefsFormatOption(nameStringObj, paramsPtr->type, TCL_INDEX_NONE, &colonWritten, &first); } else if (isNonpos && paramsPtr->nrArgs == 0) { ParamDefsFormatOption(nameStringObj, "switch", 6, &colonWritten, &first); } if (outputRequired != 0) { ParamDefsFormatOption(nameStringObj, "required", 8, &colonWritten, &first); } else if (outputOptional != 0) { ParamDefsFormatOption(nameStringObj, "optional", 8, &colonWritten, &first); } if ((paramsPtr->flags & NSF_ARG_SUBST_DEFAULT) != 0u) { char buffer[30]; size_t len = 12; memcpy(buffer, "substdefault", (size_t)len); if ((paramsPtr->flags & NSF_ARG_SUBST_DEFAULT_ALL) != 0u) { memcpy(buffer + len + 1, "=0b", 3u); len += 4; buffer[len] = ((paramsPtr->flags & NSF_ARG_SUBST_DEFAULT_VARIABLES) != 0u) ? '1' : '0'; len ++; buffer[len] = ((paramsPtr->flags & NSF_ARG_SUBST_DEFAULT_COMMANDS) != 0u) ? '1' : '0'; len ++; buffer[len] = ((paramsPtr->flags & NSF_ARG_SUBST_DEFAULT_BACKSLASHES) != 0u) ? '1' : '0'; len ++; } else { len ++; } buffer[len] = '\0'; ParamDefsFormatOption(nameStringObj, buffer, (TCL_SIZE_T)len, &colonWritten, &first); } if ((paramsPtr->flags & NSF_ARG_ALLOW_EMPTY) != 0u || (paramsPtr->flags & NSF_ARG_MULTIVALUED) != 0u) { char option[10] = "...."; option[0] = ((paramsPtr->flags & NSF_ARG_ALLOW_EMPTY) != 0u) ? '0' : '1'; option[3] = ((paramsPtr->flags & NSF_ARG_MULTIVALUED) != 0u) ? '*' : '1'; ParamDefsFormatOption(nameStringObj, option, 4, &colonWritten, &first); } if ((paramsPtr->flags & NSF_ARG_IS_CONVERTER) != 0u) { ParamDefsFormatOption(nameStringObj, "convert", 7, &colonWritten, &first); } if ((paramsPtr->flags & NSF_ARG_INITCMD) != 0u) { ParamDefsFormatOption(nameStringObj, "initcmd", 7, &colonWritten, &first); } else if ((paramsPtr->flags & NSF_ARG_CMD) != 0u) { ParamDefsFormatOption(nameStringObj, "cmd", 3, &colonWritten, &first); } else if ((paramsPtr->flags & NSF_ARG_ALIAS) != 0u) { ParamDefsFormatOption(nameStringObj, "alias", 5, &colonWritten, &first); } else if ((paramsPtr->flags & NSF_ARG_FORWARD) != 0u) { ParamDefsFormatOption(nameStringObj, "forward", 7, &colonWritten, &first); } else if ((paramsPtr->flags & NSF_ARG_NOARG) != 0u) { ParamDefsFormatOption(nameStringObj, "noarg", 5, &colonWritten, &first); } else if ((paramsPtr->flags & NSF_ARG_NOCONFIG) != 0u) { ParamDefsFormatOption(nameStringObj, "noconfig", 8, &colonWritten, &first); } innerListObj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, innerListObj, nameStringObj); if (paramsPtr->defaultValue != NULL) { Tcl_ListObjAppendElement(interp, innerListObj, paramsPtr->defaultValue); } } Tcl_ListObjAppendElement(interp, listObj, innerListObj); } return listObj; } /* *---------------------------------------------------------------------- * ParamDefsList -- * * Produce a Tcl_ListObj containing the list of the parameters * based on a parameter structure. * * Results: * Tcl_Obj * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj *ParamDefsList( Tcl_Interp *interp, const Nsf_Param *paramsPtr, NsfObject *contextObject, const char *pattern ) nonnull(1) nonnull(2) returns_nonnull; static Tcl_Obj * ParamDefsList( Tcl_Interp *interp, const Nsf_Param *paramsPtr, NsfObject *contextObject, const char *pattern ) { Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); nonnull_assert(interp != NULL); nonnull_assert(paramsPtr != NULL); INCR_REF_COUNT2("paramDefsObj", listObj); for (; likely(paramsPtr->name != NULL); paramsPtr++) { if ((paramsPtr->flags & NSF_ARG_NOCONFIG) != 0u) { continue; } if (NsfParamDefsAppendVirtual(interp, listObj, paramsPtr, contextObject, pattern, ParamDefsList)) { continue; } Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(paramsPtr->name, TCL_INDEX_NONE)); } return listObj; } /* *---------------------------------------------------------------------- * ParamDefsNames -- * * Produce a Tcl_ListObj containing the names of the parameters * based on a parameter structure. * * Results: * Tcl_Obj * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj * ParamDefsNames( Tcl_Interp *interp, const Nsf_Param *paramsPtr, NsfObject *contextObject, const char *pattern ) nonnull(1) nonnull(2) returns_nonnull; static Tcl_Obj * ParamDefsNames( Tcl_Interp *interp, const Nsf_Param *paramsPtr, NsfObject *contextObject, const char *pattern ) { Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); nonnull_assert(interp != NULL); nonnull_assert(paramsPtr != NULL); INCR_REF_COUNT2("paramDefsObj", listObj); for (; likely(paramsPtr->name != NULL); paramsPtr++) { const char* paramName; if ((paramsPtr->flags & NSF_ARG_NOCONFIG) != 0u) { continue; } if (NsfParamDefsAppendVirtual(interp, listObj, paramsPtr, contextObject, pattern, ParamDefsNames)) { continue; } paramName = *paramsPtr->name == '-' ? paramsPtr->name+1 : paramsPtr->name; if (pattern != NULL && !Tcl_StringMatch(paramName, pattern)) { continue; } Tcl_ListObjAppendElement(interp, listObj, (paramsPtr->nameObj != NULL) ? paramsPtr->nameObj : Tcl_NewStringObj(paramsPtr->name, TCL_INDEX_NONE)); } return listObj; } /* *---------------------------------------------------------------------- * ParamGetType -- * * Obtain the type of a single parameter and return it as a string. * * Results: * Type of the parameter in form of a string * * Side effects: * None. * *---------------------------------------------------------------------- */ static const char *ParamGetType(Nsf_Param const *paramPtr) nonnull(1) returns_nonnull; static const char * ParamGetType(Nsf_Param const *paramPtr) { const char *result = "value"; nonnull_assert(paramPtr != NULL); if (paramPtr->type != NULL) { if (paramPtr->converter == ConvertViaCmd) { result = paramPtr->type + 5; } else if (paramPtr->converter == Nsf_ConvertToClass && ((paramPtr->flags & (NSF_ARG_BASECLASS|NSF_ARG_METACLASS)) != 0u) ) { if ((paramPtr->flags & NSF_ARG_BASECLASS) != 0u) { result = "baseclass"; } else { result = "metaclass"; } } else if (strcmp(paramPtr->type, "stringtype") == 0) { if (paramPtr->converterArg != NULL) { result = ObjStr(paramPtr->converterArg); } } else { result = paramPtr->type; } } return result; } /* *---------------------------------------------------------------------- * ParamGetDomain -- * * Obtain the domain of a single parameter and return it as a * string. The domain is an approximate type used in the parameter * syntax. * * Results: * Domain of the parameter in form of a string * * Side effects: * None. * *---------------------------------------------------------------------- */ static const char * ParamGetDomain(Nsf_Param const *paramPtr) nonnull(1) returns_nonnull; static const char * ParamGetDomain(Nsf_Param const *paramPtr) { const char *result; nonnull_assert(paramPtr != NULL); if ((paramPtr->flags & NSF_ARG_IS_ENUMERATION) != 0u) { return Nsf_EnumerationTypeGetDomain(paramPtr->converter); } else { result = ParamGetType(paramPtr); } return result; } /* *---------------------------------------------------------------------- * NsfParamDefsSyntaxOne -- * * Appends the formatted parameter (provided as 2nd argument) to the * content of the first argument. * * Results: * None. * * Side effects: * Appending to first argument. * *---------------------------------------------------------------------- */ static void NsfParamDefsSyntaxOne(Tcl_Obj *argStringObj, const Nsf_Param *pPtr) nonnull(1) nonnull(2); static void NsfParamDefsSyntaxOne(Tcl_Obj *argStringObj, const Nsf_Param *pPtr) { nonnull_assert(argStringObj != NULL); nonnull_assert(pPtr != NULL); if (pPtr->nrArgs > 0 && *pPtr->name == '-') { Tcl_AppendLimitedToObj(argStringObj, pPtr->name, TCL_INDEX_NONE, INT_MAX, NULL); Tcl_AppendLimitedToObj(argStringObj, " ", 1, INT_MAX, NULL); if ((pPtr->flags & NSF_ARG_IS_ENUMERATION) != 0u) { Tcl_AppendLimitedToObj(argStringObj, ParamGetDomain(pPtr), TCL_INDEX_NONE, INT_MAX, NULL); if ((pPtr->flags & NSF_ARG_MULTIVALUED) != 0u) { Tcl_AppendLimitedToObj(argStringObj, " ...", 4, INT_MAX, NULL); } } else { Tcl_AppendLimitedToObj(argStringObj, "/", 1, INT_MAX, NULL); Tcl_AppendLimitedToObj(argStringObj, ParamGetDomain(pPtr), TCL_INDEX_NONE, INT_MAX, NULL); if ((pPtr->flags & NSF_ARG_MULTIVALUED) != 0u) { Tcl_AppendLimitedToObj(argStringObj, " ...", 4, INT_MAX, NULL); } Tcl_AppendLimitedToObj(argStringObj, "/", 1, INT_MAX, NULL); } } else if (*pPtr->name != '-') { Tcl_AppendLimitedToObj(argStringObj, "/", 1, INT_MAX, NULL); Tcl_AppendLimitedToObj(argStringObj, pPtr->name, TCL_INDEX_NONE, INT_MAX, NULL); Tcl_AppendLimitedToObj(argStringObj, "/", 1, INT_MAX, NULL); } else { Tcl_AppendLimitedToObj(argStringObj, pPtr->name, TCL_INDEX_NONE, INT_MAX, NULL); } } /* * NsfParamDefsVirtualFormat -- * * This function is called, when we know we can resolve a virtual argument * against the context object. In such cases, obtain the resolved parsed * params and call the formatter. * * Results: * Standard Tcl result code. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj * NsfParamDefsVirtualFormat( Tcl_Interp *interp, const Nsf_Param *pPtr, NsfObject *contextObject, const char *pattern, NsfFormatFunction formatFunction ) { NsfParsedParam parsedParam; int result; nonnull_assert(interp != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(contextObject != NULL); nonnull_assert(formatFunction != NULL); assert(pPtr->type != NULL); parsedParam.paramDefs = NULL; if (strcmp(pPtr->type, "virtualobjectargs") == 0) { result = GetObjectParameterDefinition(interp, NsfGlobalObjs[NSF_EMPTY], contextObject, NULL, &parsedParam); } else if (NsfObjectIsClass(contextObject)) { result = GetObjectParameterDefinition(interp, NsfGlobalObjs[NSF_EMPTY], NULL, (NsfClass *)contextObject, &parsedParam); } else { NsfLog(interp, NSF_LOG_WARN, "virtual args: provided context is not a class <%s>", ObjectName_(contextObject)); result = TCL_ERROR; } if (result == TCL_OK && parsedParam.paramDefs != NULL) { return (*formatFunction)(interp, parsedParam.paramDefs->paramsPtr, contextObject, pattern); } return NULL; } /* *---------------------------------------------------------------------- * NsfParamDefsAppendVirtual -- * * Check for the given paramsPtr whether this is a virtual parameter and if * possible, resolve it and append the formatted content to the Tcl_Obj. * * Results: * Boolean value for success * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool NsfParamDefsAppendVirtual( Tcl_Interp *interp, Tcl_Obj *listObj, const Nsf_Param *paramsPtr, NsfObject *contextObject, const char *pattern, NsfFormatFunction formatFunction ) { nonnull_assert(interp != NULL); nonnull_assert(listObj != NULL); nonnull_assert(paramsPtr != NULL); nonnull_assert(formatFunction != NULL); assert(paramsPtr->name != NULL); if (paramsPtr->converter == ConvertToNothing && strcmp(paramsPtr->name, "args") == 0) { if ((contextObject != NULL) && (paramsPtr->type != NULL) && strncmp(paramsPtr->type, "virtual", 7) == 0 ) { Tcl_Obj *formattedObj = NsfParamDefsVirtualFormat(interp, paramsPtr, contextObject, pattern, formatFunction); if (formattedObj != NULL) { Tcl_ListObjAppendList(interp, listObj, formattedObj); DECR_REF_COUNT2("paramDefsObj", formattedObj); return NSF_TRUE; } } } return NSF_FALSE; } /* *---------------------------------------------------------------------- * NsfParamDefsSyntax -- * * Return the parameter definitions of a sequence of parameters in * the form of the "parametersyntax", inspired by the Tcl manual * pages. * * Results: * Tcl_Obj containing the parameter syntax * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Obj *NsfParamDefsSyntax( Tcl_Interp *interp, const Nsf_Param *paramsPtr, NsfObject *contextObject, const char *pattern ) nonnull(1) nonnull(2) returns_nonnull; Tcl_Obj * NsfParamDefsSyntax( Tcl_Interp *interp, const Nsf_Param *paramsPtr, NsfObject *contextObject, const char *pattern ) { Tcl_Obj *argStringObj = Tcl_NewObj(); const Nsf_Param *pPtr; int needSpace = 0; nonnull_assert(interp != NULL); nonnull_assert(paramsPtr != NULL); INCR_REF_COUNT2("paramDefsObj", argStringObj); for (pPtr = paramsPtr; pPtr->name != NULL; pPtr++) { if ((pPtr->flags & NSF_ARG_NOCONFIG) != 0u) { /* * Don't output non-configurable parameters */ continue; } if (pPtr != paramsPtr) { /* * Don't output non-consuming parameters (i.e. positional, and no args) */ if (*pPtr->name != '-' && pPtr->nrArgs == 0) { continue; } } if (pPtr->converter == ConvertToNothing && strcmp(pPtr->name, "args") == 0) { int argsResolved = 0; if ((contextObject != NULL) && (pPtr->type != NULL) && strncmp(pPtr->type, "virtual", 7) == 0 ) { Tcl_Obj *formattedObj = NsfParamDefsVirtualFormat(interp, pPtr, contextObject, pattern, NsfParamDefsSyntax); if (formattedObj != NULL) { argsResolved = 1; if (needSpace != 0) { Tcl_AppendLimitedToObj(argStringObj, " ", 1, INT_MAX, NULL); } Tcl_AppendObjToObj(argStringObj, formattedObj); DECR_REF_COUNT2("paramDefsObj", formattedObj); } } if (argsResolved == 0) { if (pattern != NULL && !ParamsDefMatchPattern(pPtr, pattern)) { continue; } if (needSpace != 0) { Tcl_AppendLimitedToObj(argStringObj, " ", 1, INT_MAX, NULL); } Tcl_AppendLimitedToObj(argStringObj, "?/arg .../?", 11, INT_MAX, NULL); } } else if ((pPtr->flags & NSF_ARG_REQUIRED) != 0u) { if (pattern != NULL && !ParamsDefMatchPattern(pPtr, pattern)) { continue; } if (needSpace != 0) { Tcl_AppendLimitedToObj(argStringObj, " ", 1, INT_MAX, NULL); } if ((pPtr->flags & NSF_ARG_IS_ENUMERATION) != 0u) { Tcl_AppendLimitedToObj(argStringObj, Nsf_EnumerationTypeGetDomain(pPtr->converter), TCL_INDEX_NONE, INT_MAX, NULL); } else { NsfParamDefsSyntaxOne(argStringObj, pPtr); } } else { if (pattern != NULL && !ParamsDefMatchPattern(pPtr, pattern)) { continue; } if (needSpace != 0) { Tcl_AppendLimitedToObj(argStringObj, " ", 1, INT_MAX, NULL); } Tcl_AppendLimitedToObj(argStringObj, "?", 1, INT_MAX, NULL); NsfParamDefsSyntaxOne(argStringObj, pPtr); Tcl_AppendLimitedToObj(argStringObj, "?", 1, INT_MAX, NULL); } needSpace = 1; } /* * Caller has to decrement. */ return argStringObj; } /* *---------------------------------------------------------------------- * ParsedParamFree -- * * Free the provided information of the parsed parameters. * * Results: * None. * * Side effects: * Freed Memory. * *---------------------------------------------------------------------- */ static void ParsedParamFree(NsfParsedParam *parsedParamPtr) { nonnull_assert(parsedParamPtr != NULL); /*fprintf(stderr, "ParsedParamFree %p, npargs %p\n", (void *)parsedParamPtr, (void *)parsedParamPtr->paramDefs);*/ if (parsedParamPtr->paramDefs != NULL) { ParamDefsRefCountDecr(parsedParamPtr->paramDefs); } FREE(NsfParsedParam, parsedParamPtr); } /* * method dispatch */ /* *---------------------------------------------------------------------- * ProcMethodDispatchFinalize -- * * Finalization function for ProcMethodDispatch which executes * scripted methods. Essentially it handles post-assertions and * frees per-invocation memory. The function was developed for NRE * enabled Tcl versions but is used in the same way for non-NRE * enabled versions. * * Results: * A standard Tcl result. * * Side effects: * indirect effects by calling Tcl code * *---------------------------------------------------------------------- */ static int ProcMethodDispatchFinalize(ClientData data[], Tcl_Interp *interp, int result) nonnull(1) nonnull(2); static int ProcMethodDispatchFinalize(ClientData data[], Tcl_Interp *interp, int result) { ParseContext *pcPtr; /*const char *methodName = data[2];*/ #if defined(NSF_WITH_ASSERTIONS) || defined(NRE) NsfCallStackContent *cscPtr; #endif #if defined(NSF_WITH_ASSERTIONS) NsfObject *object; NsfObjectOpt *opt; #endif nonnull_assert(data != NULL); nonnull_assert(interp != NULL); pcPtr = data[0]; #if defined(NSF_WITH_ASSERTIONS) || defined(NRE) cscPtr = data[1]; assert(cscPtr != NULL); #endif #if defined(NSF_WITH_ASSERTIONS) object = cscPtr->self; opt = object->opt; #endif /*fprintf(stderr, "ProcMethodDispatchFinalize %s %s flags %.6x isNRE %d pcPtr %p result %d\n", ObjectName(object), methodName, cscPtr->flags, (cscPtr->flags & NSF_CSC_CALL_IS_NRE), (void *)pcPtr, result);*/ #if defined(NSF_WITH_ASSERTIONS) if (unlikely(opt != NULL && object->teardown != NULL && (opt->checkoptions & CHECK_POST)) && likely(result == TCL_OK)) { int rc = AssertionCheck(interp, object, cscPtr->cl, data[2], CHECK_POST); if (rc != TCL_OK) { result = rc; } } #endif #if defined(NRE) if (likely((cscPtr->flags & NSF_CSC_CALL_IS_NRE) != 0u)) { if (likely(pcPtr != NULL)) { ParseContextRelease(pcPtr); NsfTclStackFree(interp, pcPtr, "release parse context"); } result = ObjectDispatchFinalize(interp, cscPtr, result /*, "NRE" , methodName*/); CscFinish(interp, cscPtr, result, "scripted finalize"); } #else if (unlikely(pcPtr != NULL)) { ParseContextRelease(pcPtr); } #endif return result; } /* *---------------------------------------------------------------------- * ProcDispatchFinalize -- * * Finalization function for nsf::proc. Simplified version of * ProcMethodDispatchFinalize(). * * Results: * A standard Tcl result. * * Side effects: * indirect effects by calling Tcl code * *---------------------------------------------------------------------- */ static int ProcDispatchFinalize(ClientData data[], Tcl_Interp *interp, int result) nonnull(1) nonnull(2); static int ProcDispatchFinalize(ClientData data[], Tcl_Interp *interp, int result) { ParseContext *pcPtr; Tcl_Time *ttPtr; nonnull_assert(data != NULL); nonnull_assert(interp != NULL); /*const char *methodName = data[0]; fprintf(stderr, "ProcDispatchFinalize of method %s\n", methodName);*/ pcPtr = data[1]; ttPtr = data[2]; if (ttPtr != NULL) { const char *methodName = data[0]; unsigned int cmdFlags = (unsigned int)PTR2UINT(data[3]); #if defined(NSF_PROFILE) NsfRuntimeState *rst = RUNTIME_STATE(interp); #endif /*fprintf(stderr, "ProcDispatchFinalize methodName %s flags %.6lx\n", methodName, (cmdFlags & NSF_CMD_DEBUG_METHOD));*/ if ((cmdFlags & NSF_CMD_DEBUG_METHOD) != 0u) { NsfProfileDebugExit(interp, NULL, NULL, methodName, ttPtr->sec, ttPtr->usec); } #if defined(NSF_PROFILE) if (rst->doProfile != 0) { NsfProfileRecordProcData(interp, methodName, ttPtr->sec, ttPtr->usec); } #endif ckfree((char *)ttPtr); } ParseContextRelease(pcPtr); NsfTclStackFree(interp, pcPtr, "nsf::proc dispatch finalize release parse context"); return result; } /* *---------------------------------------------------------------------- * ProcMethodDispatch -- * * Invoke a scripted method (with assertion checking and filters). * * Results: * A standard Tcl result. * * Side effects: * Indirect effects by calling Tcl code * *---------------------------------------------------------------------- */ static int ProcMethodDispatch( ClientData cp, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const char *methodName, NsfObject *object, NsfClass *class, Tcl_Command cmdPtr, NsfCallStackContent *cscPtr ) nonnull(1) nonnull(2) nonnull(4) nonnull(5) nonnull(6) nonnull(8) nonnull(9); static int ProcMethodDispatch( ClientData cp, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const char *methodName, NsfObject *object, NsfClass *class, Tcl_Command cmdPtr, NsfCallStackContent *cscPtr ) { NsfParamDefs *paramDefs; int result; bool releasePc = NSF_FALSE; Tcl_Namespace *execNsPtr = NULL; unsigned int checkAlwaysFlag = 0u; #if defined(NSF_WITH_ASSERTIONS) NsfObjectOpt *opt; #endif #if defined(NRE) ParseContext *pcPtr = NULL; #else ParseContext pc, *pcPtr = &pc; #endif nonnull_assert(cp != NULL); nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); nonnull_assert(methodName != NULL); nonnull_assert(cmdPtr != NULL); nonnull_assert(cscPtr != NULL); nonnull_assert(object != NULL); assert(object->teardown != NULL); #if defined(NRE) /*fprintf(stderr, "ProcMethodDispatch cmd %s\n", Tcl_GetCommandName(interp, cmdPtr));*/ assert((cscPtr->flags & NSF_CSC_CALL_IS_NRE) != 0u); #endif /* * If this is a filter, check whether its guard applies, * if not: just step forward to the next filter */ if (unlikely(cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_FILTER)) { NsfCmdList *cmdList; /* * Seek cmd in obj's filterOrder. */ assert((object->flags & NSF_FILTER_ORDER_VALID) != 0u); /* otherwise: FilterComputeDefined(interp, object);*/ for (cmdList = object->filterOrder; (cmdList != NULL) && (cmdList->cmdPtr != cmdPtr); cmdList = cmdList->nextPtr) { ; } if (cmdList != NULL) { /* * A filter was found, check whether it has a guard. */ if (cmdList->clientData != NULL) { result = GuardCall(object, interp, cmdList->clientData, cscPtr); } else { result = TCL_OK; } if (unlikely(result != TCL_OK)) { /*fprintf(stderr, "Filter GuardCall in invokeProc returned %d\n", result);*/ if (likely(result != TCL_ERROR)) { /* * The guard failed (but no error), and we call "next". * Since we may not be in a method with already provided * arguments, we call next with the actual arguments and * perform no argument substitution. * * The call stack content is not jet pushed to the Tcl * stack, we pass it already to search-and-invoke. */ /*fprintf(stderr, "... calling nextmethod cscPtr %p\n", (void *)cscPtr);*/ result = NextSearchAndInvoke(interp, methodName, objc, objv, cscPtr, NSF_FALSE); /*fprintf(stderr, "... after nextmethod result %d\n", result);*/ } /* * Next might have succeeded or not, but we are done. In the * NRE-case, we need a CscFinish for all return codes. */ #if defined(NRE) CscFinish(interp, cscPtr, result, "guard failed"); #endif return result; } } } #if defined(NSF_WITH_ASSERTIONS) opt = object->opt; if (unlikely(opt != NULL && (opt->checkoptions & CHECK_PRE)) && (result = AssertionCheck(interp, object, class, methodName, CHECK_PRE)) == TCL_ERROR) { goto prep_done; } #endif /* * If the method to be invoked has paramDefs, we have to call the * argument parser with the argument definitions obtained from the * proc context from the cmdPtr. */ paramDefs = ParamDefsGet(cmdPtr, &checkAlwaysFlag, &execNsPtr); if (paramDefs != NULL && paramDefs->paramsPtr != NULL) { #if defined(NRE) pcPtr = (ParseContext *) NsfTclStackAlloc(interp, sizeof(ParseContext), "parse context"); #endif result = ProcessMethodArguments(pcPtr, interp, object, checkAlwaysFlag|NSF_ARGPARSE_METHOD_PUSH|NSF_ARGPARSE_FORCE_REQUIRED, paramDefs, objv[0], objc, objv); cscPtr->objc = objc; cscPtr->objv = (Tcl_Obj **)objv; if (likely(result == TCL_OK)) { releasePc = NSF_TRUE; result = PushProcCallFrame(cp, interp, pcPtr->objc+1, pcPtr->full_objv, execNsPtr, cscPtr); } else { /* * some error occurred */ #if defined(NRE) ParseContextRelease(pcPtr); NsfTclStackFree(interp, pcPtr, "parse context (proc prep failed)"); pcPtr = NULL; #else ParseContextRelease(pcPtr); #endif } } else { /*if (execNsPtr == NULL) { fprintf(stderr, "PushProcCallFrame for %s without method arguments and empty execNsPtr %p\n", methodName, (void*)execNsPtr); }*/ result = PushProcCallFrame(cp, interp, objc, objv, execNsPtr, cscPtr); } /* * The stack frame is pushed, we could do something here before * running the byte code of the body. */ /* We could consider to run here ARG_METHOD or ARG_INITCMD if (likely(result == TCL_OK)) { } */ #if defined(NSF_WITH_ASSERTIONS) prep_done: #endif if (likely(result == TCL_OK)) { #if defined(NRE) /*fprintf(stderr, "CALL TclNRInterpProcCore %s method '%s'\n", ObjectName(object), ObjStr(objv[0]));*/ Tcl_NRAddCallback(interp, ProcMethodDispatchFinalize, (releasePc ? pcPtr : NULL), cscPtr, (ClientData)methodName, NULL); cscPtr->flags |= NSF_CSC_CALL_IS_NRE; result = TclNRInterpProcCore(interp, objv[0], 1, &MakeProcError); #else ClientData data[3] = { (releasePc ? pcPtr : NULL), cscPtr, (ClientData)methodName }; result = TclObjInterpProcCore(interp, objv[0], 1, &MakeProcError); result = ProcMethodDispatchFinalize(data, interp, result); #endif } else /* result != OK */ { #if defined(NRE) CscFinish(interp, cscPtr, result, "nre, prep failed"); #endif } return result; } /* *---------------------------------------------------------------------- * CmdMethodDispatch -- * * Invoke a method implemented as a cmd. Essentially it stacks * optionally a frame, calls the method, pops the frame and runs * invariants. * * Results: * A standard Tcl result. * * Side effects: * Indirect effects by calling cmd * *---------------------------------------------------------------------- */ static int CmdMethodDispatch( ClientData cp, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], NsfObject *object, Tcl_Command cmd, NsfCallStackContent *cscPtr ) nonnull(2) nonnull(4) nonnull(5) nonnull(6); static int CmdMethodDispatch( ClientData cp, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], NsfObject *object, Tcl_Command cmd, NsfCallStackContent *cscPtr ) { CallFrame frame, *framePtr = &frame; int result; nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); nonnull_assert(cmd != NULL); nonnull_assert(object != NULL); assert(object->teardown != NULL); #if defined(NRE) assert(!cscPtr || (cscPtr->flags & NSF_CSC_CALL_IS_NRE) == 0u); #endif if (cscPtr != NULL) { /* * We have a call-stack content, but the requested dispatch will not store * the call-stack content in a corresponding call-frame on its own. To get, * for example, self-introspection working for the requested dispatch, we * introduce a CMETHOD frame. */ /*fprintf(stderr, "Nsf_PushFrameCsc %s %s\n", ObjectName(object), Tcl_GetCommandName(interp, cmd));*/ Nsf_PushFrameCsc(interp, cscPtr, framePtr); result = Tcl_NRCallObjProc(interp, Tcl_Command_objProc(cmd), cp, (TCL_SIZE_T)objc, objv); Nsf_PopFrameCsc(interp, framePtr); } else { result = Tcl_NRCallObjProc(interp, Tcl_Command_objProc(cmd), cp, (TCL_SIZE_T)objc, objv); } #if defined(NSF_WITH_ASSERTIONS) if (unlikely(object->opt != NULL) && likely(result == TCL_OK)) { CheckOptions co = object->opt->checkoptions; if ((co & CHECK_INVAR)) { int rc = AssertionCheckInvars(interp, object, Tcl_GetCommandName(interp, cmd), co); if (rc != TCL_OK) { result = rc; } } } #endif /* * Reference counting in the calling ObjectDispatch() makes sure * that obj->opt is still accessible even after "dealloc" */ return result; } /* *---------------------------------------------------------------------- * ObjectCmdMethodDispatch -- * * Invoke a method implemented as an object. The referenced object is used * as a source for methods to be executed. Essentially this is currently * primarily used to implement the dispatch of ensemble objects. * * Results: * A standard Tcl result. * * Side effects: * Indirect effects by calling cmd * *---------------------------------------------------------------------- */ static int ObjectCmdMethodDispatch( NsfObject *invokedObject, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const char *methodName, NsfObject *callerSelf, NsfCallStackContent *cscPtr ) nonnull(1) nonnull(2) nonnull(4) nonnull(5) nonnull(6) nonnull(7); static int ObjectCmdMethodDispatch( NsfObject *invokedObject, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const char *methodName, NsfObject *callerSelf, NsfCallStackContent *cscPtr ) { CallFrame frame, *framePtr = &frame; Tcl_Command cmd, subMethodCmd; const char *subMethodName; NsfObject *actualSelf; NsfClass *actualClass; int result; nonnull_assert(invokedObject != NULL); nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); nonnull_assert(methodName != NULL); nonnull_assert(callerSelf != NULL); nonnull_assert(cscPtr != NULL); cmd = cscPtr->cmdPtr; /*fprintf(stderr, "ObjectCmdMethodDispatch %p %s\n", (void *)cmd, Tcl_GetCommandName(interp, cmd));*/ /*fprintf(stderr, "ObjectCmdMethodDispatch method %s invokedObject %p %s callerSelf %p %s\n", methodName, (void *)invokedObject, ObjectName(invokedObject), (void *)callerSelf, ObjectName(callerSelf));*/ if (unlikely((invokedObject->flags & NSF_DELETED) != 0u)) { /* * When we try to invoke a deleted object, the cmd (alias) is * automatically removed. Note that the cmd might be still referenced * in various entries in the call-stack. The reference counting on * these elements takes care that the cmdPtr is deleted on a pop * operation (although we do a Tcl_DeleteCommandFromToken() below. */ /*fprintf(stderr, "methodName %s found DELETED object with cmd %p my cscPtr %p\n", methodName, (void *)cmd, (void *)cscPtr);*/ Tcl_DeleteCommandFromToken(interp, cmd); if (cscPtr->cl != NULL) { NsfInstanceMethodEpochIncr("DeleteObjectAlias"); } else { NsfObjectMethodEpochIncr("DeleteObjectAlias"); } NsfCleanupObject(invokedObject, "alias-delete1"); return NsfPrintError(interp, "trying to dispatch deleted object via method '%s'", methodName); } /* * Check whether the object cmd was called without a reference to a * method. If so, perform the standard dispatch of default methods. */ if (unlikely(objc < 2)) { if ((invokedObject->flags & NSF_PER_OBJECT_DISPATCH) != 0u) { cscPtr->flags |= NSF_CSC_CALL_IS_ENSEMBLE; } Nsf_PushFrameCsc(interp, cscPtr, framePtr); result = DispatchDefaultMethod(interp, invokedObject, objv[0], NSF_CSC_IMMEDIATE); Nsf_PopFrameCsc(interp, framePtr); return result; } /* * Check whether we want NSF_KEEP_CALLER_SELF. The setting of this flag * determines the values of actualSelf and actualClass. */ if ((invokedObject->flags & NSF_KEEP_CALLER_SELF) != 0u) { actualSelf = callerSelf; actualClass = cscPtr->cl; } else { actualSelf = invokedObject; actualClass = NULL; } subMethodName = ObjStr(objv[1]); if ((invokedObject->flags & NSF_PER_OBJECT_DISPATCH) == 0u) { /*fprintf(stderr, "invokedObject %p %s methodName %s: no perobjectdispatch\n", (void*)invokedObject, ObjectName(invokedObject), methodName);*/ #if 0 /* * We should have either an approach * - to obtain from an object to methodname the cmd, and * call e.g. MethodDispatch(), or pass a fully qualified * method name, or * - to pass the actualSelf and invokedObject both * to MethodDispatch/MethodDispatch * TODO: maybe remove NSF_CM_KEEP_CALLER_SELF when done. */ result = MethodDispatch(interp, nobjc+1, nobjv-1, cmd, object, NULL /*NsfClass *cl*/, Tcl_GetCommandName(interp, cmd), NSF_CSC_TYPE_PLAIN, flags); #endif #if 1 /* * Simple and brutal. */ if (likely(invokedObject->nsPtr != NULL)) { subMethodCmd = FindMethod(invokedObject->nsPtr, subMethodName); } else { subMethodCmd = NULL; } if (subMethodCmd == NULL) { /* * no -system handling. */ actualClass = SearchPLMethod(invokedObject->cl->order, subMethodName, &subMethodCmd, NSF_CMD_CALL_PRIVATE_METHOD); } if (likely(subMethodCmd != NULL)) { cscPtr->objc = objc; cscPtr->objv = objv; Nsf_PushFrameCsc(interp, cscPtr, framePtr); result = MethodDispatch(interp, objc-1, objv+1, subMethodCmd, actualSelf, actualClass, subMethodName, cscPtr->frameType|NSF_CSC_TYPE_ENSEMBLE, (cscPtr->flags & 0xFF)|NSF_CSC_IMMEDIATE); Nsf_PopFrameCsc(interp, framePtr); return result; } /*fprintf(stderr, "... objv[0] %s cmd %p %s csc %p\n", ObjStr(objv[0]), (void *)subMethodCmd, subMethodName, (void *)cscPtr); */ #endif return ObjectDispatch(actualSelf, interp, objc, objv, NSF_CM_KEEP_CALLER_SELF); } /* * NSF_PER_OBJECT_DISPATCH is set */ if (likely(invokedObject->nsPtr != NULL)) { subMethodCmd = FindMethod(invokedObject->nsPtr, subMethodName); } else { subMethodCmd = NULL; } #if 1 if (subMethodCmd != NULL) { unsigned int cmdFlags = (unsigned int)Tcl_Command_flags(subMethodCmd); if ((cscPtr->flags & (NSF_CM_LOCAL_METHOD|NSF_CM_IGNORE_PERMISSIONS)) == 0u && (cmdFlags & NSF_CMD_CALL_PRIVATE_METHOD) != 0u) { subMethodCmd = NULL; } else if (unlikely((cmdFlags & NSF_CMD_CALL_PROTECTED_METHOD) != 0u)) { const NsfObject *lastSelf; Tcl_CallFrame *framePtr0; bool withinEnsemble = ((cscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE) != 0u); if (withinEnsemble) { Tcl_CallFrame *framePtr1; /* Alternatively: (void)NsfCallStackFindLastInvocation(interp, 0, &framePtr1); */ (void)CallStackGetTopFrame(interp, &framePtr0); (void)CallStackFindEnsembleCsc(framePtr0, &framePtr1); /* NsfShowStack(interp); fprintf(stderr, "framePtr %p\n", (void *)framePtr1);*/ if (framePtr1 != NULL) { lastSelf = GetSelfObj2(interp, framePtr1); } else { lastSelf = NULL; } } else { lastSelf = GetSelfObj(interp); } /* fprintf(stderr, "'%s (%s) == %s == %s? for %s\n", lastSelf != NULL ? ObjectName(lastSelf): "n/a", ObjectName(GetSelfObj(interp)), ObjectName(actualSelf), ObjectName(invokedObject), subMethodName); */ if (actualSelf != lastSelf) { const char *path; Tcl_Obj *pathObj = NULL; if (withinEnsemble) { pathObj = NsfMethodNamePath(interp, framePtr0, methodName); INCR_REF_COUNT(pathObj); path = ObjStr(pathObj); } else { path = methodName; } NsfLog(interp, NSF_LOG_WARN, "'%s %s %s' fails since method %s.%s %s is protected", ObjectName(actualSelf), path, subMethodName, (actualClass != NULL) ? ClassName(actualClass) : ObjectName(actualSelf), path, subMethodName); subMethodCmd = NULL; if (pathObj != NULL) { DECR_REF_COUNT(pathObj); } } } } #endif /* * Make sure that the current call is marked as an ensemble call, both * for dispatching to the default-method and for dispatching the method * interface of the given object. Otherwise, current introspection * specific to sub-methods fails (e.g., a [current method-path] in the * default-method). */ cscPtr->flags |= NSF_CSC_CALL_IS_ENSEMBLE; /* fprintf(stderr, "ensemble dispatch cp %s %s objc %d\n", ObjectName((NsfObject*)cp), methodName, objc);*/ cscPtr->objc = objc; cscPtr->objv = objv; Nsf_PushFrameCsc(interp, cscPtr, framePtr); /*fprintf(stderr, "... objv[0] %s cmd %p %s csc %p\n", ObjStr(objv[0]), (void *)subMethodCmd, subMethodName, (void *)cscPtr); */ if (likely(subMethodCmd != NULL)) { /* * In order to allow [next] to be called in an ensemble method, * an extra call-frame is needed. This CSC frame is typed as * NSF_CSC_TYPE_ENSEMBLE. Note that the associated call is flagged * additionally (NSF_CSC_CALL_IS_ENSEMBLE; see above) to be able * to identify ensemble-specific frames during [next] execution. * * The dispatch requires NSF_CSC_IMMEDIATE to be set, ensuring * that scripted methods are executed before the ensemble ends. If * they were executed later, they would find their parent frame * (CMETHOD) being popped from the stack already. */ /*fprintf(stderr, ".... ensemble dispatch object %s self %s pass %s\n", ObjectName(invokedObject), ObjectName(actualSelf), (actualSelf->flags & NSF_KEEP_CALLER_SELF) ? "callerSelf" : "invokedObject"); fprintf(stderr, ".... ensemble dispatch on %s.%s objflags %.8x cscPtr %p base flags %.6x flags %.6x cl %s\n", ObjectName(actualSelf), subMethodName, actualSelf->flags, (void *)cscPtr, (0xFF & cscPtr->flags), (cscPtr->flags & 0xFF)|NSF_CSC_IMMEDIATE, (actualClass != NULL) ? ClassName(actualClass) : "NONE");*/ result = MethodDispatch(interp, objc-1, objv+1, subMethodCmd, actualSelf, actualClass, subMethodName, cscPtr->frameType|NSF_CSC_TYPE_ENSEMBLE, (cscPtr->flags & 0xFF)|NSF_CSC_IMMEDIATE); /*if (unlikely(result != TCL_OK)) { fprintf(stderr, "ERROR: cmd %p %s subMethodName %s -- %s -- %s\n", (void *)subMethodCmd, Tcl_GetCommandName(interp, subMethodCmd), subMethodName, Tcl_GetCommandName(interp, cscPtr->cmdPtr), ObjStr(Tcl_GetObjResult(interp))); }*/ } else { /* * The method to be called was not part of this ensemble. Call * next to try to call such methods along the next path. */ Tcl_CallFrame *framePtr1; NsfCallStackContent *cscPtr1 = CallStackGetTopFrame(interp, &framePtr1); /*fprintf(stderr, "call next instead of unknown %s.%s \n", ObjectName(cscPtr->self), methodName);*/ assert(cscPtr1 != NULL); if ((cscPtr1->frameType & NSF_CSC_TYPE_ENSEMBLE)) { /* * We are in an ensemble method. The next works here not on the * actual methodName + frame, but on the ensemble above it. We * locate the appropriate call-stack content and continue next on * that. */ cscPtr1 = CallStackFindEnsembleCsc(framePtr1, &framePtr1); assert(cscPtr1 != NULL); } /* * We mark in the flags that we are in an ensemble but failed so far to * resolve the cmd. Now we try to resolve the unknown subcmd via next and * we record this in the flags. The method name for next might be * colon-prefixed. In these cases, we have to skip the single colon with * the MethodName() function. */ cscPtr1->flags |= NSF_CM_ENSEMBLE_UNKNOWN; /*fprintf(stderr, "==> trying to find <%s> in ensemble <%s> via next\n", subMethodName, MethodName(cscPtr1->objv[0]));*/ result = NextSearchAndInvoke(interp, MethodName(cscPtr1->objv[0]), cscPtr1->objc, cscPtr1->objv, cscPtr1, NSF_FALSE); /*fprintf(stderr, "==> next %s.%s subMethodName %s (obj %s) cscPtr %p (flags %.8x)) cscPtr1 %p (flags %.8x) result %d unknown %d\n", ObjectName(callerSelf), methodName, subMethodName, ObjectName(invokedObject), (void*)cscPtr, cscPtr->flags, (void*)cscPtr1, (cscPtr1 != NULL) ? cscPtr1->flags : 0, result, RUNTIME_STATE(interp)->unknown);*/ if (RUNTIME_STATE(interp)->unknown) { Tcl_Obj *callInfoObj = Tcl_NewListObj(1, &callerSelf->cmdName); Tcl_CallFrame *varFramePtr, *tclFramePtr = CallStackGetTclFrame(interp, (Tcl_CallFrame *)framePtr, 1); int pathLength, pathLength0 = 0, unknownIndex; Tcl_Obj *pathObj = NsfMethodNamePath(interp, tclFramePtr, MethodName(objv[0])); bool getPath = NSF_TRUE; INCR_REF_COUNT(pathObj); /* * The "next" call could not resolve the unknown subcommand. At this * point, potentially serval different ensembles were tried, which can * be found on the stack. * * Example1: call: foo a b d * mixin: foo a b c * object: foo a x * * We want to return the longest, most precise prefix (here "foo a b") * and flag "d" as unknown (here the mixin frame). Another (inferior) * solution would be to report "foo a" as know prefix and "b d" as * unknown (when the error is generated from the point of view of the * object method frame). * * In the general case, we traverse the stack for all ensembles and pick * the longest known ensemble for reporting. This path is passed to the * unknown-handler of the ensemble. */ Tcl_ListObjLength(interp, pathObj, &pathLength0); pathLength = pathLength0; for (varFramePtr = (Tcl_CallFrame *)framePtr; likely(varFramePtr != NULL); varFramePtr = Tcl_CallFrame_callerVarPtr(varFramePtr)) { const NsfCallStackContent *stackCscPtr; /* * If we reach a non-nsf frame, or it is not an ensemble, we are done. */ stackCscPtr = (((unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr) & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) != 0u) ? ((NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr)) : NULL; if (stackCscPtr == NULL || (stackCscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE) == 0u) { break; } /* * Every ensemble block starts with a frame of * NSF_CSC_TYPE_ENSEMBLE. If we find one, then we compute a new * path in the next iteration. */ if ((stackCscPtr->frameType & (NSF_CSC_TYPE_ENSEMBLE)) == 0) { /* * Get method path the next round. */ getPath = NSF_TRUE; } else if (getPath) { int pathLength1; Tcl_Obj *pathObj1 = CallStackMethodPath(interp, varFramePtr); INCR_REF_COUNT(pathObj1); getPath = NSF_FALSE; Tcl_ListObjLength(interp, pathObj1, &pathLength1); if (pathLength1 > pathLength) { if (pathObj != NULL) { DECR_REF_COUNT(pathObj); } pathObj = pathObj1; pathLength = pathLength1; } else { DECR_REF_COUNT(pathObj1); } } } unknownIndex = pathLength <= pathLength0 ? 1 : 1 + pathLength - pathLength0; assert(objc > unknownIndex); INCR_REF_COUNT(callInfoObj); Tcl_ListObjAppendList(interp, callInfoObj, pathObj); Tcl_ListObjAppendElement(interp, callInfoObj, objv[unknownIndex]); /* fprintf(stderr, "DispatchUnknownMethod is called with callinfo <%s> (callerSelf <%s>, methodName '%s', methodPath '%s')\n", ObjStr(callInfoObj), ObjStr(callerSelf->cmdName), MethodName(objv[0]), ObjStr(callInfoObj)); */ result = DispatchUnknownMethod(interp, invokedObject, objc-1, objv+1, callInfoObj, objv[1], NSF_CM_NO_OBJECT_METHOD|NSF_CSC_IMMEDIATE); DECR_REF_COUNT(callInfoObj); DECR_REF_COUNT(pathObj); } } Nsf_PopFrameCsc(interp, framePtr); return result; } #if !defined(NSF_ASSEMBLE) static int NsfAsmProc(ClientData UNUSED(clientData), Tcl_Interp *UNUSED(interp), int UNUSED(objc), Tcl_Obj *const UNUSED(objv[])) { return TCL_OK; } #endif /* *---------------------------------------------------------------------- * CheckCStack -- * * Monitor the growth of the C Stack when complied with * NSF_STACKCHECK. * * Results: * None. * * Side effects: * update of rst->bottomOfStack * *---------------------------------------------------------------------- */ #if defined(NSF_STACKCHECK) && defined(PRE86) NSF_INLINE static void CheckCStack(Tcl_Interp *interp, const char *prefix, const char *fullMethodName) nonnull(1) nonnull(2) nonnull(3); NSF_INLINE static void CheckCStack(Tcl_Interp *interp, const char *prefix, const char *fullMethodName) { int somevar; NsfRuntimeState *rst = RUNTIME_STATE(interp); nonnull_assert(interp != NULL); nonnull_assert(prefix != NULL); nonnull_assert(fullMethodName != NULL); if (rst->exitHandlerDestroyRound == NSF_EXITHANDLER_OFF) { # if TCL_STACK_GROWS_UP if ((void *)&somevar < rst->bottomOfStack) { NsfLog(interp, NSF_LOG_WARN, "Stack adjust bottom %ld - %s %s", (void *)&somevar - rst->bottomOfStack, prefix, fullMethodName); rst->bottomOfStack = (void *)&somevar; } else if ((void *)&somevar > rst->maxStack) { NsfLog(interp, NSF_LOG_WARN, "Stack adjust top %ld - %s %s", (void *)&somevar - rst->bottomOfStack, prefix, fullMethodName); rst->maxStack = (void *)&somevar; } # else if ((void *)&somevar > rst->bottomOfStack) { NsfLog(interp, NSF_LOG_WARN, "Stack adjust bottom %ld - %s %s", rst->bottomOfStack - (void *)&somevar, prefix, fullMethodName); rst->bottomOfStack = (void *)&somevar; } else if ((void *)&somevar < rst->maxStack) { NsfLog(interp, NSF_LOG_WARN, "Stack adjust top %ld - %s %s", rst->bottomOfStack - (void *)&somevar, prefix, fullMethodName); rst->maxStack = (void *)&somevar; } # endif } } #else # define CheckCStack(interp, prefix, methodName) #endif /* *---------------------------------------------------------------------- * MethodDispatchCsc -- * * Dispatch a method (scripted or cmd) with an already allocated * call stack content. The method calls either ProcMethodDispatch() * (for scripted methods) or CmdMethodDispatch() (otherwise). * * Results: * A standard Tcl result. * * Side effects: * Indirect effects by calling methods * *---------------------------------------------------------------------- */ static int MethodDispatchCsc( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Tcl_Command cmd, NsfCallStackContent *cscPtr, const char *methodName, bool *validCscPtr ) nonnull(1) nonnull(2) nonnull(4) nonnull(5) nonnull(6) nonnull(7) nonnull(8); static int MethodDispatchCsc( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Tcl_Command cmd, NsfCallStackContent *cscPtr, const char *methodName, bool *validCscPtr ) { NsfObject *object; ClientData cp; Tcl_ObjCmdProc *proc; NsfCallStackContent *cscPtr1; nonnull_assert(clientData != NULL); nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); nonnull_assert(cmd != NULL); nonnull_assert(cscPtr != NULL); nonnull_assert(methodName != NULL); nonnull_assert(validCscPtr != NULL); cp = Tcl_Command_objClientData(cmd); proc = Tcl_Command_objProc(cmd); object = cscPtr->self; /* * Provide DTrace with calling info */ if (NSF_DTRACE_METHOD_ENTRY_ENABLED()) { NSF_DTRACE_METHOD_ENTRY(ObjectName(object), (cscPtr->cl != NULL) ? ClassName(cscPtr->cl) : ObjectName(object), (char *)methodName, objc-1, (Tcl_Obj **)objv+1); } if (unlikely(((unsigned int)Tcl_Command_flags(cmd) & NSF_CMD_DEPRECATED_METHOD) != 0u)) { NsfProfileDeprecatedCall(interp, object, cscPtr->cl, methodName, ""); } if (unlikely(((unsigned int)Tcl_Command_flags(cmd) & NSF_CMD_DEBUG_METHOD) != 0u)) { NsfProfileDebugCall(interp, object, cscPtr->cl, methodName, objc-1, (Tcl_Obj **)objv+1); } /*fprintf(stderr, "MethodDispatch method '%s' cmd %p %s clientData %p cp=%p objc=%d cscPtr %p csc->flags %.6x \n", methodName, (void *)cmd, Tcl_GetCommandName(interp, cmd), (void *)clientData, (void *)cp, objc, cscPtr, cscPtr->flags);*/ /*fprintf(stderr, "MethodDispatch method '%s' cmd %p cp=%p objc=%d cscPtr %p csc->flags %.6x " "obj->flags %.6x teardown %p\n", methodName, (void *)cmd, (void *)cp, objc, (void *)cscPtr, cscPtr->flags, object->flags, object->teardown);*/ assert(object->teardown != NULL); /* * The default assumption is that the CscPtr is valid after this function * finishes. */ if (likely(proc == TclObjInterpProc)) { int result; #if defined(NRE) NRE_callback *rootPtr = TOP_CB(interp); int isImmediate = (cscPtr->flags & NSF_CSC_IMMEDIATE); # if defined(NRE_CALLBACK_TRACE) NsfClass *class = cscPtr->cl; # endif #endif /* * The cmd is a scripted method */ //assert(((Proc *)cp)->refCount > 0); result = ProcMethodDispatch(cp, interp, objc, objv, methodName, object, cscPtr->cl, cmd, cscPtr); #if defined(NRE) /* * In the NRE case, there is no trust in the cscPtr anymore, it might be already gone. */ *validCscPtr = NSF_FALSE; if (unlikely(isImmediate)) { # if defined(NRE_CALLBACK_TRACE) fprintf(stderr, ".... manual run callbacks rootPtr = %p, result %d methodName %s.%s\n", (void *)rootPtr, result, ClassName(class), methodName); # endif result = NsfNRRunCallbacks(interp, result, rootPtr); } else { # if defined(NRE_CALLBACK_TRACE) fprintf(stderr, ".... don't run callbacks rootPtr = %p, result %d methodName %s.%s\n", (void *)rootPtr, result, ClassName(class), methodName); # endif } #endif /* * scripted method done */ return result; } else if (proc == NsfObjDispatch) { assert(cp != NULL); return ObjectCmdMethodDispatch((NsfObject *)cp, interp, objc, objv, methodName, object, cscPtr); } else if (cp != NULL) { cscPtr1 = cscPtr; /*fprintf(stderr, "cscPtr %p cmd %p %s want to stack cmd %p %s cp %p no-leaf %d force frame %d\n", (void *)cscPtr, (void *)cmd, Tcl_GetCommandName(interp, cmd), (void *)cmd, Tcl_GetCommandName(interp, cmd), (void *)cp, (Tcl_Command_flags(cmd) & NSF_CMD_NONLEAF_METHOD), (cscPtr->flags & NSF_CSC_FORCE_FRAME));*/ /* * The cmd has client data, we check for required updates in this * structure. */ if (proc == NsfForwardMethod || proc == NsfObjscopedMethod || proc == NsfSetterMethod || proc == NsfAsmProc ) { TclCmdClientData *tcd = (TclCmdClientData *)cp; assert(tcd != NULL); tcd->object = object; assert(!CmdIsProc(cmd)); } else if (cp == (ClientData)NSF_CMD_NONLEAF_METHOD) { cp = clientData; assert(!CmdIsProc(cmd)); } #if !defined(NDEBUG) else if (proc == NsfProcAliasMethod) { /* * This should never happen! */ Tcl_Panic("Alias invoked in unexpected way"); } #endif } else if (((unsigned int)Tcl_Command_flags(cmd) & NSF_CMD_NONLEAF_METHOD) != 0u || ((cscPtr->flags & NSF_CSC_FORCE_FRAME) != 0u)) { /* * Technically, we would not need a frame to execute the cmd, but maybe, * the user wants it (to be able to call next, or the keep proc-level * variables. The clientData cp is in such cases typically NULL. */ /*fprintf(stderr, "FORCE_FRAME\n");*/ cscPtr1 = cscPtr; } else { /* * There is no need to pass a frame. Use the original clientData. */ cscPtr1 = NULL; } if (cscPtr1 != NULL) { /* * Call with a stack frame. */ /*fprintf(stderr, "cmdMethodDispatch %s.%s, cscPtr %p objflags %.6x\n", ObjectName(object), methodName, (void *)cscPtr, object->flags); */ return CmdMethodDispatch(cp, interp, objc, objv, object, cmd, cscPtr1); } else { /* * Call without a stack frame. */ CscListAdd(interp, cscPtr); /*fprintf(stderr, "cmdMethodDispatch %p %s.%s, nothing stacked, objflags %.6x\n", cmd, ObjectName(object), methodName, object->flags); */ return CmdMethodDispatch(clientData, interp, objc, objv, object, cmd, NULL); } } /* *---------------------------------------------------------------------- * MethodDispatch -- * * Convenience wrapper for MethodDispatchCsc(). It allocates a call * stack content and invokes MethodDispatchCsc. * * Results: * A standard Tcl result. * * Side effects: * Indirect effects by calling methods * *---------------------------------------------------------------------- */ static int MethodDispatch(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Tcl_Command cmd, NsfObject *object, NsfClass *class, const char *methodName, unsigned short frameType, unsigned int flags) { NsfCallStackContent csc, *cscPtr; bool isValidCsc = NSF_TRUE; Tcl_Command resolvedCmd; int result; nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); nonnull_assert(cmd != NULL); nonnull_assert(object != NULL); nonnull_assert(methodName != NULL); assert(object->teardown != NULL); CheckCStack(interp, "method", methodName); /*fprintf(stderr, "MethodDispatch method '%s.%s' objc %d flags %.6x\n", ObjectName(object), methodName, objc, flags); */ resolvedCmd = AliasDereference(interp, object, methodName, cmd); if (unlikely(resolvedCmd == NULL)) { return TCL_ERROR; } /* * cscAlloc uses for resolvedCmd for allocating the call stack content and * sets the IS_NRE flag based on it. We use the original cmd in the * call-stack content structure for introspection. */ cscPtr = CscAlloc(interp, &csc, resolvedCmd); /* * We would not need CscInit when cp (clientData) == NULL && * !(Tcl_Command_flags(cmd) & NSF_CMD_NONLEAF_METHOD) TODO: We could * pass cmd == NULL, but is this worth it? */ CscInit(cscPtr, object, class, cmd, frameType, flags, methodName); result = MethodDispatchCsc(object, interp, objc, objv, resolvedCmd, cscPtr, methodName, &isValidCsc); #if defined(NRE) if (isValidCsc) { CscListRemove(interp, cscPtr, NULL); CscFinish(interp, cscPtr, result, "csc cleanup"); } #else CscListRemove(interp, cscPtr, NULL); CscFinish(interp, cscPtr, result, "csc cleanup"); #endif return result; } /* *---------------------------------------------------------------------- * ObjectDispatchFinalize -- * * Finalization function for ObjectDispatch() which performs method * lookup and call all kind of methods. The function runs after * ObjectDispatch() and calls the unknown handler if necessary and * resets the filter and mixin stacks. * * Results: * A standard Tcl result. * * Side effects: * Maybe side effects by the cmd called by ParameterCheck() * or DispatchUnknownMethod() * *---------------------------------------------------------------------- */ NSF_INLINE static int ObjectDispatchFinalize(Tcl_Interp *interp, NsfCallStackContent *cscPtr, int result /*, char *msg, const char *methodName*/) nonnull(1) nonnull(2); NSF_INLINE static int ObjectDispatchFinalize(Tcl_Interp *interp, NsfCallStackContent *cscPtr, int result /*, char *msg, const char *methodName*/) { const NsfRuntimeState *rst; NsfObject *object; unsigned int flags; nonnull_assert(interp != NULL); nonnull_assert(cscPtr != NULL); object = cscPtr->self; assert(object != NULL); assert(object->id != NULL); flags = cscPtr->flags; rst = RUNTIME_STATE(interp); /*fprintf(stderr, "ObjectDispatchFinalize %p %s flags %.6x (%d) frame %.6x unk %d m %s\n", (void*)cscPtr, ObjectName(object), flags, result, cscPtr->frameType, RUNTIME_STATE(interp)->unknown, (cscPtr->cmdPtr != NULL) ? Tcl_GetCommandName(interp, cscPtr->cmdPtr) : "");*/ /* * Check the return value if wanted */ if (likely((result == TCL_OK) && (cscPtr->cmdPtr != NULL) && (Tcl_Command_cmdEpoch(cscPtr->cmdPtr) == 0))) { Tcl_Obj *returnsObj = ParamDefsGetReturns(cscPtr->cmdPtr); if (returnsObj != NULL) { NsfObject *ctxObject = (cscPtr->cl != NULL) ? (NsfObject *)cscPtr->cl : object; Tcl_Namespace *nsPtr = Tcl_Command_nsPtr(ctxObject->id); Tcl_Obj *valueObj = Tcl_GetObjResult(interp); result = ParameterCheck(interp, returnsObj, valueObj, "return-value:", rst->doCheckResults, NSF_FALSE, NSF_FALSE, NULL, nsPtr != NULL ? nsPtr->fullName : NULL); } } else { /*fprintf(stderr, "We have no cmdPtr in cscPtr %p %s", cscPtr, ObjectName(object)); fprintf(stderr, "... cannot check return values!\n");*/ } /* * On success (no error occurred) check for unknown cases. */ if (likely(result == TCL_OK)) { /* * When triggered via filter, we might have cases with NRE, where the * filter is called from a filter, leading to an unknown cscPtr->objv); * however, there is no need to dispatch in such a case the unknown method. */ if (unlikely(((flags & NSF_CSC_METHOD_IS_UNKNOWN) != 0u) || ((cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_FILTER) && rst->unknown && (cscPtr->objv != NULL)) )) { result = DispatchUnknownMethod(interp, object, cscPtr->objc, cscPtr->objv, NULL, cscPtr->objv[0], (cscPtr->flags & NSF_CSC_CALL_NO_UNKNOWN)|NSF_CSC_IMMEDIATE); } } /* * Resetting mixin and filter stacks */ if (unlikely((flags & NSF_CSC_MIXIN_STACK_PUSHED) && object->mixinStack != NULL) != 0u) { /* fprintf(stderr, "MixinStackPop %s.%s %p %s\n", ObjectName(object), methodName, object->mixinStack, msg);*/ MixinStackPop(object); } if (unlikely((flags & NSF_CSC_FILTER_STACK_PUSHED) && object->filterStack) != 0u) { /* fprintf(stderr, "FilterStackPop %s.%s %p %s\n", ObjectName(object), methodName, object->filterStack, msg);*/ FilterStackPop(object); } return result; } /*#define INHERIT_CLASS_METHODS 1*/ #if defined(INHERIT_CLASS_METHODS) static Tcl_Command NsfFindClassMethod(Tcl_Interp *interp, NsfClass *class, const char *methodName) nonnull(1) nonnull(2) nonnull(3); static Tcl_Command NsfFindClassMethod(Tcl_Interp *interp, NsfClass *class, const char *methodName) { Tcl_Command cmd; NsfClasses *p; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(methodName != NULL); /*fprintf(stderr, "NsfFindClassMethod %s %s\n", ClassName(class), methodName);*/ for(p = PrecedenceOrder(class); p != NULL; p = p->nextPtr) { NsfClass *currentClass = p->cl; Tcl_Namespace *nsPtr = currentClass->object.nsPtr; /*fprintf(stderr, "1 check for obj ns in class %s => %p\n", ClassName(currentClass), nsPtr);*/ if (nsPtr != NULL) { cmd = FindMethod(nsPtr, methodName); /*fprintf(stderr, "1 lookup for method %s in class %s => %p\n", methodName, ClassName(currentClass), cmd);*/ if (cmd != NULL) { return cmd; } } } return NULL; } #endif /* *---------------------------------------------------------------------- * CmdObjProcName -- * * Try to find a symbolic name for the objCmdProc of a Tcl_command. * * Results: * String name, potentially "other" * * Side effects: * None. * *---------------------------------------------------------------------- */ static const char *CmdObjProcName( Tcl_Command cmd ) nonnull(1) NSF_pure; static const char * CmdObjProcName( Tcl_Command cmd ) { const char *result; Tcl_ObjCmdProc *proc; nonnull_assert(cmd != NULL); proc = Tcl_Command_objProc(cmd); if (CmdIsNsfObject(cmd)) { result = "object"; } else if (CmdIsProc(cmd)) { result = "proc"; } else if (proc == NsfForwardMethod) { result = "forward"; } else if (proc == NsfProcAliasMethod) { result = "alias"; } else if (proc == NsfODestroyMethodStub) { result = "destroy"; } else if (proc == NsfCCreateMethodStub) { result = "create"; } else if (proc == NsfCNewMethodStub) { result = "new"; } else if (proc == NsfOConfigureMethodStub) { result = "configure"; } else if (proc == NsfOVolatileMethodStub) { result = "volatile"; } else if (proc == NsfOVolatile1MethodStub) { result = "volatile"; } else if (proc == NsfOAutonameMethodStub) { result = "autoname"; } else if (proc == NsfOUplevelMethodStub) { result = "uplevel"; } else if (proc == NsfOUpvarMethodStub) { result = "upvar"; } else if (proc == NsfObjscopedMethod) { result = "objscoped"; } else if (proc == NsfProcStub) { result = "nsfproc"; } else if (proc == NsfSetterMethod) { result = "setter"; } else if (proc == NsfAsmProc) { result = "asm"; } else if (proc == TclObjInterpProc) { result = "alt proc"; #if 0 } else if (proc == Tcl_ApplyObjCmd) { result = "apply"; } else if (proc == Tcl_EvalObjCmd) { result = "eval"; #endif } else { result = "unknown"; } return result; } /* *---------------------------------------------------------------------- * ColonCmdCacheSet -- * * Fill out an ColonCmdCacheSet entry * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static void ColonCmdCacheSet( NsfColonCmdContext *ccCtxPtr, NsfClass *currentClass, unsigned int methodEpoch, Tcl_Command cmd, NsfClass *class, unsigned int flags ) { ccCtxPtr->context = currentClass; ccCtxPtr->methodEpoch = methodEpoch; ccCtxPtr->cmd = cmd; ccCtxPtr->class = class; ccCtxPtr->flags = flags; } #if defined(COLON_CMD_STATS) static void ColonCmdCacheNew(NsfColonCmdContext *ccCtxPtr, Tcl_Obj *obj) { ccCtxPtr->hits = 0u; ccCtxPtr->invalidates = 0u; ccCtxPtr->requiredRefetches = 0u; ccCtxPtr->obj = obj; INCR_REF_COUNT(obj); } static void ColonCmdCacheInvalidate(NsfColonCmdContext *ccCtxPtr) { ccCtxPtr->invalidates ++; } static void ColonCmdCacheRequiredRefetch(NsfColonCmdContext *ccCtxPtr) { ccCtxPtr->requiredRefetches ++; } static void ColonCmdCacheHit(NsfColonCmdContext *ccCtxPtr) { ccCtxPtr->hits ++; } #else #define ColonCmdCacheNew(ccCtxPtr, obj) #define ColonCmdCacheInvalidate(ccCtxPtr) #define ColonCmdCacheRequiredRefetch(ccCtxPtr) #define ColonCmdCacheHit(ccCtxPtr) #endif #ifdef DO_CLEANUP /* *---------------------------------------------------------------------- * NsfColonCmdContextFree -- * * FreeProc for NsfColonCmdContext * * Results: * None. * * Side effects: * Freeing memory. * *---------------------------------------------------------------------- */ static void NsfColonCmdContextFree(void *clientData) { #if defined(COLON_CMD_STATS) NsfColonCmdContext *ccCtxPtr = clientData; fprintf(stderr, "### free colonCmdContext for %s: hits %lu invalidates %lu required-refetches %lu\n", ObjStr(ccCtxPtr->obj), (unsigned long)ccCtxPtr->hits, (unsigned long)ccCtxPtr->invalidates, (unsigned long)ccCtxPtr->requiredRefetches); DECR_REF_COUNT(ccCtxPtr->obj); #endif FREE(NsfColonCmdContext, clientData); } #endif /* *---------------------------------------------------------------------- * CacheCmd -- * * Cache a Tcl_Command element in a Tcl_Obj, using either the NSF * specific object types, or the colon cmd cache for Tcl cmd types. * * Results: * None. * * Side effects: * Add cache entry * *---------------------------------------------------------------------- */ static void CacheCmd( Tcl_Interp *interp, Tcl_Command cmd, Tcl_Obj *methodObj, const Tcl_ObjType *nsfObjTypePtr, void *context, unsigned int methodEpoch, NsfClass *class, unsigned int flags, bool isColonCmd ) { const Tcl_ObjType *methodObjTypePtr = methodObj->typePtr; if (((methodObjTypePtr != Nsf_OT_tclCmdNameType)) && (methodObjTypePtr != Nsf_OT_parsedVarNameType) ) { /*fprintf(stderr, "==== SET OBJ TYPE for %s.%s to NsfInstanceMethodObjType cmd %p\n", ObjectName(object), calledName, (void*)cmd);*/ NsfMethodObjSet(interp, methodObj, nsfObjTypePtr, context, methodEpoch, cmd, class, flags); } else if (isColonCmd && (methodObj->refCount > 1)) { /* * When the refCount <= 1, the object is a temporary object, for which * caching is not useful. We could also cache the following types, but the * benefit is not clear. * * (methodObjTypePtr != Nsf_OT_tclCmdNameType) * || (Tcl_Command_objProc(cmd) == NsfProcAliasMethod) * */ NsfColonCmdContext *ccCtxPtr = methodObj->internalRep.twoPtrValue.ptr2; if (ccCtxPtr != NULL) { /* * We had already a ccCtxPtr, so the value was invalidated before. */ ColonCmdCacheInvalidate(ccCtxPtr); if (ccCtxPtr->cmd != cmd) { /* * The cached cmd differs from actual one, so this was a required * refetch operation, where the invalidation was truly necessary. */ ColonCmdCacheRequiredRefetch(ccCtxPtr); } ColonCmdCacheSet(ccCtxPtr, context, methodEpoch, cmd, class, flags); } else { NsfRuntimeState *rst = RUNTIME_STATE(interp); /*fprintf(stderr, "======== new entry for %p %s type %s refCount %d ccCtxPtr %p flags %.6x context %s\n", (void*)methodObj, ObjStr(methodObj), ObjTypeStr(methodObj), methodObj->refCount, (void*)ccCtxPtr, flags, ObjectName((NsfObject*)context));*/ /* * Create an NsfColonCmdContext and supply it with data (primarily the * cmd, the other data is for validation). */ ccCtxPtr = NEW(NsfColonCmdContext); ColonCmdCacheNew(ccCtxPtr, methodObj); ColonCmdCacheSet(ccCtxPtr, context, methodEpoch, cmd, class, flags); /* * Save the NsfColonCmdContext in the proc context for memory management * and as well for reuse in twoPtrValue.ptr2. */ /* rst->freeListPtr = NsfListCons(ccCtxPtr, rst->freeListPtr); */ NsfDListAppend(&rst->freeDList, ccCtxPtr); methodObj->internalRep.twoPtrValue.ptr2 = ccCtxPtr; /*fprintf(stderr, "==== ptr2 of %s empty, is set %p for obj %p %p %s target proc ctx %p ccCtx %p\n", ObjStr(methodObj), (void*)cmd, (void*)object, (void*)methodObj, ObjStr(methodObj), (void*)pCtxPtr, (void*)pCtxPtr->freeListObj);*/ } } else { /* * We found a command, but we do not cache it... */ /* fprintf(stderr, "... found cmd '%s' type of methodObj '%s' type %s, procType %s but we do not cache\n", Tcl_GetCommandName(NULL, cmd), ObjStr(methodObj), methodObjTypePtr ? methodObjTypePtr->name : "NONE", CmdObjProcName(cmd));*/ } } /* *---------------------------------------------------------------------- * ObjectDispatch -- * * This function performs the method lookup and call all kind of * methods. It checks, whether a filter or mixin has to be * applied. In these cases, the effective method lookup is * performed by "next". * * Results: * A standard Tcl result. * * Side effects: * Maybe side effects by the cmd called by ParameterCheck() * or DispatchUnknownMethod() * *---------------------------------------------------------------------- */ NSF_INLINE static int ObjectDispatch(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], unsigned int flags) nonnull(1) nonnull(2) nonnull(4); NSF_INLINE static int ObjectDispatch( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], unsigned int flags ) { int result = TCL_OK, shift; bool isValidCsc = NSF_TRUE; unsigned int objflags, nsfObjectMethodEpoch; unsigned short frameType = NSF_CSC_TYPE_PLAIN; register NsfObject *object; const char *methodName, *calledName; NsfObject *calledObject; NsfClass *class = NULL; Tcl_Obj *cmdName, *methodObj; const Tcl_ObjType *methodObjTypePtr; NsfColonCmdContext *ccCtxPtr; const NsfRuntimeState *rst; NsfCallStackContent csc, *cscPtr = NULL; Tcl_Command cmd = NULL; nonnull_assert(clientData != NULL); nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); object = (NsfObject *)clientData; cmdName = object->cmdName; rst = RUNTIME_STATE(interp); nsfObjectMethodEpoch = rst->objectMethodEpoch; /* * None of the higher copy-flags must be passed */ assert((flags & (NSF_CSC_COPY_FLAGS & 0x000FFF000U)) == 0u); /* * Do we have to shift the argument vector? */ if (unlikely((flags & NSF_CM_NO_SHIFT) != 0u)) { shift = 0; methodObj = objv[0]; methodName = MethodName(methodObj); calledName = ObjStr(methodObj);; } else { assert(objc > 1); shift = 1; methodObj = objv[1]; methodName = ObjStr(methodObj); calledName = methodName; if (unlikely(FOR_COLON_RESOLVER(methodName))) { return NsfPrintError(interp, "%s: method name '%s' must not start with a colon", ObjectName_(object), methodName); } } methodObjTypePtr = methodObj->typePtr; if (methodObjTypePtr == Nsf_OT_tclCmdNameType) { ccCtxPtr = methodObj->internalRep.twoPtrValue.ptr2; } else { ccCtxPtr = NULL; } #if 0 /* * This code block is purely for debugging erroneous behavior with broken * cached Tcl Command, where the command itself looks perfectly fine, but * the procPtr behind this contains invalid data. This seems to happen only * for scripted commands. In such cases, we do not trust the data obtained * from the Tcl_Obj. */ if (ccCtxPtr != NULL && ccCtxPtr->context == object && ccCtxPtr->methodEpoch == nsfObjectMethodEpoch && ccCtxPtr->flags == flags && ccCtxPtr->cmd != NULL && CmdIsProc(ccCtxPtr->cmd)) { /* fprintf(stderr, "cached scipted call %s (object %s class %s) cmd %p (proc %p) cmdName %s \n", methodName, ObjectName(object), ClassName(object->cl), ccCtxPtr->cmd, Tcl_Command_objClientData(ccCtxPtr->cmd), Tcl_GetCommandName(interp, ccCtxPtr->cmd));*/ Proc *procPtr = Tcl_Command_objClientData(ccCtxPtr->cmd); if ((Tcl_Interp *)procPtr->iPtr != interp || procPtr->bodyPtr == NULL || procPtr->refCount < 1 #ifdef PRE9 || procPtr->numArgs < 0 || procPtr->numCompiledLocals < 0 #endif || procPtr->numArgs > 10000 || procPtr->numCompiledLocals > 10000 ) { fprintf(stderr, "################### do NOT trust cached procPtr %p of %s " "(object %s class %s) bodyPtr %p " "iPtr %p interp %p refCount %lu numArgs %lu numCompiledLocals %lu\n", (void*)procPtr, methodName, ObjectName(object), ClassName(object->cl), (void*)procPtr->bodyPtr, (void*)procPtr->iPtr, (void*)interp, (unsigned long)procPtr->refCount, (unsigned long)procPtr->numArgs, (unsigned long)procPtr->numCompiledLocals); ccCtxPtr = NULL; } } #endif assert(object->teardown != NULL); #if defined(METHOD_OBJECT_TRACE) fprintf(stderr, "method %p/%d '%s' type %p <%s>\n", (void*)methodObj, methodObj->refCount, methodName, (void*)methodObjTypePtr, (methodObjTypePtr != NULL) ? methodObjTypePtr->name : ""); #endif /*fprintf(stderr, "==== ObjectDispatch obj = %s objc = %d 0=%s methodName=%s method-obj-type %s cmd %p shift %d\n", (object != NULL) ? ObjectName(object) : NULL, objc, objv[0] ? ObjStr(objv[0]) : NULL, methodName, methodObjTypePtr ? methodObjTypePtr->name : "NONE", (void*)cmd, shift);*/ objflags = object->flags; /* avoid stalling */ /* * Make sure, cmdName and obj survive this method until the end of * this function. */ INCR_REF_COUNT(cmdName); NsfObjectRefCountIncr(object); /*fprintf(stderr, "obj refCount of %p after incr %d (ObjectDispatch) %s\n", object, object->refCount, methodName);*/ if (unlikely((objflags & NSF_FILTER_ORDER_VALID) == 0u)) { FilterComputeDefined(interp, object); objflags = object->flags; } if (unlikely((objflags & NSF_MIXIN_ORDER_VALID) == 0u)) { MixinComputeDefined(interp, object); objflags = object->flags; } /* * Only start new filter chain, if * (a) filters are defined and * (b) the top-level csc entry is not a filter on self */ /*fprintf(stderr, "call %s, objflags %.6x, defined and valid %.6x doFilters %d guard count %d\n", methodName, objflags, NSF_FILTER_ORDER_DEFINED_AND_VALID, rst->doFilters, rst->guardCount);*/ assert((flags & (NSF_CSC_MIXIN_STACK_PUSHED|NSF_CSC_FILTER_STACK_PUSHED)) == 0u); if (unlikely((objflags & NSF_FILTER_ORDER_DEFINED_AND_VALID) == NSF_FILTER_ORDER_DEFINED_AND_VALID)) { if (rst->doFilters && !rst->guardCount) { const NsfCallStackContent *cscPtr1 = CallStackGetTopFrame0(interp); if ((cscPtr1 == NULL) || (object != cscPtr1->self) || (cscPtr1->frameType != NSF_CSC_TYPE_ACTIVE_FILTER) ) { FilterStackPush(object, methodObj); flags |= NSF_CSC_FILTER_STACK_PUSHED; cmd = FilterSearchProc(interp, object, &object->filterStack->currentCmdPtr, &class); if (cmd != NULL) { /*fprintf(stderr, "*** filterSearchProc returned cmd %p\n", cmd);*/ frameType = NSF_CSC_TYPE_ACTIVE_FILTER; methodName = (char *)Tcl_GetCommandName(interp, cmd); flags |= NSF_CM_IGNORE_PERMISSIONS; } } } } if (unlikely(cmd == NULL && ((flags & NSF_CM_LOCAL_METHOD) != 0u))) { /* * We require a local method. If the local method is found, we set always * the cmd and sometimes the class (if it is a class specific method). */ const NsfCallStackContent *cscPtr1 = CallStackGetTopFrame0(interp); if (unlikely(cscPtr1 == NULL)) { return NsfPrintError(interp, "flag '-local' only allowed when called from a method body"); } if (cscPtr1->cl != NULL) { cmd = FindMethod(cscPtr1->cl->nsPtr, methodName); if (cmd != NULL) { class = cscPtr1->cl; } } else if (object->nsPtr != NULL) { cmd = FindMethod(object->nsPtr, methodName); } /*fprintf(stderr, "ObjectDispatch NSF_CM_LOCAL_METHOD obj %s methodName %s => cl %p %s cmd %p \n", (object != NULL) ? ObjectName(object) : NULL, methodName, (void*)class, (class != NULL) ? ClassName(class) : "NONE", (void*)cmd);*/ } else if (unlikely(*methodName == ':')) { NsfObject *regObject; bool fromClassNS = NSF_FALSE; /* * We have fully qualified name provided. Determine the class and/or * object on which the method was registered. */ INCR_REF_COUNT(methodObj); cmd = ResolveMethodName(interp, NULL, methodObj, NULL, ®Object, NULL, NULL, &fromClassNS); DECR_REF_COUNT(methodObj); if (likely(cmd != NULL)) { if (CmdIsNsfObject(cmd)) { /* * Don't allow for calling objects as methods via fully qualified * names. Otherwise, in line [2] below, ::State (or any children of * it, e.g., ::Slot::child) is interpreted as a method candidate. As a * result, dispatch chaining occurs with ::State or ::State::child * being the receiver (instead of Class) of the method call * "-parameter". In such a dispatch chaining, the method "unknown" * won't be called on Class (in the XOTcl tradition), effectively * bypassing any unknown-based indirection mechanism (e.g., XOTcl's short-cutting * of object/class creations). * * [1] Class ::State; Class ::State::child * [2] Class ::State -parameter x; Class ::State::child -parameter x */ NsfLog(interp, NSF_LOG_NOTICE, "Don't invoke object %s this way. Register object via alias ...", methodName); cmd = NULL; } else { if (regObject != NULL) { if (NsfObjectIsClass(regObject)) { class = (NsfClass *)regObject; } } /* fprintf(stderr, "fully qualified lookup of %s returned %p\n", ObjStr(methodObj), cmd); */ /* * Ignore permissions for fully qualified method names. */ flags |= NSF_CM_IGNORE_PERMISSIONS; } /*fprintf(stderr, "ObjectDispatch fully qualified obj %s methodName %s => cl %p cmd %p \n", (object != NULL) ? ObjectName(object) : NULL, methodName, (void*)cl, (void*)cmd);*/ } } /*fprintf(stderr, "MixinStackPush check for %p %s.%s objflags %.6x == %d\n", object, ObjectName(object), methodName, objflags & NSF_MIXIN_ORDER_DEFINED_AND_VALID, (objflags & NSF_MIXIN_ORDER_DEFINED_AND_VALID) == NSF_MIXIN_ORDER_DEFINED_AND_VALID);*/ /* * Check whether a mixed in method has to be called. This is necessary, even when * cmd is already determined. */ if (unlikely((objflags & NSF_MIXIN_ORDER_DEFINED_AND_VALID) == NSF_MIXIN_ORDER_DEFINED_AND_VALID && (flags & (NSF_CM_SYSTEM_METHOD|NSF_CM_INTRINSIC_METHOD)) == 0u && ((flags & NSF_CM_LOCAL_METHOD) == 0u || class != NULL)) ) { /* * The current logic allocates first an entry on the per-object * stack and searches then for a mixin. This could be improved by * allocating a stack entry just when a mixin is found. The same * holds for the filters above, but there, the hit-rate is much * larger. */ MixinStackPush(object); flags |= NSF_CSC_MIXIN_STACK_PUSHED; if (frameType != NSF_CSC_TYPE_ACTIVE_FILTER) { Tcl_Command cmd1 = cmd; /* * The entry is just searched and pushed on the stack when we * have no filter; in the filter case, the search happens in * next. */ result = MixinSearchProc(interp, object, methodName, &class, &object->mixinStack->currentCmdPtr, &cmd1); if (unlikely(result != TCL_OK)) { /*fprintf(stderr, "mixinsearch returned an error for %p %s.%s\n", object, ObjectName(object), methodName);*/ isValidCsc = NSF_FALSE; goto exit_object_dispatch; } if (cmd1 != NULL) { frameType = NSF_CSC_TYPE_ACTIVE_MIXIN; cmd = cmd1; } } } /*fprintf(stderr, "ObjectDispatch ordinary lookup %s.%s cmd %p\n", ObjectName(object), ObjStr(methodObj), (void*)cmd);*/ /* * If no fully qualified method name/filter/mixin was found then perform * ordinary method lookup. First, try to resolve the method name as a * per-object method. */ if (likely(cmd == NULL)) { NsfMethodContext *mcPtr = methodObj->internalRep.twoPtrValue.ptr1; if (methodObjTypePtr == &NsfObjectMethodObjType && mcPtr->context == object && mcPtr->methodEpoch == nsfObjectMethodEpoch && mcPtr->flags == flags ) { cmd = mcPtr->cmd; #if defined(METHOD_OBJECT_TRACE) fprintf(stderr, "... use internal rep method %p %s cmd %p (objProc %p) cl %p %s\n", (void*)methodObj, ObjStr(methodObj), (void*)cmd, (cmd != NULL) ? (void*)((Command *)cmd)->objProc : 0, (void*)class, (class != NULL) ? ClassName(class) : ObjectName(object)); #endif assert((cmd != NULL) ? ((Command *)cmd)->objProc != NULL : 1); } else if (methodObjTypePtr == Nsf_OT_tclCmdNameType && ccCtxPtr != NULL && ccCtxPtr->context == object && ccCtxPtr->methodEpoch == nsfObjectMethodEpoch && ccCtxPtr->flags == flags ) { cmd = ccCtxPtr->cmd; class = ccCtxPtr ->class; ColonCmdCacheHit(ccCtxPtr); } else { /* * Check whether the call can be resolved against an object-specific method. */ if (unlikely((object->nsPtr != NULL) && (flags & (NSF_CM_NO_OBJECT_METHOD|NSF_CM_SYSTEM_METHOD)) == 0u)) { cmd = FindMethod(object->nsPtr, methodName); /*fprintf(stderr, "ObjectDispatch lookup for per-object method in obj %p method %s nsPtr %p" " => %p objProc %p\n", (void*)object, methodName, (void*)object->nsPtr, (void*)cmd, (cmd != NULL) ? (void*)((Command *)cmd)->objProc : NULL);*/ if (cmd != NULL) { /* * Reject resolved cmd when * a) trying to call a private method without the local flag or ignore permissions, or * b) trying to call an object with no method interface */ if (((flags & (NSF_CM_LOCAL_METHOD|NSF_CM_IGNORE_PERMISSIONS)) == 0u && ((unsigned int)Tcl_Command_flags(cmd) & NSF_CMD_CALL_PRIVATE_METHOD) != 0u) ) { cmd = NULL; } else { CacheCmd(interp, cmd, methodObj, &NsfObjectMethodObjType, object, nsfObjectMethodEpoch, NULL, flags, (*calledName == ':')); } } } } #if defined(INHERIT_CLASS_METHODS) /* * This is not optimized yet, since current class might be checked twice, * but easier to maintain. */ if ((flags & NSF_CM_NO_OBJECT_METHOD) == 0u && cmd == NULL && NsfObjectIsClass(object)) { cmd = NsfFindClassMethod(interp, (NsfClass *)object, methodName); } #endif if (likely(cmd == NULL)) { /* * Check whether the call can be resolved against an instance method. */ NsfClass *currentClass = object->cl; NsfMethodContext *mcPtr0 = methodObj->internalRep.twoPtrValue.ptr1; unsigned int nsfInstanceMethodEpoch = rst->instanceMethodEpoch; #if defined(METHOD_OBJECT_TRACE) fprintf(stderr, "... method %p/%d '%s' type %p %s type? %d context? %d nsfMethodEpoch %d => %d\n", (void*)methodObj, methodObj->refCount, ObjStr(methodObj), (void*)methodObjTypePtr, (methodObjTypePtr != NULL) ? methodObjTypePtr->name : "NONE", methodObjTypePtr == &NsfInstanceMethodObjType, methodObjTypePtr == &NsfInstanceMethodObjType ? mcPtr0->context == currentClass : 0, methodObjTypePtr == &NsfInstanceMethodObjType ? mcPtr0->methodEpoch : 0, nsfInstanceMethodEpoch ); #endif if (methodObjTypePtr == &NsfInstanceMethodObjType && mcPtr0->context == currentClass && mcPtr0->methodEpoch == nsfInstanceMethodEpoch && mcPtr0->flags == flags ) { cmd = mcPtr0->cmd; class = mcPtr0->cl; #if defined(METHOD_OBJECT_TRACE) fprintf(stderr, "... use internal rep method %p %s cmd %p (objProc %p) cl %p %s\n", (void*)methodObj, ObjStr(methodObj), (void*)cmd, (cmd != NULL) ? (void*)((Command *)cmd)->objProc : NULL, (void*)class, (class != NULL) ? ClassName(class) : ObjectName(object)); #endif assert((cmd != NULL) ? ((Command *)cmd)->objProc != NULL : 1); } else if (methodObjTypePtr == Nsf_OT_tclCmdNameType && ccCtxPtr != NULL && ccCtxPtr->context == currentClass && ccCtxPtr->methodEpoch == nsfInstanceMethodEpoch && ccCtxPtr->flags == flags ) { cmd = ccCtxPtr->cmd; class = ccCtxPtr ->class; ColonCmdCacheHit(ccCtxPtr); #if defined(METHOD_OBJECT_TRACE) fprintf(stderr, "... use internal rep ptr2 method %p %s cmd %p (objProc %p) cl %p %s\n", (void*)methodObj, ObjStr(methodObj), (void*)cmd, (cmd != NULL) ? (void*)((Command *)cmd)->objProc : NULL, (void*)class, (class != NULL) ? ClassName(class) : ObjectName(object)); #endif } else { /* * We could call PrecedenceOrder(currentClass) to recompute * currentClass->order on demand, but by construction this is already * set here. */ assert(currentClass->order); if (unlikely((flags & NSF_CM_SYSTEM_METHOD) != 0u)) { NsfClasses *classListPtr = currentClass->order; /* * Skip entries until the (first) base class. */ do { if (IsBaseClass(&classListPtr->cl->object)) { break; } classListPtr = classListPtr->nextPtr; } while (classListPtr->nextPtr != NULL); class = SearchPLMethod(classListPtr, methodName, &cmd, NSF_CMD_CALL_PRIVATE_METHOD); } else { class = SearchPLMethod(currentClass->order, methodName, &cmd, NSF_CMD_CALL_PRIVATE_METHOD); } /*fprintf(stderr, "... check type of methodObj %s type %s check %d\n", calledName, methodObjTypePtr ? methodObjTypePtr->name : "NONE", (((methodObjTypePtr != Nsf_OT_tclCmdNameType) || *calledName == ':') && methodObjTypePtr != Nsf_OT_parsedVarNameType && likely(cmd != NULL) ) );*/ if (likely(cmd != NULL)) { CacheCmd(interp, cmd, methodObj, &NsfInstanceMethodObjType, currentClass, nsfInstanceMethodEpoch, class, flags, (*calledName == ':')); } } } } calledObject = object; /* * If we have a command, check the permissions, unless * NSF_CM_IGNORE_PERMISSIONS is set. Note that NSF_CM_IGNORE_PERMISSIONS is * set currently for fully qualified cmd names and in nsf::object::dispatch. */ if (likely((cmd != NULL) && (flags & NSF_CM_IGNORE_PERMISSIONS) == 0u)) { const unsigned int cmdFlags = (unsigned int)Tcl_Command_flags(cmd); #if !defined(NDEBUG) if (unlikely(((cmdFlags & NSF_CMD_CALL_PRIVATE_METHOD) != 0u) && ((flags & NSF_CM_LOCAL_METHOD) == 0u)) ) { /* * Private methods can be only called with the "-local" flag. All cases * handling private methods should be covered above (e.g. by setting * NSF_CM_IGNORE_PERMISSIONS, or by filtering private methods in method * search. So, this branch should never by executed. */ Tcl_Panic("Unexpected handling of private method; most likely a caching bug"); cmd = NULL; } else #endif if (unlikely((cmdFlags & NSF_CMD_CALL_PROTECTED_METHOD) != 0u)) { const NsfObject *lastSelf = GetSelfObj(interp); /* * Protected methods can be called, when calling object == called object. */ if (unlikely(object != lastSelf)) { NsfLog(interp, NSF_LOG_WARN, "'%s %s' fails since method %s.%s is protected", ObjectName(object), methodName, (class != NULL) ? ClassName(class) : ObjectName(object), methodName); /* * Reset cmd, since it is still unknown. */ cmd = NULL; } } } assert(result == TCL_OK); if (likely(cmd != NULL)) { /* * We found the method to dispatch. */ const Tcl_Command resolvedCmd = AliasDereference(interp, object, methodName, cmd); if (unlikely(resolvedCmd == NULL)) { isValidCsc = NSF_FALSE; goto exit_object_dispatch; } /* * cscAlloc uses resolvedCmd for allocating the call stack content and * sets the IS_NRE flag based on it. We use the original cmd in the * call-stack content structure for introspection. */ cscPtr = CscAlloc(interp, &csc, resolvedCmd); CscInit(cscPtr, calledObject, class, cmd, frameType, flags, methodName); if (unlikely(cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_FILTER)) { /* * Run filters is not NRE enabled. */ cscPtr->flags |= NSF_CSC_IMMEDIATE; /* * Setting cscPtr->objc and cscPtr->objv is needed for invoking UNKNOWN * from ProcMethodDispatchFinalize() */ cscPtr->objc = objc - shift; cscPtr->objv = objv + shift; } /* fprintf(stderr, "MethodDispatchCsc %s.%s %p flags %.6x cscPtr %p method-obj-type %s\n", ObjectName(object), methodName, (void*)object->mixinStack, cscPtr->flags, (void*)cscPtr, methodObj->typePtr ? methodObj->typePtr->name : "NONE");*/ result = MethodDispatchCsc(clientData, interp, objc - shift, objv + shift, resolvedCmd, cscPtr, methodName, &isValidCsc); /* fprintf(stderr, "MethodDispatchCsc %s.%s %p flags %.6x cscPtr %p method-obj-type %s DONE\n", ObjectName(object), methodName, (void*)object->mixinStack, cscPtr->flags, (void*)cscPtr, methodObj->typePtr ? methodObj->typePtr->name : "NONE"); */ if (unlikely(result == TCL_ERROR)) { /*fprintf(stderr, "Call ErrInProc cl = %p, cmd %p, methodName %s flags %.6x\n", class, (class != NULL) ? class->object.id : NULL, methodName, (class != NULL) ? class->object.flags : 0);*/ result = NsfErrInProc(interp, cmdName, (class != NULL && class->object.teardown) ? class->object.cmdName : NULL, methodName); } } else { /* * The method to be dispatched is unknown */ cscPtr = CscAlloc(interp, &csc, cmd); CscInit(cscPtr, object, class, cmd, frameType, flags, methodName); cscPtr->flags |= NSF_CSC_METHOD_IS_UNKNOWN; if ((flags & NSF_CM_NO_UNKNOWN) != 0u) { cscPtr->flags |= NSF_CSC_CALL_NO_UNKNOWN; } cscPtr->objc = objc - shift; cscPtr->objv = objv + shift; } exit_object_dispatch: if (likely(isValidCsc)) { /* * In every situation, we have a cscPtr containing all context information */ assert(cscPtr != NULL); result = ObjectDispatchFinalize(interp, cscPtr, result /*, "immediate" , methodName*/); CscListRemove(interp, cscPtr, NULL); CscFinish(interp, cscPtr, result, "non-scripted finalize"); } /*fprintf(stderr, "ObjectDispatch %s.%s returns %d\n", ObjectName(object), methodName, result);*/ NsfCleanupObject(object, "ObjectDispatch"); /*fprintf(stderr, "ObjectDispatch call NsfCleanupObject %p DONE\n", object);*/ DECR_REF_COUNT(cmdName); /* must be after last dereferencing of obj */ return result; } /* *---------------------------------------------------------------------- * DispatchDefaultMethod -- * * Dispatch the default method (when object is called without arguments) * in case the object system has it defined. * * Results: * A standard Tcl result. * * Side effects: * indirect effects by calling Tcl code * *---------------------------------------------------------------------- */ static int DispatchDefaultMethod(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *obj, unsigned int flags) { int result; Tcl_Obj *methodObj; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(obj != NULL); if (CallDirectly(interp, object, NSF_o_defaultmethod_idx, &methodObj)) { Tcl_SetObjResult(interp, object->cmdName); result = TCL_OK; } else { Tcl_Obj *tov[2]; tov[0] = obj; tov[1] = methodObj; result = ObjectDispatch(object, interp, 2, tov, flags|NSF_CM_NO_UNKNOWN|NSF_CM_IGNORE_PERMISSIONS); } return result; } /* *---------------------------------------------------------------------- * DispatchDestroyMethod -- * * Dispatch the method "destroy" in case the object system has it * defined. During the final cleanup of the object system, the * destroy is called separately from deallocation. Normally, * Object.destroy() calls dealloc, which is responsible for the * physical deallocation. * * Results: * A standard Tcl result. * * Side effects: * indirect effects by calling Tcl code * *---------------------------------------------------------------------- */ static int DispatchDestroyMethod(Tcl_Interp *interp, NsfObject *object, unsigned int flags) { int result; NsfRuntimeState *rst; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); rst = RUNTIME_STATE(interp); if (unlikely(rst == NULL)) { /* * There is no run time state in this interpreter. */ if ((Tcl_Interp_flags(interp) & DELETED)) { /* * The interpreter is already deleted, just ignore this call. */ result = TCL_OK; } else { /* * In all other cases we expect a run time state. If this is violated, * something substantial must be wrong, so panic. */ Tcl_Panic("Runtime state is lost"); result = TCL_OK; } } else { /* * Don't call destroy after exit handler started physical * destruction, or when it was called already before */ if (rst->exitHandlerDestroyRound == NSF_EXITHANDLER_ON_PHYSICAL_DESTROY || (object->flags & NSF_DESTROY_CALLED) != 0u ) { result = TCL_OK; } else { Tcl_Obj *methodObj; /* * We can call destroy. */ /*fprintf(stderr, " DispatchDestroyMethod obj %p flags %.6x active %d\n", object, object->flags, object->activationCount); */ PRINTOBJ("DispatchDestroyMethod", object); /* * Flag that destroy was called and invoke the method. */ object->flags |= NSF_DESTROY_CALLED; if (CallDirectly(interp, object, NSF_o_destroy_idx, &methodObj)) { NSF_PROFILE_TIME_DATA; NSF_PROFILE_CALL(interp, object, Nsf_SystemMethodOpts[NSF_o_destroy_idx]); result = NsfODestroyMethod(interp, object); NSF_PROFILE_EXIT(interp, object, Nsf_SystemMethodOpts[NSF_o_destroy_idx]); } else { result = CallMethod(object, interp, methodObj, 2, NULL, NSF_CM_IGNORE_PERMISSIONS|NSF_CSC_IMMEDIATE|flags); } if (unlikely(result != TCL_OK)) { /* * The object might be already gone here, since we have no stack frame. * Therefore, we can't even use nsf::current object safely. */ NsfErrorContext(interp, "method destroy"); if (++rst->errorCount > 20) { Tcl_Panic("too many destroy errors occurred. Endless loop?"); } } else if (rst->errorCount > 0) { rst->errorCount--; } #ifdef OBJDELETION_TRACE fprintf(stderr, "DispatchDestroyMethod for %p exit\n", (void *)object); #endif } } return result; } /* *---------------------------------------------------------------------- * DispatchInitMethod -- * in case the object system has it * defined and it was not already called on the object, * * Results: * A standard Tcl result. * * Side effects: * Indirect effects by calling Tcl code * *---------------------------------------------------------------------- */ static int DispatchInitMethod(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const objv[], unsigned int flags) nonnull(1) nonnull(2); static int DispatchInitMethod(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const objv[], unsigned int flags) { int result; Tcl_Obj *methodObj; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); /* * check, whether init was called already */ if ((object->flags & (NSF_INIT_CALLED|NSF_DESTROY_CALLED)) == 0u) { /* * Flag the call to "init" before the dispatch, such that a call to * "configure" within init does not clear the already set instance * variables. */ object->flags |= NSF_INIT_CALLED; if (CallDirectly(interp, object, NSF_o_init_idx, &methodObj)) { /*fprintf(stderr, "%s init directly\n", ObjectName(object));*/ /* * Actually, nothing to do. */ result = TCL_OK; } else { result = CallMethod(object, interp, methodObj, objc+2, objv, flags|NSF_CM_IGNORE_PERMISSIONS|NSF_CSC_IMMEDIATE); } } else { result = TCL_OK; } return result; } /* *---------------------------------------------------------------------- * DispatchUnknownMethod -- * * Dispatch the method "unknown" in case the object system has it * defined and the application program contains an unknown handler. * * Results: * A standard Tcl result. * * Side effects: * There might be indirect effects by calling Tcl code; also, * the interp's unknown-state is reset. * *---------------------------------------------------------------------- */ static int DispatchUnknownMethod(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const objv[], Tcl_Obj *callInfoObj, Tcl_Obj *methodObj, unsigned int flags) { int result; Tcl_Obj *unknownObj; const char *methodName; NsfRuntimeState *rst; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(objv != NULL); nonnull_assert(methodObj != NULL); rst = RUNTIME_STATE(interp); methodName = MethodName(methodObj); unknownObj = NsfMethodObj(object, NSF_o_unknown_idx); /*fprintf(stderr, "compare unknownObj %p with methodObj %p '%s' %p %p %s -- %s\n", unknownObj, methodObj, ObjStr(methodObj), callInfoObj, (callInfoObj != NULL) ?objv[1]:NULL, (callInfoObj != NULL) ?ObjStr(objv[1]) : NULL, methodName);*/ if ((unknownObj != NULL) && (methodObj != unknownObj) && (flags & NSF_CSC_CALL_NO_UNKNOWN) == 0u ) { /* * Back off and try unknown. */ bool mustCopy = (*(ObjStr(methodObj)) == ':'); ALLOC_ON_STACK(Tcl_Obj*, objc+3, tov); if (callInfoObj == NULL) { callInfoObj = (mustCopy ? Tcl_NewStringObj(methodName, TCL_INDEX_NONE) : methodObj); } INCR_REF_COUNT(callInfoObj); /*fprintf(stderr, "calling unknown for %s %s, flags=%.6x,%.6x/%.6x isClass=%d %p %s objc %d\n", ObjectName(object), ObjStr(methodObj), flags, NSF_CM_NO_UNKNOWN, NSF_CSC_CALL_NO_UNKNOWN, NsfObjectIsClass(object), object, ObjectName(object), objc);*/ tov[0] = object->cmdName; tov[1] = unknownObj; tov[2] = callInfoObj; if (objc > 1) { memcpy(tov + 3, objv + 1, sizeof(Tcl_Obj *) * ((size_t)objc - 1u)); } flags &= ~NSF_CM_NO_SHIFT; /*fprintf(stderr, "call unknown via dispatch mustCopy %d delegator %p method %s (%s)\n", mustCopy, delegator, ObjStr(tov[offset]), ObjStr(methodObj));*/ result = ObjectDispatch(object, interp, objc+2, tov, flags|NSF_CM_NO_UNKNOWN|NSF_CM_IGNORE_PERMISSIONS); DECR_REF_COUNT(callInfoObj); FREE_ON_STACK(Tcl_Obj*, tov); } else { Tcl_Obj *tailMethodObj = NULL; /* * No unknown called. This is the built-in unknown handler. */ if (objc > 1 && ((*methodName) == '-' || (unknownObj && objv[0] == unknownObj))) { int length; tailMethodObj = objv[1]; if ((((object->flags & NSF_KEEP_CALLER_SELF) != 0u) || ((object->flags & NSF_PER_OBJECT_DISPATCH) != 0u)) && Tcl_ListObjLength(interp, objv[1], &length) == TCL_OK) { if (length > 1) { Tcl_ListObjIndex(interp, objv[1], (TCL_SIZE_T)length - 1, &tailMethodObj); } } } result = NsfPrintError(interp, "%s: unable to dispatch method '%s'", ObjectName_(object), (tailMethodObj != NULL) ? MethodName(tailMethodObj) : methodName); } /* * Reset interp state, unknown has been fired. */ rst->unknown = 0; return result; } /* *---------------------------------------------------------------------- * NsfObjDispatch -- * * This function is called on every object dispatch (when an object * is invoked). It calls either the passed method, or dispatches * some default method. * * Results: * A standard Tcl result. * * Side effects: * Maybe side effects by the cmd called by ParameterCheck() * or DispatchUnknownMethod() * *---------------------------------------------------------------------- */ #if defined(NRE) Tcl_ObjCmdProc NsfObjDispatchNRE; int NsfObjDispatch(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { nonnull_assert(clientData != NULL); nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); return Tcl_NRCallObjProc(interp, NsfObjDispatchNRE, clientData, (TCL_SIZE_T)objc, objv); } int NsfObjDispatchNRE(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) nonnull(1) nonnull(2) nonnull(4); int NsfObjDispatchNRE(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) #else EXTERN int NsfObjDispatch(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) #endif { int result; #ifdef STACK_TRACE NsfStackDump(interp); #endif nonnull_assert(clientData != NULL); nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); if (likely(objc > 1)) { /* * Normal dispatch; we must not use NSF_CSC_IMMEDIATE here, * otherwise coroutines won't work. */ result = ObjectDispatch(clientData, interp, objc, objv, 0u); } else { result = DispatchDefaultMethod(interp, (NsfObject *)clientData, objv[0], NSF_CSC_IMMEDIATE); } return result; } /* * Proc-Creation */ /* *---------------------------------------------------------------------- * AddPrefixToBody -- * * Create a fresh TclObj* containing the body with a potential prefix. * The caller has to decrement the ref-count on this Tcl_Obj*. * * Results: * Tcl_Obj * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj * AddPrefixToBody(Tcl_Obj *body, bool useParamDefs, NsfParsedParam *paramPtr) nonnull(1) nonnull(3); static Tcl_Obj * AddPrefixToBody(Tcl_Obj *body, bool useParamDefs, NsfParsedParam *paramPtr) { Tcl_Obj *resultBody = Tcl_NewObj(); nonnull_assert(body != NULL); nonnull_assert(paramPtr != NULL); INCR_REF_COUNT2("resultBody", resultBody); if (useParamDefs && paramPtr->possibleUnknowns > 0) { Tcl_AppendStringsToObj(resultBody, "::nsf::__unset_unknown_args\n", (char *) NULL); } Tcl_AppendStringsToObj(resultBody, ObjStr(body), (char *) NULL); return resultBody; } /* *---------------------------------------------------------------------- * NoMetaChars -- * * Check, of the provided string contains meta characters * (i.e. "*", "?", or "[") * * Results: * Boolean value * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static bool NoMetaChars(const char *pattern) nonnull(1) NSF_pure; NSF_INLINE static bool NoMetaChars(const char *pattern) { register char c; bool result = NSF_TRUE; nonnull_assert(pattern != NULL); for (c = *pattern; c; c = *++pattern) { if (c == '*' || c == '?' || c == '[') { result = NSF_FALSE; break; } } return result; } /*********************************************************************** * Nsf_TypeConverter ***********************************************************************/ /* *---------------------------------------------------------------------- * Nsf_ConvertToString -- * * Minimal Nsf_TypeConverter setting the client data (passed to C * functions) to the ObjStr of the object. * * Results: * Tcl result code, *clientData and **outObjPtr * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_ConvertToString(Tcl_Interp *UNUSED(interp), Tcl_Obj *objPtr, const Nsf_Param *UNUSED(pPtr), ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) nonnull(2) nonnull(4); int Nsf_ConvertToString(Tcl_Interp *UNUSED(interp), Tcl_Obj *objPtr, const Nsf_Param *UNUSED(pPtr), ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) { nonnull_assert(objPtr != NULL); nonnull_assert(clientData != NULL); *clientData = (char *)ObjStr(objPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * ConvertToNothing -- * * Minimalistic Nsf_TypeConverter, even setting the client data (passed to * C functions). * * Results: * Tcl result code, **outObjPtr * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ConvertToNothing(Tcl_Interp *UNUSED(interp), Tcl_Obj *objPtr, const Nsf_Param *UNUSED(pPtr), ClientData *UNUSED(clientData), Tcl_Obj **outObjPtr) nonnull(2) nonnull(5) NSF_pure; static int ConvertToNothing(Tcl_Interp *UNUSED(interp), Tcl_Obj *objPtr, const Nsf_Param *UNUSED(pPtr), ClientData *UNUSED(clientData), Tcl_Obj **outObjPtr) { nonnull_assert(objPtr != NULL); nonnull_assert(outObjPtr != NULL); assert(*outObjPtr == objPtr); *outObjPtr = objPtr; return TCL_OK; } #ifdef NSF_WITH_TCL_OBJ_TYPES_AS_CONVERTER int Nsf_ConvertToTclObjType(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(5); int Nsf_ConvertToTclObjType(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int result = TCL_OK; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(clientData != NULL); fprintf(stderr, "Nsf_ConvertToTclObjType: converterArg %p\n", (void*)pPtr->converterArg); if (unlikely(pPtr->converterArg != NULL)) { const Tcl_ObjType *tclObjType = pPtr->converterArg->internalRep.twoPtrValue.ptr1; if (tclObjType != NULL) { result = Tcl_ConvertToType(interp, objPtr, tclObjType); fprintf(stderr, "Nsf_ConvertToTclObjType:type %p -> %d\n", (void*)tclObjType, result); if (result != TCL_OK) { Tcl_ResetResult(interp); result = NsfObjErrType(interp, NULL, objPtr, tclObjType->name, (Nsf_Param *)pPtr); } } } *outObjPtr = objPtr; /* nsf::proc foo {a:ns:mem_unit} {return $a} nsf::proc bar {a:ns:mem_unit} {return [expr {$a + 1}]} foo 1kB foo xxx bar 1kB */ return result; } #endif /* *---------------------------------------------------------------------- * Nsf_ConvertToTclobj -- * * Nsf_TypeConverter setting the client data (passed to C functions) to the * passed Tcl_Obj. Optionally this converter checks if the Tcl_Obj has * permissible content via the Tcl "string is" checkers. * * Results: * Tcl result code, *clientData and **outObjPtr * * Side effects: * None. * *---------------------------------------------------------------------- */ enum stringTypeIdx {StringTypeAlnum, StringTypeAlpha, StringTypeAscii, StringTypeBoolean, StringTypeControl, StringTypeDigit, StringTypeDouble, StringTypeFalse, StringTypeGraph, StringTypeInteger, StringTypeLower, StringTypePrint, StringTypePunct, StringTypeSpace, StringTypeTrue, StringTypeUpper, StringTypeWideinteger, StringTypeWordchar, StringTypeXdigit }; static const char *stringTypeOpts[] = {"alnum", "alpha", "ascii", "boolean", "control", "digit", "double", "false", "graph", "integer", "lower", "print", "punct", "space", "true", "upper", "wideinteger", "wordchar", "xdigit", NULL}; int Nsf_ConvertToTclobj(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(5); int Nsf_ConvertToTclobj(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) { int result; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(clientData != NULL); if (unlikely(pPtr->converterArg != NULL)) { Tcl_Obj *objv[4]; /*fprintf(stderr, "ConvertToTclobj %s (must be %s)\n", ObjStr(objPtr), ObjStr(pPtr->converterArg));*/ objv[0] = NULL; objv[1] = pPtr->converterArg; objv[2] = NsfGlobalObjs[NSF_OPTION_STRICT]; objv[3] = objPtr; result = NsfCallCommand(interp, NSF_STRING_IS, 4, objv); if (likely(result == TCL_OK)) { int success; Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &success); if (success == 1) { *clientData = objPtr; } else { Tcl_ResetResult(interp); result = NsfObjErrType(interp, NULL, objPtr, ObjStr(pPtr->converterArg), (Nsf_Param *)pPtr); } } } else { result = TCL_OK; #if defined(NSF_WITH_VALUE_WARNINGS) if (RUNTIME_STATE(interp)->logSeverity == NSF_LOG_DEBUG) { const char *value = ObjStr(objPtr); if (unlikely(*value == '-' && (pPtr->flags & NSF_ARG_CHECK_NONPOS) != 0u && isalpha(*(value+1)) && strchr(value+1, ' ') == NULL) ) { /* * In order to flag a warning, we set the error message and * return TCL_CONTINUE */ (void)NsfPrintError(interp, "value '%s' of parameter '%s' could be a non-positional argument", value, pPtr->name); result = TCL_CONTINUE; } } #endif *clientData = objPtr; } return result; } /* *---------------------------------------------------------------------- * Nsf_ConvertToBoolean -- * * Nsf_TypeConverter setting the client data (passed to C functions) to the * internal representation of a boolean. This converter checks the passed * value via Tcl_GetBooleanFromObj(). * * Results: * Tcl result code, *clientData and **outObjPtr * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_ConvertToBoolean(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(5); int Nsf_ConvertToBoolean(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) { int result, boolVal; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(clientData != NULL); result = Tcl_GetBooleanFromObj(interp, objPtr, &boolVal); if (likely(result == TCL_OK)) { *clientData = (ClientData)INT2PTR(boolVal); } else { Tcl_ResetResult(interp); NsfObjErrType(interp, NULL, objPtr, "boolean", pPtr); } return result; } /* *---------------------------------------------------------------------- * Nsf_ConvertToInt32 -- * * Nsf_TypeConverter setting the client data (passed to C functions) to the * internal representation of an integer. This converter checks the passed * value via Tcl_GetIntFromObj(). * * Results: * Tcl result code, *clientData and **outObjPtr * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_ConvertToInt32(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) nonnull(1) nonnull(2) nonnull(3) nonnull(4); int Nsf_ConvertToInt32(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) { int result, i; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(clientData != NULL); result = Tcl_GetIntFromObj(interp, objPtr, &i); if (likely(result == TCL_OK)) { *clientData = (ClientData)INT2PTR(i); } else { Tcl_ResetResult(interp); NsfObjErrType(interp, NULL, objPtr, "int32", (Nsf_Param *)pPtr); } return result; } /* *---------------------------------------------------------------------- * Nsf_ConvertToInteger -- * * Nsf_TypeConverter setting the client data (passed to C functions) to the * Tcl_Obj containing the bignum value. This converter checks the passed * value via Tcl_GetBignumFromObj(). * * Results: * Tcl result code, *clientData and **outObjPtr * * Side effects: * None. * *---------------------------------------------------------------------- */ #if TCL_MAJOR_VERSION > 8 || TCL_MINOR_VERSION > 6 /* * Starting with Tcl 8.7a4 and TIP 538, NSF might end up built against Tcl * linking against a system-wide/ external libtommath, rather than with an * embedded libtommath. In both cases, even the embedded one, Tcl does not * ship tommat.h anymore. This leaves NSF without the necessary build-time * definitions for mp_int and mp_clear (see below). For the time being, we * rely on a hot fix by the TIP 538 author, providing compat definitions when * setting the TCL_NO_TOMMATH_H macro before including tclTomMath.h. * * See https://core.tcl-lang.org/tcl/tktview?name=4663e0636f (also for other * mid-term options) */ //#define TCL_NO_TOMMATH_H 1 # ifndef MP_INT_DECLARED typedef size_t mp_int[4]; # endif #else # include #endif int Nsf_ConvertToInteger(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(5); int Nsf_ConvertToInteger(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) { int result; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(clientData != NULL); /* * Try to short_cut common cases to avoid conversion to bignums, since * Tcl_GetBignumFromObj returns a value, which has to be freed. */ if (objPtr->typePtr == Nsf_OT_intType || objPtr->typePtr == Nsf_OT_bignumType) { /* * We know already that the value is an int */ result = TCL_OK; } else if (objPtr->typePtr == Nsf_OT_doubleType) { /* * We know already that the value is not an int */ result = TCL_ERROR; } else { long longValue; Tcl_WideInt wideIntValue; mp_int bignumValue; /* * We have to figure out, whether the value is an int. We perform this * test via Tcl_GetBignumFromObj(), which tries to keep the type small if * possible (e.g. it might return type "int" or "float" when appropriate. */ /*if (objPtr->typePtr != NULL) { fprintf(stderr, "### type is on call %p %s value %s \n", objPtr->typePtr, ObjTypeStr(objPtr), ObjStr(objPtr)); }*/ if ((result = Tcl_GetLongFromObj(interp, objPtr, &longValue)) == TCL_OK) { } else if ((result = Tcl_GetWideIntFromObj(interp, objPtr, &wideIntValue)) == TCL_OK) { } else if ((result = Tcl_GetBignumFromObj(interp, objPtr, &bignumValue)) == TCL_OK) { Tcl_Obj *bigNumObj = Tcl_NewBignumObj(&bignumValue); Tcl_DecrRefCount(bigNumObj); /* fprintf(stderr, "### IS BIG %s\n", objPtr->typePtr->name); */ } } if (likely(result == TCL_OK)) { *clientData = (ClientData)objPtr; } else { Tcl_ResetResult(interp); NsfObjErrType(interp, NULL, objPtr, "integer", (Nsf_Param *)pPtr); } return result; } /* *---------------------------------------------------------------------- * Nsf_ConvertToSwitch -- * * Nsf_TypeConverter setting the client data (passed to C functions) to the * internal representation of an Boolean. This converter simply calls * Tcl_ConvertToBoolean(). The distinction between "switch" and boolean is * made on the semantics of which arguments/defaults are passed to the real * converter. * * Results: * Tcl result code, *clientData and **outObjPtr * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_ConvertToSwitch(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(5); int Nsf_ConvertToSwitch(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(clientData != NULL); nonnull_assert(outObjPtr != NULL); return Nsf_ConvertToBoolean(interp, objPtr, pPtr, clientData, outObjPtr); } /* *---------------------------------------------------------------------- * Nsf_ConvertToObject -- * * Nsf_TypeConverter setting the client data (passed to C functions) to the * internal representation of an object. This converter checks the passed * value via IsObjectOfType(). * * Results: * Tcl result code, *clientData and **outObjPtr * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_ConvertToObject(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) nonnull(1) nonnull(2) nonnull(3) nonnull(4); int Nsf_ConvertToObject(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) { int result; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(clientData != NULL); if (likely(GetObjectFromObj(interp, objPtr, (NsfObject **)clientData) == TCL_OK)) { result = IsObjectOfType(interp, (NsfObject *)*clientData, "object", objPtr, pPtr); } else { result = NsfObjErrType(interp, NULL, objPtr, "object", (Nsf_Param *)pPtr); } return result; } /* *---------------------------------------------------------------------- * Nsf_ConvertToClass -- * * Nsf_TypeConverter setting the client data (passed to C functions) to the * internal representation of a class. This converter checks the passed * value via IsObjectOfType(). * * Results: * Tcl result code, *clientData and **outObjPtr * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_ConvertToClass(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) nonnull(1) nonnull(2) nonnull(3) nonnull(4); int Nsf_ConvertToClass(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) { bool withUnknown; int result; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(clientData != NULL); withUnknown = (RUNTIME_STATE(interp)->doClassConverterOmitUnknown == 0); if (likely(GetClassFromObj(interp, objPtr, (NsfClass **)clientData, withUnknown) == TCL_OK)) { result = IsObjectOfType(interp, (NsfObject *)*clientData, "class", objPtr, pPtr); } else { result = NsfObjErrType(interp, NULL, objPtr, "class", (Nsf_Param *)pPtr); } return result; } /* *---------------------------------------------------------------------- * Nsf_ConvertToFilterreg -- * * Nsf_TypeConverter setting the client data (passed to C functions) to the * Tcl_Obj. This nsf type converter checks the passed value via the * NsfFilterregObjType tcl_obj converter, which provides an internal * representation for the client function. * * Results: * Tcl result code, *clientData and **outObjPtr * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_ConvertToFilterreg(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) nonnull(1) nonnull(2) nonnull(3) nonnull(4); int Nsf_ConvertToFilterreg(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) { int result; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(clientData != NULL); result = Tcl_ConvertToType(interp, objPtr, &NsfFilterregObjType); if (likely(result == TCL_OK)) { *clientData = objPtr; } else { result = NsfObjErrType(interp, NULL, objPtr, "filterreg", (Nsf_Param *)pPtr); } return result; } /* *---------------------------------------------------------------------- * Nsf_ConvertToMixinreg -- * * Nsf_TypeConverter setting the client data (passed to C functions) to the * Tcl_Obj. This nsf type converter checks the passed value via the * NsfMixinregObjType tcl_obj converter, which provides an internal * representation for the client function. * * Results: * Tcl result code, *clientData and **outObjPtr * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_ConvertToMixinreg(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) nonnull(1) nonnull(2) nonnull(3) nonnull(4); int Nsf_ConvertToMixinreg(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) { int result; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(clientData != NULL); result = Tcl_ConvertToType(interp, objPtr, &NsfMixinregObjType); if (likely(result == TCL_OK)) { *clientData = objPtr; } else { result = NsfObjErrType(interp, NULL, objPtr, "mixinreg", (Nsf_Param *)pPtr); } return result; } /* *---------------------------------------------------------------------- * Nsf_ConvertToParameter -- * * Nsf_TypeConverter setting the client data (passed to C functions) to the * Tcl_Obj. This nsf type converter checks if the provided value could be a * valid parameter spec (i.e. start with no ":", is not an unnamed spec * "-:int"). This converter performs just a rough syntactic check. * * Results: * Tcl result code, *clientData and **outObjPtr * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_ConvertToParameter(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) nonnull(1) nonnull(2) nonnull(3) nonnull(4); int Nsf_ConvertToParameter(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **UNUSED(outObjPtr)) { const char *value; int result; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(clientData != NULL); value = ObjStr(objPtr); /*fprintf(stderr, "convert to parameter '%s' t '%s'\n", value, pPtr->type);*/ if (*value == ':' || (*value == '-' && *(value + 1) == ':')) { result = NsfPrintError(interp, "leading colon in '%s' not allowed in parameter specification '%s'", ObjStr(objPtr), pPtr->name); } else { *clientData = (char *)ObjStr(objPtr); result = TCL_OK; } return result; } /* *---------------------------------------------------------------------- * ConvertViaCmd -- * * Nsf_TypeConverter calling a used-defined checking/conversion * function. It sets the client data (passed to C functions) to the * Tcl_Obj. * * Results: * Tcl result code, *clientData and **outObjPtr * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ConvertViaCmd(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(5); static int ConvertViaCmd(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { Tcl_Obj *ov[5], *savedResult; NsfObject *object; int result, oc; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(clientData != NULL); nonnull_assert(outObjPtr != NULL); /* * In general, when the converter is used e.g. for result checking, * we do not want to alter the result just when the converter sets a * result. So, for non-converter, we save the old result and restore * it before the return in case of success. Strictly speaking, * result-overwriting just harms for result-converters, but saving is * always semantically correct. */ if (unlikely((pPtr->flags & NSF_ARG_IS_CONVERTER) == 0u)) { savedResult = Tcl_GetObjResult(interp); /* save the result */ INCR_REF_COUNT(savedResult); } else { savedResult = NULL; } ov[0] = (pPtr->slotObj != NULL) ? pPtr->slotObj : NsfGlobalObjs[NSF_METHOD_PARAMETER_SLOT_OBJ]; ov[1] = pPtr->converterName; ov[2] = pPtr->nameObj; ov[3] = objPtr; oc = 4; if (pPtr->converterArg != NULL) { ov[4] = pPtr->converterArg; oc++; } /*fprintf(stderr, "ConvertViaCmd call converter %s (refCount %d) on %s paramPtr %p arg %p oc %d\n", ObjStr(pPtr->converterName), pPtr->converterName->refCount, ObjStr(ov[0]), pPtr, pPtr->converterArg, oc);*/ INCR_REF_COUNT(ov[1]); INCR_REF_COUNT(ov[2]); /* result = Tcl_EvalObjv(interp, oc, ov, 0); */ result = GetObjectFromObj(interp, ov[0], &object); if(likely(result == TCL_OK)) { result = ObjectDispatch(object, interp, oc, ov, NSF_CSC_IMMEDIATE|NSF_CM_IGNORE_PERMISSIONS); } DECR_REF_COUNT(ov[1]); DECR_REF_COUNT(ov[2]); /* * Per default, the input arg is the output arg. */ assert(*outObjPtr == objPtr); if (likely(result == TCL_OK)) { /*fprintf(stderr, "ConvertViaCmd could convert %s to '%s' paramPtr %p, is_converter %d\n", ObjStr(objPtr), ObjStr(Tcl_GetObjResult(interp)), pPtr, pPtr->flags & NSF_ARG_IS_CONVERTER);*/ if ((pPtr->flags & NSF_ARG_IS_CONVERTER) != 0u) { Tcl_Obj *resultObj; /* * If we want to convert, the resulting obj is the result of the * converter. The increment of the refCount is necessary e.g. for * * return [expr {$value + 1}] * * The conversion is just needed, when resultObj differs from the actual * value in the output vector. Otherwise the conversion and the value * increment happened already before (and is already recorded in the * parse context). */ resultObj = Tcl_GetObjResult(interp); if (*outObjPtr != resultObj) { INCR_REF_COUNT2("valueObj", resultObj); *outObjPtr = resultObj; } /*fprintf(stderr, "**** NSF_ARG_IS_CONVERTER %p\n", *outObjPtr);*/ } *clientData = (ClientData) *outObjPtr; if (savedResult != NULL) { /*fprintf(stderr, "restore savedResult %p\n", savedResult);*/ Tcl_SetObjResult(interp, savedResult); /* restore the result */ } } if (savedResult != NULL) { DECR_REF_COUNT(savedResult); } return result; } /* *---------------------------------------------------------------------- * ConvertToObjpattern -- * * This function obtains a Tcl_Obj *, which contains the pattern if a Next * Scripting Object. When this pattern contains no meta characters, we * check whether the object exists. If it exists, the Tcl_Obj is converted to * the cmd-type. If it does not exit, the function using this pattern will * fail. If the pattern contains meta characters, we prepend to the pattern * "::" if necessary to avoid errors, if one specifies a pattern object * without the prefix. In this case, the patternObj is of plain type. * The resulting patternObj has always the refCount incremented, which has * to be decremented by the caller.x * * Results: * A standard Tcl result. * * Side effects: * Incremented refCount for the patternObj. * *---------------------------------------------------------------------- */ static int ConvertToObjpattern(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *UNUSED(pPtr), ClientData *clientData, Tcl_Obj **outObjPtr) nonnull(1) nonnull(2) nonnull(4) nonnull(5); static int ConvertToObjpattern(Tcl_Interp *interp, Tcl_Obj *objPtr, const Nsf_Param *UNUSED(pPtr), ClientData *clientData, Tcl_Obj **outObjPtr) { Tcl_Obj *patternObj; const char *pattern; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(clientData != NULL); nonnull_assert(outObjPtr != NULL); patternObj = objPtr; pattern = ObjStr(objPtr); if (NoMetaChars(pattern)) { /* * We have no meta characters, we try to check for an existing object */ NsfObject *object = NULL; if (GetObjectFromObj(interp, objPtr, &object) == TCL_OK && object != NULL) { patternObj = object->cmdName; } } else { /* * We have a pattern and meta characters, we might have * to prefix it to ovoid obvious errors: since all object * names are prefixed with ::, we add this prefix automatically * to the match pattern, if it does not exist. */ if (*pattern != ':' && *pattern+1 != ':') { patternObj = Tcl_NewStringObj("::", 2); Tcl_AppendLimitedToObj(patternObj, pattern, TCL_INDEX_NONE, INT_MAX, NULL); } } if (patternObj != NULL) { INCR_REF_COUNT2("patternObj", patternObj); } *clientData = (ClientData)patternObj; /* The following assert does not hold here, since we have a direct call to the converter assert(*outObjPtr == objPtr); */ *outObjPtr = objPtr; return TCL_OK; } /* *---------------------------------------------------------------------- * ParamCheckObj -- * * This function returns a fresh Tcl_Obj in the form of a method name for a * checker method. * * Results: * Tcl_Obj * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj *ParamCheckObj(const char *start, size_t len) nonnull(1) returns_nonnull; static Tcl_Obj * ParamCheckObj(const char *start, size_t len) { Tcl_Obj *checker = Tcl_NewStringObj("type=", 5); nonnull_assert(start != NULL); Tcl_AppendLimitedToObj(checker, start, (TCL_SIZE_T)len, INT_MAX, NULL); return checker; } /* *---------------------------------------------------------------------- * ParamOptionSetConverter -- * * Fill in the fields int to the specified paramPtr structure * checker method and perform sanity checking. * * Results: * Standard result code * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ParamOptionSetConverter(Tcl_Interp *interp, Nsf_Param *paramPtr, const char *typeName, Nsf_TypeConverter *converter) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static int ParamOptionSetConverter(Tcl_Interp *interp, Nsf_Param *paramPtr, const char *typeName, Nsf_TypeConverter *converter) { int result; nonnull_assert(interp != NULL); nonnull_assert(paramPtr != NULL); nonnull_assert(typeName != NULL); nonnull_assert(converter != NULL); if (paramPtr->converter != NULL) { result = NsfPrintError(interp, "refuse to redefine parameter type of '%s' from type '%s' to type '%s'", paramPtr->name, paramPtr->type, typeName); } else { paramPtr->converter = converter; paramPtr->nrArgs = 1; paramPtr->type = typeName; result = TCL_OK; } return result; } /* *---------------------------------------------------------------------- * Unescape -- * * Unescape double commas in the provided Tcl_Obj. * * Results: * None. * * Side effects: * Potentially shortened string content * *---------------------------------------------------------------------- */ static void Unescape(Tcl_Obj *objPtr) nonnull(1); static void Unescape(Tcl_Obj *objPtr) { TCL_SIZE_T i, j, l; char *string; nonnull_assert(objPtr != NULL); l = Tcl_GetCharLength(objPtr); string = ObjStr(objPtr); for (i = 0; i < l; i++) { if (string[i] == ',' && string[i+1] == ',') { for (j = i+1; j < l; j++) { string[j] = string[j+1]; } l--; i++; } } Tcl_SetObjLength(objPtr, l); } /* *---------------------------------------------------------------------- * ParamOptionParse -- * * Parse a single parameter option of a parameter. The parameter option * string is passed in as second argument, the sizes start and remainder * flag the offsets in the string follow. As a result, the fields of the * parameter structure are updated. * * Results: * Tcl result code, updated fields in the Nsf_Param structure. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ParamOptionParse(Tcl_Interp *interp, const char *argString, size_t start, size_t optionLength, unsigned int disallowedOptions, Nsf_Param *paramPtr, bool unescape, const char *qualifier) nonnull(1) nonnull(2) nonnull(6); static int ParamOptionParse(Tcl_Interp *interp, const char *argString, size_t start, size_t optionLength, unsigned int disallowedOptions, Nsf_Param *paramPtr, bool unescape, const char *qualifier) { const char *dotdot, *option; char firstChar; int result = TCL_OK; nonnull_assert(interp != NULL); nonnull_assert(argString != NULL); nonnull_assert(paramPtr != NULL); option = argString + start; firstChar = *option; /*fprintf(stderr, "ParamOptionParse name %s, option '%s' (%ld) disallowed %.6x\n", paramPtr->name, option, start, disallowedOptions);*/ /* * Allow user to abbreviate "required", "optional" and "int" to 3 chars. */ if (firstChar == 'r' && optionLength <= 8 && strncmp(option, "required", NsfMax(3, optionLength)) == 0) { paramPtr->flags |= NSF_ARG_REQUIRED; } else if (firstChar == 'o' && optionLength <= 8 && strncmp(option, "optional", NsfMax(3, optionLength)) == 0) { paramPtr->flags &= ~NSF_ARG_REQUIRED; } else if (firstChar == 's' && optionLength == 12 && strncmp(option, "substdefault", 12) == 0 ) { int substDefaultFlags = 0; char trailingChar = *(option+12); if (trailingChar == '=') { if ((Tcl_GetInt(interp, option + 13, &substDefaultFlags) != TCL_OK) || (substDefaultFlags < 0) || (substDefaultFlags > 7)) { return NsfPrintError(interp, "parameter option 'substdefault=' must be a value between 0b000 and 0b111: %s", option); } } else if (trailingChar == '\0' || trailingChar == ',') { substDefaultFlags = 7; } else { return NsfPrintError(interp, "unexpected character %c (%d) after 'substdefault'", trailingChar, trailingChar); } paramPtr->flags |= NSF_ARG_SUBST_DEFAULT; paramPtr->flags |= ((unsigned int)substDefaultFlags << 28); } else if (firstChar == 'c' && optionLength == 7 && strncmp(option, "convert", 7) == 0) { paramPtr->flags |= NSF_ARG_IS_CONVERTER; } else if (firstChar == 'i' && optionLength == 7 && strncmp(option, "initcmd", 7) == 0) { if (unlikely((paramPtr->flags & (NSF_ARG_CMD|NSF_ARG_ALIAS|NSF_ARG_FORWARD)) != 0u)) { return NsfPrintError(interp, "parameter option 'initcmd' not valid in this option combination"); } paramPtr->flags |= NSF_ARG_INITCMD; } else if (firstChar == 'c' && optionLength == 3 && strncmp(option, "cmd", 3) == 0) { if (unlikely((paramPtr->flags & (NSF_ARG_INITCMD|NSF_ARG_ALIAS|NSF_ARG_FORWARD)) != 0u)) { return NsfPrintError(interp, "parameter option 'cmd' not valid in this option combination"); } paramPtr->flags |= NSF_ARG_CMD; } else if (firstChar == 'a' && optionLength == 5 && strncmp(option, "alias", 5) == 0) { if (unlikely((paramPtr->flags & (NSF_ARG_INITCMD|NSF_ARG_CMD|NSF_ARG_FORWARD)) != 0u)) { return NsfPrintError(interp, "parameter option 'alias' not valid in this option combination"); } paramPtr->flags |= NSF_ARG_ALIAS; } else if (firstChar == 'f' && optionLength == 7 && strncmp(option, "forward", 7) == 0) { if (unlikely((paramPtr->flags & (NSF_ARG_INITCMD|NSF_ARG_CMD|NSF_ARG_ALIAS)) != 0u)) { return NsfPrintError(interp, "parameter option 'forward' not valid in this option combination"); } paramPtr->flags |= NSF_ARG_FORWARD; } else if (firstChar == 's' && optionLength == 7 && strncmp(option, "slotset", 7) == 0) { if (unlikely(paramPtr->slotObj == NULL)) { return NsfPrintError(interp, "parameter option 'slotset' must follow 'slot='"); } paramPtr->flags |= NSF_ARG_SLOTSET; } else if (firstChar == 's' && optionLength == 14 && strncmp(option, "slotinitialize", 14) == 0) { if (unlikely(paramPtr->slotObj == NULL)) { return NsfPrintError(interp, "parameter option 'slotinit' must follow 'slot='"); } paramPtr->flags |= NSF_ARG_SLOTINITIALIZE; } else if ((dotdot = strnstr(option, "..", optionLength-1))) { /* * Check lower bound. */ if (*option == '0') { paramPtr->flags |= NSF_ARG_ALLOW_EMPTY; } else if (unlikely(*option != '1')) { return NsfPrintError(interp, "lower bound of multiplicity in %s not supported", argString); } /* * Check upper bound. */ option = dotdot + 2; if (*option == '*' || *option == 'n') { if (unlikely((paramPtr->flags & (NSF_ARG_SWITCH)) != 0u)) { return NsfPrintError(interp, "upper bound of multiplicity of '%c' not allowed for \"switch\"\n", *option); } paramPtr->flags |= NSF_ARG_MULTIVALUED; } else if (*option != '1') { return NsfPrintError(interp, "upper bound of multiplicity in %s not supported", argString); } } else if (firstChar == 'n' && optionLength == 5 && strncmp(option, "noarg", 5) == 0) { if ((paramPtr->flags & NSF_ARG_ALIAS) == 0u) { return NsfPrintError(interp, "parameter option \"noarg\" only allowed for parameter type \"alias\""); } paramPtr->flags |= NSF_ARG_NOARG; paramPtr->nrArgs = 0; } else if (firstChar == 'n' && optionLength == 11 && strncmp(option, "nodashalnum", 11) == 0) { if (*paramPtr->name == '-') { return NsfPrintError(interp, "parameter option 'nodashalnum' only allowed for positional parameters"); } paramPtr->flags |= NSF_ARG_NODASHALNUM; } else if (firstChar == 'n' && optionLength == 8 && strncmp(option, "noconfig", 8) == 0) { if (disallowedOptions != NSF_DISALLOWED_ARG_OBJECT_PARAMETER) { return NsfPrintError(interp, "parameter option 'noconfig' only allowed for object parameters"); } paramPtr->flags |= NSF_ARG_NOCONFIG; } else if (firstChar == 'a' && optionLength == 4 && strncmp(option, "args", 4) == 0) { if ((paramPtr->flags & NSF_ARG_ALIAS) == 0u) { return NsfPrintError(interp, "parameter option \"args\" only allowed for parameter type \"alias\""); } result = ParamOptionSetConverter(interp, paramPtr, "args", ConvertToNothing); } else if (firstChar == 'a' && optionLength >= 4 && strncmp(option, "arg=", 4) == 0) { if (paramPtr->converter != ConvertViaCmd) { return NsfPrintError(interp, "parameter option 'arg=' only allowed for user-defined converter"); } if (paramPtr->converterArg != NULL) { DECR_REF_COUNT(paramPtr->converterArg); } paramPtr->converterArg = Tcl_NewStringObj(option + 4, (TCL_SIZE_T)optionLength - 4); /* * In case, we know that we have to unescape double commas, do it here... */ if (unlikely(unescape)) { Unescape(paramPtr->converterArg); } INCR_REF_COUNT(paramPtr->converterArg); } else if (firstChar == 's' && optionLength == 6 && strncmp(option, "switch", 6) == 0) { if (*paramPtr->name != '-') { return NsfPrintError(interp, "invalid parameter type \"switch\" for argument \"%s\"; " "type \"switch\" only allowed for non-positional arguments", paramPtr->name); } else if ((paramPtr->flags & NSF_ARG_METHOD_INVOCATION) != 0u) { return NsfPrintError(interp, "parameter invocation types cannot be used with option 'switch'"); } result = ParamOptionSetConverter(interp, paramPtr, "switch", Nsf_ConvertToSwitch); paramPtr->flags |= NSF_ARG_SWITCH; paramPtr->nrArgs = 0; assert(paramPtr->defaultValue == NULL); paramPtr->defaultValue = Tcl_NewBooleanObj(0); INCR_REF_COUNT(paramPtr->defaultValue); } else if (firstChar == 'i' && optionLength <= 7 && strncmp(option, "integer", NsfMax(3, optionLength)) == 0) { result = ParamOptionSetConverter(interp, paramPtr, "integer", Nsf_ConvertToInteger); } else if (firstChar == 'i' && optionLength == 5 && strncmp(option, "int32", 5) == 0) { result = ParamOptionSetConverter(interp, paramPtr, "int32", Nsf_ConvertToInt32); } else if (firstChar == 'b' && optionLength == 7 && strncmp(option, "boolean", 7) == 0) { result = ParamOptionSetConverter(interp, paramPtr, "boolean", Nsf_ConvertToBoolean); } else if (firstChar == 'o' && optionLength == 6 && strncmp(option, "object", 6) == 0) { result = ParamOptionSetConverter(interp, paramPtr, "object", Nsf_ConvertToObject); } else if (firstChar == 'c' && optionLength == 5 && strncmp(option, "class", 5) == 0) { result = ParamOptionSetConverter(interp, paramPtr, "class", Nsf_ConvertToClass); } else if (firstChar == 'm' && optionLength == 9 && strncmp(option, "metaclass", 9) == 0) { result = ParamOptionSetConverter(interp, paramPtr, "class", Nsf_ConvertToClass); paramPtr->flags |= NSF_ARG_METACLASS; } else if (firstChar == 'b' && optionLength == 9 && strncmp(option, "baseclass", 9) == 0) { result = ParamOptionSetConverter(interp, paramPtr, "class", Nsf_ConvertToClass); paramPtr->flags |= NSF_ARG_BASECLASS; } else if (firstChar == 'm' && optionLength == 8 && strncmp(option, "mixinreg", 8) == 0) { result = ParamOptionSetConverter(interp, paramPtr, "mixinreg", Nsf_ConvertToMixinreg); } else if (firstChar == 'f' && optionLength == 9 && strncmp(option, "filterreg", 9) == 0) { result = ParamOptionSetConverter(interp, paramPtr, "filterreg", Nsf_ConvertToFilterreg); } else if (firstChar == 'p' && optionLength == 9 && strncmp(option, "parameter", 9) == 0) { result = ParamOptionSetConverter(interp, paramPtr, "parameter", Nsf_ConvertToParameter); } else if (firstChar == 't' && optionLength >= 6 && strncmp(option, "type=", 5) == 0) { const char* typeValue = option + 5; TCL_SIZE_T typeValueLength = (TCL_SIZE_T)optionLength - 5; if (paramPtr->converter != Nsf_ConvertToObject && paramPtr->converter != Nsf_ConvertToClass ) { return NsfPrintError(interp, "parameter option 'type=' only allowed for parameter types 'object' and 'class'"); } if (paramPtr->converterArg != NULL) { DECR_REF_COUNT(paramPtr->converterArg); } if (qualifier != NULL && !isAbsolutePath(typeValue) && isAbsolutePath(qualifier)) { Tcl_DString ds, *dsPtr = &ds; Tcl_DStringInit(dsPtr); Tcl_DStringAppend(dsPtr, qualifier, TCL_INDEX_NONE); if (Tcl_DStringLength(dsPtr) > 2) { Tcl_DStringAppend(dsPtr, "::", 2); } Tcl_DStringAppend(dsPtr, typeValue, typeValueLength); paramPtr->converterArg = Tcl_NewStringObj(Tcl_DStringValue(dsPtr), Tcl_DStringLength(dsPtr)); Tcl_DStringFree(dsPtr); } else { paramPtr->converterArg = Tcl_NewStringObj(typeValue, typeValueLength); } if (unlikely(unescape)) { Unescape(paramPtr->converterArg); } INCR_REF_COUNT(paramPtr->converterArg); } else if (firstChar == 's' && optionLength >= 6 && strncmp(option, "slot=", 5) == 0) { if (paramPtr->slotObj != NULL) { DECR_REF_COUNT(paramPtr->slotObj); } paramPtr->slotObj = Tcl_NewStringObj(option + 5, (TCL_SIZE_T)optionLength - 5); if (unlikely(unescape)) { Unescape(paramPtr->slotObj); } INCR_REF_COUNT(paramPtr->slotObj); } else if (firstChar == 'm' && optionLength >= 6 && strncmp(option, "method=", 7) == 0) { if ((paramPtr->flags & (NSF_ARG_ALIAS|NSF_ARG_FORWARD|NSF_ARG_SLOTSET)) == 0u) { return NsfPrintError(interp, "parameter option 'method=' only allowed for parameter " "types 'alias', 'forward' and 'slotset'"); } if (paramPtr->method != NULL) { DECR_REF_COUNT(paramPtr->method); } paramPtr->method = Tcl_NewStringObj(option + 7, (TCL_SIZE_T)optionLength - 7); if (unlikely(unescape)) { Unescape(paramPtr->method); } INCR_REF_COUNT(paramPtr->method); } else if ((firstChar == 'v') && ((strncmp(option, "virtualobjectargs", 17) == 0) || (strncmp(option, "virtualclassargs", 16) == 0))) { result = ParamOptionSetConverter(interp, paramPtr, option, ConvertToNothing); } else { Tcl_DString ds, *dsPtr = &ds; #ifdef NSF_WITH_TCL_OBJ_TYPES_AS_CONVERTER const Tcl_ObjType *tclObjType; #endif if (option[0] == '\0') { NsfLog(interp, NSF_LOG_WARN, "empty parameter option ignored"); return TCL_OK; } Tcl_DStringInit(dsPtr); Tcl_DStringAppend(dsPtr, option, (TCL_SIZE_T)optionLength); if (unlikely(paramPtr->converter != NULL)) { NsfPrintError(interp, "parameter option '%s' unknown for parameter type '%s'", Tcl_DStringValue(dsPtr), paramPtr->type); Tcl_DStringFree(dsPtr); return TCL_ERROR; } /*fprintf(stderr, "HAV TYPE converter for <%s> ?\n", option);*/ if (Nsf_PointerTypeLookup(Tcl_DStringValue(dsPtr))) { /* * Check whether the option refers to a pointer converter. */ ParamOptionSetConverter(interp, paramPtr, Tcl_DStringValue(dsPtr), Nsf_ConvertToPointer); Tcl_DStringFree(dsPtr); #ifdef NSF_WITH_TCL_OBJ_TYPES_AS_CONVERTER } else if ((tclObjType = Tcl_GetObjType(option)) != NULL) { /*fprintf(stderr, "SET TYPE converter for <%s>\n", option);*/ result = ParamOptionSetConverter(interp, paramPtr, Tcl_DStringValue(dsPtr), Nsf_ConvertToTclObjType); if (paramPtr->converterArg != NULL) { DECR_REF_COUNT(paramPtr->converterArg); } paramPtr->converterArg = Tcl_NewObj(); paramPtr->converterArg->internalRep.twoPtrValue.ptr1 = (void *)tclObjType; INCR_REF_COUNT(paramPtr->converterArg); #endif } else { int i, found = -1; /* * The option is still unknown, check the Tcl string-is checkers */ Tcl_DStringFree(dsPtr); for (i = 0; stringTypeOpts[i]; i++) { /* * Do not allow abbreviations, so the additional strlen() checks * for a full match. */ if (strncmp(option, stringTypeOpts[i], optionLength) == 0 && strlen(stringTypeOpts[i]) == optionLength) { found = i; break; } } if (found > -1) { /* * Converter is stringType. */ result = ParamOptionSetConverter(interp, paramPtr, "stringtype", Nsf_ConvertToTclobj); if (paramPtr->converterArg != NULL) { DECR_REF_COUNT(paramPtr->converterArg); } paramPtr->converterArg = Tcl_NewStringObj(stringTypeOpts[i], TCL_INDEX_NONE); INCR_REF_COUNT(paramPtr->converterArg); } else { /* * The parameter option is still unknown. We assume that the parameter * option identifies a user-defined argument checker, implemented as a * method. */ if (paramPtr->converterName != NULL) { DECR_REF_COUNT2("converterNameObj", paramPtr->converterName); } paramPtr->converterName = ParamCheckObj(option, optionLength); INCR_REF_COUNT2("converterNameObj", paramPtr->converterName); result = ParamOptionSetConverter(interp, paramPtr, ObjStr(paramPtr->converterName), ConvertViaCmd); } } } if ((paramPtr->flags & disallowedOptions) != 0u) { return NsfPrintError(interp, "parameter option '%s' not allowed", option); } if (unlikely(((paramPtr->flags & NSF_ARG_METHOD_INVOCATION) != 0u) && ((paramPtr->flags & NSF_ARG_NOCONFIG)) != 0u)) { return NsfPrintError(interp, "parameter option 'noconfig' cannot used together with this type of object parameter"); } return result; } /* *---------------------------------------------------------------------- * ParamDefinitionParse -- * * Parse a single parameter definition with a possible default provided in * the form of a Tcl_Obj. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ParamDefinitionParse(Tcl_Interp *interp, Tcl_Obj *procNameObj, Tcl_Obj *arg, unsigned int disallowedFlags, Nsf_Param *paramPtr, int *possibleUnknowns, int *plainParams, int *nrNonposArgs, const char *qualifier) nonnull(1) nonnull(3) nonnull(5) nonnull(6) nonnull(7) nonnull(8); static int ParamDefinitionParse(Tcl_Interp *interp, Tcl_Obj *procNameObj, Tcl_Obj *arg, unsigned int disallowedFlags, Nsf_Param *paramPtr, int *possibleUnknowns, int *plainParams, int *nrNonposArgs, const char *qualifier) { const char *argString, *argName; int result, npac, isNonposArgument, parensCount; size_t length, j; Tcl_Obj **npav; nonnull_assert(interp != NULL); nonnull_assert(arg != NULL); nonnull_assert(paramPtr != NULL); nonnull_assert(possibleUnknowns != NULL); nonnull_assert(plainParams != NULL); nonnull_assert(nrNonposArgs != NULL); paramPtr->paramObj = arg; INCR_REF_COUNT(paramPtr->paramObj); result = Tcl_ListObjGetElements(interp, paramPtr->paramObj, &npac, &npav); if (unlikely(result != TCL_OK || npac < 1 || npac > 2)) { if (procNameObj != NULL) { result = NsfPrintError(interp, "wrong # of elements in parameter definition " "of method '%s'. " "Should be a list of 1 or 2 elements, but got: '$s'", ObjStr(procNameObj), ObjStr(paramPtr->paramObj)); } else { result = NsfPrintError(interp, "wrong # of elements in parameter definition. " "Should be a list of 1 or 2 elements, but got: '%s'", ObjStr(paramPtr->paramObj)); } DECR_REF_COUNT(paramPtr->paramObj); return result; } argString = ObjStr(npav[0]); length = strlen(argString); /* For whatever reason, the snippet above seems to be faster than: argString = Tcl_GetStringFromObj(npav[0], &result); length = (size_t) result; */ /* * Per default parameter have exactly one argument; types without arguments * (like "switch") have to set their nrArgs explicitly. */ paramPtr->nrArgs = 1; isNonposArgument = *argString == '-'; if (isNonposArgument != 0) { argName = argString+1; (*nrNonposArgs) ++; } else { argName = argString; paramPtr->flags |= NSF_ARG_REQUIRED; /* positional arguments are required unless we have a default */ } /*fprintf(stderr, "... parsing '%s', name '%s' argString '%s' \n", ObjStr(arg), argName, argString);*/ /* * Find the first ':' outside of parens; the name of the parameter might be * in array syntax, the array index might contain ":", "," etc. */ parensCount = 0; for (j = 0; j < length; j++) { if (parensCount > 0 && argString[j] == ')') { parensCount --; continue; } if (argString[j] == '(') { parensCount ++; continue; } if (parensCount == 0 && argString[j] == ':') { break; } } if (argString[j] == ':') { /* * We found a ':' */ size_t l, start, end; bool unescape = NSF_FALSE; /* * Get parameter name */ STRING_NEW(paramPtr->name, argString, j); paramPtr->nameObj = Tcl_NewStringObj(argName, (isNonposArgument != 0) ? (TCL_SIZE_T)j-1 : (TCL_SIZE_T)j); INCR_REF_COUNT(paramPtr->nameObj); /* * Skip space at begin */ for (start = j+1; start 0 && isspace((int)argString[end-1]); end--); result = ParamOptionParse(interp, argString, start, end-start, disallowedFlags, paramPtr, unescape, qualifier); unescape = NSF_FALSE; if (unlikely(result != TCL_OK)) { goto param_error; } l++; /* * Skip space from begin. */ for (start = l; start 0 && isspace((int)argString[end-1]); end--); /* * process last option */ if (end-start > 0) { result = ParamOptionParse(interp, argString, start, end-start, disallowedFlags, paramPtr, unescape, qualifier); if (unlikely(result != TCL_OK)) { goto param_error; } } } else { /* * No ':', the whole arg is the name, we have no options */ STRING_NEW(paramPtr->name, argString, length); if (isNonposArgument != 0) { paramPtr->nameObj = Tcl_NewStringObj(argName, (TCL_SIZE_T)length-1); } else { (*plainParams) ++; paramPtr->nameObj = Tcl_NewStringObj(argName, (TCL_SIZE_T)length); } INCR_REF_COUNT(paramPtr->nameObj); } /* * If we have two arguments in the list, the second one is a default value */ if (npac == 2) { if ((disallowedFlags & NSF_ARG_HAS_DEFAULT) != 0u) { NsfPrintError(interp, "parameter specification for \"%s\" is not allowed to have default \"%s\"", argString, ObjStr(npav[1])); goto param_error; } /* * If we have for some reason already a default value, free it */ if (paramPtr->defaultValue != NULL) { DECR_REF_COUNT(paramPtr->defaultValue); } paramPtr->defaultValue = Tcl_DuplicateObj(npav[1]); INCR_REF_COUNT(paramPtr->defaultValue); /* * The argument will be not required for an invocation, since we * have a default. */ paramPtr->flags &= ~NSF_ARG_REQUIRED; } else if ((paramPtr->flags & NSF_ARG_SUBST_DEFAULT) != 0u) { NsfPrintError(interp, "parameter option substdefault specified for parameter \"%s\"" " without default value", paramPtr->name); goto param_error; } /* * Postprocessing the parameter options */ if (paramPtr->converter == NULL) { /* * If no converter is set, use the default converter */ paramPtr->converter = Nsf_ConvertToTclobj; } else if ( paramPtr->converter == ConvertToNothing && (paramPtr->flags & (NSF_ARG_ALLOW_EMPTY|NSF_ARG_MULTIVALUED)) != 0u ) { NsfPrintError(interp, "multiplicity settings for variable argument parameter \"%s\" not allowed", paramPtr->name); goto param_error; } /* * Check for application specific value checkers and converters */ /*fprintf(stderr, "parm %s: slotObj %p viaCmd? %d\n", paramPtr->name, paramPtr->slotObj, paramPtr->converter == ConvertViaCmd);*/ if ((paramPtr->slotObj || paramPtr->converter == ConvertViaCmd) && paramPtr->type) { const char *converterNameString; Tcl_Obj *converterNameObj, *slotObj; NsfObject *paramObject; Tcl_Command cmd; NsfClass *paramClass = NULL; slotObj = (paramPtr->slotObj != NULL) ? paramPtr->slotObj : NsfGlobalObjs[NSF_METHOD_PARAMETER_SLOT_OBJ]; result = GetObjectFromObj(interp, slotObj, ¶mObject); if (unlikely(result != TCL_OK)) { NsfPrintError(interp, "non-existing slot object \"%s\"", ObjStr(slotObj)); goto param_error; } if (paramPtr->converterName == NULL) { converterNameObj = ParamCheckObj(paramPtr->type, strlen(paramPtr->type)); INCR_REF_COUNT2("converterNameObj", converterNameObj); } else { converterNameObj = paramPtr->converterName; } converterNameString = ObjStr(converterNameObj); cmd = ObjectFindMethod(interp, paramObject, converterNameObj, ¶mClass); /*fprintf(stderr, "locating %s on %s returns %p (%s)\n", ObjStr(converterNameObj), ObjectName(paramObject), cmd, ClassName(paramClass));*/ if (cmd == NULL) { if (paramPtr->converter == ConvertViaCmd) { NsfLog(interp, NSF_LOG_WARN, "Could not find value checker %s defined on %s", converterNameString, ObjectName(paramObject)); paramPtr->flags |= NSF_ARG_CURRENTLY_UNKNOWN; /* TODO: for the time being, we do not return an error here */ } } else if (paramPtr->converter != ConvertViaCmd && paramPtr->slotObj && strcmp(ObjStr(paramPtr->slotObj), NsfGlobalStrings[NSF_METHOD_PARAMETER_SLOT_OBJ]) != 0) { NsfLog(interp, NSF_LOG_WARN, "Checker method %s defined on %s shadows built-in converter", converterNameString, ObjectName(paramObject)); if (paramPtr->converterName == NULL) { paramPtr->converterName = converterNameObj; paramPtr->converter = NULL; result = ParamOptionSetConverter(interp, paramPtr, converterNameString, ConvertViaCmd); if (unlikely(result != TCL_OK)) { if (converterNameObj != paramPtr->converterName) { DECR_REF_COUNT2("converterNameObj", converterNameObj); } goto param_error; } } } if (((paramPtr->flags & NSF_ARG_IS_CONVERTER) != 0u) && paramPtr->converter != ConvertViaCmd) { NsfPrintError(interp, "option 'convert' only allowed for application-defined converters"); if (converterNameObj != paramPtr->converterName) { DECR_REF_COUNT2("converterNameObj", converterNameObj); } goto param_error; } if (converterNameObj != paramPtr->converterName) { DECR_REF_COUNT2("converterNameObj", converterNameObj); } } /* * If the argument has no arguments and it is positional, it can't be * required. */ if (paramPtr->nrArgs == 0 && *paramPtr->name != '-' && (paramPtr->flags & NSF_ARG_REQUIRED) != 0u ) { paramPtr->flags &= ~NSF_ARG_REQUIRED; } /* * If the argument is not required and no default value is specified, we * have to handle in the client code (e.g. in the canonical arg handlers for * scripted methods) the unknown value (e.g. don't set/unset a variable) */ if ((paramPtr->flags & NSF_ARG_REQUIRED) == 0u && paramPtr->defaultValue == NULL) { (*possibleUnknowns)++; } return TCL_OK; param_error: ParamFree(paramPtr); paramPtr->name = NULL; #if !defined(NDEBUG) /* * Whenever we return a TCL_ERROR, we expect that the interp result contains * an error message. */ { const char *errStr = ObjStr(Tcl_GetObjResult(interp)); assert(*errStr != '\0'); } #endif return TCL_ERROR; } /* *---------------------------------------------------------------------- * ParamDefsParse -- * * Parse a list of parameters in the form of Tcl_Objs into a * parsedParamPtr structure (last argument). The argument * allowedOptions is used to flag, what parameter options are * generally allowed (typically different for method and object * parameters). Unless forceParamdefs is set, the parsed parameter * structure is only returned when needed (i.e. when not all * parameters are plain parameters). * * Results: * A standard Tcl result, parsedParameter structure in last * argument (allocated by the caller). * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ParamDefsParse(Tcl_Interp *interp, Tcl_Obj *procNameObj, Tcl_Obj *paramSpecObjs, unsigned int allowedOptions, bool forceParamdefs, NsfParsedParam *parsedParamPtr, const char *qualifier) nonnull(1) nonnull(3) nonnull(6); static int ParamDefsParse(Tcl_Interp *interp, Tcl_Obj *procNameObj, Tcl_Obj *paramSpecObjs, unsigned int allowedOptions, bool forceParamdefs, NsfParsedParam *parsedParamPtr, const char *qualifier) { Tcl_Obj **argsv; int result, argsc; nonnull_assert(interp != NULL); nonnull_assert(paramSpecObjs != NULL); nonnull_assert(parsedParamPtr != NULL); parsedParamPtr->paramDefs = NULL; parsedParamPtr->possibleUnknowns = 0; result = Tcl_ListObjGetElements(interp, paramSpecObjs, &argsc, &argsv); if (unlikely(result != TCL_OK)) { return NsfPrintError(interp, "cannot break down non-positional args: %s", ObjStr(paramSpecObjs)); } if (argsc > 0) { Nsf_Param *paramsPtr, *paramPtr, *lastParamPtr; int i, possibleUnknowns = 0, plainParams = 0, nrNonposArgs = 0; NsfParamDefs *paramDefs; paramPtr = paramsPtr = ParamsNew((size_t)argsc); for (i = 0; i < argsc; i++, paramPtr++) { result = ParamDefinitionParse(interp, procNameObj, argsv[i], allowedOptions, paramPtr, &possibleUnknowns, &plainParams, &nrNonposArgs, qualifier); if (result == TCL_OK) { if (paramPtr->converter == ConvertToNothing && i < argsc-1) { result = NsfPrintError(interp, "parameter option \"args\" invalid for parameter \"%s\"; only allowed for last parameter", paramPtr->name); } /* fprintf(stderr, "qual %s\n", qualifier); if (qualifier != NULL && (paramPtr->converter == Nsf_ConvertToObject || paramPtr->converter == Nsf_ConvertToClass) && paramPtr->converterArg != NULL) { fprintf(stderr, "qual %s\n", qualifier); const char *carg = ObjStr(paramPtr->converterArg); if (*carg != ':') { Tcl_Obj *qualifiedConverterArg = Tcl_NewStringObj(qualifier, TCL_INDEX_NONE); Tcl_AppendToObj(qualifiedConverterArg, "::", 2); Tcl_AppendObjToObj(qualifiedConverterArg, paramPtr->converterArg); DECR_REF_COUNT(paramPtr->converterArg); paramPtr->converterArg = qualifiedConverterArg; INCR_REF_COUNT(qualifiedConverterArg); fprintf(stderr, ">>> converterArg %s qualifier %s\n", ObjStr(paramPtr->converterArg), qualifier); } }*/ } if (unlikely(result != TCL_OK)) { ParamsFree(paramsPtr); return result; } /* * Every parameter must have at least a name set. */ assert(paramPtr->name); } #if defined(NSF_WITH_VALUE_WARNINGS) if (nrNonposArgs > 0 && argsc > 1) { for (i = 0; i < argsc; i++) { (paramsPtr + i)->flags |= NSF_ARG_CHECK_NONPOS; } } #endif /* * If all arguments are good old Tcl arguments, there is no need * to use the parameter definition structure, unless we force it. */ if (plainParams == argsc && !forceParamdefs) { ParamsFree(paramsPtr); return TCL_OK; } /*fprintf(stderr, "we need param definition structure for {%s}, argsc %d plain %d\n", ObjStr(paramSpecObjs), argsc, plainParams);*/ /* * Check the last argument. If the last argument is named 'args', * force converter and make it non-required. */ lastParamPtr = paramPtr - 1; if (isArgsString(lastParamPtr->name)) { lastParamPtr->converter = ConvertToNothing; lastParamPtr->flags &= ~NSF_ARG_REQUIRED; } paramDefs = ParamDefsNew(); paramDefs->paramsPtr = paramsPtr; paramDefs->nrParams = (int)(paramPtr - paramsPtr); /*fprintf(stderr, "method %s serial %d paramDefs %p ifsize %ld, possible unknowns = %d,\n", ObjStr(procNameObj), paramDefs->serial, paramDefs, paramPtr-paramsPtr, possibleUnknowns);*/ parsedParamPtr->paramDefs = paramDefs; parsedParamPtr->possibleUnknowns = possibleUnknowns; } return TCL_OK; } /* *---------------------------------------------------------------------- * ParameterMethodForwardDispatch -- * * Dispatch a forwarding method provided via parameter definition. * * The current implementation performs for every object * parameter forward the full cycle of * * (a) splitting the spec, * (b) convert it to the client data structure, * (c) invoke forward, * (d) free client data structure * * In the future, it should convert to the client data * structure just once and free it with the disposal of the * parameter. This could be achieved * * Results: * A standard Tcl result. * * Side effects: * The called function might side-effect. * *---------------------------------------------------------------------- */ static int ParameterMethodForwardDispatch(Tcl_Interp *interp, NsfObject *object, const Nsf_Param *paramPtr, Tcl_Obj *newValue, NsfCallStackContent *cscPtr) nonnull(1) nonnull(2) nonnull(3); static int ParameterMethodForwardDispatch(Tcl_Interp *interp, NsfObject *object, const Nsf_Param *paramPtr, Tcl_Obj *newValue, NsfCallStackContent *cscPtr) { Tcl_Obj **nobjv, *ov[3], *methodObj, *forwardSpec; ForwardCmdClientData *tcd = NULL; int result, oc, nobjc; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(paramPtr != NULL); assert((paramPtr->flags & NSF_ARG_FORWARD) != 0u); forwardSpec = (paramPtr->method != NULL) ? paramPtr->method : NULL; /* different default? */ if (forwardSpec == NULL) { return NsfPrintError(interp, "forward: no spec available\n"); } result = Tcl_ListObjGetElements(interp, forwardSpec, &nobjc, &nobjv); if (unlikely(result != TCL_OK)) { return result; } methodObj = paramPtr->nameObj; result = ForwardProcessOptions(interp, methodObj, NULL /*withDefault*/, 0 /*withEarlybinding*/, NULL /*withOnerror*/, NULL /*withMethodprefix*/, 0 /*withFrame*/, NSF_FALSE /*withVerbose*/, nobjv[0], nobjc-1, nobjv+1, &tcd); if (unlikely(result != TCL_OK)) { if (tcd != NULL) { ForwardCmdDeleteProc(tcd); } return result; } /*fprintf(stderr, "parameter %s forward spec <%s> After Options obj %s method %s\n", ObjStr(paramPtr->nameObj), ObjStr(forwardSpec), ObjectName(object), ObjStr(methodObj));*/ tcd->object = object; oc = 1; ov[0] = methodObj; if (paramPtr->nrArgs == 1 && newValue) { ov[oc] = newValue; oc ++; } /* * Mark the intermittent CSC frame as INACTIVE, so that, e.g., * call-stack traversals seeking active frames ignore it. */ if (cscPtr != NULL) { cscPtr->frameType = NSF_CSC_TYPE_INACTIVE; } result = NsfForwardMethod(tcd, interp, oc, ov); ForwardCmdDeleteProc(tcd); return result; } /* *---------------------------------------------------------------------- * ParameterMethodDispatch -- * * Dispatch a method provided via parameter definition. The function checks * the parameter definition, builds an argument list for the function call * and invokes finally the configured cmd. This function is typically * called from configure. * * Results: * A standard Tcl result. * * Side effects: * The called function might side-effect. * *---------------------------------------------------------------------- */ static int ParameterMethodDispatch( Tcl_Interp *interp, NsfObject *object, Nsf_Param *paramPtr, Tcl_Obj *newValue, CallFrame *uplevelVarFramePtr, const char *initString, Tcl_Obj **nextObjPtr, int nrRemainingArgs ) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(6) nonnull(7); static int ParameterMethodDispatch( Tcl_Interp *interp, NsfObject *object, Nsf_Param *paramPtr, Tcl_Obj *newValue, CallFrame *uplevelVarFramePtr, const char *initString, Tcl_Obj **nextObjPtr, int nrRemainingArgs ) { CallFrame *varFramePtr; NsfCallStackContent csc, *cscPtr = &csc; CallFrame frame2, *framePtr2 = &frame2; int result = TCL_OK; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(paramPtr != NULL); nonnull_assert(newValue != NULL); nonnull_assert(initString != NULL); nonnull_assert(nextObjPtr != NULL); #if 0 {int i; fprintf(stderr, "ParameterMethodDispatch %s flags %06x nrRemainingArgs %d ", paramPtr->name, paramPtr->flags, nrRemainingArgs); for(i = 0; i < nrRemainingArgs; i++) { fprintf(stderr, " [%d]=%p %s,", i, &nextObjPtr[i], ObjStr(nextObjPtr[i])); } fprintf(stderr, "\n"); } #endif /* * The current call-frame of configure uses an obj-frame, such * that setvar etc. are able to access variables like "a" as a * local variable. However, in the init block, we do not like * that behavior, since this should look like a proc body. * So we push yet another call-frame without providing the * var-frame. * * The new frame will have the namespace of the caller to avoid * the current obj-frame. Nsf_PushFrameCsc() will establish a * CMETHOD frame. */ varFramePtr = Tcl_Interp_varFramePtr(interp); Tcl_Interp_varFramePtr(interp) = varFramePtr->callerVarPtr; cscPtr->flags = 0; CscInit(cscPtr, object, object->cl /*cl*/, NULL /*cmd*/, NSF_CSC_TYPE_PLAIN, 0, NsfGlobalStrings[NSF_CONFIGURE]); Nsf_PushFrameCsc(interp, cscPtr, framePtr2); if ((paramPtr->flags & (NSF_ARG_INITCMD|NSF_ARG_CMD)) != 0u) { /* cscPtr->cmdPtr = NSFindCommand(interp, "::eval"); */ result = Tcl_EvalObjEx(interp, newValue, TCL_EVAL_DIRECT); } else if ((paramPtr->flags & NSF_ARG_ALIAS) != 0u) { Tcl_Obj *methodObj, **ovPtr, *ov0; static Tcl_Obj *constantObj = NULL; const char *methodString; int oc = 0; /* * Restore the variable frame context as found at the original call * site of configure(). Note that we do not have to revert this * context change when leaving this configure() context because a * surrounding [uplevel] will correct the call-stack context for us ... */ if (uplevelVarFramePtr != NULL) { Tcl_Interp_varFramePtr(interp) = uplevelVarFramePtr; } /* * Mark the intermittent CSC frame as INACTIVE, so that, e.g., * call-stack traversals seeking active frames ignore it. */ cscPtr->frameType = NSF_CSC_TYPE_INACTIVE; /* * If parameter option "method=" was given, use it as method name */ methodObj = (paramPtr->method != NULL) ? paramPtr->method : paramPtr->nameObj; methodString = ObjStr(methodObj); /*fprintf(stderr, "ALIAS %s, nrargs %d converter %p ConvertToNothing %d oc %d\n", paramPtr->name, paramPtr->nrArgs, paramPtr->converter, paramPtr->converter == ConvertToNothing, oc);*/ if (paramPtr->converter == ConvertToNothing) { /* * We are using the varargs interface; pass all remaining args into * the called method. */ if (newValue == paramPtr->defaultValue) { /* * Use the default. */ if (Tcl_ListObjGetElements(interp, paramPtr->defaultValue, &oc, &ovPtr) != TCL_OK) { goto method_arg_done; } ov0 = *ovPtr; ovPtr ++; } else { /* * Use actual args. */ ov0 = *nextObjPtr; /*fprintf(stderr, "ALIAS use actual args oc %d ov0 <%s> nextObjPtr %p %p\n", nrRemainingArgs, ObjStr(ov0), nextObjPtr, nextObjPtr+1);*/ ovPtr = nextObjPtr+1; oc = nrRemainingArgs; } } else { /* * A simple alias, receives no arg (when noarg was specified) or a * single argument (which might be the default value). */ int moc = 1; Tcl_Obj **movPtr = NULL; ov0 = NULL; ovPtr = &constantObj; if (Tcl_ListObjGetElements(interp, methodObj, &moc, &movPtr) == TCL_OK) { if (moc != 2) { oc = 0; if (unlikely(moc > 2)) { NsfLog(interp, NSF_LOG_WARN, "max 2 words are currently allowed in methodName <%s>", methodString); } } else { oc = 1; methodObj = movPtr[0]; ov0 = movPtr[1]; } } if (paramPtr->nrArgs == 1) { oc++; if (oc == 1) { ov0 = newValue; } else { ovPtr = &newValue; } } } /* * Check whether we have an object parameter alias for the constructor. * Since we require the object system for the current object to determine * its object system configuration, we can't do this at parameter compile * time. */ if (*initString == *methodString && strcmp(initString, methodString) == 0) { result = DispatchInitMethod(interp, object, oc, &ov0, 0u); } else { /*fprintf(stderr, "... call alias %s with methodObj %s.%s oc %d, nrArgs %d '%s'\n", paramPtr->name, ObjectName(object), ObjStr(methodObj), oc, paramPtr->nrArgs, ObjStr(newValue));*/ #if !defined(NDEBUG) if (oc > 2) { assert(ovPtr != NULL); assert(ovPtr != &constantObj); assert(ISOBJ(ovPtr[oc-2])); } #endif Tcl_ResetResult(interp); result = NsfCallMethodWithArgs(interp, (Nsf_Object*)object, methodObj, ov0, oc, ovPtr, NSF_CSC_IMMEDIATE|NSF_CM_IGNORE_PERMISSIONS); } } else { /* * must be NSF_ARG_FORWARD */ assert((paramPtr->flags & NSF_ARG_FORWARD) != 0u); result = ParameterMethodForwardDispatch(interp, object, paramPtr, newValue, cscPtr); } method_arg_done: /* * Pop previously stacked frame for eval context and set the * varFramePtr to the previous value. */ Nsf_PopFrameCsc(interp, framePtr2); CscListRemove(interp, cscPtr, NULL); CscFinish(interp, cscPtr, result, "converter object frame"); Tcl_Interp_varFramePtr(interp) = varFramePtr; /* fprintf(stderr, "NsfOConfigureMethod_ attribute %s evaluated %s => (%d)\n", ObjStr(paramPtr->nameObj), ObjStr(newValue), result);*/ if (likely(result == TCL_OK)) { if ((paramPtr->flags & NSF_ARG_CMD) != 0u && RUNTIME_STATE(interp)->doKeepcmds ) { Tcl_Obj *resultObj; resultObj = Tcl_ObjSetVar2(interp, NsfGlobalObjs[NSF_ARRAY_CMD], paramPtr->nameObj, newValue, TCL_LEAVE_ERR_MSG); if (unlikely(resultObj == NULL)) { result = TCL_ERROR; } } } return result; } /* *---------------------------------------------------------------------- * MakeProc -- * * Define a scripted function via the ObjCmd "proc". * * Results: * A standard Tcl result. * * Side effects: * Defined function or exception. * *---------------------------------------------------------------------- */ static int MakeProc(Tcl_Namespace *nsPtr, NsfAssertionStore *aStore, Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_Obj *args, Tcl_Obj *body, Tcl_Obj *precondition, Tcl_Obj *postcondition, NsfObject *defObject, NsfObject *regObject, int withPer_object, int withInner_namespace, unsigned int checkAlwaysFlag ) nonnull(1) nonnull(3) nonnull(4) nonnull(5) nonnull(6) nonnull(9); static int MakeProc( Tcl_Namespace *nsPtr, NsfAssertionStore *aStore, Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_Obj *args, Tcl_Obj *body, Tcl_Obj *precondition, Tcl_Obj *postcondition, NsfObject *defObject, NsfObject *regObject, int withPer_object, int withInner_namespace, unsigned int checkAlwaysFlag ) { const char *methodName; NsfParsedParam parsedParam; Tcl_Obj *ov[4], *fullyQualifiedNameObj; int result; nonnull_assert(nsPtr != NULL); nonnull_assert(interp != NULL); nonnull_assert(nameObj != NULL); nonnull_assert(args != NULL); nonnull_assert(body != NULL); nonnull_assert(defObject != NULL); methodName = ObjStr(nameObj); /* * Tcl (at least in newer versions) will raise an error in cases, where * the methodName starts with a colon. */ if (regObject == NULL) { regObject = defObject; } /* * Check whether we are allowed to redefine the method. */ result = CanRedefineCmd(interp, nsPtr, defObject, methodName, 0u); if (likely(result == TCL_OK)) { /* * Yes, we can! ...so obtain the method parameter definition. */ Tcl_Namespace *nsPtr1 = Tcl_Command_nsPtr(defObject->id); result = ParamDefsParse(interp, nameObj, args, NSF_DISALLOWED_ARG_METHOD_PARAMETER, NSF_FALSE, &parsedParam, nsPtr1 != NULL ? nsPtr1->fullName : NULL); } else { /* * Strictly speaking, the following assignment is not necessary. However, * it avoids a false positive from facbook infer. */ parsedParam.paramDefs = NULL; } if (unlikely(result != TCL_OK)) { return result; } if (isAbsolutePath(methodName)) { fullyQualifiedNameObj = nameObj; } else { fullyQualifiedNameObj = NameInNamespaceObj(methodName, nsPtr); INCR_REF_COUNT2("fullyQualifiedName", fullyQualifiedNameObj); } ov[0] = NULL; ov[1] = fullyQualifiedNameObj; if (parsedParam.paramDefs != NULL) { Nsf_Param *pPtr; Tcl_Obj *argList = Tcl_NewListObj(0, NULL); for (pPtr = parsedParam.paramDefs->paramsPtr; pPtr->name != NULL; pPtr++) { if (*pPtr->name == '-') { Tcl_ListObjAppendElement(interp, argList, Tcl_NewStringObj(pPtr->name+1, TCL_INDEX_NONE)); } else { Tcl_ListObjAppendElement(interp, argList, Tcl_NewStringObj(pPtr->name, TCL_INDEX_NONE)); } } ov[2] = argList; INCR_REF_COUNT(ov[2]); /*fprintf(stderr, "final arglist = <%s>\n", ObjStr(argList)); */ ov[3] = AddPrefixToBody(body, NSF_TRUE, &parsedParam); } else { /* no parameter handling needed */ ov[2] = args; ov[3] = AddPrefixToBody(body, NSF_FALSE, &parsedParam); } /* * Check whether the cmd exists already in the namespace. If so, delete it * from there. */ { Tcl_Command cmdPtr = FindMethod(nsPtr, methodName); if (cmdPtr != NULL) { Tcl_DeleteCommandFromToken(interp, cmdPtr); } } /* * Create the method in the provided namespace. */ result = Tcl_ProcObjCmd(NULL, interp, 4, ov); if (likely(result == TCL_OK)) { /* * Retrieve the newly defined proc */ Proc *procPtr = FindProcMethod(nsPtr, methodName); if (procPtr != NULL) { Namespace *execNsPtr; if (withInner_namespace == 1) { /* * Set the execution namespace to the registration object (e.g. same * as the class). */ if (regObject->nsPtr == NULL) { MakeObjNamespace(interp, regObject); } /*fprintf(stderr, "obj %s\n", ObjectName(defObject)); fprintf(stderr, "ns %p defObject->ns %p\n", nsPtr, defObject->nsPtr); fprintf(stderr, "ns %s defObject->ns %s\n", nsPtr->fullName, defObject->nsPtr->fullName); fprintf(stderr, "old %s\n", procPtr->cmdPtr->nsPtr->fullName);*/ execNsPtr = (Namespace *)regObject->nsPtr; } else { /* * Set the execution namespace of the method to the same namespace the * cmd of the defObject has. */ execNsPtr = ((Command *)regObject->id)->nsPtr; } ParamDefsStore((Tcl_Command)procPtr->cmdPtr, parsedParam.paramDefs, checkAlwaysFlag, (Tcl_Namespace *)execNsPtr); Tcl_SetObjResult(interp, MethodHandleObj(defObject, withPer_object, methodName)); result = TCL_OK; } else { result = TCL_ERROR; NsfLog(interp, NSF_LOG_WARN, "cannot retrieve newly defined method %s from namespace %s", methodName, nsPtr->fullName); if (*methodName == ':') { NsfPrintError(interp, "can't create procedure \"%s\" in non-global namespace" " with name starting with \":\"", methodName); } else { NsfPrintError(interp, "can't create procedure \"%s\" in non-global namespace", methodName); } } } #if defined(NSF_WITH_ASSERTIONS) if (result == TCL_OK && aStore != NULL /* (precondition || postcondition)*/) { AssertionAddProc(interp, methodName, aStore, precondition, postcondition); } #endif if (parsedParam.paramDefs != NULL) { DECR_REF_COUNT(ov[2]); } DECR_REF_COUNT2("resultBody", ov[3]); if (fullyQualifiedNameObj != nameObj) { DECR_REF_COUNT2("fullyQualifiedName", fullyQualifiedNameObj); } return result; } /* *---------------------------------------------------------------------- * MakeMethod -- * * Define a scripted method to be defined on defObject and registered on * regObject (if specified). This function handles as well assertions. * * Results: * A standard Tcl result. * * Side effects: * Defined method or exception. * *---------------------------------------------------------------------- */ static int MakeMethod(Tcl_Interp *interp, NsfObject *defObject, NsfObject *regObject, NsfClass *class, Tcl_Obj *nameObj, Tcl_Obj *args, Tcl_Obj *body, Tcl_Obj *precondition, Tcl_Obj *postcondition, int withInner_namespace, unsigned int checkAlwaysFlag) nonnull(1) nonnull(2) nonnull(5) nonnull(6) nonnull(7); static int MakeMethod(Tcl_Interp *interp, NsfObject *defObject, NsfObject *regObject, NsfClass *class, Tcl_Obj *nameObj, Tcl_Obj *args, Tcl_Obj *body, Tcl_Obj *precondition, Tcl_Obj *postcondition, int withInner_namespace, unsigned int checkAlwaysFlag) { const char *argsStr, *bodyStr, *nameStr; int result; nonnull_assert(interp != NULL); nonnull_assert(defObject != NULL); nonnull_assert(nameObj != NULL); nonnull_assert(args != NULL); nonnull_assert(body != NULL); nameStr = ObjStr(nameObj); if (*nameStr == '\0' || NsfHasTclSpace(nameStr)) { return NsfPrintError(interp, "invalid method name '%s'", nameStr); } if (precondition != NULL && postcondition == NULL) { return NsfPrintError(interp, "%s method '%s'; when specifying a precondition (%s)" " a postcondition must be specified as well", ClassName(class), nameStr, ObjStr(precondition)); } argsStr = ObjStr(args); bodyStr = ObjStr(body); if (*argsStr == 0 && *bodyStr == 0) { /* * Both, args and body are empty strings. This means we should delete the * method. */ if (RUNTIME_STATE(interp)->exitHandlerDestroyRound == NSF_EXITHANDLER_OFF) { /* * Don't delete methods via scripting during shutdown */ result = (class != NULL) ? NsfRemoveClassMethod(interp, (Nsf_Class *)class, nameStr) : NsfRemoveObjectMethod(interp, (Nsf_Object *)defObject, nameStr); } else { /* fprintf(stderr, "don't delete method %s during shutdown\n", nameStr); */ result = TCL_OK; } } else { #if defined(NSF_WITH_ASSERTIONS) NsfAssertionStore *aStore = NULL; if (precondition != NULL || postcondition != NULL) { if (class != NULL) { NsfClassOpt *opt = NsfRequireClassOpt(class); if (opt->assertions == NULL) { opt->assertions = AssertionCreateStore(); } aStore = opt->assertions; } else { NsfObjectOpt *opt = NsfRequireObjectOpt(defObject); if (opt->assertions == NULL) { opt->assertions = AssertionCreateStore(); } aStore = opt->assertions; } } result = MakeProc((class != NULL) ? class->nsPtr : defObject->nsPtr, aStore, interp, nameObj, args, body, precondition, postcondition, defObject, regObject, class == NULL, withInner_namespace, checkAlwaysFlag); #else if (precondition != NULL) { NsfLog(interp, NSF_LOG_WARN, "Precondition %s provided, but not compiled with assertion enabled", ObjStr(precondition)); } else if (postcondition != NULL) { NsfLog(interp, NSF_LOG_WARN, "Postcondition %s provided, but not compiled with assertion enabled", ObjStr(postcondition)); } result = MakeProc((class != NULL) ? class->nsPtr : defObject->nsPtr, NULL, interp, nameObj, args, body, NULL, NULL, defObject, regObject, class == NULL, withInner_namespace, checkAlwaysFlag); #endif } if (class != NULL) { NsfInstanceMethodEpochIncr("MakeMethod"); /* * Could be a filter or filter inheritance ... update filter orders. */ if (FilterIsActive(interp, nameStr)) { NsfClasses *subClasses = TransitiveSubClasses(class); if (subClasses != NULL) { FilterInvalidateObjOrders(interp, subClasses); NsfClassListFree(subClasses); } } } else { NsfObjectMethodEpochIncr("MakeMethod"); /* * Could be a filter => recompute filter order. */ FilterComputeDefined(interp, defObject); } return result; } /************************************************************************** * Begin Definition of nsf::proc (Tcl Procs with Parameter handling) **************************************************************************/ /* *---------------------------------------------------------------------- * NsfProcStubDeleteProc -- * * Tcl_CmdDeleteProc for NsfProcStubs. Is called, whenever a * NsfProcStub is deleted and frees the associated client data. * * Results: * None. * * Side effects: * Frees client-data * *---------------------------------------------------------------------- */ static void NsfProcStubDeleteProc(ClientData clientData) { NsfProcClientData *tcd = clientData; /* fprintf(stderr, "NsfProcStubDeleteProc received %p\n", clientData); fprintf(stderr, "... procName %s paramDefs %p\n", ObjStr(tcd->procName), tcd->paramDefs);*/ DECR_REF_COUNT2("procNameObj", tcd->procName); if (tcd->cmd != NULL) { Tcl_DeleteCommandFromToken(tcd->interp, tcd->cmd); NsfCommandRelease(tcd->cmd); } /* tcd->paramDefs is freed by NsfProcDeleteProc() */ FREE(NsfProcClientData, tcd); } /* *---------------------------------------------------------------------- * InvokeShadowedProc -- * * Call the proc specified in objc/objv; procNameObj should be used * for error messages. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int InvokeShadowedProc(Tcl_Interp *interp, Tcl_Obj *procNameObj, Tcl_Command cmd, ParseContext *pcPtr, struct Tcl_Time *trtPtr, unsigned int cmdFlags, Tcl_Namespace *execNsPtr) nonnull(1) nonnull(2) nonnull(4) nonnull(3) nonnull(4) nonnull(5); static int InvokeShadowedProc(Tcl_Interp *interp, Tcl_Obj *procNameObj, Tcl_Command cmd, ParseContext *pcPtr, struct Tcl_Time *trtPtr, unsigned int cmdFlags, Tcl_Namespace *execNsPtr) { Tcl_Obj *const *objv; int objc, result, includeTiming; const char *fullMethodName; Tcl_CallFrame *framePtr; Proc *procPtr; Tcl_Time *ttPtr; nonnull_assert(interp != NULL); nonnull_assert(procNameObj != NULL); nonnull_assert(cmd != NULL); nonnull_assert(pcPtr != NULL); nonnull_assert(trtPtr != NULL); objv = pcPtr->full_objv; objc = pcPtr->objc+1; fullMethodName = ObjStr(procNameObj); CheckCStack(interp, "nsfProc", fullMethodName); /* fprintf(stderr, "=== InvokeShadowedProc %s objc %d\n", fullMethodName, objc); */ /* * The code below is derived from the scripted method dispatch and just * slightly adapted to remove object dependencies. */ procPtr = (Proc *)Tcl_Command_objClientData(cmd); result = TclPushStackFrame(interp, &framePtr, execNsPtr /* procPtr->cmdPtr->nsPtr */, (FRAME_IS_PROC)); if (likely(result == TCL_OK)) { unsigned int dummy = 0; result = ByteCompiled(interp, &dummy, procPtr, (Namespace *)execNsPtr, fullMethodName); } if (unlikely(result != TCL_OK)) { /* todo: really? error msg? */ return result; } includeTiming = ((cmdFlags & NSF_CMD_DEBUG_METHOD) != 0u); #if defined(NSF_PROFILE) if (includeTiming == 0) { NsfRuntimeState *rst = RUNTIME_STATE(interp); /*fprintf(stderr, "InvokeShadowedProc %s cmdFlags %.6lx\n", fullMethodName, cmdFlags);*/ includeTiming = rst->doProfile; } #endif Tcl_CallFrame_objc(framePtr) = (TCL_SIZE_T)objc; Tcl_CallFrame_objv(framePtr) = objv; Tcl_CallFrame_procPtr(framePtr) = procPtr; if (includeTiming) { ttPtr = (Tcl_Time *) ckalloc(sizeof(Tcl_Time)); memcpy(ttPtr, trtPtr, sizeof(Tcl_Time)); } else { ttPtr = NULL; } #if defined(NRE) /* fprintf(stderr, "CALL TclNRInterpProcCore proc '%s' %s nameObj %p %s\n", ObjStr(objv[0]), fullMethodName, procNameObj, ObjStr(procNameObj)); */ Tcl_NRAddCallback(interp, ProcDispatchFinalize, (ClientData)fullMethodName, pcPtr, (ClientData)ttPtr, (ClientData)UINT2PTR(cmdFlags) ); result = TclNRInterpProcCore(interp, procNameObj, 1, &MakeProcError); #else { ClientData data[4] = { (ClientData)fullMethodName, pcPtr, (ClientData)ttPtr, (ClientData)UINT2PTR(cmdFlags) }; result = TclObjInterpProcCore(interp, procNameObj, 1, &MakeProcError); result = ProcDispatchFinalize(data, interp, result); } #endif return result; } /* *---------------------------------------------------------------------- * NsfProcStub -- * * Tcl_ObjCmdProc implementing Proc Stubs. This function processes * the argument list in accordance with the parameter definitions * and calls in case of success the shadowed proc. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int NsfProcStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { NsfProcClientData *tcd; int result; ParseContext *pcPtr; nonnull_assert(clientData != NULL); nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); tcd = clientData; assert(tcd->cmd != NULL); /*fprintf(stderr, "NsfProcStub %s is called, tcd %p, paramDefs %p\n", ObjStr(objv[0]), tcd, tcd ? tcd->paramDefs : NULL);*/ if (!TclIsCommandDeleted(tcd->cmd) || Tcl_Command_cmdEpoch(tcd->cmd) != 0) { /* * It seems as if the (cached) command was deleted (e.g., rename), or * someone messed around with the shadowed proc. * * We must refetch the command ... */ Tcl_Command newCmdPtr = Tcl_GetCommandFromObj(interp, tcd->procName); if (unlikely(newCmdPtr == NULL)) { return NsfPrintError(interp, "cannot lookup command '%s'", ObjStr(tcd->procName)); } else if (unlikely(!CmdIsProc(newCmdPtr))) { return NsfPrintError(interp, "command '%s' is not a proc", ObjStr(tcd->procName)); } /* * ... and update the refCounts and cmd in ClientData */ NsfCommandRelease(tcd->cmd); tcd->cmd = newCmdPtr; NsfCommandPreserve(tcd->cmd); } pcPtr = (ParseContext *) NsfTclStackAlloc(interp, sizeof(ParseContext), "parse context"); if (likely(tcd->paramDefs != NULL && tcd->paramDefs->paramsPtr)) { /* * We have a parameter definition, parse the provided objv against the * parameter definition. */ result = ProcessMethodArguments(pcPtr, interp, NULL, (((tcd->flags & NSF_PROC_FLAG_CHECK_ALWAYS) != 0u) ? NSF_ARGPARSE_CHECK : 0u) |NSF_ARGPARSE_FORCE_REQUIRED, tcd->paramDefs, objv[0], objc, objv); } else { /* * In case we have no parameter definition (e.g. no arguments, or no * arguments), just pass the objv along. */ pcPtr->full_objv = (Tcl_Obj**)objv; pcPtr->objc = objc-1; pcPtr->status = 0; result = TCL_OK; } /* * Check whether the argument parsing was ok. */ if (likely(result == TCL_OK)) { Tcl_Command cmd = tcd->wrapperCmd; unsigned int cmdFlags; struct Tcl_Time trt; assert(cmd != NULL); cmdFlags = (unsigned int)Tcl_Command_flags(cmd); #if defined(NSF_PROFILE) Tcl_GetTime(&trt); if (RUNTIME_STATE(interp)->doTrace) { NsfProfileTraceCallAppend(interp, ObjStr(objv[0])); } if ((cmdFlags & NSF_CMD_DEBUG_METHOD) != 0u) { NsfProfileDebugCall(interp, NULL, NULL, ObjStr(objv[0]), objc-1, (Tcl_Obj **)objv+1); } #else if ((cmdFlags & NSF_CMD_DEBUG_METHOD) != 0u) { Tcl_GetTime(&trt); NsfProfileDebugCall(interp, NULL, NULL, ObjStr(objv[0]), objc-1, (Tcl_Obj **)objv+1); } else { trt.sec = 0; trt.usec = 0; } #endif if ((cmdFlags & NSF_CMD_DEPRECATED_METHOD) != 0u) { NsfDeprecatedCmd(interp, "proc", ObjStr(objv[0]), ""); } result = InvokeShadowedProc(interp, tcd->procName, tcd->cmd, pcPtr, &trt, cmdFlags, Tcl_Command_nsPtr(cmd)); } else { /* * Result is already set to TCL_ERROR, the error message should be already * provided. */ ParseContextRelease(pcPtr); NsfTclStackFree(interp, pcPtr, "release parse context"); } return result; } /* *---------------------------------------------------------------------- * NsfProcAdd -- * * Add a command for implementing a Tcl proc with next scripting * parameter handling. * * For the time being, this function adds two things, (a) a Tcl cmd * functioning as a stub for the argument processing (in accordance * with the parameter definitions) and (b) the shadowed Tcl proc * with a mutated name. * * TODO: the current 1 cmd + 1 proc implementation is not robust * against renaming and partial deletions (deletion of the * stub). * * Results: * A standard Tcl result. * * Side effects: * Adding one Tcl command and one Tcl proc * *---------------------------------------------------------------------- */ static int NsfProcAdd(Tcl_Interp *interp, NsfParsedParam *parsedParamPtr, const char *procName, Tcl_Obj *body, int with_ad, int with_checkAlways, int with_Debug, int with_Deprecated) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static int NsfProcAdd(Tcl_Interp *interp, NsfParsedParam *parsedParamPtr, const char *procName, Tcl_Obj *body, int with_ad, int with_checkAlways, int with_Debug, int with_Deprecated) { NsfParamDefs *paramDefs; NsfProcClientData *tcd; Tcl_Namespace *cmdNsPtr; Tcl_Obj *argList, *procNameObj, *ov[4]; Tcl_DString ds, *dsPtr = &ds; int result; unsigned int checkAlwaysFlag; Tcl_Command cmd; nonnull_assert(interp != NULL); nonnull_assert(parsedParamPtr != NULL); nonnull_assert(procName != NULL); nonnull_assert(body != NULL); Tcl_DStringInit(dsPtr); /* * Create a fully qualified procName */ if (*procName != ':') { DStringAppendQualName(dsPtr, Tcl_GetCurrentNamespace(interp), procName); procName = Tcl_DStringValue(dsPtr); } /* * Create first the ProcStub to obtain later its namespace, which is * needed as the inner namespace of the shadowed proc. */ tcd = NEW(NsfProcClientData); cmd = Tcl_CreateObjCommand(interp, procName, NsfProcStub, tcd, NsfProcStubDeleteProc); if (unlikely(cmd == NULL)) { /* * For some reason, the command could not be created. Let us hope, * we have a useful error message. */ Tcl_DStringFree(dsPtr); FREE(NsfProcClientData, tcd); return TCL_ERROR; } checkAlwaysFlag = (with_checkAlways != 0) ? NSF_ARGPARSE_CHECK : 0u; cmdNsPtr = Tcl_Command_nsPtr(cmd); /* * Storing param definitions is not needed for running the proc, since the * stub receives parameters + flag via client data... but it is needed for * introspection. * * TODO: For now, we provide no means to set the execNsPtr via interface. */ paramDefs = parsedParamPtr->paramDefs; ParamDefsStore(cmd, paramDefs, checkAlwaysFlag, NULL); /*fprintf(stderr, "NsfProcAdd procName '%s' define cmd '%s' %p in namespace %s\n", procName, Tcl_GetCommandName(interp, cmd), cmd, cmdNsPtr->fullName);*/ /* * Let us create the shadowed Tcl proc, which is stored under * ::nsf::procs::*. First build the fully qualified name procNameObj. */ Tcl_DStringSetLength(dsPtr, 0); Tcl_DStringAppend(dsPtr, "::nsf::procs", TCL_INDEX_NONE); DStringAppendQualName(dsPtr, cmdNsPtr, Tcl_GetCommandName(interp, cmd)); procNameObj = Tcl_NewStringObj(Tcl_DStringValue(dsPtr), Tcl_DStringLength(dsPtr)); INCR_REF_COUNT2("procNameObj", procNameObj); /* will be freed, when NsfProcStub is deleted */ /* * Make sure to create the target namespace under "::nsf::procs::", if * it does not exist. */ { Namespace *nsPtr, *dummy1Ptr, *dummy2Ptr; const char *dummy; /* * Create the target namespace, if it does not exist. */ TclGetNamespaceForQualName(interp, ObjStr(procNameObj), NULL, TCL_CREATE_NS_IF_UNKNOWN, &nsPtr, &dummy1Ptr, &dummy2Ptr, &dummy); } /* * Create the client data, which links the stub cmd with the proc. */ tcd->procName = procNameObj; tcd->paramDefs = paramDefs; tcd->flags = (checkAlwaysFlag != 0u ? NSF_PROC_FLAG_CHECK_ALWAYS : 0u) | (with_ad != 0 ? NSF_PROC_FLAG_AD : 0u); tcd->cmd = NULL; tcd->wrapperCmd = cmd; /* TODO should we preserve? */ tcd->interp = interp; /* for deleting the shadowed proc */ /*fprintf(stderr, "NsfProcAdd %s tcd %p paramdefs %p\n", ObjStr(procNameObj), tcd, tcd->paramDefs);*/ /* * Build an argument list for the shadowed proc. */ argList = Tcl_NewListObj(0, NULL); INCR_REF_COUNT(argList); if (paramDefs != NULL) { Nsf_Param *paramPtr; for (paramPtr = paramDefs->paramsPtr; paramPtr->name != NULL; paramPtr++) { if (*paramPtr->name == '-') { Tcl_Obj *varNameObj = Tcl_NewStringObj(paramPtr->name+1, TCL_INDEX_NONE); /* * If we have the -ad (for ars digita) flag set, we provide the * OpenACS semantics. This is (a) to use the name "boolean" for * a switch and (b) to name the automatic variable with the * prefix "_p". */ if (with_ad && paramPtr->converter == Nsf_ConvertToBoolean && paramPtr->nrArgs == 1) { /*fprintf(stderr, "... ad handling: proc %s param %s type %s nrargs %d default %p\n", procName, paramPtr->name, paramPtr->type, paramPtr->nrArgs, paramPtr->defaultValue);*/ paramPtr->nrArgs = 0; /*paramPtr->converter = Nsf_ConvertToSwitch;*/ Tcl_AppendToObj(varNameObj, "_p", 2); if (paramPtr->defaultValue == NULL) { paramPtr->defaultValue = Tcl_NewBooleanObj(0); INCR_REF_COUNT(paramPtr->defaultValue); } } Tcl_ListObjAppendElement(interp, argList, varNameObj); } else { Tcl_ListObjAppendElement(interp, argList, Tcl_NewStringObj(paramPtr->name, TCL_INDEX_NONE)); } } } ov[0] = NULL; ov[1] = procNameObj; ov[2] = argList; ov[3] = AddPrefixToBody(body, NSF_TRUE, parsedParamPtr); /*fprintf(stderr, "NsfProcAdd define proc %s arglist '%s'\n", ObjStr(ov[1]), ObjStr(ov[2])); */ result = Tcl_ProcObjCmd(0, interp, 4, ov); DECR_REF_COUNT(argList); DECR_REF_COUNT2("resultBody", ov[3]); if (likely(result == TCL_OK)) { /* * The shadowed proc was created successfully. Retrieve the defined proc * and set its namespace to the namespace of the stub cmd. */ Tcl_Command procCmd = Tcl_GetCommandFromObj(interp, procNameObj); assert(procCmd != NULL); tcd->cmd = procCmd; NsfCommandPreserve(tcd->cmd); if (with_Debug) { Tcl_Command_flags(cmd) |= NSF_CMD_DEBUG_METHOD; } if (with_Deprecated) { Tcl_Command_flags(cmd) |= NSF_CMD_DEPRECATED_METHOD; } } else { /* * We could not define the shadowed proc. In this case, cleanup by * removing the stub cmd. */ Tcl_DeleteCommandFromToken(interp, cmd); } Tcl_DStringFree(dsPtr); return result; } /* *---------------------------------------------------------------------- * ProcessMethodArguments -- * * Process the arguments provided to a method call. It parses the argument * vector objv, disallows certain parameter types and updates the parse * context. * * Results: * A standard Tcl result. * * Side effects: * Updates parameter context * *---------------------------------------------------------------------- */ static int ProcessMethodArguments(ParseContext *pcPtr, Tcl_Interp *interp, NsfObject *object, unsigned int processFlags, NsfParamDefs *paramDefs, Tcl_Obj *methodNameObj, int objc, Tcl_Obj *const objv[]) { int result; CallFrame frame, *framePtr = &frame; nonnull_assert(pcPtr != NULL); nonnull_assert(interp != NULL); nonnull_assert(paramDefs != NULL); nonnull_assert(methodNameObj != NULL); nonnull_assert(objv != NULL); if (object != NULL && (processFlags & NSF_ARGPARSE_METHOD_PUSH) != 0u ) { #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, object, framePtr); #pragma GCC diagnostic pop } #if 0 {int i; fprintf(stderr, "ProcessMethodArguments before ArgumentParse %s (flags %.6x objc %d): ", ObjStr(methodNameObj), processFlags, objc); for(i = 0; i < objc; i++) {fprintf(stderr, " [%d]=%s,", i, ObjStr(objv[i]));} fprintf(stderr, "\n"); Tcl_Obj *listObj = ParamDefsList(interp, paramDefs->paramsPtr, NULL, NULL); fprintf(stderr, "... got params <%s>\n", ObjStr(listObj)); } #endif result = ArgumentParse(interp, objc, objv, object, methodNameObj, paramDefs->paramsPtr, paramDefs->nrParams, paramDefs->serial, processFlags|RUNTIME_STATE(interp)->doCheckArguments, pcPtr); #if 0 { int i, fromArg, toArg; fprintf(stderr, "ProcessMethodArguments after ArgumentParse %s pcPtr->objc %d result %d\n", ObjStr(methodNameObj), pcPtr->objc, result); if (result == TCL_OK) { if ((processFlags & NSF_ARGPARSE_START_ZERO) != 0u) { fromArg = 0; toArg = pcPtr->objc; } else { fromArg = 1; toArg = pcPtr->objc; } for (i = fromArg; i < toArg; i++) { fprintf(stderr, "... pcPtr %p [%d] obj %p refCount %d (%s) flags %.6x & %p\n", (void*)pcPtr, i, pcPtr->objv[i] ? (void*)pcPtr->objv[i] : NULL, pcPtr->objv[i] ? pcPtr->objv[i]->refCount : -1, pcPtr->objv[i] ? ObjStr(pcPtr->objv[i]) : "(null)", pcPtr->flags[i], (void*)&(pcPtr->flags[i])); } } } #endif if (object != NULL && ((processFlags & NSF_ARGPARSE_METHOD_PUSH) != 0u)) { Nsf_PopFrameObj(interp, framePtr); } /* * Set objc of the parse context to the number of defined parameters. * pcPtr->objc and paramDefs->nrParams will be equivalent in cases * where argument values are passed to the call in absence of var * args ('args'). Treating "args is more involved (see below). */ if (unlikely(result != TCL_OK)) { return result; } if (pcPtr->varArgs) { /* * The last argument was "args". */ int elts = objc - pcPtr->lastObjc; if (elts == 0) { /* * No arguments were passed to "args". We simply decrement objc. */ pcPtr->objc--; } else if (elts > 1) { /* * Multiple arguments were passed to "args". The array pcPtr->objv is * pointing to the first of the var args. We have to copy the remaining * actual argument vector objv to the parse context. */ /*NsfPrintObjv("actual: ", objc, objv);*/ ParseContextExtendObjv(pcPtr, (unsigned)paramDefs->nrParams, (unsigned)elts-1u, objv + 1u + pcPtr->lastObjc); } else { /* * A single argument was passed to "args". There is no need to * mutate the pcPtr->objv, because this has been achieved in * ArgumentParse (i.e., pcPtr->objv[i] contains this element). */ } } return TCL_OK; } /************************************************************************** * End Definition of nsf::proc (Tcl Procs with Parameter handling) **************************************************************************/ /* *---------------------------------------------------------------------- * ForwardCmdDeleteProc -- * * This Tcl_CmdDeleteProc is called, when a forward method is deleted * * Results: * None. * * Side effects: * Frees client data of the setter command. * *---------------------------------------------------------------------- */ static void ForwardCmdDeleteProc(ClientData clientData) { ForwardCmdClientData *tcd; nonnull_assert(clientData != NULL); tcd = (ForwardCmdClientData *)clientData; if (tcd->cmdName != NULL) {DECR_REF_COUNT(tcd->cmdName);} if (tcd->subcommands != NULL) {DECR_REF_COUNT(tcd->subcommands);} #if defined(NSF_FORWARD_WITH_ONERROR) if (tcd->onerror != NULL) {DECR_REF_COUNT(tcd->onerror);} #endif if (tcd->prefix != NULL) {DECR_REF_COUNT(tcd->prefix);} if (tcd->args != NULL) {DECR_REF_COUNT(tcd->args);} FREE(ForwardCmdClientData, tcd); } /* *---------------------------------------------------------------------- * SetterCmdDeleteProc -- * * This Tcl_CmdDeleteProc is called, when a setter method is deleted * * Results: * None. * * Side effects: * Frees client data of the setter command. * *---------------------------------------------------------------------- */ static void SetterCmdDeleteProc(ClientData clientData) nonnull(1); static void SetterCmdDeleteProc(ClientData clientData) { SetterCmdClientData *setterClientData; nonnull_assert(clientData != NULL); setterClientData = (SetterCmdClientData *)clientData; if (setterClientData->paramsPtr != NULL) { ParamsFree(setterClientData->paramsPtr); } FREE(SetterCmdClientData, setterClientData); } /* *---------------------------------------------------------------------- * AliasCmdDeleteProc -- * * This Tcl_CmdDeleteProc is called, when an alias method is deleted * * Results: * None. * * Side effects: * Frees client data of the setter command. * *---------------------------------------------------------------------- */ static void AliasCmdDeleteProc(ClientData clientData) nonnull(1); static void AliasCmdDeleteProc(ClientData clientData) { AliasCmdClientData *tcd; nonnull_assert(clientData != NULL); /* * Since we just get the clientData, we have to obtain interp, * object, methodName and per-object from tcd; the obj might be * deleted already. We need as well at least still the global * namespace. */ tcd = (AliasCmdClientData *)clientData; if ((tcd->interp != NULL) && (((Interp *)(tcd->interp))->globalNsPtr != NULL) && RUNTIME_STATE(tcd->interp)->exitHandlerDestroyRound != NSF_EXITHANDLER_ON_PHYSICAL_DESTROY ) { const char *methodName = Tcl_GetCommandName(tcd->interp, tcd->aliasCmd); AliasDelete(tcd->interp, tcd->cmdName, methodName, tcd->class == NULL); } /*fprintf(stderr, "AliasCmdDeleteProc aliasedCmd %p\n", tcd->aliasedCmd);*/ if (tcd->cmdName != NULL) { DECR_REF_COUNT(tcd->cmdName); } if (tcd->aliasedCmd != NULL) { #if defined(WITH_IMPORT_REFS) ImportRef *refPtr, *prevPtr = NULL; Command *aliasedCmd = (Command *)(tcd->aliasedCmd); /*fprintf(stderr, "AliasCmdDeleteProc aliasedCmd %p epoch %d refCount %d\n", aliasedCmd, Tcl_Command_cmdEpoch(tcd->aliasedCmd), aliasedCmd->refCount);*/ /* * Clear the aliasCmd from the imported-ref chain of the aliased * (or real) cmd. This widely resembles what happens in the * DeleteImportedCmd() (see tclNamesp.c), however, as we do not * provide for ImportedCmdData client data etc., we cannot * directly use it. */ for (refPtr = aliasedCmd->importRefPtr; refPtr != NULL; refPtr = refPtr->nextPtr) { if (refPtr->importedCmdPtr == (Command *) tcd->aliasCmd) { if (prevPtr == NULL) { aliasedCmd->importRefPtr = refPtr->nextPtr; } else { prevPtr->nextPtr = refPtr->nextPtr; } ckfree((char *) refPtr); break; } prevPtr = refPtr; } #endif NsfCommandRelease(tcd->aliasedCmd); } FREE(AliasCmdClientData, tcd); } /* *---------------------------------------------------------------------- * GetMatchObject -- * * Helper method used by nsfAPI.h and the info methods to check whether the * Tcl_Obj patternObj was provided and can be looked up. If this is the * case, wild card matching etc. does not have to be performed, but just * the properties of the object have to be tested. * * Results: * 0 or 1 or -1, potentially the matchObject (when 0 is returned) * 0: we have wild-card characters, iterate to get matches * 1: we have an existing object * -1: we no wild-card characters and a non-existing object * * Side effects: * None. * *---------------------------------------------------------------------- */ static int GetMatchObject(Tcl_Interp *interp, Tcl_Obj *patternObj, Tcl_Obj *origObj, NsfObject **matchObjectPtr, const char **patternPtr) { nonnull_assert(interp != NULL); nonnull_assert(matchObjectPtr != NULL); nonnull_assert(patternPtr != NULL); if (patternObj != NULL) { *patternPtr = ObjStr(patternObj); if (TclObjIsNsfObject(interp, patternObj, matchObjectPtr)) { return 1; } if (patternObj == origObj && **patternPtr != ':') { return -1; } } return 0; } /* *---------------------------------------------------------------------- * ForwardProcessOptions -- * * Process the options provided by the forward method and turn these into * the ForwardCmdClientData structure. * * Results: * A standard Tcl result. * * Side effects: * Allocated and initialized ForwardCmdClientData * *---------------------------------------------------------------------- */ static int ForwardProcessOptions(Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_Obj *withDefault, int withEarlybinding, Tcl_Obj *withOnerror, Tcl_Obj *withMethodprefix, int withFrame, bool withVerbose, Tcl_Obj *target, int objc, Tcl_Obj * const objv[], ForwardCmdClientData **tcdPtr) { ForwardCmdClientData *tcd; int i, result = 0; nonnull_assert(interp != NULL); nonnull_assert(nameObj != NULL); nonnull_assert(objv != NULL); tcd = NEW(ForwardCmdClientData); memset(tcd, 0, sizeof(ForwardCmdClientData)); if (withDefault != 0) { Tcl_DString ds, *dsPtr = &ds; DSTRING_INIT(dsPtr); Tcl_DStringAppend(dsPtr, "%1 {", 4); Tcl_DStringAppend(dsPtr, ObjStr(withDefault), TCL_INDEX_NONE); Tcl_DStringAppend(dsPtr, "}", 1); NsfDeprecatedCmd(interp, "forward option", "-default ...", Tcl_DStringValue(dsPtr)); DSTRING_FREE(dsPtr); tcd->subcommands = withDefault; result = Tcl_ListObjLength(interp, withDefault, &tcd->nr_subcommands); INCR_REF_COUNT(tcd->subcommands); } if (withMethodprefix != 0) { tcd->prefix = withMethodprefix; INCR_REF_COUNT(tcd->prefix); } #if defined(NSF_FORWARD_WITH_ONERROR) if (withOnerror != 0) { tcd->onerror = withOnerror; INCR_REF_COUNT(tcd->onerror); } #endif tcd->frame = withFrame; tcd->verbose = withVerbose; tcd->needobjmap = NSF_FALSE; tcd->cmdName = target; /*fprintf(stderr, "...forwardprocess objc %d, cmdName %p %s\n", objc, target, ObjStr(target));*/ for (i = 0; i < objc; i++) { const char *element = ObjStr(objv[i]); /*fprintf(stderr, "... [%d] forwardprocess element '%s'\n", i, element);*/ tcd->needobjmap = (tcd->needobjmap || (*element == '%' && *(element+1) == '@')); tcd->hasNonposArgs = (tcd->hasNonposArgs || (*element == '%' && *(element+1) == '-')); if (tcd->args == NULL) { tcd->args = Tcl_NewListObj(1, &objv[i]); tcd->nr_args++; INCR_REF_COUNT(tcd->args); } else { Tcl_ListObjAppendElement(interp, tcd->args, objv[i]); tcd->nr_args++; } } if (tcd->cmdName == NULL) { tcd->cmdName = nameObj; } /*fprintf(stderr, "+++ cmdName = %s, args = %s, # = %d\n", ObjStr(tcd->cmdName), (tcd->args != NULL) ?ObjStr(tcd->args):"NULL", tcd->nr_args);*/ if (tcd->frame == FrameObjectIdx) { /* * When we evaluating objscope, and define ... * o forward append -frame object append * a call to * o append ... * would lead to a recursive call; so we add the appropriate namespace. */ const char *nameString = ObjStr(tcd->cmdName); if (!isAbsolutePath(nameString)) { tcd->cmdName = NameInNamespaceObj(nameString, CallingNameSpace(interp)); /*fprintf(stderr, "+++ name %s not absolute, therefore, qualifying %s\n", nameString, ObjStr(tcd->cmdName));*/ } } INCR_REF_COUNT(tcd->cmdName); if (withEarlybinding != 0) { Tcl_Command cmd = Tcl_GetCommandFromObj(interp, tcd->cmdName); if (cmd == NULL) { result = NsfPrintError(interp, "cannot lookup command '%s'", ObjStr(tcd->cmdName)); goto forward_process_options_exit; } if (CmdIsNsfObject(cmd) /* don't do direct invoke on nsf objects */ || Tcl_Command_objProc(cmd) == TclObjInterpProc /* don't do direct invoke on Tcl procs */ ) { /* * Silently ignore earlybinding flag */ tcd->objProc = NULL; } else { tcd->objProc = Tcl_Command_objProc(cmd); tcd->clientData = Tcl_Command_objClientData(cmd); } } tcd->passthrough = (tcd->args == NULL && *(ObjStr(tcd->cmdName)) != '%' && tcd->objProc); forward_process_options_exit: /*fprintf(stderr, "forward args = %p, name = '%s'\n", tcd->args, ObjStr(tcd->cmdName));*/ if (likely(result == TCL_OK)) { *tcdPtr = tcd; } else { ForwardCmdDeleteProc(tcd); } return result; } /* *---------------------------------------------------------------------- * StripBodyPrefix -- * * Strip the prefix of the body, which might have been added by nsf. * * Results: * The string of the body without the prefix. * * Side effects: * None. * *---------------------------------------------------------------------- */ static const char * StripBodyPrefix(const char *body) nonnull(1) NSF_pure; static const char * StripBodyPrefix(const char *body) { nonnull_assert(body != NULL); if (strncmp(body, "::nsf::__unset_unknown_args\n", 28) == 0) { body += 28; } return body; } /* *---------------------------------------------------------------------- * AddSlotObjects -- * * Compute the slot objects (children of the slot container) for a provided * object. The objects can be filtered via a pattern. * * Results: * The function appends results to the provide listObj * * Side effects: * Might add as well to the hash-table to avoid duplicates. * *---------------------------------------------------------------------- */ static void AddSlotObjects(Tcl_Interp *interp, NsfObject *parent, const char *prefix, Tcl_HashTable *slotTablePtr, NsfClass *typeClass, const char *pattern, Tcl_Obj *listObj) nonnull(1) nonnull(2) nonnull(3) nonnull(7); static void AddSlotObjects(Tcl_Interp *interp, NsfObject *parent, const char *prefix, Tcl_HashTable *slotTablePtr, NsfClass *typeClass, const char *pattern, Tcl_Obj *listObj) { NsfObject *slotContainerObject; Tcl_DString ds, *dsPtr = &ds; bool isFullQualPattern = ((pattern != NULL) && *pattern == ':' && *(pattern+1) == ':'); nonnull_assert(interp != NULL); nonnull_assert(parent != NULL); nonnull_assert(prefix != NULL); nonnull_assert(listObj != NULL); /*fprintf(stderr, "AddSlotObjects parent %s prefix %s type %p %s\n", ObjectName(parent), prefix, type, (type != NULL) ? ClassName(type) : "");*/ DSTRING_INIT(dsPtr); Tcl_DStringAppend(dsPtr, ObjectName_(parent), TCL_INDEX_NONE); Tcl_DStringAppend(dsPtr, prefix, TCL_INDEX_NONE); slotContainerObject = GetObjectFromString(interp, Tcl_DStringValue(dsPtr)); if (slotContainerObject != NULL && slotContainerObject->nsPtr && ((slotContainerObject->flags & NSF_IS_SLOT_CONTAINER) != 0u)) { Tcl_HashSearch hSrch; const Tcl_HashEntry *hPtr; Tcl_HashTable *cmdTablePtr = Tcl_Namespace_cmdTablePtr(slotContainerObject->nsPtr); Tcl_Command cmd; hPtr = Tcl_FirstHashEntry(cmdTablePtr, &hSrch); for (; hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { const char *key = Tcl_GetHashKey(cmdTablePtr, hPtr); NsfObject *childObject; if (slotTablePtr != NULL) { int new; /* * Check whether we have and entry with this key already processed. We * never want to report shadowed entries. */ Tcl_CreateHashEntry(slotTablePtr, key, &new); if (new == 0) { continue; } } /* * Obtain the childObject */ cmd = (Tcl_Command) Tcl_GetHashValue(hPtr); childObject = NsfGetObjectFromCmdPtr(cmd); /* * Report just the already fully initialized slot objects, not the one * being right now created. */ if (childObject == NULL || (childObject->flags & NSF_INIT_CALLED) == 0u) { /* fprintf(stderr, "....... key %s unfinished\n", key);*/ continue; } /* * Check the pattern. */ if (pattern != NULL) { int isMatch; /* * If the pattern looks like fully qualified, we match against the * fully qualified name. */ if (isFullQualPattern) { isMatch = Tcl_StringMatch(ObjectName(childObject), pattern); } else { /* * do we have a mangled name of a private property/variable? */ if (*key == '_' && *(key+1) == '_' && *(key+2) == '_' && *(key+3) == '_') { Tcl_Obj *value = Nsf_ObjGetVar2((Nsf_Object *)childObject, interp, NsfGlobalObjs[NSF_SETTERNAME], NULL, 0); isMatch = (value != NULL) ? Tcl_StringMatch(ObjStr(value), pattern) : 0; /*fprintf(stderr, "pattern <%s> isFullQualPattern %d child %s key %s %p <%s> match %d\n", pattern, isFullQualPattern, ObjectName(childObject), key, value, (value != NULL) ? ObjStr(value) : "", match);*/ } else { isMatch = Tcl_StringMatch(key, pattern); } } if (isMatch == 0) { continue; } } /* * Check whether the entry is from the right type. */ if (typeClass != NULL && !IsSubType(childObject->cl, typeClass)) { continue; } /* * Add finally the entry to the returned list. */ Tcl_ListObjAppendElement(interp, listObj, childObject->cmdName); } } DSTRING_FREE(dsPtr); } /* *---------------------------------------------------------------------- * FindCalledClass -- * * Find the called class of the called proc on the call-stack. * * Results: * NsfClass * or NULL * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfClass *FindCalledClass(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); static NsfClass * FindCalledClass(Tcl_Interp *interp, NsfObject *object) { NsfCallStackContent *cscPtr; NsfClass *result; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); cscPtr = CallStackGetTopFrame0(interp); if (unlikely(cscPtr == NULL)) { result = NULL; } else { if (cscPtr->frameType == NSF_CSC_TYPE_PLAIN) { result = cscPtr->cl; } else { const char *methodName; if (cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_FILTER) { methodName = MethodName(cscPtr->filterStackEntry->calledProc); } else if (cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_MIXIN && object->mixinStack != NULL) { methodName = Tcl_GetCommandName(interp, cscPtr->cmdPtr); } else { methodName = NULL; } if (unlikely(methodName == NULL)) { result = NULL; } else if (object->nsPtr != NULL && FindMethod(object->nsPtr, methodName) != NULL) { /* * An object specific method was called. */ result = NULL; } else { Tcl_Command cmd; result = SearchCMethod(object->cl, methodName, &cmd); } } } return result; } /* * Next Primitive Handling */ /* *---------------------------------------------------------------------- * NextSearchMethod -- * * Determine the method to be called via "next". The function returns on * success the found cmd and information like method name, was it from a * mixin, filter, or was the end of the filter chain reached. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static int NextSearchMethod( NsfObject *object, Tcl_Interp *interp, const NsfCallStackContent *cscPtr, NsfClass **classPtr, const char **methodNamePtr, Tcl_Command *cmdPtr, bool *isMixinEntry, bool *isFilterEntry, bool *endOfFilterChain, Tcl_Command *currentCmdPtr ) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(5) nonnull(6) nonnull(7) nonnull(8) nonnull(9) nonnull(10); NSF_INLINE static int NextSearchMethod( NsfObject *object, Tcl_Interp *interp, const NsfCallStackContent *cscPtr, NsfClass **classPtr, const char **methodNamePtr, Tcl_Command *cmdPtr, bool *isMixinEntry, bool *isFilterEntry, bool *endOfFilterChain, Tcl_Command *currentCmdPtr ) { bool endOfChain = NSF_FALSE; unsigned int objflags; nonnull_assert(object != NULL); nonnull_assert(interp != NULL); nonnull_assert(cscPtr != NULL); nonnull_assert(classPtr != NULL); nonnull_assert(methodNamePtr != NULL); nonnull_assert(cmdPtr != NULL); nonnull_assert(isMixinEntry != NULL); nonnull_assert(isFilterEntry != NULL); nonnull_assert(endOfFilterChain != NULL); nonnull_assert(currentCmdPtr != NULL); /*fprintf(stderr, "NextSearchMethod for %s called with cl %p\n", *methodNamePtr, *classPtr);*/ /* * Next in filters */ objflags = object->flags; /* avoid stalling */ if ((objflags & NSF_MIXIN_ORDER_VALID) == 0u) { MixinComputeDefined(interp, object); objflags = object->flags; /* avoid stalling */ } if ((objflags & NSF_FILTER_ORDER_VALID) != 0u && (object->filterStack != NULL) && object->filterStack->currentCmdPtr) { *cmdPtr = FilterSearchProc(interp, object, currentCmdPtr, classPtr); /*fprintf(stderr, "FilterSearchProc returned cmd %p\n", *cmdPtr); NsfShowStack(interp);*/ if (*cmdPtr == NULL) { if (cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_FILTER) { /* * Reset the information to the values of method, classPtr * to the values they had before calling the filters. */ *methodNamePtr = MethodName(object->filterStack->calledProc); endOfChain = NSF_TRUE; *endOfFilterChain = NSF_TRUE; *classPtr = NULL; /*fprintf(stderr, "EndOfChain resetting cl\n");*/ } } else { *methodNamePtr = (char *) Tcl_GetCommandName(interp, *cmdPtr); *endOfFilterChain = NSF_FALSE; *isFilterEntry = NSF_TRUE; return TCL_OK; } } /* * Next in Mixins requires that we have already a mixinStack, and the * current frame is not a plain frame. */ assert((objflags & NSF_MIXIN_ORDER_VALID) != 0u); if ((object->mixinStack != NULL) && cscPtr->frameType) { int result = MixinSearchProc(interp, object, *methodNamePtr, classPtr, currentCmdPtr, cmdPtr); /* fprintf(stderr, "next in mixins %s frameType %.6x\n", *methodNamePtr, cscPtr->frameType); */ if (unlikely(result != TCL_OK)) { return result; } if (*cmdPtr == NULL) { if (cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_MIXIN) { endOfChain = NSF_TRUE; *classPtr = NULL; } } else { *isMixinEntry = NSF_TRUE; return TCL_OK; } } /*fprintf(stderr, "nextsearch: object %s nsPtr %p endOfChain %d\n", ObjectName(object), object->nsPtr, endOfChain);*/ /* * Otherwise: normal method dispatch * * If we are already in the precedence ordering, then advance * past our last point; otherwise (if classPtr == NULL) begin from the start. * * When a mixin or filter chain reached its end, we have to check for * fully qualified method names and search the obj-specific methods as well. */ if (endOfChain) { if (**methodNamePtr == ':') { *cmdPtr = Tcl_FindCommand(interp, *methodNamePtr, NULL, TCL_GLOBAL_ONLY); /* fprintf(stderr, "NEXT found absolute cmd %s => %p\n", *methodNamePtr, *cmdPtr); */ } else if (object->nsPtr != NULL) { *cmdPtr = FindMethod(object->nsPtr, *methodNamePtr); if ((*cmdPtr != NULL) && ((unsigned int)Tcl_Command_flags(*cmdPtr) & NSF_CMD_CALL_PRIVATE_METHOD) != 0u ) { /*fprintf(stderr, "NEXT found private cmd %s => %p\n", *methodNamePtr, *cmdPtr);*/ *cmdPtr = NULL; } } else { *cmdPtr = NULL; } } else { *cmdPtr = NULL; } /*fprintf(stderr, "NEXT methodName %s *classPtr %p %s *cmd %p cscPtr->flags %.6x\n", *methodNamePtr, *classPtr, ClassName((*classPtr)), *cmdPtr, cscPtr->flags); */ if (*cmdPtr == NULL) { const NsfClasses *pl = PrecedenceOrder(object->cl); const NsfClass *class = *classPtr; if (class != NULL) { /* * Skip until actual class */ for ( ; pl != NULL; pl = pl->nextPtr) { if (pl->cl == class) { pl = pl->nextPtr; break; } } } if (pl != NULL) { /* * Search for a further class method. When we are called from an active * filter and the call had the "-local" flag set, then allow one to call * private methods. */ *classPtr = SearchPLMethod(pl, *methodNamePtr, cmdPtr, ((cscPtr->flags & NSF_CM_LOCAL_METHOD) != 0u && (cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_FILTER) != 0u) ? 0 : NSF_CMD_CALL_PRIVATE_METHOD); } else { *classPtr = NULL; } } else { *classPtr = NULL; } return TCL_OK; } /* *---------------------------------------------------------------------- * NextGetArguments -- * * Obtain arguments for a method invoked via next either from the argument * vector or from the stack (call stack content or Tcl stack). In case of * ensemble calls the stack entries of the ensemble invocation are * used. The function returns the arguments 4 to 8. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int NextGetArguments( Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], NsfCallStackContent **cscPtrPtr, const char **methodNamePtr, int *outObjc, Tcl_Obj ***outObjv, bool *freeArgumentVector ) nonnull(1) nonnull(4) nonnull(5) nonnull(6) nonnull(7) nonnull(8); static int NextGetArguments( Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], NsfCallStackContent **cscPtrPtr, const char **methodNamePtr, int *outObjc, Tcl_Obj ***outObjv, bool *freeArgumentVector ) { Tcl_Obj **nobjv; TCL_SIZE_T nobjc, oc; bool inEnsemble; Tcl_CallFrame *framePtr; NsfCallStackContent *cscPtr; nonnull_assert(interp != NULL); nonnull_assert(cscPtrPtr != NULL); nonnull_assert(methodNamePtr != NULL); nonnull_assert(outObjc != NULL); nonnull_assert(outObjv != NULL); nonnull_assert(freeArgumentVector != NULL); /* * Initialize to zero to make sure, we only decrement when necessary. */ *freeArgumentVector = NSF_FALSE; cscPtr = CallStackGetTopFrame(interp, &framePtr); if (cscPtr == NULL) { return NsfPrintError(interp, "next: can't find self"); } if (cscPtr->cmdPtr == NULL) { return NsfPrintError(interp, "next: no executing proc"); } oc = Tcl_CallFrame_objc(framePtr); if ((cscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE)) { /* * We are in an ensemble method. The next works here not on the * actual methodName + frame, but on the ensemble above it. We * locate the appropriate call-stack content and continue next on * that. */ cscPtr = CallStackFindEnsembleCsc(framePtr, &framePtr); assert(cscPtr != NULL); inEnsemble = NSF_TRUE; *methodNamePtr = MethodName(cscPtr->objv[0]); } else { inEnsemble = NSF_FALSE; *methodNamePtr = Tcl_GetCommandName(interp, cscPtr->cmdPtr); } /*fprintf(stderr, "NextGetArguments oc %d objc %d inEnsemble %d objv %p\n", oc, objc, inEnsemble, cscPtr->objv); */ if (objc > -1) { size_t methodNameLength; /* * Arguments were provided. We have to construct an argument * vector with the first argument(s) as the method name. In an * ensemble, we have to insert the objs of the full ensemble name. */ if (inEnsemble) { methodNameLength = 1 + (size_t)cscPtr->objc - (size_t)oc; nobjc = (TCL_SIZE_T)objc + (TCL_SIZE_T)methodNameLength; nobjv = (Tcl_Obj **)ckalloc((unsigned)sizeof(Tcl_Obj *) * (unsigned)nobjc); MEM_COUNT_ALLOC("nextArgumentVector", nobjv); /* * Copy the ensemble pathname */ memcpy((char *)nobjv, cscPtr->objv, sizeof(Tcl_Obj *) * (size_t)methodNameLength); } else { methodNameLength = 1; nobjc = (TCL_SIZE_T)objc + (TCL_SIZE_T)methodNameLength; nobjv = (Tcl_Obj **)ckalloc((unsigned)sizeof(Tcl_Obj *) * (unsigned)nobjc); MEM_COUNT_ALLOC("nextArgumentVector", nobjv); /* * Copy the method name */ if (cscPtr->objv != NULL) { nobjv[0] = cscPtr->objv[0]; } else if (Tcl_CallFrame_objv(framePtr)) { nobjv[0] = Tcl_CallFrame_objv(framePtr)[0]; } } if (objc > 0 && (objv != NULL || cscPtr->objv != NULL)) { /* * Copy the remaining argument vector */ memcpy(nobjv + methodNameLength, objv == NULL ? cscPtr->objv : objv, sizeof(Tcl_Obj *) * (size_t)objc); } INCR_REF_COUNT(nobjv[0]); /* we seem to need this here */ *freeArgumentVector = NSF_TRUE; } else { /* * No arguments were provided */ if (cscPtr->objv != NULL) { nobjv = (Tcl_Obj **)cscPtr->objv; nobjc = (TCL_SIZE_T)cscPtr->objc; } else { nobjc = Tcl_CallFrame_objc(framePtr); nobjv = (Tcl_Obj **)Tcl_CallFrame_objv(framePtr); } } *cscPtrPtr = cscPtr; *outObjc = (int)nobjc; *outObjv = nobjv; return TCL_OK; } /* *---------------------------------------------------------------------- * NextInvokeFinalize -- * * This finalize function is either called via NRE callback or * directly (from NextSearchAndInvoke). It resets after a successful * lookup and invocation the continuation context (filter flags etc) * and cleans up optionally the argument vector (inverse operation * of NextGetArguments). * * Results: * A standard Tcl result. * * Side effects: * freeing memory * *---------------------------------------------------------------------- */ NSF_INLINE static int NextInvokeFinalize(ClientData data[], Tcl_Interp *interp, int result) nonnull(1) nonnull(2); NSF_INLINE static int NextInvokeFinalize(ClientData data[], Tcl_Interp *interp, int result) { Tcl_Obj **nobjv; NsfCallStackContent *cscPtr; nonnull_assert(data != NULL); nonnull_assert(interp != NULL); nobjv = data[0]; cscPtr = data[1]; /*fprintf(stderr, "***** NextInvokeFinalize cscPtr %p flags %.6x is next %d result %d unk %d\n", cscPtr, cscPtr->flags, cscPtr->flags & NSF_CSC_CALL_IS_NEXT, result, RUNTIME_STATE(interp)->unknown);*/ if ((cscPtr->flags & NSF_CSC_CALL_IS_NEXT) != 0u) { /* fprintf(stderr, "..... it was a successful next\n"); */ cscPtr->flags &= ~NSF_CSC_CALL_IS_NEXT; if (cscPtr->frameType == NSF_CSC_TYPE_INACTIVE_FILTER) { cscPtr->frameType = NSF_CSC_TYPE_ACTIVE_FILTER; } else if (cscPtr->frameType == NSF_CSC_TYPE_INACTIVE_MIXIN) { cscPtr->frameType = NSF_CSC_TYPE_ACTIVE_MIXIN; } } if (nobjv != NULL) { DECR_REF_COUNT(nobjv[0]); MEM_COUNT_FREE("nextArgumentVector", nobjv); ckfree((char *)nobjv); } if (result == TCL_ERROR && RUNTIME_STATE(interp)->unknown) { /* fprintf(stderr, "don't report unknown error\n"); */ /* * Don't report "unknown" errors via next. */ result = TCL_OK; } return result; } /* *---------------------------------------------------------------------- * NextSearchAndInvoke -- * * The function is called with a final argument vector and searches for a * possibly shadowed method. If a target method is found, this dispatcher * function updates the continuation context (filter flags etc.), invokes * upon the target method, and performs a cleanup. * * Results: * A standard Tcl result. * * Side effects: * The invoked method might produce side effects. Also, the interp's unknown * state may be modified. * *---------------------------------------------------------------------- */ static int NextSearchAndInvoke( Tcl_Interp *interp, const char *methodName, int objc, Tcl_Obj *const objv[], NsfCallStackContent *cscPtr, bool freeArgumentVector ) { Tcl_Command cmd = NULL, currentCmd = NULL; int result; bool endOfFilterChain = NSF_FALSE, isMixinEntry = NSF_FALSE, isFilterEntry = NSF_FALSE; NsfRuntimeState *rst; NsfObject *object; NsfClass *class; nonnull_assert(interp != NULL); nonnull_assert(methodName != NULL); nonnull_assert(cscPtr != NULL); rst = RUNTIME_STATE(interp); /* * Search the next method & compute its method data */ class = cscPtr->cl; object = cscPtr->self; result = NextSearchMethod(object, interp, cscPtr, &class, &methodName, &cmd, &isMixinEntry, &isFilterEntry, &endOfFilterChain, ¤tCmd); /*fprintf(stderr, "NEXT search on %s.%s cl %p cmd %p endOfFilterChain %d result %d IS OK %d\n", ObjectName(object), methodName, (void*)class, (void*)cmd, endOfFilterChain, result, (result == TCL_OK));*/ if (unlikely(result != TCL_OK)) { goto next_search_and_invoke_cleanup; } #if 0 Tcl_ResetResult(interp); /* needed for bytecode support */ #endif if (cmd != NULL) { unsigned short frameType = NSF_CSC_TYPE_PLAIN; /* * Change mixin state. */ if (object->mixinStack != NULL) { if (cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_MIXIN) { cscPtr->frameType = NSF_CSC_TYPE_INACTIVE_MIXIN; } /* * Otherwise move the command pointer forward. */ if (isMixinEntry) { frameType = NSF_CSC_TYPE_ACTIVE_MIXIN; object->mixinStack->currentCmdPtr = currentCmd; } } /* * Change filter state */ if (object->filterStack != NULL) { if (cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_FILTER) { /*fprintf(stderr, "next changes filter state\n");*/ cscPtr->frameType = NSF_CSC_TYPE_INACTIVE_FILTER; } /* * Otherwise move the command pointer forward. */ if (isFilterEntry) { /*fprintf(stderr, "next moves filter forward\n");*/ frameType = NSF_CSC_TYPE_ACTIVE_FILTER; object->filterStack->currentCmdPtr = currentCmd; } } /* * Now actually call the "next" method. */ cscPtr->flags |= NSF_CSC_CALL_IS_NEXT; rst->unknown = 0; #if defined(NRE) { unsigned int flags; /* * Allow call only without immediate flag, when caller has NRE without * immediate. */ flags = NsfImmediateFromCallerFlags(cscPtr->flags); /*fprintf(stderr, "MethodDispatch in next flags %.6x NRE %d immediate %d next-flags %.6x\n", cscPtr->flags, (cscPtr->flags & NSF_CSC_CALL_IS_NRE) != 0, (cscPtr->flags & NSF_CSC_IMMEDIATE) != 0, flags);*/ if (flags == 0) { /* * The call is NRE-enabled. We register the callback and return * here immediately. All other forms of this function have * to call NextInvokeFinalize() manually on return. */ Tcl_NRAddCallback(interp, NextInvokeFinalize, freeArgumentVector ? (ClientData)objv : NULL, cscPtr, NULL, NULL); return MethodDispatch(interp, objc, objv, cmd, object, class, methodName, frameType, flags); } else { result = MethodDispatch(interp, objc, objv, cmd, object, class, methodName, frameType, flags); } } #else /*fprintf(stderr, "NextSearchAndWinvoke calls cmd %p methodName %s cscPtr->flags %.8x\n", cmd, methodName, cscPtr->flags);*/ result = MethodDispatch(interp, objc, objv, cmd, object, class, methodName, frameType, cscPtr->flags); #endif } else if (likely(result == TCL_OK)) { NsfCallStackContent *topCscPtr; Tcl_CallFrame *varFramePtr = NULL; int isLeafNext; /* * We could not find a cmd, yet the dispatch attempt did not result * in an error. This means that we find ourselves in either of three * situations at this point: * * 1) An explicit "next" cmd (NsfNextCmd()) at the end of a filter chain: * Dispatch to unknown as there is no implementation for the requested * call available. * * 2) An explicit "next" cmd from within a leaf sub-method (a "leaf * next"): Remain silent, do not dispatch to unknown. * 3) An implicit "next" triggered for unresolved sub-methods that might be * resolved along the next path: Dispatch to unknown, the requested * sub-cmd is not resolvable to a cmd. * * For the cases 1) and 3), set the interp's unknown flag signaling to * higher levels (e.g., in MethodDispatchCsc(), in NsfNextCmd()) the need * for dispatching to unknown. */ /* NsfShowStack(interp);*/ topCscPtr = CallStackGetTopFrame(interp, &varFramePtr); assert(topCscPtr != NULL); assert(varFramePtr != NULL); /* * Find the appropriate frame pointing to the start of the ensemble, in * case we are in the middle of an ensemble. */ /*fprintf(stderr, "######## cscPtr %p topCscPtr %p\n", cscPtr, topCscPtr);*/ if ( cscPtr != topCscPtr && (cscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE) != 0u && (topCscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE) != 0u) { for (; varFramePtr != NULL; varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr)) { topCscPtr = (NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr); assert(topCscPtr != NULL); /*fprintf(stderr, "######## cscPtr %p topCscPtr %p topCscPtr->flags %8x\n", cscPtr, topCscPtr, (topCscPtr != NULL) ? topCscPtr->flags : 0);*/ if ((topCscPtr->flags & NSF_CM_ENSEMBLE_UNKNOWN) != 0u) { break; } } if (varFramePtr != NULL) { varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr); if (((unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr) & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) != 0u) { topCscPtr = (NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr); assert(topCscPtr != NULL); } } } /* case 2 */ isLeafNext = (cscPtr != topCscPtr) && (topCscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE) != 0u && (topCscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE) == 0u; /*fprintf(stderr, "******** isleavenext %d based on %d && %d && %d <%s>\n", isLeafNext, (cscPtr != topCscPtr), (topCscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE) != 0u, (topCscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE) == 0u);*/ /* * If we are in an ENSEMBLE_UNKNOWN we have to identify a special variant * of case 2: When "next" is called from an ensemble method (e.g. from a * method "i s") the call of "next" has to start over from "i" to search * for the next method (the next "i s") of the shadowed methods. If there * is none, we reach the ENSEMBLE_UNKNOWN state. But we reach the state * not immediately after the "next" call, the other checks for handling * this case fails, and we would run into the unknown handler, although * being called from "next". * * Therefore, we check in the call-stack whether we are were called inside * an ensemble setup on a path leading to an invocation of "next". * * Such a situation is e.g. (simplified stack view, then with flag names) * * varFrame flags lvl csc frameType flags * 0x7ffeeb7b1698 040001 5 0x7ffeeb7b1870 0000 8000104 (::b.0x7fa756821490 i) * 0x7fa75480eda0 020001 4 0x7fa75480ed40 0020 002100 (::b.0x7fa756821e10 s) * 0x7ffeeb7b2028 040001 3 0x7ffeeb7b2370 0000 000005 (::b.0x7fa756821c10 i) * * topcsc 0x7ffeeb7b1870 * 0x7ffeeb7b1698 flags NSF_CSC_CALL_IS_ENSEMBLE|NSF_CSC_IMMEDIATE|NSF_CM_ENSEMBLE_UNKNOWN * 0x7fa75480eda0 flags NSF_CSC_IMMEDIATE|NSF_CSC_CALL_IS_NRE frametype NSF_CSC_TYPE_ENSEMBLE * 0x7ffeeb7b2028 flags NSF_CSC_CALL_IS_NEXT|NSF_CSC_CALL_IS_ENSEMBLE * */ if (!isLeafNext && (topCscPtr->flags & NSF_CM_ENSEMBLE_UNKNOWN) != 0u) { for (;;) { varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr); if (unlikely(varFramePtr == NULL)) { break; } if (((unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr) & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) == 0) { /* * Parent frame is not an NSF frame. */ /*fprintf(stderr, "******** parent frame ptr is not an NSF frame %p\n", (void*)varFramePtr);*/ break; } topCscPtr = (NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr); if ((topCscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE) == 0u) { /* * Call stack content not of type ensemble. */ /*fprintf(stderr, "******** topCscPtr not type ensemble %p\n", (void*)topCscPtr);*/ break; } } isLeafNext = ( (topCscPtr->flags & (NSF_CSC_CALL_IS_NEXT|NSF_CSC_CALL_IS_ENSEMBLE)) == (NSF_CSC_CALL_IS_NEXT|NSF_CSC_CALL_IS_ENSEMBLE) && (topCscPtr->flags & NSF_CM_ENSEMBLE_UNKNOWN) == 0u ); /*fprintf(stderr, "******** alternate isleavenext %d based on topcscptr %p flags %.6x\n", isLeafNext, (void*)topCscPtr, (topCscPtr != NULL ? topCscPtr->flags : 0));*/ } rst->unknown = /* case 1 */ endOfFilterChain || /* case 3 */ (!isLeafNext && ((cscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE) != 0u)); /*NsfShowStack(interp);*/ /*fprintf(stderr, "******** setting unknown to %d isLeafNext %d topCscPtr %p endOfFilterChain %d\n", rst->unknown, isLeafNext, (void *)topCscPtr, endOfFilterChain);*/ } next_search_and_invoke_cleanup: /* * We come here, whenever the NRE callback is NOT registered */ {ClientData data[2] = { freeArgumentVector ? (ClientData)objv : NULL, cscPtr }; return NextInvokeFinalize(data, interp, result); } } /* *---------------------------------------------------------------------- * NsfNextObjCmd -- * * nsf::xotclnext is for backwards compatibility to the next * implementation in XOTcl. It receives an argument vector which * is used for the invocation. If no argument vector is provided, * the argument vector of the last invocation is used. If the * argument vector starts with "--noArgs", then no arguments are * passed to the shadowed method. * * TODO: On the longer range, this function should go into an external * library (e.g. XOTcl compatibility library) * * Results: * A standard Tcl result. * * Side effects: * The invoked method might produce side effects * *---------------------------------------------------------------------- */ static int NsfNextObjCmd(ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) nonnull(2) nonnull(4); static int NsfNextObjCmd(ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { int result, nobjc = 0; bool freeArgumentVector; const char *methodName = NULL; NsfCallStackContent *cscPtr; Tcl_Obj **nobjv; nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); if (likely(objc < 2)) { /* * No arguments were provided. */ objc = 0; } else { /* * In case "--noArgs" is used, remove the flag and provide an empty * argument list. */ const char *arg1String = ObjStr(objv[1]); if (*arg1String == '-' && !strcmp(arg1String, "--noArgs")) { objc = 1; } } result = NextGetArguments(interp, objc-1, &objv[1], &cscPtr, &methodName, &nobjc, &nobjv, &freeArgumentVector); if (likely(result == TCL_OK)) { assert(nobjc > 0); result = NextSearchAndInvoke(interp, methodName, nobjc, nobjv, cscPtr, freeArgumentVector); } return result; } /* *---------------------------------------------------------------------- * FindNextMethod -- * * This function is called via [current nextmethod] to resolve the * method to be invoked by [next]. If there is a next method found * on the precedence path, a method handle (Tcl_Obj) will be * returned. The caller is responsible for managing the resulting * Tcl_Obj, if any. * * Results: * A Tcl_Obj; The result is NULL when no next method or called from * outside of NSF. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj *FindNextMethod(Tcl_Interp *interp, Tcl_CallFrame *framePtr) nonnull(1) nonnull(2); static Tcl_Obj * FindNextMethod(Tcl_Interp *interp, Tcl_CallFrame *framePtr) { Tcl_Obj *result; NsfCallStackContent *cscPtr; nonnull_assert(interp != NULL); nonnull_assert(framePtr != NULL); cscPtr = Tcl_CallFrame_clientData(framePtr); if (unlikely(cscPtr == NULL)) { result = NULL; } else { bool isEnsemble, isMixinEntry = NSF_FALSE, isFilterEntry = NSF_FALSE, endOfFilterChain = NSF_FALSE; Tcl_Command cmd = NULL, currentCmd = NULL; const char *lookupMethodName, *methodName; NsfClass *class; NsfObject *object; isEnsemble = ((cscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE) != 0u); methodName = Tcl_GetCommandName(interp, cscPtr->cmdPtr); if (isEnsemble) { NsfCallStackContent *cscPtr1 = CallStackFindEnsembleCsc(framePtr, &framePtr); lookupMethodName = MethodName(cscPtr1->objv[0]); } else { lookupMethodName = methodName; } class = cscPtr->cl; object = cscPtr->self; if (NextSearchMethod(object, interp, cscPtr, &class, &lookupMethodName, &cmd, &isMixinEntry, &isFilterEntry, &endOfFilterChain, ¤tCmd) == TCL_OK && cmd != NULL) { Tcl_Obj *pathObj = NsfMethodNamePath(interp, framePtr, methodName); INCR_REF_COUNT(pathObj); methodName = isEnsemble ? ObjStr(pathObj) : lookupMethodName; result = MethodHandleObj((class != NULL) ? (NsfObject *)class : object, (class == NULL), methodName); DECR_REF_COUNT(pathObj); } else { result = NULL; } } return result; } /* *---------------------------------------------------------------------- * ComputeLevelObj -- * * This function computes a fresh Tcl_Obj referring to the interp level. The * caller has to care about freeing the returned Tcl_Obj. * * Results: * Tcl_Obj * * * Side effects: * Allocates a new Tcl_Obj * *---------------------------------------------------------------------- */ static Tcl_Obj * ComputeLevelObj(Tcl_Interp *interp, CallStackLevel level) nonnull(1) returns_nonnull; static Tcl_Obj * ComputeLevelObj(Tcl_Interp *interp, CallStackLevel level) { Tcl_CallFrame *framePtr = NULL; Tcl_Obj *resultObj; nonnull_assert(interp != NULL); switch (level) { case CALLING_LEVEL: { Tcl_CallFrame *callingFramePtr = NULL; /* * NsfCallStackFindCallingContext() sets always the framePtr, but * initialize framePtr explicitly to silence static checkers, since * ComputeLevelObj() is not performance critical. */ framePtr = NULL; NsfCallStackFindCallingContext(interp, 1, &framePtr, &callingFramePtr); if (framePtr == NULL) { framePtr = callingFramePtr; } break; } case ACTIVE_LEVEL: NsfCallStackFindActiveFrame(interp, 1, &framePtr); break; } if (framePtr != NULL) { /* * The call was from an NSF frame, return absolute frame number. */ char buffer[LONG_AS_STRING]; int l; buffer[0] = '#'; Nsf_ltoa(buffer+1, (long)Tcl_CallFrame_level(framePtr), &l); resultObj = Tcl_NewStringObj(buffer, (TCL_SIZE_T)l+1); } else { /* * If not called from an NSF frame, return #0 as default. * * TODO: With NsfCallStackFindCallingContext in place, this cannot (should * not) be reachable. Need to check NsfCallStackFindActiveFrame. When in * the "clear", provide for a warning here? * */ resultObj = Tcl_NewStringObj("#0", 2); } return resultObj; } /* int NsfKObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { if (objc < 2) { return NsfPrintError(interp, "wrong # of args for K"); } Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } */ /* * object creation & destruction */ /* *---------------------------------------------------------------------- * UnsetInAllNamespaces -- * * Try to unset a variable, searching for the variable in all * name-spaces. This function is used by volatile to unset the automatic * variable used for the destroy trace. * * Results: * A standard Tcl result. * * Side effects: * Might unset variable * *---------------------------------------------------------------------- */ static int UnsetInAllNamespaces( Tcl_Interp *interp, const Tcl_Namespace *nsPtr, const char *name ) nonnull(1) nonnull(2) nonnull(3); static int UnsetInAllNamespaces( Tcl_Interp *interp, const Tcl_Namespace *nsPtr, const char *name ) { int rc = 0; Tcl_HashSearch search; Tcl_HashEntry *entryPtr; const Tcl_Var *varPtr; nonnull_assert(interp != NULL); nonnull_assert(nsPtr != NULL); nonnull_assert(name != NULL); /*fprintf(stderr, "### UnsetInAllNamespaces variable '%s', current namespace '%s'\n", name, (nsPtr != NULL) ? nsPtr->fullName : "NULL");*/ entryPtr = Tcl_FirstHashEntry(Tcl_Namespace_childTablePtr(nsPtr), &search); varPtr = (Tcl_Var *) Tcl_FindNamespaceVar(interp, name, (Tcl_Namespace *)nsPtr, 0); /*fprintf(stderr, "found %s in %s -> %p\n", name, nsPtr->fullName, varPtr);*/ if (varPtr != NULL) { Tcl_DString dFullname, *dsPtr = &dFullname; int result; Tcl_DStringInit(dsPtr); Tcl_DStringAppend(dsPtr, "unset ", TCL_INDEX_NONE); DStringAppendQualName(dsPtr, nsPtr, name); result = Tcl_Eval(interp, Tcl_DStringValue(dsPtr)); /* fprintf(stderr, "fqName = '%s' unset => %d %d\n", Tcl_DStringValue(dsPtr), rc, TCL_OK);*/ if (likely(result == TCL_OK)) { rc = 1; } else { Tcl_Obj *resultObj = Tcl_GetObjResult(interp); fprintf(stderr, " err = '%s'\n", ObjStr(resultObj)); } Tcl_DStringFree(dsPtr); } while ((rc == 0) && (entryPtr != NULL)) { Tcl_Namespace *childNsPtr = (Tcl_Namespace *) Tcl_GetHashValue(entryPtr); /*fprintf(stderr, "child = %s\n", childNsPtr->fullName);*/ entryPtr = Tcl_NextHashEntry(&search); rc |= UnsetInAllNamespaces(interp, childNsPtr, name); } return rc; } /* *---------------------------------------------------------------------- * FreeUnsetTraceVariable -- * * Unset trace variable. * * Results: * A standard Tcl result. * * Side effects: * Might unset variable * *---------------------------------------------------------------------- */ static int FreeUnsetTraceVariable(Tcl_Interp *interp, const NsfObject *object) nonnull(1) nonnull(2); static int FreeUnsetTraceVariable(Tcl_Interp *interp, const NsfObject *object) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); if (object->opt != NULL && (object->opt->volatileVarName != NULL)) { int result = Tcl_UnsetVar2(interp, object->opt->volatileVarName, NULL, 0); /* * Somebody destroys a volatile object manually while the var-trace is * still active. Destroying the object will be a problem in case the * variable is deleted later and fires the trace. So, we unset the * variable here which will cause a destroy via var-trace, which in turn * clears the volatileVarName flag. */ /* fprintf(stderr, "### FreeUnsetTraceVariable %s\n", object->opt->volatileVarName);*/ if (unlikely(result != TCL_OK)) { result = Tcl_UnsetVar2(interp, object->opt->volatileVarName, NULL, TCL_GLOBAL_ONLY); if (unlikely(result != TCL_OK)) { Tcl_Namespace *nsPtr = Tcl_GetCurrentNamespace(interp); if (UnsetInAllNamespaces(interp, nsPtr, object->opt->volatileVarName) == 0) { fprintf(stderr, "### don't know how to delete variable '%s' of volatile object\n", object->opt->volatileVarName); /* * Return always success, since an error during destroy does not * help at all */ } } } /*fprintf(stderr, "### FreeUnsetTraceVariable returns %d OK %d\n", result, TCL_OK);*/ } return TCL_OK; } /* *---------------------------------------------------------------------- * NsfUnsetTrace -- * * Function to be triggered whenever the trigger variable is * deleted. Typically, this function deletes the associated object. * * Results: * Result msg or null. * * Side effects: * Might delete associated object. * *---------------------------------------------------------------------- */ static const char *NsfUnsetTrace( ClientData clientData, Tcl_Interp *interp, const char *UNUSED(name), const char *UNUSED(name2), unsigned int UNUSED(flags) ) nonnull(1) nonnull(2); static const char * NsfUnsetTrace( ClientData clientData, Tcl_Interp *interp, const char *UNUSED(name), const char *UNUSED(name2), unsigned int UNUSED(flags) ) { Tcl_Obj *objPtr = (Tcl_Obj *)clientData; NsfObject *object; const char *resultMsg = NULL; nonnull_assert(clientData != NULL); nonnull_assert(interp != NULL); /*fprintf(stderr, "NsfUnsetTrace %s flags %.4x deleted %d\n", name, flags, Tcl_InterpDeleted(interp));*/ if (Tcl_InterpDeleted(interp) == 0) { if (GetObjectFromObj(interp, objPtr, &object) == TCL_OK) { Tcl_Obj *savedResultObj = Tcl_GetObjResult(interp); /* save the result */ INCR_REF_COUNT(savedResultObj); /* * Clear variable, destroy is called from trace. */ if (object->opt != NULL && object->opt->volatileVarName) { object->opt->volatileVarName = NULL; } if (DispatchDestroyMethod(interp, object, 0u) != TCL_OK) { resultMsg = "Destroy for volatile object failed"; } else { resultMsg = "No NSF Object passed"; } Tcl_SetObjResult(interp, savedResultObj); /* restore the result */ DECR_REF_COUNT(savedResultObj); } } else { /* fprintf(stderr, "omitting destroy\n"); */ } DECR_REF_COUNT2("volatile", objPtr); return resultMsg; } /* *---------------------------------------------------------------------- * CleanupDestroyObject -- * * Perform cleanup of object; after the function is executed, the object is * in the same fresh state as after initialization. * * Results: * None. * * Side effects: * Possibly freeing memory. * *---------------------------------------------------------------------- */ static void CleanupDestroyObject(Tcl_Interp *interp, NsfObject *object, bool softrecreate) nonnull(1) nonnull(2); static void CleanupDestroyObject(Tcl_Interp *interp, NsfObject *object, bool softrecreate) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); /*fprintf(stderr, "CleanupDestroyObject obj %p softrecreate %d nsPtr %p\n", object, softrecreate, object->nsPtr);*/ /* * The object pointer is guaranteed to point to the same object, so it is * not sufficient for methodObj validation. Therefore, for objects * containing per-object methods, we increment the objectMethodEpoch. */ if (object->nsPtr != NULL) { NsfObjectMethodEpochIncr("CleanupDestroyObject"); } /* * Remove the instance, but not for ::Class/::Object */ if (!IsBaseClass(object)) { if (!softrecreate) { RemoveInstance(object, object->cl); } } /* * Unset object variables with unset traces preemptively. */ UnsetTracedVars(interp, object); if (object->nsPtr != NULL) { NSCleanupNamespace(interp, object->nsPtr); NSDeleteChildren(interp, object->nsPtr); } if (object->varTablePtr != NULL) { /* * Any unset-traced variable has been deleted before (UnsetTracedVars). */ TclDeleteVars(((Interp *)interp), object->varTablePtr); ckfree((char *)object->varTablePtr); /*FREE(obj->varTablePtr, obj->varTablePtr);*/ object->varTablePtr = 0; } if (object->opt != NULL) { NsfObjectOpt *opt = object->opt; #if defined(NSF_WITH_ASSERTIONS) if (opt->assertions != NULL) { AssertionRemoveStore(opt->assertions); opt->assertions = NULL; } #endif #if defined(PER_OBJECT_PARAMETER_CACHING) if (object->opt->parsedParamPtr != NULL) { NsfParameterCacheObjectInvalidateCmd(interp, object); } #endif if (!softrecreate) { /* * Remove this object from all per object mixin lists and clear the * mixin list. */ if (opt->objMixins != NULL) { RemoveFromObjectMixinsOf(object->id, opt->objMixins); } CmdListFree(&opt->objMixins, GuardDel); CmdListFree(&opt->objFilters, GuardDel); FREE(NsfObjectOpt, opt); object->opt = NULL; } } object->flags &= ~NSF_MIXIN_ORDER_VALID; if (object->mixinOrder != NULL) { MixinResetOrder(object); } object->flags &= ~NSF_FILTER_ORDER_VALID; if (object->filterOrder != NULL) { FilterResetOrder(object); } } /* * obj initialization & namespace creation */ /* *---------------------------------------------------------------------- * CleanupInitObject -- * * Perform the initialization of an object in a virgin state. * During bootstrap, cl might be NULL. * * Results: * None. * * Side effects: * Updating the object structure * *---------------------------------------------------------------------- */ static void CleanupInitObject( Tcl_Interp *interp, NsfObject *object, NsfClass *class, Tcl_Namespace *nsPtr, bool softrecreate ) nonnull(1) nonnull(2); static void CleanupInitObject( Tcl_Interp *interp, NsfObject *object, NsfClass *class, Tcl_Namespace *nsPtr, bool softrecreate ) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); #ifdef OBJDELETION_TRACE fprintf(stderr, "+++ CleanupInitObject\n"); #endif object->teardown = interp; object->nsPtr = nsPtr; if (!softrecreate && class != NULL) { AddInstance(object, class); } if ((object->flags & NSF_RECREATE) != 0u) { object->opt = NULL; object->varTablePtr = NULL; object->mixinOrder = NULL; object->filterOrder = NULL; object->flags = 0; } /* fprintf(stderr, "cleanupInitObject %s: %p cl = %p\n", (obj->cmdName != NULL) ? ObjectName(object) : "", object, object->cl);*/ } /* *---------------------------------------------------------------------- * PrimitiveDestroy -- * * Dispatch either PrimitiveCDestroy or PrimitiveODestroy * depending on whether the object is a class * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void PrimitiveDestroy(ClientData clientData) { nonnull_assert(clientData != NULL); if (NsfObjectIsClass((NsfObject *)clientData)) { PrimitiveCDestroy(clientData); } else { PrimitiveODestroy(clientData); } } /* *---------------------------------------------------------------------- * TclDeletesObject -- * * Function to be called, when Tcl deletes the command which has an * object/class associated. This happens, when e.g. a namespace is deleted. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void TclDeletesObject(ClientData clientData) nonnull(1); static void TclDeletesObject(ClientData clientData) { NsfObject *object; nonnull_assert(clientData != NULL); object = (NsfObject *)clientData; /* * TODO: Actually, it seems like a good idea to flag a deletion from Tcl by * setting object->id to NULL. However, we seem to have some dependencies * avoiding this currently, so we use the flag. */ object->flags |= NSF_TCL_DELETE; /*fprintf(stderr, "cmd dealloc %p TclDeletesObject (%d)\n", object->id, Tcl_Command_refCount(object->id));*/ #ifdef OBJDELETION_TRACE fprintf(stderr, "TclDeletesObject %p obj->id %p flags %.6x\n", (void *)object, (void *)object->id, object->flags); #endif if (unlikely((object->flags & NSF_DURING_DELETE) == 0u) && (object->teardown != NULL) ) { # ifdef OBJDELETION_TRACE fprintf(stderr, "... %p %s\n", (void *)object, ObjectName(object)); # endif CallStackDestroyObject(object->teardown, object); } } /* *---------------------------------------------------------------------- * PrimitiveODestroy -- * * Delete an object with its namespace and associated data structures * (mixin stack, filter stack). The physical deallocation is handled by * NsfCleanupObject() which performs reference counting. * * Results: * None. * * Side effects: * Free object contents. * *---------------------------------------------------------------------- */ static void PrimitiveODestroy(ClientData clientData) { NsfObject *object; Tcl_Interp *interp; nonnull_assert(clientData != NULL); object = (NsfObject *)clientData; assert(object->teardown != NULL); /*fprintf(stderr, "****** PrimitiveODestroy %p cmd %p flags %.6x\n", (void *)object, (void *)object->id, object->flags);*/ /* * We assume, the object was not yet deleted, but destroy was called * already. */ assert((object->flags & NSF_DELETED) == 0u); assert((object->flags & NSF_DESTROY_CALLED) != 0u); /* * Check and latch against recurrent calls with object->teardown. */ PRINTOBJ("PrimitiveODestroy", object); interp = object->teardown; /* * Don't destroy, if the interpreter is destroyed already * e.g. TK calls Tcl_DeleteInterp directly, if the window is killed */ if (!Tcl_InterpDeleted(interp)) { #ifdef OBJDELETION_TRACE {Command *cmdPtr = (Command*)object->id; fprintf(stderr, " physical delete of %p id=%p (cmd->refCount %d) destroyCalled=%d '%s'\n", (void *)object, (void *)object->id, cmdPtr->refCount, (object->flags & NSF_DESTROY_CALLED), ObjectName(object)); } #endif CleanupDestroyObject(interp, object, NSF_FALSE); while (object->mixinStack != NULL) { MixinStackPop(object); } while (object->filterStack != NULL) { FilterStackPop(object); } /* * Object is now mostly dead, but still allocated. However, since * Nsf_DeleteNamespace might delegate to the parent (e.g. slots) we clear * teardown after the deletion of the children. */ if (object->nsPtr != NULL) { /*fprintf(stderr, "PrimitiveODestroy calls deleteNamespace for object %p nsPtr %p\n", (void*)object, object->nsPtr);*/ Nsf_DeleteNamespace(interp, object->nsPtr); object->nsPtr = NULL; } object->teardown = NULL; /*fprintf(stderr, " +++ OBJ/CLS free: %p %s\n", (void *)object, ObjectName(object));*/ object->flags |= NSF_DELETED; ObjTrace("ODestroy", object); DECR_REF_COUNT(object->cmdName); NsfCleanupObject(object, "PrimitiveODestroy"); } } /* *---------------------------------------------------------------------- * DoDealloc -- * * Perform deallocation of an object/class. This function is called * from the dealloc method and internally to get rid of an * abject. It cares about volatile and frees/triggers free * operation depending on the stack references. * * Results: * A standard Tcl result. * * Side effects: * freed object or object is marked to be freed. * *---------------------------------------------------------------------- */ static int DoDealloc(Tcl_Interp *interp, NsfObject *object) nonnull(1) nonnull(2); static int DoDealloc(Tcl_Interp *interp, NsfObject *object) { int result; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); /*fprintf(stderr, "DoDealloc obj= %s %p flags %.6x activation %d cmd %p opt=%p\n", ObjectName(object), object, object->flags, object->activationCount, object->id, object->opt);*/ result = FreeUnsetTraceVariable(interp, object); if (unlikely(result == TCL_OK)) { /* * Latch, and call delete command if not already in progress. */ if (RUNTIME_STATE(interp)->exitHandlerDestroyRound != NSF_EXITHANDLER_ON_SOFT_DESTROY) { CallStackDestroyObject(interp, object); } } return result; } /* *---------------------------------------------------------------------- * MarkUndestroyed -- * * Mark an object as if destroy was not called. This function is e.g. used * from recreate. * * Results: * None. * * Side effects: * Setting object flag. * *---------------------------------------------------------------------- */ static void MarkUndestroyed(NsfObject *object) nonnull(1); static void MarkUndestroyed(NsfObject *object) { nonnull_assert(object != NULL); object->flags &= ~NSF_DESTROY_CALLED; } /* *---------------------------------------------------------------------- * PrimitiveOInit -- * * Set/reset the object to a fresh, un-destroyed state * * Results: * A standard Tcl result. * * Side effects: * initializing object structure * *---------------------------------------------------------------------- */ static void PrimitiveOInit(NsfObject *object, Tcl_Interp *interp, const char *name, Tcl_Namespace *nsPtr, NsfClass *class) nonnull(1) nonnull(2) nonnull(3); static void PrimitiveOInit(NsfObject *object, Tcl_Interp *interp, const char *name, Tcl_Namespace *nsPtr, NsfClass *class) { nonnull_assert(object != NULL); nonnull_assert(interp != NULL); nonnull_assert(name != NULL); #ifdef OBJDELETION_TRACE fprintf(stderr, "+++ PrimitiveOInit\n"); #endif #ifdef NSFOBJ_TRACE fprintf(stderr, "OINIT %s = %p\n", name, (void *)object); #endif NsfObjectRefCountIncr(object); MarkUndestroyed(object); /* * There might be already a namespace with the provided name; if this is the * case, use this namespace as object namespace. The preexisting namespace * might contain Next Scripting objects. If we would not use the namespace * as child namespace, we would not recognize the objects as child objects, * deletions of the object might lead to a crash. * * We can use here the provided nsPtr, except in cases, where this * namespaces is being destroyed (e.g. recreate a new object from a * different object system). */ if (nsPtr != NULL && (((Namespace *)nsPtr)->flags & NS_DYING) != 0u) { Namespace *dummy1Ptr, *dummy2Ptr, *nsPtr1 = (Namespace *)nsPtr; const char *dummy; TclGetNamespaceForQualName(interp, name, NULL, TCL_GLOBAL_ONLY|TCL_FIND_ONLY_NS, &nsPtr1, &dummy1Ptr, &dummy2Ptr, &dummy); nsPtr = (Tcl_Namespace *)nsPtr1; /*fprintf(stderr, "PrimitiveOInit %p calls TclGetNamespaceForQualName with %s => %p given %p object->nsPtr %p\n", object, name, nsPtr, nsPtr, object->nsPtr);*/ } if (nsPtr != NULL) { NsfNamespaceInit(nsPtr); } /* fprintf(stderr, "PrimitiveOInit %p %s, ns %p\n", object, name, nsPtr); */ CleanupInitObject(interp, object, class, nsPtr, NSF_FALSE); /* * TODO: would be nice, if we could init object flags. */ /* object->flags = NSF_MIXIN_ORDER_VALID | NSF_FILTER_ORDER_VALID;*/ object->mixinStack = NULL; object->filterStack = NULL; } /* *---------------------------------------------------------------------- * PrimitiveOCreate -- * * Allocate memory for an object, create the object name and the associated * Tcl command and call the initialization functions. * * Results: * NsfObject* * * Side effects: * Allocating memory * *---------------------------------------------------------------------- */ static NsfObject * PrimitiveOCreate(Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_Namespace *parentNsPtr, NsfClass *class) nonnull(1) nonnull(2) nonnull(4) returns_nonnull; static NsfObject * PrimitiveOCreate(Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_Namespace *parentNsPtr, NsfClass *class) { const char *nameString; Tcl_Namespace *nsPtr; NsfObject *object; nonnull_assert(interp != NULL); nonnull_assert(nameObj != NULL); nonnull_assert(class != NULL); object = (NsfObject *)ckalloc((int)sizeof(NsfObject)); MEM_COUNT_ALLOC("NsfObject/NsfClass", object); assert(object != NULL); /* ckalloc panics, if malloc fails */ memset(object, 0, sizeof(NsfObject)); nameString = ObjStr(nameObj); assert(isAbsolutePath(nameString)); #if defined(NSFOBJ_TRACE) fprintf(stderr, "CKALLOC Object %p %s\n", (void *)object, nameString); #endif #ifdef OBJDELETION_TRACE fprintf(stderr, "+++ PrimitiveOCreate\n"); #endif nsPtr = NSCheckNamespace(interp, nameString, parentNsPtr); if (nsPtr != NULL) { NSNamespacePreserve(nsPtr); } #if defined(NRE) object->id = Tcl_NRCreateCommand(interp, nameString, NsfObjDispatch, NsfObjDispatchNRE, object, TclDeletesObject); #else object->id = Tcl_CreateObjCommand(interp, nameString, NsfObjDispatch, object, TclDeletesObject); #endif /*fprintf(stderr, "cmd alloc %p %d (%s)\n", object->id, Tcl_Command_refCount(object->id), nameString);*/ PrimitiveOInit(object, interp, nameString, nsPtr, class); if (nsPtr != NULL) { NSNamespaceRelease(nsPtr); } object->cmdName = nameObj; INCR_REF_COUNT(object->cmdName); ObjTrace("PrimitiveOCreate", object); return object; } /* *---------------------------------------------------------------------- * DefaultSuperClass -- * * Determine the default superclass of the class (specified as * second argument) and metaclass (third argument). The function * searches for the variable NSF_DEFAULTMETACLASS or * NSF_DEFAULTSUPERCLASS and uses it if present. * * Results: * Default superclass or NULL * * Side effects: * None. * *---------------------------------------------------------------------- */ static NsfClass * DefaultSuperClass(Tcl_Interp *interp, const NsfClass *class, const NsfClass *metaClass, bool isMeta) { NsfClass *resultClass = NULL; Tcl_Obj *resultObj; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(metaClass != NULL); /*fprintf(stderr, "DefaultSuperClass cl %s, mcl %s, isMeta %d\n", ClassName(class), ClassName(metaClass), isMeta );*/ resultObj = Nsf_ObjGetVar2((Nsf_Object *)metaClass, interp, (isMeta != 0) ? NsfGlobalObjs[NSF_DEFAULTMETACLASS] : NsfGlobalObjs[NSF_DEFAULTSUPERCLASS], NULL, 0); if (resultObj != NULL) { if (unlikely(GetClassFromObj(interp, resultObj, &resultClass, NSF_FALSE) != TCL_OK)) { NsfPrintError(interp, "default superclass is not a class"); } /*fprintf(stderr, "DefaultSuperClass for %s got from var %s => %s\n", ClassName(class), ObjStr((isMeta != 0) ? NsfGlobalObjs[NSF_DEFAULTMETACLASS] : NsfGlobalObjs[NSF_DEFAULTSUPERCLASS]), ClassName(resultClass));*/ } else { const NsfClasses *sc; /*fprintf(stderr, "DefaultSuperClass for %s: search in superClasses starting with %p meta %d\n", ClassName(class), cl->super, isMeta);*/ if (isMeta != 0) { /* * Is this already the root metaclass ? */ if (IsRootMetaClass(metaClass->object.cl)) { return metaClass->object.cl; } } /* * Check superClasses of metaclass */ for (sc = metaClass->super; sc && sc->cl != class; sc = sc->nextPtr) { /* fprintf(stderr, " ... check ismeta %d %s root mcl %d root cl %d\n", isMeta, ClassName(sc->cl), sc->cl->object.flags & NSF_IS_ROOT_META_CLASS, sc->cl->object.flags & NSF_IS_ROOT_CLASS); */ if (isMeta != 0) { if (IsRootMetaClass(sc->cl)) { return sc->cl; } } else { if (IsRootClass(sc->cl)) { /* fprintf(stderr, "found root-class %p %s\n", sc->cl, ClassName(sc->cl)); */ return sc->cl; } } resultClass = DefaultSuperClass(interp, class, sc->cl, isMeta); if (resultClass != NULL) { break; } } } return resultClass; } /* *---------------------------------------------------------------------- * CleanupDestroyClass -- * * Cleanup class in a destroy call. Remove filters, mixins, assertions, * instances and remove finally class from class hierarchy. In the recreate * case, it preserves the pointers from other class structures. * * Results: * None. * * Side effects: * Updated class structures. * *---------------------------------------------------------------------- */ static void CleanupDestroyClass(Tcl_Interp *interp, NsfClass *class, bool softrecreate, bool recreate) nonnull(1) nonnull(2); static void CleanupDestroyClass(Tcl_Interp *interp, NsfClass *class, bool softrecreate, bool recreate) { NsfClassOpt *clopt; NsfClass *baseClass = NULL; NsfClasses *subClasses; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); PRINTOBJ("CleanupDestroyClass", (NsfObject *)class); assert(softrecreate ? recreate : NSF_TRUE); clopt = class->opt; /*fprintf(stderr, "CleanupDestroyClass %p %s (ismeta=%d) softrecreate=%d, recreate=%d, %p\n", class, ClassName(class), IsMetaClass(interp, cl, NSF_TRUE), softrecreate, recreate, clopt);*/ subClasses = DependentSubClasses(class); if (subClasses != NULL) { /* * Perform the next steps even with clopt == NULL, since the class * might be used as a superclass of a per object mixin, so it might * have no clopt... */ MixinInvalidateObjOrders(subClasses); if (FiltersDefined(interp) > 0) { FilterInvalidateObjOrders(interp, subClasses); } } if (clopt != NULL) { /* * Remove this class from all isClassMixinOf lists and clear the * class mixin list */ if (clopt->classMixins != NULL) { RemoveFromClassMixinsOf(clopt->id, clopt->classMixins); } CmdListFree(&clopt->classMixins, GuardDel); CmdListFree(&clopt->classFilters, GuardDel); if (clopt->mixinRegObjs != NULL) { NsfMixinregInvalidate(interp, clopt->mixinRegObjs); DECR_REF_COUNT2("mixinRegObjs", clopt->mixinRegObjs); clopt->mixinRegObjs = NULL; } if (!recreate) { /* * Remove this class from all mixin lists and clear the isObjectMixinOf list */ if (clopt->isObjectMixinOf != 0) { RemoveFromObjectMixins(clopt->id, clopt->isObjectMixinOf); } CmdListFree(&clopt->isObjectMixinOf, GuardDel); /* * Remove this class from all class mixin lists and clear the * isClassMixinOf list */ if (clopt->isClassMixinOf != 0) { RemoveFromClassmixins(clopt->id, clopt->isClassMixinOf); } CmdListFree(&clopt->isClassMixinOf, GuardDel); } /* * Remove dependent filters of this class from all subclasses */ if (subClasses != NULL) { FilterRemoveDependentFilterCmds(class, subClasses); } #if defined(NSF_WITH_ASSERTIONS) if (clopt->assertions != NULL) { AssertionRemoveStore(clopt->assertions); clopt->assertions = NULL; } #endif #ifdef NSF_OBJECTDATA NsfFreeObjectData(class); #endif } NSCleanupNamespace(interp, class->nsPtr); NSDeleteChildren(interp, class->nsPtr); if (!softrecreate) { /* * Reclass all instances of the current class to the appropriate * most general class ("baseClass"). The most general class of a * metaclass is the root metaclass, the most general class of an * object is the root-class. Instances of metaclasses can be only * reset to the root metaclass (and not to the root base * class). */ baseClass = DefaultSuperClass(interp, class, class->object.cl, IsMetaClass(interp, class, NSF_TRUE)); /* * We do not have to reclassing in case, cl is a root-class */ if (!IsRootClass(class)) { Tcl_HashTable *instanceTablePtr = &class->instances; Tcl_HashSearch hSrch; const Tcl_HashEntry *hPtr; for (hPtr = Tcl_FirstHashEntry(instanceTablePtr, &hSrch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { NsfObject *inst = (NsfObject *)Tcl_GetHashKey(instanceTablePtr, hPtr); /*fprintf(stderr, " inst %p %s flags %.6x id %p baseClass %p %s\n", inst, ObjectName(inst), inst->flags, inst->id, baseClass, ClassName(baseClass));*/ if ((inst != NULL) && (inst != (NsfObject *)class) && likely((inst->flags & NSF_DURING_DELETE) == 0u) /*inst->id*/ ) { if (inst != &(baseClass->object)) { AddInstance(inst, baseClass); } } } } Tcl_DeleteHashTable(&class->instances); MEM_COUNT_FREE("Tcl_InitHashTable", &class->instances); } if (clopt != NULL && !recreate) { FREE(NsfClassOpt, clopt); class->opt = NULL; } if (subClasses != NULL) { /* * On a recreate, it might be possible that the newly created class * has a different superclass. So we have to flush the precedence * list on a recreate as well. */ FlushPrecedences(subClasses); NsfClassListFree(subClasses); } while (class->super != NULL) { (void)RemoveSuper(class, class->super->cl); } if (!softrecreate) { /* * Flush all caches, unlink superClasses. */ while (class->sub != NULL) { NsfClass *subClass = class->sub->cl; (void)RemoveSuper(subClass, class); /* * If there are no more superclasses add the Object * class as superClasses * -> don't do that for Object itself! */ if (subClass->super == NULL && !IsRootClass(class)) { /* fprintf(stderr, "subClass %p %s baseClass %p %s\n", class, ClassName(class), baseClass, ClassName(baseClass)); */ AddSuper(subClass, baseClass); } } } } /* *---------------------------------------------------------------------- * CleanupInitClass -- * * Basic initialization of a class, setting namespace, super- and * subclasses, and setup optionally instances table. * * Results: * None. * * Side effects: * Makes a class structure usable. * *---------------------------------------------------------------------- */ static void CleanupInitClass( Tcl_Interp *interp, NsfClass *class, Tcl_Namespace *nsPtr, bool softrecreate, bool recreate ) nonnull(1) nonnull(2) nonnull(3); static void CleanupInitClass( Tcl_Interp *interp, NsfClass *class, Tcl_Namespace *nsPtr, bool softrecreate, bool recreate ) { NsfClass *defaultSuperclass; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(nsPtr != NULL); assert((softrecreate) ? recreate : NSF_TRUE); #ifdef OBJDELETION_TRACE fprintf(stderr, "+++ CleanupInitClass\n"); #endif /* * Record, that cl is a class and set its namespace */ NsfObjectSetClass((NsfObject *)class); class->nsPtr = nsPtr; if (!softrecreate) { /* * Subclasses are preserved during recreate, superClasses not (since the * creation statement defined the superclass, might be different the * second time). */ class->sub = NULL; } class->super = NULL; /* * We can the default superclass from the metaclass, if this exists. */ if (class->object.cl != NULL) { /* * Look for a configured default superclass. */ defaultSuperclass = DefaultSuperClass(interp, class, class->object.cl, NSF_FALSE); } else { defaultSuperclass = NULL; } if (class != defaultSuperclass) { AddSuper(class, defaultSuperclass); } class->color = WHITE; class->order = NULL; if (!softrecreate) { Tcl_InitHashTable(&class->instances, TCL_ONE_WORD_KEYS); MEM_COUNT_ALLOC("Tcl_InitHashTable", &class->instances); } if (!recreate) { class->opt = NULL; } } /* *---------------------------------------------------------------------- * PrimitiveCDestroy -- * * Delete a class with its namespace and associated data structures. The * physical deallocation is handled by PrimitiveODestroy(). * * Results: * None. * * Side effects: * Free object contents. * *---------------------------------------------------------------------- */ static void PrimitiveCDestroy(ClientData clientData) { NsfClass *class; nonnull_assert(clientData != NULL); class = (NsfClass *)clientData; PRINTOBJ("PrimitiveCDestroy", &class->object); /* * Check and latch against recurrent calls with obj->teardown */ if (class != NULL && class->object.teardown != NULL) { Tcl_Interp *interp; interp = class->object.teardown; /* * Don't destroy, if the interpreted is destroyed already * e.g. TK calls Tcl_DeleteInterp directly, if Window is killed */ if (!Tcl_InterpDeleted(interp)) { Tcl_Namespace *saved; /* * Call and latch user destroy with object->id if we haven't */ /*fprintf(stderr, "PrimitiveCDestroy %s flags %.6x\n", ObjectName(object), object->flags);*/ class->object.teardown = NULL; CleanupDestroyClass(interp, class, NSF_FALSE, NSF_FALSE); /* * handoff the primitive teardown */ saved = class->nsPtr; class->object.teardown = interp; /* * class object destroy + physical destroy */ PrimitiveODestroy(clientData); /*fprintf(stderr, "primitive cdestroy calls delete namespace for obj %p, nsPtr %p flags %.6x\n", cl, saved, ((Namespace *)saved)->flags);*/ Nsf_DeleteNamespace(interp, saved); /*fprintf(stderr, "primitive cdestroy %p DONE\n", class);*/ } } return; } /* *---------------------------------------------------------------------- * PrimitiveCInit -- * * Set/reset a class to a fresh, un-destroyed state * * Results: * A standard Tcl result. * * Side effects: * initializing object structure * *---------------------------------------------------------------------- */ static void PrimitiveCInit(NsfClass *class, Tcl_Interp *interp, const char *name) nonnull(1) nonnull(2) nonnull(3); static void PrimitiveCInit(NsfClass *class, Tcl_Interp *interp, const char *name) { Tcl_CallFrame frame, *framePtr = &frame; nonnull_assert(class != NULL); nonnull_assert(interp != NULL); nonnull_assert(name != NULL); /* * Ensure that namespace is newly created during CleanupInitClass. Kill it, * if it exists already */ if (Tcl_PushCallFrame(interp, (Tcl_CallFrame *)framePtr, RUNTIME_STATE(interp)->NsfClassesNS, 0) == TCL_OK) { Tcl_Namespace *nsPtr; nsPtr = NSGetFreshNamespace(interp, &class->object, name); Tcl_PopCallFrame(interp); CleanupInitClass(interp, class, nsPtr, NSF_FALSE, NSF_FALSE); } return; } /* *---------------------------------------------------------------------- * PrimitiveCCreate -- * * Allocate memory for a class, initialize the class specific data * structure (e.g. class namespace) and call PrimitiveOCreate() for the * object specific initialization. * * Results: * NsfClass* * * Side effects: * Allocating memory * *---------------------------------------------------------------------- */ static NsfClass *PrimitiveCCreate( Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_Namespace *parentNsPtr, NsfClass *metaClass ) nonnull(1) nonnull(2) returns_nonnull; static NsfClass * PrimitiveCCreate( Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_Namespace *parentNsPtr, NsfClass *metaClass ) { Tcl_Namespace *nsPtr; const char *nameString; NsfObject *object; NsfClass *class; nonnull_assert(interp != NULL); nonnull_assert(nameObj != NULL); class = (NsfClass *)ckalloc((int)sizeof(NsfClass)); nameString = ObjStr(nameObj); object = (NsfObject *)class; #if defined(NSFOBJ_TRACE) fprintf(stderr, "CKALLOC Class %p %s\n", (void *)class, nameString); #endif memset(class, 0, sizeof(NsfClass)); MEM_COUNT_ALLOC("NsfObject/NsfClass", class); /* * Pass object system from metaclass. */ if (metaClass != NULL) { class->osPtr = metaClass->osPtr; } assert(isAbsolutePath(nameString)); /* fprintf(stderr, "Class alloc %p '%s'\n", cl, nameString); */ nsPtr = NSCheckNamespace(interp, nameString, parentNsPtr); if (nsPtr != NULL) { NSNamespacePreserve(nsPtr); } #if defined(NRE) object->id = Tcl_NRCreateCommand(interp, nameString, NsfObjDispatch, NsfObjDispatchNRE, class, TclDeletesObject); #else object->id = Tcl_CreateObjCommand(interp, nameString, NsfObjDispatch, class, TclDeletesObject); #endif PrimitiveOInit(object, interp, nameString, nsPtr, metaClass); if (nsPtr != NULL) { NSNamespaceRelease(nsPtr); } object->cmdName = nameObj; INCR_REF_COUNT(object->cmdName); PrimitiveCInit(class, interp, nameString+2); ObjTrace("PrimitiveCCreate", object); return class; } /* *---------------------------------------------------------------------- * ChangeClass -- * * Change class of a Next Scripting object. This function takes * care that one tries not to change an object into a class or vice * versa. Changing metaclass to metaclass, or class to class, or * object to object is fine, but upgrading/downgrading is not * allowed. * * Results: * A standard Tcl result. * * Side effects: * Changes class of object if possible and updates instance relation. * *---------------------------------------------------------------------- */ NSF_INLINE static int ChangeClass(Tcl_Interp *interp, NsfObject *object, NsfClass *class) nonnull(1) nonnull(2) nonnull(3); NSF_INLINE static int ChangeClass(Tcl_Interp *interp, NsfObject *object, NsfClass *class) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(class != NULL); NsfInstanceMethodEpochIncr("ChangeClass"); /*fprintf(stderr, "changing %s to class %s ismeta %d\n", ObjectName(object), ClassName(class), IsMetaClass(interp, cl, NSF_TRUE));*/ if (class != object->cl) { if (IsMetaClass(interp, class, NSF_TRUE)) { /* * Do not allow upgrading from a class to a metaclass (in other words, * don't make an object to a class). To allow this, it would be * necessary to reallocate the base structures. */ if (!IsMetaClass(interp, object->cl, NSF_TRUE)) { return NsfPrintError(interp, "cannot turn object into a class"); } } else { /* * The target class is not a metaclass. */ /*fprintf(stderr, "target class %s not a metaclass, am i a class %d\n", ClassName(class), NsfObjectIsClass(object) );*/ if (NsfObjectIsClass(object)) { return NsfPrintError(interp, "cannot turn class into an object "); } } RemoveInstance(object, object->cl); AddInstance(object, class); MixinComputeDefined(interp, object); FilterComputeDefined(interp, object); } return TCL_OK; } /* *---------------------------------------------------------------------- * DoObjInitialization -- * * Perform the object initialization: first call "configure" and the * constructor "init", if not called already from configure. The function * will make sure that the called methods do not change the result passed * into this function. * * Results: * A standard Tcl result. * * Side effects: * Indirect effects by calling Tcl code * *---------------------------------------------------------------------- */ static int DoObjInitialization(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const objv[]) nonnull(1) nonnull(2) nonnull(4); static int DoObjInitialization(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const objv[]) { Tcl_Obj *methodObj, *savedObjResult; int result; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(objv != NULL); assert(objc >= 0); #if 0 { int i; fprintf(stderr, "DoObjInitialization objc %d: ", objc); for(i = 0; i < objc; i++) {fprintf(stderr, " [%d]=%s,", i, ObjStr(objv[i]));} fprintf(stderr, "\n"); } #endif /* * Save the result we have so far to return it in case of success */ savedObjResult = Tcl_GetObjResult(interp); INCR_REF_COUNT(savedObjResult); /* * clear INIT_CALLED flag */ object->flags &= ~NSF_INIT_CALLED; /* * Make sure, the object survives initialization; the cmd/initcmd might * destroy it. */ NsfObjectRefCountIncr(object); /* * Call configure method */ if (CallDirectly(interp, object, NSF_o_configure_idx, &methodObj)) { NSF_PROFILE_TIME_DATA; if (methodObj == NULL) { methodObj = NsfGlobalObjs[NSF_CONFIGURE]; } assert(methodObj != NULL); /* * The methodObj is just used for error reporting. */ NSF_PROFILE_CALL(interp, object, ObjStr(methodObj)); result = NsfOConfigureMethod(interp, object, objc, objv, methodObj); NSF_PROFILE_EXIT(interp, object, ObjStr(methodObj)); } else { result = CallMethod(object, interp, methodObj, objc+2, objv, NSF_CSC_IMMEDIATE); } if (likely(result == TCL_OK)) { /* * Call constructor when needed */ if ((object->flags & (NSF_INIT_CALLED|NSF_DESTROY_CALLED)) == 0u) { result = DispatchInitMethod(interp, object, 0, NULL, 0u); } if (likely(result == TCL_OK)) { Tcl_SetObjResult(interp, savedObjResult); } } else { /* * Configure failed and might have left the object in a bogus state. To * avoid strange errors, we delete the half-baked object. */ Tcl_Obj *errObj; /* * Preserve the outer error message, calls triggered by * DispatchDestroyMethod() can cause the interp result to be reset */ errObj = Tcl_GetObjResult(interp); INCR_REF_COUNT(errObj); DispatchDestroyMethod(interp, (NsfObject *)object, 0u); Tcl_SetObjResult(interp, errObj); DECR_REF_COUNT(errObj); } NsfCleanupObject(object, "obj init"); DECR_REF_COUNT(savedObjResult); return result; } /* *---------------------------------------------------------------------- * IsRootMetaClass -- * * Check, of the class has the root metaclass flag set. * * Results: * A Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool IsRootMetaClass(const NsfClass *class) { nonnull_assert(class != NULL); return ((class->object.flags & NSF_IS_ROOT_META_CLASS) != 0u); } /* *---------------------------------------------------------------------- * IsBaseClass -- * * Check, whether the object is a base class. * * Results: * A Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool IsBaseClass(const NsfObject *object) { nonnull_assert(object != NULL); return ((object->flags & (NSF_IS_ROOT_CLASS|NSF_IS_ROOT_META_CLASS)) != 0u); } /* *---------------------------------------------------------------------- * IsRootClass -- * * Check, whether the object is a root-class. * * Results: * A Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool IsRootClass(const NsfClass *class) { nonnull_assert(class != NULL); return ((class->object.flags & (NSF_IS_ROOT_CLASS)) != 0u); } /* *---------------------------------------------------------------------- * IsMetaClass -- * * Check, whether the object is a metaclass. Optionally, mixins are * checked as well. * * Results: * A Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool IsMetaClass(Tcl_Interp *interp, NsfClass *class, bool withMixins) { NsfClasses *pl; bool result = NSF_FALSE; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); /* * Is the class the most general metaclass? */ if (IsRootMetaClass(class)) { return NSF_TRUE; } /* * Is the class a subclass of a metaclass? */ for (pl = PrecedenceOrder(class); pl != NULL; pl = pl->nextPtr) { if (IsRootMetaClass(pl->cl)) { return NSF_TRUE; } } if (withMixins) { NsfClasses *checkList = NULL, *mixinClasses = NULL, *mc; /* * Has the class metaclass mixed in? */ NsfClassListAddPerClassMixins(interp, class, &mixinClasses, &checkList); for (mc = mixinClasses; mc != NULL; mc = mc->nextPtr) { if (IsMetaClass(interp, mc->cl, NSF_FALSE)) { result = NSF_TRUE; break; } } if (mixinClasses != NULL) { NsfClassListFree(mixinClasses); } if (checkList != NULL) { NsfClassListFree(checkList); } /*fprintf(stderr, "has MC returns %d, mixinClasses = %p\n", result, mixinClasses);*/ } return result; } /* *---------------------------------------------------------------------- * IsSubType -- * * Check, whether a class is a subclass of another class. * * Results: * A Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool IsSubType(NsfClass *subClass, const NsfClass *class) { bool result; nonnull_assert(subClass != NULL); nonnull_assert(class != NULL); if (class != subClass) { result = (NsfClassListFind(PrecedenceOrder(subClass), class) != NULL); } else { result = NSF_TRUE; } return result; } /* *---------------------------------------------------------------------- * HasMixin -- * * Check, whether the specified object the specified class as mixin. * * Results: * A Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool HasMixin(Tcl_Interp *interp, NsfObject *object, NsfClass *class) nonnull(1) nonnull(2) nonnull(3); static bool HasMixin(Tcl_Interp *interp, NsfObject *object, NsfClass *class) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(class != NULL); if ((object->flags & NSF_MIXIN_ORDER_VALID) == 0u) { MixinComputeDefined(interp, object); } if ((object->flags & NSF_MIXIN_ORDER_DEFINED_AND_VALID) != 0u) { NsfCmdList *ml; for (ml = object->mixinOrder; ml != NULL; ml = ml->nextPtr) { NsfClass *mixinClass = NsfGetClassFromCmdPtr(ml->cmdPtr); if (mixinClass == class) { return NSF_TRUE; } } } return NSF_FALSE; } /* *---------------------------------------------------------------------- * ImportInstVarIntoCurrentScope -- * * Import an instance variable into the current variable scope * (e.g. function scope). * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ImportInstVarIntoCurrentScope(Tcl_Interp *interp, const char *cmdName, NsfObject *object, Tcl_Obj *varName, Tcl_Obj *newName) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static int ImportInstVarIntoCurrentScope(Tcl_Interp *interp, const char *cmdName, NsfObject *object, Tcl_Obj *varName, Tcl_Obj *newName) { Var *otherPtr = NULL, *arrayPtr; unsigned int flogs = TCL_LEAVE_ERR_MSG; Tcl_CallFrame *varFramePtr; CallFrame frame, *framePtr = &frame; const char *varNameString; nonnull_assert(interp != NULL); nonnull_assert(cmdName != NULL); nonnull_assert(object != NULL); nonnull_assert(varName != NULL); if (unlikely(CheckVarName(interp, ObjStr(varName)) != TCL_OK)) { return TCL_ERROR; } #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, object, framePtr); #pragma GCC diagnostic pop if (object->nsPtr != NULL) { flogs = flogs|TCL_NAMESPACE_ONLY; } otherPtr = TclObjLookupVar(interp, varName, NULL, (int)flogs, "define", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); Nsf_PopFrameObj(interp, framePtr); if (unlikely(otherPtr == NULL)) { return NsfPrintError(interp, "can't import variable %s into method scope: " "can't find variable on %s", ObjStr(varName), ObjectName_(object)); } /* * if newName == NULL -> there is no alias, use varName * as target link name */ if (newName == NULL) { /* * Variable link into namespace cannot be an element in an array. * see Tcl_VariableObjCmd ... */ if (arrayPtr != NULL) { return NsfPrintError(interp, "can't make instance variable %s on %s: " "Variable cannot be an element in an array; use e.g. an alias.", ObjStr(varName), ObjectName_(object)); } newName = varName; } varNameString = ObjStr(newName); varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); /* * If we are executing inside a Tcl procedure, create a local * variable linked to the new namespace variable "varName". */ if (varFramePtr != NULL && (Tcl_CallFrame_isProcCallFrame(varFramePtr) & FRAME_IS_PROC)) { Var *varPtr = (Var *)CompiledLocalsLookup((CallFrame *)varFramePtr, varNameString); int new = 0; if (varPtr == NULL) { /* * Look in frame's local var hash-table. */ TclVarHashTable *varTablePtr = Tcl_CallFrame_varTablePtr(varFramePtr); if (varTablePtr == NULL) { /* * The variable table does not exist. This seems to be is the * first access to a variable on this frame. We create the and * initialize the variable hash-table and update the object */ /*fprintf(stderr, "+++ create varTable in ImportInstVarIntoCurrentScope\n");*/ Tcl_CallFrame_varTablePtr(varFramePtr) = varTablePtr = VarHashTableCreate(); } varPtr = VarHashCreateVar(varTablePtr, newName, &new); } /* * If we define an alias (newName != varName), be sure that * the target does not exist already. */ if (new == 0) { /*fprintf(stderr, "GetIntoScope create alias\n");*/ if (unlikely(varPtr == otherPtr)) { return NsfPrintError(interp, "can't instvar to variable itself"); } if (TclIsVarLink(varPtr)) { /* * We try to make the same instvar again ... this is ok */ Var *linkPtr = TclVarValue(Var, varPtr, linkPtr); if (linkPtr == otherPtr) { return TCL_OK; } /*fprintf(stderr, "linkvar flags=%x\n", linkPtr->flags); Tcl_Panic("new linkvar %s... When does this happen?", ObjStr(newName), NULL);*/ /* * We have already a variable with the same name imported * from a different object. Get rid of this old variable. */ VarHashRefCount(linkPtr)--; if (TclIsVarUndefined(linkPtr)) { TclCleanupVar(linkPtr, (Var *) NULL); } } else if (unlikely(TclIsVarUndefined(varPtr) == 0)) { return NsfPrintError(interp, "varName '%s' exists already", varNameString); } else if (unlikely(TclIsVarTraced(varPtr) != 0)) { return NsfPrintError(interp, "varName '%s' has traces: can't use for instvar", varNameString); } } TclSetVarLink(varPtr); TclClearVarUndefined(varPtr); varPtr->value.linkPtr = otherPtr; VarHashRefCount(otherPtr)++; /* fprintf(stderr, "defining an alias var='%s' in obj %s fwd %d flags %x isLink %d isTraced %d isUndefined %d\n", ObjStr(newName), ObjectName(object), 0, varPtr->flags, TclIsVarLink(varPtr), TclIsVarTraced(varPtr), TclIsVarUndefined(varPtr)); */ } else { return NsfPrintError(interp, "%s cannot import variable '%s' into method scope; " "not called from a method frame", cmdName, varNameString); } return TCL_OK; } /* *---------------------------------------------------------------------- * SetInstVar -- * * Set an instance variable of the specified object to the given value. * * Results: * A standard Tcl result. * * Side effects: * Set instance variable. * *---------------------------------------------------------------------- */ static int SetInstVar(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *nameObj, Tcl_Obj *valueObj, unsigned int flags) { CallFrame frame, *framePtr = &frame; Tcl_Obj *resultObj; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(nameObj != NULL); #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, object, framePtr); #pragma GCC diagnostic pop if ((flags & NSF_VAR_TRIGGER_TRACE) != 0u) { int tclVarFlags; /* * The command should trigger traces, use therefore the high-level Tcl_Obj* * interface. */ tclVarFlags = (object->nsPtr != NULL) ? TCL_LEAVE_ERR_MSG|TCL_NAMESPACE_ONLY : TCL_LEAVE_ERR_MSG; if (likely(valueObj == NULL)) { resultObj = Tcl_ObjGetVar2(interp, nameObj, NULL, tclVarFlags); } else { resultObj = Tcl_ObjSetVar2(interp, nameObj, NULL, valueObj, tclVarFlags); } } else { /* * The command should not trigger traces, use the low-level TclLookupVar() * interface. */ Var *arrayPtr, *varPtr; if (likely(valueObj == NULL)) { varPtr = TclLookupVar(interp, ObjStr(nameObj), NULL, TCL_LEAVE_ERR_MSG, "access", /*createPart1*/ 0, /*createPart2*/ 0, &arrayPtr); if (likely(varPtr != NULL)) { resultObj = varPtr->value.objPtr; } else { resultObj = NULL; } } else { Tcl_Obj *oldValuePtr; varPtr = TclLookupVar(interp, ObjStr(nameObj), NULL, TCL_LEAVE_ERR_MSG, "access", /*createPart1*/ 1, /*createPart2*/ 0, &arrayPtr); oldValuePtr = varPtr->value.objPtr; INCR_REF_COUNT2("SetInstVar", valueObj); varPtr->value.objPtr = valueObj; if (oldValuePtr != NULL) { DECR_REF_COUNT2("SetInstVar", oldValuePtr); } resultObj = valueObj; } } Nsf_PopFrameObj(interp, framePtr); if (likely(resultObj != NULL)) { Tcl_SetObjResult(interp, resultObj); return TCL_OK; } return TCL_ERROR; } /* *---------------------------------------------------------------------- * SetInstArray -- * * Set an instance variable array of the specified object to the given * value. This function performs essentially an "array set" or "array get" * operation. * * Results: * A standard Tcl result. * * Side effects: * Set instance variable. * *---------------------------------------------------------------------- */ static int SetInstArray(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *arrayNameObj, Tcl_Obj *valueObj) nonnull(1) nonnull(2) nonnull(3); static int SetInstArray(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *arrayNameObj, Tcl_Obj *valueObj) { CallFrame frame, *framePtr = &frame; int result; Tcl_Obj *ov[4]; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(arrayNameObj != NULL); #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, object, framePtr); #pragma GCC diagnostic pop ov[0] = NsfGlobalObjs[NSF_ARRAY]; ov[2] = arrayNameObj; INCR_REF_COUNT(arrayNameObj); if (valueObj == NULL) { /* * Perform an "array get" */ ov[1] = NsfGlobalObjs[NSF_GET]; result = Tcl_EvalObjv(interp, 3, ov, 0); } else { /* * Perform an "array set" */ ov[1] = NsfGlobalObjs[NSF_SET]; ov[3] = valueObj; INCR_REF_COUNT(valueObj); result = Tcl_EvalObjv(interp, 4, ov, 0); DECR_REF_COUNT(valueObj); } DECR_REF_COUNT(arrayNameObj); Nsf_PopFrameObj(interp, framePtr); return result; } /* *---------------------------------------------------------------------- * UnsetInstVar -- * * Unset an instance variable of the specified object. * * Results: * A standard Tcl result. * * Side effects: * Variable unset. * *---------------------------------------------------------------------- */ static int UnsetInstVar(Tcl_Interp *interp, int withNocomplain, NsfObject *object, const char *name) { CallFrame frame, *framePtr = &frame; unsigned int flags; int result; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(name != NULL); flags = (withNocomplain != 0) ? 0 : TCL_LEAVE_ERR_MSG; if (object->nsPtr != NULL) { flags |= TCL_NAMESPACE_ONLY; } #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, object, framePtr); #pragma GCC diagnostic pop result = Tcl_UnsetVar2(interp, name, NULL, (int)flags); Nsf_PopFrameObj(interp, framePtr); return (withNocomplain != 0) ? TCL_OK : result; } /* *---------------------------------------------------------------------- * NsfSetterMethod -- * * This Tcl_ObjCmdProc is called, when a setter method is invoked. A setter * is a method that accesses/modifies a same-named instance variable. If * the setter is called without arguments, it returns the values, if it is * called with one argument, the argument is used as new value. * * Results: * A standard Tcl result. * * Side effects: * Can set an instance variable. * *---------------------------------------------------------------------- */ static int NsfSetterMethod(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) nonnull(1) nonnull(2) nonnull(4); static int NsfSetterMethod(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { SetterCmdClientData *cd; NsfObject *object; int result; nonnull_assert(clientData != NULL); nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); cd = (SetterCmdClientData *)clientData; object = cd->object; if (objc > 2) { Tcl_Obj *pathObj = NsfMethodNamePath(interp, CallStackGetTclFrame(interp, NULL, 1), NsfMethodName(objv[0])); INCR_REF_COUNT(pathObj); result = NsfObjWrongArgs(interp, "wrong # args", object->cmdName, pathObj, "?value?"); DECR_REF_COUNT(pathObj); } else if (object == NULL) { result = NsfDispatchClientDataError(interp, clientData, "object", ObjStr(objv[0])); } else { Tcl_Obj *nameObj; const char *nameString = ObjStr(objv[0]); /* * When the setter method is called with a leading colon, pass plain * object to SetInstVar(), otherwise we might run into shimmering with * tclCmds. */ if (FOR_COLON_RESOLVER(nameString)) { nameString ++; nameObj = Tcl_NewStringObj(nameString, TCL_INDEX_NONE); INCR_REF_COUNT(nameObj); } else { nameObj = objv[0]; } if (cd->paramsPtr != NULL && objc == 2) { Tcl_Obj *outObjPtr; unsigned flags = 0u; ClientData checkedData; result = ArgumentCheck(interp, objv[1], cd->paramsPtr, RUNTIME_STATE(interp)->doCheckArguments, &flags, &checkedData, &outObjPtr); if (likely(result == TCL_OK)) { result = SetInstVar(interp, object, nameObj, outObjPtr, NSF_VAR_TRIGGER_TRACE); } if ((flags & NSF_PC_MUST_DECR) != 0u) { DECR_REF_COUNT2("valueObj", outObjPtr); } } else { result = SetInstVar(interp, object, nameObj, objc == 2 ? objv[1] : NULL, NSF_VAR_TRIGGER_TRACE); } if (nameObj != objv[0]) { DECR_REF_COUNT(nameObj); } } return result; } /* *---------------------------------------------------------------------- * NsfForwardPrintError -- * * Helper function to print either an error message directly to * call the forwarder specific callback method specified in * tcd->onerror. Background: ForwardArg() is called at run time to * substitute the argument list. Catching such errors is not * conveniently doable via catch, since it would be necessary to * wrap every possible usage of a forwarder in a catch. Therefore, * the callback function can be used to give a sensible error * message appropriate for each context. * * Results: * A standard Tcl result. * * Side effects: * Potential side effects through the script. * *---------------------------------------------------------------------- */ static int NsfForwardPrintError(Tcl_Interp *interp, ForwardCmdClientData *tcd, int objc, Tcl_Obj *const objv[], const char *fmt, ...) nonnull(1) nonnull(2) nonnull(5) NSF_attribute_format((printf,5,6)); static int NsfForwardPrintError(Tcl_Interp *interp, ForwardCmdClientData *tcd, int objc, Tcl_Obj *const objv[], const char *fmt, ...) { Tcl_DString ds; va_list ap; int result; nonnull_assert(interp != NULL); nonnull_assert(tcd != NULL); nonnull_assert(fmt != NULL); Tcl_DStringInit(&ds); va_start(ap, fmt); NsfDStringVPrintf(&ds, fmt, ap); va_end(ap); //fprintf(stderr, "==== DEBUG AppVeyor: error msg<<%s>> (len %d)\n", ds.string, ds.length); if (tcd->onerror != NULL) { Tcl_Obj *script = Tcl_DuplicateObj(tcd->onerror); Tcl_Obj *cmd; if (tcd->object != NULL) { cmd = Tcl_DuplicateObj(tcd->object->cmdName); if (objc > 0) { Tcl_Obj *methodObjPath = NsfMethodNamePath(interp, CallStackGetTclFrame(interp, NULL, 1), MethodName(objv[0])); INCR_REF_COUNT(methodObjPath); Tcl_ListObjAppendList(interp, cmd, methodObjPath); DECR_REF_COUNT(methodObjPath); if (objc > 1) { Tcl_ListObjAppendElement(interp, cmd, Tcl_NewListObj((TCL_SIZE_T)objc-1, objv+1)); } } } else { cmd = Tcl_NewListObj((TCL_SIZE_T)objc, objv); } Tcl_ListObjAppendElement(interp, script, cmd); Tcl_ListObjAppendElement(interp, script, Tcl_NewStringObj(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds))); INCR_REF_COUNT(script); result = Tcl_EvalObjEx(interp, script, TCL_EVAL_DIRECT); DECR_REF_COUNT(script); } else { result = NsfPrintError(interp, "%s", Tcl_DStringValue(&ds)); } Tcl_DStringFree(&ds); return result; } /* *---------------------------------------------------------------------- * ForwardArg -- * * This function is a helper function of NsfForwardMethod() and * processes a single entry (ForwardArgObj) of the forward * spec. Essentially, it performs the percent substitution of the * forward spec. * * Results: * A standard Tcl result. * * Side effects: * Updates the provided output arguments. * *---------------------------------------------------------------------- */ static int ForwardArg( Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Tcl_Obj *forwardArgObj, ForwardCmdClientData *tcd, Tcl_Obj **out, Tcl_Obj **freeListObjPtr, int *inputArg, long *mapvalue, int firstPosArg, int *outputincr ) nonnull(1) nonnull(3) nonnull(4) nonnull(5) nonnull(6) nonnull(7) nonnull(8) nonnull(9) nonnull(11); static int ForwardArg( Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Tcl_Obj *forwardArgObj, ForwardCmdClientData *tcd, Tcl_Obj **out, Tcl_Obj **freeListObjPtr, int *inputArg, long *mapvalue, int firstPosArg, int *outputincr ) { const char *ForwardArgString, *p; int totalargs, result = TCL_OK; char c; nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); nonnull_assert(forwardArgObj != NULL); nonnull_assert(tcd != NULL); nonnull_assert(out != NULL); nonnull_assert(freeListObjPtr != NULL); nonnull_assert(inputArg != NULL); nonnull_assert(mapvalue != NULL); nonnull_assert(outputincr != NULL); assert(objc >= 1); totalargs = objc + tcd->nr_args - 1; /* * Per default every ForwardArgString from the processed list corresponds to * exactly one ForwardArgString in the computed final list. */ *outputincr = 1; ForwardArgString = ObjStr(forwardArgObj); p = ForwardArgString; /* fprintf(stderr, "ForwardArg: processing '%s'\n", ForwardArgString);*/ c = *ForwardArgString; if (c == '%' && *(ForwardArgString+1) == '@') { char *remainder = NULL; long pos; ForwardArgString += 2; pos = strtol(ForwardArgString, &remainder, 0); if (ForwardArgString == remainder && *ForwardArgString == 'e' && !strncmp(ForwardArgString, "end", 3)) { pos = -1; remainder += 3; } else if (pos < 0) { pos --; } if (ForwardArgString == remainder || labs(pos) > totalargs) { return NsfForwardPrintError(interp, tcd, objc, objv, "forward: invalid index specified in argument %s", ObjStr(forwardArgObj)); } if (!remainder || *remainder != ' ') { return NsfForwardPrintError(interp, tcd, objc, objv, "forward: invalid syntax in '%s'; use: %%@ ", ObjStr(forwardArgObj)); } ForwardArgString = remainder + 1; /* * In case we address from the end, we reduce further to distinguish from * -1 (void) */ if (pos < 0) { pos--; } /*fprintf(stderr, "remainder = '%s' pos = %ld\n", remainder, pos);*/ *mapvalue = pos; c = *ForwardArgString; } if (c == '%') { Tcl_Obj *listObj = NULL, **listElements = NULL; int nrArgs = objc-1, nrPosArgs = objc - firstPosArg, nrElements = 0; char c1, *firstActualArgument = nrArgs > 0 ? ObjStr(objv[1]) : NULL; const char *c1Ptr; assert(nrPosArgs >= 0); assert(nrArgs >= 0); c = *++ForwardArgString; c1Ptr = ForwardArgString + 1; c1 = *c1Ptr; if (c == 's' && !strcmp(ForwardArgString, "self")) { *out = tcd->object->cmdName; } else if ((c == 'p' && !strcmp(ForwardArgString, "proc")) || (c == 'm' && !strcmp(ForwardArgString, "method")) ) { const char *methodName = ObjStr(objv[0]); /* * If we dispatch a method via ".", we do not want to see the "." in the * %proc, e.g. for the interceptor slots (such as mixin, ...) */ if (FOR_COLON_RESOLVER(methodName)) { *out = Tcl_NewStringObj(methodName + 1, TCL_INDEX_NONE); } else { *out = objv[0]; } AddObjToTclList(interp, freeListObjPtr, *out); } else if (c == '1' && (c1 == '\0' || NsfHasTclSpace(c1Ptr))) { if (c1 != '\0') { if (unlikely(Tcl_ListObjIndex(interp, forwardArgObj, 1, &listObj) != TCL_OK)) { return NsfForwardPrintError(interp, tcd, objc, objv, "forward: %%1 must be followed by a valid list, given: '%s'", ObjStr(forwardArgObj)); } if (unlikely(Tcl_ListObjGetElements(interp, listObj, &nrElements, &listElements) != TCL_OK)) { return NsfForwardPrintError(interp, tcd, objc, objv, "forward: %%1 contains invalid list '%s'", ObjStr(listObj)); } } else if (unlikely(tcd->subcommands != NULL)) { /* * This is a deprecated part, kept for backwards compatibility. */ if (Tcl_ListObjGetElements(interp, tcd->subcommands, &nrElements, &listElements) != TCL_OK) { return NsfForwardPrintError(interp, tcd, objc, objv, "forward: %%1 contains invalid list '%s'", ObjStr(tcd->subcommands)); } } else { assert(nrElements <= nrPosArgs); } /*fprintf(stderr, "nrElements=%d, nra=%d firstPos %d objc %d\n", nrElements, nrArgs, firstPosArg, objc);*/ if (nrElements > nrPosArgs) { /* * Insert default subcommand depending on number of arguments. */ assert(listElements != NULL); /*fprintf(stderr, "inserting listElements[%d] '%s'\n", nrPosArgs, ObjStr(listElements[nrPosArgs]));*/ *out = listElements[nrPosArgs]; } else if (objc <= 1) { result = NsfForwardPrintError(interp, tcd, objc, objv, "%%1 requires argument; should be \"%s arg ...\"", ObjStr(objv[0])); } else { /*fprintf(stderr, "copying %%1: '%s'\n", ObjStr(objv[firstPosArg]));*/ *out = objv[firstPosArg]; *inputArg = firstPosArg+1; } } else if (c == '-') { const char *firstElementString; int insertRequired; bool done = NSF_FALSE; /*fprintf(stderr, "process flag '%s'\n", firstActualArgument);*/ if (Tcl_ListObjGetElements(interp, forwardArgObj, &nrElements, &listElements) != TCL_OK) { return NsfForwardPrintError(interp, tcd, objc, objv, "forward: '%s' is not a valid list", ForwardArgString); } if (nrElements < 1 || nrElements > 2) { return NsfForwardPrintError(interp, tcd, objc, objv, "forward: '%s': must contain 1 or 2 arguments", ForwardArgString); } firstElementString = ObjStr(listElements[0]); firstElementString++; /* we skip the dash */ if (firstActualArgument && *firstActualArgument == '-') { int i; /*fprintf(stderr, "we have a flag in first argument '%s'\n", firstActualArgument);*/ for (i = 1; i < firstPosArg; i++) { if (strcmp(firstElementString, ObjStr(objv[i])) == 0) { /*fprintf(stderr, "We have a MATCH for '%s' oldInputArg %d\n", ForwardArgString, *inputArg);*/ *out = objv[i]; /* %1 will start at a different place. Proceed if necessary to firstPosArg */ if (*inputArg < firstPosArg) { *inputArg = firstPosArg; } done = NSF_TRUE; break; } } } if (! done) { /* * We have a flag in the actual arguments that does not match. We * proceed to the actual arguments without dashes. */ if (*inputArg < firstPosArg) { *inputArg = firstPosArg; } /* * If the user requested we output the argument also when not * given in the argument list. */ if (nrElements == 2 && Tcl_GetIntFromObj(interp, listElements[1], &insertRequired) == TCL_OK && insertRequired) { /* * No match, but insert of flag is required. */ /*fprintf(stderr, "no match, but insert of %s required\n", firstElementString);*/ *out = Tcl_NewStringObj(firstElementString, TCL_INDEX_NONE); *outputincr = 1; AddObjToTclList(interp, freeListObjPtr, *out); } else { /* * No match, no insert of flag required, we skip the forwarder * option and output nothing. */ /*fprintf(stderr, "no match, nrElements %d insert req %d\n", nrElements, insertRequired);*/ *outputincr = 0; } } } else if (c == 'a' && !strncmp(ForwardArgString, "argcl", 4)) { if (Tcl_ListObjIndex(interp, forwardArgObj, 1, &listObj) != TCL_OK) { result = NsfForwardPrintError(interp, tcd, objc, objv, "forward: %%argclindex must by a valid list, given: '%s'", ForwardArgString); } else if (Tcl_ListObjGetElements(interp, listObj, &nrElements, &listElements) != TCL_OK) { result = NsfForwardPrintError(interp, tcd, objc, objv, "forward: %%argclindex contains invalid list '%s'", ObjStr(listObj)); } else if (nrArgs >= nrElements) { result = NsfForwardPrintError(interp, tcd, objc, objv, "forward: not enough elements in specified list of ARGC argument %s", ForwardArgString); } else { *out = listElements[nrArgs]; } } else if (c == '%') { Tcl_Obj *newarg = Tcl_NewStringObj(ForwardArgString, TCL_INDEX_NONE); *out = newarg; AddObjToTclList(interp, freeListObjPtr, *out); } else { /* * Evaluate the given command. */ /*fprintf(stderr, "evaluating '%s'\n", ForwardArgString);*/ result = Tcl_EvalEx(interp, ForwardArgString, TCL_INDEX_NONE, 0); if (likely(result == TCL_OK)) { *out = Tcl_DuplicateObj(Tcl_GetObjResult(interp)); AddObjToTclList(interp, freeListObjPtr, *out); /*fprintf(stderr, "result = '%s'\n", ObjStr(*out));*/ } } } else { if (likely(p == ForwardArgString)) { *out = forwardArgObj; } else { Tcl_Obj *newarg = Tcl_NewStringObj(ForwardArgString, TCL_INDEX_NONE); *out = newarg; AddObjToTclList(interp, freeListObjPtr, *out); } } return result; } /* *---------------------------------------------------------------------- * CallForwarder -- * * Invoke the method to which the forwarder points. This function * receives the already transformed argument vector, calls the * method and performs error handling. * * Results: * A standard Tcl result. * * Side effects: * Maybe through the invoked command. * *---------------------------------------------------------------------- */ static int CallForwarder(ForwardCmdClientData *tcd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) nonnull(1) nonnull(2) nonnull(4); static int CallForwarder(ForwardCmdClientData *tcd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { int result; NsfObject *object; CallFrame frame, *framePtr = &frame; nonnull_assert(tcd != NULL); nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); object = tcd->object; tcd->object = NULL; if (unlikely(tcd->verbose)) { Tcl_Obj *cmd = Tcl_NewListObj((TCL_SIZE_T)objc, objv); NsfLog(interp, NSF_LOG_DEBUG, "forwarder calls '%s'", ObjStr(cmd)); DECR_REF_COUNT(cmd); } if (tcd->frame == FrameObjectIdx) { #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, object, framePtr); #pragma GCC diagnostic pop } if (tcd->objProc != NULL) { /*fprintf(stderr, "CallForwarder Tcl_NRCallObjProc %p\n", tcd->clientData);*/ result = Tcl_NRCallObjProc(interp, tcd->objProc, tcd->clientData, (TCL_SIZE_T)objc, objv); } else if (TclObjIsNsfObject(interp, tcd->cmdName, &object)) { /*fprintf(stderr, "CallForwarder NsfObjDispatch object %s, objc=%d\n", ObjStr(tcd->cmdName), objc);*/ if (likely(objc > 1)) { result = ObjectDispatch(object, interp, objc, objv, NSF_CSC_IMMEDIATE); } else { result = DispatchDefaultMethod(interp, object, objv[0], NSF_CSC_IMMEDIATE); } } else { /*fprintf(stderr, "CallForwarder: no nsf object %s [0] %s\n", ObjStr(tcd->cmdName), ObjStr(objv[0]));*/ result = Tcl_EvalObjv(interp, (TCL_SIZE_T)objc, objv, 0); } if (tcd->frame == FrameObjectIdx) { Nsf_PopFrameObj(interp, framePtr); } #if defined(NSF_FORWARD_WITH_ONERROR) if (unlikely(result == TCL_ERROR && tcd->onerror != NULL)) { Tcl_Obj *resultObj = Tcl_GetObjResult(interp); const char *errorMsg = ObjStr(resultObj); INCR_REF_COUNT(resultObj); //fprintf(stderr, "==== DEBUG AppVeyor: calling NsfForwardPrintError with <<%s>> (len %lu)\n", // errorMsg, (unsigned long)strlen(errorMsg)); result = NsfForwardPrintError(interp, tcd, objc, objv, "%s", errorMsg); DECR_REF_COUNT(resultObj); } #endif return result; } /* *---------------------------------------------------------------------- * NsfForwardMethod -- * * This Tcl_ObjCmdProc is called, when a forwarder is invoked. It * performs argument substitution through ForwardArg() and calls * finally the method, to which the call was forwarded via * CallForwarder(). * * Results: * A standard Tcl result. * * Side effects: * Maybe through the invoked command. * *---------------------------------------------------------------------- */ static int NsfForwardMethod(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) nonnull(1) nonnull(2) nonnull(4); static int NsfForwardMethod(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { ForwardCmdClientData *tcd = (ForwardCmdClientData *)clientData; int result, inputArg = 1; nonnull_assert(clientData != NULL); nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); if (unlikely(!tcd || !tcd->object)) { return NsfDispatchClientDataError(interp, tcd, "object", objc > 0 ? ObjStr(objv[0]) : "forwarder"); } /* * First, we handle two short cuts for simple cases. */ if (tcd->passthrough) { /* * This is set for early binding. This means, that the cmd is already * resolved, we have to care only for objscope. */ return CallForwarder(tcd, interp, objc, objv); } else if (tcd->args == NULL && *(ObjStr(tcd->cmdName)) != '%') { /* * We have no args, therefore, we have only to replace the method name * with the given cmd name. */ ALLOC_ON_STACK(Tcl_Obj*, objc, ov); /*fprintf(stderr, "+++ forwardMethod must subst oc=%d <%s>\n", objc, ObjStr(tcd->cmdName));*/ memcpy(ov, objv, sizeof(Tcl_Obj *) * (size_t)objc); ov[0] = tcd->cmdName; result = CallForwarder(tcd, interp, objc, ov); FREE_ON_STACK(Tcl_Obj *, ov); return result; } else { Tcl_Obj **ov, *freeList = NULL; int j, outputincr, outputArg = 0, firstPosArg=1, totalargs = objc + tcd->nr_args + 3; ALLOC_ON_STACK(Tcl_Obj*, totalargs, OV); { ALLOC_ON_STACK(long, totalargs, objvmap); /*fprintf(stderr, "+++ forwardMethod standard case, allocated %d args, tcd->args %s\n", totalargs, ObjStr(tcd->args));*/ ov = &OV[1]; if (tcd->needobjmap) { memset(objvmap, -1, sizeof(long) * (size_t)totalargs); } /* * The first argument is always the command, to which we forward. */ if ((result = ForwardArg(interp, objc, objv, tcd->cmdName, tcd, &ov[outputArg], &freeList, &inputArg, &objvmap[outputArg], firstPosArg, &outputincr)) != TCL_OK) { goto exitforwardmethod; } outputArg += outputincr; /* * If we have non-pos args, determine the first positional arg position * for %1 */ if (tcd->hasNonposArgs) { firstPosArg = objc; for (j = outputArg; j < objc; j++) { const char *arg = ObjStr(objv[j]); if (*arg != '-') { firstPosArg = j; break; } } } if (tcd->args != NULL) { Tcl_Obj **listElements; int nrElements; /* * Copy argument list from the definitions. */ Tcl_ListObjGetElements(interp, tcd->args, &nrElements, &listElements); for (j = 0; j < nrElements; j++, outputArg += outputincr) { if ((result = ForwardArg(interp, objc, objv, listElements[j], tcd, &ov[outputArg], &freeList, &inputArg, &objvmap[outputArg], firstPosArg, &outputincr)) != TCL_OK) { goto exitforwardmethod; } } } /*fprintf(stderr, "objc=%d, tcd->nr_subcommands=%d size=%d\n", objc, tcd->nr_subcommands, objc+ 2 );*/ if (objc-inputArg > 0) { /*fprintf(stderr, " copying remaining %d args starting at [%d]\n", objc-inputArg, outputArg);*/ memcpy(ov+outputArg, objv+inputArg, sizeof(Tcl_Obj *) * ((size_t)objc - (size_t)inputArg)); } else { /*fprintf(stderr, " nothing to copy, objc=%d, inputArg=%d\n", objc, inputArg);*/ } if (tcd->needobjmap) { /* * The objmap can shuffle the argument list. We have to set the * addressing relative from the end; -2 means last, -3 element before * last, etc. */ int max = objc + tcd->nr_args - inputArg; for (j = 0; j < totalargs; j++) { if (objvmap[j] < -1) { /*fprintf(stderr, "must reduct, v=%d\n", objvmap[j]);*/ objvmap[j] = max + objvmap[j] + 2; /*fprintf(stderr, "... new value=%d, max = %d\n", objvmap[j], max);*/ } } } objc += outputArg - inputArg; #if 0 for(j = 0; j < objc; j++) { /*fprintf(stderr, " ov[%d]=%p, objc=%d\n", j, ov[j], objc);*/ fprintf(stderr, " o[%d]=%p %s (%d),", j, ov[j], ov[j] ? ObjStr(ov[j]) : "NADA", objvmap[j]); } fprintf(stderr, "\n"); #endif if (tcd->needobjmap) { for (j = 0; j < totalargs; j++) { Tcl_Obj *tmp; long pos = objvmap[j], i; if (pos == -1 || pos == j) { continue; } tmp = ov[j]; if (j > pos) { for(i = j; i > pos; i--) { /*fprintf(stderr, "...moving right %d to %d\n", i-1, i);*/ ov[i] = ov[i-1]; objvmap[i] = objvmap[i-1]; } } else { for(i = j; i < pos; i++) { /*fprintf(stderr, "...moving left %d to %d\n", i+1, i);*/ ov[i] = ov[i+1]; objvmap[i] = objvmap[i+1]; } } /*fprintf(stderr, "...setting at %d -> %s\n", pos, ObjStr(tmp));*/ ov[pos] = tmp; objvmap[pos] = -1; } } /* If a prefix is provided, it will be prepended to the 2nd argument. This allows for avoiding name clashes if the 2nd argument denotes a subcommand, for example. Make sure that the prefix is only prepended, if a second argument is actually available! Otherwise, the requested prefix has no effect. */ if (tcd->prefix && objc > 1) { Tcl_Obj *methodName = Tcl_DuplicateObj(tcd->prefix); Tcl_AppendObjToObj(methodName, ov[1]); ov[1] = methodName; INCR_REF_COUNT(ov[1]); } #if 0 for(j = 0; j < objc; j++) { /*fprintf(stderr, " ov[%d]=%p, objc=%d\n", j, ov[j], objc);*/ fprintf(stderr, " ov[%d]=%p '%s' map=%d\n", j, ov[j], ov[j] ? ObjStr(ov[j]) : "NADA", objvmap[j]); } #endif OV[0] = tcd->cmdName; result = CallForwarder(tcd, interp, objc, ov); if (tcd->prefix && objc > 1) { DECR_REF_COUNT(ov[1]); } exitforwardmethod: if (freeList != NULL) { DECR_REF_COUNT2("AddObjToTclList", freeList); } FREE_ON_STACK(long, objvmap); } FREE_ON_STACK(Tcl_Obj*, OV); } return result; } /* *---------------------------------------------------------------------- * NsfProcAliasMethod -- * * Since alias-resolving happens in dispatch, this Tcl_ObjCmdProc * should never be called during normal operations. The only way to * invoke this could happen via directly calling the handle. * * Results: * Result is always TCL_ERROR (as returned by * NsfDispatchClientDataError()). * * Side effects: * None. * *---------------------------------------------------------------------- */ static int NsfProcAliasMethod(ClientData clientData, Tcl_Interp *interp, int UNUSED(objc), Tcl_Obj *const UNUSED(objv[])) nonnull(1) nonnull(2) nonnull(4); static int NsfProcAliasMethod(ClientData clientData, Tcl_Interp *interp, int UNUSED(objc), Tcl_Obj *const UNUSED(objv[])) { AliasCmdClientData *tcd; nonnull_assert(clientData != NULL); nonnull_assert(interp != NULL); tcd = (AliasCmdClientData *)clientData; return NsfDispatchClientDataError(interp, NULL, "object", Tcl_GetCommandName(interp, tcd->aliasCmd)); } /* *---------------------------------------------------------------------- * NsfObjscopedMethod -- * * This Tcl_ObjCmdProc is called, when an obj-scoped alias is * invoked. * * Results: * A standard Tcl result. * * Side effects: * Maybe through the invoked command. * *---------------------------------------------------------------------- */ static int NsfObjscopedMethod(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) nonnull(1) nonnull(2) nonnull(4); static int NsfObjscopedMethod(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { AliasCmdClientData *tcd; NsfObject *object; CallFrame frame, *framePtr = &frame; int result; nonnull_assert(clientData != NULL); nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); tcd = (AliasCmdClientData *)clientData; /*fprintf(stderr, "objscopedMethod obj=%p %s, ptr=%p\n", object, ObjectName(object), tcd->objProc);*/ object = tcd->object; tcd->object = NULL; #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, object, framePtr); #pragma GCC diagnostic pop result = Tcl_NRCallObjProc(interp, tcd->objProc, tcd->clientData, (TCL_SIZE_T)objc, objv); Nsf_PopFrameObj(interp, framePtr); return result; } /* *---------------------------------------------------------------------- * IsDashArg -- * * Check, whether the provided argument (pointed to be the index * isFirstArg) starts with a "-", or is a list starting with a * "-". The method returns via **methodName the name of the dashed * argument (without the dash). * * Results: * Enum value dashArgType. * * Side effects: * None. * *---------------------------------------------------------------------- */ typedef enum {NO_DASH, SCALAR_DASH, LIST_DASH} dashArgType; static dashArgType IsDashArg(Tcl_Interp *interp, Tcl_Obj *obj, int isFirstArg, const char **methodName, int *objcPtr, Tcl_Obj **objvPtr[]) nonnull(1) nonnull(2) nonnull(4) nonnull(5) nonnull(6); static dashArgType IsDashArg(Tcl_Interp *interp, Tcl_Obj *obj, int isFirstArg, const char **methodName, int *objcPtr, Tcl_Obj **objvPtr[]) { const char *flag; nonnull_assert(interp != NULL); nonnull_assert(obj != NULL); nonnull_assert(methodName != NULL); nonnull_assert(objcPtr != NULL); nonnull_assert(objvPtr != NULL); if (obj->typePtr == Nsf_OT_listType) { if (Tcl_ListObjGetElements(interp, obj, objcPtr, objvPtr) == TCL_OK && *objcPtr > 1) { flag = ObjStr(*objvPtr[0]); /*fprintf(stderr, "we have a list starting with '%s'\n", flag);*/ if (*flag == '-') { *methodName = flag+1; return LIST_DASH; } } } flag = ObjStr(obj); /*fprintf(stderr, "we have a scalar '%s' isFirstArg %d\n", flag, isFirstArg);*/ if ((*flag == '-') && isalpha(*((flag)+1))) { if (isFirstArg == 1) { /* * If the argument contains a space, try to split. */ const char *p = flag+1; while (*p != '\0' && !NsfHasTclSpace(p)) p++; if (NsfHasTclSpace(p)) { if (Tcl_ListObjGetElements(interp, obj, objcPtr, objvPtr) == TCL_OK) { *methodName = ObjStr(*objvPtr[0]); if (**methodName == '-') { (*methodName)++ ; } return LIST_DASH; } } } *methodName = flag+1; *objcPtr = 1; return SCALAR_DASH; } return NO_DASH; } /* *---------------------------------------------------------------------- * CallConfigureMethod -- * * Call a method identified by a string selector; or provide an * error message. This dispatcher function records as well * constructor (init) calls via this interface. The dispatcher is * used in XOTcl's configure(), interpreting arguments with a * leading dash as method dispatches. This behavior is now * implemented in NsfOResidualargsMethod(). * * Results: * A standard Tcl result. * * Side effects: * Maybe side effects from the called methods. * *---------------------------------------------------------------------- */ static int CallConfigureMethod(Tcl_Interp *interp, NsfObject *object, const char *initString, const char *methodName, int argc, Tcl_Obj *const argv[]) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static int CallConfigureMethod(Tcl_Interp *interp, NsfObject *object, const char *initString, const char *methodName, int argc, Tcl_Obj *const argv[]) { int result; Tcl_Obj *methodObj = Tcl_NewStringObj(methodName, TCL_INDEX_NONE); nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(initString != NULL); nonnull_assert(methodName != NULL); /* * When configure gets "-init" passed, we call "init" and notice the fact it * in the object's flags. */ if (*initString == *methodName && strcmp(methodName, initString) == 0) { object->flags |= NSF_INIT_CALLED; } Tcl_ResetResult(interp); INCR_REF_COUNT(methodObj); result = CallMethod(object, interp, methodObj, argc, argv, NSF_CM_NO_UNKNOWN|NSF_CSC_IMMEDIATE|NSF_CM_IGNORE_PERMISSIONS); DECR_REF_COUNT(methodObj); /*fprintf(stderr, "method '%s' called args: %d o=%p, result=%d %d\n", methodName, argc+1, object, result, TCL_ERROR);*/ if (unlikely(result != TCL_OK)) { Tcl_Obj *res = Tcl_DuplicateObj(Tcl_GetObjResult(interp)); /* save the result */ INCR_REF_COUNT(res); NsfPrintError(interp, "%s during '%s.%s'", ObjStr(res), ObjectName_(object), methodName); DECR_REF_COUNT(res); } return result; } /* * class method implementations */ /* *---------------------------------------------------------------------- * IsRootNamespace -- * * Check whether the provided namespace is the namespace of the base * class of an object system. * * Results: * Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool IsRootNamespace(const Tcl_Interp *interp, const Tcl_Namespace *nsPtr) nonnull(1) nonnull(2) NSF_pure; static bool IsRootNamespace(const Tcl_Interp *interp, const Tcl_Namespace *nsPtr) { const NsfObjectSystem *osPtr; nonnull_assert(interp != NULL); nonnull_assert(nsPtr != NULL); for (osPtr = RUNTIME_STATE(interp)->objectSystems; osPtr != NULL; osPtr = osPtr->nextPtr) { const Tcl_Command cmd = osPtr->rootClass->object.id; if ((Tcl_Namespace *)((Command *)cmd)->nsPtr == nsPtr) { return NSF_TRUE; } } return NSF_FALSE; } /* *---------------------------------------------------------------------- * CallingNameSpace -- * * Find the last invocation outside the Next Scripting system * namespaces. This function return the namespace of the caller but * skips system-specific namespaces (e.g. the namespaces of the * pre-defined slot handlers for mixin and class * registration. etc.) If we would use such namespaces, we would * resolve non-fully-qualified names against the root namespace). * * Results: * Tcl_Namespace or NULL * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Namespace * CallingNameSpace(Tcl_Interp *interp) { Tcl_CallFrame *framePtr; Tcl_Namespace *nsPtr = NULL; nonnull_assert(interp != NULL); /*NsfShowStack(interp);*/ framePtr = CallStackGetActiveProcFrame((Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp)); /* framePtr = BeginOfCallChain(interp, GetSelfObj(interp));*/ for (; likely(framePtr != NULL); framePtr = Tcl_CallFrame_callerVarPtr(framePtr)) { nsPtr = Tcl_CallFrame_nsPtr(framePtr); if (IsRootNamespace(interp, nsPtr)) { /*fprintf(stderr, "... %p skip %s\n", framePtr, nsPtr->fullName);*/ continue; } /*fprintf(stderr, "... %p take %s\n", framePtr, nsPtr->fullName); */ break; } if (framePtr == NULL) { nsPtr = Tcl_GetGlobalNamespace(interp); } /*fprintf(stderr, " **** CallingNameSpace: returns %p %s framePtr %p\n", nsPtr, (nsPtr != NULL) ? nsPtr->fullName:"(null)", framePtr);*/ return nsPtr; } /*********************************** * argument handling ***********************************/ static void ArgumentResetRefCounts(const struct Nsf_Param *pPtr, Tcl_Obj *valueObj) nonnull(1) nonnull(2); static void ArgumentResetRefCounts(const struct Nsf_Param *pPtr, Tcl_Obj *valueObj) { nonnull_assert(pPtr != NULL); nonnull_assert(valueObj != NULL); if ((pPtr->flags & NSF_ARG_IS_CONVERTER) != 0u) { DECR_REF_COUNT2("valueObj", valueObj); } } /* *---------------------------------------------------------------------- * ArgumentCheckHelper -- * * Helper function for ArgumentCheck() called when argument * checking leads to a different output element (non-pure * checking). * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ArgumentCheckHelper(Tcl_Interp *interp, Tcl_Obj *objPtr, const struct Nsf_Param *pPtr, unsigned int *flags, ClientData *clientData, Tcl_Obj **outObjPtr) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(5) nonnull(6); static int ArgumentCheckHelper(Tcl_Interp *interp, Tcl_Obj *objPtr, const struct Nsf_Param *pPtr, unsigned int *flags, ClientData *clientData, Tcl_Obj **outObjPtr) { int objc, i, result; Tcl_Obj **ov; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(flags != NULL); nonnull_assert(clientData != NULL); nonnull_assert(outObjPtr != NULL); assert((pPtr->flags & NSF_ARG_MULTIVALUED) != 0u); assert((*flags & NSF_PC_MUST_DECR) != 0u); result = Tcl_ListObjGetElements(interp, objPtr, &objc, &ov); if (unlikely(result != TCL_OK)) { return result; } *outObjPtr = Tcl_NewListObj(0, NULL); INCR_REF_COUNT2("valueObj", *outObjPtr); for (i = 0; i < objc; i++) { Tcl_Obj *elementObjPtr = ov[i]; const char *valueString = ObjStr(elementObjPtr); if ((pPtr->flags & NSF_ARG_ALLOW_EMPTY) != 0u && *valueString == '\0') { result = Nsf_ConvertToString(interp, elementObjPtr, pPtr, clientData, &elementObjPtr); } else { result = (*pPtr->converter)(interp, elementObjPtr, pPtr, clientData, &elementObjPtr); } /*fprintf(stderr, "ArgumentCheckHelper convert %s result %d (%s)\n", valueString, result, ObjStr(elementObjPtr));*/ if (result == TCL_OK || result == TCL_CONTINUE) { Tcl_ListObjAppendElement(interp, *outObjPtr, elementObjPtr); /* * If the refCount of the valueObj was already incremented, we have to * decrement it here, since we want the valueObj reclaimed when the list * containing the valueObj is freed. */ ArgumentResetRefCounts(pPtr, elementObjPtr); } else { Tcl_Obj *resultObj = Tcl_GetObjResult(interp); INCR_REF_COUNT(resultObj); NsfPrintError(interp, "invalid value in \"%s\": %s", ObjStr(objPtr), ObjStr(resultObj)); *flags &= ~NSF_PC_MUST_DECR; *outObjPtr = objPtr; DECR_REF_COUNT2("valueObj", *outObjPtr); DECR_REF_COUNT(resultObj); break; } } return result; } /* *---------------------------------------------------------------------- * ArgumentCheck -- * * Check a single argument (2nd argument) against the parameter * structure when argument checking is turned on (default). * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ArgumentCheck(Tcl_Interp *interp, Tcl_Obj *objPtr, const struct Nsf_Param *pPtr, unsigned int doCheckArguments, unsigned int *flags, ClientData *clientData, Tcl_Obj **outObjPtr) { int result; nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); nonnull_assert(pPtr != NULL); nonnull_assert(flags != NULL); nonnull_assert(clientData != NULL); nonnull_assert(outObjPtr != NULL); /* * Default assumption: outObjPtr is not modified. */ *outObjPtr = objPtr; /* * Omit argument checking, provided that ... * ... argument checking is turned off *and* no converter is specified, or * ... the ruling parameter option is 'cmd' * ... slotset is active */ if ((unlikely((doCheckArguments & NSF_ARGPARSE_CHECK) == 0u) && (pPtr->flags & (NSF_ARG_IS_CONVERTER)) == 0u) || ((pPtr->flags & (NSF_ARG_CMD)) != 0u) || ((pPtr->flags & (NSF_ARG_SLOTSET)) != 0u)) { /* fprintf(stderr, "*** omit argument check for arg %s flags %.6x\n", pPtr->name, pPtr->flags); */ *clientData = ObjStr(objPtr); return TCL_OK; } /* * If the argument is multivalued, perform the check for every element * of the list (pure checker), or we have to build a new list of * values (in case, the converter alters the values). */ if (unlikely((pPtr->flags & NSF_ARG_MULTIVALUED) != 0u)) { int objc, i; Tcl_Obj **ov; result = Tcl_ListObjGetElements(interp, objPtr, &objc, &ov); if (unlikely(result != TCL_OK)) { return result; } if (objc == 0 && ((pPtr->flags & NSF_ARG_ALLOW_EMPTY) == 0u)) { return NsfPrintError(interp, "invalid value for parameter '%s': list is not allowed to be empty", pPtr->name); } /* * In cases where necessary (the output element changed), switch to the * helper function */ for (i = 0; i < objc; i++) { Tcl_Obj *elementObjPtr = ov[i]; result = (*pPtr->converter)(interp, elementObjPtr, pPtr, clientData, &elementObjPtr); if (likely(result == TCL_OK || result == TCL_CONTINUE)) { if (ov[i] != elementObjPtr) { /*fprintf(stderr, "ArgumentCheck: switch to output list construction for value %s\n", ObjStr(elementObjPtr));*/ /* * The elementObjPtr differs from the input Tcl_Obj, we switch to * the version of this handler building an output list. But first, * we have to reset the ref-counts from the first conversion. */ ArgumentResetRefCounts(pPtr, elementObjPtr); *flags |= NSF_PC_MUST_DECR; result = ArgumentCheckHelper(interp, objPtr, pPtr, flags, clientData, outObjPtr); break; } } else { Tcl_Obj *resultObj = Tcl_GetObjResult(interp); INCR_REF_COUNT(resultObj); NsfPrintError(interp, "invalid value in \"%s\": %s", ObjStr(objPtr), ObjStr(resultObj)); DECR_REF_COUNT(resultObj); break; } } } else { assert(objPtr == *outObjPtr); if ((pPtr->flags & NSF_ARG_ALLOW_EMPTY) != 0u && *(ObjStr(objPtr)) == '\0') { result = Nsf_ConvertToString(interp, objPtr, pPtr, clientData, outObjPtr); } else { result = (*pPtr->converter)(interp, objPtr, pPtr, clientData, outObjPtr); } /*fprintf(stderr, "ArgumentCheck param %s type %s is converter %d flags %.6x " "outObj changed %d (%p %p) isok %d\n", pPtr->name, pPtr->type, pPtr->flags & NSF_ARG_IS_CONVERTER, pPtr->flags, objPtr != *outObjPtr, objPtr, *outObjPtr, result == TCL_OK);*/ if (unlikely((pPtr->flags & NSF_ARG_IS_CONVERTER) != 0u) && objPtr != *outObjPtr) { *flags |= NSF_PC_MUST_DECR; } else { /* * If the output obj differs from the input obj, ensure we have * MUST_DECR set. */ assert( (*flags & NSF_PC_MUST_DECR) != 0u || objPtr == *outObjPtr ); } } if (unlikely(result == TCL_CONTINUE)) { *flags |= NSF_ARG_WARN; result = TCL_OK; } return result; } /* *---------------------------------------------------------------------- * ArgumentDefaults -- * * Process the argument vector and set defaults in parse context if * provided and necessary. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ArgumentDefaults(ParseContext *pcPtr, Tcl_Interp *interp, const Nsf_Param *ifd, int nrParams, unsigned int processFlags) nonnull(1) nonnull(2) nonnull(3); static int ArgumentDefaults(ParseContext *pcPtr, Tcl_Interp *interp, const Nsf_Param *ifd, int nrParams, unsigned int processFlags) { const Nsf_Param *pPtr; int i; nonnull_assert(pcPtr != NULL); nonnull_assert(interp != NULL); nonnull_assert(ifd != NULL); for (pPtr = ifd, i = 0; i < nrParams; pPtr++, i++) { /*fprintf(stderr, "ArgumentDefaults got for arg %s (req %d, nrArgs %d) %p => %p %p, default '%s' \n", pPtr->name, pPtr->flags & NSF_ARG_REQUIRED, pPtr->nrArgs, pPtr, pcPtr->clientData[i], pcPtr->objv[i], (pPtr->defaultValue != NULL) ? ObjStr(pPtr->defaultValue) : "NONE");*/ if (pcPtr->objv[i] != NULL) { /* * We got an actual value, which was already checked by ArgumentParse(). * In case the value is a switch and NSF_PC_INVERT_DEFAULT is set, we * take the default and invert the value in place. */ if (unlikely((pcPtr->flags[i] & NSF_PC_INVERT_DEFAULT) != 0u)) { int boolVal; assert(pPtr->defaultValue != NULL); Tcl_GetBooleanFromObj(interp, pPtr->defaultValue, &boolVal); pcPtr->objv[i] = Tcl_NewBooleanObj(boolVal == 0); /* * Perform bookkeeping to avoid that someone releases the new obj * before we are done. The according DECR is performed by * ParseContextRelease() */ INCR_REF_COUNT2("valueObj", pcPtr->objv[i]); pcPtr->flags[i] |= NSF_PC_MUST_DECR; pcPtr->status |= NSF_PC_STATUS_MUST_DECR; } } else { /* * No valued was passed, check whether a default is available. */ if (pPtr->defaultValue != NULL) { int mustDecrNewValue; Tcl_Obj *newValue = pPtr->defaultValue; ClientData checkedData; /* * We have a default value for the argument. Mark that this argument * gets the default value. */ pcPtr->flags[i] |= NSF_PC_IS_DEFAULT; /* * Does the user want to substitute in the default value? */ if (unlikely((pPtr->flags & NSF_ARG_SUBST_DEFAULT) != 0u)) { int tclOptions = 0; Tcl_Obj *obj; if ((pPtr->flags & NSF_ARG_SUBST_DEFAULT_VARIABLES) != 0u) { tclOptions |= TCL_SUBST_VARIABLES; } if ((pPtr->flags & NSF_ARG_SUBST_DEFAULT_COMMANDS) != 0u) { tclOptions |= TCL_SUBST_COMMANDS; } if ((pPtr->flags & NSF_ARG_SUBST_DEFAULT_BACKSLASHES) != 0u) { tclOptions |= TCL_SUBST_BACKSLASHES; } /* fprintf(stderr, "SUBST tclOptions %.4x\n", tclOptions);*/ obj = Tcl_SubstObj(interp, newValue, tclOptions); if (likely(obj != NULL)) { newValue = obj; } else { pcPtr->flags[i] = 0u; return TCL_ERROR; } /* * The matching DECR is performed by ParseContextRelease(). */ INCR_REF_COUNT2("valueObj", newValue); /*fprintf(stderr, "SUBST_DEFAULT increments %p refCount %d\n", newValue, newValue->refCount);*/ mustDecrNewValue = 1; pcPtr->flags[i] |= NSF_PC_MUST_DECR; pcPtr->status |= NSF_PC_STATUS_MUST_DECR; } else { mustDecrNewValue = 0; } pcPtr->objv[i] = newValue; /*fprintf(stderr, "==> setting default value '%s' for var '%s' flag %d type %s conv %p\n", ObjStr(newValue), pPtr->name, pPtr->flags & NSF_ARG_INITCMD, pPtr->type, pPtr->converter);*/ /* * Check the default value if necessary */ if (pPtr->type != NULL || unlikely((pPtr->flags & NSF_ARG_MULTIVALUED) != 0u)) { unsigned int mustDecrList = 0; if (unlikely((pPtr->flags & NSF_ARG_INITCMD) == 0u && ArgumentCheck(interp, newValue, pPtr, RUNTIME_STATE(interp)->doCheckArguments, &mustDecrList, &checkedData, &pcPtr->objv[i]) != TCL_OK)) { if (mustDecrNewValue == 1) { DECR_REF_COUNT2("valueObj", newValue); pcPtr->flags[i] &= ~NSF_PC_MUST_DECR; } return TCL_ERROR; } if (unlikely(pcPtr->objv[i] != newValue)) { /* * The output Tcl_Obj differs from the input, so the Tcl_Obj was * converted; in case we have set previously the flag * NSF_PC_MUST_DECR on newValue, we decrement the refCount on * newValue here and clear the flag. */ if (mustDecrNewValue == 1) { DECR_REF_COUNT2("valueObj", newValue); pcPtr->flags[i] &= ~NSF_PC_MUST_DECR; } /* * The new output value itself might require a decrement, so set * the flag here if required; this is just necessary for * multivalued converted output. */ if (mustDecrList == 1) { pcPtr->flags[i] |= NSF_PC_MUST_DECR; pcPtr->status |= NSF_PC_STATUS_MUST_DECR; } } } else { /*fprintf(stderr, "Param %s default %s type %s\n", pPtr->name, ObjStr(pPtr->defaultValue), pPtr->type);*/ assert((pPtr->type != NULL) ? pPtr->defaultValue == NULL : 1); } } else if (unlikely((pPtr->flags & NSF_ARG_REQUIRED) != 0u) && ((processFlags & NSF_ARGPARSE_FORCE_REQUIRED) != 0u)) { Tcl_Obj *paramDefsObj = NsfParamDefsSyntax(interp, ifd, pcPtr->object, NULL); Tcl_Obj *methodPathObj = NsfMethodNamePath(interp, CallStackGetTclFrame(interp, NULL, 1), MethodName(pcPtr->full_objv[0])); INCR_REF_COUNT2("methodPathObj", methodPathObj); NsfPrintError(interp, "required argument '%s' is missing, should be:\n %s%s%s %s", (pPtr->nameObj != NULL) ? ObjStr(pPtr->nameObj) : pPtr->name, (pcPtr->object != NULL) ? ObjectName(pcPtr->object) : "", (pcPtr->object != NULL) ? " " : "", ObjStr(methodPathObj), ObjStr(paramDefsObj)); DECR_REF_COUNT2("paramDefsObj", paramDefsObj); DECR_REF_COUNT2("methodPathObj", methodPathObj); return TCL_ERROR; } else { /* * Use as dummy default value an arbitrary symbol, which must * not be returned to the Tcl level level; this value is unset * later typically by NsfUnsetUnknownArgsCmd(). */ pcPtr->objv[i] = NsfGlobalObjs[NSF___UNKNOWN__]; } } } return TCL_OK; } /* *---------------------------------------------------------------------- * ArgumentParse -- * * Parse the argument vector based on the parameter definitions. * The parsed argument vector is returned in a normalized order * in the parse context. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_ArgumentParse( Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Nsf_Object *object, Tcl_Obj *procNameObj, const Nsf_Param *paramPtr, int nrParams, int serial, unsigned int processFlags, Nsf_ParseContext *pcPtr ) { nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); nonnull_assert(procNameObj != NULL); nonnull_assert(pcPtr != NULL); return ArgumentParse(interp, objc, objv, (NsfObject *)object, procNameObj, paramPtr, nrParams, serial, processFlags, (ParseContext *)pcPtr); } /* *---------------------------------------------------------------------- * NextParam -- * * Advance in the parameter definitions and return the next parameter. * * Results: * Next parameter. * * Side effects: * None. * *---------------------------------------------------------------------- */ static const Nsf_Param * NextParam(Nsf_Param const *paramPtr, const Nsf_Param *lastParamPtr) nonnull(1) nonnull(2) returns_nonnull NSF_pure; static const Nsf_Param * NextParam(Nsf_Param const *paramPtr, const Nsf_Param *lastParamPtr) { nonnull_assert(paramPtr != NULL); nonnull_assert(lastParamPtr != NULL); for (; (++paramPtr <= lastParamPtr) && (*paramPtr->name == '-'); ); return paramPtr; } /* *---------------------------------------------------------------------- * ArgumentParse -- * * Parse the provided list of argument against the given definition. The * result is returned in the parse context structure. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ #define SkipNonposParamDefs(cPtr) \ for (; (++(cPtr) <= lastParamPtr) && (*(cPtr)->name == '-'); ) static int ArgumentParse( Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], NsfObject *object, Tcl_Obj *procNameObj, const Nsf_Param *paramPtr, int nrParams, int serial, unsigned int processFlags, ParseContext *pcPtr ) { int o, fromArg; bool dashdash = NSF_FALSE; long j; const Nsf_Param *currentParamPtr; const Nsf_Param *lastParamPtr; nonnull_assert(interp != NULL); nonnull_assert(procNameObj != NULL); nonnull_assert(paramPtr != NULL); nonnull_assert(pcPtr != NULL); if ((processFlags & NSF_ARGPARSE_START_ZERO) != 0u) { fromArg = 0; } else { fromArg = 1; } ParseContextInit(pcPtr, nrParams, object, procNameObj); #if defined(PARSE_TRACE) { const Nsf_Param *pPtr; fprintf(stderr, "PARAMETER "); for (o = 0, pPtr = paramPtr; pPtr->name != NULL; o++, pPtr++) { fprintf(stderr, "[%d]%s (nrargs %d %s) ", o, pPtr->name, pPtr->nrArgs, (pPtr->flags & NSF_ARG_REQUIRED) != 0u ? "req" : "opt"); } fprintf(stderr, "\n"); fprintf(stderr, "BEGIN (%d) [0]%s ", objc, ObjStr(procNameObj)); for (o = fromArg; o < objc; o++) { Tcl_Obj *obj = objv[o]; if (obj->bytes == NULL) { fprintf(stderr, "[%d]unk(%s) ", o, obj->typePtr->name); } else { fprintf(stderr, "[%d]%s ", o, ObjStr(obj)); } } fprintf(stderr, "\n"); } #endif currentParamPtr = paramPtr; lastParamPtr = paramPtr + nrParams - 1; for (o = fromArg; o < objc; o++) { const Nsf_Param *pPtr = currentParamPtr; Tcl_Obj *argumentObj = objv[o], *valueObj = NULL; const char *valueInArgument = NULL; #if defined(PARSE_TRACE_FULL) fprintf(stderr, "arg [%d]: %s (param %ld, last %d)\n", o, ObjStr(argumentObj), currentParamPtr - paramPtr, currentParamPtr == lastParamPtr); #endif if (unlikely(currentParamPtr > lastParamPtr)) { int result; Tcl_Obj *methodPathObj; methodPathObj = NsfMethodNamePath(interp, CallStackGetTclFrame(interp, NULL, 0), NsfMethodName(procNameObj)); INCR_REF_COUNT(methodPathObj); /*fprintf(stderr, "call NsfUnexpectedArgumentError 1\n");*/ result = NsfUnexpectedArgumentError(interp, ObjStr(argumentObj), (Nsf_Object*)object, paramPtr, methodPathObj); DECR_REF_COUNT(methodPathObj); return result; } if (*currentParamPtr->name == '-') { /* * We expect a non-pos arg. Check whether we a Tcl_Obj already converted * to NsfFlagObjType. */ NsfFlag *flagPtr = argumentObj->internalRep.twoPtrValue.ptr1; #if defined(PARSE_TRACE_FULL) fprintf(stderr, "... arg %p %s expect non-pos arg in block %s isFlag %d sig %d serial %d (%d => %d)\n", (void*)argumentObj, ObjStr(argumentObj), currentParamPtr->name, argumentObj->typePtr == &NsfFlagObjType, argumentObj->typePtr == &NsfFlagObjType ? flagPtr->signature == paramPtr : 0, argumentObj->typePtr == &NsfFlagObjType ? flagPtr->serial == serial : 0, argumentObj->typePtr == &NsfFlagObjType ? flagPtr->serial : 0, serial ); #endif if (argumentObj->typePtr == &NsfFlagObjType && flagPtr->signature == paramPtr && flagPtr->serial == serial && flagPtr->paramPtr != NULL /* when the parameter was previously used in a cget */ ) { /* * The argument was processed before and the Tcl_Obj is still valid. */ if ((flagPtr->flags & NSF_FLAG_DASHDAH) != 0u) { /* * We got a dashDash, skip non-pos param definitions and continue with next * element from objv. */ SkipNonposParamDefs(currentParamPtr); assert(!dashdash); continue; } else if ((flagPtr->flags & NSF_FLAG_CONTAINS_VALUE) != 0u) { /* * We got a flag with an embedded value (e.g. -flag=1). */ valueInArgument = "flag"; } pPtr = flagPtr->paramPtr; valueObj = flagPtr->payload; } else if ((argumentObj->typePtr == Nsf_OT_byteArrayType) || (argumentObj->typePtr == Nsf_OT_properByteArrayType) /* || (argumentObj->typePtr == Nsf_OT_intType) || (argumentObj->typePtr == Nsf_OT_doubleType) */ ) { /* * The actual argument belongs to the types, for which we assume that * these can't belong to a non-pos flag. The argument might be e.g. a * pure Tcl bytearray, for which we do not want to add a string rep * via ObjStr() such it loses its purity (Tcl 8.6). For these * argument types. Proceed in the parameter vector to the next block * (positional parameter) */ SkipNonposParamDefs(currentParamPtr); pPtr = currentParamPtr; /* * currentParamPtr is either NULL or points to a positional parameter */ assert(currentParamPtr == NULL || currentParamPtr->name == NULL || *currentParamPtr->name != '-'); } else { const char *argumentString = ObjStr(argumentObj); /* * We are in a state, where we expect a non-positional argument, and * the lookup from the Tcl_Obj has failed. If this non-pos args are * optional, the current argument might contain also a value for a * positional argument maybe the argument is for a posarg * later). First check whether the argument looks like a flag. */ if (argumentString[0] != '-') { /* * The actual argument is not a flag, so proceed in the parameter * vector to the next block (positional parameter) */ SkipNonposParamDefs(currentParamPtr); pPtr = currentParamPtr; /* * currentParamPtr is either NULL or points to a positional parameter */ assert(currentParamPtr == NULL || currentParamPtr->name == NULL || *currentParamPtr->name != '-'); } else { /* * The actual argument starts with a dash, so search for the flag in * the current block of non-pos parameter definitions */ char ch1 = *(argumentString+1); /* * Is there a "--" ? */ if (ch1 == '-' && *(argumentString+2) == '\0' && !dashdash) { dashdash = NSF_TRUE; NsfFlagObjSet(interp, argumentObj, paramPtr, serial, NULL, NULL, NSF_FLAG_DASHDAH); SkipNonposParamDefs(currentParamPtr); continue; } valueInArgument = strchr(argumentString, '='); if (valueInArgument != NULL) { bool found = NSF_FALSE; long equalOffset = valueInArgument - argumentString; /* * Handle parameter like -flag=1 */ for (; (pPtr <= lastParamPtr) && (*pPtr->name == '-'); pPtr++) { if (pPtr->nrArgs > 0) { /* * Parameter expects no arg, can't be this. */ continue; } if ((pPtr->flags & NSF_ARG_NOCONFIG) == 0u && ch1 == pPtr->name[1] && strncmp(argumentString, pPtr->name, (size_t)equalOffset) == 0 && *(pPtr->name+equalOffset) == '\0') { valueObj = Tcl_NewStringObj(valueInArgument+1, TCL_INDEX_NONE); /*fprintf(stderr, "... value from argument = %s\n", ObjStr(valueObj));*/ NsfFlagObjSet(interp, argumentObj, paramPtr, serial, pPtr, valueObj, NSF_FLAG_CONTAINS_VALUE); found = NSF_TRUE; break; } } if (!found) { const Nsf_Param *nextParamPtr = NextParam(currentParamPtr, lastParamPtr); if (nextParamPtr > lastParamPtr || ((nextParamPtr->flags & NSF_ARG_NODASHALNUM) != 0u)) { int result; Tcl_Obj *methodPathObj= NsfMethodNamePath(interp, CallStackGetTclFrame(interp, NULL, 0), NsfMethodName(procNameObj)); INCR_REF_COUNT(methodPathObj); result = NsfUnexpectedNonposArgumentError(interp, argumentString, (Nsf_Object *)object, currentParamPtr, paramPtr, methodPathObj); DECR_REF_COUNT(methodPathObj); return result; } pPtr = currentParamPtr = nextParamPtr; } } else { /* * Must be a classical non-pos arg; check for a matching parameter * definition. */ bool found = NSF_FALSE; assert(pPtr == currentParamPtr); if (likely(ch1 != '\0')) { if (unlikely(NsfParamDefsNonposLookup(interp, argumentString, currentParamPtr, &pPtr) != TCL_OK)) { return TCL_ERROR; } else { if (pPtr != NULL) { found = NSF_TRUE; NsfFlagObjSet(interp, argumentObj, paramPtr, serial, pPtr, NULL, 0u); } } } /* * We might have found the argument starting with the dash in the * parameter definitions or not. If it was not found, then we can * advance to the next positional parameter and stuff the value in * there, if the parameter definition allows this. */ if (!found) { int nonposArgError = 0; const Nsf_Param *nextParamPtr = NextParam(currentParamPtr, lastParamPtr); /*fprintf(stderr, "non-pos-arg '%s' not found, current %p %s last %p %s next %p %s\n", argumentString, currentParamPtr, currentParamPtr->name, lastParamPtr, lastParamPtr->name, nextParamPtr, nextParamPtr->name);*/ if (nextParamPtr > lastParamPtr) { nonposArgError = 1; } else if ((nextParamPtr->flags & NSF_ARG_NODASHALNUM) != 0u) { /* * Check whether argument is numeric, since we want to allow it as * value even when NSF_ARG_NODASHALNUM was specified. */ nonposArgError = 1; if (argumentString[1] >= '0' && argumentString[1] <= '9') { char *p; (void)strtod(&argumentString[1], &p); if (*p == '\0') { /* * Argument is numeric. */ nonposArgError = 0; } } } if (nonposArgError != 0) { int result; Tcl_Obj *methodPathObj = NsfMethodNamePath(interp, CallStackGetTclFrame(interp, NULL, 0), NsfMethodName(procNameObj)); INCR_REF_COUNT(methodPathObj); result = NsfUnexpectedNonposArgumentError(interp, argumentString, (Nsf_Object *)object, currentParamPtr, paramPtr, methodPathObj); DECR_REF_COUNT(methodPathObj); return result; } pPtr = currentParamPtr = nextParamPtr; } } } /* end of lookup loop */ } } else { valueInArgument = NULL; } assert(pPtr != NULL); /* * "pPtr" points to the actual parameter (part of the currentParamPtr * block) or might point to a place past the last parameter, in which case * an unexpected argument was provided. "o" is the index of the actual * parameter, "valueObj" might be already provided for valueInArgument. */ if (unlikely(pPtr > lastParamPtr)) { int result; Tcl_Obj *methodPathObj; methodPathObj = NsfMethodNamePath(interp, CallStackGetTclFrame(interp, NULL, 0), NsfMethodName(procNameObj)); INCR_REF_COUNT(methodPathObj); /*fprintf(stderr, "call NsfUnexpectedArgumentError 2\n");*/ result = NsfUnexpectedArgumentError(interp, ObjStr(argumentObj), (Nsf_Object *)object, paramPtr, methodPathObj); DECR_REF_COUNT(methodPathObj); return result; } /* * Set the position in the downstream argv (normalized order) */ j = pPtr - paramPtr; #if defined(PARSE_TRACE_FULL) fprintf(stderr, "... pPtr->name %s/%d o %d objc %d\n", pPtr->name, pPtr->nrArgs, o, objc); #endif if (*pPtr->name == '-') { /* * Process the non-pos arg. */ if (pPtr->nrArgs == 1) { /* * The non-pos arg expects an argument. */ o++; if (unlikely(o >= objc)) { /* * We expect an argument, but we are already at the end of the * argument list. */ return NsfPrintError(interp, "value for parameter '%s' expected", pPtr->name); } assert(valueObj == NULL); valueObj = objv[o]; } else { /* * The non-pos arg expects no argument. */ if (valueObj == NULL) { valueObj = NsfGlobalObjs[NSF_ONE]; } } } else if (unlikely((pPtr == lastParamPtr) && (pPtr->converter == ConvertToNothing))) { /* * "args" was given, use the varargs interface. Store the actual * argument into pcPtr->objv. No checking is performed on "args". */ pcPtr->varArgs = NSF_TRUE; pcPtr->objv[j] = argumentObj; #if defined(PARSE_TRACE_FULL) fprintf(stderr, "... args found o %d objc %d is dashdash %d [%ld] <%s>\n", o, objc, (int)dashdash, j, ObjStr(argumentObj)); #endif break; } else { /* * Process an ordinary positional argument. */ currentParamPtr ++; #if defined(PARSE_TRACE_FULL) fprintf(stderr, "... positional arg o %d objc %d, nrArgs %d next paramPtr %s\n", o, objc, pPtr->nrArgs, currentParamPtr->name); #endif if (unlikely(pPtr->nrArgs == 0)) { /* * Allow positional arguments with 0 args for object parameter * aliases, which are always fired. Such parameter are non-consuming, * therefore the processing of the current argument is not finished, we * have to decrement o. We have to check here if we are already at the * end if the parameter vector. */ o--; continue; } if (unlikely(dashdash)) { /* * Reset dashdash. */ dashdash = NSF_FALSE; } valueObj = argumentObj; } #if defined(PARSE_TRACE_FULL) fprintf(stderr, "... setting parameter %s pos %ld valueObj '%s'\n", pPtr->name, j, valueObj == argumentObj ? "=" : ObjStr(valueObj)); #endif /* * The value for the flag is now in the valueObj. We * check, whether it is value is permissible. */ assert(valueObj != NULL); if (unlikely(ArgumentCheck(interp, valueObj, pPtr, processFlags, &pcPtr->flags[j], &pcPtr->clientData[j], &pcPtr->objv[j]) != TCL_OK)) { if (pcPtr->flags[j] & NSF_PC_MUST_DECR) { pcPtr->status |= NSF_PC_STATUS_MUST_DECR; } return TCL_ERROR; } /* * Switches are more tricky: if the flag is provided without * valueInArgument, we take the default and invert it. If valueInArgument * was used, the default inversion must not happen. */ if (likely(valueInArgument == NULL)) { if (unlikely(pPtr->converter == Nsf_ConvertToSwitch)) { /*fprintf(stderr, "... set INVERT_DEFAULT for '%s' flags %.6x\n", pPtr->name, pPtr->flags);*/ assert(pPtr->defaultValue != NULL); pcPtr->flags[j] |= NSF_PC_INVERT_DEFAULT; } } /*fprintf(stderr, "... non-positional pcPtr %p check [%d] obj %p flags %.6x & %p\n", pcPtr, j, pcPtr->objv[j], pcPtr->flags[j], &(pcPtr->flags[j])); */ /* * Provide warnings for double-settings. */ if (unlikely((pcPtr->flags[j] & NSF_ARG_SET) != 0u)) { Tcl_Obj *cmdLineObj = Tcl_NewListObj((TCL_SIZE_T)objc-1, objv+1); INCR_REF_COUNT(cmdLineObj); NsfLog(interp, NSF_LOG_WARN, "Non-positional parameter %s was passed more than once (%s%s%s %s)", pPtr->name, (object != NULL) ? ObjectName(object) : "", (object != NULL) ? " method " : "", ObjStr(procNameObj), ObjStr(cmdLineObj)); DECR_REF_COUNT(cmdLineObj); } pcPtr->flags[j] |= NSF_ARG_SET; /* * Embed error message of converter in current context. */ if (unlikely((pcPtr->flags[j] & NSF_ARG_WARN) != 0u)) { Tcl_Obj *resultObj = Tcl_GetObjResult(interp); Tcl_DString ds, *dsPtr = &ds; Tcl_DStringInit(dsPtr); INCR_REF_COUNT(resultObj); NsfDStringArgv(dsPtr, objc, objv); NsfLog(interp, NSF_LOG_WARN, "%s during:\n%s %s", ObjStr(resultObj), (object != NULL) ? ObjectName(object) : "nsf::proc", Tcl_DStringValue(dsPtr)); DECR_REF_COUNT(resultObj); Tcl_DStringFree(dsPtr); } if (unlikely((pcPtr->flags[j] & NSF_PC_MUST_DECR) != 0u)) { pcPtr->status |= NSF_PC_STATUS_MUST_DECR; } assert(!pcPtr->varArgs); #if defined(PARSE_TRACE_FULL) fprintf(stderr, "... iterate on o %d objc %d, currentParamPtr %s\n", o, objc, currentParamPtr->name); #endif } if ((currentParamPtr <= lastParamPtr) && (!pcPtr->varArgs)) { /* * Not all parameter processed, make sure varags is set. */ /*fprintf(stderr, ".... not all parms processed, pPtr '%s' j %ld nrParams %d last '%s' varArgs %d dashdash %d\n", currentParamPtr->name, currentParamPtr - paramPtr, nrParams, lastParamPtr->name, pcPtr->varArgs, (int)dashdash);*/ if (lastParamPtr->converter == ConvertToNothing) { pcPtr->varArgs = NSF_TRUE; } } /* * Set lastObjc as index of the first "unprocessed" parameter. */ pcPtr->lastObjc = o; pcPtr->objc = nrParams; /* * The index "pcPtr->lastObjc-1" can be "-1", which is a problem, when * called via nsf::parseargs, where the allocated objv array starts at * position 0. It is fine when just a part of the real objv is passed to * ArgumentParse(). * * assert(ISOBJ(objv[pcPtr->lastObjc-1])); */ #if defined(PARSE_TRACE_FULL) fprintf(stderr, "..... argv processed o %d lastObjc %d nrParams %d olastObjc, nrParams, ovarArgs); #endif return ArgumentDefaults(pcPtr, interp, paramPtr, nrParams, processFlags); } /*********************************** * Begin result setting commands * (essentially List*() and support ***********************************/ /* *---------------------------------------------------------------------- * ListVarKeys -- * * Return variable names of the provided hash table in the interp * result. Optionally "pattern" might be used to filter the result * list. * * Results: * A standard Tcl result. * * Side effects: * Sets the interpreter's result object. * *---------------------------------------------------------------------- */ static int ListVarKeys(Tcl_Interp *interp, Tcl_HashTable *tablePtr, const char *pattern) nonnull(1); static int ListVarKeys(Tcl_Interp *interp, Tcl_HashTable *tablePtr, const char *pattern) { const Tcl_HashEntry *hPtr; nonnull_assert(interp != NULL); if (pattern != NULL && NoMetaChars(pattern)) { Tcl_Obj *patternObj = Tcl_NewStringObj(pattern, TCL_INDEX_NONE); INCR_REF_COUNT(patternObj); hPtr = (tablePtr != NULL) ? Tcl_CreateHashEntry(tablePtr, (char *)patternObj, NULL) : NULL; if (hPtr != NULL) { const Var *val = TclVarHashGetValue(hPtr); Tcl_SetObjResult(interp, TclVarHashGetKey(val)); } else { Tcl_SetObjResult(interp, NsfGlobalObjs[NSF_EMPTY]); } DECR_REF_COUNT(patternObj); } else { Tcl_Obj *list = Tcl_NewListObj(0, NULL); Tcl_HashSearch hSrch; hPtr = (tablePtr != NULL) ? Tcl_FirstHashEntry(tablePtr, &hSrch) : NULL; for (; hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { const Var *val = TclVarHashGetValue(hPtr); Tcl_Obj *key = TclVarHashGetKey(val); if (pattern == NULL || Tcl_StringMatch(ObjStr(key), pattern)) { Tcl_ListObjAppendElement(interp, list, key); } } Tcl_SetObjResult(interp, list); } return TCL_OK; } /* *---------------------------------------------------------------------- * GetOriginalCommand -- * * Obtain for an imported/aliased cmd the original definition. * * Results: * Tcl command * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Command GetOriginalCommand( Tcl_Command cmd /* The imported command for which the original * command should be returned. */ ) { Tcl_Command importedCmd; nonnull_assert(cmd != NULL); while (1) { AliasCmdClientData *tcd; /* * Dereference the namespace import reference chain */ if ((importedCmd = TclGetOriginalCommand(cmd))) { cmd = importedCmd; } /* * Dereference the Next Scripting alias chain */ if (Tcl_Command_deleteProc(cmd) == AliasCmdDeleteProc) { tcd = (AliasCmdClientData *)Tcl_Command_objClientData(cmd); /* fprintf(stderr, "... GetOriginalCommand finds alias %s -> %s\n", Tcl_GetCommandName(NULL, cmd), Tcl_GetCommandName(NULL, tcd->aliasedCmd)); */ cmd = tcd->aliasedCmd; continue; } /* * Dereference the Next Scripting alias chain via potential proc contexts, * since we identify the alias reference on the AliasCmdDeleteProc. */ if (Tcl_Command_deleteProc(cmd) == NsfProcDeleteProc && Tcl_Command_objProc(cmd) == NsfProcAliasMethod) { NsfProcContext *ctxPtr = Tcl_Command_deleteData(cmd); if (ctxPtr->oldDeleteProc == AliasCmdDeleteProc) { tcd = (AliasCmdClientData *)Tcl_Command_objClientData(cmd); /* fprintf(stderr, "... GetOriginalCommand finds alias via oldDeleteProc %s -> %s (%p -> %p)\n", Tcl_GetCommandName(NULL, cmd), Tcl_GetCommandName(NULL, tcd->aliasedCmd), (void*)cmd, (void*)tcd->aliasedCmd ); char *name =Tcl_GetCommandName(NULL, cmd); if (!strcmp("incr", name)) {char *p = NULL; *p=1;} */ cmd = tcd->aliasedCmd; continue; } } break; } return cmd; } /* *---------------------------------------------------------------------- * ListProcBody -- * * Return the body of a scripted proc as Tcl interp result. * * Results: * A standard Tcl result. * * Side effects: * Sets the interpreter's result object. * *---------------------------------------------------------------------- */ static int ListProcBody(Tcl_Interp *interp, Proc *procPtr) nonnull(1) nonnull(2); static int ListProcBody(Tcl_Interp *interp, Proc *procPtr) { const char *body; nonnull_assert(interp != NULL); nonnull_assert(procPtr != NULL); body = ObjStr(procPtr->bodyPtr); Tcl_SetObjResult(interp, Tcl_NewStringObj(StripBodyPrefix(body), TCL_INDEX_NONE)); return TCL_OK; } /* *---------------------------------------------------------------------- * ListParamDefs -- * * Compute the parameter definition in one of four different forms. * * Results: * A standard Tcl result. * * Side effects: * Sets the interpreter's result object. * *---------------------------------------------------------------------- */ static Tcl_Obj *ListParamDefs(Tcl_Interp *interp, const Nsf_Param *paramsPtr, NsfObject *contextObject, const char *pattern, NsfParamsPrintStyle style) nonnull(1) nonnull(2) returns_nonnull; static Tcl_Obj * ListParamDefs(Tcl_Interp *interp, const Nsf_Param *paramsPtr, NsfObject *contextObject, const char *pattern, NsfParamsPrintStyle style) { Tcl_Obj *listObj = NsfGlobalObjs[NSF_EMPTY]; /* enumeration is complete, make stupid checker happy */ nonnull_assert(interp != NULL); nonnull_assert(paramsPtr != NULL); switch (style) { case NSF_PARAMS_PARAMETER: listObj = ParamDefsFormat(interp, paramsPtr, contextObject, pattern); break; case NSF_PARAMS_LIST: listObj = ParamDefsList(interp, paramsPtr, contextObject, pattern); break; case NSF_PARAMS_NAMES: listObj = ParamDefsNames(interp, paramsPtr, contextObject, pattern); break; case NSF_PARAMS_SYNTAX: listObj = NsfParamDefsSyntax(interp, paramsPtr, contextObject, pattern); break; } return listObj; } /* *---------------------------------------------------------------------- * ListCmdParams -- * * Obtains a cmd and a method name. As a side effect, sets the Tcl * interp result to a list of parameter definitions, if * available. The print-style NSF_PARAMS_NAMES, NSF_PARAMS_LIST, * NSF_PARAMS_PARAMETER, NSF_PARAMS_SYNTAX controls the list * content. * * Results: * A standard Tcl result. * * Side effects: * Sets the interpreter's result object. * *---------------------------------------------------------------------- */ static int ListCmdParams(Tcl_Interp *interp, Tcl_Command cmd, NsfObject *contextObject, const char *pattern, const char *methodName, NsfParamsPrintStyle printStyle) nonnull(1) nonnull(2) nonnull(5); static int ListCmdParams(Tcl_Interp *interp, Tcl_Command cmd, NsfObject *contextObject, const char *pattern, const char *methodName, NsfParamsPrintStyle printStyle) { NsfParamDefs *paramDefs; Tcl_Obj *listObj; Proc *procPtr; int result = TCL_OK; nonnull_assert(interp != NULL); nonnull_assert(methodName != NULL); nonnull_assert(cmd != NULL); paramDefs = ParamDefsGet(cmd, NULL, NULL); if (paramDefs != NULL && paramDefs->paramsPtr != NULL) { /* * Obtain parameter info from paramDefs. */ listObj = ListParamDefs(interp, paramDefs->paramsPtr, contextObject, pattern, printStyle); Tcl_SetObjResult(interp, listObj); DECR_REF_COUNT2("paramDefsObj", listObj); return TCL_OK; } procPtr = GetTclProcFromCommand(cmd); if (procPtr != NULL) { /* * Obtain parameter info from compiled locals. */ CompiledLocal *args = procPtr->firstLocalPtr; listObj = Tcl_NewListObj(0, NULL); for ( ; args; args = args->nextPtr) { if (!TclIsCompiledLocalArgument(args)) { continue; } if (pattern != NULL && !Tcl_StringMatch(args->name, pattern)) { continue; } if (printStyle == NSF_PARAMS_SYNTAX && strcmp(args->name, "args") == 0) { if (args != procPtr->firstLocalPtr) { Tcl_AppendToObj(listObj, " ", 1); } Tcl_AppendToObj(listObj, "?/arg .../?", 11); } else { if (printStyle == NSF_PARAMS_SYNTAX) { /* * A default means that the argument is optional. */ if (args->defValuePtr != NULL) { Tcl_AppendToObj(listObj, "?", 1); Tcl_AppendToObj(listObj, args->name, TCL_INDEX_NONE); Tcl_AppendToObj(listObj, "?", 1); } else { Tcl_AppendToObj(listObj, "/", 1); Tcl_AppendToObj(listObj, args->name, TCL_INDEX_NONE); Tcl_AppendToObj(listObj, "/", 1); } if (args->nextPtr != NULL) { Tcl_AppendToObj(listObj, " ", 1); } } else { Tcl_Obj *innerListObj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, innerListObj, Tcl_NewStringObj(args->name, TCL_INDEX_NONE)); /* * Return default just for NSF_PARAMS_PARAMETER. */ if ((args->defValuePtr != NULL) && (printStyle == NSF_PARAMS_PARAMETER)) { Tcl_ListObjAppendElement(interp, innerListObj, args->defValuePtr); } Tcl_ListObjAppendElement(interp, listObj, innerListObj); } } } Tcl_SetObjResult(interp, listObj); return TCL_OK; } { /* * If a command is not found for the object|class, check whether we * find the parameter definitions for the C-defined method. */ Nsf_methodDefinition *mdPtr = Nsf_CmdDefinitionGet(((Command *)cmd)->objProc); if (mdPtr != NULL) { NsfParamDefs localParamDefs = {mdPtr->paramDefs, mdPtr->nrParameters, 1, 0}; Tcl_Obj *list = ListParamDefs(interp, localParamDefs.paramsPtr, contextObject, pattern, printStyle); Tcl_SetObjResult(interp, list); DECR_REF_COUNT2("paramDefsObj", list); return TCL_OK; } } if (((Command *)cmd)->objProc == NsfSetterMethod) { SetterCmdClientData *cd = (SetterCmdClientData *)Tcl_Command_objClientData(cmd); if (cd != NULL && cd->paramsPtr) { NsfParamDefs localParamDefs; Tcl_Obj *list; localParamDefs.paramsPtr = cd->paramsPtr; /*localParamDefs.nrParams = 1;*/ list = ListParamDefs(interp, localParamDefs.paramsPtr, contextObject, pattern, printStyle); Tcl_SetObjResult(interp, list); DECR_REF_COUNT2("paramDefsObj", list); } else { Tcl_SetObjResult(interp, Tcl_NewStringObj(methodName, TCL_INDEX_NONE)); } return TCL_OK; } /* * In case, we failed so far to obtain a result, try to use the * object-system implementors definitions in the global array * ::nsf::parametersyntax. Note that we can only obtain the * parameter syntax this way. */ if (printStyle == NSF_PARAMS_SYNTAX) { Tcl_DString ds, *dsPtr = &ds; Tcl_Obj *parameterSyntaxObj; Tcl_DStringInit(dsPtr); DStringAppendQualName(dsPtr, Tcl_Command_nsPtr(cmd), methodName); /*fprintf(stderr, "Looking up ::nsf::parametersyntax(%s) ...\n", Tcl_DStringValue(dsPtr));*/ parameterSyntaxObj = Tcl_GetVar2Ex(interp, NsfGlobalStrings[NSF_ARRAY_PARAMETERSYNTAX], Tcl_DStringValue(dsPtr), TCL_GLOBAL_ONLY); /*fprintf(stderr, "No parametersyntax so far methodName %s cmd name %s ns %s\n", methodName, Tcl_GetCommandName(interp, cmd), Tcl_DStringValue(dsPtr));*/ Tcl_DStringFree(dsPtr); if (parameterSyntaxObj != NULL) { Tcl_SetObjResult(interp, parameterSyntaxObj); return TCL_OK; } } if (Tcl_Command_objProc(cmd) == NsfForwardMethod) { result = NsfPrintError(interp, "could not obtain parameter definition for forwarder '%s'", methodName); } else if (CmdIsNsfObject(cmd)) { /* procPtr == NsfObjDispatch: Reached for: ... ensemble objects ... plain objects */ } else if (Tcl_Command_objProc(cmd) == NsfProcStub) { /* * Reached for C-implemented Tcl command procs. */ } else { /* * Reached for other C-implemented command procs. */ result = NsfPrintError(interp, "could not obtain parameter definition for method '%s'", methodName); } return result; } /* *---------------------------------------------------------------------- * AppendForwardDefinition -- * * Append the parameters of a forward definition to the specified listObj. * * Results: * None. * * Side effects: * Appending to listObj * *---------------------------------------------------------------------- */ static void AppendForwardDefinition(Tcl_Interp *interp, Tcl_Obj *listObj, ForwardCmdClientData *tcd) nonnull(1) nonnull(2) nonnull(3); static void AppendForwardDefinition(Tcl_Interp *interp, Tcl_Obj *listObj, ForwardCmdClientData *tcd) { nonnull_assert(interp != NULL); nonnull_assert(listObj != NULL); nonnull_assert(tcd != NULL); if (tcd->prefix != NULL) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-prefix", TCL_INDEX_NONE)); Tcl_ListObjAppendElement(interp, listObj, tcd->prefix); } if (tcd->subcommands != NULL) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-default", TCL_INDEX_NONE)); Tcl_ListObjAppendElement(interp, listObj, tcd->subcommands); } if (tcd->objProc != NULL) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-earlybinding", TCL_INDEX_NONE)); } if (tcd->frame == FrameObjectIdx) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-frame", 6)); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("object", 6)); } Tcl_ListObjAppendElement(interp, listObj, tcd->cmdName); if (tcd->args != NULL) { Tcl_Obj **args; int nrArgs, i; Tcl_ListObjGetElements(interp, tcd->args, &nrArgs, &args); for (i = 0; i < nrArgs; i++) { Tcl_ListObjAppendElement(interp, listObj, args[i]); } } } /* *---------------------------------------------------------------------- * AppendMethodRegistration -- * * Append to the listObj the command words needed for definition / * registration. * * Results: * None. * * Side effects: * Appending to listObj * *---------------------------------------------------------------------- */ static void AppendMethodRegistration(Tcl_Interp *interp, Tcl_Obj *listObj, const char *registerCmdName, NsfObject *object, const char *methodName, Tcl_Command cmd, bool withObjFrame, bool withPer_object, int withProtection) nonnull(1) nonnull(2) nonnull(3) nonnull(4) nonnull(5) nonnull(6); static void AppendMethodRegistration(Tcl_Interp *interp, Tcl_Obj *listObj, const char *registerCmdName, NsfObject *object, const char *methodName, Tcl_Command cmd, bool withObjFrame, bool withPer_object, int withProtection) { nonnull_assert(interp != NULL); nonnull_assert(listObj != NULL); nonnull_assert(registerCmdName != NULL); nonnull_assert(object != NULL); nonnull_assert(methodName != NULL); nonnull_assert(cmd != NULL); Tcl_ListObjAppendElement(interp, listObj, object->cmdName); if (withProtection != CallprotectionNULL) { Tcl_ListObjAppendElement(interp, listObj, (((unsigned int)Tcl_Command_flags(cmd) & NSF_CMD_CALL_PRIVATE_METHOD) != 0) ? Tcl_NewStringObj("private", 7) : (((unsigned int)Tcl_Command_flags(cmd) & NSF_CMD_CALL_PROTECTED_METHOD) != 0) ? Tcl_NewStringObj("protected", 9) : Tcl_NewStringObj("public", 6)); } if (!NsfObjectIsClass(object) || withPer_object) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("object", 6)); } Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(registerCmdName, TCL_INDEX_NONE)); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(methodName, TCL_INDEX_NONE)); if (withObjFrame) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-frame", 6)); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("object", 6)); } if (((unsigned int)Tcl_Command_flags(cmd) & NSF_CMD_NONLEAF_METHOD) != 0) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-frame", 6)); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("method", 6)); } } /* *---------------------------------------------------------------------- * AppendReturnsClause -- * * Append to the listObj a returns clause, if it was specified for * the current cmd. * * Results: * None. * * Side effects: * Appending to listObj * *---------------------------------------------------------------------- */ static void AppendReturnsClause(Tcl_Interp *interp, Tcl_Obj *listObj, Tcl_Command cmd) nonnull(1) nonnull(2) nonnull(3); static void AppendReturnsClause(Tcl_Interp *interp, Tcl_Obj *listObj, Tcl_Command cmd) { Tcl_Obj *returnsObj; nonnull_assert(interp != NULL); nonnull_assert(listObj != NULL); nonnull_assert(cmd != NULL); returnsObj = ParamDefsGetReturns(cmd); if (returnsObj != NULL) { /* TODO: avoid hard-coding the script-level/NX-specific keyword "-returns" */ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-returns", TCL_INDEX_NONE)); Tcl_ListObjAppendElement(interp, listObj, returnsObj); } } static Tcl_Obj *DisassembleProc(Tcl_Interp *interp, Proc *procPtr, const char *procName, Namespace *nsPtr) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static Tcl_Obj *DisassembleProc(Tcl_Interp *interp, Proc *procPtr, const char *procName, Namespace *nsPtr) { unsigned int dummy = 0; Tcl_Obj *byteCodeObj = NULL; if ((procPtr->bodyPtr->typePtr == Nsf_OT_byteCodeType) || (ByteCompiled(interp, &dummy, procPtr, nsPtr, procName) == TCL_OK)) { Tcl_Obj *ov[3]; ov[0] = NULL; ov[1] = NsfGlobalObjs[NSF_SCRIPT]; ov[2] = procPtr->bodyPtr; if ((NsfCallCommand(interp, NSF_DISASSEMBLE, 3, ov) == TCL_OK)) { byteCodeObj = Tcl_GetObjResult(interp); } } return byteCodeObj; } /* *---------------------------------------------------------------------- * ListMethod -- * * Construct a command to regenerate the specified method. The * method might be scripted or not (alias, forwarder, ...). The * command is returned in the interp result. * * Results: * A standard Tcl result. * * Side effects: * Sets the interpreter's result object. * *---------------------------------------------------------------------- */ static int ListMethod(Tcl_Interp *interp, NsfObject *regObject, NsfObject *defObject, const char *methodName, Tcl_Command cmd, InfomethodsubcmdIdx_t subcmd, NsfObject *contextObject, const char *pattern, bool withPer_object) nonnull(1) nonnull(4) nonnull(5); static int ListDefinedMethods(Tcl_Interp *interp, NsfObject *object, const char *pattern, bool withPer_object, MethodtypeIdx_t methodType, CallprotectionIdx_t withCallprotection, bool withPath) nonnull(1) nonnull(2); static int ListMethod(Tcl_Interp *interp, NsfObject *regObject, NsfObject *defObject, const char *methodName, Tcl_Command cmd, InfomethodsubcmdIdx_t subcmd, NsfObject *contextObject, const char *pattern, bool withPer_object) { Tcl_ObjCmdProc *objCmdProc; Proc *procPtr; bool outputPerObject; Tcl_Obj *resultObj; nonnull_assert(interp != NULL); nonnull_assert(methodName != NULL); nonnull_assert(cmd != NULL); assert(*methodName != ':'); Tcl_ResetResult(interp); if (regObject != NULL && !NsfObjectIsClass(regObject)) { withPer_object = 1; /* * Don't output "object" modifier, if regObject is not a class. */ outputPerObject = NSF_FALSE; } else { outputPerObject = withPer_object; } switch (subcmd) { case InfomethodsubcmdRegistrationhandleIdx: { if (regObject != NULL) { Tcl_SetObjResult(interp, MethodHandleObj(regObject, withPer_object, methodName)); } return TCL_OK; } case InfomethodsubcmdDefinitionhandleIdx: { if (defObject != NULL) { Tcl_SetObjResult(interp, MethodHandleObj(defObject, NsfObjectIsClass(defObject) ? withPer_object : 1, Tcl_GetCommandName(interp, cmd))); } return TCL_OK; } case InfomethodsubcmdExistsIdx: { Tcl_SetObjResult(interp, Tcl_NewIntObj((int)(!CmdIsNsfObject(cmd)))); return TCL_OK; } case InfomethodsubcmdArgsIdx: { Tcl_Command importedCmd = GetOriginalCommand(cmd); return ListCmdParams(interp, importedCmd, contextObject, pattern, methodName, NSF_PARAMS_NAMES); } case InfomethodsubcmdParameterIdx: { Tcl_Command importedCmd = GetOriginalCommand(cmd); return ListCmdParams(interp, importedCmd, contextObject, pattern, methodName, NSF_PARAMS_PARAMETER); } case InfomethodsubcmdReturnsIdx: { Tcl_Obj *returnsObj = ParamDefsGetReturns(GetOriginalCommand(cmd)); if (returnsObj != NULL) { Tcl_SetObjResult(interp, returnsObj); } return TCL_OK; } case InfomethodsubcmdSyntaxIdx: { Tcl_Command importedCmd = GetOriginalCommand(cmd); return ListCmdParams(interp, importedCmd, contextObject, pattern, methodName, NSF_PARAMS_SYNTAX); } case InfomethodsubcmdPreconditionIdx: #if defined(NSF_WITH_ASSERTIONS) if (regObject != NULL) { NsfProcAssertion *procs = NULL; if (withPer_object == 1) { if (regObject->opt != NULL && regObject->opt->assertions != NULL) { procs = AssertionFindProcs(regObject->opt->assertions, methodName); } } else { NsfClass *class = (NsfClass *)regObject; if (class->opt != NULL && class->opt->assertions != NULL) { procs = AssertionFindProcs(class->opt->assertions, methodName); } } if (procs != NULL) { Tcl_SetObjResult(interp, AssertionList(interp, procs->pre)); } } #endif return TCL_OK; case InfomethodsubcmdPostconditionIdx: #if defined(NSF_WITH_ASSERTIONS) if (regObject != NULL) { NsfProcAssertion *procs = NULL; if (withPer_object == 1) { if (regObject->opt != NULL && regObject->opt->assertions != NULL) { procs = AssertionFindProcs(regObject->opt->assertions, methodName); } } else { NsfClass *class = (NsfClass *)regObject; if (class->opt != NULL && class->opt->assertions != NULL) { procs = AssertionFindProcs(class->opt->assertions, methodName); } } if (procs != NULL) { Tcl_SetObjResult(interp, AssertionList(interp, procs->post)); } } #endif return TCL_OK; case InfomethodsubcmdSubmethodsIdx: { Tcl_Command origCmd = GetOriginalCommand(cmd); if (CmdIsNsfObject(origCmd)) { NsfObject *subObject = NsfGetObjectFromCmdPtr(origCmd); if (subObject != NULL) { return ListDefinedMethods(interp, subObject, NULL, NSF_TRUE /* per-object */, NSF_METHODTYPE_ALL, CallprotectionAllIdx, NSF_FALSE); } } /* * All other cases return empty. */ Tcl_SetObjResult(interp, NsfGlobalObjs[NSF_EMPTY]); return TCL_OK; } case InfomethodsubcmdBodyIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdOriginIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdTypeIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdDefinitionIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdDisassembleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdNULL: break; } objCmdProc = Tcl_Command_objProc(cmd); procPtr = GetTclProcFromCommand(cmd); /* * The subcommands differ per type of method. The converter in * InfoMethods defines the types: * * all|scripted|builtin|alias|forwarder|object|setter|nsfproc */ if (procPtr != NULL) { /* * A scripted method. */ switch (subcmd) { case InfomethodsubcmdTypeIdx: if (regObject != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj("scripted", TCL_INDEX_NONE)); } else { Tcl_SetObjResult(interp, Tcl_NewStringObj("proc", TCL_INDEX_NONE)); } break; case InfomethodsubcmdBodyIdx: ListProcBody(interp, procPtr); break; case InfomethodsubcmdDisassembleIdx: { Tcl_Namespace *nsPtr; NsfParamDefs *paramDefs; paramDefs = ParamDefsGet(cmd, NULL, &nsPtr); if (paramDefs == NULL || nsPtr == NULL) { nsPtr = (Tcl_Namespace *)procPtr->cmdPtr->nsPtr; } resultObj = DisassembleProc(interp, procPtr, methodName, (Namespace *)nsPtr); if (resultObj != NULL) { Tcl_SetObjResult(interp, resultObj); } } break; case InfomethodsubcmdDefinitionIdx: { resultObj = Tcl_NewListObj(0, NULL); /* todo: don't hard-code registering command name "method" / NSF_METHOD */ if (regObject != NULL) { AppendMethodRegistration(interp, resultObj, NsfGlobalStrings[NSF_METHOD], regObject, methodName, cmd, NSF_FALSE, outputPerObject, 1); } else { Tcl_DString ds, *dsPtr = &ds; Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("::proc", TCL_INDEX_NONE)); Tcl_DStringInit(dsPtr); DStringAppendQualName(dsPtr, Tcl_Command_nsPtr(cmd), methodName); Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(Tcl_DStringValue(dsPtr), Tcl_DStringLength(dsPtr))); Tcl_DStringFree(dsPtr); } ListCmdParams(interp, cmd, contextObject, NULL, methodName, NSF_PARAMS_PARAMETER); Tcl_ListObjAppendElement(interp, resultObj, Tcl_GetObjResult(interp)); AppendReturnsClause(interp, resultObj, cmd); ListProcBody(interp, procPtr); Tcl_ListObjAppendElement(interp, resultObj, Tcl_GetObjResult(interp)); #if defined(NSF_WITH_ASSERTIONS) if (regObject != NULL) { NsfAssertionStore *assertions; if (withPer_object == 1) { assertions = (regObject->opt != NULL) ? regObject->opt->assertions : NULL; } else { NsfClass *class = (NsfClass *)regObject; assertions = (class->opt != NULL) ? class->opt->assertions : NULL; } if (assertions != NULL) { NsfProcAssertion *procs = AssertionFindProcs(assertions, methodName); if (procs != NULL) { Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("-precondition", TCL_INDEX_NONE)); Tcl_ListObjAppendElement(interp, resultObj, AssertionList(interp, procs->pre)); Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("-postcondition", TCL_INDEX_NONE)); Tcl_ListObjAppendElement(interp, resultObj, AssertionList(interp, procs->post)); } } } #endif Tcl_SetObjResult(interp, resultObj); break; } case InfomethodsubcmdArgsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdDefinitionhandleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdExistsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdOriginIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdParameterIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdPostconditionIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdPreconditionIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdRegistrationhandleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdReturnsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdSubmethodsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdSyntaxIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdNULL: break; } } else if (objCmdProc == NsfForwardMethod) { /* * The command is a forwarder. */ switch (subcmd) { case InfomethodsubcmdTypeIdx: Tcl_SetObjResult(interp, NsfGlobalObjs[NSF_FORWARD]); break; case InfomethodsubcmdDefinitionIdx: if (regObject != NULL) { ClientData clientData; clientData = Tcl_Command_objClientData(cmd); if (clientData != NULL) { resultObj = Tcl_NewListObj(0, NULL); /* todo: don't hard-code registering command name "forward" / NSF_FORWARD*/ AppendMethodRegistration(interp, resultObj, NsfGlobalStrings[NSF_FORWARD], regObject, methodName, cmd, NSF_FALSE, outputPerObject, 1); AppendReturnsClause(interp, resultObj, cmd); AppendForwardDefinition(interp, resultObj, clientData); Tcl_SetObjResult(interp, resultObj); } } break; case InfomethodsubcmdArgsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdBodyIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdDefinitionhandleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdExistsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdOriginIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdParameterIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdPostconditionIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdPreconditionIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdRegistrationhandleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdReturnsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdSubmethodsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdSyntaxIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdDisassembleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdNULL: break; } } else if (objCmdProc == NsfSetterMethod) { /* * The cmd is one of the setter methods. */ switch (subcmd) { case InfomethodsubcmdTypeIdx: Tcl_SetObjResult(interp, NsfGlobalObjs[NSF_SETTER]); break; case InfomethodsubcmdDefinitionIdx: if (regObject != NULL) { SetterCmdClientData *cd = (SetterCmdClientData *)Tcl_Command_objClientData(cmd); resultObj = Tcl_NewListObj(0, NULL); /* todo: don't hard-code registering command name "setter" / NSF_SETTER */ AppendMethodRegistration(interp, resultObj, NsfGlobalStrings[NSF_SETTER], regObject, (cd != NULL && cd->paramsPtr) ? ObjStr(cd->paramsPtr->paramObj) : methodName, cmd, NSF_FALSE, outputPerObject, 1); Tcl_SetObjResult(interp, resultObj); } break; case InfomethodsubcmdArgsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdBodyIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdDefinitionhandleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdExistsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdOriginIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdParameterIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdPostconditionIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdPreconditionIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdRegistrationhandleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdReturnsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdSubmethodsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdSyntaxIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdDisassembleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdNULL: break; } } else if (objCmdProc == NsfProcStub) { /* * Special nsfproc handling: */ NsfProcClientData *tcd = Tcl_Command_objClientData(cmd); if (tcd != NULL && tcd->procName) { Tcl_Command procCmd = Tcl_GetCommandFromObj(interp, tcd->procName); Proc *tProcPtr = GetTclProcFromCommand(procCmd); Tcl_DString ds, *dsPtr = &ds; switch (subcmd) { case InfomethodsubcmdTypeIdx: Tcl_SetObjResult(interp, Tcl_NewStringObj("nsfproc", TCL_INDEX_NONE)); break; case InfomethodsubcmdBodyIdx: ListProcBody(interp, tProcPtr); break; case InfomethodsubcmdDefinitionIdx: resultObj = Tcl_NewListObj(0, NULL); Tcl_DStringInit(dsPtr); DStringAppendQualName(dsPtr, Tcl_Command_nsPtr(cmd), methodName); /* don't hardcode names */ Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("::nsf::proc", TCL_INDEX_NONE)); if ((tcd->flags & NSF_PROC_FLAG_AD) != 0) { Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("-ad", 3)); } if (((unsigned int)Tcl_Command_flags(tcd->wrapperCmd) & NSF_CMD_DEBUG_METHOD) != 0) { Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("-debug", 6)); } if (((unsigned int)Tcl_Command_flags(tcd->wrapperCmd) & NSF_CMD_DEPRECATED_METHOD) != 0) { Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("-deprecated", 11)); } Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(Tcl_DStringValue(dsPtr), Tcl_DStringLength(dsPtr))); ListCmdParams(interp, cmd, NULL, NULL, Tcl_DStringValue(dsPtr), NSF_PARAMS_PARAMETER); Tcl_ListObjAppendElement(interp, resultObj, Tcl_GetObjResult(interp)); ListProcBody(interp, tProcPtr); Tcl_ListObjAppendElement(interp, resultObj, Tcl_GetObjResult(interp)); Tcl_SetObjResult(interp, resultObj); Tcl_DStringFree(dsPtr); break; case InfomethodsubcmdDisassembleIdx: resultObj = DisassembleProc(interp, tProcPtr, methodName, tProcPtr->cmdPtr->nsPtr); if (resultObj != NULL) { Tcl_SetObjResult(interp, resultObj); } break; case InfomethodsubcmdArgsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdDefinitionhandleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdExistsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdOriginIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdParameterIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdPostconditionIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdPreconditionIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdRegistrationhandleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdReturnsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdSubmethodsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdSyntaxIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdNULL: break; } } } else if (defObject != NULL) { /* * The cmd must be an alias or object. * * Note that some aliases come with objCmdProc == NsfObjDispatch. In order * to distinguish between "object" and alias, we have to do the lookup for * the entryObj to determine whether it is really an alias. */ Tcl_Obj *entryObj; entryObj = AliasGet(interp, defObject->cmdName, Tcl_GetCommandName(interp, cmd), regObject != defObject ? NSF_TRUE : withPer_object, NSF_FALSE); /* fprintf(stderr, "aliasGet %s -> %s/%s (%d) returned %p\n", ObjectName(defObject), methodName, Tcl_GetCommandName(interp, cmd), withPer_object, entryObj); fprintf(stderr, "... regObject %p %s\n", regObject, ObjectName(regObject)); fprintf(stderr, "... defObject %p %s\n", defObject, ObjectName(defObject)); */ if (entryObj != NULL) { /* * The entry is an alias. */ switch (subcmd) { case InfomethodsubcmdTypeIdx: Tcl_SetObjResult(interp, NsfGlobalObjs[NSF_ALIAS]); break; case InfomethodsubcmdDefinitionIdx: if (regObject != NULL) { int nrElements; Tcl_Obj **listElements; resultObj = Tcl_NewListObj(0, NULL); Tcl_ListObjGetElements(interp, entryObj, &nrElements, &listElements); /* todo: don't hard-code registering command name "alias" / NSF_ALIAS */ AppendMethodRegistration(interp, resultObj, NsfGlobalStrings[NSF_ALIAS], regObject, methodName, cmd, objCmdProc == NsfObjscopedMethod, outputPerObject, 1); AppendReturnsClause(interp, resultObj, cmd); Tcl_ListObjAppendElement(interp, resultObj, listElements[nrElements-1]); Tcl_SetObjResult(interp, resultObj); } break; case InfomethodsubcmdOriginIdx: { int nrElements; Tcl_Obj **listElements; Tcl_ListObjGetElements(interp, entryObj, &nrElements, &listElements); Tcl_SetObjResult(interp, listElements[nrElements-1]); break; } case InfomethodsubcmdArgsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdBodyIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdDefinitionhandleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdExistsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdParameterIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdPostconditionIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdPreconditionIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdRegistrationhandleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdReturnsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdSubmethodsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdSyntaxIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdDisassembleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdNULL: break; } } else { /* * Check if the command is and nsfObject to be on the safe side. */ if (CmdIsNsfObject(cmd)) { /* * The command is an object. */ switch (subcmd) { case InfomethodsubcmdTypeIdx: Tcl_SetObjResult(interp, Tcl_NewStringObj("object", TCL_INDEX_NONE)); break; case InfomethodsubcmdDefinitionIdx: { NsfObject *subObject = NsfGetObjectFromCmdPtr(cmd); assert(subObject != NULL); resultObj = Tcl_NewListObj(0, NULL); AppendMethodRegistration(interp, resultObj, "create", &(subObject->cl)->object, ObjStr(subObject->cmdName), cmd, NSF_FALSE, NSF_FALSE, 0); Tcl_SetObjResult(interp, resultObj); break; } case InfomethodsubcmdArgsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdBodyIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdDefinitionhandleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdExistsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdParameterIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdPostconditionIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdPreconditionIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdRegistrationhandleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdReturnsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdSubmethodsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdSyntaxIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdOriginIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdDisassembleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdNULL: break; } } else { /* * Should never happen. * * The warning is just a guess, so we don't raise an error here. */ NsfLog(interp, NSF_LOG_WARN, "Could not obtain alias definition for %s. " "Maybe someone deleted the alias %s for object %s?", methodName, methodName, ObjectName(regObject)); Tcl_ResetResult(interp); } } } else { /* * The cmd must be a plain unregistered cmd */ switch (subcmd) { case InfomethodsubcmdTypeIdx: Tcl_SetObjResult(interp, NsfGlobalObjs[NSF_CMD]); break; case InfomethodsubcmdDefinitionIdx: break; case InfomethodsubcmdOriginIdx: break; case InfomethodsubcmdArgsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdBodyIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdDefinitionhandleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdExistsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdParameterIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdPostconditionIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdPreconditionIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdRegistrationhandleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdReturnsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdSubmethodsIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdSyntaxIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdDisassembleIdx: ;NSF_FALL_THROUGH; /* fall through */ case InfomethodsubcmdNULL: break; } } return TCL_OK; } /* *---------------------------------------------------------------------- * ListMethodResolve -- * * Call essentially ListMethod(), but try to resolve the method * name/handle first. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ListMethodResolve(Tcl_Interp *interp, InfomethodsubcmdIdx_t subcmd, NsfObject *contextObject, const char *pattern, Tcl_Namespace *nsPtr, NsfObject *object, Tcl_Obj *methodNameObj, bool fromClassNS) nonnull(1) nonnull(7); static int ListMethodResolve(Tcl_Interp *interp, InfomethodsubcmdIdx_t subcmd, NsfObject *contextObject, const char *pattern, Tcl_Namespace *nsPtr, NsfObject *object, Tcl_Obj *methodNameObj, bool fromClassNS) { NsfObject *regObject, *defObject; const char *methodName1 = NULL; int result = TCL_OK; Tcl_DString ds, *dsPtr = &ds; Tcl_Command cmd; nonnull_assert(interp != NULL); nonnull_assert(methodNameObj != NULL); Tcl_DStringInit(dsPtr); cmd = ResolveMethodName(interp, nsPtr, methodNameObj, dsPtr, ®Object, &defObject, &methodName1, &fromClassNS); /* * If the cmd is NOT found, we return empty, unless for the sub-command * "exists", we return TCL_ERROR. */ if (likely(cmd != NULL)) { result = ListMethod(interp, (regObject != NULL) ? regObject : object, (defObject != NULL) ? defObject : object, methodName1, cmd, subcmd, contextObject, pattern, (fromClassNS == 0)); } else if (subcmd == InfomethodsubcmdExistsIdx) { Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); } Tcl_DStringFree(dsPtr); return result; } /* *---------------------------------------------------------------------- * MethodSourceMatches -- * * Check, whether the provided class or object (mutually exclusive) * matches with the required method source (typically * all|application|system). * * Results: * Returns boolean * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool MethodSourceMatches(DefinitionsourceIdx_t withSource, NsfClass *class, NsfObject *object) NSF_pure; static bool MethodSourceMatches(DefinitionsourceIdx_t withSource, NsfClass *class, NsfObject *object) { bool result; if (withSource == DefinitionsourceAllIdx) { result = NSF_TRUE; } else if (class == NULL) { /* * If the method is object specific, it can't be from a baseclass and must * be application specific. */ assert(object != NULL); result = (withSource == DefinitionsourceApplicationIdx && !IsBaseClass(object)); } else { bool isBaseClass; assert(class != NULL); isBaseClass = IsBaseClass(&class->object); if (withSource == DefinitionsourceSystemIdx && isBaseClass) { result = NSF_TRUE; } else if (withSource == DefinitionsourceApplicationIdx && !isBaseClass) { result = NSF_TRUE; } else { result = NSF_FALSE; } } return result; } /* *---------------------------------------------------------------------- * MethodTypeMatches -- * * Check, whether the provided method (specified as a cmd) matches * with the required method type (typically * all|scripted|builtin|alias|forwarder|object|setter). * * Results: * Returns Boolean value * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool MethodTypeMatches(Tcl_Interp *interp, MethodtypeIdx_t methodType, Tcl_Command cmd, NsfObject *object, const char *methodName, int withPer_object, bool *isObject) nonnull(1) nonnull(3) nonnull(5) nonnull(7); static bool MethodTypeMatches(Tcl_Interp *interp, MethodtypeIdx_t methodType, Tcl_Command cmd, NsfObject *object, const char *methodName, int withPer_object, bool *isObject) { Tcl_ObjCmdProc *proc; Tcl_Command importedCmd; nonnull_assert(interp != NULL); nonnull_assert(cmd != NULL); nonnull_assert(methodName != NULL); nonnull_assert(isObject != NULL); proc = Tcl_Command_objProc(cmd); importedCmd = GetOriginalCommand(cmd); /* * Return always state isObject, since the cmd might be an ensemble, * where we have to search further. */ *isObject = CmdIsNsfObject(importedCmd); if (methodType == NSF_METHODTYPE_ALIAS) { if (!(proc == NsfProcAliasMethod || AliasGet(interp, object->cmdName, methodName, withPer_object, NSF_FALSE)) ) { return NSF_FALSE; } } else { Tcl_ObjCmdProc *resolvedProc; if (proc == NsfProcAliasMethod) { if ((methodType & NSF_METHODTYPE_ALIAS) == 0) { return NSF_FALSE; } } resolvedProc = Tcl_Command_objProc(importedCmd); /* * The following cases are disjoint. */ if (CmdIsProc(importedCmd)) { /*fprintf(stderr, "%s scripted %d\n", methodName, methodType & NSF_METHODTYPE_SCRIPTED);*/ if ((methodType & NSF_METHODTYPE_SCRIPTED) == 0) { return NSF_FALSE; } } else if (resolvedProc == NsfForwardMethod) { if ((methodType & NSF_METHODTYPE_FORWARDER) == 0) { return NSF_FALSE; } } else if (resolvedProc == NsfSetterMethod) { if ((methodType & NSF_METHODTYPE_SETTER) == 0) { return NSF_FALSE; } } else if (*isObject) { if ((methodType & NSF_METHODTYPE_OBJECT) == 0) { return NSF_FALSE; } } else if (resolvedProc == NsfProcStub) { if ((methodType & NSF_METHODTYPE_NSFPROC) == 0) { return NSF_FALSE; } } else if ((methodType & NSF_METHODTYPE_OTHER) == 0) { /* fprintf(stderr, "OTHER %s not wanted %.4x\n", methodName, methodType);*/ return NSF_FALSE; } /* NsfObjscopedMethod ??? */ } return NSF_TRUE; } /* *---------------------------------------------------------------------- * ProtectionMatches -- * * Check, whether the provided method (specified as a cmd) matches * with the required call-protection (typically * all|public|protected|private). * * Results: * Returns boolean * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool ProtectionMatches(CallprotectionIdx_t withCallprotection, Tcl_Command cmd) nonnull(2) NSF_pure; static bool ProtectionMatches(CallprotectionIdx_t withCallprotection, Tcl_Command cmd) { int result; bool isProtected, isPrivate; unsigned int cmdFlags; nonnull_assert(cmd != NULL); cmdFlags = (unsigned int)Tcl_Command_flags(cmd); isProtected = ((cmdFlags & NSF_CMD_CALL_PROTECTED_METHOD) != 0u); isPrivate = ((cmdFlags & NSF_CMD_CALL_PRIVATE_METHOD) != 0u); if (withCallprotection == CallprotectionNULL) { withCallprotection = CallprotectionPublicIdx; } switch (withCallprotection) { case CallprotectionAllIdx: result = NSF_TRUE; break; case CallprotectionPublicIdx: result = (isProtected == 0); break; case CallprotectionProtectedIdx: result = (isProtected && !isPrivate); break; case CallprotectionPrivateIdx: result = isPrivate; break; case CallprotectionNULL: result = NSF_TRUE; break; default: result = NSF_FALSE; break; } return result; } /* *---------------------------------------------------------------------- * * ListMethodKeys -- * * List the method names contained in the specified hash-table * according to the filtering options (types, pattern, * protection, etc.). Optionally, a name prefix can be provided * in form of a Tcl_DString. The result is placed into the interp * result. * * Results: * A standard Tcl result. * * Side effects: * Sets the interpreter's result object. * *---------------------------------------------------------------------- */ static int ListMethodKeys(Tcl_Interp *interp, Tcl_HashTable *tablePtr, Tcl_DString *prefix, const char *pattern, MethodtypeIdx_t methodType, CallprotectionIdx_t withCallprotection, bool withPath, Tcl_HashTable *dups, NsfObject *object, bool withPer_object) nonnull(1) nonnull(2); static int ListMethodKeys(Tcl_Interp *interp, Tcl_HashTable *tablePtr, Tcl_DString *prefix, const char *pattern, MethodtypeIdx_t methodType, CallprotectionIdx_t withCallprotection, bool withPath, Tcl_HashTable *dups, NsfObject *object, bool withPer_object) { Tcl_HashSearch hSrch; const Tcl_HashEntry *hPtr; Tcl_Command cmd; const char *key; bool isObject, methodTypeMatch; Tcl_Obj *resultObj; nonnull_assert(interp != NULL); nonnull_assert(tablePtr != NULL); resultObj = Tcl_GetObjResult(interp); if (pattern != NULL && NoMetaChars(pattern) && strchr(pattern, ' ') == NULL) { /* * We have a pattern that can be used for direct lookup; no need * to iterate. */ hPtr = Tcl_CreateHashEntry(tablePtr, pattern, NULL); if (hPtr != NULL) { NsfObject *childObject; Tcl_Command origCmd; key = Tcl_GetHashKey(tablePtr, hPtr); cmd = (Tcl_Command)Tcl_GetHashValue(hPtr); methodTypeMatch = MethodTypeMatches(interp, methodType, cmd, object, key, withPer_object, &isObject); if (((unsigned int)Tcl_Command_flags(cmd) & NSF_CMD_CLASS_ONLY_METHOD) != 0u && !NsfObjectIsClass(object)) { return TCL_OK; } /* * Aliased objects methods return NSF_TRUE but lookup from cmd returns * NULL. Below, we are just interested on true sub-objects. */ origCmd = GetOriginalCommand(cmd); childObject = (isObject) ? NsfGetObjectFromCmdPtr(origCmd) : NULL; if (childObject != NULL && withPath) { return TCL_OK; } if (ProtectionMatches(withCallprotection, cmd) && methodTypeMatch) { TCL_SIZE_T prefixLength = (prefix != NULL) ? Tcl_DStringLength(prefix) : 0; if (prefixLength != 0) { Tcl_DStringAppend(prefix, key, TCL_INDEX_NONE); key = Tcl_DStringValue(prefix); } if (dups != NULL) { int new; (void)Tcl_CreateHashEntry(dups, key, &new); if (new != 0) { Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(key, TCL_INDEX_NONE)); } } else { Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(key, TCL_INDEX_NONE)); } } } return TCL_OK; } else { size_t prefixLength = (prefix != NULL) ? (size_t)Tcl_DStringLength(prefix) : 0u; /* * We have to iterate over the elements. */ for (hPtr = Tcl_FirstHashEntry(tablePtr, &hSrch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { NsfObject *childObject = NULL, *directObject = NULL; Tcl_Command origCmd; key = Tcl_GetHashKey(tablePtr, hPtr); cmd = (Tcl_Command)Tcl_GetHashValue(hPtr); if (prefixLength != 0) { Tcl_DStringSetLength(prefix, (TCL_SIZE_T)prefixLength); } methodTypeMatch = MethodTypeMatches(interp, methodType, cmd, object, key, withPer_object, &isObject); /* * Aliased objects methods return NSF_TRUE but lookup from cmd returns * NULL. Below, we are just interested on true sub-objects. */ origCmd = GetOriginalCommand(cmd); if (isObject) { childObject = NsfGetObjectFromCmdPtr(origCmd); directObject = NsfGetObjectFromCmdPtr(cmd); } /*fprintf(stderr, "key <%s> isObject %d childObject %p directo %p ensemble %d prefixl %d ali %d ali2 %d hasChild %d\n", key, isObject, (void*)childObject,(void*)directObject, childObject ? ((childObject->flags & NSF_KEEP_CALLER_SELF) != 0u) : 0, prefixLength, Tcl_Command_objProc(cmd) == NsfProcAliasMethod, childObject ? AliasGet(interp, childObject->cmdName, key, withPer_object, NSF_FALSE) != NULL : 0, childObject ? (childObject->nsPtr == NULL) : 0 );*/ if (childObject != NULL) { /* * If we have a child object, check if we have an ensemble method, * which we detect on the flag NSF_KEEP_CALLER_SELF. */ if (withPath && ((childObject->flags & NSF_KEEP_CALLER_SELF) != 0u) && ((childObject->flags & NSF_PER_OBJECT_DISPATCH) != 0u) ) { Tcl_HashTable *cmdTablePtr; if (childObject->nsPtr == NULL) { /* * Nothing to do. */ continue; } cmdTablePtr = Tcl_Namespace_cmdTablePtr(childObject->nsPtr); if (cmdTablePtr == NULL) { /* * Nothing to do. */ continue; } if ((childObject->flags & NSF_IS_SLOT_CONTAINER) != 0u) { /* * Don't report slot container. */ continue; } if ((childObject->flags & NSF_KEEP_CALLER_SELF) == 0u) { /* * Do only report sub-objects with keep caller self. */ continue; } /*fprintf(stderr, "ListMethodKeys key %s append key space flags %.6x\n", key, childObject->flags);*/ if (prefix == NULL) { Tcl_DString ds, *dsPtr = &ds; DSTRING_INIT(dsPtr); Tcl_DStringAppend(dsPtr, key, TCL_INDEX_NONE); Tcl_DStringAppend(dsPtr, " ", 1); ListMethodKeys(interp, cmdTablePtr, dsPtr, pattern, methodType, withCallprotection, NSF_TRUE, dups, object, withPer_object); DSTRING_FREE(dsPtr); } else { Tcl_DStringAppend(prefix, key, TCL_INDEX_NONE); Tcl_DStringAppend(prefix, " ", 1); ListMethodKeys(interp, cmdTablePtr, prefix, pattern, methodType, withCallprotection, NSF_TRUE, dups, object, withPer_object); } /* * Don't list ensembles by themselves. */ continue; } if ((childObject->flags & NSF_IS_SLOT_CONTAINER) != 0u) { /* * Don't report slot container. */ continue; } if (withPath && directObject != NULL) { /* * Don't report direct children when "-path" was requested */ continue; } #if 0 if (!withPath && directObject != NULL) { /* * Don't report true child objects if no "-path" was requested, * unless these are from ensemble methods. */ if (!( ((childObject->flags & NSF_KEEP_CALLER_SELF) != 0u) && ((childObject->flags & NSF_PER_OBJECT_DISPATCH) != 0u) )) { continue; } } #endif } if (((unsigned int)Tcl_Command_flags(cmd) & NSF_CMD_CLASS_ONLY_METHOD) != 0u && !NsfObjectIsClass(object) ) { continue; } if (!ProtectionMatches(withCallprotection, cmd) || (!methodTypeMatch)) { continue; } if (prefixLength != 0) { Tcl_DStringAppend(prefix, key, TCL_INDEX_NONE); key = Tcl_DStringValue(prefix); } if (pattern != NULL && !Tcl_StringMatch(key, pattern)) { continue; } if (dups != NULL) { int new; Tcl_CreateHashEntry(dups, key, &new); if (new == 0) { continue; } } Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(key, TCL_INDEX_NONE)); } } /*fprintf(stderr, "listkeys returns '%s'\n", ObjStr(Tcl_GetObjResult(interp)));*/ return TCL_OK; } /* *---------------------------------------------------------------------- * * ListChildren -- * * List the children of the specified object. The result can be * filtered via a pattern or a type. * * Results: * A standard Tcl result. * * Side effects: * Sets the interpreter's result object. * *---------------------------------------------------------------------- */ static int ListChildren( Tcl_Interp *interp, NsfObject *object, const char *pattern, bool classesOnly, NsfClass *typeClass ) nonnull(1) nonnull(2); static int ListChildren( Tcl_Interp *interp, NsfObject *object, const char *pattern, bool classesOnly, NsfClass *typeClass ) { NsfObject *childObject; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); if (object->nsPtr == NULL) { return TCL_OK; } if (pattern != NULL && NoMetaChars(pattern)) { Tcl_DString ds, *dsPtr = &ds; Tcl_DStringInit(dsPtr); if (*pattern != ':') { /* * Build a fully qualified name. */ DStringAppendQualName(dsPtr, object->nsPtr, pattern); pattern = Tcl_DStringValue(dsPtr); } if ((childObject = GetObjectFromString(interp, pattern)) && (!classesOnly || NsfObjectIsClass(childObject)) && ((typeClass == NULL) || IsSubType(childObject->cl, typeClass)) && (Tcl_Command_nsPtr(childObject->id) == object->nsPtr) /* true children */ ) { Tcl_SetObjResult(interp, childObject->cmdName); } else { Tcl_SetObjResult(interp, NsfGlobalObjs[NSF_EMPTY]); } Tcl_DStringFree(dsPtr); } else { Tcl_Obj *list = Tcl_NewListObj(0, NULL); Tcl_HashSearch hSrch; Tcl_HashTable *cmdTablePtr = Tcl_Namespace_cmdTablePtr(object->nsPtr); const Tcl_HashEntry *hPtr; for (hPtr = Tcl_FirstHashEntry(cmdTablePtr, &hSrch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { const char *key = Tcl_GetHashKey(cmdTablePtr, hPtr); if (pattern == NULL || Tcl_StringMatch(key, pattern)) { Tcl_Command cmd = (Tcl_Command)Tcl_GetHashValue(hPtr); /*fprintf(stderr, "... check %s child key %s child object %p %p\n", ObjectName(object), key, GetObjectFromString(interp, key), NsfGetObjectFromCmdPtr(cmd));*/ if ((childObject = NsfGetObjectFromCmdPtr(cmd)) && (!classesOnly || NsfObjectIsClass(childObject)) && ((typeClass == NULL) || IsSubType(childObject->cl, typeClass)) && (Tcl_Command_nsPtr(childObject->id) == object->nsPtr) /* true children */ ) { Tcl_ListObjAppendElement(interp, list, childObject->cmdName); } } } Tcl_SetObjResult(interp, list); } return TCL_OK; } /* *---------------------------------------------------------------------- * * ListForward -- * * List registered forwarder defined in the hash table. The result * can be filtered via a pattern, optionally the forward definition * is returned. * * Results: * A standard Tcl result. * * Side effects: * Sets the interpreter's result object. * *---------------------------------------------------------------------- */ static int ListForward(Tcl_Interp *interp, Tcl_HashTable *tablePtr, const char *pattern, int withDefinition) nonnull(1) nonnull(2); static int ListForward(Tcl_Interp *interp, Tcl_HashTable *tablePtr, const char *pattern, int withDefinition) { nonnull_assert(interp != NULL); nonnull_assert(tablePtr != NULL); if (withDefinition != 0) { const Tcl_HashEntry *hPtr = (pattern != NULL) ? Tcl_CreateHashEntry(tablePtr, pattern, NULL) : NULL; /* * Notice: we don't use pattern for wildcard matching here; pattern can * only contain wildcards when used without "-definition". */ if (hPtr != NULL) { Tcl_Command cmd = (Tcl_Command)Tcl_GetHashValue(hPtr); ClientData clientData = (cmd != NULL) ? Tcl_Command_objClientData(cmd) : NULL; ForwardCmdClientData *tcd = (ForwardCmdClientData *)clientData; if (tcd != NULL && Tcl_Command_objProc(cmd) == NsfForwardMethod) { Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); AppendForwardDefinition(interp, listObj, tcd); Tcl_SetObjResult(interp, listObj); return TCL_OK; } } return NsfPrintError(interp, "'%s' is not a forwarder", pattern); } return ListMethodKeys(interp, tablePtr, NULL, pattern, NSF_METHODTYPE_FORWARDER, CallprotectionAllIdx, NSF_FALSE, NULL, NULL, NSF_FALSE); } /* *---------------------------------------------------------------------- * * ListDefinedMethods -- * * List the methods defined by the specified object/class * according to the filtering options (types, pattern, * protection, etc.). The result is placed into the interp * result. * * Results: * A standard Tcl result. * * Side effects: * Sets the interpreter's result object. * *---------------------------------------------------------------------- */ static int ListDefinedMethods(Tcl_Interp *interp, NsfObject *object, const char *pattern, bool withPer_object, MethodtypeIdx_t methodType, CallprotectionIdx_t withCallprotection, bool withPath) { Tcl_HashTable *cmdTablePtr; Tcl_DString ds, *dsPtr = NULL; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); if (pattern != NULL && *pattern == ':' && *(pattern + 1) == ':') { Namespace *nsPtr, *dummy1Ptr, *dummy2Ptr; const char *remainder; /*fprintf(stderr, "we have a colon pattern '%s' methodtype %.6x\n", pattern, methodType);*/ TclGetNamespaceForQualName(interp, pattern, NULL, 0, &nsPtr, &dummy1Ptr, &dummy2Ptr, &remainder); /*fprintf(stderr, "TclGetNamespaceForQualName with %s => (%p %s) (%p %s) (%p %s) (%p %s)\n", pattern, nsPtr, (nsPtr != NULL) ? nsPtr->fullName : "", dummy1Ptr, (dummy1Ptr != NULL) ? dummy1Ptr->fullName : "", dummy2Ptr, (dummy2Ptr != NULL) ? dummy2Ptr->fullName : "", remainder, (remainder != 0) ? remainder : "");*/ if (nsPtr != NULL) { cmdTablePtr = Tcl_Namespace_cmdTablePtr(nsPtr); dsPtr = &ds; Tcl_DStringInit(dsPtr); Tcl_DStringAppend(dsPtr, nsPtr->fullName, TCL_INDEX_NONE); if (Tcl_DStringLength(dsPtr) > 2) { Tcl_DStringAppend(dsPtr, "::", 2); } pattern = remainder; } else { cmdTablePtr = NULL; } } else if (NsfObjectIsClass(object) && !withPer_object) { cmdTablePtr = Tcl_Namespace_cmdTablePtr(((NsfClass *)object)->nsPtr); } else { cmdTablePtr = (object->nsPtr != NULL) ? Tcl_Namespace_cmdTablePtr(object->nsPtr) : NULL; } if (cmdTablePtr != NULL) { ListMethodKeys(interp, cmdTablePtr, dsPtr, pattern, methodType, withCallprotection, withPath, NULL, object, withPer_object); if (dsPtr != NULL) { Tcl_DStringFree(dsPtr); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * ListSuperClasses -- * * List the superclasses of a class. Optionally the transitive * closure is computed and the result can be filtered via a * pattern. * * Results: * A standard Tcl result. * * Side effects: * Sets the interpreter's result object. * *---------------------------------------------------------------------- */ static int ListSuperClasses(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *pattern, bool withClosure) nonnull(1) nonnull(2); static int ListSuperClasses(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *pattern, bool withClosure) { nonnull_assert(interp != NULL); nonnull_assert(class != NULL); if (class->super != NULL) { NsfObject *matchObject = NULL; Tcl_Obj *outObjPtr, *patternObj = NULL; const char *patternString = NULL; ClientData clientData; bool found; if (pattern != NULL && ConvertToObjpattern(interp, pattern, NULL, &clientData, &outObjPtr) == TCL_OK ) { patternObj = (Tcl_Obj *)clientData; if (GetMatchObject(interp, patternObj, pattern, &matchObject, &patternString) == -1) { /* * The pattern has no meta chars and does not correspond to an existing * object. Therefore, it can't be a superclass. */ if (patternObj != NULL) { DECR_REF_COUNT2("patternObj", patternObj); } return TCL_OK; } } if (withClosure) { NsfClasses *pl = PrecedenceOrder(class); if (pl != NULL) { pl = pl->nextPtr; } found = AppendMatchingElementsFromClasses(interp, pl, patternString, matchObject); } else { NsfClasses *clSuper = NsfReverseClasses(class->super); found = AppendMatchingElementsFromClasses(interp, clSuper, patternString, matchObject); NsfClassListFree(clSuper); } if (matchObject != NULL) { Tcl_SetObjResult(interp, found ? matchObject->cmdName : NsfGlobalObjs[NSF_EMPTY]); } if (patternObj != NULL) { DECR_REF_COUNT2("patternObj", patternObj); } } return TCL_OK; } /******************************** * End result setting commands ********************************/ /* *---------------------------------------------------------------------- * * AliasIndex -- * * The alias index is an internal data structure keeping track of * constructing aliases. This function computes the key of the index. * * Results: * Returns a fresh Tcl_Obj. The caller is responsible for refcounting. * * Side effects: * updating DString * *---------------------------------------------------------------------- */ static Tcl_Obj *AliasIndex(Tcl_Obj *cmdName, const char *methodName, bool withPer_object) nonnull(1) nonnull(2) returns_nonnull; static Tcl_Obj * AliasIndex(Tcl_Obj *cmdName, const char *methodName, bool withPer_object) { Tcl_DString ds, *dsPtr = &ds; Tcl_Obj *resultObj; nonnull_assert(cmdName != NULL); nonnull_assert(methodName != NULL); Tcl_DStringInit(dsPtr); Tcl_DStringAppend(dsPtr, ObjStr(cmdName), TCL_INDEX_NONE); Tcl_DStringAppend(dsPtr, ",", 1); Tcl_DStringAppend(dsPtr, methodName, TCL_INDEX_NONE); if (withPer_object) { Tcl_DStringAppend(dsPtr, ",1", 2); } else { Tcl_DStringAppend(dsPtr, ",0", 2); } /*fprintf(stderr, "AI %s\n", Tcl_DStringValue(dsPtr));*/ resultObj = Tcl_NewStringObj(dsPtr->string, dsPtr->length); Tcl_DStringFree(dsPtr); return resultObj; } /* *---------------------------------------------------------------------- * * AliasAdd -- * * Add an alias to the alias index * * Results: * A standard Tcl result. * * Side effects: * Adding value to the hidden associated array. * *---------------------------------------------------------------------- */ static int AliasAdd(Tcl_Interp *interp, Tcl_Obj *cmdName, const char *methodName, bool withPer_object, Tcl_Obj *cmdObj) nonnull(1) nonnull(2) nonnull(3) nonnull(5); static int AliasAdd(Tcl_Interp *interp, Tcl_Obj *cmdName, const char *methodName, bool withPer_object, Tcl_Obj *cmdObj) { Tcl_Obj *indexObj; nonnull_assert(interp != NULL); nonnull_assert(cmdName != NULL); nonnull_assert(methodName != NULL); nonnull_assert(cmdObj != NULL); indexObj = AliasIndex(cmdName, methodName, withPer_object); INCR_REF_COUNT(indexObj); Tcl_ObjSetVar2(interp, NsfGlobalObjs[NSF_ARRAY_ALIAS], indexObj, cmdObj, TCL_GLOBAL_ONLY); DECR_REF_COUNT(indexObj); return TCL_OK; } /* *---------------------------------------------------------------------- * * AliasDelete -- * * Deletes an alias from the index. * * Results: * A standard Tcl result. * * Side effects: * Deletes an entry from the hidden associative array. * *---------------------------------------------------------------------- */ static int AliasDelete(Tcl_Interp *interp, Tcl_Obj *cmdName, const char *methodName, bool withPer_object) { int result; Tcl_Obj *indexObj; nonnull_assert(interp != NULL); nonnull_assert(cmdName != NULL); nonnull_assert(methodName != NULL); indexObj = AliasIndex(cmdName, methodName, withPer_object); INCR_REF_COUNT(indexObj); result = Tcl_UnsetVar2(interp, NsfGlobalStrings[NSF_ARRAY_ALIAS], ObjStr(indexObj), TCL_GLOBAL_ONLY); DECR_REF_COUNT(indexObj); /*fprintf(stderr, "aliasDelete ::nsf::alias(%s) returned %d (%d)\n", AliasIndex(dsPtr, cmdName, methodName, withPer_object), result);*/ return result; } /* *---------------------------------------------------------------------- * * AliasGet -- * * Get an entry from the alias index. * * Results: * Alias in form of a Tcl_Obj* (or NULL). * * Side effects: * delete an entry from the hidden associative array * *---------------------------------------------------------------------- */ static Tcl_Obj * AliasGet(Tcl_Interp *interp, Tcl_Obj *cmdName, const char *methodName, bool withPer_object, bool leaveError) { Tcl_Obj *obj, *indexObj; nonnull_assert(interp != NULL); nonnull_assert(cmdName != NULL); nonnull_assert(methodName != NULL); indexObj = AliasIndex(cmdName, methodName, withPer_object); INCR_REF_COUNT(indexObj); obj = Tcl_ObjGetVar2(interp, NsfGlobalObjs[NSF_ARRAY_ALIAS], indexObj, TCL_GLOBAL_ONLY); DECR_REF_COUNT(indexObj); /*fprintf(stderr, "aliasGet methodName '%s' returns %p\n", methodName, obj);*/ if (obj == NULL && leaveError) { NsfPrintError(interp, "could not obtain alias definition for %s %s.", ObjStr(cmdName), methodName); } return obj; } /* *---------------------------------------------------------------------- * AliasDeleteObjectReference -- * * Delete an alias to a referenced object. Such aliases are * created by registering an alias to an object. This function * distinguishes between a sub-object and an alias to an object, * deletes the alias but never the referenced object. * * Results: * Boolean value indicating when alias is deleted. * * Side effects: * Deletes cmd sometimes * *---------------------------------------------------------------------- */ static bool AliasDeleteObjectReference(Tcl_Interp *interp, Tcl_Command cmd) { NsfObject *referencedObject = NsfGetObjectFromCmdPtr(cmd); nonnull_assert(interp != NULL); nonnull_assert(cmd != NULL); nonnull_assert(referencedObject != NULL); /*fprintf(stderr, "AliasDeleteObjectReference on %p obj %p\n", cmd, referencedObject);*/ if (referencedObject->refCount > 0 && cmd != referencedObject->id) { /* * The cmd is an aliased object, reduce the refCount of the * object, delete the cmd. */ /*fprintf(stderr, "remove alias %s to %s\n", Tcl_GetCommandName(interp, cmd), ObjectName(referencedObject));*/ NsfCleanupObject(referencedObject, "AliasDeleteObjectReference"); Tcl_DeleteCommandFromToken(interp, cmd); return NSF_TRUE; } return NSF_FALSE; } /* *---------------------------------------------------------------------- * AliasRefetch -- * * Perform a refetch of an epoched aliased cmd and update the * AliasCmdClientData structure with fresh values. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int AliasRefetch(Tcl_Interp *interp, NsfObject *object, const char *methodName, AliasCmdClientData *tcd) { Tcl_Obj **listElements, *entryObj, *targetObj; int nrElements, withPer_object; NsfObject *defObject; Tcl_Command cmd; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodName != NULL); nonnull_assert(tcd != NULL); /*fprintf(stderr, "AliasRefetch %s\n", methodName);*/ defObject = (tcd->class != NULL) ? &(tcd->class->object) : object; /* * Get the targetObject. Currently, we can get it just via the * alias array. */ withPer_object = (tcd->class == NULL); entryObj = AliasGet(interp, defObject->cmdName, methodName, withPer_object, NSF_TRUE); if (unlikely(entryObj == NULL)) { return TCL_ERROR; } INCR_REF_COUNT(entryObj); Tcl_ListObjGetElements(interp, entryObj, &nrElements, &listElements); targetObj = listElements[nrElements-1]; NsfLog(interp, NSF_LOG_NOTICE, "trying to refetch an epoched cmd %p as %s -- cmdName %s", (void *)tcd->aliasedCmd, methodName, ObjStr(targetObj)); /* * Replace cmd and its objProc and clientData with a newly fetched * version. */ cmd = Tcl_GetCommandFromObj(interp, targetObj); if (cmd != NULL) { cmd = GetOriginalCommand(cmd); /*fprintf(stderr, "cmd %p epoch %d deleted %.6x\n", cmd, Tcl_Command_cmdEpoch(cmd), TclIsCommandDeleted(cmd));*/ if (TclIsCommandDeleted(cmd)) { cmd = NULL; } } if (cmd == NULL) { int result = NsfPrintError(interp, "target \"%s\" of alias %s apparently disappeared", ObjStr(targetObj), methodName); DECR_REF_COUNT(entryObj); return result; } assert(Tcl_Command_objProc(cmd) != NULL); NsfCommandRelease(tcd->aliasedCmd); tcd->objProc = Tcl_Command_objProc(cmd); tcd->aliasedCmd = cmd; tcd->clientData = Tcl_Command_objClientData(cmd); NsfCommandPreserve(tcd->aliasedCmd); DECR_REF_COUNT(entryObj); /* * Now, we should be able to proceed as planned, we have an * non-epoched aliasCmd. */ return TCL_OK; } /* *---------------------------------------------------------------------- * AliasDereference -- * * Dereference a cmd in respect of the alias structure. If necessary, * this command refetches the aliased command. * * Results: * NULL, in case refetching fails, * the aliased cmd if it was an alias, or * the original cmd * * Side effects: * None. * *---------------------------------------------------------------------- */ NSF_INLINE static Tcl_Command AliasDereference(Tcl_Interp *interp, NsfObject *object, const char *methodName, Tcl_Command cmd) nonnull(1) nonnull(2) nonnull(3) nonnull(4); NSF_INLINE static Tcl_Command AliasDereference(Tcl_Interp *interp, NsfObject *object, const char *methodName, Tcl_Command cmd) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodName != NULL); nonnull_assert(cmd != NULL); if (unlikely(Tcl_Command_objProc(cmd) == NsfProcAliasMethod)) { AliasCmdClientData *tcd = (AliasCmdClientData *)Tcl_Command_objClientData(cmd); assert(tcd != NULL); /*fprintf(stderr, "AliasDereference %s epoch %d\n", methodName, Tcl_Command_cmdEpoch(tcd->aliasedCmd));*/ if (unlikely(Tcl_Command_cmdEpoch(tcd->aliasedCmd) != 0)) { /*fprintf(stderr, "NsfProcAliasMethod aliasedCmd %p epoch %p\n", tcd->aliasedCmd, Tcl_Command_cmdEpoch(tcd->aliasedCmd));*/ if (AliasRefetch(interp, object, methodName, tcd) != TCL_OK) { return NULL; } } return tcd->aliasedCmd; } return cmd; } #if defined(NSF_ASSEMBLE) # include "asm/nsfAssemble.c" #else static int NsfAsmMethodCreateCmd(Tcl_Interp *UNUSED(interp), NsfObject *UNUSED(defObject), int UNUSED(with_checkAlways), int UNUSED(withInner_namespace), int UNUSED(withPer_object), NsfObject *UNUSED(regObject), Tcl_Obj *UNUSED(nameObj), Tcl_Obj *UNUSED(argumentsObj), Tcl_Obj *UNUSED(bodyObj)) { /* * Dummy stub; used, when compiled without NSF_ASSEMBLE */ return TCL_OK; } #endif /* *---------------------------------------------------------------------- * SetBooleanFlag -- * * Set an unsigned int flag based on valueObj * * Results: * A standard Tcl result. * * Side effects: * update passed flags * *---------------------------------------------------------------------- */ static int SetBooleanFlag(Tcl_Interp *interp, unsigned int *flagsPtr, unsigned int flag, Tcl_Obj *valueObj, int *flagValue) nonnull(1) nonnull(2) nonnull(4) nonnull(5); static int SetBooleanFlag(Tcl_Interp *interp, unsigned int *flagsPtr, unsigned int flag, Tcl_Obj *valueObj, int *flagValue) { int result; nonnull_assert(interp != NULL); nonnull_assert(flagsPtr != NULL); nonnull_assert(valueObj != NULL); nonnull_assert(flagValue != NULL); result = Tcl_GetBooleanFromObj(interp, valueObj, flagValue); if (unlikely(result != TCL_OK)) { return result; } if (*flagValue) { *flagsPtr |= flag; } else { *flagsPtr &= ~flag; } return result; } /*********************************************************************** * Begin generated Next Scripting commands ***********************************************************************/ /* cmd __db_compile_epoch NsfDebugCompileEpoch {} */ static int NsfDebugCompileEpoch(Tcl_Interp *interp) nonnull(1); static int NsfDebugCompileEpoch(Tcl_Interp *interp) { nonnull_assert(interp != NULL); Tcl_SetObjResult(interp, Tcl_NewIntObj((int)(((Interp *)interp)->compileEpoch))); return TCL_OK; } /* cmd __db_show_obj NsfDebugShowObj { {-argName "obj" -required 1 -type tclobj} } */ static int NsfDebugShowObj(Tcl_Interp *interp, Tcl_Obj *obj) nonnull(1) nonnull(2); static int NsfDebugShowObj(Tcl_Interp *interp, Tcl_Obj *obj) { nonnull_assert(interp != NULL); nonnull_assert(obj != NULL); fprintf(stderr, "*** obj %p refCount %lu type <%s> ", (void *)obj, (unsigned long)obj->refCount, ObjTypeStr(obj)); if (obj->typePtr == &NsfObjectMethodObjType || obj->typePtr == &NsfInstanceMethodObjType ) { NsfMethodContext *mcPtr = obj->internalRep.twoPtrValue.ptr1; unsigned int currentMethodEpoch = obj->typePtr == &NsfObjectMethodObjType ? RUNTIME_STATE(interp)->objectMethodEpoch : RUNTIME_STATE(interp)->instanceMethodEpoch; Tcl_Command cmd = mcPtr->cmd; fprintf(stderr, " method epoch %u max %u cmd %p objProc 0x%" PRIxPTR " flags %.6x", mcPtr->methodEpoch, currentMethodEpoch, (void *)cmd, (cmd != NULL) ? (unsigned long)PTR2UINT(((Command *)cmd)->objProc) : 0ul, mcPtr->flags); if (cmd != NULL) { fprintf(stderr, "... cmd %p flags %.6x\n", (void *)cmd, Tcl_Command_flags(cmd)); assert(((Command *)cmd)->objProc != NULL); } assert(currentMethodEpoch >= mcPtr->methodEpoch); } else if (obj->typePtr == Nsf_OT_tclCmdNameType) { Tcl_Command cmd = Tcl_GetCommandFromObj(interp, obj); if (likely(cmd != NULL)) { Command *procPtr = (Command *)cmd; const char *tail = Tcl_GetHashKey(procPtr->hPtr->tablePtr, procPtr->hPtr); fprintf(stderr, "... cmd %p flags %.6x name '%s' ns '%s' objProcName %s", (void *)cmd, Tcl_Command_flags(cmd), tail, procPtr->nsPtr->name, CmdObjProcName(cmd)); } } else if ((obj->typePtr == Nsf_OT_byteArrayType) || (obj->typePtr == Nsf_OT_properByteArrayType)) { const char *bytes; int i, length; bytes = (char *)Tcl_GetByteArrayFromObj(obj, &length); fprintf(stderr, "bytearray proper %d length %d string rep %p: ", (obj->typePtr == Nsf_OT_properByteArrayType), length, (void*)obj->bytes); for (i = 0; i < length; i++) { fprintf(stderr, "%.2x", (unsigned)(*(bytes+i)) & 0xff); } } fprintf(stderr, "\n"); return TCL_OK; } /* cmd __db_get_obj NsfDebugGetDict { {-argName "obj" -required 1 -type tclobj} } */ #define NSF_DEBUG_SHOW_BYTES 10u static int NsfDebugGetDict(Tcl_Interp *interp, Tcl_Obj *obj) nonnull(1) nonnull(2); static int NsfDebugGetDict(Tcl_Interp *interp, Tcl_Obj *obj) { Tcl_Obj *resultObj; const char *typeString; nonnull_assert(interp != NULL); nonnull_assert(obj != NULL); typeString = (obj->typePtr != NULL) ? obj->typePtr->name : ""; resultObj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("type", TCL_INDEX_NONE)); Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(typeString, TCL_INDEX_NONE)); Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("refcount", TCL_INDEX_NONE)); Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewIntObj(obj->refCount)); Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("length", TCL_INDEX_NONE)); Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewIntObj(obj->length)); Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("hex", TCL_INDEX_NONE)); if (obj->bytes != NULL) { size_t i, objLength = (size_t)obj->length; char trailer[3] = "..."; char buffer[NSF_DEBUG_SHOW_BYTES*2u + sizeof(trailer) + 1u]; for (i = 0; i < NSF_DEBUG_SHOW_BYTES && i < objLength; i++) { snprintf(buffer + i*2, sizeof(buffer) - (i+1)*2, "%.2x", (unsigned)(*((obj->bytes)+i) & 0xff)); } if (objLength > NSF_DEBUG_SHOW_BYTES) { memmove(buffer, trailer, sizeof(buffer) - strlen(buffer) - 1); } Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj(buffer, TCL_INDEX_NONE)); } else { Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("", 0)); } Tcl_SetObjResult(interp, resultObj); return TCL_OK; } /* cmd __db_show_stack NsfShowStackCmd {} */ static int NsfShowStackCmd(Tcl_Interp *interp) { nonnull_assert(interp != NULL); NsfShowStack(interp); return TCL_OK; } /* cmd __db_run_assertions NsfDebugRunAssertionsCmd {} */ static int NsfDebugRunAssertionsCmd(Tcl_Interp *interp) { NsfObjectSystem *osPtr; NsfCmdList *instances = NULL, *entry; nonnull_assert(interp != NULL); /* * Collect all instances from all object systems. */ for (osPtr = RUNTIME_STATE(interp)->objectSystems; osPtr != NULL; osPtr = osPtr->nextPtr) { GetAllInstances(interp, &instances, osPtr->rootClass); } for (entry = instances; entry != NULL; entry = entry->nextPtr) { #if !defined(NDEBUG) NsfObject *object = (NsfObject *)entry->clorobj; #endif assert(object != NULL); assert(object->refCount > 0); assert(object->cmdName->refCount > 0); assert(object->activationCount >= 0); #if defined(CHECK_ACTIVATION_COUNTS) if (object->activationCount > 0) { Tcl_CallFrame *framePtr; int count = 0; NsfClasses *unstackedEntries = RUNTIME_STATE(interp)->cscList; /*fprintf(stderr, "DEBUG obj %p %s activationcount %d\n", object, ObjectName(object), object->activationCount);*/ framePtr = (Tcl_CallFrame *)Tcl_Interp_framePtr(interp); for (; framePtr != NULL; framePtr = Tcl_CallFrame_callerPtr(framePtr)) { int frameFlags = Tcl_CallFrame_isProcCallFrame(framePtr); NsfCallStackContent *cscPtr = ((frameFlags & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) != 0u) ? ((NsfCallStackContent *)Tcl_CallFrame_clientData(framePtr)) : NULL; if (cscPtr != NULL && cscPtr->self == object) { count ++; } if (cscPtr != NULL && (NsfObject *)cscPtr->cl == object) { count ++; } } for (; unstackedEntries; unstackedEntries = unstackedEntries->nextPtr) { NsfCallStackContent *cscPtr = (NsfCallStackContent *)unstackedEntries->cl; if (cscPtr != NULL && cscPtr->self == object) { count ++; } if (cscPtr != NULL && (NsfObject *)cscPtr->cl == object) { count ++; } } if (count != object->activationCount) { fprintf(stderr, "DEBUG obj %p %s activationcount %d on stack %d; " "might be from non-stacked but active call-stack content\n", object, ObjectName(object), object->activationCount, count); fprintf(stderr, "fixed count %d\n", count); /*NsfShowStack(interp);*/ /*return NsfPrintError(interp, "wrong activation count for object %s", ObjectName(object));*/ } } #endif } CmdListFree(&instances, NULL); /*fprintf(stderr, "all assertions passed\n");*/ return TCL_OK; } /* cmd __profile_clear_data NsfProfileClearDataStub {} cmd __profile_get_data NsfProfileGetDataStub {} cmd __profile_trace NsfProfileTraceStub { {-argName "-enable" -required 1 -nrargs 1 -type boolean} {-argName "-verbose" -required 0 -nrargs 1 -type boolean} {-argName "-dontsave" -required 0 -nrargs 1 -type boolean} {-argName "-builtins" -required 0 -nrargs 1 -type tclobj} } */ static int NsfProfileClearDataStub(Tcl_Interp *interp) nonnull(1); static int NsfProfileGetDataStub(Tcl_Interp *interp) nonnull(1); static int NsfProfileTraceStub(Tcl_Interp *interp, int withEnable, int withVerbose, int withDontsave, Tcl_Obj *builtinsObj) NSF_nonnull(1); #if defined(NSF_PROFILE) static int NsfProfileClearDataStub(Tcl_Interp *interp) { nonnull_assert(interp != NULL); NsfProfileClearData(interp); return TCL_OK; } static int NsfProfileGetDataStub(Tcl_Interp *interp) { nonnull_assert(interp != NULL); NsfProfileGetData(interp); return TCL_OK; } static int NsfProfileTraceStub(Tcl_Interp *interp, int withEnable, int withVerbose, int withDontsave, Tcl_Obj *builtinsObj) { nonnull_assert(interp != NULL); NsfProfileTrace(interp, withEnable, withVerbose, withDontsave, builtinsObj); return TCL_OK; } #else static int NsfProfileClearDataStub(Tcl_Interp *UNUSED(interp)) { return TCL_OK; } static int NsfProfileGetDataStub( Tcl_Interp *UNUSED(interp)) { return TCL_OK; } static int NsfProfileTraceStub( Tcl_Interp *UNUSED(interp), int UNUSED(withEnable), int UNUSED(withVerbose), int UNUSED(withDontsave), Tcl_Obj *UNUSED(builtins)) { return TCL_OK; } #endif /* * Valgrind/callgrind support */ #if defined(NSF_VALGRIND) #include /* cmd __callgrind_dump_stats NsfCallgrindDumpStatsCmd { {-argName "-name" -required 0 -nrargs 1} } cmd __callgrind_start_instrumentation NsfCallgrindStartInstrumentationCmd {} cmd __callgrind_stop_instrumentation NsfCallgrindStopInstrumentationCmd {} cmd __callgrind_toggle_collect NsfCallgrindToggleCollectCmd {} cmd __callgrind_zero_stats NsfCallgrindZeroStatsCmd {} */ static int NsfCallgrindDumpStatsCmd(Tcl_Interp *UNUSED(interp), const char *nameString) { if (nameString == NULL) { CALLGRIND_DUMP_STATS; } else { CALLGRIND_DUMP_STATS_AT(nameString); } return TCL_OK; } static int NsfCallgrindStartInstrumentationCmd(Tcl_Interp *UNUSED(interp)) { CALLGRIND_START_INSTRUMENTATION; return TCL_OK; } static int NsfCallgrindStopInstrumentationCmd(Tcl_Interp *UNUSED(interp)) { CALLGRIND_STOP_INSTRUMENTATION; return TCL_OK; } static int NsfCallgrindToggleCollectCmd(Tcl_Interp *UNUSED(interp)) { CALLGRIND_TOGGLE_COLLECT; return TCL_OK; } static int NsfCallgrindZeroStatsCmd(Tcl_Interp *UNUSED(interp)) { CALLGRIND_ZERO_STATS; return TCL_OK; } #else static int NsfCallgrindDumpStatsCmd(Tcl_Interp *UNUSED(interp), const char *UNUSED(nameString)) { return TCL_OK; } static int NsfCallgrindStartInstrumentationCmd(Tcl_Interp *UNUSED(interp)) { return TCL_OK; } static int NsfCallgrindStopInstrumentationCmd(Tcl_Interp *UNUSED(interp)) { return TCL_OK; } static int NsfCallgrindToggleCollectCmd(Tcl_Interp *UNUSED(interp)) { return TCL_OK; } static int NsfCallgrindZeroStatsCmd(Tcl_Interp *UNUSED(interp)) { return TCL_OK; } #endif /* *---------------------------------------------------------------------- * NsfUnsetUnknownArgsCmd -- * * Unset variables set from arguments with the default dummy * default value. The dummy default values are set by * ArgumentDefaults() * * Results: * A standard Tcl result. * * Side effects: * unsets some variables * *---------------------------------------------------------------------- */ /* cmd __unset_unknown_args NsfUnsetUnknownArgsCmd {} */ static int NsfUnsetUnknownArgsCmd(Tcl_Interp *interp) { CallFrame *varFramePtr; Proc *proc; nonnull_assert(interp != NULL); varFramePtr = Tcl_Interp_varFramePtr(interp); proc = Tcl_CallFrame_procPtr(varFramePtr); if (likely(proc != NULL)) { const CompiledLocal *ap; const Var *varPtr; int i; for (ap = proc->firstLocalPtr, i = 0; ap; ap = ap->nextPtr, i++) { if (!TclIsCompiledLocalArgument(ap)) { continue; } varPtr = &Tcl_CallFrame_compiledLocals(varFramePtr)[i]; /*fprintf(stderr, "NsfUnsetUnknownArgsCmd var '%s' i %d fi %d var %p flags %.8x obj %p unk %p\n", ap->name, i, ap->frameIndex, varPtr, varPtr->flags, varPtr->value.objPtr, NsfGlobalObjs[NSF___UNKNOWN__]);*/ if (varPtr->value.objPtr != NsfGlobalObjs[NSF___UNKNOWN__]) { continue; } /*fprintf(stderr, "NsfUnsetUnknownArgsCmd must unset %s\n", ap->name);*/ Tcl_UnsetVar2(interp, ap->name, NULL, 0); } } return TCL_OK; } /* cmd asmproc NsfAsmProcCmd { {-argName "-ad" -required 0 -nrargs 0 -type switch} {-argName "-checkalways" -required 0 -nrargs 0 -type switch} {-argName "procName" -required 1 -type tclobj} {-argName "arguments" -required 1 -type tclobj} {-argName "body" -required 1 -type tclobj} } */ #if !defined(NSF_ASSEMBLE) static int NsfAsmProcCmd(Tcl_Interp *UNUSED(interp), int UNUSED(with_ad), int UNUSED(with_checkAlways), Tcl_Obj *UNUSED(nameObj), Tcl_Obj *UNUSED(arguments), Tcl_Obj *UNUSED(body)) { return TCL_OK; } #else static int NsfAsmProcCmd(Tcl_Interp *interp, int with_ad, int with_checkAlways, Tcl_Obj *nameObj, Tcl_Obj *arguments, Tcl_Obj *body) { NsfParsedParam parsedParam; int result; nonnull_assert(interp != NULL); nonnull_assert(nameObj != NULL); nonnull_assert(arguments != NULL); nonnull_assert(body != NULL); /* * Parse argument list "arguments" to determine if we should provide * nsf parameter handling. */ result = ParamDefsParse(interp, nameObj, arguments, NSF_DISALLOWED_ARG_METHOD_PARAMETER, NSF_FALSE, &parsedParam, NULL); if (unlikely(result != TCL_OK)) { return result; } if (parsedParam.paramDefs != NULL) { /* * We need parameter handling. */ result = NsfAsmProcAddParam(interp, &parsedParam, nameObj, body, with_ad, with_checkAlways); } else { /* * No parameter handling needed. */ result = NsfAsmProcAddArgs(interp, arguments, nameObj, body, with_ad, with_checkAlways); } return result; } #endif /* cmd "cmd::info" NsfCmdInfoCmd { {-argName "subcmd" -required 1 -typeName "methodgetcmd" -type "args|body|definition|exists|registrationhandle|definitionhandle|origin|parameter|syntax|type|precondition|postcondition|submethods|returns"} {-argName "-context" -required 0 -type object} {-argName "methodName" -required 1 -type tclobj} {-argName "pattern" -required 0} } {-nxdoc 1} */ static int NsfCmdInfoCmd(Tcl_Interp *interp, InfomethodsubcmdIdx_t subcmd, NsfObject *contextObject, Tcl_Obj *methodNameObj, const char *pattern) { nonnull_assert(interp != NULL); nonnull_assert(methodNameObj != NULL); return ListMethodResolve(interp, subcmd, contextObject, pattern, NULL, NULL, methodNameObj, NSF_FALSE); } /* cmd configure NsfConfigureCmd { {-argName "option" -required 1 -type "debug|dtrace|filter|profile|softrecreate|objectsystems|keepcmds|checkresults|checkarguments"} {-argName "value" -required 0 -type tclobj} } */ static int NsfConfigureCmd(Tcl_Interp *interp, ConfigureoptionIdx_t option, Tcl_Obj *valueObj) { int boolVal = 0; nonnull_assert(interp != NULL); #if defined(NSF_DTRACE) if (NSF_DTRACE_CONFIGURE_PROBE_ENABLED()) { NSF_DTRACE_CONFIGURE_PROBE(Nsf_Configureoption[option-1].key, (valueObj != NULL) ? ObjStr(valueObj) : NULL); } #endif if (option == ConfigureoptionObjectsystemsIdx) { NsfObjectSystem *osPtr; Tcl_Obj *list = Tcl_NewListObj(0, NULL); for (osPtr = RUNTIME_STATE(interp)->objectSystems; osPtr != NULL; osPtr = osPtr->nextPtr) { Tcl_Obj *osObj = Tcl_NewListObj(0, NULL); Tcl_Obj *systemMethods = Tcl_NewListObj(0, NULL); int idx; Tcl_ListObjAppendElement(interp, osObj, osPtr->rootClass->object.cmdName); Tcl_ListObjAppendElement(interp, osObj, osPtr->rootMetaClass->object.cmdName); for (idx = 0; Nsf_SystemMethodOpts[idx]; idx++) { /*fprintf(stderr, "opt %s %s\n", Nsf_SystemMethodOpts[idx], osPtr->methods[idx] ? ObjStr(osPtr->methods[idx]) : "NULL");*/ if (osPtr->methods[idx] == NULL) { continue; } Tcl_ListObjAppendElement(interp, systemMethods, Tcl_NewStringObj(Nsf_SystemMethodOpts[idx], TCL_INDEX_NONE)); if (osPtr->handles[idx] || osPtr->protected[idx]) { Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, listObj, osPtr->methods[idx]); Tcl_ListObjAppendElement(interp, listObj, osPtr->handles[idx]); if (osPtr->protected[idx]) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(1)); } Tcl_ListObjAppendElement(interp, systemMethods, listObj); } else { Tcl_ListObjAppendElement(interp, systemMethods, osPtr->methods[idx]); } } Tcl_ListObjAppendElement(interp, osObj, systemMethods); Tcl_ListObjAppendElement(interp, list, osObj); } Tcl_SetObjResult(interp, list); return TCL_OK; } if (option == ConfigureoptionDebugIdx) { if (valueObj != NULL) { int level, result = Tcl_GetIntFromObj(interp, valueObj, &level); if (unlikely(result != TCL_OK)) { return result; } RUNTIME_STATE(interp)->logSeverity = level; } Tcl_SetIntObj(Tcl_GetObjResult(interp), RUNTIME_STATE(interp)->logSeverity); return TCL_OK; } /* * All other configure options are boolean. */ if (valueObj != NULL) { int result = Tcl_GetBooleanFromObj(interp, valueObj, &boolVal); if (unlikely(result != TCL_OK)) { return result; } } switch (option) { case ConfigureoptionDebugIdx: ;NSF_FALL_THROUGH; /* fall through */ case ConfigureoptionObjectsystemsIdx: /* * Handled above. */ break; case ConfigureoptionDtraceIdx: /* * Not implemented. */ break; case ConfigureoptionNULL: /* * Do nothing; just for detection if option was specified. */ break; case ConfigureoptionFilterIdx: Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (RUNTIME_STATE(interp)->doFilters)); if (valueObj != NULL) { RUNTIME_STATE(interp)->doFilters = boolVal; } break; case ConfigureoptionSoftrecreateIdx: Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (RUNTIME_STATE(interp)->doSoftrecreate)); if (valueObj != NULL) { RUNTIME_STATE(interp)->doSoftrecreate = boolVal; } break; case ConfigureoptionKeepcmdsIdx: Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (RUNTIME_STATE(interp)->doKeepcmds)); if (valueObj != NULL) { RUNTIME_STATE(interp)->doKeepcmds = boolVal; } break; case ConfigureoptionCheckresultsIdx: Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (RUNTIME_STATE(interp)->doCheckResults)); if (valueObj != NULL) { RUNTIME_STATE(interp)->doCheckResults = (unsigned int)boolVal; } break; case ConfigureoptionCheckargumentsIdx: Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (RUNTIME_STATE(interp)->doCheckArguments) != 0); if (valueObj != NULL) { RUNTIME_STATE(interp)->doCheckArguments = (boolVal != 0) ? NSF_ARGPARSE_CHECK : 0; } break; } return TCL_OK; } /* cmd colon NsfColonCmd { {-argName "args" -type allargs} } */ static int NsfColonCmd(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { const char *methodName = ObjStr(objv[0]); NsfObject *self; int result; nonnull_assert(interp != NULL); self = GetSelfObj(interp); if (unlikely(self == NULL)) { return NsfNoCurrentObjectError(interp, methodName); } /*fprintf(stderr, "Colon dispatch %s.%s (%d)\n", ObjectName(self), ObjStr(objv[0]), objc);*/ /* * Do we have a method, which is NOT a single colon? */ if (likely(!(*methodName == ':' && *(methodName + 1) == '\0'))) { /* * A method like ":foo" is called via plain ObjectDispatch(). */ result = ObjectDispatch(self, interp, objc, objv, NSF_CM_NO_SHIFT); } else { /* * The method name is a single colon, and might have one or more * arguments. */ if (objc <= 1) { /* * Single colon and no arguments. */ Tcl_SetObjResult(interp, self->cmdName); result = TCL_OK; } else { /* * Single colon and multiple arguments. */ methodName = ObjStr(objv[1]); if (*methodName != '-') { /* * No need to parse arguments (local, intrinsic, ...). */ result = ObjectDispatch(self, interp, objc, objv, 0u); } else { ParseContext pc; /* * Parse arguments, use definitions from nsf::my */ result = ArgumentParse(interp, objc, objv, NULL, objv[0], method_definitions[NsfMyCmdIdx].paramDefs, method_definitions[NsfMyCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc); if (likely(result == TCL_OK)) { int withIntrinsic, withLocal, withSystem; Tcl_Obj *methodObj; withIntrinsic = (int)PTR2INT(pc.clientData[0]); withLocal = (int)PTR2INT(pc.clientData[1]); withSystem = (int)PTR2INT(pc.clientData[2]); methodObj = (Tcl_Obj *)pc.clientData[3]; assert(pc.status == 0); if ((withIntrinsic && withLocal) || (withIntrinsic && withSystem) || (withLocal && withSystem)) { result = NsfPrintError(interp, "flags '-intrinsic', '-local' and '-system' are mutual exclusive"); } else { unsigned int flags; flags = NSF_CSC_IMMEDIATE; if (withIntrinsic != 0) { flags |= NSF_CM_INTRINSIC_METHOD; } if (withLocal != 0) { flags |= NSF_CM_LOCAL_METHOD; } if (withSystem != 0) { flags |= NSF_CM_SYSTEM_METHOD; } result = CallMethod(self, interp, methodObj, (objc - pc.lastObjc) + 2, objv + pc.lastObjc, flags); } } } } } return result; } /* cmd "definitionnamespace" NsfDefinitionNamespaceCmd { } */ static int NsfDefinitionNamespaceCmd(Tcl_Interp *interp) { Tcl_Namespace *nsPtr; nonnull_assert(interp != NULL); nsPtr = CallingNameSpace(interp); Tcl_SetObjResult(interp, Tcl_NewStringObj(nsPtr->fullName, TCL_INDEX_NONE)); return TCL_OK; } /* cmd "directdispatch" NsfDirectDispatchCmd { {-argName "object" -required 1 -type object} {-argName "-frame" -required 0 -nrargs 1 -type "method|object|default" -default "default"} {-argName "command" -required 1 -type tclobj} {-argName "args" -type args} } */ static int NsfDirectDispatchCmd(Tcl_Interp *interp, NsfObject *object, FrameIdx_t withFrame, Tcl_Obj *commandObj, int trailingObjc, Tcl_Obj *const trailingObjv[]) { int result; const char *methodName; Tcl_Command cmd, importedCmd; CallFrame frame, *framePtr = &frame; Tcl_ObjCmdProc *proc; unsigned int flags = 0u; bool useCmdDispatch = NSF_TRUE; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(commandObj != NULL); /*fprintf(stderr, "NsfDirectDispatchCmd obj=%s, cmd m='%s' oc %d\n", ObjectName(object), methodName, nobjc);*/ methodName = ObjStr(commandObj); if (unlikely(*methodName != ':')) { return NsfPrintError(interp, "method name '%s' must be fully qualified", methodName); } /* * We have a fully qualified name of a Tcl command that will be dispatched. */ cmd = Tcl_GetCommandFromObj(interp, commandObj); if (likely(cmd != NULL)) { importedCmd = TclGetOriginalCommand(cmd); if (unlikely(importedCmd != NULL)) { cmd = importedCmd; } } if (unlikely(cmd == NULL)) { return NsfPrintError(interp, "cannot lookup command '%s'", methodName); } proc = Tcl_Command_objProc(cmd); if (proc == TclObjInterpProc || proc == NsfForwardMethod || proc == NsfObjscopedMethod || proc == NsfSetterMethod || CmdIsNsfObject(cmd)) { if (withFrame && withFrame != FrameDefaultIdx) { return NsfPrintError(interp, "cannot use -frame object|method in dispatch for command '%s'", methodName); } useCmdDispatch = NSF_FALSE; } else { if (unlikely(withFrame == FrameMethodIdx)) { useCmdDispatch = NSF_FALSE; } } /* * If "withFrame == FrameObjectIdx" is specified, a call-stack frame is * pushed to make instance variables accessible for the command. */ if (unlikely(withFrame == FrameObjectIdx)) { #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, object, framePtr); #pragma GCC diagnostic pop flags = NSF_CSC_IMMEDIATE; } /* * Since we know, that we are always called with a full argument * vector, we can include the cmd name in the objv by using * nobjv-1; this way, we avoid a memcpy(). */ if (useCmdDispatch) { if (NSF_DTRACE_METHOD_ENTRY_ENABLED()) { NSF_DTRACE_METHOD_ENTRY(ObjectName(object), "", (char *)methodName, trailingObjc, (Tcl_Obj **)trailingObjv); } result = CmdMethodDispatch(object, interp, trailingObjc + 1, trailingObjv - 1, object, cmd, NULL); } else { /* * If "withFrame == FrameMethodIdx" is specified, a call-stack frame is * pushed to make instance variables accessible for the command. */ if (unlikely(withFrame == FrameMethodIdx)) { flags = NSF_CSC_FORCE_FRAME|NSF_CSC_IMMEDIATE; } result = MethodDispatch(interp, trailingObjc + 1, trailingObjv - 1, cmd, object, NULL /*NsfClass *cl*/, Tcl_GetCommandName(interp, cmd), NSF_CSC_TYPE_PLAIN, flags); } if (unlikely(withFrame == FrameObjectIdx)) { Nsf_PopFrameObj(interp, framePtr); } return result; } /* cmd "dispatch" NsfDispatchCmd { {-argName "object" -required 1 -type object} {-argName "-intrinsic" -required 0 -nrargs 0} {-argName "-system" -required 0 -nrargs 0} {-argName "command" -required 1 -type tclobj} {-argName "args" -type args} } */ static int NsfDispatchCmd(Tcl_Interp *interp, NsfObject *object, int withIntrinsic, int withSystem, Tcl_Obj *commandObj, int trailingObjc, Tcl_Obj *const trailingObjv[]) { unsigned int flags = NSF_CM_NO_UNKNOWN|NSF_CSC_IMMEDIATE|NSF_CM_IGNORE_PERMISSIONS|NSF_CM_NO_SHIFT; Tcl_Obj *const *objv = trailingObjv-1; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(commandObj != NULL); /* * We use the construct "tclobj" + "args" in the spec to enforce that at least a * commandName is specified (this way we allow empty "args", and can provide * a nice error message, if cmdName is not specified). Since the we know * that the commandObj has to be right before "args" in the objv, we can * decrement the nobjv to obtain objv (and increment nobjc), be we make sure * that this assumption is correct. */ assert(objv[0] == commandObj); assert(ISOBJ_(commandObj)); trailingObjc++; #if 0 {int i; fprintf(stderr, "NsfDispatchCmd %s method %s oc %2d", ObjectName(object), ObjStr(commandObj), trailingObjc); for(i = 0; i < trailingObjc; i++) {fprintf(stderr, " [%d]=%s,", i, ObjStr(trailingObjv[i]));} fprintf(stderr, "\n"); } #endif if (unlikely(withIntrinsic && withSystem)) { return NsfPrintError(interp, "flags '-intrinsic' and '-system' are mutual exclusive"); } /* * Dispatch the command the method from the precedence order, with filters * etc. -- strictly speaking unnecessary, but this function can be used to * call protected methods and provide the flags '-intrinsics' and '-system'. */ if (withIntrinsic != 0) { flags |= NSF_CM_INTRINSIC_METHOD; } if (withSystem != 0) { flags |= NSF_CM_SYSTEM_METHOD; } /* * Since we know, that we are always called with a full argument * vector, we can include the cmd name in the objv by using * nobjv-1; this way, we avoid a memcpy(). */ return ObjectDispatch(object, interp, trailingObjc, objv, flags); } /* cmd finalize NsfFinalizeCmd { {-argName "-keepvars" -required 0 -nrargs 0} } */ static int NsfFinalizeCmd(Tcl_Interp *interp, int withKeepvars) { int result; /* fprintf(stderr, "#### (%lx) NsfFinalizeCmd exitHandlerRound %d\n", (long)(void*)pthread_self(), RUNTIME_STATE(interp)->exitHandlerDestroyRound );*/ nonnull_assert(interp != NULL); #if defined(NSF_PROFILE) /* * Check whether profile trace is still running. If so, delete it here. * Interestingly, NsfLog() seems to be unavailable at this place. */ if (RUNTIME_STATE(interp)->doTrace == 1) { NsfLog(interp, NSF_LOG_WARN, "tracing is still active; deactivate it due to cleanup."); NsfProfileTrace(interp, 0, 0, 0, NULL); } #endif #if defined(NSF_STACKCHECK) {NsfRuntimeState *rst = RUNTIME_STATE(interp); NsfLog(interp, NSF_LOG_WARN, "Stack max usage %ld", labs(rst->maxStack - rst->bottomOfStack)); } #endif /*fprintf(stderr, "+++ call tcl-defined exit handler (%x)\n", PTR2INT(pthread_self()));*/ /* * Evaluate user-defined exit handler. */ result = Tcl_Eval(interp, "::nsf::__exithandler"); if (unlikely(result != TCL_OK)) { fprintf(stderr, "User defined exit handler contains errors!\n" "Error in line %d: %s\nExecution interrupted.\n", (int)Tcl_GetErrorLine(interp), ObjStr(Tcl_GetObjResult(interp))); } ObjectSystemsCleanup(interp, withKeepvars ? NSF_TRUE : NSF_FALSE); #ifdef DO_CLEANUP { NsfRuntimeState *rst = RUNTIME_STATE(interp); # if defined(CHECK_ACTIVATION_COUNTS) assert(rst->cscList == NULL); # endif /*fprintf(stderr, "CLEANUP TOP NS\n");*/ Tcl_Export(interp, rst->NsfNS, "", 1); if (rst->NsfClassesNS != NULL) { MEM_COUNT_FREE("TclNamespace", rst->NsfClassesNS); Tcl_DeleteNamespace(rst->NsfClassesNS); } if (rst->NsfNS != NULL) { MEM_COUNT_FREE("TclNamespace", rst->NsfNS); Tcl_DeleteNamespace(rst->NsfNS); } { NsfDList *dlPtr = &rst->freeDList; size_t i; #if defined(COLON_CMD_STATS) fprintf(stderr, "#### DList free size %lu avail %lu\n", dlPtr->size, dlPtr->avail); #endif for (i = 0u; i < dlPtr->size; i++) { /* fprintf(stderr, "#### DList free data[%lu] %p: %p\n", i, (void*)&(dlPtr->data[i]), (void*)dlPtr->data[i]); */ NsfColonCmdContextFree(dlPtr->data[i]); } NsfDListFree(dlPtr); } } #endif return TCL_OK; } /* cmd interp NsfInterpObjCmd { {-argName "name"} {-argName "args" -type allargs} } */ /* * Create a slave interp that calls Next Scripting Init */ static int NsfInterpObjCmd(Tcl_Interp *interp, const char *name, int objc, Tcl_Obj *const objv[]) { nonnull_assert(interp != NULL); nonnull_assert(name != NULL); /* * Create a fresh Tcl interpreter, or pass command to an existing one */ if (unlikely(NsfCallCommand(interp, NSF_INTERP, objc, objv) != TCL_OK)) { return TCL_ERROR; } /* * Upon [interp create], set up NSF for the new child interp by running * Nsf_Init() */ if (isCreateString(name)) { Tcl_Obj *slaveCmdObj; Tcl_Interp *slavePtr; /* * Tcl_InterpObjCmd() stores the newly created child interp's command name * in the interp result store. */ slaveCmdObj = Tcl_GetObjResult(interp); slavePtr = Tcl_GetChild(interp, ObjStr(slaveCmdObj)); if (slavePtr == NULL) { return NsfPrintError(interp, "creation of slave interpreter failed"); } if (unlikely(Nsf_Init(slavePtr) == TCL_ERROR)) { return TCL_ERROR; } } return TCL_OK; } /* cmd is NsfIsCmd { {-argName "-complain" -nrargs 0} {-argName "-configure" -nrargs 0} {-argName "-name" -required 0} {-argName "constraint" -required 1 -type tclobj} {-argName "value" -required 1 -type tclobj} } {-nxdoc 1} */ static int NsfIsCmd(Tcl_Interp *interp, int withComplain, int withConfigure, const char *withName, Tcl_Obj *constraintObj, Tcl_Obj *valueObj) { Nsf_Param *paramPtr = NULL; int result; nonnull_assert(interp != NULL); nonnull_assert(constraintObj != NULL); nonnull_assert(valueObj != NULL); result = ParameterCheck(interp, constraintObj, valueObj, (withName != NULL) ? withName : "value:", 1, (withName != NULL), (withConfigure == 1), ¶mPtr, Tcl_GetCurrentNamespace(interp)->fullName); if (unlikely(paramPtr == NULL)) { /* * We could not convert the arguments. Even with noComplain, we * report the invalid converter spec as exception. */ result = TCL_ERROR; } else { if (paramPtr->converter == ConvertViaCmd && (withComplain == 0 || result == TCL_OK)) { Tcl_ResetResult(interp); } if (withComplain == 0) { Tcl_SetIntObj(Tcl_GetObjResult(interp), (result == TCL_OK)); result = TCL_OK; } else if (likely(result == TCL_OK)) { Tcl_SetIntObj(Tcl_GetObjResult(interp), 1); } } return result; } /* cmd parseargs NsfParseArgsCmd { {-argName "-asdict" -nrargs 0 -required 0 -type switch} {-argName "argspec" -required 1 -type tclobj} {-argName "arglist" -required 1 -type tclobj} } {-nxdoc 0} */ static int NsfParseArgsCmd(Tcl_Interp *interp, int withAsDict, Tcl_Obj *argspecObj, Tcl_Obj *arglistObj) { NsfParsedParam parsedParam; Tcl_Obj **objv; int result, objc; result = ParamDefsParse(interp, NsfGlobalObjs[NSF_PARSE_ARGS], argspecObj, NSF_DISALLOWED_ARG_METHOD_PARAMETER, NSF_TRUE /* force use of param structure, even for Tcl-only params */, &parsedParam, Tcl_GetCurrentNamespace(interp)->fullName); if (unlikely(result != TCL_OK)) { return result; } result = Tcl_ListObjGetElements(interp, arglistObj, &objc, &objv); if (likely(result == TCL_OK) && parsedParam.paramDefs != NULL) { ParseContext pc; NsfParamDefs *paramDefs = parsedParam.paramDefs; unsigned int processFlags = 0u; ParamDefsRefCountIncr(paramDefs); result = ArgumentParse(interp, objc, objv, NULL, NsfGlobalObjs[NSF_PARSE_ARGS], paramDefs->paramsPtr, paramDefs->nrParams, paramDefs->serial, processFlags|NSF_ARGPARSE_START_ZERO|RUNTIME_STATE(interp)->doCheckArguments, &pc); if (result == TCL_OK) { Nsf_Param *paramPtr; size_t i; if (withAsDict == 1) { Tcl_Obj *resultObj; resultObj = Tcl_NewDictObj(); INCR_REF_COUNT2("resultDictObj", resultObj); for (i = 0u, paramPtr = paramDefs->paramsPtr; paramPtr->name != NULL; paramPtr++, i++) { Tcl_Obj *valueObj = pc.objv[i]; if (valueObj != NsfGlobalObjs[NSF___UNKNOWN__]) { /*fprintf(stderr, "param %s -> <%s>\n", paramPtr->name, ObjStr(valueObj));*/ result = Tcl_DictObjPut(interp, resultObj, paramPtr->nameObj, valueObj); if (result == TCL_ERROR) { break; } } } if (result == TCL_OK) { Tcl_SetObjResult(interp, resultObj); } DECR_REF_COUNT2("resultDictObj", resultObj); } else { for (i = 0u, paramPtr = paramDefs->paramsPtr; paramPtr->name != NULL; paramPtr++, i++) { Tcl_Obj *valueObj = pc.objv[i]; if (valueObj != NsfGlobalObjs[NSF___UNKNOWN__]) { /*fprintf(stderr, "param %s -> <%s>\n", paramPtr->name, ObjStr(valueObj));*/ if (Tcl_ObjSetVar2(interp, paramPtr->nameObj, NULL, valueObj, TCL_LEAVE_ERR_MSG) == NULL) { result = TCL_ERROR; break; } } } } } ParamDefsRefCountDecr(paramDefs); ParseContextRelease(&pc); } return result; } /* cmd method::alias NsfMethodAliasCmd { {-argName "object" -type object} {-argName "-per-object"} {-argName "methodName"} {-argName "-frame" -required 0 -nrargs 1 -type "method|object|default" -default "default"} {-argName "-protection" -required 0 -type "call-protected|redefine-protected|none" -default "none"} {-argName "cmdName" -required 1 -type tclobj} } */ static int NsfMethodAliasCmd( Tcl_Interp *interp, NsfObject *object, int withPer_object, const char *methodName, FrameIdx_t withFrame, ProtectionIdx_t withProtection, Tcl_Obj *cmdNameObj ) { Tcl_ObjCmdProc *objProc, *newObjProc; Tcl_CmdDeleteProc *deleteProc; AliasCmdClientData *tcd; Tcl_Command cmd, oldCmd, newCmd; Tcl_Namespace *nsPtr; int result; unsigned int flags = 0u; const NsfClass *class; NsfObject *newTargetObject; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodName != NULL); assert(*methodName != ':'); nonnull_assert(cmdNameObj != NULL); cmd = Tcl_GetCommandFromObj(interp, cmdNameObj); if (cmd == NULL) { return NsfPrintError(interp, "cannot lookup command '%s'", ObjStr(cmdNameObj)); } cmd = GetOriginalCommand(cmd); objProc = Tcl_Command_objProc(cmd); assert(objProc != NULL); /* * objProc is either ... * * 1. NsfObjDispatch: a command representing a Next Scripting object * * 2. TclObjInterpProc: a cmd standing for a Tcl proc (including * Next Scripting methods), verified through CmdIsProc() -> to be * wrapped by NsfProcAliasMethod() * * 3. NsfForwardMethod: a Next Scripting forwarder * * 4. NsfSetterMethod: a Next Scripting setter * * 5. Arbitrary Tcl commands (e.g. set, ..., ::nsf::relation, ...) * */ if (withFrame == FrameObjectIdx) { newObjProc = NsfObjscopedMethod; } else { newObjProc = NULL; } /* * We need to perform a defensive lookup of a previously defined * object-alias under the given methodName. */ class = (withPer_object || ! NsfObjectIsClass(object)) ? NULL : (NsfClass *)object; nsPtr = (class != NULL) ? class->nsPtr : object->nsPtr; oldCmd = (nsPtr != NULL) ? FindMethod(nsPtr, methodName) : NULL; newTargetObject = NsfGetObjectFromCmdPtr(cmd); if (oldCmd != NULL) { #if 1 /* * Old solution, leasds to a broken regression test with Tcl 8.7a1. * However, using Tcl_DeleteCommandFromToken() leads to a crash also with * earlier solutions when defining recursive aliases. */ NsfObject *oldTargetObject; /*fprintf(stderr, "... DELETE preexisting cmd %s in ns %s\n", methodName, nsPtr->fullName);*/ oldTargetObject = NsfGetObjectFromCmdPtr(oldCmd); /* fprintf(stderr, "oldTargetObject %p flags %.6x newTargetObject %p\n", oldTargetObject, (oldTargetObject != NULL) ? oldTargetObject->flags : 0, newTargetObject);*/ /* * We might have to decrement the reference counter on a previously * aliased object. Decrement the reference count to the old aliased object * only, when it is different to the new target Object. */ if (oldTargetObject != NULL && oldTargetObject != newTargetObject) { /*fprintf(stderr, "--- releasing old target object %p refCount %d\n", oldTargetObject, oldTargetObject->refCount);*/ assert(oldTargetObject->refCount > 0); AliasDeleteObjectReference(interp, oldCmd); } #else Tcl_DeleteCommandFromToken(interp, oldCmd); #endif } if (newTargetObject != NULL) { /* * We set now for every alias to an object a stub proc, such we can * distinguish between cases, where the user wants to create a method, and * between cases, where object-invocation via method interface might * happen. */ newObjProc = NsfProcAliasMethod; } else if (CmdIsProc(cmd)) { /* * When we have a Tcl proc|nsf-method as alias, then use the * wrapper, which will be deleted automatically when the original * proc/method is deleted. */ newObjProc = NsfProcAliasMethod; if (objProc == TclObjInterpProc) { /* * We have an alias to a Tcl proc; */ Proc *procPtr = (Proc *)Tcl_Command_objClientData(cmd); Tcl_Obj *bodyObj = (procPtr != NULL) ? procPtr->bodyPtr : NULL; if (bodyObj && bodyObj->typePtr == Nsf_OT_byteCodeType) { /* * Flush old byte code */ /*fprintf(stderr, "flush byte code\n");*/ TclFreeInternalRep(bodyObj); } } if (withFrame && withFrame != FrameDefaultIdx) { return NsfPrintError(interp, "cannot use -frame object|method in alias for scripted command '%s'", ObjStr(cmdNameObj)); } } if (newObjProc != NULL) { /* * Add a wrapper. */ /*fprintf(stderr, "NsfMethodAliasCmd add wrapper cmd %p\n", cmd);*/ NsfCommandPreserve(cmd); tcd = NEW(AliasCmdClientData); tcd->cmdName = object->cmdName; tcd->interp = interp; /* just for deleting the alias */ tcd->object = NULL; tcd->class = (class != NULL) ? (NsfClass *) object : NULL; tcd->objProc = objProc; tcd->aliasedCmd = cmd; tcd->clientData = Tcl_Command_objClientData(cmd); objProc = newObjProc; deleteProc = AliasCmdDeleteProc; if (tcd->cmdName != NULL) { INCR_REF_COUNT(tcd->cmdName); } } else { /* * Call the command directly (must be a c-implemented command not * depending on a volatile client data) */ deleteProc = NULL; tcd = Tcl_Command_objClientData(cmd); /*fprintf(stderr, "NsfMethodAliasCmd no wrapper cmd %p\n", (void*)cmd);*/ } switch (withProtection) { case ProtectionCall_protectedIdx: flags = NSF_CMD_CALL_PROTECTED_METHOD; break; case ProtectionRedefine_protectedIdx: flags = NSF_CMD_REDEFINE_PROTECTED_METHOD; break; case ProtectionNoneIdx: ;NSF_FALL_THROUGH; /* fall through */ case ProtectionNULL: flags = 0u; break; } if (class != NULL) { result = NsfAddClassMethod(interp, (Nsf_Class *)class, methodName, objProc, tcd, deleteProc, flags); nsPtr = class->nsPtr; } else { result = NsfAddObjectMethod(interp, (Nsf_Object *)object, methodName, objProc, tcd, deleteProc, flags); nsPtr = object->nsPtr; } if (likely(result == TCL_OK)) { newCmd = FindMethod(nsPtr, methodName); } else { newCmd = NULL; } #if defined(WITH_IMPORT_REFS) if (newObjProc != NULL) { /* * Define the reference chain like for 'namespace import' to * obtain automatic deletes when the original command is deleted. */ ImportRef *refPtr = (ImportRef *) ckalloc((int)sizeof(ImportRef)); refPtr->importedCmdPtr = (Command *) newCmd; refPtr->nextPtr = ((Command *) tcd->aliasedCmd)->importRefPtr; ((Command *) tcd->aliasedCmd)->importRefPtr = refPtr; tcd->aliasCmd = newCmd; } #else if (newObjProc != NULL) { tcd->aliasCmd = newCmd; } #endif if (newCmd != NULL) { AliasAdd(interp, object->cmdName, methodName, class == NULL, cmdNameObj); if (withFrame == FrameMethodIdx) { Tcl_Command_flags(newCmd) |= NSF_CMD_NONLEAF_METHOD; /*fprintf(stderr, "setting aliased for cmd %p %s flags %.6x, tcd = %p\n", newCmd, methodName, Tcl_Command_flags(newCmd), tcd);*/ } Tcl_SetObjResult(interp, MethodHandleObj(object, class == NULL, methodName)); result = TCL_OK; } return result; } /* cmd method::assertion NsfMethodAssertionCmd { {-argName "object" -type object} {-argName "assertionsubcmd" -required 1 -type "check|object-invar|class-invar"} {-argName "arg" -required 0 -type tclobj} } Make "::nsf::assertion" a cmd rather than a method, otherwise we cannot define e.g. a "method check options {...}" to reset the check options in case of a failed option, since assertion checking would be applied on the sketched method already. */ static int NsfMethodAssertionCmd(Tcl_Interp *interp, NsfObject *object, AssertionsubcmdIdx_t subcmd, Tcl_Obj *argObj) { #if defined(NSF_WITH_ASSERTIONS) NsfClass *class; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); switch (subcmd) { case AssertionsubcmdCheckIdx: if (argObj != NULL) { return AssertionSetCheckOptions(interp, object, argObj); } else { return AssertionListCheckOption(interp, object); } /*break; unreachable */ case AssertionsubcmdObject_invarIdx: if (argObj != NULL) { NsfObjectOpt *opt = NsfRequireObjectOpt(object); AssertionSetInvariants(interp, &opt->assertions, argObj); } else { if (object->opt != NULL && object->opt->assertions != NULL) { Tcl_SetObjResult(interp, AssertionList(interp, object->opt->assertions->invariants)); } } break; case AssertionsubcmdClass_invarIdx: if (!NsfObjectIsClass(object)) { return NsfPrintError(interp, "object is not a class"); } class = (NsfClass *)object; if (argObj != NULL) { NsfClassOpt *opt = NsfRequireClassOpt(class); AssertionSetInvariants(interp, &opt->assertions, argObj); } else { if (class->opt != NULL && class->opt->assertions != NULL) { Tcl_SetObjResult(interp, AssertionList(interp, class->opt->assertions->invariants)); } } case AssertionsubcmdNULL: /* * Do nothing; just for detection if option was specified. */ break; } #endif return TCL_OK; } /* cmd method::create NsfMethodCreateCmd { {-argName "object" -required 1 -type object} {-argName "-checkalways" -required 0 -nrargs 0 -type switch} {-argName "-inner-namespace"} {-argName "-per-object"} {-argName "-reg-object" -required 0 -nrargs 1 -type object} {-argName "name" -required 1 -type tclobj} {-argName "arguments" -required 1 -type tclobj} {-argName "body" -required 1 -type tclobj} {-argName "-precondition" -nrargs 1 -type tclobj} {-argName "-postcondition" -nrargs 1 -type tclobj} } */ static int NsfMethodCreateCmd(Tcl_Interp *interp, NsfObject *object, int withCheckalways, int withInner_namespace, int withPer_object, NsfObject *regObject, Tcl_Obj *methodNameObj, Tcl_Obj *argumentsObj, Tcl_Obj *bodyObj, Tcl_Obj *preconditionObj, Tcl_Obj *postconditionObj) { NsfClass *class; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodNameObj != NULL); nonnull_assert(argumentsObj != NULL); nonnull_assert(bodyObj != NULL); class = (withPer_object || ! NsfObjectIsClass(object)) ? NULL : (NsfClass *)object; if (class == NULL) { RequireObjNamespace(interp, object); } return MakeMethod(interp, object, regObject, class, methodNameObj, argumentsObj, bodyObj, preconditionObj, postconditionObj, withInner_namespace, (withCheckalways != 0) ? NSF_ARGPARSE_CHECK : 0); } /* cmd "method::delete" NsfMethodDeleteCmd { {-argName "object" -required 1 -type object} {-argName "-per-object"} {-argName "methodName" -required 1 -type tclobj} } */ static int NsfMethodDeleteCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, Tcl_Obj *methodNameObj) { NsfObject *regObject, *defObject; const char *methodName1 = NULL; const NsfClass *class; bool fromClassNS; int result; Tcl_DString ds, *dsPtr = &ds; Tcl_Command cmd; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodNameObj != NULL); class = withPer_object == 0 && NsfObjectIsClass(object) ? (NsfClass *)object : NULL; fromClassNS = (class != NULL); Tcl_DStringInit(dsPtr); cmd = ResolveMethodName(interp, (class != NULL) ? class->nsPtr : object->nsPtr, methodNameObj, dsPtr, ®Object, &defObject, &methodName1, &fromClassNS); /*fprintf(stderr, "NsfMethodDeleteCmd method %s '%s' object %p regObject %p defObject %p cl %p fromClass %d cmd %p\n", ObjStr(methodNameObj), methodName1, object, regObject, defObject, cl, fromClassNS, cmd);*/ if (cmd != NULL) { methodName1 = Tcl_GetCommandName(interp, cmd); if (defObject != NULL) { class = (withPer_object == 0 && NsfObjectIsClass(defObject)) ? (NsfClass *)defObject : NULL; } else { defObject = object; } if (RUNTIME_STATE(interp)->exitHandlerDestroyRound == NSF_EXITHANDLER_OFF) { result = (class != NULL) ? NsfRemoveClassMethod(interp, (Nsf_Class *)defObject, methodName1) : NsfRemoveObjectMethod(interp, (Nsf_Object *)defObject, methodName1); } else { result = TCL_OK; } } else { result = NsfPrintError(interp, "%s: %s method '%s' does not exist", ObjectName_(object), (withPer_object == 1) ? "object specific" : "instance", ObjStr(methodNameObj)); } Tcl_DStringFree(dsPtr); return result; } /* cmd method::forward NsfMethodForwardCmd { {-argName "object" -required 1 -type object} {-argName "-per-object" -required 0 -nrargs 0 -type switch} {-argName "method" -required 1 -type tclobj} {-argName "-default" -type tclobj} {-argName "-earlybinding" -nrargs 0} {-argName "-prefix" -type tclobj} {-argName "-frame" -nrargs 1 -type "object|method|default" -default default} {-argName "-verbose" -nrargs 0} {-argName "target" -type tclobj} {-argName "args" -type args} } */ static int NsfMethodForwardCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, Tcl_Obj *methodObj, Tcl_Obj *defaultObj, int withEarlybinding, Tcl_Obj *onerrorObj, Tcl_Obj *prefixObj, FrameIdx_t withFrame, int withVerbose, Tcl_Obj *targetObj, int trailingObjc, Tcl_Obj *const trailingObjv[]) { ForwardCmdClientData *tcd = NULL; int result; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodObj != NULL); result = ForwardProcessOptions(interp, methodObj, defaultObj, withEarlybinding, onerrorObj, prefixObj, (int)withFrame, (withVerbose == 1), targetObj, trailingObjc, trailingObjv, &tcd); if (likely(result == TCL_OK)) { const char *methodName = NSTail(ObjStr(methodObj)); NsfClass *class = (withPer_object || ! NsfObjectIsClass(object)) ? NULL : (NsfClass *)object; tcd->object = object; if (class == NULL) { result = NsfAddObjectMethod(interp, (Nsf_Object *)object, methodName, (Tcl_ObjCmdProc *)NsfForwardMethod, tcd, ForwardCmdDeleteProc, 0u); } else { result = NsfAddClassMethod(interp, (Nsf_Class *)class, methodName, (Tcl_ObjCmdProc *)NsfForwardMethod, tcd, ForwardCmdDeleteProc, 0u); } if (likely(result == TCL_OK)) { Tcl_SetObjResult(interp, MethodHandleObj(object, (class == NULL), methodName)); } } if (result != TCL_OK && tcd != NULL) { ForwardCmdDeleteProc(tcd); } return result; } /* cmd "method::forward::property" NsfForwardPropertyCmd { {-argName "object" -required 1 -type object} {-argName "-per-object" -required 0 -nrargs 0 -type switch} {-argName "methodName" -required 1 -type tclobj} {-argName "forwardProperty" -required 1 -type "target|verbose"} {-argName "value" -type tclobj} } */ static int NsfForwardPropertyCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, Tcl_Obj *methodNameObj, ForwardpropertyIdx_t forwardProperty, Tcl_Obj *valueObj) { ForwardCmdClientData *tcd; Tcl_ObjCmdProc *procPtr; Tcl_Command cmd; NsfObject *defObject; const NsfClass *class; bool fromClassNS; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodNameObj != NULL); class = withPer_object == 0 && NsfObjectIsClass(object) ? (NsfClass *)object : NULL; fromClassNS = (class != NULL); cmd = ResolveMethodName(interp, (class != NULL) ? class->nsPtr : object->nsPtr, methodNameObj, NULL, NULL, &defObject, NULL, &fromClassNS); if (unlikely(cmd == NULL)) { return NsfPrintError(interp, "cannot lookup %smethod '%s' for %s", class == NULL ? "object " : "", ObjStr(methodNameObj), ObjectName_(object)); } procPtr = Tcl_Command_objProc(cmd); if (procPtr != NsfForwardMethod) { return NsfPrintError(interp, "%s is not a forwarder method", ObjStr(methodNameObj)); } tcd = (ForwardCmdClientData *)Tcl_Command_objClientData(cmd); if (tcd == NULL) { return NsfPrintError(interp, "forwarder method has no client data"); } switch (forwardProperty) { case ForwardpropertyTargetIdx: if (valueObj != NULL) { DECR_REF_COUNT(tcd->cmdName); INCR_REF_COUNT(valueObj); tcd->cmdName = valueObj; } Tcl_SetObjResult(interp, tcd->cmdName); break; case ForwardpropertyPrefixIdx: if (valueObj != NULL) { DECR_REF_COUNT(tcd->prefix); INCR_REF_COUNT(valueObj); tcd->prefix = valueObj; } Tcl_SetObjResult(interp, tcd->prefix); break; case ForwardpropertyVerboseIdx: if (valueObj != NULL) { int boolValue; Tcl_GetBooleanFromObj(interp, valueObj, &boolValue); tcd->verbose = (boolValue != 0); } Tcl_SetObjResult(interp, Tcl_NewBooleanObj(tcd->verbose)); break; case ForwardpropertyNULL: /* * Do nothing; just for detection if option was specified. */ break; } return TCL_OK; } /* cmd ::method::property NsfMethodPropertyCmd { {-argName "object" -required 1 -type object} {-argName "-per-object"} {-argName "methodName" -required 1 -type tclobj} {-argName "methodProperty" -required 1 -type "class-only|call-private|call-protected|debug|deprecated|exists|redefine-protected|returns"} {-argName "value" -type tclobj} } */ static int NsfMethodPropertyCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, Tcl_Obj *methodNameObj, MethodpropertyIdx_t methodProperty, Tcl_Obj *valueObj) { NsfObject *defObject; Tcl_Command cmd; const NsfClass *class; bool fromClassNS; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(methodNameObj != NULL); class = withPer_object == 0 && NsfObjectIsClass(object) ? (NsfClass *)object : NULL; fromClassNS = (class != NULL); cmd = ResolveMethodName(interp, (class != NULL) ? class->nsPtr : object->nsPtr, methodNameObj, NULL, NULL, &defObject, NULL, &fromClassNS); /*fprintf(stderr, "methodProperty for method '%s' prop %d value %s => cl %p cmd %p\n", ObjStr(methodNameObj), methodproperty, (valueObj != NULL) ? ObjStr(valueObj) : "NULL", cl, cmd);*/ if (unlikely(cmd == NULL)) { if (methodProperty == MethodpropertyExistsIdx) { Tcl_SetObjResult(interp, Tcl_NewIntObj(0)); return TCL_OK; } else { return NsfPrintError(interp, "cannot lookup %smethod '%s' for %s", class == NULL ? "object " : "", ObjStr(methodNameObj), ObjectName_(object)); } } switch (methodProperty) { case MethodpropertyExistsIdx: Tcl_SetObjResult(interp, Tcl_NewIntObj(1)); break; case MethodpropertyClass_onlyIdx: ;NSF_FALL_THROUGH; /* fall through */ case MethodpropertyCall_privateIdx: ;NSF_FALL_THROUGH; /* fall through */ case MethodpropertyCall_protectedIdx: ;NSF_FALL_THROUGH; /* fall through */ case MethodpropertyDebugIdx: ;NSF_FALL_THROUGH; /* fall through */ case MethodpropertyDeprecatedIdx: ;NSF_FALL_THROUGH; /* fall through */ case MethodpropertyRedefine_protectedIdx: { int impliedSetFlag = 0, impliedClearFlag = 0; unsigned int flag = 0u; switch (methodProperty) { case MethodpropertyClass_onlyIdx: flag = NSF_CMD_CLASS_ONLY_METHOD; break; case MethodpropertyCall_privateIdx: flag = NSF_CMD_CALL_PRIVATE_METHOD; impliedSetFlag = NSF_CMD_CALL_PROTECTED_METHOD; break; case MethodpropertyCall_protectedIdx: impliedClearFlag = NSF_CMD_CALL_PRIVATE_METHOD; flag = NSF_CMD_CALL_PROTECTED_METHOD; break; case MethodpropertyDebugIdx: flag = NSF_CMD_DEBUG_METHOD; break; case MethodpropertyDeprecatedIdx: flag = NSF_CMD_DEPRECATED_METHOD; break; case MethodpropertyRedefine_protectedIdx: flag = NSF_CMD_REDEFINE_PROTECTED_METHOD; break; case MethodpropertyNULL: ;NSF_FALL_THROUGH; /* fall through */ case MethodpropertyReturnsIdx: ;NSF_FALL_THROUGH; /* fall through */ case MethodpropertyExistsIdx: flag = 0u; break; } if (valueObj != NULL) { int boolVal, result; result = Tcl_GetBooleanFromObj(interp, valueObj, &boolVal); if (unlikely(result != TCL_OK)) { return result; } if (boolVal != 0) { /* * set flag */ Tcl_Command_flags(cmd) |= (int)flag; if (impliedSetFlag != 0) { Tcl_Command_flags(cmd) |= (int)impliedSetFlag; } } else { /* * clear flag */ Tcl_Command_flags(cmd) &= (int)~flag; if (impliedClearFlag != 0) { Tcl_Command_flags(cmd) &= (int)~impliedClearFlag; } } if (class != NULL) { NsfInstanceMethodEpochIncr("Permissions"); } else { NsfObjectMethodEpochIncr("Permissions"); } } Tcl_SetIntObj(Tcl_GetObjResult(interp), ((unsigned int)Tcl_Command_flags(cmd) & flag) != 0u); } break; case MethodpropertyReturnsIdx: { NsfProcContext *pCtx = ProcContextGet(cmd); /*fprintf(stderr, "MethodProperty, ParamDefsGet cmd %p paramDefs %p returns %p\n", cmd, paramDefs, (paramDefs != NULL) ? paramDefs->returns:NULL);*/ if (valueObj == NULL) { /* * Return the actual value for "returns". */ Tcl_Obj *resultObj; if (pCtx == NULL || pCtx->returnsObj == NULL) { resultObj = NsfGlobalObjs[NSF_EMPTY]; } else { resultObj = pCtx->returnsObj; } Tcl_SetObjResult(interp, resultObj); } else { /* * Set the value of "returns". */ const char *valueString = ObjStr(valueObj); if (pCtx == NULL) { pCtx = ProcContextRequire(cmd); } /* * Set a new value; if there is already a value, free it. */ if (pCtx->returnsObj != NULL) { DECR_REF_COUNT2("returnsObj", pCtx->returnsObj); } if (*valueString == '\0') { /* * Set returnsObj to NULL */ pCtx->returnsObj = NULL; } else { pCtx->returnsObj = valueObj; INCR_REF_COUNT2("returnsObj", pCtx->returnsObj); } } } break; case MethodpropertyNULL: /* * Do nothing; just for detection if option was specified. */ break; } return TCL_OK; } /* cmd "method::registered" NsfMethodRegisteredCmd { {-argName "handle" -required 1 -type tclobj} } */ static int NsfMethodRegisteredCmd(Tcl_Interp *interp, Tcl_Obj *handleObj) { NsfObject *regObject; bool fromClassNS = NSF_FALSE; Tcl_Command cmd; nonnull_assert(interp != NULL); nonnull_assert(handleObj != NULL); cmd = ResolveMethodName(interp, NULL, handleObj, NULL, ®Object, NULL, NULL, &fromClassNS); /* * In case the provided cmd is fully qualified and refers to a registered * method, the function returns the object, on which the method was * resisted. */ Tcl_SetObjResult(interp, ((cmd != NULL) && (regObject != NULL)) ? regObject->cmdName : NsfGlobalObjs[NSF_EMPTY]); return TCL_OK; } /* cmd method::setter NsfMethodSetterCmd { {-argName "object" -required 1 -type object} {-argName "-per-object"} {-argName "parameter" -type tclobj} } */ static int NsfMethodSetterCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, Tcl_Obj *parameterObj) { SetterCmdClientData *setterClientData; const NsfClass *class; const char *methodName; size_t j, length; int result; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(parameterObj != NULL); methodName = ObjStr(parameterObj); if (unlikely(*methodName == '-' || *methodName == ':')) { return NsfPrintError(interp, "invalid setter name \"%s\" (must not start with a dash or colon)", methodName); } setterClientData = NEW(SetterCmdClientData); setterClientData->object = NULL; setterClientData->paramsPtr = NULL; length = strlen(methodName); for (j = 0; j < length; j++) { if (methodName[j] == ':' || NsfHasTclSpace(&methodName[j])) { break; } } class = (withPer_object || ! NsfObjectIsClass(object)) ? NULL : (NsfClass *)object; if (j < length) { /* * Looks as if we have a parameter specification. */ int rc, possibleUnknowns = 0, plainParams = 0, nrNonposArgs = 0; NsfObject *ctx = (class != NULL) ? (NsfObject *)class : object; Tcl_Namespace *nsPtr = Tcl_Command_nsPtr(ctx->id); setterClientData->paramsPtr = ParamsNew(1u); rc = ParamDefinitionParse(interp, NsfGlobalObjs[NSF_SETTER], parameterObj, NSF_DISALLOWED_ARG_SETTER|NSF_ARG_HAS_DEFAULT, setterClientData->paramsPtr, &possibleUnknowns, &plainParams, &nrNonposArgs, nsPtr != NULL ? nsPtr->fullName : NULL); if (unlikely(rc != TCL_OK)) { SetterCmdDeleteProc(setterClientData); return rc; } methodName = setterClientData->paramsPtr->name; } else { setterClientData->paramsPtr = NULL; } if (class != NULL) { result = NsfAddClassMethod(interp, (Nsf_Class *)class, methodName, (Tcl_ObjCmdProc *)NsfSetterMethod, setterClientData, SetterCmdDeleteProc, 0u); } else { result = NsfAddObjectMethod(interp, (Nsf_Object *)object, methodName, (Tcl_ObjCmdProc *)NsfSetterMethod, setterClientData, SetterCmdDeleteProc, 0u); } if (likely(result == TCL_OK)) { Tcl_SetObjResult(interp, MethodHandleObj(object, class == NULL, methodName)); } else { SetterCmdDeleteProc(setterClientData); } return result; } /* cmd "object::alloc" NsfObjectAllocCmd { {-argName "class" -required 1 -type class} {-argName "name" -required 1 -type tclobj} {-argName "initcmd" -required 0 -type tclobj} } */ static int NsfObjectAllocCmd(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *nameObj, Tcl_Obj *initcmdObj) { Tcl_Obj *newNameObj = NULL; int result; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(nameObj != NULL); /* * If the provided name is empty, make a new symbol */ if (strlen(ObjStr(nameObj)) == 0) { Tcl_DString ds, *dsPtr = &ds; Tcl_DStringInit(dsPtr); Tcl_DStringAppend(dsPtr, autonamePrefix, (int)autonamePrefixLength); NewTclCommand(interp, dsPtr); newNameObj = Tcl_NewStringObj(Tcl_DStringValue(dsPtr), Tcl_DStringLength(dsPtr)); INCR_REF_COUNT(newNameObj); Tcl_DStringFree(dsPtr); nameObj = newNameObj; } /*fprintf(stderr, "trying to alloc <%s>\n", ObjStr(nameObj));*/ result = NsfCAllocMethod(interp, class, nameObj); if (result == TCL_OK && initcmdObj != NULL) { NsfObject *object; Tcl_Obj *initNameObj = Tcl_GetObjResult(interp); INCR_REF_COUNT(initNameObj); if (unlikely(GetObjectFromObj(interp, initNameObj, &object) != TCL_OK)) { result = NsfPrintError(interp, "couldn't find result of alloc"); } else { result = NsfDirectDispatchCmd(interp, object, 1, NsfGlobalObjs[NSF_EVAL], 1, &initcmdObj); if (likely(result == TCL_OK)) { Tcl_SetObjResult(interp, initNameObj); } } DECR_REF_COUNT(initNameObj); } if (newNameObj != NULL) { DECR_REF_COUNT(newNameObj); } return result; } /* cmd "object::exists" NsfObjectExistsCmd { {-argName "value" -required 1 -type tclobj} } */ static int NsfObjectExistsCmd(Tcl_Interp *interp, Tcl_Obj *valueObj) { NsfObject *object; nonnull_assert(interp != NULL); nonnull_assert(valueObj != NULL); /* * Pass the object as Tcl_Obj, since we do not want to raise an error in * case the object does not exist. */ Tcl_SetBooleanObj(Tcl_GetObjResult(interp), GetObjectFromObj(interp, valueObj, &object) == TCL_OK); return TCL_OK; } /* cmd "object::property" NsfObjectPropertyCmd { {-argName "object" -required 1 -type object} {-argName "objectproperty" -type "initialized|class|rootmetaclass|rootclass|volatile|autonamed|slotcontainer|hasperobjectslots|keepcallerself|perobjectdispatch" -required 1} {-argName "value" -required 0 -type tclobj} } */ static int NsfObjectPropertyCmd(Tcl_Interp *interp, NsfObject *object, ObjectpropertyIdx_t objectProperty, Tcl_Obj *valueObj) { unsigned int flags = 0u, allowSet = 0u; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); switch (objectProperty) { case ObjectpropertyAutonamedIdx: flags = NSF_IS_AUTONAMED; allowSet = 1; break; case ObjectpropertyInitializedIdx: flags = NSF_INIT_CALLED; allowSet = 1; break; case ObjectpropertyClassIdx: flags = NSF_IS_CLASS; break; case ObjectpropertyRootmetaclassIdx: flags = NSF_IS_ROOT_META_CLASS; break; case ObjectpropertyVolatileIdx: if (valueObj == NULL) { Tcl_SetObjResult(interp, NsfGlobalObjs[object->opt != NULL && object->opt->volatileVarName ? NSF_ONE : NSF_ZERO]); return TCL_OK; } allowSet = 1; break; /* * If a value is provided, return the error below. */ case ObjectpropertyRootclassIdx: flags = NSF_IS_ROOT_CLASS; break; case ObjectpropertySlotcontainerIdx: flags = NSF_IS_SLOT_CONTAINER; allowSet = 1; break; case ObjectpropertyKeepcallerselfIdx: flags = NSF_KEEP_CALLER_SELF; allowSet = 1; break; case ObjectpropertyPerobjectdispatchIdx: flags = NSF_PER_OBJECT_DISPATCH; allowSet = 1; break; case ObjectpropertyHasperobjectslotsIdx: flags = NSF_HAS_PER_OBJECT_SLOTS; allowSet = 1; break; case ObjectpropertyNULL: /* * Do nothing; just for detection if option was specified. */ break; } if (valueObj != NULL) { if (likely(allowSet)) { int flagValue, result; result = SetBooleanFlag(interp, &object->flags, flags, valueObj, &flagValue); if (unlikely(result != TCL_OK)) { return result; } if (objectProperty == ObjectpropertySlotcontainerIdx) { assert(object->nsPtr != NULL); if (flagValue != 0) { /* * Turn on SlotContainerCmdResolver. */ Tcl_SetNamespaceResolvers(object->nsPtr, (Tcl_ResolveCmdProc *)SlotContainerCmdResolver, NsColonVarResolver, (Tcl_ResolveCompiledVarProc *)NULL); } else { /* * Turn off SlotContainerCmdResolver. */ Tcl_SetNamespaceResolvers(object->nsPtr, (Tcl_ResolveCmdProc *)NULL, NsColonVarResolver, (Tcl_ResolveCompiledVarProc *)NULL); } } else if (objectProperty == ObjectpropertyVolatileIdx) { bool objectIsVolatile = (object->opt != NULL && object->opt->volatileVarName != NULL); if (flagValue != 0 && !objectIsVolatile) { /* * Set volatile property. */ /*NsfObjectSystem *osPtr = GetObjectSystem(object);*/ /*fprintf(stderr, "change volatile ... make volatile %s\n", ObjectName(&osPtr->rootClass->object));*/ result = VolatileMethod(interp, object, NSF_TRUE); } else if (flagValue == 0 && objectIsVolatile) { /* * Remove volatile property. */ UnsetTracedVars(interp, object); object->opt->volatileVarName = NULL; } else { /* * Nothing to do. */ } if (unlikely(result != TCL_OK)) { return result; } } } else { return NsfPrintError(interp, "object property is read only"); } } Tcl_SetObjResult(interp, NsfGlobalObjs[(object->flags & flags) ? NSF_ONE : NSF_ZERO]); return TCL_OK; } /* cmd "object::qualify" NsfObjectQualifyCmd { {-argName "objectName" -required 1 -type tclobj} } */ static int NsfObjectQualifyCmd(Tcl_Interp *interp, Tcl_Obj *objectNameObj) { const char *nameString; nonnull_assert(interp != NULL); nonnull_assert(objectNameObj != NULL); nameString = ObjStr(objectNameObj); if (isAbsolutePath(nameString)) { Tcl_SetObjResult(interp, objectNameObj); } else { Tcl_SetObjResult(interp, NameInNamespaceObj(nameString, CallingNameSpace(interp))); } return TCL_OK; } /* cmd "objectsystem::create" NsfObjectSystemCreateCmd { {-argName "rootClass" -required 1 -type tclobj} {-argName "rootMetaClass" -required 1 -type tclobj} {-argName "systemMethods" -required 0 -type tclobj} } */ static int NsfObjectSystemCreateCmd(Tcl_Interp *interp, Tcl_Obj *rootClassObj, Tcl_Obj *rootMetaClassObj, Tcl_Obj *systemMethodsObj) { NsfClass *theobj = NULL, *thecls = NULL; Tcl_Obj *object, *class; const char *objectName, *className; NsfObjectSystem *osPtr; nonnull_assert(interp != NULL); nonnull_assert(rootClassObj != NULL); nonnull_assert(rootMetaClassObj != NULL); osPtr = NEW(NsfObjectSystem); memset(osPtr, 0, sizeof(NsfObjectSystem)); objectName = ObjStr(rootClassObj); object = isAbsolutePath(objectName) ? rootClassObj : NameInNamespaceObj(objectName, CallingNameSpace(interp)); className = ObjStr(rootMetaClassObj); class = isAbsolutePath(className) ? rootMetaClassObj : NameInNamespaceObj(className, CallingNameSpace(interp)); GetClassFromObj(interp, object, &theobj, NSF_FALSE); GetClassFromObj(interp, class, &thecls, NSF_FALSE); if ((theobj != NULL) || (thecls != NULL)) { ObjectSystemFree(interp, osPtr); NsfLog(interp, NSF_LOG_WARN, "Base class '%s' exists already; ignoring definition", (theobj != NULL) ? objectName : className); return TCL_OK; } if (systemMethodsObj != NULL) { int oc, idx; Tcl_Obj **ov; if ((Tcl_ListObjGetElements(interp, systemMethodsObj, &oc, &ov)) == TCL_OK) { int i; if (oc % 2) { ObjectSystemFree(interp, osPtr); return NsfPrintError(interp, "system methods must be provided as pairs"); } for (i = 0; i < oc; i += 2) { Tcl_Obj *arg, **arg_ov = NULL; int arg_oc = -1, result; arg = ov[i+1]; result = Tcl_GetIndexFromObj(interp, ov[i], Nsf_SystemMethodOpts, "system method", 0, &idx); if (likely(result == TCL_OK)) { result = Tcl_ListObjGetElements(interp, arg, &arg_oc, &arg_ov); } if (unlikely(result != TCL_OK)) { ObjectSystemFree(interp, osPtr); return NsfPrintError(interp, "invalid system method '%s'", ObjStr(ov[i])); } else if (arg_oc < 1 || arg_oc > 3) { ObjectSystemFree(interp, osPtr); return NsfPrintError(interp, "invalid system method argument '%s'", ObjStr(ov[i]), ObjStr(arg)); } /*fprintf(stderr, "NsfCreateObjectSystemCmd [%d] = %p %s (max %d, given %d)\n", idx, ov[i+1], ObjStr(ov[i+1]), NSF_s_set_idx, oc);*/ if (arg_oc == 1) { osPtr->methods[idx] = arg; osPtr->methodNames[idx] = ObjStr(arg); } else { /* (arg_oc == 2) */ osPtr->methods[idx] = arg_ov[0]; osPtr->methodNames[idx] = ObjStr(arg_ov[0]); osPtr->handles[idx] = arg_ov[1]; if (arg_oc == 3) { int boolVal = 0; Tcl_GetBooleanFromObj(interp, arg_ov[2], &boolVal); osPtr->protected[idx] = (char)boolVal; } INCR_REF_COUNT(osPtr->handles[idx]); } INCR_REF_COUNT(osPtr->methods[idx]); } } else { ObjectSystemFree(interp, osPtr); return NsfPrintError(interp, "provided system methods are not a proper list"); } } /* * Create a basic object system with the basic root-class Object and the * basic metaclass Class, and store them in the RUNTIME STATE if successful. */ theobj = PrimitiveCCreate(interp, object, NULL, NULL); thecls = PrimitiveCCreate(interp, class, NULL, NULL); /* fprintf(stderr, "CreateObjectSystem created base classes \n"); */ /* * Check whether Object and Class creation was successful. */ if ((theobj == NULL) || (thecls == NULL)) { if (thecls != NULL) { PrimitiveCDestroy(thecls); } if (theobj != NULL) { PrimitiveCDestroy(theobj); } ObjectSystemFree(interp, osPtr); return NsfPrintError(interp, "creation of object system failed"); } theobj->osPtr = osPtr; thecls->osPtr = osPtr; osPtr->rootClass = theobj; osPtr->rootMetaClass = thecls; theobj->object.flags |= (NSF_IS_ROOT_CLASS|NSF_INIT_CALLED); thecls->object.flags |= (NSF_IS_ROOT_META_CLASS|NSF_INIT_CALLED); ObjectSystemAdd(interp, osPtr); AddInstance((NsfObject *)theobj, thecls); AddInstance((NsfObject *)thecls, thecls); AddSuper(thecls, theobj); if (NSF_DTRACE_OBJECT_ALLOC_ENABLED()) { NSF_DTRACE_OBJECT_ALLOC(ObjectName((NsfObject *)theobj), ClassName(((NsfObject *)theobj)->cl)); NSF_DTRACE_OBJECT_ALLOC(ObjectName((NsfObject *)thecls), ClassName(((NsfObject *)thecls)->cl)); } return TCL_OK; } /* cmd my NsfMyCmd { {-argName "-intrinsic" -nrargs 0} {-argName "-local" -nrargs 0} {-argName "-system" -nrargs 0} {-argName "method" -required 1 -type tclobj} {-argName "args" -type args} } */ static int NsfMyCmd(Tcl_Interp *interp, int withIntrinsic, int withLocal, int withSystem, Tcl_Obj *methodNameObj, int trailingObjc, Tcl_Obj *const trailingObjv[]) { NsfObject *self; int result; nonnull_assert(interp != NULL); nonnull_assert(methodNameObj != NULL); self = GetSelfObj(interp); if (unlikely(self == NULL)) { result = NsfNoCurrentObjectError(interp, method_definitions[NsfMyCmdIdx].methodName); } else if ((withIntrinsic && withLocal) || (withIntrinsic && withSystem) || (withLocal && withSystem)) { result = NsfPrintError(interp, "flags '-intrinsic', '-local' and '-system' are mutual exclusive"); } else { unsigned int flags; #if 0 /* TODO attempt to make "my" NRE-enabled, failed so far (crash in mixinInheritanceTest) */ NsfCallStackContent *cscPtr = CallStackGetTopFrame0(interp); if (cscPtr == NULL || self != cscPtr->self) { flags = NSF_CSC_IMMEDIATE; } else { flags = NsfImmediateFromCallerFlags(cscPtr->flags); fprintf(stderr, "XXX MY %s.%s frame has flags %.6x -> next-flags %.6x\n", ObjectName(self), ObjStr(methodNameObj), cscPtr->flags, flags); } if (withIntrinsic != 0) {flags |= NSF_CM_INTRINSIC_METHOD;} if (withLocal != 0) {flags |= NSF_CM_LOCAL_METHOD;} if (withSystem != 0) {flags |= NSF_CM_SYSTEM_METHOD;} result = CallMethod(self, interp, methodNameObj, trailingObjc+2, trailingObjv, flags); #else flags = NSF_CSC_IMMEDIATE; if (withIntrinsic != 0) {flags |= NSF_CM_INTRINSIC_METHOD;} if (withLocal != 0) {flags |= NSF_CM_LOCAL_METHOD;} if (withSystem != 0) {flags |= NSF_CM_SYSTEM_METHOD;} result = CallMethod(self, interp, methodNameObj, trailingObjc+2, trailingObjv, flags); #endif } return result; } /* *---------------------------------------------------------------------- * NsfNextCmd -- * * nsf::next calls the next shadowed method. It might get a single * argument which is used as argument vector for that method. If no * argument is provided, the argument vector of the last invocation * is used. * * Results: * A standard Tcl result. * * Side effects: * The invoked method might produce side effects * *---------------------------------------------------------------------- */ /* cmd next NsfNextCmd { {-argName "arguments" -required 0 -type tclobj} } */ static int NsfNextCmd(Tcl_Interp *interp, Tcl_Obj *argumentsObj) { int oc, nobjc = 0, result; bool freeArgumentVector; NsfCallStackContent *cscPtr = NULL; const char *methodName = NULL; Tcl_Obj **nobjv = NULL, **ov; nonnull_assert(interp != NULL); if (argumentsObj != NULL) { /* * Arguments were provided. */ int rc = Tcl_ListObjGetElements(interp, argumentsObj, &oc, &ov); if (unlikely(rc != TCL_OK)) { return rc; } } else { /* * No arguments were provided. */ oc = -1; ov = NULL; } result = NextGetArguments(interp, oc, ov, &cscPtr, &methodName, &nobjc, &nobjv, &freeArgumentVector); if (likely(result == TCL_OK)) { assert(cscPtr != NULL); assert(methodName != NULL); result = NextSearchAndInvoke(interp, methodName, nobjc, nobjv, cscPtr, freeArgumentVector); } return result; } /* cmd nscopyvars NsfNSCopyVars { {-argName "fromNs" -required 1 -type tclobj} {-argName "toNs" -required 1 -type tclobj} } */ static int NsfNSCopyVarsCmd(Tcl_Interp *interp, Tcl_Obj *fromNsObj, Tcl_Obj *toNsObj) { Tcl_Namespace *fromNsPtr = NULL, *toNsPtr; Var *varPtr = NULL; Tcl_HashSearch hSrch; const Tcl_HashEntry *hPtr; TclVarHashTable *varTablePtr; NsfObject *destObject; const char *destFullName; Tcl_Obj *destFullNameObj; Tcl_CallFrame frame, *framePtr = &frame; int result; nonnull_assert(interp != NULL); nonnull_assert(fromNsObj != NULL); nonnull_assert(toNsObj != NULL); TclGetNamespaceFromObj(interp, fromNsObj, &fromNsPtr); if (fromNsPtr != NULL) { if (TclGetNamespaceFromObj(interp, toNsObj, &toNsPtr) != TCL_OK) { return NsfPrintError(interp, "CopyVars: Destination namespace %s does not exist", ObjStr(toNsObj)); } destFullName = toNsPtr->fullName; destFullNameObj = Tcl_NewStringObj(destFullName, TCL_INDEX_NONE); INCR_REF_COUNT(destFullNameObj); varTablePtr = Tcl_Namespace_varTablePtr(fromNsPtr); Tcl_PushCallFrame(interp, (Tcl_CallFrame *)framePtr, toNsPtr, 0); } else { NsfObject *newObject, *object; if (GetObjectFromObj(interp, fromNsObj, &object) != TCL_OK) { return NsfPrintError(interp, "CopyVars: Origin object/namespace %s does not exist", ObjStr(fromNsObj)); } else if (GetObjectFromObj(interp, toNsObj, &newObject) != TCL_OK) { return NsfPrintError(interp, "CopyVars: Destination object/namespace %s does not exist", ObjStr(toNsObj)); } else { varTablePtr = object->varTablePtr; destFullNameObj = newObject->cmdName; destFullName = ObjStr(destFullNameObj); } } destObject = GetObjectFromString(interp, destFullName); result = TCL_OK; /* * Copy all vars in the namespace. */ hPtr = (varTablePtr != NULL) ? Tcl_FirstHashEntry(TclVarHashTablePtr(varTablePtr), &hSrch) : NULL; while (hPtr != NULL) { Tcl_Obj *varNameObj, *resultObj; GetVarAndNameFromHash(hPtr, &varPtr, &varNameObj); INCR_REF_COUNT(varNameObj); if (!TclIsVarUndefined(varPtr) && !TclIsVarLink(varPtr)) { if (TclIsVarScalar(varPtr)) { /* * Copy scalar variables from the namespace, which might be * either instance or namespace variables. */ if (destObject != NULL) { /* fprintf(stderr, "copy in obj %s var %s val '%s'\n", ObjectName(destObject), ObjStr(varNameObj), ObjStr(TclVarValue(Tcl_Obj, varPtr, objPtr)));*/ resultObj = Nsf_ObjSetVar2((Nsf_Object *)destObject, interp, varNameObj, NULL, TclVarValue(Tcl_Obj, varPtr, objPtr), TCL_LEAVE_ERR_MSG); } else { resultObj = Tcl_ObjSetVar2(interp, varNameObj, NULL, TclVarValue(Tcl_Obj, varPtr, objPtr), TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG); } if (unlikely(resultObj == NULL)) { DECR_REF_COUNT(varNameObj); result = TCL_ERROR; goto copy_done; } } else { if (TclIsVarArray(varPtr)) { /* HERE!! PRE85 Why not [array get/set] based? Let the core iterate */ TclVarHashTable *aTable = TclVarValue(TclVarHashTable, varPtr, tablePtr); Tcl_HashSearch ahSrch; Tcl_HashEntry *ahPtr = (aTable != NULL) ? Tcl_FirstHashEntry(TclVarHashTablePtr(aTable), &ahSrch) : 0; for (; ahPtr != NULL; ahPtr = Tcl_NextHashEntry(&ahSrch)) { Tcl_Obj *eltNameObj; Var *eltVar; GetVarAndNameFromHash(ahPtr, &eltVar, &eltNameObj); INCR_REF_COUNT(eltNameObj); if (TclIsVarScalar(eltVar)) { if (destObject != NULL) { resultObj = Nsf_ObjSetVar2((Nsf_Object *)destObject, interp, varNameObj, eltNameObj, TclVarValue(Tcl_Obj, eltVar, objPtr), TCL_LEAVE_ERR_MSG); } else { resultObj = Tcl_ObjSetVar2(interp, varNameObj, eltNameObj, TclVarValue(Tcl_Obj, eltVar, objPtr), TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG); } if (unlikely(resultObj == NULL)) { DECR_REF_COUNT(varNameObj); result = TCL_ERROR; goto copy_done; } } DECR_REF_COUNT(eltNameObj); } } } } DECR_REF_COUNT(varNameObj); hPtr = Tcl_NextHashEntry(&hSrch); } copy_done: if (fromNsPtr != NULL) { DECR_REF_COUNT(destFullNameObj); Tcl_PopCallFrame(interp); } return result; } /* cmd parameter::info NsfParameterInfoCmd { {-argName "subcmd" -typeName "parametersubcmd" -type "default|list|name|syntax|type" -required 1} {-argName "parameterspec" -required 1 -type tclobj} {-argName "varname" -required 0 -type tclobj} } */ static int NsfParameterInfoCmd(Tcl_Interp *interp, ParametersubcmdIdx_t subcmd, Tcl_Obj *specObj, Tcl_Obj *varnameObj) { NsfParsedParam parsedParam; Tcl_Obj *paramsObj, *listObj = NULL; Nsf_Param *paramsPtr; int result; nonnull_assert(interp != NULL); nonnull_assert(specObj != NULL); if (subcmd != ParametersubcmdDefaultIdx && varnameObj != NULL) { return NsfPrintError(interp, "parameter::info: provided third argument is only valid for querying defaults"); } paramsObj = Tcl_NewListObj(1, &specObj); INCR_REF_COUNT(paramsObj); result = ParamDefsParse(interp, NULL, paramsObj, NSF_DISALLOWED_ARG_OBJECT_PARAMETER, NSF_TRUE, &parsedParam, NULL); DECR_REF_COUNT(paramsObj); if (unlikely(result != TCL_OK)) { return result; } assert(parsedParam.paramDefs != NULL); paramsPtr = parsedParam.paramDefs->paramsPtr; assert(paramsPtr != NULL); /* * Since we are passing in a parameter definition in Tcl syntax, and we want * to extract information from that syntax, it makes limited sense to * provide a context object for virtual parameter expansion. At least, we do * not allow this so far. */ switch (subcmd) { case ParametersubcmdDefaultIdx: if (paramsPtr->defaultValue != NULL) { if (varnameObj != NULL) { Tcl_Obj *resultObj = Tcl_ObjSetVar2(interp, varnameObj, NULL, paramsPtr->defaultValue, TCL_LEAVE_ERR_MSG); if (unlikely(resultObj == NULL)) { ParamDefsRefCountDecr(parsedParam.paramDefs); return TCL_ERROR; } } Tcl_SetObjResult(interp, NsfGlobalObjs[NSF_ONE]); } else { Tcl_SetObjResult(interp, NsfGlobalObjs[NSF_ZERO]); } break; case ParametersubcmdListIdx: listObj = ParamDefsList(interp, paramsPtr, NULL, NULL); Tcl_SetObjResult(interp, listObj); DECR_REF_COUNT2("paramDefsObj", listObj); break; case ParametersubcmdNameIdx: listObj = ParamDefsNames(interp, paramsPtr, NULL, NULL); Tcl_SetObjResult(interp, listObj); DECR_REF_COUNT2("paramDefsObj", listObj); break; case ParametersubcmdSyntaxIdx: listObj = NsfParamDefsSyntax(interp, paramsPtr, NULL, NULL); Tcl_SetObjResult(interp, listObj); DECR_REF_COUNT2("paramDefsObj", listObj); break; case ParametersubcmdTypeIdx: if (paramsPtr->type != NULL) { if (paramsPtr->converter == Nsf_ConvertToTclobj && paramsPtr->converterArg) { Tcl_SetObjResult(interp, paramsPtr->converterArg); } else { if (paramsPtr->converter == Nsf_ConvertToObject || paramsPtr->converter == Nsf_ConvertToClass) { const char *what = paramsPtr->type; /* * baseclass and metaclass are communicated via flags */ if (unlikely((paramsPtr->flags & NSF_ARG_BASECLASS) != 0u)) { what = "baseclass"; } else if (unlikely((paramsPtr->flags & NSF_ARG_METACLASS) != 0u)) { what = "metaclass"; } /* * The converterArg might contain a class for type checking */ if (paramsPtr->converterArg == NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj(what, TCL_INDEX_NONE)); } else { Tcl_SetObjResult(interp, paramsPtr->converterArg); } } else { Tcl_SetObjResult(interp, Tcl_NewStringObj(paramsPtr->type, TCL_INDEX_NONE)); } } } else { Tcl_SetObjResult(interp, NsfGlobalObjs[NSF_EMPTY]); } break; case ParametersubcmdNULL: /* * Do nothing; just for detection if option was specified. */ break; } ParamDefsRefCountDecr(parsedParam.paramDefs); return TCL_OK; } /* cmd parameter::cache::classinvalidate NsfParameterCacheClassInvalidateCmd { {-argName "class" -required 1 -type class} } */ static int NsfParameterCacheClassInvalidateCmd(Tcl_Interp *interp, NsfClass *class) { nonnull_assert(interp != NULL); nonnull_assert(class != NULL); /* * First, increment the epoch in case we have a parsedParam. The * classParamPtrEpoch is just used for PER_OBJECT_PARAMETER_CACHING */ #if defined(PER_OBJECT_PARAMETER_CACHING) if (unlikely(class->parsedParamPtr != NULL)) { NsfClassParamPtrEpochIncr("NsfParameterCacheClassInvalidateCmd"); } #endif /* * During shutdown, no new objects are created, therefore, we do not need to * to invalidate the cached parsedParamPtr of the classes. */ if (unlikely(RUNTIME_STATE(interp)->exitHandlerDestroyRound == NSF_EXITHANDLER_OFF)) { NsfClasses *dependentSubClasses; NsfClasses *clPtr; /* * Clear the cached parsedParam of the class and all its subclasses (the * result of DependentSubClasses() contains the starting * class). Furthermore, make a quick check whether any of the subclasses * is a class mixin of some other class. */ dependentSubClasses = DependentSubClasses(class); if (dependentSubClasses != NULL) { for (clPtr = dependentSubClasses; clPtr != NULL; clPtr = clPtr->nextPtr) { NsfClass *subClass = clPtr->cl; if (subClass->parsedParamPtr != NULL) { ParsedParamFree(subClass->parsedParamPtr); subClass->parsedParamPtr = NULL; } } NsfClassListFree(dependentSubClasses); } } return TCL_OK; } /* cmd parameter::cache::objectinvalidate NsfParameterCacheObjectInvalidateCmd { {-argName "object" -required 1 -type object} } */ static int NsfParameterCacheObjectInvalidateCmd(Tcl_Interp *UNUSED(interp), NsfObject *object) { nonnull_assert(object != NULL); #if defined(PER_OBJECT_PARAMETER_CACHING) if (object->opt != NULL && object->opt->parsedParamPtr) { /*fprintf(stderr, " %p %s invalidate %p\n", object, ObjectName(object), object->opt->parsedParamPtr);*/ ParsedParamFree(object->opt->parsedParamPtr); object->opt->parsedParamPtr = NULL; } #endif return TCL_OK; } /* cmd parameter::specs NsfParameterSpecsCmd { {-argName "-configure" -nrargs 0 -required 0} {-argName "-nonposargs" -nrargs 0 -required 0} {-argName "slotobjs" -required 1 -type tclobj} } */ static int NsfParameterSpecsCmd(Tcl_Interp *interp, int withConfigure, int withNonposargs, Tcl_Obj *slotobjsObj) { NsfTclObjList *objList = NULL, *elt; Tcl_Obj **objv, *resultObj; int result = TCL_OK, i, objc; nonnull_assert(interp != NULL); nonnull_assert(slotobjsObj != NULL); if (Tcl_ListObjGetElements(interp, slotobjsObj, &objc, &objv) != TCL_OK) { return NsfPrintError(interp, "NsfParameterSpecsCmd: invalid slot object list"); } /* * Iterate over the slot objects and obtain the position and the * parameterSpec. */ for (i = 0; i < objc; i++) { NsfObject *slotObject; Tcl_Obj *positionObj, *specObj = NULL; if (GetObjectFromObj(interp, objv[i], &slotObject) != TCL_OK) { return NsfPrintError(interp, "objectparameter: slot element is not a next scripting object"); } assert(slotObject != NULL); /* * When withConfigure is provided, skip this parameter ... * - when configure is not set * - or configure == 0 */ if (withConfigure != 0) { int configure = 0; Tcl_Obj *configureObj = Nsf_ObjGetVar2((Nsf_Object *)slotObject, interp, NsfGlobalObjs[NSF_CONFIGURABLE], NULL, 0); if (configureObj == NULL) { continue; } Tcl_GetBooleanFromObj(interp, configureObj, &configure); if (configure == 0) { continue; } } /* * When withNonposargs is provided, skip this parameter ... * - when positional == 1 */ if (withNonposargs != 0) { Tcl_Obj *positionalObj = Nsf_ObjGetVar2((Nsf_Object *)slotObject, interp, NsfGlobalObjs[NSF_POSITIONAL], NULL, 0); if (positionalObj != NULL) { int positional = 0; Tcl_GetBooleanFromObj(interp, positionalObj, &positional); if (positional != 0) { continue; } } } positionObj = Nsf_ObjGetVar2((Nsf_Object *)slotObject, interp, NsfGlobalObjs[NSF_POSITION], NULL, 0); specObj = Nsf_ObjGetVar2((Nsf_Object *)slotObject, interp, NsfGlobalObjs[NSF_PARAMETERSPEC], NULL, 0); if (specObj == NULL) { result = CallMethod(slotObject, interp, NsfGlobalObjs[NSF_GET_PARAMETER_SPEC], 2, NULL, NSF_CM_IGNORE_PERMISSIONS|NSF_CSC_IMMEDIATE); if (unlikely(result != TCL_OK)) { return NsfPrintError(interp, "objectparameter: %s %s returned error", ObjectName_(slotObject), NsfGlobalStrings[NSF_GET_PARAMETER_SPEC]); } specObj = Tcl_GetObjResult(interp); } /*fprintf(stderr, "NsfParameterSpecsCmd slot obj = %s pos %s spec %s\n", ObjStr(objv[i]), (positionObj != NULL) ? ObjStr(positionObj) : "NONE", ObjStr(specObj) );*/ /* * Add the spec to the list indicated by the position */ TclObjListAdd(interp, &objList, positionObj, specObj); } /* * Fold the per-position lists into a flat result list */ resultObj = Tcl_NewListObj(0, NULL); for (elt = objList; elt != NULL; elt = elt->nextPtr) { Tcl_ListObjGetElements(interp, elt->payload, &objc, &objv); for (i = 0; i < objc; i++) { Tcl_ListObjAppendElement(interp, resultObj, objv[i]); } } Tcl_SetObjResult(interp, resultObj); if (objList != NULL) { TclObjListFreeList(objList); } return result; } /* cmd proc NsfProcCmd { {-argName "-ad" -required 0 -nrargs 0 -type switch} {-argName "-checkalways" -required 0 -nrargs 0 -type switch} {-argName "-debug" -required 0 -nrargs 0 -type switch} {-argName "-deprecated" -required 0 -nrargs 0 -type switch} {-argName "procName" -required 1 -type tclobj} {-argName "arguments" -required 1 -type tclobj} {-argName "body" -required 1 -type tclobj} } */ static int NsfProcCmd(Tcl_Interp *interp, int withAd, int withCheckalways, int withDebug, int withDeprecated, Tcl_Obj *procNameObj, Tcl_Obj *argumentsObj, Tcl_Obj *bodyObj) { NsfParsedParam parsedParam; int result; nonnull_assert(interp != NULL); nonnull_assert(procNameObj != NULL); nonnull_assert(argumentsObj != NULL); nonnull_assert(bodyObj != NULL); /* * Parse argument list "arguments" to determine if we should provide * nsf parameter handling. */ result = ParamDefsParse(interp, procNameObj, argumentsObj, NSF_DISALLOWED_ARG_METHOD_PARAMETER, (withDebug != 0), &parsedParam, Tcl_GetCurrentNamespace(interp)->fullName); if (unlikely(result != TCL_OK)) { return result; } if (parsedParam.paramDefs != NULL || withDebug != 0 || withDeprecated != 0) { /* * We need parameter handling. In such cases, a thin C-based layer * is added which handles the parameter passing and calls the proc * later. */ result = NsfProcAdd(interp, &parsedParam, ObjStr(procNameObj), bodyObj, withAd, withCheckalways, withDebug, withDeprecated); } else { /* * No parameter handling needed. A plain Tcl proc is added. */ Tcl_Obj *ov[4]; ov[0] = NULL; ov[1] = procNameObj; ov[2] = argumentsObj; ov[3] = bodyObj; result = Tcl_ProcObjCmd(0, interp, 4, ov); } return result; } /* cmd relation::get NsfRelationGetCmd { {-argName "object" -type object} {-argName "type" -required 1 -typeName "relationtype" -type "object-mixin|class-mixin|object-filter|class-filter|class|superclass|rootclass"} } */ static int NsfRelationGetCmd(Tcl_Interp *interp, NsfObject *object, RelationtypeIdx_t type) { return NsfRelationSetCmd(interp, object, type, NULL); } /* *---------------------------------------------------------------------- * NsfRelationClassMixinsSet -- * * Set class mixins; the main reason for the factored-out semantics is that * it supports to undo/redo the operations in case of a failure. * * Results: * A standard Tcl result. * * Side effects: * class mixins are set, various kinds of invalidations. * *---------------------------------------------------------------------- */ static int NsfRelationClassMixinsSet(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *valueObj, int oc, Tcl_Obj **ov) nonnull(1) nonnull(2) nonnull(3); static int NsfRelationClassMixinsSet(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *valueObj, int oc, Tcl_Obj **ov) { NsfCmdList *newMixinCmdList = NULL, *cmds; NsfClasses *subClasses; NsfClassOpt *clopt; int i; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(valueObj != NULL); for (i = 0; i < oc; i++) { if (unlikely(MixinAdd(interp, &newMixinCmdList, ov[i]) != TCL_OK)) { CmdListFree(&newMixinCmdList, GuardDel); return TCL_ERROR; } } clopt = class->opt; assert(clopt != NULL); if (clopt->classMixins != NULL) { RemoveFromClassMixinsOf(class->object.id, clopt->classMixins); CmdListFree(&clopt->classMixins, GuardDel); } subClasses = DependentSubClasses(class); MixinInvalidateObjOrders(subClasses); /* * Since methods of mixed in classes may be used as filters, we have to * invalidate the filters as well. */ if (FiltersDefined(interp) > 0) { FilterInvalidateObjOrders(interp, subClasses); } NsfClassListFree(subClasses); /* * Now register the specified mixins. */ clopt->classMixins = newMixinCmdList; /* * Finally, update classMixinOfs */ for (cmds = newMixinCmdList; cmds; cmds = cmds->nextPtr) { NsfObject *nObject = NsfGetObjectFromCmdPtr(cmds->cmdPtr); if (nObject != NULL) { NsfClassOpt *nclopt = NsfRequireClassOpt((NsfClass *) nObject); CmdListAddSorted(&nclopt->isClassMixinOf, class->object.id, NULL); } else { NsfLog(interp, NSF_LOG_WARN, "Problem registering %s as a class mixin of %s\n", ObjStr(valueObj), ClassName_(class)); } } return TCL_OK; } /* cmd relation::set NsfRelationSetCmd { {-argName "object" -required 1 -type object} {-argName "type" -required 1 -typeName "relationtype" -type "object-mixin|class-mixin|object-filter|class-filter|class|superclass|rootclass"} {-argName "value" -required 0 -type tclobj} } */ static int NsfRelationSetCmd(Tcl_Interp *interp, NsfObject *object, RelationtypeIdx_t type, Tcl_Obj *valueObj) { int oc = 0, i; Tcl_Obj **ov; NsfClass *class = NULL; NsfObjectOpt *objopt = NULL; NsfClassOpt *clopt = NULL, *nclopt = NULL; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); /*fprintf(stderr, "NsfRelationSetCmd %s rel=%d val='%s'\n", ObjectName(object), relationtype, (valueObj != NULL) ? ObjStr(valueObj) : "NULL");*/ if (type == RelationtypeClass_mixinIdx || type == RelationtypeClass_filterIdx) { if (NsfObjectIsClass(object)) { class = (NsfClass *)object; } else { /* * Fall back to per-object case. */ type = (type == RelationtypeClass_mixinIdx) ? RelationtypeObject_mixinIdx : RelationtypeObject_filterIdx ; } } /* * The first switch block is just responsible for obtaining objopt or clopt * or handling other simple cases. */ switch (type) { case RelationtypeObject_filterIdx: ;NSF_FALL_THROUGH; /* fall through */ case RelationtypeObject_mixinIdx: if (valueObj == NULL) { objopt = object->opt; if (type == RelationtypeObject_mixinIdx) { return (objopt != NULL) ? MixinInfo(interp, objopt->objMixins, NULL, NSF_TRUE, NULL) : TCL_OK; } else /* (type == RelationtypeObject_filterIdx) */ { return (objopt != NULL) ? FilterInfo(interp, objopt->objFilters, NULL, NSF_TRUE, NSF_FALSE) : TCL_OK; } } if (unlikely(Tcl_ListObjGetElements(interp, valueObj, &oc, &ov) != TCL_OK)) { return TCL_ERROR; } objopt = NsfRequireObjectOpt(object); break; case RelationtypeClass_mixinIdx: ;NSF_FALL_THROUGH; /* fall through */ case RelationtypeClass_filterIdx: assert(class != NULL); if (valueObj == NULL) { clopt = class->opt; if (type == RelationtypeClass_mixinIdx) { return (clopt != NULL) ? MixinInfo(interp, clopt->classMixins, NULL, NSF_TRUE, NULL) : TCL_OK; } else /* if (relationtype == RelationtypeClass_filterIdx) */ { return (clopt != NULL) ? FilterInfo(interp, clopt->classFilters, NULL, NSF_TRUE, NSF_FALSE) : TCL_OK; } } if (unlikely(Tcl_ListObjGetElements(interp, valueObj, &oc, &ov) != TCL_OK)) { return TCL_ERROR; } clopt = NsfRequireClassOpt(class); break; case RelationtypeSuperclassIdx: if (!NsfObjectIsClass(object)) { return NsfObjErrType(interp, "superclass", object->cmdName, "class", NULL); } class = (NsfClass *)object; if (valueObj == NULL) { return ListSuperClasses(interp, class, NULL, NSF_FALSE); } if (unlikely(Tcl_ListObjGetElements(interp, valueObj, &oc, &ov) != TCL_OK)) { return TCL_ERROR; } return SuperclassAdd(interp, class, oc, ov, valueObj); case RelationtypeClassIdx: if (valueObj == NULL) { Tcl_SetObjResult(interp, object->cl->object.cmdName); return TCL_OK; } GetClassFromObj(interp, valueObj, &class, NSF_TRUE); if (class == NULL) { return NsfObjErrType(interp, "class", valueObj, "a class", NULL); } i = ChangeClass(interp, object, class); if (i == TCL_OK) { Tcl_SetObjResult(interp, object->cl->object.cmdName); } return i; case RelationtypeRootclassIdx: { NsfClass *metaClass = NULL; if (!NsfObjectIsClass(object)) { return NsfObjErrType(interp, "rootclass", object->cmdName, "class", NULL); } class = (NsfClass *)object; if (valueObj == NULL) { return NsfPrintError(interp, "metaclass must be specified as third argument"); } GetClassFromObj(interp, valueObj, &metaClass, NSF_FALSE); if (metaClass == NULL) { return NsfObjErrType(interp, "rootclass", valueObj, "class", NULL); } class->object.flags |= NSF_IS_ROOT_CLASS; metaClass->object.flags |= NSF_IS_ROOT_META_CLASS; return TCL_OK; /* TODO: Need to remove these properties? Allow one to delete a class system at run time? */ } case RelationtypeNULL: /* do nothing; just for detection if option was specified */ return TCL_OK; } /* * The second switch block is responsible for the more complex handling of * the relations. */ switch (type) { case RelationtypeObject_mixinIdx: { NsfCmdList *newMixinCmdList = NULL, *cmds; /* * Add every mixin class */ for (i = 0; i < oc; i++) { if (unlikely(MixinAdd(interp, &newMixinCmdList, ov[i]) != TCL_OK)) { CmdListFree(&newMixinCmdList, GuardDel); return TCL_ERROR; } } if (objopt->objMixins != NULL) { NsfCmdList *cmdlist, *del; /* * Delete from old isObjectMixinOf lists */ for (cmdlist = objopt->objMixins; cmdlist != NULL; cmdlist = cmdlist->nextPtr) { class = NsfGetClassFromCmdPtr(cmdlist->cmdPtr); clopt = (class != NULL) ? class->opt : NULL; if (clopt != NULL) { del = CmdListFindCmdInList(object->id, clopt->isObjectMixinOf); if (del != NULL) { /* fprintf(stderr, "Removing object %s from isObjectMixinOf of class %s\n", ObjectName(object), ObjStr(NsfGetClassFromCmdPtr(cmdlist->cmdPtr)->object.cmdName)); */ del = CmdListRemoveFromList(&clopt->isObjectMixinOf, del); CmdListDeleteCmdListEntry(del, GuardDel); } } } CmdListFree(&objopt->objMixins, GuardDel); } /* * Invalidate per-object infos */ NsfParameterCacheObjectInvalidateCmd(interp, object); object->flags &= ~NSF_MIXIN_ORDER_VALID; /* * Since mixin procs may be used as filters -> we have to invalidate * filters as well. */ object->flags &= ~NSF_FILTER_ORDER_VALID; /* * Now register the specified mixins. */ objopt->objMixins = newMixinCmdList; for (cmds = newMixinCmdList; cmds; cmds = cmds->nextPtr) { NsfObject *nObject = NsfGetObjectFromCmdPtr(cmds->cmdPtr); if (nObject != NULL) { nclopt = NsfRequireClassOpt((NsfClass *) nObject); CmdListAddSorted(&nclopt->isObjectMixinOf, object->id, NULL); } else { NsfLog(interp, NSF_LOG_WARN, "Problem registering %s as an object mixin of %s\n", ObjStr(valueObj), ObjectName_(object)); } } MixinComputeDefined(interp, object); FilterComputeDefined(interp, object); } break; case RelationtypeObject_filterIdx: { NsfCmdList *newFilterCmdList = NULL; for (i = 0; i < oc; i ++) { if (unlikely(FilterAdd(interp, &newFilterCmdList, ov[i], object, NULL) != TCL_OK)) { CmdListFree(&newFilterCmdList, GuardDel); return TCL_ERROR; } } if (objopt->objFilters != NULL) { CmdListFree(&objopt->objFilters, GuardDel); } object->flags &= ~NSF_FILTER_ORDER_VALID; objopt->objFilters = newFilterCmdList; /*FilterComputeDefined(interp, object);*/ } break; case RelationtypeClass_mixinIdx: if (unlikely(NsfRelationClassMixinsSet(interp, class, valueObj, oc, ov) != TCL_OK)) { return TCL_ERROR; } break; case RelationtypeClass_filterIdx: { NsfCmdList *newFilterCmdList = NULL; for (i = 0; i < oc; i ++) { if (unlikely(FilterAdd(interp, &newFilterCmdList, ov[i], NULL, class) != TCL_OK)) { CmdListFree(&newFilterCmdList, GuardDel); return TCL_ERROR; } } if (clopt->classFilters != NULL) { CmdListFree(&clopt->classFilters, GuardDel); } if (FiltersDefined(interp) > 0) { NsfClasses *subClasses = DependentSubClasses(class); if (subClasses != NULL) { FilterInvalidateObjOrders(interp, subClasses); NsfClassListFree(subClasses); } } clopt->classFilters = newFilterCmdList; } break; case RelationtypeClassIdx: ;NSF_FALL_THROUGH; /* fall through */ case RelationtypeRootclassIdx: ;NSF_FALL_THROUGH; /* fall through */ case RelationtypeSuperclassIdx: ;NSF_FALL_THROUGH; /* fall through */ case RelationtypeNULL: /* handled above */ break; } /* * Return on success the final setting */ NsfRelationSetCmd(interp, object, type, NULL); return TCL_OK; } /* cmd current NsfCurrentCmd { {-argName "option" -required 0 -typeName "currentoption" -type "activelevel|activemixin|args|calledclass|calledmethod|calledproc|callingclass|callinglevel|callingmethod|callingobject|callingproc|class|filterreg|isnextcall|level|methodpath|method|nextmethod|object|proc" -default object} } */ static int NsfCurrentCmd(Tcl_Interp *interp, CurrentoptionIdx_t option) { NsfObject *object; NsfCallStackContent *cscPtr; Tcl_CallFrame *framePtr; int result = TCL_OK; nonnull_assert(interp != NULL); object = GetSelfObj(interp); /* * The first two clauses can succeed even it we are outside an NSF context * (no object known). The commands are "nsf::current", "nsf::current * object", "nsf::current level", and "nsf::current activelevel" */ if (option == CurrentoptionNULL || option == CurrentoptionObjectIdx) { if (likely(object != NULL)) { Tcl_SetObjResult(interp, object->cmdName); } else { result = NsfNoCurrentObjectError(interp, NULL); } return result; } if (unlikely(object == NULL)) { if (option == CurrentoptionCallinglevelIdx) { Tcl_SetIntObj(Tcl_GetObjResult(interp), 1); } else if (option == CurrentoptionLevelIdx) { /* * Return empty, if we are not on an NSF level. */ Tcl_ResetResult(interp); } else { result = NsfNoCurrentObjectError(interp, NULL); } return result; } /* * From here on, we have to be on a valid nsf frame/level, object has to be * know. */ assert(object != NULL); switch (option) { case CurrentoptionMethodIdx: ;NSF_FALL_THROUGH; /* fall through */ case CurrentoptionProcIdx: cscPtr = CallStackGetTopFrame0(interp); if (cscPtr != NULL) { const char *procName = Tcl_GetCommandName(interp, cscPtr->cmdPtr); Tcl_SetObjResult(interp, Tcl_NewStringObj(procName, TCL_INDEX_NONE)); } else { /* TODO: Is this, practically, reachable? */ return NsfPrintError(interp, "can't find method"); } break; case CurrentoptionMethodpathIdx: cscPtr = CallStackGetTopFrame0(interp); if (cscPtr != NULL) { Tcl_SetObjResult(interp, NsfMethodNamePath(interp, CallStackGetTclFrame(interp, NULL, 1), Tcl_GetCommandName(interp, cscPtr->cmdPtr))); } else { /* TODO: Is this, practically, reachable? */ return NsfPrintError(interp, "can't find method"); } break; case CurrentoptionClassIdx: /* class subcommand */ cscPtr = CallStackGetTopFrame0(interp); Tcl_SetObjResult(interp, (cscPtr != NULL && cscPtr->cl) ? cscPtr->cl->object.cmdName : NsfGlobalObjs[NSF_EMPTY]); break; case CurrentoptionActivelevelIdx: Tcl_SetObjResult(interp, ComputeLevelObj(interp, ACTIVE_LEVEL)); break; case CurrentoptionArgsIdx: { cscPtr = CallStackGetTopFrame(interp, &framePtr); if (cscPtr != NULL) { TCL_SIZE_T nobjc; Tcl_Obj **nobjv; if (cscPtr->objv != NULL) { nobjc = (TCL_SIZE_T)cscPtr->objc; nobjv = (Tcl_Obj **)cscPtr->objv; } else { nobjc = Tcl_CallFrame_objc(framePtr); nobjv = (Tcl_Obj **)Tcl_CallFrame_objv(framePtr); } Tcl_SetObjResult(interp, Tcl_NewListObj(nobjc-1, nobjv+1)); } else { return NsfPrintError(interp, "can't find proc"); } break; } case CurrentoptionActivemixinIdx: { NsfObject *cmdObject = NULL; if (RUNTIME_STATE(interp)->currentMixinCmdPtr) { cmdObject = NsfGetObjectFromCmdPtr(RUNTIME_STATE(interp)->currentMixinCmdPtr); } Tcl_SetObjResult(interp, (cmdObject != NULL) ? cmdObject->cmdName : NsfGlobalObjs[NSF_EMPTY]); break; } case CurrentoptionCalledprocIdx: case CurrentoptionCalledmethodIdx: cscPtr = CallStackFindActiveFilter(interp); if (cscPtr != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj(MethodName(cscPtr->filterStackEntry->calledProc), TCL_INDEX_NONE)); } else { result = NsfPrintError(interp, "called from outside of a filter"); } break; case CurrentoptionCalledclassIdx: { const NsfClass *class = FindCalledClass(interp, object); Tcl_SetObjResult(interp, (class != NULL) ? class->object.cmdName : NsfGlobalObjs[NSF_EMPTY]); break; } case CurrentoptionCallingmethodIdx: case CurrentoptionCallingprocIdx: { Tcl_Obj *resultObj; cscPtr = NsfCallStackFindLastInvocation(interp, 1, &framePtr); if ((cscPtr != NULL) && (cscPtr->cmdPtr != NULL)) { resultObj = NsfMethodNamePath(interp, CallStackGetTclFrame(interp, framePtr, 1), Tcl_GetCommandName(interp, cscPtr->cmdPtr)); } else { resultObj = NsfGlobalObjs[NSF_EMPTY]; } Tcl_SetObjResult(interp, resultObj); break; } case CurrentoptionCallingclassIdx: cscPtr = NsfCallStackFindLastInvocation(interp, 1, NULL); Tcl_SetObjResult(interp, (cscPtr != NULL && cscPtr->cl != NULL) ? cscPtr->cl->object.cmdName : NsfGlobalObjs[NSF_EMPTY]); break; case CurrentoptionCallinglevelIdx: /* * Special case of object==NULL handled above. */ Tcl_SetObjResult(interp, ComputeLevelObj(interp, CALLING_LEVEL)); break; case CurrentoptionCallingobjectIdx: cscPtr = NsfCallStackFindLastInvocation(interp, 1, NULL); Tcl_SetObjResult(interp, (cscPtr != NULL) ? cscPtr->self->cmdName : NsfGlobalObjs[NSF_EMPTY]); break; case CurrentoptionFilterregIdx: cscPtr = CallStackFindActiveFilter(interp); if (cscPtr != NULL) { Tcl_SetObjResult(interp, FilterFindReg(interp, object, cscPtr->cmdPtr)); } else { result = NsfPrintError(interp, "called from outside of a filter"); } break; case CurrentoptionIsnextcallIdx: { cscPtr = CallStackGetTopFrame(interp, &framePtr); if ((cscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE) != 0u) { (void)CallStackFindEnsembleCsc(framePtr, &framePtr); } framePtr = CallStackNextFrameOfType(Tcl_CallFrame_callerPtr(framePtr), FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD); cscPtr = (framePtr != NULL) ? Tcl_CallFrame_clientData(framePtr) : NULL; Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (cscPtr != NULL && ((cscPtr->flags & NSF_CSC_CALL_IS_NEXT) != 0u))); break; } case CurrentoptionLevelIdx: /* * We have an "object", therefore, we are on an NSF-frame/level. In this * case, "nsf level" behaves like "info level" (without arguments). */ Tcl_SetObjResult(interp, Tcl_NewIntObj(Tcl_CallFrame_level(Tcl_Interp_varFramePtr(interp)))); break; case CurrentoptionNextmethodIdx: { Tcl_Obj *methodHandle; /* cscPtr = */ (void) CallStackGetTopFrame(interp, &framePtr); /*assert(cscPtr != NULL);*/ methodHandle = FindNextMethod(interp, framePtr); if (methodHandle == NULL) { Tcl_ResetResult(interp); } else { Tcl_SetObjResult(interp, methodHandle); } break; } case CurrentoptionObjectIdx: ;NSF_FALL_THROUGH; /* fall through */ case CurrentoptionNULL: /* handled above */ break; } return result; } /* cmd self NsfSelfCmd { } */ static int NsfSelfCmd(Tcl_Interp *interp) { NsfObject *object; nonnull_assert(interp != NULL); object = GetSelfObj(interp); if (likely(object != NULL)) { Tcl_SetObjResult(interp, object->cmdName); return TCL_OK; } else { return NsfNoCurrentObjectError(interp, NULL); } } /* cmd var::exists NsfVarExistsCmd { {-argName "-array" -required 0 -nrargs 0} {-argName "object" -required 1 -type object} {-argName "varName" -required 1} } */ static int NsfVarExistsCmd(Tcl_Interp *interp, int withArray, NsfObject *object, const char *varName) { unsigned int flags = NSF_VAR_TRIGGER_TRACE|NSF_VAR_REQUIRE_DEFINED| ((withArray != 0) ? NSF_VAR_ISARRAY : 0u); nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(varName != NULL); if (unlikely(CheckVarName(interp, varName) != TCL_OK)) { return TCL_ERROR; } Tcl_SetIntObj(Tcl_GetObjResult(interp), VarExists(interp, object, varName, NULL, flags)); return TCL_OK; } /* cmd var::get NsfVarGetCmd { {-argName "-array" -required 0 -nrargs 0 -type switch} {-argName "-notrace" -required 0 -nrargs 0 -type switch} {-argName "object" -required 1 -type object} {-argName "varName" -required 1 -type tclobj} } */ static int NsfVarGetCmd(Tcl_Interp *interp, int withArray, int withNotrace, NsfObject *object, Tcl_Obj *varNameObj) { return NsfVarSetCmd(interp, withArray, withNotrace, object, varNameObj, NULL); } /* cmd var::import NsfVarImportCmd { {-argName "object" -type object} {-argName "args" -type args} } */ static int NsfVarImport(Tcl_Interp *interp, NsfObject *object, const char *cmdName, int objc, Tcl_Obj *const objv[]) nonnull(1) nonnull(2) nonnull(3) nonnull(5); static int NsfVarImport(Tcl_Interp *interp, NsfObject *object, const char *cmdName, int objc, Tcl_Obj *const objv[]) { int i, result = TCL_OK; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(cmdName != NULL); nonnull_assert(objv != NULL); for (i = 0; i < objc && result == TCL_OK; i++) { Tcl_Obj **ov; int oc; /*fprintf(stderr, "ListGetElements %p %s\n", objv[i], ObjStr(objv[i]));*/ if ((result = Tcl_ListObjGetElements(interp, objv[i], &oc, &ov)) == TCL_OK) { Tcl_Obj *varName = NULL, *alias = NULL; switch (oc) { case 0: varName = objv[i]; break; case 1: varName = ov[0]; break; case 2: varName = ov[0]; alias = ov[1]; break; default: break; } if (likely(varName != NULL)) { result = ImportInstVarIntoCurrentScope(interp, cmdName, object, varName, alias); } else { assert(objv[i] != NULL); result = NsfPrintError(interp, "invalid variable specification '%s'", ObjStr(objv[i])); } } } return result; } static int NsfVarImportCmd(Tcl_Interp *interp, NsfObject *object, int trailingObjc, Tcl_Obj *const trailingObjv[]) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); return NsfVarImport(interp, object, "importvar", trailingObjc, trailingObjv); } /* cmd var::set NsfVarSetCmd { {-argName "-array" -required 0 -nrargs 0 -type switch} {-argName "-notrace" -required 0 -nrargs 0 -type switch} {-argName "object" -required 1 -type object} {-argName "varName" -required 1 -type tclobj} {-argName "value" -required 0 -type tclobj} } */ static int NsfVarSetCmd(Tcl_Interp *interp, int withArray, int withNotrace, NsfObject *object, Tcl_Obj *varNameObj, Tcl_Obj *valueObj) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(varNameObj != NULL); if (unlikely(CheckVarName(interp, ObjStr(varNameObj)) != TCL_OK)) { return TCL_ERROR; } if (withArray != 0) { return SetInstArray(interp, object, varNameObj, valueObj); } else { return SetInstVar(interp, object, varNameObj, valueObj, withNotrace ? 0 : NSF_VAR_TRIGGER_TRACE); } } /* cmd var::unset NsfVarUnsetCmd { {-argName "-nocomplain" -required 0 -nrargs 0} {-argName "object" -required 1 -type object} {-argName "varName" -required 1 -type tclobj} } */ static int NsfVarUnsetCmd(Tcl_Interp *interp, int withNocomplain, NsfObject *object, Tcl_Obj *varNameObj) { const char *varName; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(varNameObj != NULL); varName = ObjStr(varNameObj); if (unlikely(CheckVarName(interp, varName) != TCL_OK)) { return TCL_ERROR; } return UnsetInstVar(interp, withNocomplain, object, varName); } /*********************************************************************** * End generated Next Scripting commands ***********************************************************************/ /* * Parameter support functions */ typedef struct NsfParamWrapper { Nsf_Param *paramPtr; int refCount; bool canFree; } NsfParamWrapper; static Tcl_DupInternalRepProc ParamDupInteralRep; static Tcl_FreeInternalRepProc ParamFreeInternalRep; static Tcl_UpdateStringProc ParamUpdateString; static void ParamUpdateString(Tcl_Obj *objPtr) nonnull(1); static void ParamDupInteralRep(Tcl_Obj *srcPtr, Tcl_Obj *UNUSED(dupPtr)) nonnull(1); static void ParamFreeInternalRep(register Tcl_Obj *objPtr) nonnull(1); static int ParamSetFromAny(Tcl_Interp *interp, register Tcl_Obj *objPtr) nonnull(1) nonnull(2); static int ParamSetFromAny2(Tcl_Interp *interp, const char *varNamePrefix, bool allowObjectParameter, register Tcl_Obj *objPtr, const char *qualifier) nonnull(1) nonnull(2) nonnull(4); static void ParamUpdateString(Tcl_Obj *objPtr) { nonnull_assert(objPtr != NULL); Tcl_Panic("%s of type %s should not be called", "updateStringProc", objPtr->typePtr->name); } static void ParamDupInteralRep(Tcl_Obj *srcPtr, Tcl_Obj *UNUSED(dupPtr)) { nonnull_assert(srcPtr != NULL); Tcl_Panic("%s of type %s should not be called", "dupStringProc", srcPtr->typePtr->name); } static Tcl_ObjType paramObjType = { "nsfParam", /* name */ ParamFreeInternalRep, /* freeIntRepProc */ ParamDupInteralRep, /* dupIntRepProc */ ParamUpdateString, /* updateStringProc */ ParamSetFromAny /* setFromAnyProc */ }; static void ParamFreeInternalRep( register Tcl_Obj *objPtr) /* Param structure object with internal * representation to free. */ { NsfParamWrapper *paramWrapperPtr; nonnull_assert(objPtr != NULL); paramWrapperPtr = (NsfParamWrapper *)objPtr->internalRep.twoPtrValue.ptr1; if (paramWrapperPtr != NULL) { /* fprintf(stderr, "ParamFreeInternalRep freeing wrapper %p paramPtr %p refCount %dcanFree %d\n", paramWrapperPtr, paramWrapperPtr->paramPtr, paramWrapperPtr->refCount, paramWrapperPtr->canFree);*/ if (paramWrapperPtr->canFree) { ParamsFree(paramWrapperPtr->paramPtr); FREE(NsfParamWrapper, paramWrapperPtr); } else { paramWrapperPtr->refCount--; } } } /* *---------------------------------------------------------------------- * ParamSetFromAny2 -- * * Convert the second argument (e.g. "x:integer") into the internal * representation of a Tcl_Obj of the type parameter. The conversion is * performed by the usual ParamDefinitionParse() function, used e.g. for * the parameter passing for arguments. * * Results: * A standard Tcl result. * * Side effects: * Converted internal rep of Tcl_Obj * *---------------------------------------------------------------------- */ static int ParamSetFromAny2( Tcl_Interp *interp, /* Used for error reporting if not NULL. */ const char *varNamePrefix, /* shows up as varName in error message */ bool allowObjectParameter, /* allow object parameters */ register Tcl_Obj *objPtr, /* The object to convert. */ const char *qualifier) { Tcl_Obj *fullParamObj = Tcl_NewStringObj(varNamePrefix, TCL_INDEX_NONE); int result, possibleUnknowns = 0, plainParams = 0, nrNonposArgs = 0; NsfParamWrapper *paramWrapperPtr = NEW(NsfParamWrapper); nonnull_assert(interp != NULL); nonnull_assert(varNamePrefix != NULL); nonnull_assert(objPtr != NULL); paramWrapperPtr->paramPtr = ParamsNew(1u); paramWrapperPtr->refCount = 1; paramWrapperPtr->canFree = NSF_FALSE; Tcl_AppendLimitedToObj(fullParamObj, ObjStr(objPtr), TCL_INDEX_NONE, INT_MAX, NULL); INCR_REF_COUNT(fullParamObj); result = ParamDefinitionParse(interp, NsfGlobalObjs[NSF_VALUECHECK], fullParamObj, (allowObjectParameter ? NSF_DISALLOWED_ARG_OBJECT_PARAMETER : NSF_DISALLOWED_ARG_VALUECHECK), paramWrapperPtr->paramPtr, &possibleUnknowns, &plainParams, &nrNonposArgs, qualifier); /* * We treat currently unknown user level converters as error. */ if (unlikely((paramWrapperPtr->paramPtr->flags & NSF_ARG_CURRENTLY_UNKNOWN) != 0u)) { result = TCL_ERROR; } if (likely(result == TCL_OK)) { /* * In success cases, the memory allocated by this function is freed via * the Tcl_Obj type. */ paramWrapperPtr->paramPtr->flags |= NSF_ARG_UNNAMED; if (*(paramWrapperPtr->paramPtr->name) == 'r') { paramWrapperPtr->paramPtr->flags |= NSF_ARG_IS_RETURNVALUE; } TclFreeInternalRep(objPtr); objPtr->internalRep.twoPtrValue.ptr1 = (void *)paramWrapperPtr; objPtr->internalRep.twoPtrValue.ptr2 = NULL; objPtr->typePtr = ¶mObjType; } else { /* * In error cases, free manually memory allocated by this function. */ ParamsFree(paramWrapperPtr->paramPtr); FREE(NsfParamWrapper, paramWrapperPtr); } DECR_REF_COUNT(fullParamObj); return result; } static int ParamSetFromAny( Tcl_Interp *interp, /* Used for error reporting if not NULL. */ register Tcl_Obj *objPtr) /* The object to convert. */ { nonnull_assert(interp != NULL); nonnull_assert(objPtr != NULL); return ParamSetFromAny2(interp, "value:", NSF_FALSE, objPtr, NULL); } /* *---------------------------------------------------------------------- * GetObjectParameterDefinition -- * * Obtain the parameter definitions for an object by calling the method * "__objectparameter" if the value is not cached already. Either "object" * or "class" must be non-null. Caching is performed on the class, the * cached values are used in case there are no object-specific slots. * * Results: * A standard Tcl result, parsed structure in last argument * * Side effects: * Updates potentially cl->parsedParamPtr * *---------------------------------------------------------------------- */ static int ComputeParameterDefinition( Tcl_Interp *interp, Tcl_Obj *procNameObj, NsfObject *object, NsfClass *class, NsfParsedParam *parsedParamPtr ) { int result; Tcl_Obj *methodObj; NsfObject *self; if (object != NULL) { methodObj = NsfMethodObj(object, NSF_o_configureparameter_idx); self = object; } else { assert(class != NULL); self = &class->object; methodObj = NsfMethodObj(self, NSF_c_configureparameter_idx); } if (methodObj == NULL) { result = TCL_OK; } else { /*fprintf(stderr, "calling %s %s\n", ObjectName(self), ObjStr(methodObj));*/ result = CallMethod(self, interp, methodObj, 2, NULL, NSF_CM_IGNORE_PERMISSIONS|NSF_CSC_IMMEDIATE); if (likely(result == TCL_OK)) { Tcl_Obj *rawConfArgs = Tcl_GetObjResult(interp); /* fprintf(stderr, ".... rawConfArgs for %s => '%s'\n", ObjectName(self), ObjStr(rawConfArgs));*/ INCR_REF_COUNT(rawConfArgs); /* * Parse the string representation to obtain the internal * representation. */ result = ParamDefsParse(interp, procNameObj, rawConfArgs, NSF_DISALLOWED_ARG_OBJECT_PARAMETER, NSF_TRUE, parsedParamPtr, NULL); if (likely(result == TCL_OK)) { NsfParsedParam *ppDefPtr = NEW(NsfParsedParam); ppDefPtr->paramDefs = parsedParamPtr->paramDefs; ppDefPtr->possibleUnknowns = parsedParamPtr->possibleUnknowns; if (class != NULL) { assert(class->parsedParamPtr == NULL); class->parsedParamPtr = ppDefPtr; #if defined(PER_OBJECT_PARAMETER_CACHING) } else if (object != NULL) { NsfObjectOpt *opt = NsfRequireObjectOpt(object); if (object->opt->parsedParamPtr != NULL) { NsfParameterCacheObjectInvalidateCmd(interp, object); } opt->parsedParamPtr = ppDefPtr; opt->classParamPtrEpoch = RUNTIME_STATE(interp)->classParamPtrEpoch; /*fprintf(stderr, "set obj param for obj %p %s epoch %d ppDefPtr %p\n", object, ObjectName(object), opt->classParamPtrEpoch, ppDefPtr);*/ #endif } if (ppDefPtr->paramDefs != NULL) { ParamDefsRefCountIncr(ppDefPtr->paramDefs); } } DECR_REF_COUNT(rawConfArgs); } } return result; } /* *---------------------------------------------------------------------- * GetObjectParameterDefinition -- * * Obtain the parameter definitions for an object by calling the method * "__objectparameter" if the value is not cached already. Caching is * performed on the class, the cached values are used in case there are no * object-specific slots. * * Results: * A standard Tcl result, parsed structure in last argument. * * Side effects: * Updates potentially cl->parsedParamPtr * *---------------------------------------------------------------------- */ static int GetObjectParameterDefinition( Tcl_Interp *interp, Tcl_Obj *procNameObj, NsfObject *object, NsfClass *class, NsfParsedParam *parsedParamPtr ) { int result = TCL_OK; nonnull_assert(interp != NULL); nonnull_assert(procNameObj != NULL); nonnull_assert(parsedParamPtr != NULL); parsedParamPtr->paramDefs = NULL; parsedParamPtr->possibleUnknowns = 0; if (class == NULL) { assert(object != NULL); if ((object->flags & NSF_HAS_PER_OBJECT_SLOTS) != 0u || (object->opt != NULL && object->opt->objMixins) ) { /* * We have object-specific parameters. Do not use the per-class cache, * and do not save the results in the per-class cache. */ /*fprintf(stderr, "per-object configure obj %s flags %.6x\n", ObjectName(object), object->flags);*/ } else { class = object->cl; } } /* * Parameter definitions are cached in the class, for which * instances are created. The parameter definitions are flushed in * the following situations: * * a) on class cleanup: ParsedParamFree(cl->parsedParamPtr) * b) on class structure changes, * c) when class-mixins are added, * d) when new slots are defined, * e) when slots are removed * * When slot defaults or types are changed, the slots have to * perform a manual "::nsf::invalidateobjectparameter $domain". */ /* * Check whether there is already a parameter definition available for * creating objects of this class. */ if (likely(class != NULL && class->parsedParamPtr != NULL)) { NsfParsedParam *clParsedParamPtr = class->parsedParamPtr; parsedParamPtr->paramDefs = clParsedParamPtr->paramDefs; parsedParamPtr->possibleUnknowns = clParsedParamPtr->possibleUnknowns; result = TCL_OK; #if defined(PER_OBJECT_PARAMETER_CACHING) } else if (object != NULL && object->opt != NULL && object->opt->parsedParamPtr != NULL && object->opt->classParamPtrEpoch == RUNTIME_STATE(interp)->classParamPtrEpoch) { NsfParsedParam *objParsedParamPtr = object->opt->parsedParamPtr; /*fprintf(stderr, "reuse obj param for obj %p %s paramPtr %p\n", (void *)object, ObjectName(object), (void *)objParsedParamPtr);*/ parsedParamPtr->paramDefs = objParsedParamPtr->paramDefs; parsedParamPtr->possibleUnknowns = objParsedParamPtr->possibleUnknowns; result = TCL_OK; #endif } else { /* * There is no parameter definition available, get a new one in * the string representation. */ result = ComputeParameterDefinition(interp, procNameObj, object, class, parsedParamPtr); } return result; } /* *---------------------------------------------------------------------- * ParameterCheck -- * * Check the provided valueObj against the parameter specification * provided in the second argument (paramObjPtr), when * doCheckArguments is true. This function is used e.g. by nsf::is, * where only the right-hand side of a parameter specification * (after the colon) is specified. The argument Name (before the * colon in a parameter spec) is provided via argNamePrefix. The * converted parameter structure is returned optionally via the * last argument. * * Results: * A standard Tcl result and parsed structure in last argument. * * Side effects: * Converts potentially tcl_obj type of paramObjPtr * *---------------------------------------------------------------------- */ static int ParameterCheck( Tcl_Interp *interp, Tcl_Obj *paramObjPtr, Tcl_Obj *valueObj, const char *argNamePrefix, unsigned int doCheckArguments, bool isNamed, bool doConfigureParameter, Nsf_Param **paramPtrPtr, const char *qualifier ) { Nsf_Param *paramPtr; NsfParamWrapper *paramWrapperPtr; Tcl_Obj *outObjPtr; ClientData checkedData; int result; unsigned int flags = 0u; nonnull_assert(interp != NULL); nonnull_assert(paramObjPtr != NULL); nonnull_assert(valueObj != NULL); /* fprintf(stderr, "ParameterCheck %s value %p %s\n", ObjStr(paramObjPtr), valueObj, ObjStr(valueObj)); */ if (paramObjPtr->typePtr == ¶mObjType) { paramWrapperPtr = (NsfParamWrapper *) paramObjPtr->internalRep.twoPtrValue.ptr1; } else { /* * We could use in principle Tcl_ConvertToType(..., ¶mObjType) instead * of checking the type manually, but we want to pass the argNamePrefix * explicitly. */ result = ParamSetFromAny2(interp, argNamePrefix, doConfigureParameter, paramObjPtr, qualifier); if (likely(result == TCL_OK)) { paramWrapperPtr = (NsfParamWrapper *) paramObjPtr->internalRep.twoPtrValue.ptr1; } else { const char *errMsg = ObjStr(Tcl_GetObjResult(interp)); Tcl_SetErrorCode(interp, "NSF", "VALUE", "CONSTRAINT", NULL); if (*errMsg == '\0') { return NsfPrintError(interp, "invalid value constraints \"%s\"", ObjStr(paramObjPtr) ); } else { return NsfPrintError(interp, "invalid value constraints \"%s\": %s", ObjStr(paramObjPtr), errMsg); } } } paramPtr = paramWrapperPtr->paramPtr; if (paramPtrPtr != NULL) *paramPtrPtr = paramPtr; if (isNamed) { paramPtr->flags &= ~NSF_ARG_UNNAMED; } RUNTIME_STATE(interp)->doClassConverterOmitUnknown = 1; outObjPtr = NULL; result = ArgumentCheck(interp, valueObj, paramPtr, doCheckArguments, &flags, &checkedData, &outObjPtr); RUNTIME_STATE(interp)->doClassConverterOmitUnknown = 0; /*fprintf(stderr, "ParameterCheck paramPtr %p final refCount of wrapper %d can free %d flags %.6x\n", paramPtr, paramWrapperPtr->refCount, paramWrapperPtr->canFree, flags);*/ assert(paramWrapperPtr->refCount > 0); paramWrapperPtr->canFree = NSF_TRUE; if ((flags & NSF_PC_MUST_DECR) != 0u) { DECR_REF_COUNT2("valueObj", outObjPtr); } return result; } /*********************************************************************** * Begin Object Methods ***********************************************************************/ /* objectMethod autoname NsfOAutonameMethod { {-argName "-instance"} {-argName "-reset"} {-argName "name" -required 1 -type tclobj} } */ static int NsfOAutonameMethod( Tcl_Interp *interp, NsfObject *object, int withInstance, int withReset, Tcl_Obj *nameObj ) { Tcl_Obj *autonamedObj; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(nameObj != NULL); autonamedObj = AutonameIncr(interp, nameObj, object, withInstance, withReset); if (autonamedObj != NULL) { Tcl_SetObjResult(interp, autonamedObj); DECR_REF_COUNT2("autoname", autonamedObj); return TCL_OK; } return NsfPrintError(interp, "autoname failed. Probably format string (with %%) was not well-formed"); } /* objectMethod class NsfOClassMethod { {-argName "class" -required 0 -type tclobj} } */ static int NsfOClassMethod(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *classObj) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); return NsfRelationSetCmd(interp, object, RelationtypeClassIdx, classObj); } /* objectMethod cleanup NsfOCleanupMethod { } */ static int NsfOCleanupMethod(Tcl_Interp *interp, NsfObject *object) { NsfClass *class; Tcl_Obj *savedNameObj; bool softrecreate; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); #if defined(OBJDELETION_TRACE) fprintf(stderr, "+++ NsfOCleanupMethod\n"); #endif PRINTOBJ("NsfOCleanupMethod", object); savedNameObj = object->cmdName; INCR_REF_COUNT(savedNameObj); /* * Get the class before the object is destroyed. */ class = NsfObjectToClass(object); /* * Save and pass around softrecreate. */ softrecreate = ((object->flags & NSF_RECREATE) != 0u && RUNTIME_STATE(interp)->doSoftrecreate); CleanupDestroyObject(interp, object, softrecreate); CleanupInitObject(interp, object, object->cl, object->nsPtr, softrecreate); if (class != NULL) { CleanupDestroyClass(interp, class, softrecreate, NSF_TRUE); CleanupInitClass(interp, class, class->nsPtr, softrecreate, NSF_TRUE); } DECR_REF_COUNT(savedNameObj); return TCL_OK; } /* objectMethod configure NsfOConfigureMethod { {-argName "args" -type allargs} } */ static NsfObject* GetSlotObject(Tcl_Interp *interp, Tcl_Obj *slotObj) nonnull(1) nonnull(2); static NsfObject* GetSlotObject(Tcl_Interp *interp, Tcl_Obj *slotObj) { NsfObject *slotObject = NULL; nonnull_assert(interp != NULL); nonnull_assert(slotObj != NULL); if (unlikely(GetObjectFromObj(interp, slotObj, &slotObject) != TCL_OK || slotObject == NULL)) { NsfPrintError(interp, "couldn't resolve slot object %s", ObjStr(slotObj)); } return slotObject; } static int NsfOConfigureMethod(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const objv[], Tcl_Obj *objv0) { int result, i; NsfParsedParam parsedParam; Nsf_Param *paramPtr; NsfParamDefs *paramDefs; Tcl_Obj *newValue, *initMethodObj; const char *initString; ParseContext pc; CallFrame frame, *framePtr = &frame, *uplevelVarFramePtr; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(objv != NULL); nonnull_assert(objv0 != NULL); #if 0 fprintf(stderr, "NsfOConfigureMethod %s.%s flags %.6x oc %2d", ObjectName(object), ObjStr(objv0), object->flags, objc); for(i = 0; i < objc; i++) {fprintf(stderr, " [%d]=%s,", i, ObjStr(objv[i]));} fprintf(stderr, "\n"); #endif /* * Get the object parameter definition. */ result = GetObjectParameterDefinition(interp, objv0, object, NULL, &parsedParam); if (result != TCL_OK || parsedParam.paramDefs == NULL) { /*fprintf(stderr, "... nothing to do for method %s\n", ObjStr(objv0));*/ return result; } /* * Get the initMethodObj/initString outside the loop iterating over the * arguments. */ if (CallDirectly(interp, object, NSF_o_init_idx, &initMethodObj)) { initString = NULL; } else { initString = ObjStr(initMethodObj); } /* * The effective call site of the configure() method (e.g., a proc or a * method) can result from up-leveling the object creation procedure; * therefore, the *effective* call site can deviate from the *declaring* * call site (e.g. as in XOTcl2's unknown method). In such a scenario, the * configure() dispatch finds itself in a particular call-stack * configuration: The top-most frame reflects the declaring call site * (interp->framePtr), while the effective call site (interp->varFramePtr) * is identified by a lower call-stack level. * * Since configure pushes an object frame (for accessing the instance * variables) and sometimes a CMETHOD frame (for method invocations) we * record a) whether there was a preceding uplevel (identifiable through * deviating interp->framePtr and interp->varFramePtr) and, in case, b) the * ruling variable frame context. The preserved call-frame reference can * later be used to restore the uplevel'ed call frame context. */ uplevelVarFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp) != Tcl_Interp_framePtr(interp) ? Tcl_Interp_varFramePtr(interp) : NULL; /* * Push frame to allow for [self] and make instance variables of the object * accessible as locals. */ #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, object, framePtr); #pragma GCC diagnostic pop /* * Process the actual arguments based on the parameter definitions. */ paramDefs = parsedParam.paramDefs; ParamDefsRefCountIncr(paramDefs); #if 0 if (parsedParam.paramDefs != NULL) { Tcl_Obj *listObj = ParamDefsList(interp, paramDefs->paramsPtr, NULL, NULL); fprintf(stderr, "... got params <%s>\n", ObjStr(listObj)); } #endif result = ProcessMethodArguments(&pc, interp, object, NSF_ARGPARSE_START_ZERO, paramDefs, NsfGlobalObjs[NSF_CONFIGURE], objc, objv); if (unlikely(result != TCL_OK)) { Nsf_PopFrameObj(interp, framePtr); goto configure_exit; } /* * At this point, the arguments are tested to be valid (according to the * parameter definitions) and the defaults are set. Now we have to apply the * arguments (mostly setting instance variables). */ #if defined(CONFIGURE_ARGS_TRACE) fprintf(stderr, "*** POPULATE OBJ '%s': nr of parsed args %d\n", ObjectName(object), pc.objc); #endif for (i = 1, paramPtr = paramDefs->paramsPtr; paramPtr->name != NULL; paramPtr++, i++) { /* * Set the new value always when the new value was specified (was not * taken from the default). When we take the default, we do not overwrite * already existing values (which might have been set via parameter * alias). */ /*fprintf(stderr, "[%d] param %s, object init called %d is default %d value = '%s' nrArgs %d\n", i, paramPtr->name, (object->flags & NSF_INIT_CALLED), (pc.flags[i-1] & NSF_PC_IS_DEFAULT), ObjStr(pc.full_objv[i]), paramPtr->nrArgs);*/ if ((pc.flags[i-1] & NSF_PC_IS_DEFAULT)) { /* * Object parameter method calls (when the flag * NSF_ARG_METHOD_INVOCATION is set) do not set instance variables, so * we do not have to check for existing variables. */ if ((paramPtr->flags & NSF_ARG_METHOD_INVOCATION) == 0u) { Tcl_Obj *varObj = Tcl_ObjGetVar2(interp, paramPtr->nameObj, NULL, 0); if (varObj != NULL) { /* * The value exists already, ignore this parameter. */ /*fprintf(stderr, "a variable for %s exists already, " "ignore param flags %.6x valueObj %p\n", paramPtr->name, paramPtr->flags, pc.full_objv[i]);*/ continue; } } else if ((object->flags & NSF_INIT_CALLED) != 0u) { /* * The object is already initialized. Don't use the default, since it * might change part of the state back to the original default. This * might happen, when e.g. configure is called on a class manually, * where "superclass" has a default. */ /*fprintf(stderr, "%s skip default %s in configure\n", ObjectName(object), ObjStr(pc.full_objv[i]));*/ continue; } } else if (unlikely((paramPtr->flags & NSF_ARG_REQUIRED) != 0u && pc.full_objv[i] == NsfGlobalObjs[NSF___UNKNOWN__])) { /* Previous versions contained a test for * (object->flags & NSF_INIT_CALLED) * * to perform required testing just for in the non-initialized state. We * switched in 2.0b5 to checking for the existence of the associated * instance variable, which works under the assumption that the instance * variable has the same name and that e.g. a required alias parameter * sets this variable either. Similar assumption is in the default * handling. Future versions might use a more general handling of the * parameter states. */ Tcl_Obj *varObj = Tcl_ObjGetVar2(interp, paramPtr->nameObj, NULL, 0); if (unlikely(varObj == NULL)) { Tcl_Obj *paramDefsObj = NsfParamDefsSyntax(interp, paramDefs->paramsPtr, object, NULL); NsfPrintError(interp, "required argument '%s' is missing, should be:\n %s%s%s %s", (paramPtr->nameObj != NULL) ? ObjStr(paramPtr->nameObj) : paramPtr->name, (pc.object != NULL) ? ObjectName(pc.object) : "", (pc.object != NULL) ? " " : "", ObjStr(pc.full_objv[0]), ObjStr(paramDefsObj)); DECR_REF_COUNT2("paramDefsObj", paramDefsObj); Nsf_PopFrameObj(interp, framePtr); result = TCL_ERROR; goto configure_exit; } } newValue = pc.full_objv[i]; /*fprintf(stderr, " new Value of %s = [%d] %p '%s', type %s addr %p\n", ObjStr(paramPtr->nameObj), i, newValue, (newValue != NULL) ? ObjStr(newValue) : "(null)", paramPtr->type, &(pc.full_objv[i]));*/ /* * Handling slot initialize */ if ((paramPtr->flags & NSF_ARG_SLOTINITIALIZE) != 0u) { NsfObject *slotObject = GetSlotObject(interp, paramPtr->slotObj); if (likely(slotObject != NULL)) { Tcl_Obj *ov[1]; ov[0] = paramPtr->nameObj; result = NsfCallMethodWithArgs(interp, (Nsf_Object *)slotObject, NsfGlobalObjs[NSF_INITIALIZE], object->cmdName, 2, ov, NSF_CSC_IMMEDIATE|NSF_CM_IGNORE_PERMISSIONS); } if (unlikely(result != TCL_OK)) { /* * The error message was set either by GetSlotObject or by ...CallMethod... */ Nsf_PopFrameObj(interp, framePtr); goto configure_exit; } } /* * Special setter methods for invoking methods calls; handles types * "cmd", "initcmd", "alias" and "forward". */ if ((paramPtr->flags & NSF_ARG_METHOD_INVOCATION) != 0u) { int consuming = (*paramPtr->name == '-' || paramPtr->nrArgs > 0); if (consuming && newValue == NsfGlobalObjs[NSF___UNKNOWN__]) { /* * In the case we have a consuming parameter, but we have no value * provided and not default, there is no reason to call the invocation * parameter. */ /*fprintf(stderr, "%s consuming nrargs %d no value\n", paramPtr->name, paramPtr->nrArgs);*/ continue; } if ((paramPtr->flags & NSF_ARG_INITCMD) != 0u) { if (paramPtr->defaultValue != NULL) { /* * The "defaultValue" holds the initcmd to be executed */ Tcl_Obj *varObj = Tcl_ObjGetVar2(interp, NsfGlobalObjs[NSF_ARRAY_INITCMD], paramPtr->nameObj, 0); /*fprintf(stderr, "### NSF_ARRAY_INITCMD %s has a value %s\n", NsfGlobalStrings[NSF_ARRAY_INITCMD], ObjStr(paramPtr->defaultValue));*/ if (varObj == NULL) { /* * The variable is not set. Therefore, we assume, we have to * execute the initcmd. On success, we note the execution in the * NSF_ARRAY_INITCMD variable (usually __initcmd(name)) */ result = ParameterMethodDispatch(interp, object, paramPtr, paramPtr->defaultValue, uplevelVarFramePtr, ObjStr(paramPtr->defaultValue) /*initString*/, (Tcl_Obj **)&objv[pc.lastObjc], objc - pc.lastObjc); if (unlikely(result != TCL_OK)) { Nsf_PopFrameObj(interp, framePtr); goto configure_exit; } if (unlikely(Tcl_ObjSetVar2(interp, NsfGlobalObjs[NSF_ARRAY_INITCMD], paramPtr->nameObj, Tcl_NewIntObj(1), TCL_LEAVE_ERR_MSG) == NULL)) { Nsf_PopFrameObj(interp, framePtr); goto configure_exit; } } } else { /* * We could consider to require a default. */ } /* * If we have a new actual value, proceed to setvars. */ if ((pc.flags[i-1] & NSF_PC_IS_DEFAULT) == 0) { goto setvars; } continue; } /* * lastObjc points to the first "unprocessed" argument, the argument before should be valid, when lastObjc > 1 */ if (pc.lastObjc > 1) { assert(ISOBJ(objv[pc.lastObjc-1])); } result = ParameterMethodDispatch(interp, object, paramPtr, newValue, uplevelVarFramePtr, initString, (Tcl_Obj **)&objv[pc.lastObjc], objc - pc.lastObjc); if (unlikely(result != TCL_OK)) { Nsf_PopFrameObj(interp, framePtr); goto configure_exit; } continue; } setvars: if (newValue == NsfGlobalObjs[NSF___UNKNOWN__]) { /* * Nothing to do, we have a value setter, but no value is specified and * no default was provided. */ continue; } /* * Set the instance variable unless the last argument of the * definition is varArgs. */ if (i < paramDefs->nrParams || (!pc.varArgs)) { #if defined(CONFIGURE_ARGS_TRACE) fprintf(stderr, "*** %s SET %s '%s' // %p\n", ObjectName(object), ObjStr(paramPtr->nameObj), ObjStr(newValue), (void *)paramPtr->slotObj); #endif /* * Actually, set instance variable with the provided value or default * value. In case, explicit invocation of the setter is needed, we call the method, which * is typically a forwarder to the slot object. */ if ((paramPtr->flags & NSF_ARG_SLOTSET) != 0u) { NsfObject *slotObject = GetSlotObject(interp, paramPtr->slotObj); if (likely(slotObject != NULL)) { Tcl_Obj *ov[2]; Tcl_Obj *methodObj = NsfMethodObj(object, NSF_s_set_idx); ov[0] = (paramPtr->method != NULL) ? paramPtr->method : paramPtr->nameObj; ov[1] = newValue; /*fprintf(stderr, "SLOTSET %s %s %s %s %s idx %d %p\n", ObjectName(slotObject), ObjStr(NsfGlobalObjs[NSF_SET]), ObjStr(object->cmdName), ObjStr(paramPtr->nameObj), ObjStr(newValue), NSF_s_set_idx, methodObj);*/ result = NsfCallMethodWithArgs(interp, (Nsf_Object *)slotObject, (methodObj != NULL) ? methodObj : NsfGlobalObjs[NSF_SLOT_SET], object->cmdName, 3, ov, NSF_CSC_IMMEDIATE); } if (unlikely(result != TCL_OK)) { /* * The error message was set either by GetSlotObject or by ...CallMethod... */ Nsf_PopFrameObj(interp, framePtr); goto configure_exit; } } else { Tcl_Obj *resultObj; /* * Plain set of the variable. */ resultObj = Tcl_ObjSetVar2(interp, paramPtr->nameObj, NULL, newValue, TCL_LEAVE_ERR_MSG); if (unlikely(resultObj == NULL)) { /* * When the setting of the variable failed (e.g. caused by variable * traces), report the error back. */ result = TCL_ERROR; Nsf_PopFrameObj(interp, framePtr); goto configure_exit; } } } } Nsf_PopFrameObj(interp, framePtr); configure_exit: ParamDefsRefCountDecr(paramDefs); ParseContextRelease(&pc); if (likely(result == TCL_OK)) { Tcl_ResetResult(interp); } return result; } /* objectMethod cget NsfOCgetMethod { {-argName "name" -type tclobj -required 1} } */ static int NsfOCgetMethod(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *nameObj) { int result; NsfParsedParam parsedParam; const Nsf_Param *paramPtr = NULL; CallFrame frame, *framePtr = &frame, *uplevelVarFramePtr; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(nameObj != NULL); /* * Get the object parameter definition */ result = GetObjectParameterDefinition(interp, NsfGlobalObjs[NSF_EMPTY], object, NULL, &parsedParam); if (unlikely(result != TCL_OK)) { return result; } /* * GetObjectParameterDefinition() was returning TCL_OK, the paramdefs have * to be set. */ assert(parsedParam.paramDefs != NULL); /* * We do not stack a plain stack from NSF_CSC_TYPE_PLAIN here, as we do in * NsfOConfigureMethod (but maybe we have to for full compatibility TODO: * check and compare with configure stack setup). Therefore, we pass NULL as * cscPtr to ParameterMethodForwardDispatch). */ /* * The uplevel handling is exactly the same as in NsfOConfigureMethod() and * is needed, when methods are called, which perform an upvar. */ uplevelVarFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp) != Tcl_Interp_framePtr(interp) ? Tcl_Interp_varFramePtr(interp) : NULL; /* * Push frame to allow invocations of [self] and make instance variables of * the object accessible as locals. */ #pragma GCC diagnostic push #if defined(__GNUC__) && !defined(__clang__) # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif Nsf_PushFrameObj(interp, object, framePtr); #pragma GCC diagnostic pop ParamDefsRefCountIncr(parsedParam.paramDefs); result = CGetParamLookup(interp, nameObj, parsedParam.paramDefs, ¶mPtr); if (result != TCL_OK) { /* * Error message is already set by CGetParamLookup() */ } else if (paramPtr == NULL) { result = NsfPrintError(interp, "cget: unknown configure parameter %s", ObjStr(nameObj)); } else { /* * Check for slot invocation. */ if (paramPtr->slotObj != NULL) { NsfObject *slotObject = GetSlotObject(interp, paramPtr->slotObj); Tcl_Obj *methodObj = NsfMethodObj(object, NSF_s_get_idx); Tcl_Obj *ov[1]; /* * Get instance variable via slot. */ if (uplevelVarFramePtr != NULL) { Tcl_Interp_varFramePtr(interp) = uplevelVarFramePtr; } ov[0] = (paramPtr->method != NULL) ? paramPtr->method : paramPtr->nameObj; /*fprintf(stderr, "SLOTGET %s idx %d %p method %s\n", ObjectName(slotObject), NSF_s_get_idx, (void *)methodObj, ObjStr(ov[0]));*/ result = NsfCallMethodWithArgs(interp, (Nsf_Object *)slotObject, (methodObj != NULL) ? methodObj : NsfGlobalObjs[NSF_SLOT_GET], object->cmdName, 2, ov, NSF_CSC_IMMEDIATE); } else { /* * We do NOT have a slot */ if ((paramPtr->flags & NSF_ARG_METHOD_CALL) != 0u) { if ((paramPtr->flags & NSF_ARG_ALIAS) != 0u) { /* * It is a parameter associated with an aliased method. Invoke the * method without an argument. */ Tcl_Obj *methodObj = (paramPtr->method != NULL) ? paramPtr->method : paramPtr->nameObj; if (uplevelVarFramePtr != NULL) { Tcl_Interp_varFramePtr(interp) = uplevelVarFramePtr; } result = CallMethod(object, interp, methodObj, 2, NULL, NSF_CSC_IMMEDIATE); } else { /* * Must be NSF_ARG_FORWARD */ assert((paramPtr->flags & NSF_ARG_FORWARD) != 0u); /* * Since we have no cscPtr, we provide NULL. */ result = ParameterMethodForwardDispatch(interp, object, paramPtr, NULL, NULL /* cscPtr */); } } else { /* * Must be a parameter associated with a variable. */ unsigned int flags = (object->nsPtr != NULL) ? (TCL_LEAVE_ERR_MSG|TCL_NAMESPACE_ONLY) : TCL_LEAVE_ERR_MSG; Tcl_Obj *resultObj = Tcl_ObjGetVar2(interp, paramPtr->nameObj, NULL, (int)flags); if (resultObj != NULL) { /* * The value exists. */ Tcl_SetObjResult(interp, resultObj); } } } } Nsf_PopFrameObj(interp, framePtr); ParamDefsRefCountDecr(parsedParam.paramDefs); return result; } /* objectMethod destroy NsfODestroyMethod { } */ static int NsfODestroyMethod(Tcl_Interp *interp, NsfObject *object) { PRINTOBJ("NsfODestroyMethod", object); nonnull_assert(interp != NULL); nonnull_assert(object != NULL); /* * Provide protection against destroy on base classes. */ if (unlikely(IsBaseClass(object))) { if (RUNTIME_STATE(interp)->exitHandlerDestroyRound != NSF_EXITHANDLER_ON_SOFT_DESTROY) { return NsfPrintError(interp, "cannot destroy base class %s", ObjectName_(object)); } } /*fprintf(stderr, "NsfODestroyMethod %p %s flags %.6x activation %d cmd %p cmd->flags %.6x\n", object, ((Command *)object->id)->flags == 0 ? ObjectName(object) : "(deleted)", object->flags, object->activationCount, object->id, ((Command *)object->id)->flags);*/ /* * NSF_DESTROY_CALLED might be set already be DispatchDestroyMethod(), * the implicit destroy calls. It is necessary to set it here for * the explicit destroy calls in the script, which reach the * Object->destroy. */ if ((object->flags & NSF_DESTROY_CALLED) == 0u) { object->flags |= NSF_DESTROY_CALLED; /*fprintf(stderr, "NsfODestroyMethod %p sets DESTROY_CALLED %.6x\n", object, object->flags);*/ } object->flags |= NSF_DESTROY_CALLED_SUCCESS; if (likely((object->flags & NSF_DURING_DELETE) == 0u)) { int result; Tcl_Obj *methodObj; /*fprintf(stderr, " call dealloc on %p %s\n", object, ((Command *)object->id)->flags == 0u ? ObjectName(object) : "(deleted)");*/ if (CallDirectly(interp, &object->cl->object, NSF_c_dealloc_idx, &methodObj)) { NSF_PROFILE_TIME_DATA; NSF_PROFILE_CALL(interp, &object->cl->object, Nsf_SystemMethodOpts[NSF_c_dealloc_idx]); result = DoDealloc(interp, object); NSF_PROFILE_EXIT(interp, &object->cl->object, Nsf_SystemMethodOpts[NSF_c_dealloc_idx]); } else { result = NsfCallMethodWithArgs(interp, (Nsf_Object *)object->cl, methodObj, object->cmdName, 1, NULL, NSF_CSC_IMMEDIATE|NSF_CM_IGNORE_PERMISSIONS); if (unlikely(result != TCL_OK)) { /* * In case, the call of the dealloc method has failed above (e.g. NS_DYING), * we have to call dealloc manually, otherwise we have a memory leak */ /*fprintf(stderr, "*** dealloc failed for %p %s flags %.6x, retry\n", object, ObjectName(object), object->flags);*/ result = DoDealloc(interp, object); } } return result; } else { #if defined(OBJDELETION_TRACE) fprintf(stderr, " Object->destroy already during delete, don't call dealloc %p\n", (void *)object); #endif } return TCL_OK; } /* objectMethod exists NsfOExistsMethod { {-argName "varName" -required 1} } */ static int NsfOExistsMethod(Tcl_Interp *interp, NsfObject *object, const char *varName) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(varName != NULL); Tcl_SetIntObj(Tcl_GetObjResult(interp), VarExists(interp, object, varName, NULL, NSF_VAR_TRIGGER_TRACE|NSF_VAR_REQUIRE_DEFINED)); return TCL_OK; } /* objectMethod filterguard NsfOFilterGuardMethod { {-argName "filter" -required 1} {-argName "guard" -required 1 -type tclobj} } */ static int NsfOFilterGuardMethod(Tcl_Interp *interp, NsfObject *object, const char *filter, Tcl_Obj *guardObj) { NsfObjectOpt *opt; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(filter != NULL); nonnull_assert(guardObj != NULL); opt = object->opt; if (opt != NULL && opt->objFilters) { NsfCmdList *h; h = CmdListFindNameInList(interp, filter, opt->objFilters); if (h != NULL) { if (h->clientData != NULL) { GuardDel((NsfCmdList *) h); } GuardAdd(h, guardObj); object->flags &= ~NSF_FILTER_ORDER_VALID; return TCL_OK; } } return NsfPrintError(interp, "filterguard: can't find filter %s on %s", filter, ObjectName_(object)); } /* objectMethod instvar NsfOInstvarMethod { {-argName "args" -type allargs} } */ static int NsfOInstvarMethod(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const objv[]) { callFrameContext ctx = {NULL, NULL, 0}; int result; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); if ((object->filterStack != NULL) || (object->mixinStack != NULL)) { CallStackUseActiveFrame(interp, &ctx); } if (unlikely(Tcl_Interp_varFramePtr(interp) == NULL)) { CallStackRestoreSavedFrames(interp, &ctx); return NsfPrintError(interp, "instvar used on %s, but call-stack is not in procedure scope", ObjectName_(object)); } result = NsfVarImport(interp, object, ObjStr(objv[0]), objc-1, objv+1); CallStackRestoreSavedFrames(interp, &ctx); return result; } /* objectMethod mixinguard NsfOMixinGuardMethod { {-argName "mixin" -required 1 -type tclobj} {-argName "guard" -required 1 -type tclobj} } */ static int NsfOMixinGuardMethod(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *mixinObj, Tcl_Obj *guardObj) { NsfObjectOpt *opt; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(mixinObj != NULL); nonnull_assert(guardObj != NULL); opt = object->opt; if (opt != NULL && opt->objMixins) { const Tcl_Command mixinCmd = Tcl_GetCommandFromObj(interp, mixinObj); if (mixinCmd != NULL) { const NsfClass *mixinClass = NsfGetClassFromCmdPtr(mixinCmd); if (mixinClass != NULL) { NsfCmdList *h = CmdListFindCmdInList(mixinCmd, opt->objMixins); if (h != NULL) { if (h->clientData != NULL) { GuardDel((NsfCmdList *) h); } GuardAdd(h, guardObj); object->flags &= ~NSF_MIXIN_ORDER_VALID; return TCL_OK; } } } } return NsfPrintError(interp, "mixinguard: can't find mixin %s on %s", ObjStr(mixinObj), ObjectName_(object)); } /* objectMethod noinit NsfONoinitMethod { } */ static int NsfONoinitMethod(Tcl_Interp *UNUSED(interp), NsfObject *object) { nonnull_assert(object != NULL); object->flags |= NSF_INIT_CALLED; return TCL_OK; } /* objectMethod requirenamespace NsfORequireNamespaceMethod { } */ static int NsfORequireNamespaceMethod(Tcl_Interp *interp, NsfObject *object) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); RequireObjNamespace(interp, object); return TCL_OK; } /* objectMethod residualargs NsfOResidualargsMethod { {-argName "args" -type allargs} } */ static int NsfOResidualargsMethod(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const objv[]) { int i, start = 1, argc = 0, nextArgc = 0, normalArgs, result = TCL_OK; dashArgType isdasharg = NO_DASH; const char *methodName, *nextMethodName = NULL, *initString = NULL; Tcl_Obj **argv = NULL, **nextArgv = NULL; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); #if 0 fprintf(stderr, "NsfOResidualargsMethod %s %2d ", ObjectName_(object), objc); for(i = 0; i < objc; i++) {fprintf(stderr, " [%d]=%p %s,", i, &objv[i], ObjStr(objv[i]));} fprintf(stderr, "\n"); #endif /* * Skip arguments without leading dash. */ for (i = start; i < objc; i++) { if ((isdasharg = IsDashArg(interp, objv[i], 1, &methodName, &argc, &argv))) { break; } } normalArgs = i-1; /* * Get the init string; do it once, outside the loop. If initString is not * obtainable (i.e. not configured in the object system), don't call the * "init" method in the loop. */ if (i < objc) { NsfObjectSystem *osPtr = GetObjectSystem(object); Tcl_Obj *initObj = osPtr->methods[NSF_o_init_idx]; if (initObj != NULL) { initString = osPtr->methodNames[NSF_o_init_idx]; assert(initString != NULL); } } for( ; i < objc; argc = nextArgc, argv = nextArgv, methodName = nextMethodName) { Tcl_ResetResult(interp); switch (isdasharg) { case SCALAR_DASH: /* Argument is a scalar with a leading dash */ { int j; nextMethodName = NULL; nextArgv = NULL; nextArgc = 0; for (j = i+1; j < objc; j++, argc++) { if ((isdasharg = IsDashArg(interp, objv[j], 1, &nextMethodName, &nextArgc, &nextArgv))) { break; } } if (initString != NULL) { result = CallConfigureMethod(interp, object, initString, methodName, argc+1, objv+i+1); if (unlikely(result != TCL_OK)) { return result; } } i += argc; break; } case LIST_DASH: /* Argument is a list with a leading dash, grouping determined by list */ i++; nextMethodName = NULL; if (i < objc) { isdasharg = IsDashArg(interp, objv[i], 1, &nextMethodName, &nextArgc, &nextArgv); } else { nextMethodName = NULL; nextArgv = NULL; nextArgc = 0; } if (initString != NULL) { result = CallConfigureMethod(interp, object, initString, methodName, argc+1, argv+1); if (unlikely(result != TCL_OK)) { return result; } } break; case NO_DASH: nextArgc = 0; return NsfPrintError(interp, "%s configure: unexpected argument '%s' between parameters", ObjectName_(object), ObjStr(objv[i])); } } /* * Call init with residual args in case it was not called yet. */ result = DispatchInitMethod(interp, object, normalArgs, objv+1, 0u); if (likely(result == TCL_OK)) { /* * Return the non-processed leading arguments unless there was an * error (XOTcl convention). */ Tcl_SetObjResult(interp, Tcl_NewListObj((TCL_SIZE_T)normalArgs, objv+1)); } return result; } /* objectMethod uplevel NsfOUplevelMethod { {-argName "args" -type allargs} } */ static int NsfOUplevelMethod(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const objv[]) { int result, getFrameResult = 0; CallFrame *requestedFramePtr = NULL; nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); if (objc < 2) { result = NsfPrintError(interp, "wrong # args: should be \"%s %s ?level? command ?arg ...?\"", ObjectName_(object), NsfMethodName(objv[0])); } else if (objc == 2) { result = TCL_OK; } else { /* * TclObjGetFrame returns: * 0 ... when a syntactically invalid (incl. no) level specifier was provided * 1 ... when a syntactically valid level specifier with corresp. frame was found * -1 ... when a syntactically valid level specifier was provided, but an error occurred while finding the frame (error msg in interp, "bad level") */ getFrameResult = TclObjGetFrame(interp, objv[1], &requestedFramePtr); result = unlikely(getFrameResult == -1) ? TCL_ERROR : TCL_OK; } if (likely(result == TCL_OK)) { Tcl_CallFrame *framePtr, *savedVarFramePtr; objc -= getFrameResult + 1; objv += getFrameResult + 1; if (getFrameResult == 0) { /* * 0 is returned from TclObjGetFrame when no (or, an invalid) level * specifier was provided; objv[0] is interpreted as a command word, * uplevel defaults to the computed level. */ Tcl_CallFrame *callingFramePtr = NULL; framePtr = NULL; NsfCallStackFindCallingContext(interp, 1, &framePtr, &callingFramePtr); if (framePtr == NULL) { /* * No proc frame was found, default to parent frame. */ framePtr = callingFramePtr; } } else { /* * Use the requested frame corresponding to the (valid) level specifier. */ framePtr = (Tcl_CallFrame *)requestedFramePtr; } assert(framePtr != NULL); savedVarFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); Tcl_Interp_varFramePtr(interp) = (CallFrame *)framePtr; /* * Execute the residual arguments as a command. */ if (objc == 1) { result = Tcl_EvalObjEx(interp, objv[0], TCL_EVAL_DIRECT); } else { /* * More than one argument: concatenate them together with spaces * between, then evaluate the result. Tcl_EvalObjEx will delete * the object when it decrements its refCount after eval'ing it. */ Tcl_Obj *objPtr = Tcl_ConcatObj((TCL_SIZE_T)objc, objv); result = Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_DIRECT); } if (unlikely(result == TCL_ERROR)) { Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf("\n (\"uplevel\" body line %d)", Tcl_GetErrorLine(interp))); } /* * Restore the variable frame, and return. */ Tcl_Interp_varFramePtr(interp) = (CallFrame *)savedVarFramePtr; } return result; } /* objectMethod upvar NsfOUpvarMethod { {-argName "args" -type allargs} } */ static int NsfOUpvarMethod(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const objv[]) { Tcl_Obj *frameInfoObj; int i, result = TCL_ERROR; const char *frameInfo; callFrameContext ctx = {NULL, NULL, 0}; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); if (objc < 3) { return NsfPrintError(interp, "wrong # args: should be \"%s %s " "?level? otherVar localVar ?otherVar localVar ...?\"", ObjectName_(object), NsfMethodName(objv[0])); } if (objc % 2 == 0) { /* * Even number of arguments (including method), therefore, the level * specifier is considered to be the first argument. */ frameInfoObj = NULL; frameInfo = ObjStr(objv[1]); i = 2; } else { /* * Odd number of arguments (including method), therefore, the level * specifier considered absent and the level has to be computed. */ frameInfoObj = ComputeLevelObj(interp, CALLING_LEVEL); INCR_REF_COUNT(frameInfoObj); frameInfo = ObjStr(frameInfoObj); i = 1; } if ((object->filterStack != NULL) || (object->mixinStack != NULL)) { CallStackUseActiveFrame(interp, &ctx); } for ( ; i < objc; i += 2) { result = Tcl_UpVar2(interp, frameInfo, ObjStr(objv[i]), NULL, ObjStr(objv[i+1]), 0 /*flags*/); if (unlikely(result != TCL_OK)) { break; } } if (frameInfoObj != NULL) { DECR_REF_COUNT(frameInfoObj); } CallStackRestoreSavedFrames(interp, &ctx); return result; } /* objectMethod volatile NsfOVolatileMethod { } objectMethod volatile1 NsfOVolatile1Method { } */ static int VolatileMethod(Tcl_Interp *interp, NsfObject *object, bool shallow) { int result = TCL_ERROR; Tcl_Obj *objPtr; const char *fullName, *vn; callFrameContext ctx = {NULL, NULL, 0}; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); if (unlikely(RUNTIME_STATE(interp)->exitHandlerDestroyRound != NSF_EXITHANDLER_OFF)) { return NsfPrintError(interp, "can't make objects volatile during shutdown"); } if (shallow) { CallStackUseActiveFrame(interp, &ctx); } else { NsfObjectSystem *osPtr = GetObjectSystem(object); Tcl_CallFrame *invocationFrame; /* * XOTcl1 style */ /*NsfShowStack(interp);*/ CallStackUseActiveFrame(interp, &ctx); /*fprintf(stderr, "active varframe %p\n", (void*)Tcl_Interp_varFramePtr(interp));*/ invocationFrame = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); while (1) { if (((unsigned int)Tcl_CallFrame_isProcCallFrame(invocationFrame) & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) != 0u) { NsfCallStackContent *cscPtr; const char *cmdName; cscPtr = ((NsfCallStackContent *)Tcl_CallFrame_clientData(invocationFrame)); cmdName = Tcl_GetCommandName(interp, cscPtr->cmdPtr); /* * We were not called from an NSF frame. */ if (cscPtr == NULL) { break; } /* * Walk up the stack of invocations of the current object to skip * e.g. overloaded internally called methods like "configure". */ /*fprintf(stderr, "compare object %p == %p\n", (void*)object, (void*)cscPtr->self);*/ if (cscPtr->self == object && *osPtr->methodNames[NSF_o_configure_idx] == *cmdName && strcmp(osPtr->methodNames[NSF_o_configure_idx], Tcl_GetCommandName(interp, cscPtr->cmdPtr)) == 0) { invocationFrame = Tcl_CallFrame_callerPtr(invocationFrame); /*fprintf(stderr, "same object, continue with %p\n", (void*)invocationFrame);*/ continue; } /* * If this was a "next" call, continue to walk up. */ if ((cscPtr->flags & NSF_CSC_CALL_IS_NEXT) != 0u) { invocationFrame = Tcl_CallFrame_callerPtr(invocationFrame); /*fprintf(stderr, "next call with %p\n", (void*)invocationFrame);*/ continue; } /* * Final special case for XOTcl1 compliance: In case, we were called * from an "unknown" method, skip this frame as well. */ /*fprintf(stderr, "cmd %s\n", Tcl_GetCommandName(interp, cscPtr->cmdPtr));*/ if (*osPtr->methodNames[NSF_o_unknown_idx] == *cmdName && strcmp(osPtr->methodNames[NSF_o_unknown_idx], Tcl_GetCommandName(interp, cscPtr->cmdPtr)) == 0) { invocationFrame = Tcl_CallFrame_callerPtr(invocationFrame); /*fprintf(stderr, "have unknown, continue with %p\n", (void*)invocationFrame);*/ continue; } } break; } /* * Finally, set the invocation frame. The original frame context was saved * already by CallStackUseActiveFrame() and will be properly restored. */ Tcl_Interp_varFramePtr(interp) = (CallFrame *)invocationFrame; } objPtr = object->cmdName; fullName = ObjStr(objPtr); vn = NSTail(fullName); if (Tcl_SetVar2(interp, vn, NULL, fullName, 0)) { NsfObjectOpt *opt = NsfRequireObjectOpt(object); /*fprintf(stderr, "### setting trace for %s on frame %p\n", fullName, Tcl_Interp_varFramePtr(interp)); NsfShowStack(interp);*/ result = Tcl_TraceVar(interp, vn, TCL_TRACE_UNSETS, (Tcl_VarTraceProc *)NsfUnsetTrace, objPtr); opt->volatileVarName = vn; } CallStackRestoreSavedFrames(interp, &ctx); if (likely(result == TCL_OK)) { INCR_REF_COUNT2("volatile", objPtr); } return result; } static int NsfOVolatileMethod(Tcl_Interp *interp, NsfObject *object) { return VolatileMethod(interp, object, NSF_TRUE); } static int NsfOVolatile1Method(Tcl_Interp *interp, NsfObject *object) { return VolatileMethod(interp, object, NSF_FALSE); } /*********************************************************************** * End Object Methods ***********************************************************************/ /*********************************************************************** * Begin Class Methods ***********************************************************************/ static int NsfCAllocMethod_(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *nameObj, Tcl_Namespace *parentNsPtr) { const char *nameString; NsfObject *newObj; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(nameObj != NULL); nameString = ObjStr(nameObj); assert(isAbsolutePath(nameString)); assert(NSValidObjectName(nameString, 0) != 0); /* * Create a new object from scratch. */ if (! IsMetaClass(interp, class, NSF_TRUE)) { /* * If the base class is an ordinary class, we create an object. */ newObj = PrimitiveOCreate(interp, nameObj, parentNsPtr, class); } else { /* * If the base class is a metaclass, we create a class. */ newObj = (NsfObject *)PrimitiveCCreate(interp, nameObj, parentNsPtr, class); } if (unlikely(newObj == NULL)) { return NsfPrintError(interp, "alloc failed to create '%s' " "(possibly parent namespace does not exist)", nameString); } if (NSF_DTRACE_OBJECT_ALLOC_ENABLED()) { NSF_DTRACE_OBJECT_ALLOC(ObjectName(newObj), ClassName(class)); } /*fprintf(stderr, "PrimitiveCCreate returns nameObj %p typePtr %p %s\n", nameObj, nameObj->typePtr, ObjTypeStr(nameObj)); */ Tcl_SetObjResult(interp, nameObj); return TCL_OK; } /* classMethod alloc NsfCAllocMethod { {-argName "name" -required 1 -type tclobj} } */ static int NsfCAllocMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *nameObj) { const char *nameString; int result; TCL_SIZE_T nameLength = 0; /* * Create a new object from scratch. */ nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(nameObj != NULL); /* * Check for illegal names. */ nameString = Tcl_GetStringFromObj(nameObj, &nameLength); if (unlikely(NSValidObjectName(nameString, (size_t)nameLength) == 0)) { result = NsfPrintError(interp, "cannot allocate object - illegal name '%s'", nameString); } else { Tcl_Namespace *parentNsPtr; Tcl_Obj *tmpName; /* * Name is valid. If the path is not absolute, we add the appropriate * namespace. */ if (isAbsolutePath(nameString)) { parentNsPtr = NULL; tmpName = NULL; } else { parentNsPtr = CallingNameSpace(interp); nameObj = tmpName = NameInNamespaceObj(nameString, parentNsPtr); if (strchr(nameString, ':')) { parentNsPtr = NULL; } INCR_REF_COUNT(tmpName); /*fprintf(stderr, " **** NoAbsoluteName for '%s' -> determined = '%s' parentNs %s\n", nameString, ObjStr(tmpName), parentNsPtr->fullName);*/ } result = NsfCAllocMethod_(interp, class, nameObj, parentNsPtr); if (tmpName != NULL) { DECR_REF_COUNT(tmpName); } } return result; } /* classMethod create NsfCCreateMethod { {-argName "name" -required 1} {-argName "args" -type allargs} } */ static int NsfCCreateMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *nameObj, int objc, Tcl_Obj *const objv[]) { NsfObject *newObject = NULL; Tcl_Obj *actualNameObj, *methodObj, *tmpObj = NULL; int result; TCL_SIZE_T nameLength = 0; bool autoNameCreate; const char *nameString; Tcl_Namespace *parentNsPtr; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(nameObj != NULL); nonnull_assert(objv != NULL); nameString = Tcl_GetStringFromObj(nameObj, &nameLength); #if 0 { int i; fprintf(stderr, "NsfCCreateMethod %s create <%s> oc %d ", ClassName(class), ObjStr(nameObj), objc); for(i = 0; i < objc; i++) {fprintf(stderr, " [%d]=%s,", i, ObjStr(objv[i]));} fprintf(stderr, "\n"); } #endif if (unlikely(RUNTIME_STATE(interp)->exitHandlerDestroyRound != NSF_EXITHANDLER_OFF)) { fprintf(stderr, "### Can't create instance %s of class %s during interp shutdown.\n", ObjStr(nameObj), ClassName_(class)); /* * Don't fail, if this happens during destroy, it might be canceled. */ return TCL_OK; } /* * Check for illegal names. */ if (unlikely(NSValidObjectName(nameString, (size_t)nameLength) == 0)) { result = NsfPrintError(interp, "cannot allocate object - illegal name '%s'", nameString); goto create_method_exit; } /*fprintf(stderr, "NsfCCreateMethod specifiedName %s\n", nameString);*/ /* * Complete the name if it is not absolute. */ if (!isAbsolutePath(nameString)) { parentNsPtr = CallingNameSpace(interp); tmpObj = NameInNamespaceObj(nameString, parentNsPtr); /* * If the name contains colons, the parentNsPtr is not appropriate * for determining the parent. */ if (strchr(nameString, ':')) { parentNsPtr = NULL; } nameString = ObjStr(tmpObj); /* fprintf(stderr, " **** fixed name is '%s'\n", nameString); */ INCR_REF_COUNT(tmpObj); actualNameObj = tmpObj; autoNameCreate = NSF_FALSE; } else { parentNsPtr = NULL; actualNameObj = nameObj; /* fprintf(stderr, " **** used specified name is '%s'\n", nameString); */ /* * Check for autname prefix string. This string is always an absolute path * name, so it is sufficient to test here. */ autoNameCreate = (strncmp(autonamePrefix, nameString, autonamePrefixLength) == 0); } /* * Check whether we have to call recreate (i.e. when the object exists * already). First check whether we have such a command, then check whether * the command is an object. */ { Tcl_Command cmd = NSFindCommand(interp, nameString); if (cmd != NULL) { newObject = NsfGetObjectFromCmdPtr(cmd); if (newObject == NULL) { /* * We have a cmd, but no object. Don't allow one to overwrite an * ordinary cmd by an NSF object. */ result = NsfPrintError(interp, "refuse to overwrite cmd %s; delete/rename it before overwriting", nameString); goto create_method_exit; } } } /*fprintf(stderr, "+++ createspecifiedName '%s', nameString '%s', newObject=%p ismeta(%s) %d, ismeta(%s) %d\n", ObjStr(specifiedNameObj), nameString, newObject, ClassName(class), IsMetaClass(interp, class, NSF_TRUE), (newObject != NULL) ? ClassName(newObject->cl) : "NULL", (newObject != NULL) ? IsMetaClass(interp, newObject->cl, NSF_TRUE) : 0 );*/ /* * Provide protection against recreation if base classes. */ if (unlikely(newObject != NULL && unlikely(IsBaseClass(newObject)))) { result = NsfPrintError(interp, "cannot recreate base class %s", ObjectName(newObject)); goto create_method_exit; } /* * Don't allow one to * - recreate an object as a class, * - recreate a class as an object, and to * - recreate an object in a different object system * * In these cases, we use destroy followed by create instead of recreate. */ if ((newObject != NULL) && (IsMetaClass(interp, class, NSF_TRUE) == IsMetaClass(interp, newObject->cl, NSF_TRUE)) && GetObjectSystem(newObject) == class->osPtr) { /*fprintf(stderr, "%%%% recreate, call recreate method ... %s, objc=%d oldOs %p != newOs %p EQ %d\n", ObjStr(actualNameObj), objc+1, GetObjectSystem(newObject), cl->osPtr, GetObjectSystem(newObject) != cl->osPtr );*/ /* * Call recreate --> initialization. */ if (CallDirectly(interp, &class->object, NSF_c_recreate_idx, &methodObj)) { NSF_PROFILE_TIME_DATA; NSF_PROFILE_CALL(interp, &class->object, Nsf_SystemMethodOpts[NSF_c_recreate_idx]); result = RecreateObject(interp, class, newObject, objc, objv); NSF_PROFILE_EXIT(interp, &class->object, Nsf_SystemMethodOpts[NSF_c_recreate_idx]); } else { ALLOC_ON_STACK(Tcl_Obj*, objc+3, xov); xov[0] = NULL; /* just a placeholder for passing conventions in ObjectDispatch() */ xov[1] = methodObj; xov[2] = actualNameObj; if (objc >= 1) { memcpy(xov+3, objv, sizeof(Tcl_Obj *) * (size_t)objc); } result = ObjectDispatch(class, interp, objc+3, xov, NSF_CM_IGNORE_PERMISSIONS|NSF_CSC_IMMEDIATE); FREE_ON_STACK(Tcl_Obj *, xov); } if (unlikely(result != TCL_OK)) { goto create_method_exit; } Tcl_SetObjResult(interp, newObject->cmdName); ObjTrace("RECREATE", newObject); } else { /* * "newObject" might exist here, but will be automatically destroyed by * alloc. */ if (CallDirectly(interp, &class->object, NSF_c_alloc_idx, &methodObj)) { NSF_PROFILE_TIME_DATA; NSF_PROFILE_CALL(interp, &class->object, Nsf_SystemMethodOpts[NSF_c_alloc_idx]); result = NsfCAllocMethod_(interp, class, actualNameObj, parentNsPtr); NSF_PROFILE_EXIT(interp, &class->object, Nsf_SystemMethodOpts[NSF_c_alloc_idx]); } else { result = CallMethod(class, interp, methodObj, 3, &actualNameObj, NSF_CSC_IMMEDIATE); } if (unlikely(result != TCL_OK)) { goto create_method_exit; } actualNameObj = Tcl_GetObjResult(interp); if (unlikely(GetObjectFromObj(interp, actualNameObj, &newObject) != TCL_OK)) { result = NsfPrintError(interp, "couldn't find result of alloc"); goto create_method_exit; } ObjTrace("CREATE", newObject); if (autoNameCreate) { newObject->flags |= NSF_IS_AUTONAMED; } /* * In case, the object is destroyed during initialization, we increment * the refCount. */ INCR_REF_COUNT(actualNameObj); result = DoObjInitialization(interp, newObject, objc, objv); DECR_REF_COUNT(actualNameObj); } create_method_exit: if (tmpObj != NULL) { DECR_REF_COUNT(tmpObj); } return result; } /* classMethod dealloc NsfCDeallocMethod { {-argName "object" -required 1 -type tclobj} } */ static int NsfCDeallocMethod(Tcl_Interp *interp, NsfClass *UNUSED(class), Tcl_Obj *objectObj) { NsfObject *object; nonnull_assert(interp != NULL); if (GetObjectFromObj(interp, objectObj, &object) != TCL_OK) { return NsfPrintError(interp, "can't destroy object %s that does not exist", ObjStr(objectObj)); } return DoDealloc(interp, object); } /* classMethod filterguard NsfCFilterGuardMethod { {-argName "filter" -required 1} {-argName "guard" -required 1 -type tclobj} } */ static int NsfCFilterGuardMethod(Tcl_Interp *interp, NsfClass *class, const char *filter, Tcl_Obj *guardObj) { NsfClassOpt *opt; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(filter != NULL); nonnull_assert(guardObj != NULL); opt = class->opt; if (opt != NULL && opt->classFilters) { NsfCmdList *h = CmdListFindNameInList(interp, filter, opt->classFilters); if (h != NULL) { NsfClasses *subClasses = DependentSubClasses(class); if (h->clientData != NULL) { GuardDel(h); } GuardAdd(h, guardObj); if (subClasses != NULL) { FilterInvalidateObjOrders(interp, subClasses); NsfClassListFree(subClasses); } return TCL_OK; } } return NsfPrintError(interp, "filterguard: can't find filter %s on %s", filter, ClassName_(class)); } /* classMethod getCachedParameters NsfCGetCachendParametersMethod { } */ static int NsfCGetCachendParametersMethod(Tcl_Interp *interp, NsfClass *class) { nonnull_assert(interp != NULL); nonnull_assert(class != NULL); if (likely(class->parsedParamPtr != NULL && class->parsedParamPtr->paramDefs != NULL)) { Tcl_Obj *listObj; listObj = ListParamDefs(interp, class->parsedParamPtr->paramDefs->paramsPtr, NULL, NULL, NSF_PARAMS_PARAMETER); Tcl_SetObjResult(interp, listObj); DECR_REF_COUNT2("paramDefsObj", listObj); } return TCL_OK; } /* classMethod mixinguard NsfCMixinGuardMethod { {-argName "mixin" -required 1 -type tclobj} {-argName "guard" -required 1 -type tclobj} } */ static int NsfCMixinGuardMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *mixinObj, Tcl_Obj *guardObj) { NsfClassOpt *opt; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(mixinObj != NULL); nonnull_assert(guardObj != NULL); opt = class->opt; if (opt != NULL && opt->classMixins != NULL) { const Tcl_Command mixinCmd = Tcl_GetCommandFromObj(interp, mixinObj); if (mixinCmd != NULL) { const NsfClass *mixinClass = NsfGetClassFromCmdPtr(mixinCmd); if (mixinClass != NULL) { NsfCmdList *h = CmdListFindCmdInList(mixinCmd, opt->classMixins); if (h != NULL) { NsfClasses *subClasses; if (h->clientData != NULL) { GuardDel((NsfCmdList *) h); } GuardAdd(h, guardObj); subClasses = DependentSubClasses(class); MixinInvalidateObjOrders(subClasses); NsfClassListFree(subClasses); return TCL_OK; } } } } return NsfPrintError(interp, "mixinguard: can't find mixin %s on %s", ObjStr(mixinObj), ClassName_(class)); } /* classMethod new NsfCNewMethod { {-argName "-childof" -required 0 -type tclobj} {-argName "args" -required 0 -type args} } */ static int NsfCNewMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *childofObj, int trailingObjc, Tcl_Obj *const trailingObjv[]) { Tcl_Obj *fullnameObj; Tcl_DString dFullname, *dsPtr = &dFullname; int result; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); #if 0 { int i; fprintf(stderr, "NsfCNewMethod %s withChildof %p oc %d ", ClassName(class), childofObj, trailingObjc); for(i = 0; i < trailingObjc; i++) {fprintf(stderr, " [%d]=%s,", i, ObjStr(trailingObjv[i]));} fprintf(stderr, "\n"); } #endif Tcl_DStringInit(dsPtr); if (childofObj != 0) { const char *parentName = ObjStr(childofObj); /* * If "parentName" is fully qualified, use it as prefix, else prepend the * CallingNameSpace() to be compatible with the object name completion. */ if (*parentName == ':' && *(parentName + 1) == ':') { /* * Prepend parentName only if it is not "::" */ if (*(parentName + 2) != '\0') { Tcl_DStringAppend(dsPtr, parentName, TCL_INDEX_NONE); } } else { Tcl_Obj *tmpName = NameInNamespaceObj(parentName, CallingNameSpace(interp)); const char *completedParentName; INCR_REF_COUNT(tmpName); completedParentName = ObjStr(tmpName); if (strcmp(completedParentName, "::")) { Tcl_DStringAppend(dsPtr, ObjStr(tmpName), TCL_INDEX_NONE); } DECR_REF_COUNT(tmpName); } Tcl_DStringAppend(dsPtr, "::__#", 5); } else { Tcl_DStringAppend(dsPtr, autonamePrefix, (int)autonamePrefixLength); } NewTclCommand(interp, dsPtr); fullnameObj = Tcl_NewStringObj(Tcl_DStringValue(dsPtr), Tcl_DStringLength(dsPtr)); INCR_REF_COUNT(fullnameObj); { Tcl_Obj *methodObj; int callDirectly; callDirectly = CallDirectly(interp, &class->object, NSF_c_create_idx, &methodObj); if (callDirectly != 0) { NSF_PROFILE_TIME_DATA; NSF_PROFILE_CALL(interp, &class->object, Nsf_SystemMethodOpts[NSF_c_create_idx]); result = NsfCCreateMethod(interp, class, fullnameObj, trailingObjc, trailingObjv); NSF_PROFILE_EXIT(interp, &class->object, Nsf_SystemMethodOpts[NSF_c_create_idx]); } else { ALLOC_ON_STACK(Tcl_Obj*, trailingObjc+3, ov); ov[0] = NULL; /* just a placeholder for passing conventions in ObjectDispatch() */ ov[1] = methodObj; ov[2] = fullnameObj; if (trailingObjc >= 1) { memcpy(ov+3, trailingObjv, sizeof(Tcl_Obj *) * (size_t)trailingObjc); } result = ObjectDispatch(class, interp, trailingObjc+3, ov, NSF_CSC_IMMEDIATE); FREE_ON_STACK(Tcl_Obj *, ov); } } DECR_REF_COUNT(fullnameObj); Tcl_DStringFree(dsPtr); return result; } /* classMethod recreate NsfCRecreateMethod { {-argName "objectName" -required 1 -type tclobj} {-argName "args" -type virtualclassargs} } */ static int RecreateObject(Tcl_Interp *interp, NsfClass *class, NsfObject *object, int objc, Tcl_Obj *const objv[]) { int result; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(object != NULL); nonnull_assert(objv != NULL); object->flags |= NSF_RECREATE; /* * First, cleanup the data from the object. * * Check whether we have a pending destroy on the object; if yes, * clear it, such that the recreated object and won't be destroyed * on a POP. */ MarkUndestroyed(object); /* * Ensure correct class for object. */ result = ChangeClass(interp, object, class); if (likely(result == TCL_OK)) { Tcl_Obj *methodObj; /* * Dispatch "cleanup" method. */ if (CallDirectly(interp, object, NSF_o_cleanup_idx, &methodObj)) { NSF_PROFILE_TIME_DATA; /*fprintf(stderr, "RECREATE calls cleanup directly for object %s\n", ObjectName(object));*/ NSF_PROFILE_CALL(interp, object, Nsf_SystemMethodOpts[NSF_o_cleanup_idx]); result = NsfOCleanupMethod(interp, object); NSF_PROFILE_EXIT(interp, object, Nsf_SystemMethodOpts[NSF_o_cleanup_idx]); } else { /*NsfObjectSystem *osPtr = GetObjectSystem(object); fprintf(stderr, "RECREATE calls method cleanup for object %p %s OS %s\n", object, ObjectName(object), ObjectName(&osPtr->rootClass->object));*/ result = CallMethod(object, interp, methodObj, 2, NULL, NSF_CM_IGNORE_PERMISSIONS|NSF_CSC_IMMEDIATE); } } /* * Second: if cleanup was successful, initialize the object as usual. */ if (likely(result == TCL_OK)) { result = DoObjInitialization(interp, object, objc, objv); if (likely(result == TCL_OK)) { Tcl_SetObjResult(interp, object->cmdName); } else { /* fprintf(stderr, "recreate DoObjInitialization returned %d\n", result);*/ } } return result; } static int NsfCRecreateMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *objectNameObj, int trailingObjc, Tcl_Obj *const trailingObjv[]) { NsfObject *object; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(objectNameObj != NULL); if (GetObjectFromObj(interp, objectNameObj, &object) != TCL_OK) { return NsfPrintError(interp, "can't recreate non existing object %s", ObjStr(objectNameObj)); } return RecreateObject(interp, class, object, trailingObjc, trailingObjv); } /* classMethod superclass NsfCSuperclassMethod { {-argName "superclasses" -required 0 -type tclobj} } */ static int NsfCSuperclassMethod(Tcl_Interp *interp, NsfClass *class, Tcl_Obj *superclassesObj) { nonnull_assert(interp != NULL); nonnull_assert(class != NULL); return NsfRelationSetCmd(interp, &class->object, RelationtypeSuperclassIdx, superclassesObj); } /*********************************************************************** * End Class Methods ***********************************************************************/ static MethodtypeIdx_t AggregatedMethodType(MethodtypeIdx_t methodType) { MethodtypeIdx_t result; if (methodType == MethodtypeNULL) { result = MethodtypeAllIdx; } else if (methodType == MethodtypeBuiltinIdx) { result = NSF_METHODTYPE_BUILTIN|NSF_METHODTYPE_OBJECT; } else { result = methodType; } //fprintf(stderr, "AggregatedMethodType input %.4x output %.4x\n", methodType, result); return result; } /*********************************************************************** * Begin Object Info Methods ***********************************************************************/ /* objectInfoMethod baseclass NsfObjInfoBaseclassMethod { } */ static int NsfObjInfoBaseclassMethod(Tcl_Interp *interp, NsfObject *object) { NsfObjectSystem *osPtr; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); osPtr = GetObjectSystem(object); assert(osPtr != NULL); Tcl_SetObjResult(interp, osPtr->rootClass->object.cmdName); return TCL_OK; } /* objectInfoMethod children NsfObjInfoChildrenMethod { {-argName "-type" -required 0 -nrargs 1 -type class} {-argName "pattern" -required 0} } */ static int NsfObjInfoChildrenMethod(Tcl_Interp *interp, NsfObject *object, NsfClass *typeClass, const char *pattern) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); return ListChildren(interp, object, pattern, NSF_FALSE, typeClass); } /* objectInfoMethod class NsfObjInfoClassMethod { } */ static int NsfObjInfoClassMethod(Tcl_Interp *interp, NsfObject *object) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); Tcl_SetObjResult(interp, object->cl->object.cmdName); return TCL_OK; } /* objectInfoMethod filterguard NsfObjInfoFilterguardMethod { {-argName "filter" -required 1} } */ static int NsfObjInfoFilterguardMethod(Tcl_Interp *interp, NsfObject *object, const char *filter) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(filter != NULL); return (object->opt != NULL) ? GuardList(interp, object->opt->objFilters, filter) : TCL_OK; } /* objectInfoMethod filters NsfObjInfoFiltersMethod { {-argName "-guards" -nrargs 0 -type switch} {-argName "pattern"} } */ static int NsfObjInfoFiltersMethod(Tcl_Interp *interp, NsfObject *object, int withGuards, const char *pattern) { NsfObjectOpt *opt; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); opt = object->opt; return (opt != NULL) ? FilterInfo(interp, opt->objFilters, pattern, (withGuards == 1), NSF_FALSE) : TCL_OK; } /* objectInfoMethod forward NsfObjInfoForwardMethod { {-argName "-definition"} {-argName "pattern"} } */ static int NsfObjInfoForwardMethod(Tcl_Interp *interp, NsfObject *object, int withDefinition, const char *pattern) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); return (object->nsPtr != NULL) ? ListForward(interp, Tcl_Namespace_cmdTablePtr(object->nsPtr), pattern, withDefinition) : TCL_OK; } /* objectInfoMethod hasmixin NsfObjInfoHasMixinMethod { {-argName "class" -required 1 -type class} } */ static int NsfObjInfoHasMixinMethod(Tcl_Interp *interp, NsfObject *object, NsfClass *class) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(class != NULL); Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (int)(HasMixin(interp, object, class))); return TCL_OK; } /* objectInfoMethod hasnamespace NsfObjInfoHasnamespaceMethod { } */ static int NsfObjInfoHasnamespaceMethod(Tcl_Interp *interp, NsfObject *object) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); Tcl_SetBooleanObj(Tcl_GetObjResult(interp), object->nsPtr != NULL); return TCL_OK; } /* objectInfoMethod hastype NsfObjInfoHasTypeMethod { {-argName "class" -required 1 -type class} } */ static int NsfObjInfoHasTypeMethod(Tcl_Interp *interp, NsfObject *object, NsfClass *class) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(class != NULL); Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (int)(IsSubType(object->cl, class))); return TCL_OK; } /* objectInfoMethod lookupfilter NsfObjInfoLookupFilterMethod { {-argName "filter" -required 1} } */ static int NsfObjInfoLookupFilterMethod(Tcl_Interp *interp, NsfObject *object, const char *filter) { const char *filterName; NsfCmdList *cmdList; NsfClass *fcl; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(filter != NULL); /* * Searches for filter on [self] and returns fully qualified name if it is * not found it returns an empty string. */ Tcl_ResetResult(interp); if ((object->flags & NSF_FILTER_ORDER_VALID) == 0u) { FilterComputeDefined(interp, object); } if ((object->flags & NSF_FILTER_ORDER_DEFINED) == 0u) { return TCL_OK; } for (cmdList = object->filterOrder; cmdList; cmdList = cmdList->nextPtr) { filterName = Tcl_GetCommandName(interp, cmdList->cmdPtr); if (filterName[0] == filter[0] && !strcmp(filterName, filter)) { break; } } if (cmdList == NULL) { return TCL_OK; } fcl = cmdList->clorobj; Tcl_SetObjResult(interp, MethodHandleObj((NsfObject *)fcl, !NsfObjectIsClass(&fcl->object), filterName)); return TCL_OK; } /* objectInfoMethod lookupfilters NsfObjInfoLookupFiltersMethod { {-argName "-guards" -nrargs 0 -type switch} {-argName "pattern"} } */ static int NsfObjInfoLookupFiltersMethod(Tcl_Interp *interp, NsfObject *object, int withGuards, const char *pattern) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); if ((object->flags & NSF_FILTER_ORDER_VALID) == 0u) { FilterComputeDefined(interp, object); } return FilterInfo(interp, object->filterOrder, pattern, (withGuards == 1), NSF_TRUE); } /* objectInfoMethod lookupmethod NsfObjInfoLookupMethodMethod { {-argName "name" -required 1 -type tclobj} } */ static int NsfObjInfoLookupMethodMethod(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *nameObj) { NsfClass *classPtr = NULL; Tcl_Command cmd; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(nameObj != NULL); cmd = ObjectFindMethod(interp, object, nameObj, &classPtr); if (likely(cmd != NULL)) { NsfObject *pobj = (classPtr != NULL) ? &classPtr->object : object; int perObject = (classPtr == NULL); ListMethod(interp, pobj, pobj, ObjStr(nameObj), cmd, InfomethodsubcmdRegistrationhandleIdx, NULL, NULL, (perObject == 1)); } return TCL_OK; } static int ListMethodKeysClassList(Tcl_Interp *interp, NsfClasses *classListPtr, DefinitionsourceIdx_t withSource, const char *pattern, MethodtypeIdx_t methodType, CallprotectionIdx_t withCallprotection, bool withPath, Tcl_HashTable *dups, NsfObject *object, bool withPer_object) nonnull(1) nonnull(8) nonnull(9); static int ListMethodKeysClassList(Tcl_Interp *interp, NsfClasses *classListPtr, DefinitionsourceIdx_t withSource, const char *pattern, MethodtypeIdx_t methodType, CallprotectionIdx_t withCallprotection, bool withPath, Tcl_HashTable *dups, NsfObject *object, bool withPer_object) { nonnull_assert(interp != NULL); nonnull_assert(dups != NULL); nonnull_assert(object != NULL); /* * Append method keys from inheritance order */ for (; classListPtr != NULL; classListPtr = classListPtr->nextPtr) { Tcl_HashTable *cmdTablePtr = Tcl_Namespace_cmdTablePtr(classListPtr->cl->nsPtr); if (!MethodSourceMatches(withSource, classListPtr->cl, NULL)) { continue; } ListMethodKeys(interp, cmdTablePtr, NULL, pattern, methodType, withCallprotection, withPath, dups, object, withPer_object); } return TCL_OK; } /* objectInfoMethod lookupmethods NsfObjInfoLookupMethodsMethod { {-argName "-callprotection" -type "all|public|protected|private" -default all} {-argName "-incontext" -nrargs 0} {-argName "-type" -typeName "methodtype" -type "all|scripted|builtin|alias|forwarder|object|setter|nsfproc"} {-argName "-nomixins" -nrargs 0} {-argName "-path" -nrargs 0} {-argName "-source" -type "all|application|system" -default all} {-argName "pattern" -required 0} } */ static int NsfObjInfoLookupMethodsMethod(Tcl_Interp *interp, NsfObject *object, CallprotectionIdx_t withCallprotection, int withIncontext, MethodtypeIdx_t withType, int withNomixins, int withPath, DefinitionsourceIdx_t withSource, const char *pattern) { int result; bool withPer_object = NSF_TRUE; Tcl_HashTable dupsTable, *dups = &dupsTable; MethodtypeIdx_t methodType = AggregatedMethodType(withType); nonnull_assert(interp != NULL); nonnull_assert(object != NULL); /* * TODO: We could make this faster for patterns without meta-chars by * letting ListMethodKeys() to signal us when an entry was found. we * wait, until the we decided about "info methods defined" vs. "info * method search" vs. "info defined" etc. */ if (withCallprotection == CallprotectionNULL) { withCallprotection = CallprotectionPublicIdx; } if (withSource == DefinitionsourceNULL) { withSource = DefinitionsourceAllIdx; } Tcl_InitHashTable(dups, TCL_STRING_KEYS); if (object->nsPtr != NULL) { Tcl_HashTable *cmdTablePtr = Tcl_Namespace_cmdTablePtr(object->nsPtr); if (MethodSourceMatches(withSource, NULL, object)) { ListMethodKeys(interp, cmdTablePtr, NULL, pattern, methodType, withCallprotection, (withPath == 1), dups, object, withPer_object); } } if (withNomixins == 0) { if ((object->flags & NSF_MIXIN_ORDER_VALID) == 0u) { MixinComputeDefined(interp, object); } if ((object->flags & NSF_MIXIN_ORDER_DEFINED_AND_VALID) != 0u) { NsfCmdList *ml; for (ml = object->mixinOrder; ml; ml = ml->nextPtr) { int guardOk = TCL_OK; NsfClass *mixin = NsfGetClassFromCmdPtr(ml->cmdPtr); assert(mixin != NULL); if (withIncontext != 0) { if (!RUNTIME_STATE(interp)->guardCount && ml->clientData) { guardOk = GuardCall(object, interp, ml->clientData, NULL); } } if (mixin && guardOk == TCL_OK) { Tcl_HashTable *cmdTablePtr = Tcl_Namespace_cmdTablePtr(mixin->nsPtr); if (!MethodSourceMatches(withSource, mixin, NULL)) { continue; } ListMethodKeys(interp, cmdTablePtr, NULL, pattern, methodType, withCallprotection, withPath, dups, object, withPer_object); } } } } result = ListMethodKeysClassList(interp, PrecedenceOrder(object->cl), withSource, pattern, methodType, withCallprotection, (withPath == 1), dups, object, withPer_object); Tcl_DeleteHashTable(dups); return result; } /* objectInfoMethod lookupmixins NsfObjInfoLookupMixinsMethod { {-argName "-guards" -nrargs 0 -type switch} {-argName "pattern" -type objpattern} } */ static int NsfObjInfoLookupMixinsMethod(Tcl_Interp *interp, NsfObject *object, int withGuards, const char *patternString, NsfObject *patternObject) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); if ((object->flags & NSF_MIXIN_ORDER_VALID) == 0u) { MixinComputeDefined(interp, object); } return MixinInfo(interp, object->mixinOrder, patternString, (withGuards == 1), patternObject); } /* objectInfoMethod lookupslots NsfObjInfoLookupSlotsMethod { {-argName "-source" -nrargs 1 -type "all|application|system" -default all} {-argName "-type" -required 0 -nrargs 1 -type class} {-argName "pattern" -required 0} } */ static int NsfObjInfoLookupSlotsMethod(Tcl_Interp *interp, NsfObject *object, DefinitionsourceIdx_t withSource, NsfClass *typeClass, const char *pattern) { Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); NsfClasses *precedenceList, *clPtr; Tcl_HashTable slotTable; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); precedenceList = ComputePrecedenceList(interp, object, NULL /* pattern*/, NSF_TRUE, NSF_TRUE); assert(precedenceList != NULL); if (withSource == 0) { withSource = 1; } Tcl_InitHashTable(&slotTable, TCL_STRING_KEYS); MEM_COUNT_ALLOC("Tcl_InitHashTable", &slotTable); /* * First add the per-object slot objects. */ if (MethodSourceMatches(withSource, NULL, object)) { AddSlotObjects(interp, object, "::per-object-slot", &slotTable, typeClass, pattern, listObj); } /* * Then add the class provided slot objects. */ for (clPtr = precedenceList; likely(clPtr != NULL); clPtr = clPtr->nextPtr) { if (MethodSourceMatches(withSource, clPtr->cl, NULL)) { AddSlotObjects(interp, &clPtr->cl->object, "::slot", &slotTable, typeClass, pattern, listObj); } } Tcl_DeleteHashTable(&slotTable); MEM_COUNT_FREE("Tcl_InitHashTable", &slotTable); NsfClassListFree(precedenceList); Tcl_SetObjResult(interp, listObj); return TCL_OK; } /* objectInfoMethod method NsfObjInfoMethodMethod { {-argName "infomethodsubcmd" -type "args|body|definition|exists|registrationhandle|definitionhandle|origin|parameter|syntax|type|precondition|postcondition|submethods"} {-argName "name" -required 1 -type tclobj} } */ static int NsfObjInfoMethodMethod(Tcl_Interp *interp, NsfObject *object, InfomethodsubcmdIdx_t subcmd, Tcl_Obj *nameObj) { return ListMethodResolve(interp, subcmd, NULL, NULL, object->nsPtr, object, nameObj, NSF_FALSE); } /* objectInfoMethod methods NsfObjInfoMethodsMethod { {-argName "-callprotection" -type "all|public|protected|private" -default all} {-argName "-type" -nrargs 1 -typeName "methodtype" -type "all|scripted|builtin|alias|forwarder|object|setter"} {-argName "-path" -nrargs 0} {-argName "pattern"} } */ static int NsfObjInfoMethodsMethod(Tcl_Interp *interp, NsfObject *object, CallprotectionIdx_t withCallprotection, MethodtypeIdx_t withType, int withPath, const char *pattern) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); return ListDefinedMethods(interp, object, pattern, 1 /* per-object */, AggregatedMethodType(withType), withCallprotection, withPath); } /* objectInfoMethod mixins NsfObjInfoMixinsMethod { {-argName "-guards" -nrargs 0 -type switch} {-argName "pattern" -type objpattern} } */ static int NsfObjInfoMixinsMethod(Tcl_Interp *interp, NsfObject *object, int withGuards, const char *patternString, NsfObject *patternObject) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); return (object->opt != NULL) ? MixinInfo(interp, object->opt->objMixins, patternString, (withGuards == 1), patternObject) : TCL_OK; } /* objectInfoMethod mixinguard NsfObjInfoMixinguardMethod { {-argName "mixin" -required 1} } */ static int NsfObjInfoMixinguardMethod(Tcl_Interp *interp, NsfObject *object, const char *mixin) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); nonnull_assert(mixin != NULL); return (object->opt != NULL) ? GuardList(interp, object->opt->objMixins, mixin) : TCL_OK; } /* objectInfoMethod name NsfObjInfoNameMethod { } */ static int NsfObjInfoNameMethod(Tcl_Interp *interp, NsfObject *object) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_GetCommandName(interp, object->id), TCL_INDEX_NONE)); return TCL_OK; } /* objectInfoMethod parent NsfObjInfoParentMethod { } */ static int NsfObjInfoParentMethod(Tcl_Interp *interp, NsfObject *object) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); if (object->id != NULL) { Tcl_Namespace *nsPtr = Tcl_Command_nsPtr(object->id); Tcl_SetObjResult(interp, Tcl_NewStringObj((nsPtr != NULL) ? nsPtr->fullName : "", TCL_INDEX_NONE)); } return TCL_OK; } /* objectInfoMethod precedence NsfObjInfoPrecedenceMethod { {-argName "-intrinsic"} {-argName "pattern" -required 0} } */ static int NsfObjInfoPrecedenceMethod(Tcl_Interp *interp, NsfObject *object, int withIntrinsic, const char *pattern) { NsfClasses *precedenceList, *pl; Tcl_Obj *resultObj = Tcl_NewObj(); nonnull_assert(interp != NULL); nonnull_assert(object != NULL); precedenceList = ComputePrecedenceList(interp, object, pattern, (withIntrinsic == 0), NSF_TRUE); for (pl = precedenceList; pl != NULL; pl = pl->nextPtr) { assert(pl->cl != NULL); Tcl_ListObjAppendElement(interp, resultObj, pl->cl->object.cmdName); } if (precedenceList != NULL) { NsfClassListFree(precedenceList); } Tcl_SetObjResult(interp, resultObj); return TCL_OK; } /* objectInfoMethod slotobjects NsfObjInfoSlotobjectsMethod { {-argName "-type" -required 0 -nrargs 1 -type class} {-argName "pattern" -required 0} } */ static int NsfObjInfoSlotobjectsMethod(Tcl_Interp *interp, NsfObject *object, NsfClass *typeClass, const char *pattern) { Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); nonnull_assert(interp != NULL); nonnull_assert(object != NULL); AddSlotObjects(interp, object, "::per-object-slot", NULL, typeClass, pattern, listObj); Tcl_SetObjResult(interp, listObj); return TCL_OK; } /* objectInfoMethod vars NsfObjInfoVarsMethod { {-argName "pattern" -required 0} } */ static int NsfObjInfoVarsMethod(Tcl_Interp *interp, NsfObject *object, const char *pattern) { Tcl_Obj *okList; TclVarHashTable *varTablePtr; nonnull_assert(interp != NULL); nonnull_assert(object != NULL); okList = Tcl_NewListObj(0, NULL); varTablePtr = (object->nsPtr != NULL) ? Tcl_Namespace_varTablePtr(object->nsPtr) : object->varTablePtr; /* * It is possible, that both, object->nsPtr and object->varTablePtr are * NULL. */ if (likely(varTablePtr != NULL)) { Tcl_Obj *varList, *element; TCL_SIZE_T i, length; ListVarKeys(interp, TclVarHashTablePtr(varTablePtr), pattern); varList = Tcl_GetObjResult(interp); Tcl_ListObjLength(interp, varList, &length); for (i = 0; i < length; i++) { Tcl_ListObjIndex(interp, varList, (TCL_SIZE_T)i, &element); if (VarExists(interp, object, ObjStr(element), NULL, NSF_VAR_REQUIRE_DEFINED)) { Tcl_ListObjAppendElement(interp, okList, element); } else { /*fprintf(stderr, "must ignore '%s' %d\n", ObjStr(element), i);*/ /*Tcl_ListObjReplace(interp, varList, i, 1, 0, NULL);*/ } } } Tcl_SetObjResult(interp, okList); return TCL_OK; } /*********************************************************************** * End Object Info Methods ***********************************************************************/ /*********************************************************************** * Begin Class Info methods ***********************************************************************/ /* classInfoMethod filterguard NsfClassInfoFilterguardMethod { {-argName "filter" -required 1} } */ static int NsfClassInfoFilterguardMethod(Tcl_Interp *interp, NsfClass *class, const char *filter) { nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(filter != NULL); return (class->opt != NULL) ? GuardList(interp, class->opt->classFilters, filter) : TCL_OK; } /* classInfoMethod filters NsfClassInfoFiltersMethod { {-argName "-guards" -nrargs 0 -type switch} {-argName "pattern"} } */ static int NsfClassInfoFiltersMethod(Tcl_Interp *interp, NsfClass *class, int withGuards, const char *pattern) { nonnull_assert(interp != NULL); nonnull_assert(class != NULL); return (class->opt != NULL) ? FilterInfo(interp, class->opt->classFilters, pattern, (withGuards == 1), NSF_FALSE) : TCL_OK; } /* classInfoMethod forward NsfClassInfoForwardMethod { {-argName "-definition"} {-argName "pattern"} } */ static int NsfClassInfoForwardMethod(Tcl_Interp *interp, NsfClass *class, int withDefinition, const char *pattern) { nonnull_assert(interp != NULL); nonnull_assert(class != NULL); return ListForward(interp, Tcl_Namespace_cmdTablePtr(class->nsPtr), pattern, withDefinition); } /* classInfoMethod heritage NsfClassInfoHeritageMethod { {-argName "pattern"} } */ static int NsfClassInfoHeritageMethod(Tcl_Interp *interp, NsfClass *class, const char *pattern) { NsfClasses *pl, *intrinsic, *checkList = NULL, *mixinClasses = NULL; Tcl_Obj *resultObj; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); resultObj = Tcl_NewObj(); intrinsic = PrecedenceOrder(class); NsfClassListAddPerClassMixins(interp, class, &mixinClasses, &checkList); for (pl = mixinClasses; pl != NULL; pl = pl->nextPtr) { if (NsfClassListFind(pl->nextPtr, pl->cl) == NULL && NsfClassListFind(intrinsic, pl->cl) == NULL) { AppendMatchingElement(interp, resultObj, pl->cl->object.cmdName, pattern); } } if (intrinsic != NULL) { for (pl = intrinsic->nextPtr; pl != NULL; pl = pl->nextPtr) { AppendMatchingElement(interp, resultObj, pl->cl->object.cmdName, pattern); } } if (mixinClasses != NULL) { NsfClassListFree(mixinClasses); } if (checkList != NULL) { NsfClassListFree(checkList); } Tcl_SetObjResult(interp, resultObj); return TCL_OK; } /* *---------------------------------------------------------------------- * * InstancesFromClassList -- * * Collect all instances of the classes of the provided class list in the * returned result object. * * Results: * Tcl_Obj containing a list of instances or a single instance * * Side effects: * Updated resultObj. * *---------------------------------------------------------------------- */ static Tcl_Obj *InstancesFromClassList( Tcl_Interp *interp, NsfClasses *subClasses, const char *pattern, NsfObject *matchObject ) nonnull(1) nonnull(2) returns_nonnull; static Tcl_Obj * InstancesFromClassList( Tcl_Interp *interp, NsfClasses *subClasses, const char *pattern, NsfObject *matchObject ) { Tcl_Obj *resultObj = Tcl_NewObj(); nonnull_assert(interp != NULL); nonnull_assert(subClasses != NULL); do { Tcl_HashTable *tablePtr = &subClasses->cl->instances; const Tcl_HashEntry *hPtr; Tcl_HashSearch search; for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { NsfObject *inst = (NsfObject *) Tcl_GetHashKey(tablePtr, hPtr); if (matchObject != NULL && inst == matchObject) { Tcl_SetStringObj(resultObj, ObjStr(matchObject->cmdName), TCL_INDEX_NONE); return resultObj; } AppendMatchingElement(interp, resultObj, inst->cmdName, pattern); } subClasses = subClasses->nextPtr; } while (subClasses != NULL); return resultObj; } /* classInfoMethod instances NsfClassInfoInstancesMethod { {-argName "-closure" -nrargs 0} {-argName "pattern" -type objpattern} } */ static int NsfClassInfoInstancesMethod( Tcl_Interp *interp, NsfClass *class, int withClosure, const char *patternString, NsfObject *patternObject ) { NsfClasses clElement, *subClasses; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); if (withClosure != 0) { subClasses = TransitiveSubClasses(class); } else { subClasses = &clElement; clElement.cl = class; clElement.nextPtr = NULL; } Tcl_SetObjResult(interp, InstancesFromClassList(interp, subClasses, patternString, patternObject)); if (withClosure != 0) { NsfClassListFree(subClasses); } return TCL_OK; } /* classInfoMethod method NsfClassInfoMethodMethod { {-argName "infomethodsubcmd" -type "args|body|definition|exists|registrationhandle|definitionhandle|origin|parameter|syntax|type|precondition|postcondition|submethods|returns"} {-argName "name" -required 1 -type tclobj} } */ static int NsfClassInfoMethodMethod( Tcl_Interp *interp, NsfClass *class, InfomethodsubcmdIdx_t subcmd, Tcl_Obj *nameObj ) { return ListMethodResolve(interp, subcmd, NULL, NULL, class->nsPtr, &class->object, nameObj, NSF_TRUE); } /* classInfoMethod methods NsfClassInfoMethodsMethod { {-argName "-callprotection" -type "all|public|protected|private" -default all} {-argName "-closure" -nrargs 0} {-argName "-type" -typeName "methodtype" -nrargs 1 -type "all|scripted|builtin|alias|forwarder|object|setter"} {-argName "-path" -nrargs 0} {-argName "-source" -nrargs 1 -type "all|application|system"} {-argName "pattern"} } */ static int NsfClassInfoMethodsMethod( Tcl_Interp *interp, NsfClass *class, CallprotectionIdx_t withCallprotection, int withClosure, MethodtypeIdx_t withType, int withPath, DefinitionsourceIdx_t withSource, const char *pattern ) { nonnull_assert(interp != NULL); nonnull_assert(class != NULL); if (withClosure != 0) { NsfClasses *checkList = NULL, *mixinClasses = NULL; Tcl_HashTable dupsTable, *dups = &dupsTable; int result; #if 0 if (withCallprotection == CallprotectionNULL) { withCallprotection = CallprotectionPublicIdx; } #endif if (withSource == DefinitionsourceNULL) { withSource = DefinitionsourceAllIdx; } Tcl_InitHashTable(dups, TCL_STRING_KEYS); /* * Guards are ignored. */ NsfClassListAddPerClassMixins(interp, class, &mixinClasses, &checkList); (void) ListMethodKeysClassList(interp, mixinClasses, withSource, pattern, AggregatedMethodType(withType), withCallprotection, withPath, dups, &class->object, NSF_FALSE); if (checkList != NULL) { NsfClassListFree(checkList); } if (mixinClasses != NULL) { NsfClassListFree(mixinClasses); } result = ListMethodKeysClassList(interp, PrecedenceOrder(class), withSource, pattern, AggregatedMethodType(withType), withCallprotection, withPath, dups, &class->object, NSF_FALSE); Tcl_DeleteHashTable(dups); return result; } else { if (withSource != 0) { return NsfPrintError(interp, "-source cannot be used without -closure\n"); } return ListDefinedMethods(interp, &class->object, pattern, 0 /* per-object */, AggregatedMethodType(withType), withCallprotection, withPath); } } /* classInfoMethod mixins NsfClassInfoMixinsMethod { {-argName "-closure" -nrargs 0 -type switch} {-argName "-guards" -nrargs 0 -type switch} {-argName "-heritage" -nrargs 0 -type switch} {-argName "pattern" -type objpattern} } */ static int NsfClassInfoMixinsMethod( Tcl_Interp *interp, NsfClass *class, int withClosure, int withGuards, int withHeritage, const char *patternString, NsfObject *patternObject ) { NsfClassOpt *opt; Tcl_Obj *resultObj; int result = TCL_OK; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); opt = class->opt; Tcl_ResetResult(interp); resultObj = Tcl_GetObjResult(interp); if (withHeritage != 0) { NsfClasses *checkList = NULL, *mixinClasses = NULL, *clPtr; if (withGuards != 0) { return NsfPrintError(interp, "-guards cannot be used together with -heritage\n"); } NsfClassListAddPerClassMixins(interp, class, &mixinClasses, &checkList); for (clPtr = mixinClasses; clPtr != NULL; clPtr = clPtr->nextPtr) { if (NsfClassListFind(clPtr->nextPtr, clPtr->cl)) { continue; } AppendMatchingElement(interp, resultObj, clPtr->cl->object.cmdName, patternString); } if (checkList != NULL) { NsfClassListFree(checkList); } if (mixinClasses != NULL) { NsfClassListFree(mixinClasses); } } else if (withClosure != 0) { Tcl_HashTable objTable, *commandTable = &objTable; bool done; MEM_COUNT_ALLOC("Tcl_InitHashTable", commandTable); Tcl_InitHashTable(commandTable, TCL_ONE_WORD_KEYS); done = GetAllClassMixins(interp, commandTable, resultObj, class, (withGuards == 1), patternString, patternObject); if (patternObject != NULL && done && !withGuards) { Tcl_SetObjResult(interp, patternObject->cmdName); } Tcl_DeleteHashTable(commandTable); MEM_COUNT_FREE("Tcl_InitHashTable", commandTable); } else { result = (opt != NULL) ? MixinInfo(interp, opt->classMixins, patternString, (withGuards == 1), patternObject) : TCL_OK; } return result; } /* classInfoMethod mixinguard NsfClassInfoMixinguardMethod { {-argName "mixin" -required 1} } */ static int NsfClassInfoMixinguardMethod(Tcl_Interp *interp, NsfClass *class, const char *mixin) { nonnull_assert(interp != NULL); nonnull_assert(class != NULL); nonnull_assert(mixin != NULL); return (class->opt != NULL) ? GuardList(interp, class->opt->classMixins, mixin) : TCL_OK; } /* classInfoMethod mixinof NsfClassInfoMixinOfMethod { {-argName "-closure" -nrargs 0} {-argName "-scope" -required 0 -nrargs 1 -type "all|class|object"} {-argName "pattern" -type objpattern} } */ static int NsfClassInfoMixinOfMethod( Tcl_Interp *interp, NsfClass *class, int withClosure, MixinscopeIdx_t withScope, const char *patternString, NsfObject *patternObject ) { NsfClassOpt *opt; bool perClass, perObject, done = NSF_FALSE; Tcl_Obj *resultObj; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); opt = class->opt; Tcl_ResetResult(interp); resultObj = Tcl_GetObjResult(interp); if (withScope == MixinscopeNULL || withScope == MixinscopeAllIdx) { perClass = NSF_TRUE; perObject = NSF_TRUE; } else if (withScope == MixinscopeClassIdx) { perClass = NSF_TRUE; perObject = NSF_FALSE; } else { perClass = NSF_FALSE; perObject = NSF_TRUE; } if (opt != NULL && !withClosure) { if (perClass && opt->isClassMixinOf != NULL) { done = AppendMatchingElementsFromCmdList(interp, opt->isClassMixinOf, resultObj, patternString, patternObject); if (done && (patternObject != NULL)) { goto finished; } } if (perObject && opt->isObjectMixinOf) { done = AppendMatchingElementsFromCmdList(interp, opt->isObjectMixinOf, resultObj, patternString, patternObject); } } else if (withClosure != 0) { Tcl_HashTable objTable, *commandTable = &objTable; MEM_COUNT_ALLOC("Tcl_InitHashTable", commandTable); Tcl_InitHashTable(commandTable, TCL_ONE_WORD_KEYS); if (perClass) { done = GetAllClassMixinsOf(interp, commandTable, resultObj, class, NSF_FALSE, NSF_TRUE, patternString, patternObject); if (done && (patternObject != NULL)) { goto finished; } } if (perObject) { done = GetAllObjectMixinsOf(interp, commandTable, resultObj, class, NSF_FALSE, NSF_TRUE, patternString, patternObject); } Tcl_DeleteHashTable(commandTable); MEM_COUNT_FREE("Tcl_InitHashTable", commandTable); } finished: if (patternObject != NULL) { Tcl_SetObjResult(interp, done ? patternObject->cmdName : NsfGlobalObjs[NSF_EMPTY]); } else { Tcl_SetObjResult(interp, resultObj); } return TCL_OK; } /* classInfoMethod slots NsfClassInfoSlotobjectsMethod { {-argName "-closure" -nrargs 0} {-argName "-source" -nrargs 1 -type "all|application|system"} {-argName "-type" -required 0 -nrargs 1 -type class} {-argName "pattern" -required 0} } */ static int NsfClassInfoSlotobjectsMethod(Tcl_Interp *interp, NsfClass *class, int withClosure, DefinitionsourceIdx_t withSource, NsfClass *typeClass, const char *pattern) { NsfClasses *clPtr, *intrinsicClasses, *precedenceList = NULL; Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); Tcl_HashTable slotTable; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); Tcl_ResetResult(interp); intrinsicClasses = PrecedenceOrder(class); if (withClosure != 0) { NsfClasses *checkList = NULL, *mixinClasses = NULL; /* * Compute the closure: first the transitive mixin-classes... */ NsfClassListAddPerClassMixins(interp, class, &mixinClasses, &checkList); for (clPtr = mixinClasses; clPtr != NULL; clPtr = clPtr->nextPtr) { if (NsfClassListFind(clPtr->nextPtr, clPtr->cl) == NULL && NsfClassListFind(intrinsicClasses, clPtr->cl) == NULL) { NsfClassListAdd(&precedenceList, clPtr->cl, NULL); } } /* * ... followed by the intrinsic classes. */ NsfClassListAdd(&precedenceList, class, NULL); for (clPtr = intrinsicClasses->nextPtr; clPtr != NULL; clPtr = clPtr->nextPtr) { NsfClassListAdd(&precedenceList, clPtr->cl, NULL); } if (checkList != NULL) { NsfClassListFree(checkList); } if (mixinClasses != NULL) { NsfClassListFree(mixinClasses); } } else { NsfClassListAdd(&precedenceList, class, NULL); } /* NsfClassListPrint("precedence", precedenceList); */ if (withSource == 0) { withSource = 1; } /* * Use a hash-table to eliminate potential duplicates. */ Tcl_InitHashTable(&slotTable, TCL_STRING_KEYS); MEM_COUNT_ALLOC("Tcl_InitHashTable", &slotTable); for (clPtr = precedenceList; clPtr != NULL; clPtr = clPtr->nextPtr) { if (MethodSourceMatches(withSource, clPtr->cl, NULL)) { AddSlotObjects(interp, &clPtr->cl->object, "::slot", &slotTable, typeClass, pattern, listObj); } } Tcl_DeleteHashTable(&slotTable); MEM_COUNT_FREE("Tcl_InitHashTable", &slotTable); if (precedenceList != NULL) { NsfClassListFree(precedenceList); } Tcl_SetObjResult(interp, listObj); return TCL_OK; } /* classInfoMethod subclass NsfClassInfoSubclassMethod { {-argName "-closure" -nrargs 0 -type switch} {-argName "-dependent" -nrargs 0 -type switch} {-argName "pattern" -type objpattern} } */ static int NsfClassInfoSubclassMethod(Tcl_Interp *interp, NsfClass *class, int withClosure, int withDependent, const char *patternString, NsfObject *patternObject) { bool found = NSF_FALSE; nonnull_assert(interp != NULL); nonnull_assert(class != NULL); if (withClosure && withDependent) { return NsfPrintError(interp, "only -closure or -dependent can be specified, not both"); } if (withClosure || withDependent) { NsfClasses *subClasses = (withClosure != 0) ? TransitiveSubClasses(class) : DependentSubClasses(class); if (subClasses != NULL) { found = AppendMatchingElementsFromClasses(interp, subClasses, patternString, patternObject); NsfClassListFree(subClasses); } } else if (class->sub != NULL) { found = AppendMatchingElementsFromClasses(interp, class->sub, patternString, patternObject); } if (patternObject != NULL) { Tcl_SetObjResult(interp, found ? patternObject->cmdName : NsfGlobalObjs[NSF_EMPTY]); } return TCL_OK; } /* classInfoMethod superclass NsfClassInfoSuperclassMethod { {-argName "-closure" -nrargs 0} {-argName "pattern" -type tclobj} } */ static int NsfClassInfoSuperclassMethod(Tcl_Interp *interp, NsfClass *class, int withClosure, Tcl_Obj *patternObj) { nonnull_assert(interp != NULL); nonnull_assert(class != NULL); return ListSuperClasses(interp, class, patternObj, (withClosure == 1)); } /*********************************************************************** * End Class Info methods ***********************************************************************/ /* * Initialization and Exit handlers */ #ifdef DO_FULL_CLEANUP /* * Delete global variables and procs. */ static void DeleteProcsAndVars( Tcl_Interp *interp, Tcl_Namespace *nsPtr, bool withKeepvars ) nonnull(1) nonnull(2); static void DeleteProcsAndVars( Tcl_Interp *interp, Tcl_Namespace *nsPtr, bool withKeepvars ) { Tcl_HashTable *varTablePtr, *cmdTablePtr, *childTablePtr; Tcl_HashSearch search; Tcl_Command cmd; register Tcl_HashEntry *entryPtr; nonnull_assert(interp != NULL); nonnull_assert(nsPtr != NULL); /* fprintf(stderr, "DeleteProcsAndVars in %s\n", nsPtr->fullName); */ varTablePtr = (Tcl_HashTable *)Tcl_Namespace_varTablePtr(nsPtr); cmdTablePtr = Tcl_Namespace_cmdTablePtr(nsPtr); childTablePtr = Tcl_Namespace_childTablePtr(nsPtr); /* * Deleting the procs and vars in the child namespaces does not seem to be * necessary, but we do it anyway. */ for (entryPtr = Tcl_FirstHashEntry(childTablePtr, &search); entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { Tcl_Namespace *childNsPtr = (Tcl_Namespace *) Tcl_GetHashValue(entryPtr); DeleteProcsAndVars(interp, childNsPtr, withKeepvars); } if (!withKeepvars) { for (entryPtr = Tcl_FirstHashEntry(varTablePtr, &search); entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { Tcl_Obj *nameObj; Var *varPtr; GetVarAndNameFromHash(entryPtr, &varPtr, &nameObj); if (!TclIsVarUndefined(varPtr) || TclIsVarNamespaceVar(varPtr)) { /* fprintf(stderr, "unsetting var %s\n", ObjStr(nameObj));*/ Tcl_UnsetVar2(interp, ObjStr(nameObj), (char *)NULL, TCL_GLOBAL_ONLY); } } } for (entryPtr = Tcl_FirstHashEntry(cmdTablePtr, &search); entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { cmd = (Tcl_Command)Tcl_GetHashValue(entryPtr); if (Tcl_Command_objProc(cmd) == RUNTIME_STATE(interp)->objInterpProc) { /*fprintf(stderr, "cmdname = %s cmd %p proc %p objProc %p %d\n", Tcl_GetHashKey(cmdTablePtr, entryPtr), cmd, Tcl_Command_proc(cmd), Tcl_Command_objProc(cmd), Tcl_Command_proc(cmd)==RUNTIME_STATE(interp)->objInterpProc);*/ Tcl_DeleteCommandFromToken(interp, cmd); } } } #endif /* *---------------------------------------------------------------------- * * FinalObjectDeletion -- * * The method is to be called, when an object is finally deleted, * which happens typically during the final cleanup. It tests as * well the activation count of the object. * * Results: * None. * * Side effects: * Deletion of the objects. * *---------------------------------------------------------------------- */ static void FinalObjectDeletion( Tcl_Interp *interp, NsfObject *object ) { nonnull_assert(interp != NULL); nonnull_assert(object != NULL); /* * If a call to exit happens from a higher stack frame, the object * refCount might not be decremented correctly. If we are in the * physical destroy round, we can set the counter to an appropriate * value to ensure deletion. */ #if defined(NSF_DEVELOPMENT_TEST) if (unlikely(object->refCount != 1)) { if (object->refCount > 1) { NsfLog(interp, NSF_LOG_WARN, "RefCount for obj %p %d (name %s) > 1", (void *)object, object->refCount, ObjectName_(object)); } else { NsfLog(interp, NSF_LOG_WARN, "Refcount for obj %p %d > 1", (void *)object, object->refCount); } /*object->refCount = 1;*/ } #endif #if !defined(NDEBUG) if (RUNTIME_STATE(interp)->exitHandlerDestroyRound != NSF_EXITHANDLER_ON_PHYSICAL_DESTROY) { assert(object->activationCount == 0); } else if (object->activationCount != 0) { NsfLog(interp, NSF_LOG_WARN, "FinalObjectDeletion obj %p activationcount %d\n", (void *)object, object->activationCount); } #endif if (likely(object->id != NULL)) { /*fprintf(stderr, " ... cmd dealloc %p final delete refCount %d\n", object->id, Tcl_Command_refCount(object->id));*/ if (NSF_DTRACE_OBJECT_FREE_ENABLED()) { NSF_DTRACE_OBJECT_FREE(ObjectName(object), ClassName(object->cl)); } Tcl_DeleteCommandFromToken(interp, object->id); } } #ifdef DO_CLEANUP /* *---------------------------------------------------------------------- * * DeleteNsfProcs -- * * Delete all nsfprocs in the namespaces rooted by the second * argument. If the provided nsPtr is NULL, the global namespace is * used as root of the namespace tree. The function is necessary to * trigger the freeing of the parameter definitions. * * Results: * None. * * Side effects: * Deletion of nsfprocs. * *---------------------------------------------------------------------- */ static void DeleteNsfProcs( Tcl_Interp *interp, Tcl_Namespace *nsPtr ) nonnull(1); static void DeleteNsfProcs( Tcl_Interp *interp, Tcl_Namespace *nsPtr ) { Tcl_HashTable *cmdTablePtr, *childTablePtr; register Tcl_HashEntry *entryPtr; Tcl_HashSearch search; nonnull_assert(interp != NULL); if (nsPtr == NULL) { nsPtr = Tcl_GetGlobalNamespace(interp); } nonnull_assert(nsPtr != NULL); /*fprintf(stderr, "### DeleteNsfProcs current namespace '%s'\n", (nsPtr != NULL) ? nsPtr->fullName : "NULL");*/ cmdTablePtr = Tcl_Namespace_cmdTablePtr(nsPtr); childTablePtr = Tcl_Namespace_childTablePtr(nsPtr); for (entryPtr = Tcl_FirstHashEntry(cmdTablePtr, &search); entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { Tcl_Command cmd = (Tcl_Command)Tcl_GetHashValue(entryPtr); if (Tcl_Command_objProc(cmd) == NsfProcStub) { /*fprintf(stderr, "cmdname = %s cmd %p\n", Tcl_GetHashKey(cmdTablePtr, entryPtr), cmd);*/ Tcl_DeleteCommandFromToken(interp, cmd); } } for (entryPtr = Tcl_FirstHashEntry(childTablePtr, &search); entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { Tcl_Namespace *childNsPtr = (Tcl_Namespace *) Tcl_GetHashValue(entryPtr); DeleteNsfProcs(interp, childNsPtr); } } /* *---------------------------------------------------------------------- * * ClassHasSubclasses -- * * Check, whether the given class has subclasses. * * Results: * A Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool ClassHasSubclasses( const NsfClass *class ) nonnull(1) NSF_pure; static bool ClassHasSubclasses( const NsfClass *class ) { nonnull_assert(class != NULL); return (class->sub != NULL); } /* *---------------------------------------------------------------------- * * ClassHasInstances -- * * Check, whether the given class has instances. * * Results: * A Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool ClassHasInstances( NsfClass *class ) nonnull(1) NSF_pure; static bool ClassHasInstances( NsfClass *class ) { Tcl_HashSearch hSrch; nonnull_assert(class != NULL); return (Tcl_FirstHashEntry(&class->instances, &hSrch) != NULL); } /* *---------------------------------------------------------------------- * * ObjectHasChildren -- * * Check, whether the given object has children. * * Results: * A Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static bool ObjectHasChildren( const NsfObject *object ) nonnull(1) NSF_pure; static bool ObjectHasChildren( const NsfObject *object ) { const Tcl_Namespace *ns; bool result = NSF_FALSE; nonnull_assert(object != NULL); ns = object->nsPtr; if (ns != NULL) { const Tcl_HashEntry *hPtr; Tcl_HashSearch hSrch; Tcl_HashTable *cmdTablePtr = Tcl_Namespace_cmdTablePtr(ns); for (hPtr = Tcl_FirstHashEntry(cmdTablePtr, &hSrch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { Tcl_Command cmd = Tcl_GetHashValue(hPtr); const NsfObject *childObject = NsfGetObjectFromCmdPtr(cmd); if (childObject != NULL) { result = NSF_TRUE; break; } } } return result; } /* *---------------------------------------------------------------------- * * FreeAllNsfObjectsAndClasses -- * * Destroy and free all objects and classes defined in the interp. * * Results: * None. * * Side effects: * Freeing memory. * *---------------------------------------------------------------------- */ static void FreeAllNsfObjectsAndClasses( Tcl_Interp *interp, NsfCmdList **instances ) nonnull(1) nonnull(2); static void FreeAllNsfObjectsAndClasses( Tcl_Interp *interp, NsfCmdList **instances ) { NsfCmdList *entry, *lastEntry; int nrDeleted = 0; nonnull_assert(interp != NULL); nonnull_assert(instances != NULL); /*fprintf(stderr, "FreeAllNsfObjectsAndClasses in %p\n", interp);*/ RUNTIME_STATE(interp)->exitHandlerDestroyRound = NSF_EXITHANDLER_ON_PHYSICAL_DESTROY; /* * First delete all child commands of all objects, which are not * objects themselves. This will for example delete namespace * imported commands and objects and will resolve potential loops in * the dependency graph. The result is a plain object/class tree. */ for (entry = *instances; entry != NULL; entry = entry->nextPtr) { NsfObject *object = (NsfObject *)entry->clorobj; /* * Delete per-object methods. */ if (object != NULL && object->nsPtr != NULL) { const Tcl_HashEntry *hPtr; Tcl_HashSearch hSrch; for (hPtr = Tcl_FirstHashEntry(Tcl_Namespace_cmdTablePtr(object->nsPtr), &hSrch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { Tcl_Command cmd = Tcl_GetHashValue(hPtr); if (cmd != NULL) { if (CmdIsNsfObject(cmd)) { AliasDeleteObjectReference(interp, cmd); continue; } Tcl_DeleteCommandFromToken(interp, cmd); nrDeleted ++; } } } /* * Delete class methods; these methods might have aliases (dependencies) to * objects, which will be resolved this way. */ if (object != NULL && NsfObjectIsClass(object)) { const Tcl_HashEntry *hPtr; Tcl_HashSearch hSrch; for (hPtr = Tcl_FirstHashEntry(Tcl_Namespace_cmdTablePtr(((NsfClass *)object)->nsPtr), &hSrch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { Tcl_Command cmd = Tcl_GetHashValue(hPtr); if ((cmd != NULL) && CmdIsNsfObject(cmd)) { AliasDeleteObjectReference(interp, cmd); continue; } } } } /*fprintf(stderr, "deleted %d cmds\n", nrDeleted);*/ /* * Finally delete the object/class tree in a bottom up manner, * deleting all objects without dependencies first. Finally, only * the root-classes of the object system will remain, which are * deleted separately. */ while (1) { /* * Delete all plain objects without dependencies. */ nrDeleted = 0; for (entry = *instances, lastEntry = NULL; entry != NULL; lastEntry = entry, entry = entry->nextPtr) { NsfObject *object = (NsfObject *)entry->clorobj; /* * The list of the instances should contain only alive objects, without * duplicates. We would recognize duplicates since a deletion of one * object would result in the CMD_DYING (previously, CMD_IS_DELETED) * flag becoming set on the cmdPtr of the duplicate. */ assert(!TclIsCommandDeleted(entry->cmdPtr)); if (object != NULL && !NsfObjectIsClass(object) && !ObjectHasChildren(object)) { /*fprintf(stderr, "check %p obj->flags %.6x cmd %p deleted %d\n", object, object->flags, entry->cmdPtr, TclIsCommandDeleted(entry->cmdPtr)); */ assert(object->id != NULL); /*fprintf(stderr, " ... delete object %s %p, class=%s id %p ns %p\n", ObjectName(object), object, ClassName(object->cl), object->id, object->nsPtr);*/ FreeUnsetTraceVariable(interp, object); FinalObjectDeletion(interp, object); if (entry == *instances) { *instances = entry->nextPtr; CmdListDeleteCmdListEntry(entry, NULL); entry = *instances; } else { lastEntry->nextPtr = entry->nextPtr; CmdListDeleteCmdListEntry(entry, NULL); entry = lastEntry; } assert(entry != NULL); nrDeleted++; } } /*fprintf(stderr, "deleted %d Objects without dependencies\n", nrDeleted);*/ if (nrDeleted > 0) { continue; } /* * Delete all classes without dependencies. */ for (entry = *instances, lastEntry = NULL; entry != NULL; (entry != NULL ? (lastEntry = entry, entry = entry->nextPtr) : NULL)) { NsfClass *class = entry->clorobj; assert(class != NULL); if (!NsfObjectIsClass(&class->object)) { continue; } /*fprintf(stderr, "### cl key = %s %p\n", ClassName(class), class); */ /* * Remove manually mixinRegObjs to achieve correct deletion * order. Otherwise, refcount checking for NsfObjects complains during * shutdown (and dangling references would be a consequence). */ if (class->opt != NULL && class->opt->mixinRegObjs != NULL) { NsfMixinregInvalidate(interp, class->opt->mixinRegObjs); DECR_REF_COUNT2("mixinRegObjs", class->opt->mixinRegObjs); class->opt->mixinRegObjs = NULL; } if (!ObjectHasChildren((NsfObject *)class) && !ClassHasInstances(class) && !ClassHasSubclasses(class) && !IsBaseClass(&class->object) ) { /*fprintf(stderr, " ... delete class %s %p\n", ClassName(class), class); */ assert(class->object.id); FreeUnsetTraceVariable(interp, &class->object); FinalObjectDeletion(interp, &class->object); if (entry == *instances) { *instances = entry->nextPtr; /*fprintf(stderr, "... delete first entry %p\n", entry);*/ CmdListDeleteCmdListEntry(entry, NULL); entry = *instances; } else { /*fprintf(stderr, "... delete entry %p\n", entry);*/ lastEntry->nextPtr = entry->nextPtr; CmdListDeleteCmdListEntry(entry, NULL); entry = lastEntry; } nrDeleted++; } } /*fprintf(stderr, "deleted %d Classes\n", nrDeleted);*/ if (nrDeleted == 0) { int nrReclassed = 0; /* * Final check. If there are no cyclical dependencies, we should have * now just the base classes left. If this is not the case, reclass * the remaining objects to their base classes, and set the superClasses * to the most general superclass. */ for (entry = *instances; entry != NULL; entry = entry->nextPtr) { NsfObject *object = (NsfObject *)entry->clorobj; NsfClass *baseClass; NsfObjectSystem *osPtr; if (NsfObjectIsClass(object) && IsBaseClass(object)) { continue; } osPtr = GetObjectSystem(object); /* * For classes, check the superclass hierarchy. */ if (NsfObjectIsClass(object)) { NsfClass *cl = (NsfClass *)object; NsfClasses *sc; for (sc = cl->super; sc != NULL; sc = sc->nextPtr) { if (sc->cl != osPtr->rootClass) { Tcl_Obj *objectName = osPtr->rootClass->object.cmdName; SuperclassAdd(interp, cl, 1, &objectName, objectName); nrReclassed ++; break; } } } /* * In all cases, straighten the class to the base case. */ baseClass = NsfObjectIsClass(object) ? osPtr->rootMetaClass : osPtr->rootClass; if (object->cl != baseClass) { ChangeClass(interp, object, baseClass); nrReclassed ++; } } /*fprintf(stderr, "We have reclassed %d objects\n", nrReclassed);*/ if (nrReclassed == 0) { break; } } } } #endif /* DO_CLEANUP */ /* *---------------------------------------------------------------------- * * ExitHandler -- * * The exit handler is called on thread exit and application * exit. It is responsible to free all resources to avoid memory * leaks, especially in multi-threaded applications, when threads * exit. * * Results: * None. * * Side effects: * Freeing memory. * *---------------------------------------------------------------------- */ static void ExitHandler(ClientData clientData) { Tcl_Interp *interp = (Tcl_Interp *)clientData; int flags; NsfRuntimeState *rst; nonnull_assert(clientData != NULL); rst = RUNTIME_STATE(interp); /*fprintf(stderr, "+++ (%lx) ExitHandler interp %p deleted %d exitHandlerDestroyRound %d\n", (long)(void*)pthread_self(), interp, (Tcl_Interp_flags(interp) & DELETED), rst->exitHandlerDestroyRound);*/ /* * Don't use exit handler, if the interpreter is already destroyed. * Call to exit handler comes after freeing namespaces, commands, etc. * e.g. TK calls Tcl_DeleteInterp directly, if Window is killed. */ /* * Ahem ... * * Since we *must* be sure that our destroy methods will run * we must *cheat* (I mean CHEAT) here: we flip the interp * flag, saying, "hey boy, you're not deleted any more". * After our handlers are done, we restore the old state... * All this is needed so we can do an eval in the interp which * is potentially marked for delete when we start working here. * * I know, I know, this is not really elegant. But... I'd need a * standard way of invoking some code at interpreter delete time * but JUST BEFORE the actual deletion process starts. Sadly, * there is no such hook in Tcl as of Tcl8.4.*, that I know of. * * So, for the rest of procedure, assume the interp is alive ! */ flags = Tcl_Interp_flags(interp); Tcl_Interp_flags(interp) &= ~DELETED; CallStackPopAll(interp); #if defined(NSF_MEM_COUNT) /* The Tcl history list (which internally stores commands and scripts in the * array ::tcl::history) can retain Tcl_Obj references beyond the scope of * our shutdown procedures (::nsf::finalize, ExitHandler). Therefore, on * MEM_COUNT_RELEASE(), we might see unbalanced refcounts which are false * positives. Therefore, we aim at clearing the history list at this point. * * See also Tcl bug report 1ae12987cb. */ if (unlikely(Tcl_Eval(interp, "::history clear") != TCL_OK)) { NsfLog(interp, NSF_LOG_WARN, "Clearing the Tcl history list failed! " "Memcounts could be reported as unbalanced on MEM_COUNT_RELEASE(). " "Error: %s\n", ObjStr(Tcl_GetObjResult(interp))); } #endif if (rst->exitHandlerDestroyRound == NSF_EXITHANDLER_OFF) { NsfFinalizeCmd(interp, NSF_FALSE); } /* * Must be before freeing of NsfGlobalObjs. */ NsfShadowTclCommands(interp, SHADOW_UNLOAD); MEM_COUNT_FREE("Tcl_InitHashTable", &rst->activeFilterTablePtr); Tcl_DeleteHashTable(&rst->activeFilterTablePtr); /* * Free "global" (per main interp) objects. */ { int i; for (i = 0; i < nr_elements(NsfGlobalStrings); i++) { DECR_REF_COUNT(NsfGlobalObjs[i]); } } NsfStringIncrFree(&rst->iss); /* * Free all data in the hash tables managing pointer converters, * enumerations, and method definitions. */ Nsf_PointerExit(interp); Nsf_EnumerationTypeRelease(); Nsf_CmdDefinitionRelease(); #if defined(NSF_PROFILE) NsfProfileFree(interp); #endif FREE(Tcl_Obj**, NsfGlobalObjs); #if defined(TCL_MEM_DEBUG) TclDumpMemoryInfo((ClientData) stderr, 0); Tcl_DumpActiveMemory("./nsfActiveMem"); /* Tcl_Eval(interp, "puts {checkmem to checkmemFile}; checkmem checkmemFile"); */ #endif /* * Free run time state. */ /*fprintf(stderr, "+++ ExiHandler frees run time state of interp %p\n", interp);*/ ckfree((char *) rst); #if defined(USE_ASSOC_DATA) Tcl_DeleteAssocData(interp, "NsfRuntimeState"); #else Tcl_Interp_globalNsPtr(interp)->clientData = NULL; #endif #if defined(NSF_MEM_COUNT) && !defined(PRE86) /* * When raising an error, the Tcl_Objs on the error stack and in the * inner context are refCount-incremented. When Tcl exits, it does normally * not perform the according decrementing. We perform here a manual * decrementing and reset these lists. */ { Interp *iPtr = (Interp *) interp; if (iPtr->innerContext != NULL) { Tcl_DecrRefCount(iPtr->errorStack); iPtr->errorStack = Tcl_NewListObj(0, NULL); Tcl_IncrRefCount(iPtr->errorStack); Tcl_DecrRefCount(iPtr->innerContext); iPtr->innerContext = Tcl_NewListObj(0, NULL); Tcl_IncrRefCount(iPtr->innerContext); } } #endif Tcl_Interp_flags(interp) = flags; Tcl_Release(interp); MEM_COUNT_RELEASE(); } #if defined(TCL_THREADS) /* * Gets activated at thread-exit */ static void Nsf_ThreadExitProc(ClientData clientData) { nonnull_assert(clientData != NULL); /*fprintf(stderr, "+++ (%lx) Nsf_ThreadExitProc %p\n", (long)(void*)pthread_self(), clientData);*/ Tcl_DeleteThreadExitHandler(Nsf_ThreadExitProc, clientData); Tcl_DeleteExitHandler(Nsf_ExitProc, clientData); ExitHandler(clientData); } #endif /* * Gets activated at application-exit */ static void Nsf_ExitProc(ClientData clientData) { nonnull_assert(clientData != NULL); /*fprintf(stderr, "+++ (%lx) Nsf_ExitProc %p\n", (long)(void*)pthread_self(), clientData);*/ #if defined(TCL_THREADS) Tcl_DeleteExitHandler(Nsf_ExitProc, clientData); Tcl_DeleteThreadExitHandler(Nsf_ThreadExitProc, clientData); #endif ExitHandler(clientData); } /* * Registers thread/application exit handlers. */ static void RegisterExitHandlers(ClientData clientData) nonnull(1); static void RegisterExitHandlers(ClientData clientData) { nonnull_assert(clientData != NULL); Tcl_Preserve(clientData); #if defined(TCL_THREADS) Tcl_CreateThreadExitHandler(Nsf_ThreadExitProc, clientData); #endif Tcl_CreateExitHandler(Nsf_ExitProc, clientData); } /* * Tcl extension initialization routine */ #if 0 #include #endif int Nsf_Init( Tcl_Interp *interp ) { static NsfMutex initMutex = 0; ClientData runtimeState; NsfRuntimeState *rst; int result, i; Tcl_Obj *tmpObj; #ifdef NSF_BYTECODE /*NsfCompEnv *interpstructions = NsfGetCompEnv();*/ #endif #ifdef USE_TCL_STUBS static int stubsInitialized = 0; #endif nonnull_assert(interp != NULL); #if 0 ProfilerStart("profiler"); #endif #ifdef USE_TCL_STUBS /* * Since the stub-tables are initialized globally (not per interp), we want * to initialize these only once. The read operation on "stubsInitialized" * is a potentially dirty read. However, we can't use a mutex lock around * this, since Tcl_MutexLock() requires (at least on some platforms) * initialized stub-tables. The dirty read of stubsInitialized is not so * invasive as the dirty reads caused by overwriting the stub tables. * * NsfMutexLock(&stubFlagMutex); * ... * NsfMutexUnlock(&stubFlagMutex); */ if (stubsInitialized == 0) { if (Tcl_InitStubs(interp, "8.5", 0) == NULL) { return TCL_ERROR; } # if TCL_MAJOR_VERSION > 8 || TCL_MINOR_VERSION > 6 /* Tcl_TomMath_InitStubs() not needed */ # else if (Tcl_TomMath_InitStubs(interp, "8.5") == NULL) { return TCL_ERROR; } # endif stubsInitialized = 1; } #endif #if defined(TCL_MEM_DEBUG) TclDumpMemoryInfo((ClientData) stderr, 0); #endif /* * Runtime State stored in the client data of the Interp's global namespace * in order to avoid global state information. All fields are per default * set to zero. */ runtimeState = ckalloc((int)sizeof(NsfRuntimeState)); memset(runtimeState, 0, sizeof(NsfRuntimeState)); #if defined(USE_ASSOC_DATA) Tcl_SetAssocData(interp, "NsfRuntimeState", NULL, runtimeState); #else Tcl_Interp_globalNsPtr(interp)->clientData = runtimeState; #endif /* * If MEM_COUNT is activated, the tables have to be initialized before the * first call to the MEM_COUNT macros (including e.g. INCR_REF_COUNT), but * it requires that the runtimeState is already associated with the interp. */ MEM_COUNT_INIT(); /* * Init global variables for Tcl_Obj types. */ NsfMutexLock(&initMutex); Nsf_OT_byteCodeType = Tcl_GetObjType("bytecode"); assert(Nsf_OT_byteCodeType != NULL); Nsf_OT_tclCmdNameType = Tcl_GetObjType("cmdName"); assert(Nsf_OT_tclCmdNameType != NULL); Nsf_OT_listType = Tcl_GetObjType("list"); assert(Nsf_OT_listType != NULL); Nsf_OT_doubleType = Tcl_GetObjType("double"); assert(Nsf_OT_doubleType != NULL); /* * Type "int" and "wideInt" are a moving target in Tcl 8.7a+. So, get the * type from the Tcl_Obj directly, which will continue to work. */ tmpObj = Tcl_NewIntObj(0); Nsf_OT_intType = tmpObj->typePtr; Tcl_DecrRefCount(tmpObj); assert(Nsf_OT_intType != NULL); { mp_int bignumValue; Tcl_Obj *bigNumObj; tmpObj = Tcl_NewStringObj("10000000000000000000000", TCL_INDEX_NONE); Tcl_GetBignumFromObj(NULL, tmpObj, &bignumValue); Nsf_OT_bignumType = tmpObj->typePtr; assert(Nsf_OT_bignumType != NULL); /* Make sure mp_int is actually cleared (w/o using mp_clear). */ bigNumObj = Tcl_NewBignumObj(&bignumValue); Tcl_DecrRefCount(bigNumObj); Tcl_DecrRefCount(tmpObj); } /* * Get bytearray and proper bytearray from Tcl (latter if available, * introduced in Tcl 8.7a+) */ Nsf_OT_byteArrayType = Tcl_GetObjType("bytearray"); tmpObj = Tcl_NewByteArrayObj(NULL, 0); Nsf_OT_properByteArrayType = tmpObj->typePtr; if (Nsf_OT_byteArrayType == NULL) { Nsf_OT_byteArrayType = Nsf_OT_properByteArrayType; } if (Nsf_OT_properByteArrayType == Nsf_OT_byteArrayType) { /* * When both values are the same, we are in a Tcl version before 8.7, * where we have no properByteArrayTypePtr. So set it to an invalid * value to avoid potential confusions. Without this stunt, we would * need several ifdefs. */ Nsf_OT_properByteArrayType = (Tcl_ObjType *)0xffffff; } Tcl_DecrRefCount(tmpObj); assert(Nsf_OT_properByteArrayType != NULL); assert(Nsf_OT_byteArrayType != NULL); NsfMutexUnlock(&initMutex); /* * Initialize the pointer converter, the enumeration types and cmd * definitions tables and load it with the generated information for * introspection. */ Nsf_PointerInit(); Nsf_EnumerationTypeInit(); result = Nsf_EnumerationTypeRegister(interp, enumeratorConverterEntries); if (unlikely(result != TCL_OK)) { return result; } Nsf_CmdDefinitionInit(); Nsf_CmdDefinitionRegister(interp, method_definitions); /* fprintf(stderr, "SIZES: obj=%d, tcl_obj=%d, DString=%d, class=%d, namespace=%d, command=%d, HashTable=%d\n", sizeof(NsfObject), sizeof(Tcl_Obj), sizeof(Tcl_DString), sizeof(NsfClass), sizeof(Namespace), sizeof(Command), sizeof(Tcl_HashTable)); */ #if defined(NSF_PROFILE) NsfProfileInit(interp); #endif rst = RUNTIME_STATE(interp); rst->logSeverity = NSF_LOG_NOTICE; rst->doFilters = 1; rst->doCheckResults = 1; rst->doCheckArguments = NSF_ARGPARSE_CHECK; NsfDListInit(&rst->freeDList); #if defined(NSF_STACKCHECK) { int someVar; /* * Note that Nsf_Init() is called typically via a package require, which * is therefore not really the bottom of the stack, but just a first * approximation. */ rst->bottomOfStack = &someVar; rst->maxStack = rst->bottomOfStack; } #endif /* * Check whether the namespace exists, otherwise create it. */ rst->NsfNS = Tcl_FindNamespace(interp, "::nsf", NULL, TCL_GLOBAL_ONLY); if (rst->NsfNS == NULL) { rst->NsfNS = Tcl_CreateNamespace(interp, "::nsf", NULL, (Tcl_NamespaceDeleteProc *)NULL); } MEM_COUNT_ALLOC("TclNamespace", rst->NsfNS); /* * Init an empty, faked proc structure in the RUNTIME state. */ rst->fakeProc.iPtr = (Interp *)interp; rst->fakeProc.refCount = 1; rst->fakeProc.cmdPtr = NULL; rst->fakeProc.bodyPtr = NULL; rst->fakeProc.numArgs = 0; rst->fakeProc.numCompiledLocals = 0; rst->fakeProc.firstLocalPtr = NULL; rst->fakeProc.lastLocalPtr = NULL; /* * NsfClasses in separate Namespace / Objects */ rst->NsfClassesNS = Tcl_CreateNamespace(interp, nsfClassesPrefix, NULL, (Tcl_NamespaceDeleteProc *)NULL); #if !defined(PRE86) ((Namespace *)rst->NsfClassesNS)->flags |= NS_SUPPRESS_COMPILATION; #endif MEM_COUNT_ALLOC("TclNamespace", rst->NsfClassesNS); /* * Cache interpreters proc interpretation functions */ rst->objInterpProc = TclGetObjInterpProc(); rst->exitHandlerDestroyRound = NSF_EXITHANDLER_OFF; RegisterExitHandlers(interp); NsfStringIncrInit(&RUNTIME_STATE(interp)->iss); /* * initialize global Tcl_Obj */ NsfGlobalObjs = NEW_ARRAY(Tcl_Obj*, nr_elements(NsfGlobalStrings)); for (i = 0; i < nr_elements(NsfGlobalStrings); i++) { NsfGlobalObjs[i] = Tcl_NewStringObj(NsfGlobalStrings[i], TCL_INDEX_NONE); INCR_REF_COUNT(NsfGlobalObjs[i]); } Tcl_InitHashTable(&rst->activeFilterTablePtr, TCL_STRING_KEYS); MEM_COUNT_ALLOC("Tcl_InitHashTable", &rst->activeFilterTablePtr); /* * Create namespaces for the different command types. */ Tcl_CreateNamespace(interp, "::nsf::cmd", 0, (Tcl_NamespaceDeleteProc *)NULL); for (i = 0; i < nr_elements(method_command_namespace_names); i++) { Tcl_CreateNamespace(interp, method_command_namespace_names[i], 0, (Tcl_NamespaceDeleteProc *)NULL); } /* * Create all method commands (will use the namespaces above). */ for (i = 0; i < nr_elements(method_definitions)-1; i++) { Tcl_CreateObjCommand(interp, method_definitions[i].methodName, method_definitions[i].proc, 0, 0); } /* * Create Shadowed Tcl cmds: */ result = NsfShadowTclCommands(interp, SHADOW_LOAD); if (unlikely(result != TCL_OK)) { return result; } /* * Create new Tcl cmds: */ #ifdef NSF_BYTECODE instructions[INST_NEXT].cmdPtr = (Command *) #endif Tcl_CreateObjCommand(interp, "::nsf::xotclnext", NsfNextObjCmd, 0, 0); #ifdef NSF_BYTECODE instructions[INST_SELF].cmdPtr = (Command *)Tcl_FindCommand(interp, "::nsf::current", NULL, TCL_GLOBAL_ONLY); #endif /*Tcl_CreateObjCommand(interp, "::nsf::K", NsfKObjCmd, 0, 0);*/ #ifdef NSF_BYTECODE NsfBytecodeInit(); #endif NsfInitPkgConfig(interp); Tcl_AddInterpResolvers(interp, "nsf", (Tcl_ResolveCmdProc *)InterpColonCmdResolver, InterpColonVarResolver, (Tcl_ResolveCompiledVarProc *)InterpCompiledColonVarResolver); rst->colonCmd = Tcl_FindCommand(interp, "::nsf::colon", NULL, TCL_GLOBAL_ONLY); /* * Tcl occasionally resolves a proc's cmd structure (e.g., in * [info frame /number/] or TclInfoFrame()) without * verification. However, NSF non-proc frames, in particular * initcmd blocks, point to the fakeProc structure which does not * contain an initialized Command pointer. For now, we default to * an internal command. However, we might have to revisit this decision * as non-proc frames (e.g., initcmds) report a "proc" entry * for c-based functions with a proc scope, such as "::nsf::colon"), * which can lead to confusions. "proc" does not mean "tcp proc", * but an entry with a proc frame for local vars. */ rst->fakeProc.cmdPtr = (Command *)RUNTIME_STATE(interp)->colonCmd; { /* * The file "predefined.h" contains some methods and library procs * implemented in Tcl - they could go in .tcl file, but they are embedded * here with Tcl_Eval to avoid the need to carry around a separate file at * run time. */ #include "predefined.h" /* fprintf(stderr, "predefined=<<%s>>\n", cmd);*/ if ( (Tcl_Eval(interp, predefined_part1) != TCL_OK) || (Tcl_Eval(interp, predefined_part2) != TCL_OK) ) { static char reportingCmd[] = "puts stderr \"Error in predefined code\n\ $::errorInfo\""; Tcl_EvalEx(interp, reportingCmd, TCL_INDEX_NONE, 0); return TCL_ERROR; } } #ifndef AOL_SERVER /* * The AOL server uses a different package loading mechanism. */ # ifdef COMPILE_NSF_STUBS Tcl_PkgProvideEx(interp, "nsf", PACKAGE_VERSION, &nsfStubs); # else Tcl_PkgProvide(interp, "nsf", PACKAGE_VERSION); # endif #endif /* * Obtain type for parsed var name. */ if (Nsf_OT_parsedVarNameType == NULL) { Tcl_Obj *varNameObj = Tcl_NewStringObj("::nsf::version", TCL_INDEX_NONE); Var *arrayPtr; INCR_REF_COUNT(varNameObj); TclObjLookupVar(interp, varNameObj, NULL, 0, "access", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); Nsf_OT_parsedVarNameType = varNameObj->typePtr; assert(Nsf_OT_parsedVarNameType != NULL); DECR_REF_COUNT(varNameObj); } #if !defined(TCL_THREADS) if ((Tcl_GetVar2(interp, "tcl_platform", "threaded", TCL_GLOBAL_ONLY) != NULL)) { /* * A non-threaded version of NSF is loaded into a threaded environment. */ fprintf(stderr, "\n A non threaded version of the Next Scripting Framework " "is loaded into threaded environment.\n" "Please reconfigure nsf with --enable-threads!\n\n\n"); } #endif Tcl_ResetResult(interp); Tcl_SetIntObj(Tcl_GetObjResult(interp), 1); return TCL_OK; } EXTERN int Nsf_SafeInit(Tcl_Interp *interp) { nonnull_assert(interp != NULL); /*** dummy for now **/ return Nsf_Init(interp); } /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * eval: (c-guess) * End: */ ./nsf2.4.0/generic/nsfAPI.decls000644 000766 000024 00000054362 14260520562 016754 0ustar00neumannstaff000000 000000 # -*- Tcl -*- # # nsfAPI.decls -- # # Public functions and Tcl commands offered by the Next # Scripting Framework (NSF) library. This script is sourced by # the C-code generator gentclAPI.tcl in the same directory. # # Copyright (C) 2009-2017 Gustaf Neumann # # Vienna University of Economics and Business # Institute of Information Systems and New Media # A-1020, Welthandelsplatz 1 # Vienna, Austria # # This work is licensed under the MIT License https://www.opensource.org/licenses/MIT # # Copyright: # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. # # namespaces for types of methods array set ns { cmd "::nsf" objectMethod "::nsf::methods::object" objectInfoMethod "::nsf::methods::object::info" classMethod "::nsf::methods::class" classInfoMethod "::nsf::methods::class::info" } # # Next Scripting commands # cmd __db_compile_epoch NsfDebugCompileEpoch {} cmd __db_run_assertions NsfDebugRunAssertionsCmd {} cmd __db_show_stack NsfShowStackCmd {} cmd __db_show_obj NsfDebugShowObj { {-argName "obj" -required 1 -type tclobj} } cmd __db_get_obj NsfDebugGetDict { {-argName "obj" -required 1 -type tclobj} } cmd __profile_clear NsfProfileClearDataStub {} cmd __profile_get NsfProfileGetDataStub {} cmd __profile_trace NsfProfileTraceStub { {-argName "-enable" -required 1 -nrargs 1 -type boolean} {-argName "-verbose" -required 0 -nrargs 1 -type boolean} {-argName "-dontsave" -required 0 -nrargs 1 -type boolean} {-argName "-builtins" -required 0 -nrargs 1 -type tclobj} } # # valgrind/callgrind support # cmd __callgrind_dump_stats NsfCallgrindDumpStatsCmd { {-argName "-name" -required 0 -nrargs 1} } cmd __callgrind_start_instrumentation NsfCallgrindStartInstrumentationCmd {} cmd __callgrind_stop_instrumentation NsfCallgrindStopInstrumentationCmd {} cmd __callgrind_toggle_collect NsfCallgrindToggleCollectCmd {} cmd __callgrind_zero_stats NsfCallgrindZeroStatsCmd {} cmd __unset_unknown_args NsfUnsetUnknownArgsCmd {} cmd "asm::proc" NsfAsmProcCmd { {-argName "-ad" -required 0 -nrargs 0 -type switch} {-argName "-checkalways" -required 0 -nrargs 0 -type switch} {-argName "procName" -required 1 -type tclobj} {-argName "arguments" -required 1 -type tclobj} {-argName "body" -required 1 -type tclobj} } cmd configure NsfConfigureCmd { {-argName "option" -required 1 -typeName "configureoption" -type "debug|dtrace|filter|softrecreate|objectsystems|keepcmds|checkresults|checkarguments" -global 1} {-argName "value" -required 0 -type tclobj} } {-nxdoc 1} cmd colon NsfColonCmd { {-argName "args" -type allargs} } cmd "definitionnamespace" NsfDefinitionNamespaceCmd { } cmd "directdispatch" NsfDirectDispatchCmd { {-argName "object" -required 1 -type object} {-argName "-frame" -typeName "frame" -required 0 -type "method|object|default" -default "default"} {-argName "command" -required 1 -type tclobj} {-argName "args" -type args} } cmd "dispatch" NsfDispatchCmd { {-argName "object" -required 1 -type object} {-argName "-intrinsic" -required 0 -nrargs 0 -type switch} {-argName "-system" -required 0 -nrargs 0 -type switch} {-argName "command" -required 1 -type tclobj} {-argName "args" -type args} } {-nxdoc 1} cmd finalize NsfFinalizeCmd { {-argName "-keepvars" -required 0 -nrargs 0 -type switch} } {-nxdoc 1} cmd interp NsfInterpObjCmd { {-argName "name" -required 1} {-argName "args" -type allargs} } {-nxdoc 1} cmd is NsfIsCmd { {-argName "-complain" -nrargs 0 -type switch} {-argName "-configure" -nrargs 0 -type switch} {-argName "-name" -required 0} {-argName "constraint" -required 1 -type tclobj} {-argName "value" -required 1 -type tclobj} } {-nxdoc 1} cmd parameter::info NsfParameterInfoCmd { {-argName "subcmd" -typeName "parametersubcmd" -type "default|list|name|syntax|type" -required 1} {-argName "spec" -required 1 -type tclobj} {-argName "varname" -required 0 -type tclobj} } cmd parameter::cache::classinvalidate NsfParameterCacheClassInvalidateCmd { {-argName "class" -required 1 -type class} } cmd parameter::cache::objectinvalidate NsfParameterCacheObjectInvalidateCmd { {-argName "object" -required 1 -type object} } cmd parameter::specs NsfParameterSpecsCmd { {-argName "-configure" -nrargs 0 -required 0 -type switch} {-argName "-nonposargs" -nrargs 0 -required 0 -type switch} {-argName "slotobjs" -required 1 -type tclobj} } cmd parseargs NsfParseArgsCmd { {-argName "-asdict" -nrargs 0 -required 0 -type switch} {-argName "argspec" -required 1 -type tclobj} {-argName "arglist" -required 1 -type tclobj} } {-nxdoc 0} # # cmd cmds (maybe more later) # cmd "cmd::info" NsfCmdInfoCmd { {-argName "subcmd" -required 1 -typeName "methodgetcmd" -type "args|body|definition|exists|registrationhandle|definitionhandle|origin|parameter|syntax|type|precondition|postcondition|submethods|returns|disassemble"} {-argName "-context" -required 0 -type object} {-argName "methodName" -required 1 -type tclobj} {-argName "pattern" -required 0} } {-nxdoc 1} # # method cmds # cmd "method::alias" NsfMethodAliasCmd { {-argName "object" -required 1 -type object} {-argName "-per-object" -required 0 -nrargs 0 -type switch} {-argName "methodName" -required 1} {-argName "-frame" -required 0 -typeName "frame" -type "method|object|default" -default "default"} {-argName "-protection" -required 0 -typeName "protection" -type "call-protected|redefine-protected|none" -default "none"} {-argName "cmdName" -required 1 -type tclobj} } {-nxdoc 1} cmd "method::assertion" NsfMethodAssertionCmd { {-argName "object" -required 1 -type object} {-argName "subcmd" -required 1 -typeName "assertionsubcmd" -type "check|object-invar|class-invar"} {-argName "arg" -required 0 -type tclobj} } {-nxdoc 1} cmd "method::asmcreate" NsfAsmMethodCreateCmd { {-argName "object" -required 1 -type object} {-argName "-checkalways" -required 0 -nrargs 0 -type switch} {-argName "-inner-namespace" -nrargs 0 -type switch} {-argName "-per-object" -required 0 -nrargs 0 -type switch} {-argName "-reg-object" -required 0 -nrargs 1 -type object} {-argName "methodName" -required 1 -type tclobj} {-argName "arguments" -required 1 -type tclobj} {-argName "body" -required 1 -type tclobj} } cmd "method::create" NsfMethodCreateCmd { {-argName "object" -required 1 -type object} {-argName "-checkalways" -required 0 -nrargs 0 -type switch} {-argName "-inner-namespace" -nrargs 0 -type switch} {-argName "-per-object" -required 0 -nrargs 0 -type switch} {-argName "-reg-object" -required 0 -type object} {-argName "methodName" -required 1 -type tclobj} {-argName "arguments" -required 1 -type tclobj} {-argName "body" -required 1 -type tclobj} {-argName "-precondition" -type tclobj} {-argName "-postcondition" -type tclobj} } {-nxdoc 1} cmd "method::delete" NsfMethodDeleteCmd { {-argName "object" -required 1 -type object} {-argName "-per-object" -required 0 -nrargs 0 -type switch} {-argName "methodName" -required 1 -type tclobj} } {-nxdoc 1} cmd "method::forward" NsfMethodForwardCmd { {-argName "object" -required 1 -type object} {-argName "-per-object" -required 0 -nrargs 0 -type switch} {-argName "method" -required 1 -type tclobj} {-argName "-default" -type tclobj} {-argName "-earlybinding" -nrargs 0 -type switch} {-argName "-onerror" -type tclobj} {-argName "-prefix" -type tclobj} {-argName "-frame" -nrargs 1 -typeName "frame" -type "method|object|default" -default default} {-argName "-verbose" -nrargs 0 -type switch} {-argName "target" -type tclobj} {-argName "args" -type args} } {-nxdoc 1} cmd "method::forward::property" NsfForwardPropertyCmd { {-argName "object" -required 1 -type object} {-argName "-per-object" -required 0 -nrargs 0 -type switch} {-argName "methodName" -required 1 -type tclobj} {-argName "forwardProperty" -required 1 -type "prefix|target|verbose"} {-argName "value" -type tclobj} } cmd "method::property" NsfMethodPropertyCmd { {-argName "object" -required 1 -type object} {-argName "-per-object" -required 0 -nrargs 0 -type switch} {-argName "methodName" -required 1 -type tclobj} {-argName "methodProperty" -required 1 -type "class-only|call-private|call-protected|debug|deprecated|exists|redefine-protected|returns"} {-argName "value" -type tclobj} } {-nxdoc 1} cmd "method::registered" NsfMethodRegisteredCmd { {-argName "handle" -required 1 -type tclobj} } {-nxdoc 1} cmd "method::setter" NsfMethodSetterCmd { {-argName "object" -required 1 -type object} {-argName "-per-object" -required 0 -nrargs 0 -type switch} {-argName "parameter" -required 1 -type tclobj} } {-nxdoc 1} # # object cmds # cmd "object::alloc" NsfObjectAllocCmd { {-argName "class" -required 1 -type class} {-argName "name" -required 1 -type tclobj} {-argName "initcmd" -required 0 -type tclobj} } cmd "object::exists" NsfObjectExistsCmd { {-argName "value" -required 1 -type tclobj} } {-nxdoc 1} cmd "object::property" NsfObjectPropertyCmd { {-argName "object" -required 1 -type object} {-argName "objectProperty" -type "initialized|class|rootmetaclass|rootclass|volatile|autonamed|slotcontainer|hasperobjectslots|keepcallerself|perobjectdispatch" -required 1} {-argName "value" -required 0 -type tclobj} } {-nxdoc 1} cmd "object::qualify" NsfObjectQualifyCmd { {-argName "objectName" -required 1 -type tclobj} } {-nxdoc 1} # # objectsystem cmds # cmd "objectsystem::create" NsfObjectSystemCreateCmd { {-argName "rootClass" -required 1 -type tclobj} {-argName "rootMetaClass" -required 1 -type tclobj} {-argName "systemMethods" -required 0 -type tclobj} } {-nxdoc 1} cmd my NsfMyCmd { {-argName "-intrinsic" -nrargs 0 -type switch} {-argName "-local" -nrargs 0 -type switch} {-argName "-system" -nrargs 0 -type switch} {-argName "methodName" -required 1 -type tclobj} {-argName "args" -type args} } {-nxdoc 1} cmd next NsfNextCmd { {-argName "arguments" -required 0 -type tclobj} } {-nxdoc 1} cmd nscopyvars NsfNSCopyVarsCmd { {-argName "fromNs" -required 1 -type tclobj} {-argName "toNs" -required 1 -type tclobj} } cmd proc NsfProcCmd { {-argName "-ad" -required 0 -nrargs 0 -type switch} {-argName "-checkalways" -required 0 -nrargs 0 -type switch} {-argName "-debug" -required 0 -nrargs 0 -type switch} {-argName "-deprecated" -required 0 -nrargs 0 -type switch} {-argName "procName" -required 1 -type tclobj} {-argName "arguments" -required 1 -type tclobj} {-argName "body" -required 1 -type tclobj} } {-nxdoc 1} cmd relation::get NsfRelationGetCmd { {-argName "object" -required 1 -type object} {-argName "type" -required 1 -typeName "relationtype" -type "object-mixin|class-mixin|object-filter|class-filter|class|superclass|rootclass"} } {-nxdoc 1} cmd relation::set NsfRelationSetCmd { {-argName "object" -required 1 -type object} {-argName "type" -required 1 -typeName "relationtype" -type "object-mixin|class-mixin|object-filter|class-filter|class|superclass|rootclass"} {-argName "value" -required 0 -type tclobj} } {-nxdoc 1} cmd current NsfCurrentCmd { {-argName "option" -required 0 -typeName "currentoption" -type "activelevel|activemixin|args|calledclass|calledmethod|calledproc|callingclass|callinglevel|callingmethod|callingobject|callingproc|class|filterreg|isnextcall|level|methodpath|method|nextmethod|object|proc" -default object} } {-nxdoc 1} cmd self NsfSelfCmd { } {-nxdoc 1} # # var cmds # cmd "var::exists" NsfVarExistsCmd { {-argName "-array" -required 0 -nrargs 0 -type switch} {-argName "object" -required 1 -type object} {-argName "varName" -required 1} } {-nxdoc 1} cmd "var::get" NsfVarGetCmd { {-argName "-array" -required 0 -nrargs 0 -type switch} {-argName "-notrace" -required 0 -nrargs 0 -type switch} {-argName "object" -required 1 -type object} {-argName "varName" -required 1 -type tclobj} } {-nxdoc 1} cmd "var::import" NsfVarImportCmd { {-argName "object" -required 1 -type object} {-argName "args" -type args} } {-nxdoc 1} cmd "var::set" NsfVarSetCmd { {-argName "-array" -required 0 -nrargs 0 -type switch} {-argName "-notrace" -required 0 -nrargs 0 -type switch} {-argName "object" -required 1 -type object} {-argName "varName" -required 1 -type tclobj} {-argName "value" -required 0 -type tclobj} } {-nxdoc 1} cmd "var::unset" NsfVarUnsetCmd { {-argName "-nocomplain" -required 0 -nrargs 0 -type switch} {-argName "object" -required 1 -type object} {-argName "varName" -required 1 -type tclobj} } {-nxdoc 1} # # object methods # objectMethod autoname NsfOAutonameMethod { {-argName "-instance" -nrargs 0 -type switch} {-argName "-reset" -nrargs 0 -type switch} {-argName "name" -required 1 -type tclobj} } objectMethod class NsfOClassMethod { {-argName "class" -required 0 -type tclobj} } objectMethod cleanup NsfOCleanupMethod { } objectMethod cget NsfOCgetMethod { {-argName "name" -type tclobj -required 1} } objectMethod configure NsfOConfigureMethod { {-argName "args" -type virtualobjectargs} } {-objv0 1} objectMethod destroy NsfODestroyMethod { } objectMethod exists NsfOExistsMethod { {-argName "varName" -required 1} } objectMethod filterguard NsfOFilterGuardMethod { {-argName "filter" -required 1} {-argName "guard" -required 1 -type tclobj} } objectMethod instvar NsfOInstvarMethod { {-argName "args" -type allargs} } objectMethod mixinguard NsfOMixinGuardMethod { {-argName "mixin" -required 1 -type tclobj} {-argName "guard" -required 1 -type tclobj} } objectMethod noinit NsfONoinitMethod { } objectMethod requirenamespace NsfORequireNamespaceMethod { } objectMethod residualargs NsfOResidualargsMethod { {-argName "args" -type allargs} } objectMethod uplevel NsfOUplevelMethod { {-argName "args" -type allargs} } objectMethod upvar NsfOUpvarMethod { {-argName "args" -type allargs} } objectMethod volatile NsfOVolatileMethod { } objectMethod volatile1 NsfOVolatile1Method { } # # class methods # classMethod alloc NsfCAllocMethod { {-argName "objectName" -required 1 -type tclobj} } classMethod create NsfCCreateMethod { {-argName "objectName" -required 1 -type tclobj} {-argName "args" -type virtualclassargs} } classMethod dealloc NsfCDeallocMethod { {-argName "object" -required 1 -type tclobj} } classMethod filterguard NsfCFilterGuardMethod { {-argName "filter" -required 1} {-argName "guard" -required 1 -type tclobj} } classMethod getCachedParameters NsfCGetCachendParametersMethod { } classMethod mixinguard NsfCMixinGuardMethod { {-argName "mixin" -required 1 -type tclobj} {-argName "guard" -required 1 -type tclobj} } classMethod new NsfCNewMethod { {-argName "-childof" -required 0 -type tclobj} {-argName "args" -required 0 -type virtualclassargs} } classMethod recreate NsfCRecreateMethod { {-argName "objectName" -required 1 -type tclobj} {-argName "args" -type virtualclassargs} } classMethod superclass NsfCSuperclassMethod { {-argName "superclasses" -required 0 -type tclobj} } # # info object methods # objectInfoMethod baseclass NsfObjInfoBaseclassMethod { } objectInfoMethod children NsfObjInfoChildrenMethod { {-argName "-type" -required 0 -type class} {-argName "pattern" -required 0} } objectInfoMethod class NsfObjInfoClassMethod { } objectInfoMethod filterguard NsfObjInfoFilterguardMethod { {-argName "filter" -required 1} } objectInfoMethod filters NsfObjInfoFiltersMethod { {-argName "-guards" -nrargs 0 -type switch} {-argName "pattern"} } objectInfoMethod forward NsfObjInfoForwardMethod { {-argName "-definition" -nrargs 0 -type switch} {-argName "pattern"} } objectInfoMethod hasmixin NsfObjInfoHasMixinMethod { {-argName "class" -required 1 -type class} } objectInfoMethod hasnamespace NsfObjInfoHasnamespaceMethod { } objectInfoMethod hastype NsfObjInfoHasTypeMethod { {-argName "class" -required 1 -type class} } objectInfoMethod lookupfilter NsfObjInfoLookupFilterMethod { {-argName "filter" -required 1} } objectInfoMethod lookupfilters NsfObjInfoLookupFiltersMethod { {-argName "-guards" -nrargs 0 -type switch} {-argName "pattern"} } objectInfoMethod lookupmethod NsfObjInfoLookupMethodMethod { {-argName "name" -required 1 -type tclobj} } set methodType "all=NSF_METHODTYPE_ALL|scripted=NSF_METHODTYPE_SCRIPTED|builtin=NSF_METHODTYPE_BUILTIN|alias=NSF_METHODTYPE_ALIAS|forwarder=NSF_METHODTYPE_FORWARDER|object=NSF_METHODTYPE_OBJECT|setter=NSF_METHODTYPE_SETTER|nsfproc=NSF_METHODTYPE_NSFPROC" objectInfoMethod lookupmethods NsfObjInfoLookupMethodsMethod { {-argName "-callprotection" -typeName "callprotection" -type "all|public|protected|private" -default all} {-argName "-incontext" -nrargs 0 -type switch} {-argName "-type" -typeName "methodtype" -type $::methodType} {-argName "-nomixins" -nrargs 0 -type switch} {-argName "-path" -nrargs 0 -type switch} {-argName "-source" -typeName "definitionsource" -type "all|application|system" -default all} {-argName "pattern" -required 0} } objectInfoMethod lookupmixins NsfObjInfoLookupMixinsMethod { {-argName "-guards" -nrargs 0 -type switch} {-argName "pattern" -type objpattern} } objectInfoMethod lookupslots NsfObjInfoLookupSlotsMethod { {-argName "-source" -typeName "definitionsource" -type "all|application|system" -default all} {-argName "-type" -required 0 -type class} {-argName "pattern" -required 0} } objectInfoMethod method NsfObjInfoMethodMethod { {-argName "subcmd" -required 1 -typeName "infomethodsubcmd" -type "args|body|definition|exists|registrationhandle|definitionhandle|origin|parameter|syntax|type|precondition|postcondition|submethods|returns|disassemble"} {-argName "name" -required 1 -type tclobj} } objectInfoMethod methods NsfObjInfoMethodsMethod { {-argName "-callprotection" -typeName "callprotection" -type "all|public|protected|private" -default all} {-argName "-type" -typeName "methodtype" -type $::methodType} {-argName "-path" -nrargs 0 -type switch} {-argName "pattern" -required 0} } objectInfoMethod mixins NsfObjInfoMixinsMethod { {-argName "-guards" -nrargs 0 -type switch} {-argName "pattern" -type objpattern} } objectInfoMethod mixinguard NsfObjInfoMixinguardMethod { {-argName "mixin" -required 1} } objectInfoMethod name NsfObjInfoNameMethod { } objectInfoMethod parent NsfObjInfoParentMethod { } objectInfoMethod precedence NsfObjInfoPrecedenceMethod { {-argName "-intrinsic" -nrargs 0 -type switch} {-argName "pattern" -required 0} } objectInfoMethod slotobjects NsfObjInfoSlotobjectsMethod { {-argName "-type" -required 0 -type class} {-argName "pattern" -required 0} } objectInfoMethod vars NsfObjInfoVarsMethod { {-argName "pattern" -required 0} } # # info class methods # classInfoMethod filterguard NsfClassInfoFilterguardMethod { {-argName "filter" -required 1} } classInfoMethod filters NsfClassInfoFiltersMethod { {-argName "-guards" -nrargs 0 -type switch} {-argName "pattern"} } classInfoMethod forward NsfClassInfoForwardMethod { {-argName "-definition" -nrargs 0 -type switch} {-argName "pattern"} } classInfoMethod heritage NsfClassInfoHeritageMethod { {-argName "pattern"} } classInfoMethod instances NsfClassInfoInstancesMethod { {-argName "-closure" -nrargs 0 -type switch} {-argName "pattern" -type objpattern} } classInfoMethod method NsfClassInfoMethodMethod { {-argName "subcmd" -required 1 -typeName "infomethodsubcmd" -type "args|body|definition|exists|registrationhandle|definitionhandle|origin|parameter|syntax|type|precondition|postcondition|submethods|returns|disassemble"} {-argName "name" -required 1 -type tclobj} } classInfoMethod methods NsfClassInfoMethodsMethod { {-argName "-callprotection" -typeName "callprotection" -type "all|public|protected|private" -default all} {-argName "-closure" -nrargs 0 -type switch} {-argName "-type" -nrargs 1 -typeName "methodtype" -type $::methodType} {-argName "-path" -nrargs 0 -type switch} {-argName "-source" -nrargs 1 -typeName "definitionsource" -type "all|application|system" -default all} {-argName "pattern"} } classInfoMethod mixins NsfClassInfoMixinsMethod { {-argName "-closure" -nrargs 0 -type switch} {-argName "-guards" -nrargs 0 -type switch} {-argName "-heritage" -nrargs 0 -type switch} {-argName "pattern" -type objpattern} } classInfoMethod mixinguard NsfClassInfoMixinguardMethod { {-argName "mixin" -required 1} } classInfoMethod mixinof NsfClassInfoMixinOfMethod { {-argName "-closure" -nrargs 0 -type switch} {-argName "-scope" -typeName "mixinscope" -required 0 -type "all|class|object"} {-argName "pattern" -type objpattern} } classInfoMethod slotobjects NsfClassInfoSlotobjectsMethod { {-argName "-closure" -nrargs 0 -type switch} {-argName "-source" -typeName "definitionsource" -type "all|application|system" -default all} {-argName "-type" -required 0 -type class} {-argName "pattern" -required 0} } classInfoMethod subclass NsfClassInfoSubclassMethod { {-argName "-closure" -nrargs 0 -type switch} {-argName "-dependent" -nrargs 0 -type switch} {-argName "pattern" -type objpattern -flags NSF_ARG_NODASHALNUM} } classInfoMethod superclass NsfClassInfoSuperclassMethod { {-argName "-closure" -nrargs 0 -type switch} {-argName "pattern" -type tclobj} } # # check methods # # checkMethod required NsfCheckRequiredArgs { # {-argName "name" -required 1} # {-argName "value" -required 0 -type tclobj} # } # checkMethod boolean NsfCheckBooleanArgs { # {-argName "name" -required 1} # {-argName "value" -required 0 -type tclobj} # } # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/generic/nsf-part2.tcl000644 000766 000024 00000001006 13773660527 017141 0ustar00neumannstaff000000 000000 # -*- Tcl -*- # # Define a basic set of predefined Tcl commands and definitions for # the Next Scripting Framework. This file will be transformed by # mk_predefined.tcl into "predefined.h", which in included in nsf.c. # # Copyright (C) 2009-2017 Gustaf Neumann # Copyright (C) 2010 Stefan Sobernig # # The predefined code has to be split into 2 parts due to a string # literal limitation in ISO C99, that requires compilers to support # only strings up to 4095 bytes. # # This is part 2. # namespace eval ::nsf { ./nsf2.4.0/generic/nsfCmdDefinitions.c000644 000766 000024 00000012576 13774062620 020400 0ustar00neumannstaff000000 000000 /* * nsfCmdDefinitions.c -- * * Provide an API for registering method definitions and obtaining these * meta-data for introspection. Method definitions are shared by all * threads/interps. Access is governed by a mutex lock. * * Copyright (C) 2014-2016 Gustaf Neumann * Copyright (C) 2016 Stefan Sobernig * * Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #include "nsfInt.h" static Tcl_HashTable cmdDefinitionHashTable, *cmdDefinitionHashTablePtr = &cmdDefinitionHashTable; static int cmdDefinitionRefCount = 0; static NsfMutex cmdDefinitionMutex = 0; static int Register(Tcl_Interp *interp, Nsf_methodDefinition *methodDefinition); /* *---------------------------------------------------------------------- * Nsf_CmdDefinitionInit -- * * Initialize the hash-table structure for storing the method definitions. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Nsf_CmdDefinitionInit(void) { NsfMutexLock(&cmdDefinitionMutex); if (cmdDefinitionRefCount == 0) { Nsf_InitFunPtrHashTable(cmdDefinitionHashTablePtr); } cmdDefinitionRefCount++; NsfMutexUnlock(&cmdDefinitionMutex); } /*---------------------------------------------------------------------- * Nsf_CmdDefinitionRelease -- * * Release and, eventually, delete the hash table for method definitions. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Nsf_CmdDefinitionRelease(void) { NsfMutexLock(&cmdDefinitionMutex); if (--cmdDefinitionRefCount < 1) { Tcl_DeleteHashTable(cmdDefinitionHashTablePtr); } NsfMutexUnlock(&cmdDefinitionMutex); } /* *---------------------------------------------------------------------- * Nsf_CmdDefinitionRegister -- * * Register an array of cmd definitions. * * Results: * Always TCL_OK. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Nsf_CmdDefinitionRegister(Tcl_Interp *interp, Nsf_methodDefinition *definitionRecords) { Nsf_methodDefinition *ePtr; nonnull_assert(interp != NULL); nonnull_assert(definitionRecords != NULL); for (ePtr = definitionRecords; ePtr->methodName; ePtr++) { Register(interp, ePtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * Nsf_CmdDefinitionGet -- * * Obtain the definition for a previously registered proc. * * Results: * A pointer to a Method definition or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ Nsf_methodDefinition * Nsf_CmdDefinitionGet(Tcl_ObjCmdProc *proc) { Tcl_HashEntry *hPtr; nonnull_assert(proc != NULL); NsfMutexLock(&cmdDefinitionMutex); hPtr = Nsf_FindFunPtrHashEntry(cmdDefinitionHashTablePtr, (Nsf_AnyFun *)proc); NsfMutexUnlock(&cmdDefinitionMutex); if (hPtr != NULL) { return Tcl_GetHashValue(hPtr); } return NULL; } /* *---------------------------------------------------------------------- * Register -- * * Register a method definition. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Register(Tcl_Interp *interp, Nsf_methodDefinition *methodDefinition) nonnull(1) nonnull(2); static int Register(Tcl_Interp *interp, Nsf_methodDefinition *methodDefinition) { Tcl_HashEntry *hPtr; int isNew; nonnull_assert(interp != NULL); nonnull_assert(methodDefinition != NULL); NsfMutexLock(&cmdDefinitionMutex); hPtr = Nsf_CreateFunPtrHashEntry(cmdDefinitionHashTablePtr, (Nsf_AnyFun *)methodDefinition->proc, &isNew); NsfMutexUnlock(&cmdDefinitionMutex); if (isNew != 0) { Tcl_SetHashValue(hPtr, methodDefinition); return TCL_OK; } else { return NsfPrintError(interp, "proc %s is already registered", methodDefinition->methodName); } } /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * End: */ ./nsf2.4.0/generic/nsfDTrace.d000644 000766 000024 00000010440 13244511101 016611 0ustar00neumannstaff000000 000000 /* * nsfDTrace.d -- * * Next Scripting Framework DTrace provider. * * Copyright (c) 2011-2014 Gustaf Neumann * Copyright (c) 2018 Stefan Sobernig * * Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License http://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ typedef struct Tcl_Obj Tcl_Obj; /* * Next Scripting Framework (NSF) DTrace probes * * Modeled in alignment with the Tcl DTrace probes */ provider nsf { /***************************** proc probes *****************************/ /* * nsf*:::method-entry probe * triggered immediately before method bytecode execution * arg0: object name (string) * arg1: class/object name (string) * arg2: method name (string) * arg3: number of arguments (int) * arg4: array of proc argument objects (Tcl_Obj**) */ probe method__entry(char* object, char *class, char* method, int objc, Tcl_Obj **objv); /* * nsf*:::method-return probe * triggered immediately after proc bytecode execution * arg0: object name (string) * arg1: class/object name (string) * arg2: method name (string) * arg3: return code (int) */ probe method__return(char *object, char *class, char* name, int code); /***************************** Object probes ******************************/ /* * nsf*:::object-alloc probe * triggered when an NSF object is allocated * arg0: object (string) * arg1: class (string) */ probe object__alloc(char *object, char *class); /* * nsf*:::object-free probe * triggered whean an NSF object is freed * arg0: object (string) * arg1: class (string) */ probe object__free(char *object, char *class); /***************************** NSF configure probe ******************************/ /* * nsf*:::configure-probe probe * triggered when the ::nsf::configure is called * arg0-arg1: command arguments (strings) */ probe configure__probe(char *arg0, char *arg1); }; /* * Tcl types and constants for use in DTrace scripts */ typedef struct Tcl_ObjType { char *name; void *freeIntRepProc; void *dupIntRepProc; void *updateStringProc; void *setFromAnyProc; } Tcl_ObjType; struct Tcl_Obj { int refCount; char *bytes; int length; Tcl_ObjType *typePtr; union { long longValue; double doubleValue; void *otherValuePtr; int64_t wideValue; struct { void *ptr1; void *ptr2; } twoPtrValue; struct { void *ptr; unsigned long value; } ptrAndLongRep; } internalRep; }; enum return_codes { TCL_OK = 0, TCL_ERROR, TCL_RETURN, TCL_BREAK, TCL_CONTINUE }; #pragma D attributes Evolving/Evolving/Common provider nsf provider #pragma D attributes Private/Private/Common provider nsf module #pragma D attributes Private/Private/Common provider nsf function #pragma D attributes Evolving/Evolving/Common provider nsf name #pragma D attributes Evolving/Evolving/Common provider nsf args /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ ./nsf2.4.0/generic/nsfCompile.c.ast.sh000644 000766 000024 00000000762 13543460715 020263 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.8eea68.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfCompile.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/generic/nsfCompile.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfCompile.c.ast.bdump./nsf2.4.0/generic/nsfFunPtrHashTable.c.ast.sh000644 000766 000024 00000001012 13543460714 021651 0ustar00neumannstaff000000 000000 "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-8" "@/var/folders/2g/vv2xgh5s1yd8b11hlh5z4lqc0000gp/T/clang_command_.tmp.ea3750.txt" \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfFunPtrHashTable.c.ast.biniou bdump -x -d "/Users/neumann/cfs/src/infer-osx-v0.17.0/lib/infer/infer/bin/../etc/clang_ast.dict" -w '!!DUMMY!!' /Users/neumann/cfs/src/nsf2.3.0/generic/nsfFunPtrHashTable.c.ast.biniou \ > /Users/neumann/cfs/src/nsf2.3.0/generic/nsfFunPtrHashTable.c.ast.bdump./nsf2.4.0/generic/nsfProfile.c000644 000766 000024 00000072107 14260772512 017074 0ustar00neumannstaff000000 000000 /* * nsfProfile.c -- * * Provides profiling on Next Scripting Framework internals. * For turning on profiling, NSF_PROFILE must be configured. * * Copyright (C) 2010-2017 Gustaf Neumann * * Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #include "nsfInt.h" #if defined(NSF_PROFILE) typedef struct NsfProfileData { long microSec; long count; } NsfProfileData; #endif /* *---------------------------------------------------------------------- * NsfProfileObjectLabel -- * * Produce a string label for an object as used in profiling. * * Results: * None. * * Side effects: * Initializes and fills the passed Tcl_DString. * *---------------------------------------------------------------------- */ static void NsfProfileObjectLabel(Tcl_DString *dsPtr, NsfObject *object) nonnull(1) nonnull(2); static void NsfProfileObjectLabel(Tcl_DString *dsPtr, NsfObject *object) { nonnull_assert(dsPtr != NULL); nonnull_assert(object != NULL); Tcl_DStringAppend(dsPtr, ObjectName_(object), TCL_INDEX_NONE); Tcl_DStringAppend(dsPtr, " ", 1); Tcl_DStringAppend(dsPtr, ClassName(object->cl), TCL_INDEX_NONE); } /* *---------------------------------------------------------------------- * NsfProfileMethodLabel -- * * Produce a string label for a method as used in profiling. * * Results: * None. * * Side effects: * Initializes and fills the passed Tcl_DString. * *---------------------------------------------------------------------- */ static void NsfProfileMethodLabel(Tcl_DString *dsPtr, NsfClass *class, const char *methodName) nonnull(1) nonnull(3); static void NsfProfileMethodLabel(Tcl_DString *dsPtr, NsfClass *class, const char *methodName) { nonnull_assert(dsPtr != NULL); nonnull_assert(methodName != NULL); Tcl_DStringAppendElement(dsPtr, methodName); if (class != NULL) { Tcl_DStringAppend(dsPtr, " ", 1); Tcl_DStringAppend(dsPtr, ObjStr(class->object.cmdName), TCL_INDEX_NONE); } } /* *---------------------------------------------------------------------- * NsfProfileDeprecatedCall -- * * Output a line in case a deprecated function/method is called using * the low-level NsfDeprecatedCmd() function. * * Results: * None. * * Side effects: * Logging. * *---------------------------------------------------------------------- */ void NsfProfileDeprecatedCall(Tcl_Interp *interp, NsfObject *UNUSED(object), NsfClass *class, const char *methodName, const char *altMethod) { Tcl_DString ds; nonnull_assert(interp != NULL); //nonnull_assert(object != NULL); nonnull_assert(methodName != NULL); nonnull_assert(altMethod != NULL); Tcl_DStringInit(&ds); Tcl_DStringAppend(&ds, "{", 1); NsfProfileMethodLabel(&ds, class, methodName); Tcl_DStringAppend(&ds, "}", 1); NsfDeprecatedCmd(interp, "method", ds.string, altMethod); Tcl_DStringFree(&ds); } /* *---------------------------------------------------------------------- * NsfProfileDebugCall -- * * Output a line in case a function/method is called having the * debug flag set. This function is used by the Tcl command * ::nsf::debug::call for reporting. * * Results: * None. * * Side effects: * Logging. * *---------------------------------------------------------------------- */ void NsfProfileDebugCall(Tcl_Interp *interp, NsfObject *object, NsfClass *class, const char *methodName, int objc, Tcl_Obj **objv) { NsfRuntimeState *rst; Tcl_Obj *listObj; Tcl_DString ds; nonnull_assert(interp != NULL); nonnull_assert(methodName != NULL); rst = RUNTIME_STATE(interp); rst->debugCallingDepth++; Tcl_DStringInit(&ds); Nsf_DStringPrintf(&ds, "::nsf::debug::call %d {", rst->debugCallingDepth); if (object != NULL) { NsfProfileObjectLabel(&ds, object); } Tcl_DStringAppend(&ds, "} {", 3); NsfProfileMethodLabel(&ds, class, methodName); Tcl_DStringAppend(&ds, "}", 1); listObj = Tcl_NewListObj((TCL_SIZE_T)objc, objv); INCR_REF_COUNT(listObj); Nsf_DStringPrintf(&ds, " {%s}", ObjStr(listObj)); DECR_REF_COUNT(listObj); NsfDStringEval(interp, &ds, "debug call", (NSF_EVAL_DEBUG|NSF_EVAL_SAVE|NSF_EVAL_NOPROFILE)); Tcl_DStringFree(&ds); } /* *---------------------------------------------------------------------- * NsfProfileDebugExit -- * * Output a line in case a function/method is exited having the * debug flag set. This function is used by ::nsf::debug::exit * for reporting. * * Results: * None. * * Side effects: * Logging. * *---------------------------------------------------------------------- */ void NsfProfileDebugExit(Tcl_Interp *interp, NsfObject *object, NsfClass *class, const char *methodName, long startSec, long startUsec) { Tcl_DString ds, *dsPtr = &ds; NsfRuntimeState *rst; nonnull_assert(interp != NULL); nonnull_assert(methodName != NULL); rst = RUNTIME_STATE(interp); Tcl_DStringInit(dsPtr); Nsf_DStringPrintf(dsPtr, "::nsf::debug::exit %d {", rst->debugCallingDepth); if (object != NULL) { NsfProfileObjectLabel(dsPtr, object); } Tcl_DStringAppend(dsPtr, "} {", 3); NsfProfileMethodLabel(dsPtr, class, methodName); Tcl_DStringAppend(dsPtr, "} ", 2); Tcl_DStringAppendElement(dsPtr, ObjStr(Tcl_GetObjResult(interp))); if (startSec != 0 || startUsec != 0) { struct Tcl_Time trt; Tcl_GetTime(&trt); Nsf_DStringPrintf(dsPtr, " %ld ", (trt.sec - startSec) * 1000000 + (trt.usec - startUsec)); } else { Tcl_DStringAppend(dsPtr, " {}", 3); } NsfDStringEval(interp, &ds, "debug exit", (NSF_EVAL_DEBUG|NSF_EVAL_SAVE|NSF_EVAL_NOPROFILE)); Tcl_DStringFree(dsPtr); rst->debugCallingDepth--; } #if defined(NSF_PROFILE) /* *---------------------------------------------------------------------- * ReportLine -- * * Report a profile line via NsfLog(). Since NsfLog() uses a Tcl function, * ReportLine has to turn off profiling to avoid recursive profile * invocation. It is as well necessary to save the interp result. * * Results: * None. * * Side effects: * Logging. * *---------------------------------------------------------------------- */ static void ReportLine(Tcl_Interp *interp, int level, NsfRuntimeState *rst, const char *line) nonnull(1) nonnull(3) nonnull(4); static void ReportLine(Tcl_Interp *interp, int level, NsfRuntimeState *rst, const char *line) { Tcl_Obj *savedResultObj; int prevProfileSetting; nonnull_assert(interp != NULL); nonnull_assert(rst != NULL); nonnull_assert(line != NULL); prevProfileSetting = rst->doProfile; rst->doProfile = 0; savedResultObj = Tcl_GetObjResult(interp); INCR_REF_COUNT(savedResultObj); NsfLog(interp, level, "%s", line); Tcl_SetObjResult(interp, savedResultObj); DECR_REF_COUNT(savedResultObj); rst->doProfile = prevProfileSetting; } /* *---------------------------------------------------------------------- * NsfProfileFillTable -- * * Insert or Update a keyed entry with provided microseconds and * update the counts for this entry. * * Results: * None. * * Side effects: * Updated or created profile data entry. * *---------------------------------------------------------------------- */ static void NsfProfileFillTable(Tcl_HashTable *table, const char *keyStr, double totalMicroSec) nonnull(1) nonnull(2); static void NsfProfileFillTable(Tcl_HashTable *table, const char *keyStr, double totalMicroSec) { NsfProfileData *value; Tcl_HashEntry *hPtr; int isNew; nonnull_assert(table != NULL); nonnull_assert(keyStr != NULL); hPtr = Tcl_CreateHashEntry(table, keyStr, &isNew); if (isNew != 0) { value = (NsfProfileData *)ckalloc(sizeof(NsfProfileData)); value->microSec = 0; value->count = 0; Tcl_SetHashValue(hPtr, (ClientData) value); } else { value = (NsfProfileData *)Tcl_GetHashValue (hPtr); } value->microSec += (long)totalMicroSec; value->count ++; } /* *---------------------------------------------------------------------- * Nsf_ProfileFilterObjCmd -- * * Stub command to include C-level commands in profile traces. * * Results: * A standard Tcl result. * * Side effects: * Perform tracing * *---------------------------------------------------------------------- */ static int Nsf_ProfileFilterObjCmd(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { NsfShadowTclCommandInfo *ti; int result; struct Tcl_Time start; const char *fullMethodName, *label; Tcl_DString ds; assert(cd != NULL); fullMethodName = ObjStr(objv[0]); ti = (NsfShadowTclCommandInfo *)cd; if (ti->nrArgs == 0 || objc < 2) { label = fullMethodName; } else { int i, nrArgs = objc; if (nrArgs > ti->nrArgs) { nrArgs = ti->nrArgs; } Tcl_DStringInit(&ds); Tcl_DStringAppend(&ds, fullMethodName, TCL_INDEX_NONE); for (i = 1; i<=nrArgs; i++) { Tcl_DStringAppend(&ds, " ", 1); Tcl_DStringAppend(&ds, ObjStr(objv[i]), TCL_INDEX_NONE); } label = ds.string; } NsfProfileTraceCallAppend(interp, label); Tcl_GetTime(&start); result = Tcl_NRCallObjProc(interp, ti->proc, ti->clientData, (TCL_SIZE_T)objc, objv); NsfProfileRecordProcData(interp, label, start.sec, start.usec); if (label != fullMethodName) { Tcl_DStringFree(&ds); } return result; } /* *---------------------------------------------------------------------- * GetPair -- * * Split a Tcl_Obj into a nameObj and an integer value, if possible * * Results: * A standard Tcl result. * * Side effects: * Produce warnings for error cases, when "verbose" is on. * *---------------------------------------------------------------------- */ static int GetPair(Tcl_Interp *interp, Tcl_Obj *objPtr, int verbose, Tcl_Obj **nameObjPtr, int *nrArgsPtr) nonnull(1) nonnull(2) nonnull(4) nonnull(5); static int GetPair(Tcl_Interp *interp, Tcl_Obj *objPtr, int verbose, Tcl_Obj **nameObjPtr, int *nrArgsPtr) { int result = TCL_OK, oc; Tcl_Obj **ov; if (Tcl_ListObjGetElements(interp, objPtr, &oc, &ov) != TCL_OK) { if (verbose) { NsfLog(interp, NSF_LOG_WARN, "nsfprofile: invalid list element '%s'", ObjStr(objPtr)); result = TCL_ERROR; } } else { if (oc == 1) { *nameObjPtr = ov[0]; } else if (oc == 2) { if (Tcl_GetIntFromObj(interp, ov[1], nrArgsPtr) == TCL_OK) { *nameObjPtr = ov[0]; } else { if (verbose) { NsfLog(interp, NSF_LOG_WARN, "nsfprofile: second element of '%s' must be an integer", ObjStr(objPtr)); result = TCL_ERROR; } } } else { if (verbose) { NsfLog(interp, NSF_LOG_WARN, "nsfprofile: list element '%s' not a valid pair", ObjStr(objPtr)); result = TCL_ERROR; } } } return result; } /* *---------------------------------------------------------------------- * NsfProfileTrace -- * * Function to control trace behavior callable via Tcl. * * Results: * OK * * Side effects: * update RUNTIME_STATE(interp)->doTrace * and profilePtr->verbose * and profilePtr->inmemory * *---------------------------------------------------------------------- */ int NsfProfileTrace(Tcl_Interp *interp, int withEnable, int withVerbose, int withDontsave, Tcl_Obj *builtinObjs) { NsfRuntimeState *rst; NsfProfile *profilePtr; int oldProfileState, oc; Tcl_Obj **ov; nonnull_assert(interp != NULL); rst = RUNTIME_STATE(interp); profilePtr = &rst->profile; oldProfileState = rst->doTrace; rst->doTrace = withEnable; /* * Turn automatically profiling on&off, when trace is turned on/off */ if (withEnable == 1) { if (rst->doProfile == 1) { NsfLog(interp, NSF_LOG_WARN, "nsfprofile: tracing is already active"); } else { /* * Activate profile trace. */ if (builtinObjs != NULL) { /* * A list of commands was provided */ if (Tcl_ListObjGetElements(interp, builtinObjs, &oc, &ov) != TCL_OK) { NsfLog(interp, NSF_LOG_WARN, "nsfprofile: argument '%s' is not a list of commands", ObjStr(builtinObjs)); } else { int i; NsfShadowTclCommandInfo *ti = NEW_ARRAY(NsfShadowTclCommandInfo, oc); for (i = 0; i < oc; i++) { int nrArgs = 0; Tcl_Obj *nameObj = NULL; if (GetPair(interp, ov[i], 1, &nameObj, &nrArgs) == TCL_OK) { assert(nameObj != NULL); ti[i].nrArgs = nrArgs; if (NsfReplaceCommand(interp, nameObj, Nsf_ProfileFilterObjCmd, &ti[i], &ti[i]) != TCL_OK) { NsfLog(interp, NSF_LOG_WARN, "nsfprofile: list element '%s' is not a command", ObjStr(nameObj)); } } } INCR_REF_COUNT(builtinObjs); profilePtr->shadowedObjs = builtinObjs; profilePtr->shadowedTi = ti; } } } } else { /* * Deactivate profile trace. */ if (profilePtr->shadowedObjs != NULL) { if (Tcl_ListObjGetElements(interp, profilePtr->shadowedObjs, &oc, &ov) != TCL_OK) { NsfLog(interp, NSF_LOG_WARN, "nsfprofile: shadowed objects are apparently not a list"); } else { int i; for (i = 0; i < oc; i++) { int nrArgs = 0; Tcl_Obj *nameObj = NULL; if (GetPair(interp, ov[i], 0, &nameObj, &nrArgs) == TCL_OK) { assert(nameObj != NULL); NsfReplaceCommandCleanup(interp, nameObj, &profilePtr->shadowedTi[i]); } } } INCR_REF_COUNT(profilePtr->shadowedObjs); FREE(NsfShadowTclCommandInfo*, profilePtr->shadowedTi); profilePtr->shadowedTi = NULL; profilePtr->shadowedObjs = NULL; /*fprintf(stderr, "freed profile information\n");*/ } } rst->doProfile = withEnable; profilePtr->verbose = withVerbose; profilePtr->inmemory = (withDontsave == 1) ? 0 : 1; Tcl_SetObjResult(interp, Tcl_NewBooleanObj(oldProfileState)); return TCL_OK; } /* *---------------------------------------------------------------------- * NsfProfileTraceCallAppend, NsfProfileTraceExitAppend -- * * Low level function to add entries to the trace Tcl_DString when functions ar * called or exited. * * Results: * None. * * Side effects: * update profilePtr->depth and profilePtr->traceDs * *---------------------------------------------------------------------- */ void NsfProfileTraceCallAppend(Tcl_Interp *interp, const char *label) { NsfRuntimeState *rst = RUNTIME_STATE(interp); NsfProfile *profilePtr = &rst->profile; Tcl_DString ds; profilePtr->depth ++; Tcl_DStringInit(&ds); Nsf_DStringPrintf(&ds, "call(%d): %s", profilePtr->depth, label); if (profilePtr->verbose) { ReportLine(interp, NSF_LOG_NOTICE, rst, ds.string); } if (profilePtr->inmemory) { Tcl_DStringAppend(&ds, "\n", 1); Tcl_DStringAppend(&profilePtr->traceDs, ds.string, ds.length); } Tcl_DStringFree(&ds); } void NsfProfileTraceExitAppend(Tcl_Interp *interp, const char *label, double duration) { NsfRuntimeState *rst = RUNTIME_STATE(interp); NsfProfile *profilePtr = &rst->profile; Tcl_DString ds; Tcl_DStringInit(&ds); Nsf_DStringPrintf(&ds, "exit(%d): %s %.0f", profilePtr->depth, label, duration); if (profilePtr->verbose) { ReportLine(interp, NSF_LOG_NOTICE, rst, ds.string); } if (profilePtr->inmemory) { Tcl_DStringAppend(&ds, "\n", 1); Tcl_DStringAppend(&profilePtr->traceDs, ds.string, ds.length); } Tcl_DStringFree(&ds); profilePtr->depth --; } /* *---------------------------------------------------------------------- * NsfProfileTraceCall, NsfProfileTraceExit -- * * Add entries to the trace Tcl_DString when methods/procs are * called or exited. This function builds the labels for * invocation strings in the same way as for profiling and calls * the lower-level function, which does the recording. * * Results: * None. * * Side effects: * update profilePtr->depth and profilePtr->traceDs * *---------------------------------------------------------------------- */ void NsfProfileTraceCall(Tcl_Interp *interp, NsfObject *object, NsfClass *class, const char *methodName) { NsfRuntimeState *rst = RUNTIME_STATE(interp); if (rst->doTrace) { Tcl_DString ds, traceLabel; Tcl_DStringInit(&ds); NsfProfileObjectLabel(&ds, object); Tcl_DStringInit(&traceLabel); Tcl_DStringAppendElement(&traceLabel, Tcl_DStringValue(&ds)); Tcl_DStringAppend(&traceLabel, " ", 1); Tcl_DStringSetLength(&ds, 0); NsfProfileMethodLabel(&ds, class, methodName); Tcl_DStringAppendElement(&traceLabel, Tcl_DStringValue(&ds)); NsfProfileTraceCallAppend(interp, Tcl_DStringValue(&traceLabel)); Tcl_DStringFree(&traceLabel); Tcl_DStringFree(&ds); } } void NsfProfileTraceExit(Tcl_Interp *interp, NsfObject *object, NsfClass *class, const char *methodName, struct Tcl_Time *callTime) { NsfRuntimeState *rst = RUNTIME_STATE(interp); if (rst->doTrace) { Tcl_DString ds, traceLabel; double totalMicroSec; struct Tcl_Time trt; Tcl_GetTime(&trt); totalMicroSec = (double)((trt.sec - callTime->sec) * 1000000 + (trt.usec - callTime->usec)); Tcl_DStringInit(&ds); NsfProfileObjectLabel(&ds, object); Tcl_DStringInit(&traceLabel); Tcl_DStringAppendElement(&traceLabel, Tcl_DStringValue(&ds)); Tcl_DStringAppend(&traceLabel, " ", 1); Tcl_DStringSetLength(&ds, 0); NsfProfileMethodLabel(&ds, class, methodName); Tcl_DStringAppendElement(&traceLabel, Tcl_DStringValue(&ds)); NsfProfileTraceExitAppend(interp, Tcl_DStringValue(&traceLabel), totalMicroSec); Tcl_DStringFree(&traceLabel); Tcl_DStringFree(&ds); } } /* *---------------------------------------------------------------------- * NsfProfileRecordMethodData -- * * This function is invoked, when a call of a method ends. It * records profiling information based on the provided call stack * content and the caller. In particular, it records the time spent * in an object (identified with an objectKey) and the time spent * in the method (using methodKey). * * Results: * None. * * Side effects: * Updated or created profile data entries * *---------------------------------------------------------------------- */ void NsfProfileRecordMethodData(Tcl_Interp *interp, NsfCallStackContent *cscPtr) { NsfRuntimeState *rst; double totalMicroSec; NsfObject *obj; NsfClass *cl; Tcl_DString methodKey, objectKey, methodInfo; NsfProfile *profilePtr; struct Tcl_Time trt; nonnull_assert(interp != NULL); nonnull_assert(cscPtr != NULL); Tcl_GetTime(&trt); rst = RUNTIME_STATE(interp); profilePtr = &rst->profile; totalMicroSec = (double)((trt.sec - cscPtr->startSec) * 1000000 + (trt.usec - cscPtr->startUsec)); profilePtr->overallTime += (long)totalMicroSec; obj = cscPtr->self; if (obj->teardown == 0 || !obj->id) { return; } Tcl_DStringInit(&objectKey); NsfProfileObjectLabel(&objectKey, obj); Tcl_DStringInit(&methodInfo); Tcl_DStringInit(&methodKey); cl = cscPtr->cl; NsfProfileMethodLabel(&methodInfo, cl, cscPtr->methodName); if (rst->doTrace) { Tcl_DString traceKey; Tcl_DStringInit(&traceKey); Tcl_DStringAppendElement(&traceKey, Tcl_DStringValue(&objectKey)); Tcl_DStringAppend(&traceKey, " ", 1); Tcl_DStringAppendElement(&traceKey, Tcl_DStringValue(&methodInfo)); NsfProfileTraceExitAppend(interp, Tcl_DStringValue(&traceKey), totalMicroSec); Tcl_DStringFree(&traceKey); } /* * Append method to object key as needed by statistics (but not by trace) */ Tcl_DStringAppendElement(&objectKey, cscPtr->methodName); /* * Build method key, containing actual method info and caller method info. */ Tcl_DStringInit(&methodKey); Tcl_DStringAppend(&methodKey, "{", 1); Tcl_DStringAppend(&methodKey, Tcl_DStringValue(&methodInfo), Tcl_DStringLength(&methodInfo)); Tcl_DStringAppend(&methodKey, "}", 1); { NsfCallStackContent *cscPtrTop = NsfCallStackGetTopFrame(interp, NULL); if (cscPtrTop != NULL) { Tcl_DStringAppend(&methodKey, " {", 2); NsfProfileMethodLabel(&methodKey, cscPtrTop->cl, cscPtrTop->methodName); Tcl_DStringAppend(&methodKey, "}", 1); } else { Tcl_DStringAppend(&methodKey, " {}", 3); } } NsfProfileFillTable(&profilePtr->objectData, Tcl_DStringValue(&objectKey), totalMicroSec); NsfProfileFillTable(&profilePtr->methodData, Tcl_DStringValue(&methodKey), totalMicroSec); Tcl_DStringFree(&objectKey); Tcl_DStringFree(&methodKey); Tcl_DStringFree(&methodInfo); } /* *---------------------------------------------------------------------- * NsfProfileRecordProcData -- * * This function is invoked, when a call of a nsf::proc. It records * time spent and count per nsf::proc. * * Results: * None. * * Side effects: * Updated or created profile data entries * *---------------------------------------------------------------------- */ void NsfProfileRecordProcData(Tcl_Interp *interp, const char *methodName, long startSec, long startUsec) { NsfRuntimeState *rst; NsfProfile *profilePtr; double totalMicroSec; struct Tcl_Time trt; nonnull_assert(interp != NULL); nonnull_assert(methodName != NULL); rst = RUNTIME_STATE(interp); profilePtr = &rst->profile; Tcl_GetTime(&trt); totalMicroSec = (double)((trt.sec - startSec) * 1000000 + (trt.usec - startUsec)); profilePtr->overallTime += (long)totalMicroSec; if (rst->doTrace) { NsfProfileTraceExitAppend(interp, methodName, totalMicroSec); } NsfProfileFillTable(&profilePtr->procData, methodName, totalMicroSec); } /* *---------------------------------------------------------------------- * NsfProfileClearTable -- * * Clear all data in a profile table. * * Results: * None. * * Side effects: * freed profile information. * *---------------------------------------------------------------------- */ static void NsfProfileClearTable(Tcl_HashTable *table) nonnull(1); static void NsfProfileClearTable(Tcl_HashTable *table) { Tcl_HashSearch hSrch; Tcl_HashEntry *hPtr; nonnull_assert(table != NULL); for (hPtr = Tcl_FirstHashEntry(table, &hSrch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { NsfProfileData *value = (NsfProfileData *) Tcl_GetHashValue(hPtr); ckfree((char *) value); Tcl_DeleteHashEntry(hPtr); } } /* *---------------------------------------------------------------------- * NsfProfileClearData -- * * Flush all data in all profile tables and reset the time * counters. * * Results: * None. * * Side effects: * freed profile information. * *---------------------------------------------------------------------- */ void NsfProfileClearData(Tcl_Interp *interp) { NsfProfile *profilePtr; struct Tcl_Time trt; nonnull_assert(interp != NULL); profilePtr = &RUNTIME_STATE(interp)->profile; NsfProfileClearTable(&profilePtr->objectData); NsfProfileClearTable(&profilePtr->methodData); NsfProfileClearTable(&profilePtr->procData); Tcl_GetTime(&trt); profilePtr->startSec = trt.sec; profilePtr->startUSec = trt.usec; profilePtr->overallTime = 0; profilePtr->depth = 0; Tcl_DStringSetLength(&profilePtr->traceDs, 0); } /* *---------------------------------------------------------------------- * NsfProfileGetTable -- * * Return the profiling information for the specified profile table * in form of a Tcl list. * * Results: * Tcl List * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj* NsfProfileGetTable(Tcl_Interp *interp, Tcl_HashTable *table) nonnull(1) nonnull(2); static Tcl_Obj* NsfProfileGetTable(Tcl_Interp *interp, Tcl_HashTable *table) { Tcl_Obj *list = Tcl_NewListObj(0, NULL); Tcl_HashSearch hSrch; Tcl_HashEntry *hPtr; nonnull_assert(interp != NULL); nonnull_assert(table != NULL); for (hPtr = Tcl_FirstHashEntry(table, &hSrch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSrch)) { NsfProfileData *value = (NsfProfileData *) Tcl_GetHashValue(hPtr); char *key = Tcl_GetHashKey(table, hPtr); Tcl_Obj *subList = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, subList, Tcl_NewStringObj(key, TCL_INDEX_NONE)); Tcl_ListObjAppendElement(interp, subList, Tcl_NewLongObj(value->microSec)); Tcl_ListObjAppendElement(interp, subList, Tcl_NewLongObj(value->count)); Tcl_ListObjAppendElement(interp, list, subList); } return list; } /* *---------------------------------------------------------------------- * NsfProfileGetData -- * * Return recorded profiling information. This function returns a * list containing (a) the elapsed time since the last clear (or * init), (b) the cumulative time, (c) the list with the per-object * data and (d) the list with the method invocation data. * * Results: * Tcl List * * Side effects: * None. * *---------------------------------------------------------------------- */ void NsfProfileGetData(Tcl_Interp *interp) { Tcl_Obj *list = Tcl_NewListObj(0, NULL); NsfProfile *profilePtr; long totalMicroSec; struct Tcl_Time trt; nonnull_assert(interp != NULL); profilePtr = &RUNTIME_STATE(interp)->profile; Tcl_GetTime(&trt); totalMicroSec = (trt.sec - profilePtr->startSec) * 1000000 + (trt.usec - profilePtr->startUSec); Tcl_ListObjAppendElement(interp, list, Tcl_NewLongObj((long)totalMicroSec)); Tcl_ListObjAppendElement(interp, list, Tcl_NewLongObj(profilePtr->overallTime)); Tcl_ListObjAppendElement(interp, list, NsfProfileGetTable(interp, &profilePtr->objectData)); Tcl_ListObjAppendElement(interp, list, NsfProfileGetTable(interp, &profilePtr->methodData)); Tcl_ListObjAppendElement(interp, list, NsfProfileGetTable(interp, &profilePtr->procData)); Tcl_ListObjAppendElement(interp, list, Tcl_NewStringObj(profilePtr->traceDs.string, profilePtr->traceDs.length)); Tcl_SetObjResult(interp, list); } /* *---------------------------------------------------------------------- * NsfProfileInit -- * * Initialize the profiling information. This is a one-time only * operation and initializes the hash table and the timing * results. The inverse operation is NsfProfileFree() * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void NsfProfileInit(Tcl_Interp *interp) { NsfProfile *profilePtr; struct Tcl_Time trt; nonnull_assert(interp != NULL); profilePtr = &RUNTIME_STATE(interp)->profile; Tcl_InitHashTable(&profilePtr->objectData, TCL_STRING_KEYS); Tcl_InitHashTable(&profilePtr->methodData, TCL_STRING_KEYS); Tcl_InitHashTable(&profilePtr->procData, TCL_STRING_KEYS); Tcl_GetTime(&trt); profilePtr->startSec = trt.sec; profilePtr->startUSec = trt.usec; profilePtr->overallTime = 0; profilePtr->depth = 0; Tcl_DStringInit(&profilePtr->traceDs); } /* *---------------------------------------------------------------------- * NsfProfileFree -- * * Free all profiling information. This is a one-time only * operation only. The inverse operation is NsfProfileInit(). * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void NsfProfileFree(Tcl_Interp *interp) { NsfProfile *profilePtr; nonnull_assert(interp != NULL); profilePtr = &RUNTIME_STATE(interp)->profile; NsfProfileClearData(interp); Tcl_DeleteHashTable(&profilePtr->objectData); Tcl_DeleteHashTable(&profilePtr->methodData); Tcl_DeleteHashTable(&profilePtr->procData); Tcl_DStringFree(&profilePtr->traceDs); } #endif /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * End: */ ./nsf2.4.0/generic/nsfShadow.c000644 000766 000024 00000044314 14261011635 016711 0ustar00neumannstaff000000 000000 /* * nsfShadow.c -- * * API support for shadowing (overloading) and accessing C-implemented * Tcl obj-commands. * * Copyright (C) 1999-2017 Gustaf Neumann * Copyright (C) 2019 Stefan Sobernig * * Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1020, Welthandelsplatz 1 * Vienna, Austria * * This work is licensed under the MIT License https://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #include "nsfInt.h" #include "nsfAccessInt.h" #include "nsfCmdPtr.c" static Tcl_ObjCmdProc Nsf_InfoFrameObjCmd; EXTERN Tcl_ObjCmdProc NsfProcStub; static Tcl_ObjCmdProc Nsf_InfoBodyObjCmd; static Tcl_ObjCmdProc Nsf_RenameObjCmd; /* *---------------------------------------------------------------------- * NsfReplaceCommandCleanup -- * * Undo the effects of NsfReplaceCommand() for the Tcl command * referred by name. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int NsfReplaceCommandCleanup(Tcl_Interp *interp, Tcl_Obj *nameObj, NsfShadowTclCommandInfo *ti) { Tcl_Command cmd; int result = TCL_OK; nonnull_assert(interp != NULL); nonnull_assert(nameObj != NULL); nonnull_assert(ti != NULL); /*fprintf(stderr, " cleanup for %s ti=%p in %p\n", NsfGlobalStrings[name], ti, interp);*/ cmd = Tcl_GetCommandFromObj(interp, nameObj); if (cmd != NULL) { Tcl_Command_objProc(cmd) = ti->proc; if (ti->clientData != NULL) { Tcl_Command_objClientData(cmd) = ti->clientData; } ti->proc = NULL; ti->clientData = NULL; } else { result = TCL_ERROR; } return result; } /* *---------------------------------------------------------------------- * NsfReplaceCommandCheck -- * * Test, whether shadowing is still in effect, and refresh the * replacement if necessary. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void NsfReplaceCommandCheck(Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_ObjCmdProc *proc, NsfShadowTclCommandInfo *ti) nonnull(1) nonnull(2) nonnull(3) nonnull(4); static void NsfReplaceCommandCheck(Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_ObjCmdProc *proc, NsfShadowTclCommandInfo *ti) { Tcl_Command cmd; nonnull_assert(interp != NULL); nonnull_assert(nameObj != NULL); nonnull_assert(proc != NULL); nonnull_assert(ti != NULL); cmd = Tcl_GetCommandFromObj(interp, nameObj); if (cmd != NULL && ti->proc && Tcl_Command_objProc(cmd) != proc) { /* fprintf(stderr, "we have to do something about %s %p %p\n", NsfGlobalStrings[name], Tcl_Command_objProc(cmd), proc); */ ti->proc = Tcl_Command_objProc(cmd); ti->clientData = Tcl_Command_objClientData(cmd); Tcl_Command_objProc(cmd) = proc; } } /* *---------------------------------------------------------------------- * NsfReplaceCommand -- * * Lookup the objProc of a Tcl command and keep it around for * efficient calling. Replace the objProc optionally with a newly * specified one. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int NsfReplaceCommand(Tcl_Interp *interp, Tcl_Obj *nameObj, Tcl_ObjCmdProc *nsfReplacementProc, ClientData cd, NsfShadowTclCommandInfo *ti) { Tcl_Command cmd; int result = TCL_OK; nonnull_assert(interp != NULL); nonnull_assert(nameObj != NULL); nonnull_assert(ti != NULL); /* fprintf(stderr, "NsfReplaceCommand %s\n", ObjStr(nameObj)); */ cmd = Tcl_GetCommandFromObj(interp, nameObj); if (cmd == NULL) { result = TCL_ERROR; } else { Tcl_ObjCmdProc *objProc = Tcl_Command_objProc(cmd); if (nsfReplacementProc != objProc) { ti->proc = objProc; ti->clientData = Tcl_Command_objClientData(cmd); if (nsfReplacementProc != NULL) { Tcl_Command_objProc(cmd) = nsfReplacementProc; } if (cd != NULL) { Tcl_Command_objClientData(cmd) = cd; } } } return result; } /* *---------------------------------------------------------------------- * Nsf_InfoBodyObjCmd -- * * TclObjCmd for shadowing "::tcl::info::body. In case the function * is called with an nsf::proc (which is technically a command, not * a proc), the original command fails ("not a proc"). We catch this * call here and test, whether the body is from an nsf::proc. If * so, we call tcl::info::body with the shadowed body. * * Example: * nsf::proc foo {-a} {puts $a}; info body foo * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Nsf_InfoBodyObjCmd(ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { Tcl_Command cmd; nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); if (objc != 2) { /* wrong # args, let Tcl generate the error */ return NsfCallCommand(interp, NSF_INFO_BODY, objc, objv); } cmd = Tcl_FindCommand(interp, ObjStr(objv[1]), (Tcl_Namespace *)NULL, 0); if (cmd != NULL) { Tcl_ObjCmdProc *proc = Tcl_Command_objProc(cmd); ClientData procClientData = Tcl_Command_objClientData(cmd); if (proc == NsfProcStub && procClientData != NULL) { NsfProcClientData *tcd = procClientData; Tcl_Obj *ov[2]; /* * The command is from an nsf::proc */ ov[0] = objv[0]; ov[1] = tcd->procName; return NsfCallCommand(interp, NSF_INFO_BODY, objc, ov); } } /* Actually call the cmd using Tcl's info body */ return NsfCallCommand(interp, NSF_INFO_BODY, objc, objv); } /* *---------------------------------------------------------------------- * Nsf_RenameObjCmd -- * * TclObjCmd for shadowing "::rename". We check whether the cmd * refers to an NsfObject. If so we have to destroy and/or "move" * it. Otherwise proceed by calling the shadowed function. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Nsf_RenameObjCmd(ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { Tcl_Command cmd; if (objc != 3) { /* wrong # args, let Tcl generate the error */ return NsfCallCommand(interp, NSF_RENAME, objc, objv); } /* if an obj/cl should be renamed => call the Nsf move method */ cmd = Tcl_FindCommand(interp, ObjStr(objv[1]), (Tcl_Namespace *)NULL, 0); if (cmd != NULL) { Tcl_ObjCmdProc *proc = Tcl_Command_objProc(cmd); ClientData procClientData = Tcl_Command_objClientData(cmd); NsfObject *object = NsfGetObjectFromCmdPtr(cmd); Tcl_Command parentCmd; char *newName = ObjStr(objv[2]); if (proc == NsfProcStub && procClientData != NULL && *newName != '\0') { Tcl_DString fqNewName; int result; NsfProcClientData *tcd = procClientData; Tcl_DStringInit(&fqNewName); Tcl_DStringAppend(&fqNewName, "::nsf::procs::", 14); Tcl_DStringAppend(&fqNewName, newName, TCL_INDEX_NONE); /* fprintf(stderr, "oldName %s newName %s\n", ObjStr(tcd->procName), Tcl_DStringValue(&fqNewName));*/ result = TclRenameCommand(interp, ObjStr(tcd->procName), Tcl_DStringValue(&fqNewName)); if (result == TCL_OK) { DECR_REF_COUNT2("procNameObj", tcd->procName); tcd->procName = Tcl_NewStringObj(Tcl_DStringValue(&fqNewName), Tcl_DStringLength(&fqNewName)); INCR_REF_COUNT2("procNameObj", tcd->procName); } Tcl_DStringFree(&fqNewName); if (result != TCL_OK) { return TCL_ERROR; } } else if (object != NULL) { Tcl_Obj *methodObj = NsfMethodObj(object, NSF_o_move_idx); if (methodObj) { return NsfCallMethodWithArgs(interp, (Nsf_Object *)object, methodObj, objv[2], 1, 0, NSF_CSC_IMMEDIATE); } } parentCmd = Tcl_FindCommand(interp, Tcl_Command_nsPtr(cmd)->fullName, (Tcl_Namespace *)NULL, 0); if (parentCmd != NULL) { NsfObjectMethodEpochIncr("::rename"); } } /* Actually rename the cmd using Tcl's rename*/ return NsfCallCommand(interp, NSF_RENAME, objc, objv); } /* *---------------------------------------------------------------------- * Nsf_InfoFrameObjCmd -- * * TclObjCmd for shadowing "::tcl::info::frame". First we call the * shadowed method. If it returns OK we check whether the frame is * an NSF frame. If so, we remove from the result the misleading * "proc" and add "method", "class", "object" and "frametype". * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Nsf_InfoFrameObjCmd(ClientData UNUSED(clientData), Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { int result; result = NsfCallCommand(interp, NSF_INFO_FRAME, objc, objv); if (result == TCL_OK && objc == 2) { int level, topLevel; unsigned int frameFlags; CmdFrame *framePtr = Tcl_Interp_cmdFramePtr(interp); CallFrame *varFramePtr = Tcl_Interp_varFramePtr(interp); Tcl_Obj *resultObj = Tcl_GetObjResult(interp); /* * Level must be ok, otherwise we would not have a TCL_OK. */ Tcl_GetIntFromObj(interp, objv[1], &level); /* todo: coroutine level messing is missing. Needed? */ topLevel = (framePtr == NULL) ? 0 : framePtr->level; if (level > 0) { level -= topLevel; } while (++level <= 0 && varFramePtr && framePtr) { framePtr = framePtr->nextPtr; varFramePtr = varFramePtr->callerPtr; } frameFlags = (varFramePtr != NULL) ? (unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr) : 0u; /*fprintf(stderr, " ... frame %p varFramePtr %p frameFlags %.6x\n", framePtr, varFramePtr, frameFlags); Tcl85showStack(interp);*/ if (frameFlags & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) { NsfCallStackContent *cscPtr = ((NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr)); const char *frameType; Tcl_Obj *listObj, **ov; int oc, i; listObj = Tcl_NewListObj(0, NULL); /* * Remove "proc" element from list, if provided. */ Tcl_ListObjGetElements(interp, resultObj, &oc, &ov); for (i=0; iself->cmdName); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("class", 5)); Tcl_ListObjAppendElement(interp, listObj, (cscPtr->cl != NULL) ? cscPtr->cl->object.cmdName : NsfGlobalObjs[NSF_EMPTY]); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("method", 6)); Tcl_ListObjAppendElement(interp, listObj, (cscPtr->cmdPtr != NULL) ? Tcl_NewStringObj(Tcl_GetCommandName(interp, cscPtr->cmdPtr), TCL_INDEX_NONE) : NsfGlobalObjs[NSF_EMPTY]); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("frametype", 9)); if (cscPtr->frameType == NSF_CSC_TYPE_PLAIN) { frameType = "intrinsic"; } else if (cscPtr->frameType & NSF_CSC_TYPE_ACTIVE_MIXIN) { frameType = "mixin"; } else if (cscPtr->frameType & NSF_CSC_TYPE_ACTIVE_FILTER) { frameType = "filter"; } else if (cscPtr->frameType & NSF_CSC_TYPE_GUARD) { frameType = "guard"; } else { frameType = "unknown"; } Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(frameType, TCL_INDEX_NONE)); Tcl_SetObjResult(interp, listObj); } else if (frameFlags & (FRAME_IS_NSF_OBJECT)) { NsfObject *object = (NsfObject *)Tcl_CallFrame_clientData(varFramePtr); /* Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); */ Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("object", 6)); Tcl_ListObjAppendElement(interp, resultObj, object->cmdName); Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("frameType", 9)); Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("object", 6)); Tcl_SetObjResult(interp, resultObj); } } return result; } /* *---------------------------------------------------------------------- * NsfShadowTclCommands -- * * Load/refresh/unload shadowed Tcl commands. Essentially, the * shadowing function serve two things: * * (a) lookup some Tcl ObjProcs, which are not available via global * symbols and make these available via NsfCallCommand(). * (b) some Tcl commands are actually shadowed; we perform some * pre- and/or postprocessing on these calls. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ #define CMD_INFO(rst, name) &(rst)->tclCommands[(name)-NSF_EXPR] int NsfShadowTclCommands(Tcl_Interp *interp, NsfShadowOperations load) { int rc = TCL_OK; NsfRuntimeState *rst; nonnull_assert(interp != NULL); rst = RUNTIME_STATE(interp); if (load == SHADOW_LOAD) { assert(rst->tclCommands == NULL); rst->tclCommands = NEW_ARRAY(NsfShadowTclCommandInfo, NSF_RENAME - NSF_EXPR + 1); #ifdef USE_TCL_STUBS /* * When the third argument of NsfReplaceCommand is NULL, the commands are * not overloaded. However, we use this mechanism to call Tcl commands * (Tcl_ExprObjCmd(), Tcl_IncrObjCmd() and Tcl_SubstObjCmd()), which cannot be * called not available in though the stub table. */ rc |= NsfReplaceCommand(interp, NsfGlobalObjs[NSF_EXPR], NULL, NULL, CMD_INFO(rst, NSF_EXPR)); #endif rc |= NsfReplaceCommand(interp, NsfGlobalObjs[NSF_FORMAT], NULL, NULL, CMD_INFO(rst, NSF_FORMAT)); rc |= NsfReplaceCommand(interp, NsfGlobalObjs[NSF_INTERP], NULL, NULL, CMD_INFO(rst, NSF_INTERP)); rc |= NsfReplaceCommand(interp, NsfGlobalObjs[NSF_STRING_IS], NULL, NULL, CMD_INFO(rst, NSF_STRING_IS)); rc |= NsfReplaceCommand(interp, NsfGlobalObjs[NSF_DISASSEMBLE], NULL, NULL, CMD_INFO(rst, NSF_DISASSEMBLE)); /* for the following commands, we have to add our own semantics */ rc |= NsfReplaceCommand(interp, NsfGlobalObjs[NSF_INFO_BODY], Nsf_InfoBodyObjCmd, NULL, CMD_INFO(rst, NSF_INFO_BODY)); rc |= NsfReplaceCommand(interp, NsfGlobalObjs[NSF_INFO_FRAME], Nsf_InfoFrameObjCmd, NULL, CMD_INFO(rst, NSF_INFO_FRAME)); rc |= NsfReplaceCommand(interp, NsfGlobalObjs[NSF_RENAME], Nsf_RenameObjCmd, NULL, CMD_INFO(rst, NSF_RENAME)); } else if (load == SHADOW_REFETCH) { NsfReplaceCommandCheck(interp, NsfGlobalObjs[NSF_INFO_BODY], Nsf_InfoFrameObjCmd, CMD_INFO(rst, NSF_INFO_BODY)); NsfReplaceCommandCheck(interp, NsfGlobalObjs[NSF_INFO_FRAME], Nsf_InfoFrameObjCmd, CMD_INFO(rst, NSF_INFO_FRAME)); NsfReplaceCommandCheck(interp, NsfGlobalObjs[NSF_RENAME], Nsf_RenameObjCmd, CMD_INFO(rst, NSF_RENAME)); } else { NsfReplaceCommandCleanup(interp, NsfGlobalObjs[NSF_INFO_BODY], CMD_INFO(rst, NSF_INFO_BODY)); NsfReplaceCommandCleanup(interp, NsfGlobalObjs[NSF_INFO_FRAME], CMD_INFO(rst, NSF_INFO_FRAME)); NsfReplaceCommandCleanup(interp, NsfGlobalObjs[NSF_RENAME], CMD_INFO(rst, NSF_RENAME)); FREE(NsfShadowTclCommandInfo*, rst->tclCommands); rst->tclCommands = NULL; } return rc; } /* *---------------------------------------------------------------------- * NsfCallCommand -- * * Calls a Tcl Command as direct as possible. The commands have to be * looked up previously via NsfShadowTclCommands(). The element objv[0] * is replaced with the predefined command name. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int NsfCallCommand(Tcl_Interp *interp, NsfGlobalNames name, int objc, Tcl_Obj *const objv[]) { int result; NsfShadowTclCommandInfo *ti = &RUNTIME_STATE(interp)->tclCommands[name-NSF_EXPR]; ALLOC_ON_STACK(Tcl_Obj*, objc, ov); /* {int i; fprintf(stderr, "calling %s (%p %p) in %p, objc=%d ", NsfGlobalStrings[name], ti, ti->proc, interp, objc); for(i=0;i 1) { memcpy(ov+1, objv+1, sizeof(Tcl_Obj *) * ((size_t)objc - 1u)); } result = Tcl_NRCallObjProc(interp, ti->proc, ti->clientData, (TCL_SIZE_T)objc, objv); FREE_ON_STACK(Tcl_Obj *, ov); return result; } /* * Local Variables: * mode: c * c-basic-offset: 2 * fill-column: 78 * indent-tabs-mode: nil * End: */ ./nsf2.4.0/COPYRIGHT000644 000766 000024 00000005037 12501766547 014505 0ustar00neumannstaff000000 000000 /* * Next Scripting Framework * * Copyright (C) 1999-2014 Gustaf Neumann (a) (b) * Copyright (C) 1999-2007 Uwe Zdun (a) (b) * Copyright (C) 2007-2008 Martin Matuska (b) * Copyright (C) 2010-2014 Stefan Sobernig (b) * * * (a) University of Essen * Specification of Software Systems * Altendorferstrasse 97-101 * D-45143 Essen, Germany * * (b) Vienna University of Economics and Business * Institute of Information Systems and New Media * A-1090, Augasse 2-6 * Vienna, Austria * * This work is licensed under the MIT License * http://www.opensource.org/licenses/MIT * * Copyright: * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * * This software is based upon MIT Object Tcl by David Wetherall and * Christopher J. Lindblad, that contains the following copyright * message: * * "Copyright 1993 Massachusetts Institute of Technology * * Permission to use, copy, modify, distribute, and sell this * software and its documentation for any purpose is hereby granted * without fee, provided that the above copyright notice appear in * all copies and that both that copyright notice and this * permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity * pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about * the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty." */ ./nsf2.4.0/ChangeLog-2.2.0-HEAD000644 000766 000024 00000041634 13524463542 016116 0ustar00neumannstaff000000 000000 2019-05-07 Gustaf Neumann Update release steps Silence clang 8 static checker improve documentation 2019-05-06 Stefan Sobernig Updated changelog, fixed stats and indentation in announcement [skip ci] * nsf-gridfs.test: Add one more piece of harness to test suite [skip ci] * library/mongodb/*: Ran NSF MongoDB tests, against MongoDB 4.0.9 and Mongo-C driver 1.14.0 (both, latest stable); updated README.md accordingly, and fixed gridfs tests that hadn't been corrected for renaming README to README.md 2019-05-05 Gustaf Neumann make spaces after comma regular improve grammar and spelling avoid one-liner loop 2019-05-03 Stefan Sobernig * nx.tcl, properties.test: Add exists accessor to properties and variables; incl. tests and documentation Updated changelog, fixed stats in announcement [skip ci] Regenerated documentation * Object.man: Remove line break in script evaluation Bump version number from 2.3a0 to 2.3 2019-05-02 Gustaf Neumann reduce dead store operations and null after dereference 2019-05-01 Gustaf Neumann improve spelling 2019-04-30 Stefan Sobernig * tests/*.test: Add 'package prefer latest' to remaining test files. Fix typos in ChangeLog [skip ci] Fix a remainder in changelog [skip ci] Done with changelog and announcement [skip ci] 2019-04-26 Stefan Sobernig * forward.test: Constrain the max recursion depth around recursive forwards, so that we do not run into early crashes on systems with limited stack sizes (when the stack is saturated before a recursion limit is hit). This fixes test runs on MinGW/ gcc builds at AppVeyor. 2019-04-23 Stefan Sobernig * forward.tests: Provide some background comment on platform-dependent error messages as test conditions (infinite loop) and make sure tests under 8.6 are executed as intended. Continued work in changelog and announcement (still WIP) [skip ci] 2019-04-21 Gustaf Neumann added "pure" declarations removed null test after dereferences, avoid potential null dereferences in error cases removed null test after dereferences 2019-04-20 Gustaf Neumann improve code safety and remove dead statement get rid of warning of static checker, reduce number of returns before end of function 2019-04-19 Gustaf Neumann minor code cleanup add asserts 2019-04-19 Stefan Sobernig Continued work in changelog and announcement (still WIP) [skip ci] 2019-04-18 Gustaf Neumann fix memory leak on "hyper-volatile" objects. it seems, we have to set the _is_autonamed flag in advance of obj initialization 2019-04-17 Gustaf Neumann addressing coverty defect 337829 (dereference before null check) 2019-04-15 Gustaf Neumann make spelling more consistent fix typo Provide a more conservative change for setting autonamed flag provide more context info when the version mismatch test fails remove "-Wabi" for standard intense checking - more troubles then benefits Improve consistency of naming nsf objects 2019-04-15 Stefan Sobernig * nsf.c (NsfCCreateMethod): Fix access of potentially freed object to set the autonamed property (indicated by valdgrind). When destroyed and cleaned during DoObjInitialization, "newObject" will remain as a dangling pointer. Besides, setting the property before DoObjInitialization will make the object property available from within the initcmd or init method. * nsf.c (NsfProcStubDeleteProc): Plug leakage of command structure (found by valgrind) 2019-04-14 Stefan Sobernig Add changelog and announcement files (WIP) [skip ci] 2019-04-12 Gustaf Neumann muniro formatting changes 2019-04-12 Stefan Sobernig Provide 2.2 builds on Appveyor Use maintenance branch for 2.2, to fulfil presence requirements of build descriptor Provide for 2.2.0 builds, and fix allowed failures Deploy mode for Appveyor builds 2019-04-11 Stefan Sobernig Add missing install instruction [skip travis] Fix yaml [skip travis] Fix yaml [skip travis] Fix yaml [skip travis] Add deploy key to AppVeyor [skip travis] 2019-04-10 Stefan Sobernig Remove context noise (directory tree) from the tarballs * configure, configure.ac: Make sure 'git describe' uses --always, to not fail on truncated checkouts without tags in reach (as on Travis) Provide some harness around 'make test', to avoid swallowing failing test suites in light of the write-error condition * nsf.c (NsfDebugShowObj): For consistency, stick with %x using PRIxPTR *nsf.c (NsfDebugShowObj): Simplify from using %x to %p, to avoid PTR2UINT (which, starting with 8.7, will return u long, not u int) 2019-04-09 Stefan Sobernig Completed rewrite, ufff Another try Fix gcc version for macos Rewrite build matrix (testing) Refine build matrix Refine build matrix Make tarball names more explanatory linux image requires more generic fix, Python module variant not available Change script block Test NONBLOCK fix for write error Change http:// occurrences to https://, if applicable (URLs tested) Fix permissions Avoid ssh-add Avoid host check Fix ssh/scp calls Re-enable install target Add a debugging statement around make test 2019-04-08 Stefan Sobernig Stepping back, continued Stepping back, sigh Attempt at write-error fix Leave it be, for the moment Don't stop on stderr print-outs Make calls less verbose, are we hitting a limit? Avoid colliding paths Activate some introspection Fold separate bash calls into one Fix configure path Now with com Rebuild key, once again Adding new key Add build script with install target Fix glitch in openssl call Test for auto-deployment of builds Prepare for automated deploymnent of build artifacts [skip travis] * apps/build.tcl: Revert URL change for build script, archive is retrieved broken otherwise? Rewrite URLs containing tcl.tk as authority to tcl-lang.org 2019-03-31 Gustaf Neumann improve spelling 2019-03-29 Gustaf Neumann move new assertion to the right place improve wording ease human tracing of uninitialized/NULL values 2019-03-29 Stefan Sobernig Fix test 2019-03-28 Stefan Sobernig Complete caching by testing for kits fix descriptor Add caching support to travis descriptor 2019-03-27 Gustaf Neumann add generated configure file for change e3968e8c972a8ac13bfaba27fcf2ae9e36689211 address dtrace triggers from Makefile, although not configured try to simplify Makefile dependencies for DTRACE 2019-03-22 Stefan Sobernig * nsf.c (NsfOUplevelMethod, NsfOUpvarMethod): Silence compiler warnings on nonnull/NULL compares. * nsf.c (NsfOUplevelMethod, NsfOUpvarMethod, NsfCallstackFindCallingContext): Reform of uplevel and upvar methods, based on the recent feedback by Zoran. First, uplevel and upvar methods, as well as [current callinglevel] now behave consistently (re frame skipping for mixin and filter transparency). If there is no innermost enclosing proc frame, the innermost non-proc (e.g., namespace) frame is selected (rather than a "#0" as default). Second, argument handling for both uplevel (i.e., level sniffing in multi-arg case) and upvar (e.g., made silent TCL_ERROR for invalid argument arities explicit) have been fixed. * Object.man, methods.test: Added documentation for both methods (Object.man) and tests. 2019-03-22 Gustaf Neumann reduce dead assignments improve indentation of variables avoid variable name "index" in generated code since "index" shadows an outer function 2019-03-21 Gustaf Neumann mongodb: add "bson asJSON" convenience method 2019-03-20 Stefan Sobernig Fix YAML syntax appveyor.yml: Provide for caching the tclkit running the build script, to improve robustness and availability 2019-03-20 Gustaf Neumann handle ticket #3 on sourceforge: explicit "next" call in ensemble leads to unwanted "unknown" handler call 2019-03-18 Gustaf Neumann since we know length, we can replace strcmp by memcmp 2019-03-17 Gustaf Neumann trigger new travis build error message on stack overflow differs on windows and unix for tcl 8.5 we see now a different error message in tcl8.5 for a recursive loop (drop test?) improve type cleanness - deactivate under windows for the time being make test more robust ("file lstat" returns less data under windows) added an additional variant of ALLOC_ON_STACK The new version does not use alloca(), it does not use VLA and it does not boat the stack in case huge vectors are to be processed. It uses a plain array up to a certain size and switches to malloc() above this size. 2019-03-16 Gustaf Neumann improve spelling improve spelling unify spelling of "subclass" improve spelling align names (use "subclass" instead of "sub-class") align behavior of "current activelevel" with "... callinglevel" in case no NSF frame is found fix typos and make spelling more uniform add regression test for testing the behavior of :upvar from toplevel tclsh with and without filters This test covers implicitly also the behavior of [current callinglevel]. conservative fix for "current callinglevel"; probably more to come 2019-03-15 Stefan Sobernig * nx.tcl, xotcl2.tcl: Fully qualify uses of Tcl's upvar and uplevel, to avoid confusion when introducing equally named procs/ cmds in the OS namespaces. 2019-03-14 Gustaf Neumann minor cleanup: factor out common strings 2019-03-13 Gustaf Neumann improve spelling and formatting improve spelling improve spelling - improved handling of object property autonamed A call of "new" calls internally the "create" method. When the "create" method is overloaded, we want to be able to check already on this level, whether the object is autonamed or not. The previous version has set the property at the end of the "new" method, which was too late for ttrace. xotcl1 compatibility: preserve overwritte slot accessor methods via instprocs many thanks to Zoran for indicating this 2019-03-12 Stefan Sobernig * win/makefile.vc: COMDAT folding can lead to unusable, pointless function-pointer comparisons (Nsf_ConvertToSwitch vs. Nsf_ConvertToBoolean). Reported for /opt:icf under Visual Studio 2017 under x86. Kudos to Ashok P. Nadkarni. 2019-03-11 Gustaf Neumann object property volatile: provide support for tuning volatile on/off via object property. 2019-03-10 Gustaf Neumann improve spelling improve spelling improve spelling improve spelling windows: make sure, the install directory exists before copying data to it many thanks to Marc Gutman, who provided the patch momgoDB interface: add option "-asJSON" to "find all" to ease interaction e.g. with single page applications. improve spelling xotcl regression test: Added a more complex test for testing "new" + volatile 2019-03-09 Gustaf Neumann add minimal regression test for object property "autonamed" make code assumptions clear by adding asserts. This was triggered by a report of Ashok running into a crash during startup on windows (Visual Studio 2017) 2019-03-08 Gustaf Neumann Adjust regression test to more specific error message - improved error message "not allowed to have default": make clear, this is from a parameter specification - added object property "autonamed" (set automatically for objects created via "new") - xotcl2 volatile: improved backward compatibility with XOTcl 1 - extended regression test 2019-03-07 Gustaf Neumann - added new variant of "volatile" trying to mimic the XOTcl1 volatile behavior. - added experimental feature NSF_WITH_TCL_OBJ_TYPES_AS_CONVERTER, which uses registered TclObjTypes as value checkers (currently deactivated) whitespace change 2019-02-18 Gustaf Neumann protect legacy HTTPd against XSS on error messages 2019-02-06 Gustaf Neumann base package nx::zip on Tcl 8.6 builtins instead of relying on the Trf package 2019-01-15 Gustaf Neumann use "nonnull_assert" only in combination with "nonnull" declaration 2019-01-14 Stefan Sobernig * .travis.yml, appveyor.yml: Update build array to 8.6.9 * nsf-cmd.test: Make new tests 8.5-savy * nsf.c (NsfProcStub): Re-order logic, so that the availability of a shadow proc cmd is tested first (re-fetch) and the parameter passing comes second, conditional on an available dispatch target. * nsf-cmd.test: Add test rename (target) conflicts for the shadowed procs; improve test formatting nsf.c (NsfStubProc): Improve comment formatting 2019-01-11 Stefan Sobernig * nsf-cmd.test: Modernize tests to work on error codes. * nsf.c, nsf-cmd.test: Fixed nsf::procs for (unintended) deletes of the shadowed proc, plus test cases. * nsf.c, nsfShadow.c (NsfProcStubDeleteProc, Nsf_RenameObjCmd): Provide for coupled renaming of the nsf::proc pairs; and coupled deletion. * nsf.c (NsfProcStub, InvokeShadowedProc): Provide for re-fetching (e.g., deleted) ::nsf::procs::* commands, to allow for renamed nsf::procs to run. * nsf-cmd.test: Added test to cover re-fetch * nsf.c, nsfInt.h (NsfProcStub, NsfProcClientData): Apply namespace reform to nsf::procs, to prevent proc redefinition after a proc rename to fail. * nsf-cmd.test: Add test case to document/ to cover failing rename + redefine. 2018-12-22 Gustaf Neumann improve code documentation remove unneeded assignment 2018-12-15 Gustaf Neumann reduce dead assignments and variable scopes make sure, the restted path ends with a slash 2018-12-14 Gustaf Neumann security fix: avoid directory traversal attack in old XOTcl HTTP class 2018-11-18 Gustaf Neumann regenerated configure script improve handling of HAVE_INTTYPES_H under windows make sure, macros HAVE_INTPTR_T and HAVE_UINTPTR_T are set (should probably upgrade to newer TEA version) fix typo 2018-11-17 Gustaf Neumann guard definition of PRIxPTR by HAVE_INTTYPES_H and not by HAVE_STDINT_H improve type cleanness fix typo 2018-11-04 Gustaf Neumann remove comma before "that" use consistently US spelling variation 2018-11-03 Gustaf Neumann remove comma before that 2018-10-24 Stefan Sobernig * disposition.test, parameters.test: Adjust tests to reflect the changed representational behavior for numerics (int, wide) according to TIP 514 (now in Tcl 8.7a2+). 2018-10-23 Gustaf Neumann improve spelling help static analyzer to parse statements 2018-10-12 Gustaf Neumann use consistently US spelling variants 2018-10-11 Stefan Sobernig * Makefile.in, win/makefile.vc: Add TCL_PKG_PREFER_LATEST to avoid version hickups (stable beating latest) somewhere from TCLLIBPATH etc. 2018-10-02 Gustaf Neumann update README.release to make sure, all version numbers in configure.ac are updated properly 2018-09-30 Stefan Sobernig * configure: Make sure configure is stashed with repo, as autotools are not automatically re-generated (e.g., in build array) * object-system.test: Add a simple test to catch incomplete version bumps earlier 2018-09-29 Gustaf Neumann bump also NSF_MINOR_VERSION after release 2018-09-28 Gustaf Neumann follow the Tcl, not the OpenACS numbering scheme prefer US american spelling variants change version number to first version number after the 2.2.0 release (2.3d0) fix usernames at sourceforge ./nsf2.4.0/apps/utils/source-doc-beautifier.tcl000644 000766 000024 00000005111 13350304762 022160 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh # # Script to prettify documentation and test scripts into ASCIIDOC # markup documents. # # The script receives an NX script as an argument and outputs to the # same directory an ASCIIDOC markup document. # # Gustaf Neumann, Dec 2010 package req nx nx::Object create output { set :state "" set :text "" :public object method line {kind string} { if {${:state} ne $kind} { if {${:state} ne ""} {:flush} set :state $kind set :text "" } append :text $string \n } :public object method flush {} { set trimmed [string trim ${:text} \n] if {$trimmed ne ""} { :${:state} $trimmed } } :public object method postprocess {block} { set result "" set cmd "" foreach l [split $block \n] { append cmd $l \n if {[info complete $cmd]} then { set w0 "" regexp {^\s*(\S+)\s*} $cmd _ w0 #set w0 [lindex $cmd 0] if { ($w0 eq "?" && [llength $cmd] == 3) || ($w0 eq "!" && [llength $cmd] == 2) } { set body [lindex $cmd 1] regsub -all -line {^\s*#//.*//\s*$} $body {} body set body [string trim $body] append result "% $body\n" set cmdresult [lindex $cmd 2] if {$cmdresult ne "" && ![string match ::nsf::__* $cmdresult]} {append result $cmdresult \n} } else { append result $cmd } set cmd "" } } return [string trimright $result \n] } :public object method prog {block} { puts $::out {[source,tcl]} puts $::out -------------------------------------------------- puts $::out [:postprocess $block] puts $::out --------------------------------------------------\n } :public object method doc {block} { #puts $::out "=====doc\n$block\n=====" puts $::out $block\n } } #puts stderr "find -L $opt(-path) -type f -name '$opt(-name)'" nsf::proc run {-notitle:switch args} { foreach file $args { set F [open $file]; set content [read $F]; close $F set outfn [file rootname $file].txt set ::out [open $outfn w] set title "Listing of $file" regexp {^# = (.+?)\n(.*)$} $content _ title content foreach ignorePattern { "package req nx::test" "package require nx::test" "nx::Test parameter count 1" "proc ! args.*?" } { regsub "$ignorePattern\s?\n" $content "" content } if {!$notitle} { puts $::out "= $title\n" } foreach line [split $content \n] { if {[regexp {^# ?(.*)$} $line _ comment]} { output line doc $comment } else { output line prog $line } } output flush } } run {*}$argv # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/apps/utils/source-highlight-with-pp000755 000766 000024 00000000150 13350304771 022053 0ustar00neumannstaff000000 000000 #!/usr/bin/env tclsh package req nx::pp lappend argv [read stdin] puts stdout [nx::pp render {*}$argv] ./nsf2.4.0/apps/utils/asciidoc.conf000644 000766 000024 00000000274 12501766547 017740 0ustar00neumannstaff000000 000000 [blockdef-listing] source-style=template="source-highlight-block",presubs=(),postsubs=("callouts",),posattrs=("style","language","src_numbered","src_tab"),filter="source-highlight-with-pp"./nsf2.4.0/apps/build.tcl000644 000766 000024 00000010620 14271031276 015740 0ustar00neumannstaff000000 000000 # w/o tls # linux: https://kitcreator.rkeene.org/kits/840dec4286102c869d85bae3b0dcd32565e7bf12/tclkit # macos: https://kitcreator.rkeene.org/kits/6967b89da1f6af7b12cdc82819f3bdb13a661242/tclkit # w/ tls # linux: http://kitcreator.rkeene.org/kits/c8fe6fba3323b12b924b4a0716609abbaa00822c/tclkit # macos: http://kitcreator.rkeene.org/kits/31eaf9ae17e769609700b41d1d3c9abeda27510d/tclkit # win: http://kitcreator.rkeene.org/kits/32c6369ff6ef02a685b75854237635d4a3d56611/tclkit.exe package require http package require tar package require platform proc ::build {HOMEDIR BUILDDIR TCLTAG {TOOLCHAIN autoconf-tea}} { puts TCLVER=[package req Tcl],[info loaded],$::tcl_patchLevel,[catch {format %d 0777}],[catch {format %d 06440000000}] set tarball "tcl.tar.gz" set INSTALLDIR [file join $HOMEDIR install] cd $HOMEDIR set URL https://core.tcl-lang.org/tcl/tarball/$tarball?uuid=$TCLTAG if {![catch {package require tls}]} { http::register https 443 [list ::tls::socket -tls1 1] set fh [open $tarball wb+] try { ::http::geturl $URL \ -binary true \ -channel $fh close $fh # seek $fh 0 # zlib push gunzip $fh # ::tar::untar $fh -chan puts TCLVER2=[package req Tcl],[info loaded],$::tcl_patchLevel,[catch {format %d 0777}],[catch {format %d 06440000000}] exec >@stdout 2>@stderr bash -lc "ls -la" exec >@stdout 2>@stderr bash -lc "7z x -so $tarball | 7z x -aoa -si -ttar" } on error {e opts} { file delete -force tcl return -options $opts $e } finally { catch {close $fh} exec >@stdout 2>@stderr bash -lc "ls -la tcl/" exec >@stdout 2>@stderr bash -lc "pwd" file delete -force $tarball } } else { # fall back to using curl exec >@stdout 2>@stderr bash -lc "curl -L -k -o $tarball $URL" # set fh [open $tarball rb] try { # zlib push gunzip $fh # ::tar::untar $fh -chan exec >@stdout 2>@stderr bash -lc "7z x $tarball -so | 7z x -aoa -si -ttar -o tcl" } finally { # close $fh file delete -force $tarball } } # exec tar -xzf tcl.tar.gz # https://stackoverflow.com/questions/22333745/how-does-tcl-exec-work-exactly set dir [expr {[string match "win*" [platform::generic]]?"win":"unix"}] set tclRoot [file normalize tcl] set tclDir [file join $tclRoot $dir] # puts pwd([pwd])=[glob *] # puts tclDir($tclDir)=[glob $tclDir/*] set buildDir [pwd] cd $tclDir puts ENV=$::env(PATH) puts ENV=$::env(HOME) exec >@stdout 2>@stderr bash -lc "echo \$PATH" exec >@stdout 2>@stderr bash -lc "cd && pwd" exec >@stdout 2>@stderr bash -lc "pwd" exec >@stdout 2>@stderr bash -lc "cd && ls -la" switch -exact -- $TOOLCHAIN { autoconf-tea { set opts [list --libdir=$tclDir --enable-64bit] exec >@stdout 2>@stderr bash -lc "./configure $opts" exec >@stdout 2>@stderr bash -lc "make" cd $BUILDDIR # puts BUILDDIR=$BUILDDIR,PWD=[pwd],INSTALLDIR=$INSTALLDIR # exec >@stdout 2>@stderr bash -lc "./configure --with-tcl=$tclDir" exec >@stdout 2>@stderr bash -lc "./configure --prefix=$INSTALLDIR --exec-prefix=$INSTALLDIR --with-tcl=$tclDir" try { exec >@stdout 2>@stderr bash -lc "make test" } trap CHILDSTATUS {- opts} { lassign [dict get $opts -errorcode] -> pid code # when make encountered a build error, we expect to see an # error code of 2. Any other, non-make error code will be # ignored for the time being; assuming the test suite # completed. if {$code == 2} {exit 1} puts stderr "WARNING: make failed with unexpected error code: $opts" } exec >@stdout 2>@stderr bash -lc "make install" } nmake-tea { exec >@stdout 2>@stderr nmake -nologo -f makefile.vc TCLDIR=$tclRoot release cd [file join $BUILDDIR win] exec >@stdout 2>@stderr nmake -nologo -f makefile.vc TCLDIR=$tclRoot all exec >@stdout 2>@stderr nmake -nologo -f makefile.vc TCLDIR=$tclRoot test exec >@stdout 2>@stderr nmake -nologo -f makefile.vc TCLDIR=$tclRoot install INSTALLDIR=$INSTALLDIR } default { throw [list BUILD UNSUPPORTED $TOOLCHAIN] \ "Unsupported toolchain: '$TOOLCHAIN'." } } } # puts ===$::argv ::build {*}$::argv # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: ./nsf2.4.0/Makefile.in000644 000766 000024 00000121706 14274463622 015256 0ustar00neumannstaff000000 000000 # Makefile.in -- # # This file is a Makefile for Sample TEA Extension. If it has the name # "Makefile.in" then it is a template for a Makefile; to generate the # actual Makefile, run "./configure", which is a configuration script # generated by the "autoconf" program (constructs like "@foo@" will get # replaced in the actual Makefile. # # Copyright (c) 1999 Scriptics Corporation. # Copyright (c) 2002-2003 ActiveState Corporation. # Copyright (c) 2001-2007 Uwe Zdun # Copyright (c) 2001-2022 Gustaf Neumann # Copyright (c) 2016 Stefan Sobernig # # See the file "tcl-license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # #======================================================================== # Add additional lines to handle any additional AC_SUBST cases that # have been added in a customized configure script. #======================================================================== NX_VERSION = @PACKAGE_VERSION@ src_lib_dir = ${srcdir}/library src_doc_dir = ${srcdir}/doc src_test_dir = ${srcdir}/tests src_app_dir = ${srcdir}/apps src_generic_dir = ${srcdir}/generic src_man_dir = ${srcdir}/man TCL_LIB_SPEC = @TCL_LIB_SPEC@ subdirs = @subdirs@ aol_prefix = @aol_prefix@ stubdir = stubs${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION} # Requires native paths PLATFORM_DIR = `@CYGPATH@ $(srcdir)/@TEA_PLATFORM@` target_doc_dir = ./doc src_lib_dir_native = `@CYGPATH@ ${src_lib_dir}` src_doc_dir_native = `@CYGPATH@ ${src_doc_dir}` src_test_dir_native = `@CYGPATH@ ${src_test_dir}` src_app_dir_native = `@CYGPATH@ ${src_app_dir}` src_generic_dir_native = `@CYGPATH@ ${src_generic_dir}` libdirs = lib nx serialize libsrc = COPYRIGHT pkgIndex.tcl appdirs = appsrc = COPYRIGHT CPPCHECK = cppcheck # XOTcl subpackage xotcl_srcdir = ${srcdir}/library/xotcl xotcl_src_doc_dir = ${xotcl_srcdir}/doc xotcl_src_app_dir = ${xotcl_srcdir}/apps xotcl_src_lib_dir = ${xotcl_srcdir}/library xotcl_src_test_dir = ${xotcl_srcdir}/tests xotcl_target_doc_dir = ${xotcl_srcdir}/doc xotcl_libdirs = comm lib serialize @libdirs_actiweb@ xotcl_libsrc = COPYRIGHT xotcl2.tcl pkgIndex.tcl xotcl_appdirs = comm scripts utils @apps_actiweb@ xotcl_appsrc = COPYRIGHT # Documentation source for xotcl-style documentation system XODOC_SOURCE = \ $(src_lib_dir)/serialize/serializer.tcl \ $(xotcl_src_doc_dir)/langRef.xotcl \ $(xotcl_src_lib_dir)/lib/*.xotcl \ $(xotcl_src_test_dir)/*.xotcl \ $(xotcl_src_app_dir)/comm/[flsw]*.xotcl \ $(xotcl_src_app_dir)/utils/xo-*[a-z0-9] #export TCLLIBPATH=. ${srcdir} mkinstalldirs= mkdir -p #======================================================================== # Nothing of the variables below this line should need to be changed. # Please check the TARGETS section below to make sure the make targets # are correct. #======================================================================== DTRACE_OBJ = @DTRACE_OBJ@ DTRACE_HDR = @DTRACE_HDR@ DTRACE_SRC = @DTRACE_SRC@ #======================================================================== # The names of the source files is defined in the configure script. # The object files are used for linking into the final library. # This will be used when a dist target is added to the Makefile. # It is not important to specify the directory, as long as it is the # $(srcdir) or in the generic, win or unix subdirectory. #======================================================================== PKG_SOURCES = @PKG_SOURCES@ PKG_OBJECTS = @PKG_OBJECTS@ ${DTRACE_OBJ} PKG_STUB_SOURCES = @PKG_STUB_SOURCES@ PKG_STUB_OBJECTS = @PKG_STUB_OBJECTS@ #======================================================================== # PKG_TCL_SOURCES identifies Tcl runtime files that are associated with # this package that need to be installed, if any. #======================================================================== PKG_TCL_SOURCES = @PKG_TCL_SOURCES@ #======================================================================== # This is a list of public header files to be installed, if any. #======================================================================== PKG_HEADERS = @PKG_HEADERS@ #======================================================================== # "PKG_LIB_FILE" refers to the library (dynamic or static as per # configuration options) composed of the named objects. #======================================================================== PKG_LIB_FILE = @PKG_LIB_FILE@ PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@ lib_BINARIES = $(PKG_LIB_FILE) $(PKG_STUB_LIB_FILE) BINARIES = $(lib_BINARIES) SHELL = @SHELL@ srcdir = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ datadir = @datadir@ datarootdir = @datarootdir@ mandir = @mandir@ includedir = @includedir@ DESTDIR = PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_VERSION) pkglibdir = $(libdir)/$(PKG_DIR) top_builddir = INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_DATA_DIR = ${INSTALL} -d -m 755 # INSTALL_OPTIONS = # INSTALL = $(SHELL) $(srcdir)/config/install-sh -c ${INSTALL_OPTIONS} # INSTALL_DATA_DIR = ${INSTALL} -d -m 755 # INSTALL_PROGRAM = ${INSTALL} -m 755 # INSTALL_DATA = ${INSTALL} -m 644 # INSTALL_SCRIPT = ${INSTALL_PROGRAM} # INSTALL_LIBRARY = ${INSTALL_DATA} PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ CC = @CC@ CFLAGS_DEBUG = @CFLAGS_DEBUG@ CFLAGS_OPTIMIZE = @CFLAGS_OPTIMIZE@ CFLAGS_WARNING = @CFLAGS_WARNING@ CFLAGS_DEFAULT = @CFLAGS_DEFAULT@ CFLAGS_DEFAULT = -DNDEBUG # useful for debugging: #CFLAGS_DEFAULT = -pedantic -g -std=c99 -DTCL_NO_DEPRECATED -Wconversion -Wsign-conversion -Wfloat-conversion -Wsign-compare CFLAGS_CONVERSION= -Wconversion -Wsign-conversion -Wsign-compare CFLAGS_DEFINITION= -Wwrite-strings -Wextra -Wdeclaration-after-statement -Wendif-labels -Wshadow -Wmissing-prototypes -Wstrict-prototypes -Wpacked -Wno-redundant-decls -Wno-zero-length-array # -Wredundant-decls is currently not possible due to stubs interface # -Wzero-length-array is currently not possible due to TCLFLEXARRAY in Tcl 8.6.11 CFLAGS_TIDY = -Wmissing-braces -Wmissing-declarations -Wundef -Wunreachable-code -Wswitch-enum -Wpointer-arith -Wold-style-definition -Wmissing-format-attribute -Wformat-security #CFLAGS_DEFAULT = -pedantic -g -std=c99 -DTCL_NO_DEPRECATED $(CFLAGS_CONVERSION) $(CFLAGS_DEFINITION) $(CFLAGS_TIDY) CLEANFILES = @CLEANFILES@ EXEEXT = @EXEEXT@ LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@ MAKE_LIB = @MAKE_LIB@ MAKE_SHARED_LIB = @MAKE_SHARED_LIB@ MAKE_STATIC_LIB = @MAKE_STATIC_LIB@ MAKE_STUB_LIB = @MAKE_STUB_LIB@ OBJEXT = @OBJEXT@ RANLIB = @RANLIB@ RANLIB_STUB = @RANLIB_STUB@ SHLIB_CFLAGS = @SHLIB_CFLAGS@ SHLIB_LD = @SHLIB_LD@ SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ STLIB_LD = @STLIB_LD@ TCL_DEFS = @TCL_DEFS@ TCL_BIN_DIR = @TCL_BIN_DIR@ TCL_SRC_DIR = @TCL_SRC_DIR@ # DTRACE = dtrace ifeq ($(DTPLITE),) DTPLITE=dtplite else # Do nothing, use the environment variable as is. endif ifeq ($(ASCIIDOC),) ASCIIDOC = PATH=$(src_app_dir_native)/utils:$(PATH) \ asciidoc \ -f $(src_app_dir_native)/utils/asciidoc.conf else # Do nothing, use the environment variable as is. endif ifeq ($(CHROME),) CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" else # Do nothing, use the environment variable as is. endif # # Not used, but retained for reference of what libs Tcl required TCL_LIBS = @TCL_LIBS@ xotcl_pkglibdir= $(pkglibdir)/xotcl installed_shells = \ $(DESTDIR)$(bindir)/nxsh \ $(DESTDIR)$(bindir)/nxwish \ $(DESTDIR)$(bindir)/xotclsh \ $(DESTDIR)$(bindir)/xowish #======================================================================== # TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our # package without installing. The other environment variables allow us # to test against an uninstalled Tcl. Add special env vars that you # require for testing here (like TCLX_LIBRARY). #======================================================================== EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR) TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` \ @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \ PATH="$(EXTRA_PATH):$(PATH)" \ TCLLIBPATH="$(top_builddir) ${srcdir} $(TCLLIBPATH)" \ TCL_PKG_PREFER_LATEST=1 TCLSH_PROG = @TCLSH_PROG@ TCLSH = $(TCLSH_ENV) $(TCLSH_PROG) #TCLSH = $(TCLSH_ENV) LD_PRELOAD="$(srcdir)/$(PKG_LIB_FILE)" valgrind --log-fd=9 --leak-check=full --track-origins=yes --show-possibly-lost=no $(TCLSH_PROG) 9>>valgrind.out SHARED_BUILD = @SHARED_BUILD@ INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ @NSF_BUILD_INCLUDE_SPEC@ EXTRA_CFLAGS = @PKG_CFLAGS@ # TCL_DEFS is not strictly needed here, but if you remove it, then you # must make sure that configure.in checks for the necessary components # that your library may use. TCL_DEFS can actually be a problem if # you do not compile with a similar machine setup as the Tcl core was # compiled with. #DEFS = $(TCL_DEFS) @DEFS@ $(EXTRA_CFLAGS) DEFS = @DEFS@ $(EXTRA_CFLAGS) CONFIG_CLEAN_FILES = @CONFIG_CLEAN_FILES@ CPPFLAGS = @CPPFLAGS@ LIBS = @PKG_LIBS@ @LIBS@ AR = @AR@ CFLAGS = $(CFLAGS_OPTIMIZE) $(CFLAGS_WARNING) @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) #======================================================================== # Start of user-definable TARGETS section #======================================================================== EXAMPLE_SCRIPTS = \ $(src_doc_dir)/example-scripts/bagel.html \ $(src_doc_dir)/example-scripts/container.html \ $(src_doc_dir)/example-scripts/per-object-mixins.html \ $(src_doc_dir)/example-scripts/tutorial-properties.html \ $(src_doc_dir)/example-scripts/rosetta-abstract-type.html \ $(src_doc_dir)/example-scripts/rosetta-classes.html \ $(src_doc_dir)/example-scripts/rosetta-constraint-genericity.html \ $(src_doc_dir)/example-scripts/rosetta-delegates.html \ $(src_doc_dir)/example-scripts/rosetta-polymorphism.html \ $(src_doc_dir)/example-scripts/rosetta-serialization.html \ $(src_doc_dir)/example-scripts/rosetta-singleton.html \ $(src_doc_dir)/example-scripts/rosetta-sudoku.html \ $(src_doc_dir)/example-scripts/rosetta-unknown-method.html \ $(src_doc_dir)/example-scripts/ruby-mixins.html \ $(src_doc_dir)/example-scripts/starmethod.html \ $(src_doc_dir)/example-scripts/tk-horse-race.html \ $(src_doc_dir)/example-scripts/tk-locomotive.html \ $(src_doc_dir)/example-scripts/tk-ludo.html \ $(src_doc_dir)/example-scripts/tk-geo.html \ $(src_doc_dir)/example-scripts/tk-mini.html \ $(src_doc_dir)/example-scripts/tk-spread.html \ $(src_doc_dir)/example-scripts/traits-composite.html \ $(src_doc_dir)/example-scripts/traits-simple.html \ $(src_doc_dir)/example-scripts/rosetta-tokenizer.html \ $(src_doc_dir)/example-scripts/rosetta-tree.html \ $(src_doc_dir)/example-scripts/rosetta-multiple-distinct.html \ $(src_doc_dir)/example-scripts/rosetta-add-variable.html \ $(src_doc_dir)/example-scripts/rosetta-clone.html \ $(src_doc_dir)/example-scripts/rosetta-multiple-inheritance.html \ $(src_doc_dir)/example-scripts/rosetta-single-inheritance.html %.html : %.tcl $(TCLSH) $(src_app_dir_native)/utils/source-doc-beautifier.tcl $< $(ASCIIDOC) $*.txt #======================================================================== # TEA TARGETS. Please note that the "libraries:" target refers to platform # independent files, and the "binaries:" target includes executable programs and # platform-dependent libraries. Modify these targets so that they install # the various pieces of your package. The make and install rules # for the BINARIES that you specified above have already been done. #======================================================================== all: binaries libraries end #======================================================================== # The binaries target builds executable programs, Windows .dll's, unix # shared/static libraries, and any other platform-dependent files. # The list of targets to build for "binaries:" is specified at the top # of the Makefile, in the "BINARIES" variable. #======================================================================== binaries: $(BINARIES) pkgIndex.tcl @if test ! "x$(subdirs)" = "x" ; then dirs="$(subdirs)" ; \ for dir in $$dirs ; do \ if (cd $$dir; $(MAKE) $@) ; then true ; else exit 1 ; fi ; \ done; fi; libraries: libraries-pkgindex @if test ! "x$(subdirs)" = "x" ; then dirs="$(subdirs)" ; \ for dir in $$dirs ; do \ if (cd $$dir; $(MAKE) $@) ; then true ; else exit 1 ; fi ; \ done; fi; cppcheck: $(CPPCHECK) \ --enable=all generic/*.c \ $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) \ -DNDEBUG=1 -I/usr/include -D__x86_64__ #CLANG_TIDY_CHECKS=-checks=-*,modernize-*,performance-*,portability-*,cert-* #CLANG_TIDY_CHECKS=-checks=-*,bugprone-* CLANG_TIDY_CHECKS= clang-tidy: clang-tidy-mp-14 \ generic/nsf.c \ generic/nsfError.c \ generic/nsfObjectData.c \ generic/nsfProfile.c \ generic/nsfDebug.c\ generic/nsfUtil.c \ generic/nsfObj.c \ generic/nsfPointer.c \ generic/nsfEnumerationType.c \ generic/nsfCmdDefinitions.c \ generic/nsfFunPtrHashTable.c \ generic/nsfShadow.c \ generic/nsfCompile.c \ generic/aolstub.c \ $(CLANG_TIDY_CHECKS) -header-filter=.* -- \ $(INCLUDES) -I/usr/include $(DEFS) etags: etags --language=none \ --regex='/[ \t]*\(proc\)[ \t]+\([^ \t]+\)/\2/' \ --regex='/[ \t]*[:]?\(public \|protected \|private \|\)[ \t]*\(method\|object method\)[ \t]+\([^ \t]+\)/\3/' \ --regex='/[ \t]*[a-zA-Z:0-9]+[^ \t]\(public \|protected \|private \|\)[ \t]*\(method\)[ \t]+\([^ \t]+\)/\3/' \ --regex='/[ \t]*[a-zA-Z:0-9]+[^ \t]+\(proc\|instproc\)[ \t]+\([^ \t]+\)/\3/' \ `find . -name \*.tcl -or -name \*.test` libraries-pkgindex: pkgIndex.tcl $(TCLSH) $(src_lib_dir_native)/lib/mkIndex.tcl -dir $(src_lib_dir_native) full-doc: doc pdfdoc example-doc # use language reference as sample file to trigger generation of documentation files #doc: $(xotcl_target_doc_dir)/langRef-xotcl.html # for now, just the two doc files doc: $(ASCIIDOC) -a stylesheet=$(abspath $(src_doc_dir))/nx.css $(src_doc_dir)/next-migration.txt #$(ASCIIDOC) -a stylesheet=$(abspath $(src_doc_dir))/nx-small.css $(src_doc_dir)/next-tutorial/next-tutorial.txt $(ASCIIDOC) -a stylesheet=$(abspath $(src_doc_dir))/nx.css $(src_doc_dir)/next-tutorial/next-tutorial.txt pdfdoc: (cd $(src_doc_dir); \ $(CHROME) --headless --disable-gpu --print-to-pdf-no-header --print-to-pdf=next-migration.pdf next-migration.html) (cd $(src_doc_dir)/next-tutorial; \ $(CHROME) --headless --disable-gpu --print-to-pdf-no-header --print-to-pdf=next-tutorial.pdf next-tutorial.html) example-doc: $(EXAMPLE_SCRIPTS) $(xotcl_target_doc_dir)/langRef-xotcl.html: \ pkgIndex.tcl \ $(xotcl_src_doc_dir)/langRef.xotcl \ $(XODOC_SOURCE) @docs=""; \ for i in $(XODOC_SOURCE); do docs="$$docs `@CYGPATH@ $$i`"; done; \ $(TCLSH) $(xotcl_src_lib_dir)/lib/makeDoc.xotcl \ $(xotcl_target_doc_dir) $$docs pdf: -(cd $(src_doc_dir); htmldoc --webpage --format pdf14 --title \ -f tutorial.pdf tutorial.html ) -(cd $(src_doc_dir); htmldoc --webpage --format pdf14 \ -f langRef-xotcl.pdf langRef-xotcl.html ) NX_MAN3 = \ $(src_doc_dir)/Object.man \ $(src_doc_dir)/Class.man \ $(src_doc_dir)/configure.man \ $(src_doc_dir)/current.man \ $(src_doc_dir)/next.man NX_MAN1 = \ $(src_doc_dir)/nxsh.man \ $(src_doc_dir)/xotclsh.man \ $(src_doc_dir)/nxwish.man \ $(src_doc_dir)/xowish.man man: man-html man-nroff man-pdf man-html: $(NX_MAN3:%.man=%.html) $(src_doc_dir)/%.html: $(src_doc_dir)/%.man @for m in $(?F) ; do \ echo " Generating html manpage from $$m" ; \ (cd $(src_doc_dir); $(DTPLITE) -style man.css -o . html $$m) ; \ done; man-nroff : man1 man3 man1 : $(NX_MAN1:%.man=%.1) $(src_doc_dir)/%.1 : $(src_doc_dir)/%.man @for m in $(?F) ; do \ echo " Generating nroff manpage (Section 1) from $$m" ; \ (cd $(src_doc_dir); $(DTPLITE) -ext 1 -o . nroff $$m) ; \ done; man3: $(NX_MAN3:%.man=%.3) $(src_doc_dir)/%.3 : $(src_doc_dir)/%.man @for m in $(?F) ; do \ echo " Generating nroff manpage (Section 3) from $$m" ; \ (cd $(src_doc_dir); $(DTPLITE) -ext 3 -o . nroff $$m) ; \ done; man-pdf: $(NX_MAN3:%.man=%.pdf) $(src_doc_dir)/%.pdf : $(src_doc_dir)/%.html @files=$(basename $(?F)); \ for m in $$files ; do \ echo " Generating pdf manpage for $$m" ; \ (cd $(src_doc_dir); $(CHROME) --headless --disable-gpu --print-to-pdf-no-header --print-to-pdf=$$m.pdf $$m.html) ; \ done; install: install-binaries install-shells \ install-libraries install-pkgIndex install-doc \ install-xotcl-shells \ install-xotcl-libraries @if test ! "x$(subdirs)" = "x" ; then dirs="$(subdirs)" ; \ for dir in $$dirs ; do \ if (cd $$dir; $(MAKE) $@) ; then true ; else exit 1 ; fi ; \ done; fi; install-binaries: binaries install-lib-binaries install-bin-binaries install-aol: install-binaries install-libraries install-xotcl-libraries @if test -d $(DESTDIR)/$(aol_prefix)/modules/tcl/; then \ $(INSTALL) $(src_generic_dir)/aol-xotcl.tcl \ $(DESTDIR)/$(aol_prefix)/modules/tcl/xotcl.tcl ; \ else \ $(INSTALL) $(src_generic_dir)/aol-xotcl.tcl \ $(DESTDIR)/$(aol_prefix)/tcl/xotcl.tcl ; \ fi; #======================================================================== # This rule installs platform-independent files, such as header files. #======================================================================== install-libraries: libraries @$(INSTALL_DATA_DIR) $(DESTDIR)$(includedir) @echo "Installing header files in $(DESTDIR)$(includedir)" @for i in $(PKG_HEADERS) ; do \ echo " Installing $$i" ; \ $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir) ; \ done; @$(INSTALL_DATA_DIR) $(DESTDIR)$(pkglibdir) @echo "Installing Libraries to $(DESTDIR)$(pkglibdir)/" @for i in $(libdirs) ; do \ echo " Installing $$i/" ; \ rm -rf $(DESTDIR)$(pkglibdir)/$$i ; \ mkdir -p $(DESTDIR)$(pkglibdir)/$$i; \ chmod 755 $(DESTDIR)$(pkglibdir)/$$i; \ for j in $(src_lib_dir)/$$i/*.*tcl ; do \ $(INSTALL_DATA) $$j $(DESTDIR)$(pkglibdir)/$$i/; \ done; \ done; @for i in $(libsrc) ; do \ echo " Installing $$i" ; \ rm -rf $(DESTDIR)$(pkglibdir)/$$i ; \ $(INSTALL_DATA) $(src_lib_dir)/$$i $(DESTDIR)$(pkglibdir)/$$i ; \ done; @mkdir -p $(DESTDIR)$(libdir)/tcl8/site-tcl @for i in $(srcdir)/tcl8/site-tcl/*.tm ; do \ if test -f $$i; then \ echo " Installing module $$i in $(DESTDIR)$(libdir)/tcl8/site-tcl";\ $(INSTALL_DATA) $$i $(DESTDIR)$(libdir)/tcl8/site-tcl/; \ fi; \ done; @$(INSTALL_DATA) $(srcdir)/nsfConfig.sh $(DESTDIR)$(libdir)/ install-xotcl-libraries: install-libraries @$(INSTALL_DATA_DIR) $(DESTDIR)$(pkglibdir) @echo "Installing XOTcl Libraries to $(DESTDIR)$(xotcl_pkglibdir)/" @rm -rf $(DESTDIR)$(xotcl_pkglibdir) @mkdir -p $(DESTDIR)$(xotcl_pkglibdir) @chmod 755 $(DESTDIR)$(xotcl_pkglibdir) @for i in $(xotcl_libdirs) ; do \ echo " Installing library $$i/" ; \ rm -rf $(DESTDIR)$(xotcl_pkglibdir)/$$i ; \ mkdir -p $(DESTDIR)$(xotcl_pkglibdir)/$$i; \ chmod 755 $(DESTDIR)$(xotcl_pkglibdir)/$$i; \ for j in $(xotcl_src_lib_dir)/$$i/*.*tcl ; do \ $(INSTALL_DATA) $$j $(DESTDIR)$(xotcl_pkglibdir)/$$i/; \ done; \ done; @for i in $(xotcl_libsrc) ; do \ echo " Installing $$i" ; \ rm -rf $(DESTDIR)$(xotcl_pkglibdir)/$$i ; \ $(INSTALL_DATA) $(xotcl_src_lib_dir)/$$i $(DESTDIR)$(xotcl_pkglibdir)/$$i;\ done; install-xotcl-shells: @if test -f $(xotcl_srcdir)/xotclsh; then \ $(INSTALL_PROGRAM) $(xotcl_srcdir)/xotclsh $(DESTDIR)$(bindir);\ fi @if test -f $(xotcl_srcdir)/xowish; then \ $(INSTALL_PROGRAM) $(xotcl_srcdir)/xowish $(DESTDIR)$(bindir); \ fi install-xotcl-apps: install-xotcl-libraries @echo "Installing Applications to $(DESTDIR)$(xotcl_pkglibdir)/apps/" @for i in $(xotcl_appdirs) ; do \ echo " Installing apps $$i/" ; \ rm -rf $(DESTDIR)$(xotcl_pkglibdir)/apps/$$i ; \ mkdir -p $(DESTDIR)$(xotcl_pkglibdir)/apps/$$i; \ chmod 755 $(DESTDIR)$(xotcl_pkglibdir)/apps/$$i; \ for j in $(src_app_dir)/$$i/* ; do \ if test -d $$j; then \ mkdir -p $(DESTDIR)$(xotcl_pkglibdir)/$$j; \ chmod 755 $(DESTDIR)$(xotcl_pkglibdir)/$$j; \ for k in $$j/* ; do \ $(INSTALL) $$k $(DESTDIR)$(xotcl_pkglibdir)/$$j ; \ done; \ else \ $(INSTALL) $$j $(DESTDIR)$(xotcl_pkglibdir)/apps/$$i/; \ fi; \ done; \ done; @for i in $(xotcl_appsrc) ; do \ echo " Installing $$i" ; \ rm -rf $(DESTDIR)$(xotcl_pkglibdir)/apps/$$i ; \ $(INSTALL_DATA) $(src_app_dir)/$$i $(DESTDIR)$(xotcl_pkglibdir)/apps;\ done; @rm -rf $(DESTDIR)$(xotcl_pkglibdir)/store/XOTclGdbm @rm -rf $(DESTDIR)$(xotcl_pkglibdir)/store/XOTclSdbm @rm -rf $(DESTDIR)$(xotcl_pkglibdir)/xml/TclExpat-1.1 #======================================================================== # Install documentation. Unix manpages should go in the $(DESTDIR)$(mandir) # directory. #======================================================================== # install-doc: $(DESTDIR)$(mandir)/man1 $(DESTDIR)$(mandir)/man3 $(DESTDIR)$(mandir)/mann # @(cd $(src_man_dir)/ ; \ # for i in *.1; do \ # echo "Installing $$i"; \ # rm -f $(DESTDIR)$(mandir)/man1/$$i; \ # sed -e '/man\.macros/r man.macros' -e '/man\.macros/d' \ # $$i > $(DESTDIR)$(mandir)/man1/$$i; \ # chmod 444 $(DESTDIR)$(mandir)/man1/$$i; \ # done) install-doc: @$(INSTALL_DATA_DIR) $(DESTDIR)$(mandir)/man1 @echo "Installing documentation in $(DESTDIR)$(mandir)" @list='$(srcdir)/doc/*.1'; for i in $$list; do \ echo "Installing $$i"; \ $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/man1 ; \ done @$(INSTALL_DATA_DIR) $(DESTDIR)$(mandir)/man3 @list='$(srcdir)/doc/*.3'; for i in $$list; do \ echo "Installing $$i"; \ $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/man3 ; \ done shell: binaries libraries @$(TCLSH) $(SCRIPT) gdb: $(TCLSH_ENV) gdb $(TCLSH_PROG) $(SCRIPT) lldbtest: $(MAKE) "TCLSH_PROG=lldb -b -o run -- $(TCLSH_PROG)" test test: binaries libraries test-core test-xotcl test-http @test_actiweb@ @if test ! "x$(subdirs)" = "x" ; then dirs="$(subdirs)" ; \ for dir in $$dirs ; do \ if (cd $$dir; $(MAKE) $@) ; then true ; else exit 1 ; fi ; \ done; fi @$(TCLSH) $(src_test_dir_native)/summary.tcl \ -title NX+XOTcl \ -libdir $(PLATFORM_DIR) $(TESTFLAGS) test-nohttp: binaries libraries test-core test-xotcl TESTLOG = ./__test.log TESTFLAGS = -testlog $(TESTLOG) test-summary: $(TCLSH) $(src_test_dir_native)/summary.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) test-core: rm -f $(TESTLOG) $(TCLSH) $(src_test_dir_native)/object-system.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/destroy.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/methods.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/method-parameter.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/nsf-cmd.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/accessor.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/cget.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/properties.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/var-access.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/varresolution.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/info-method.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/submethods.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/info-variable.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/disposition.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/volatile.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/parameters.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/returns.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/method-require.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/interceptor-slot.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/alias.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/double-alias.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/protected.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/forward.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/mixinof.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/tcl86.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/contains.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/tcloo.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/interp.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/serialize.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/plain-object-method.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/class-method.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/linearization.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/traits.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/shells.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/msgcat.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/bagel.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/container.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/rosetta-abstract-type.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/rosetta-classes.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/rosetta-constraint-genericity.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/rosetta-delegates.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/rosetta-polymorphism.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/rosetta-serialization.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/rosetta-singleton.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/rosetta-unknown-method.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/ruby-mixins.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/traits-composite.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/traits-simple.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/rosetta-tokenizer.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/rosetta-tree.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/rosetta-multiple-distinct.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/rosetta-add-variable.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/rosetta-clone.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/rosetta-multiple-inheritance.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_doc_dir_native)/example-scripts/rosetta-single-inheritance.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) test-xotcl: $(TCLSH) $(xotcl_src_test_dir)/testo.xotcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(xotcl_src_test_dir)/speedtest.xotcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(xotcl_src_test_dir)/testx.xotcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(xotcl_src_test_dir)/slottest.xotcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) test-http: $(TCLSH) $(xotcl_src_test_dir)/xocomm.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) test-actiweb: $(TCLSH) $(xotcl_src_test_dir)/actiweb.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(xotcl_src_test_dir)/persistence.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(xotcl_src_test_dir)/UNIVERSAL.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(xotcl_src_test_dir)/xoRDF.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) @rm -rf receiver depend: #======================================================================== # $(PKG_LIB_FILE) should be listed as part of the BINARIES variable # mentioned above. That will ensure that this target is built when you # run "make binaries". # # The $(PKG_OBJECTS) objects are created and linked into the final # library. In most cases these object files will correspond to the # source files above. #======================================================================== $(PKG_LIB_FILE): $(PKG_OBJECTS) -rm -f $(PKG_LIB_FILE) ${MAKE_LIB} $(RANLIB) $(PKG_LIB_FILE) $(PKG_STUB_LIB_FILE): $(PKG_STUB_OBJECTS) -rm -f $(PKG_STUB_LIB_FILE) ${MAKE_STUB_LIB} $(RANLIB_STUB) $(PKG_STUB_LIB_FILE) #======================================================================== # We need to enumerate the list of .c to .o lines here. # # In the following lines, $(srcdir) refers to the toplevel directory # containing your extension. If your sources are in a subdirectory, # you will have to modify the paths to reflect this: # # sample.$(OBJEXT): $(srcdir)/generic/sample.c # $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@ # # Setting the VPATH variable to a list of paths will cause the makefile # to look into these paths when resolving .c to .obj dependencies. # As necessary, add $(srcdir):$(srcdir)/compat:.... #======================================================================== VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win .c.@OBJEXT@: $(COMPILE) -c `@CYGPATH@ $<` -o $@ #======================================================================== # next shells #======================================================================== pkgIndex.tcl: $(PKG_LIB_FILE) @echo "if {[package vsatisfies [package provide Tcl] 9]} {" > pkgIndex.tcl @echo " package ifneeded @PACKAGE_NAME@ @PACKAGE_VERSION@ \\" >> pkgIndex.tcl @echo " \"[list load [file join \$$dir @PKG_LIB_FILE9@]];" >> pkgIndex.tcl @echo " [list package provide @PACKAGE_NAME@ @PACKAGE_VERSION@]\"" >> pkgIndex.tcl @echo "} else {" >> pkgIndex.tcl @echo " package ifneeded @PACKAGE_NAME@ @PACKAGE_VERSION@ \\" >> pkgIndex.tcl @echo " \"[list load [file join \$$dir @PKG_LIB_FILE8@]];" >> pkgIndex.tcl @echo " [list package provide @PACKAGE_NAME@ @PACKAGE_VERSION@]\"" >> pkgIndex.tcl @echo "}" >> pkgIndex.tcl install-pkgIndex: pkgIndex.tcl @echo " Adding to pkgIndex.tcl for @PACKAGE_NAME@ in $(DESTDIR)$(pkglibdir)/pkgIndex.tcl" @echo "" >> $(DESTDIR)$(pkglibdir)/pkgIndex.tcl @cat $< >> $(DESTDIR)$(pkglibdir)/pkgIndex.tcl #nxsh: tclAppInit.o $(PKG_OBJECTS) $(CONDITIONAL_STUB_OBJECTS) # $(CC) -rdynamic -o $@ tclAppInit.o \ # $(CFLAGS) $(TCL_LIB_SPEC) \ # $(DMALLOC_LIB) $(CONDITIONAL_STUB_OBJECTS) #xowish: tkAppInit.o $(PKG_OBJECTS) $(CONDITIONAL_STUB_OBJECTS) # $(CC) -rdynamic -o $@ tkAppInit.o \ # $(PKG_OBJECTS) \ # $(CFLAGS) $(TCL_LIB_SPEC) $(TK_LIB_SPEC) \ # $(DMALLOC_LIB) $(CONDITIONAL_STUB_OBJECTS) install-shells: @if test -f nxsh; then \ $(INSTALL_PROGRAM) nxsh $(DESTDIR)$(bindir); \ fi @if test -f nxwish; then \ $(INSTALL_PROGRAM) nxwish $(DESTDIR)$(bindir); \ fi #======================================================================== # We need to enumerate the list of .c to .o lines here. # Unfortunately, there does not seem to be any other way to do this # in a Makefile-independent way. We can't use VPATH because it picks up # object files that may be located in the source directory. # # In the following lines, $(srcdir) refers to the toplevel directory # containing your extension. If your sources are in a subdirectory, # you will have to modify the paths to reflect this: # # exampleA.$(OBJEXT): $(srcdir)/src/win/exampleA.c # $(COMPILE) -c `@CYGPATH@ $(srcdir)/src/win/exampleA.c` -o $@ #======================================================================== $(src_generic_dir)/predefined.h: \ $(src_generic_dir)/mk_predefined.tcl \ $(src_generic_dir)/predefined_part1.tcl \ $(src_generic_dir)/predefined_part2.tcl (cd $(src_generic_dir); \ $(TCLSH) mk_predefined.tcl \ predefined_part1.tcl \ predefined_part2.tcl \ > predefined.h) $(src_generic_dir)/nsfAPI.h: \ $(src_generic_dir)/gentclAPI.tcl \ $(src_generic_dir)/nsfAPI.decls $(TCLSH) $(src_generic_dir)/gentclAPI.tcl \ $(src_generic_dir)/nsfAPI.decls > $(src_generic_dir)/nsfAPI.h aolstub.$(OBJEXT): $(src_generic_dir)/aolstub.c $(PKG_HEADERS) nsf.$(OBJEXT): $(PKG_HEADERS) \ $(src_generic_dir)/nsf.c \ $(src_generic_dir)/predefined.h \ $(src_generic_dir)/nsfAccessInt.h \ $(src_generic_dir)/nsfAPI.h \ $(src_generic_dir)/nsfStack.c \ $(src_generic_dir)/asm/nsfAssemble.c \ $(src_generic_dir)/asm/nsfAsmExecuteCallThreading.c \ $(src_generic_dir)/asm/nsfAsmExecuteLabelThreading.c \ $(src_generic_dir)/asm/nsfAsmAssemble.c \ $(DTRACE_HDR) nsfDebug.$(OBJEXT): $(src_generic_dir)/nsfDebug.c $(PKG_HEADERS) nsfError.$(OBJEXT): $(src_generic_dir)/nsfError.c $(PKG_HEADERS) nsfMetaData.$(OBJEXT): $(src_generic_dir)/nsfMetaData.c $(PKG_HEADERS) nsfObj.$(OBJEXT): $(src_generic_dir)/nsfObj.c $(PKG_HEADERS) nsfObjectData.$(OBJEXT): $(src_generic_dir)/nsfObjectData.c $(PKG_HEADERS) nsfPointer.$(OBJEXT): $(src_generic_dir)/nsfPointer.c $(PKG_HEADERS) nsfEnumerationType.$(OBJEXT): $(src_generic_dir)/nsfEnumerationType.c $(PKG_HEADERS) nsfProfile.$(OBJEXT): $(src_generic_dir)/nsfProfile.c $(PKG_HEADERS) nsfShadow.$(OBJEXT): $(src_generic_dir)/nsfShadow.c $(PKG_HEADERS) $(stubdir)/nsfStubInit.$(OBJEXT): $(PKG_HEADERS) nsfStubLib.$(OBJEXT): $(src_generic_dir)/nsfStubLib.c $(PKG_HEADERS) nsfUtil.$(OBJEXT): $(src_generic_dir)/nsfUtil.c $(PKG_HEADERS) # # Target to regenerate header files and stub files from the *.decls tables. # TCL_SRC_DIR_85=/usr/local/src/tcl8.5.19 TCL_SRC_DIR_86=/usr/local/src/tcl8.6.8 TCL_SRC_DIR_87=/usr/local/src/core-8-branch genstubs: $(src_generic_dir)/nsf.decls mkdir -p $(src_generic_dir)/stubs8.5 tclsh8.5 $(TCL_SRC_DIR_85)/tools/genStubs.tcl \ $(src_generic_dir)/stubs8.5 \ $(src_generic_dir)/nsf.decls $(src_generic_dir)/nsfInt.decls mkdir -p $(src_generic_dir)/stubs8.6 tclsh8.6 $(TCL_SRC_DIR_86)/tools/genStubs.tcl \ $(src_generic_dir)/stubs8.6 \ $(src_generic_dir)/nsf.decls $(src_generic_dir)/nsfInt.decls mkdir -p $(src_generic_dir)/stubs8.7 tclsh8.7 $(TCL_SRC_DIR_87)/tools/genStubs.tcl \ $(src_generic_dir)/stubs8.7 \ $(src_generic_dir)/nsf.decls $(src_generic_dir)/nsfInt.decls getstubs: $(TCLSH) $(src_app_dir_native)/utils/getstubs.tcl $(src_generic_dir) # # Target to check that all exported functions have an entry in the stubs # tables. # checkstubs: -@for i in `nm -p $(PKG_LIB_FILE) | awk '$$2 ~ /T/ { print $$3 }' \ | sort -n`; do \ match=0; \ for j in $(TCL_DECLS); do \ if [ `grep -c $$i $$j` -gt 0 ]; then \ match=1; \ fi; \ done; \ if [ $$match -eq 0 ]; then echo $$i; fi \ done # DTrace support $(DTRACE_HDR): $(DTRACE_SRC) $(DTRACE) -h $(DTRACE_SWITCHES) -o $@ -s $(DTRACE_SRC) $(DTRACE_OBJ): $(DTRACE_SRC) $(TCL_OBJS) $(DTRACE_HDR) $(DTRACE) -G $(DTRACE_SWITCHES) -o $@ -s $(DTRACE_SRC) $(TCL_OBJS) #======================================================================== # End of user-definable section #======================================================================== #======================================================================== # Don't modify the file to clean here. Instead, set the "CLEANFILES" # variable in configure.in #======================================================================== cleandoc: -rm -rf $(xotcl_target_doc_dir)/*-xotcl.html clean: cleandoc -rm -rf $(BINARIES) $(CLEANFILES) \ generic/stub*/*.o ./receiver $(TESTLOG) find ${srcdir} -type f -name \*~ -exec rm \{} \; @if test ! "x$(subdirs)" = "x" ; then dirs="$(subdirs)" ; \ for dir in $$dirs ; do \ if (cd $$dir; $(MAKE) $@) ; then true ; else exit 1 ; fi ; \ done; fi distclean: clean -rm -rf $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log config.status @if test ! "x$(subdirs)" = "x" ; then dirs="$(subdirs)" ; \ for dir in $$dirs ; do \ if (cd $$dir; $(MAKE) $@) ; then true ; else exit 1 ; fi ; \ done; fi #======================================================================== # Install binary object libraries. On Windows this includes both .dll and # .lib files. Because the .lib files are not explicitly listed anywhere, # we need to deduce their existence from the .dll file of the same name. # Library files go into the lib directory. # # A manual generation of the pkgIndex files via tclsh should look like # pkg_mkIndex -direct -verbose library/lib *tcl # # In addition, this will generate the pkgIndex.tcl # file in the install location (assuming it can find a usable tclsh shell) # # You should not have to modify this target. #======================================================================== install-lib-binaries: @mkdir -p $(DESTDIR)$(pkglibdir) @list='$(lib_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p";\ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p;\ stub=`echo $$p|sed -e "s/.*\(stub\).*/\1/"`;\ if test "x$$stub" = "xstub"; then \ echo " $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p";\ $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p;\ else \ echo " $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p";\ $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p;\ ln -s $(DESTDIR)$(pkglibdir)/$$p $(DESTDIR)$(libdir)/$$p;\ fi; \ ext=`echo $$p|sed -e "s/.*\.//"`;\ if test "x$$ext" = "xdll"; then \ lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib;\ if test -f $$lib; then \ echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib";\ $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib;\ fi; \ fi; \ fi; \ done @list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ if test -f $(srcdir)/$$p; then \ destp=`basename $$p`;\ echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp";\ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp;\ fi; \ done #======================================================================== # Install binary executables (e.g. .exe files and dependent .dll files) # This is for files that must go in the bin directory (located next to # wish and tclsh), like dependent .dll files on Windows. # # You should not have to modify this target, except to define bin_BINARIES # above if necessary. #======================================================================== install-bin-binaries: @$(INSTALL_DATA_DIR) $(DESTDIR)$(bindir) @list='$(bin_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \ fi; \ done .SUFFIXES: .c .$(OBJEXT) #Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status # cd $(top_builddir) \ # && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status uninstall-binaries: list='$(lib_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ p=`basename $$p`; \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(bin_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(bindir)/$$p; \ done end: @echo "" @echo "***************************************************************" @echo " Make completed. In order to test the Next Scripting Framework," @echo " invoke:" @echo " make test" @echo "" @echo " To install, use:" @echo " make install" @echo "" @echo " To install for AOLserver 4.x, use:" @echo " make install-aol" @echo "" @echo " In order to invoke NX interactively (before install), use:" @echo " export TCLLIBPATH=\"$(TCLLIBPATH)\" TCL8_5_TM_PATH=\"$(TCLLIBPATH)\"/tcl8/site-tcl" @echo " and" @echo " @TCLSH_PROG@" @echo " package require nx" @echo "***************************************************************" RPMSOURCES=/usr/src/redhat/SOURCES RPMSPECS=/usr/src/redhat/SPECS rpm: @if test ! -d $(RPMSOURCES); then mkdir -p $(RPMSOURCES); fi @if test ! -d $(RPMSPECS); then mkdir -p $(RPMSPECS); fi cp unix/xotcl.spec $(RPMSPECS)/xotcl-$(PACKAGE_VERSION).spec make tar cp ../xotcl-$(PACKAGE_VERSION).tar.gz $(RPMSOURCES) rpmbuild -ba $(RPMSPECS)/xotcl-$(PACKAGE_VERSION).spec bin-tar: (cd ..; tar zcvf xotcl-$(PACKAGE_VERSION)-bin-linux-i686-glibc.tar.gz \ `find \ $(prefix)/bin/nx*sh \ $(prefix)/bin/xotcl*sh \ $(prefix)/lib/nsf* \ $(prefix)/lib/libnsf* \ $(prefix)/include/nsf*.h \ $(DESTDIR)$(pkglibdir) $(prefix)/man/man1/nsf* \ -type f -o -type l | fgrep -v CVS | fgrep -v SCCS \ | fgrep -v .junk| fgrep -v .db \ | fgrep -v "~" | fgrep -v "#" | fgrep -v /receiver/` \ ) tar: libraries-pkgindex echo @NSF_COMMIT@ > COMMIT sh $(srcdir)/tclconfig/mktar.sh .PHONY: all binaries clean depend distclean doc install libraries \ test test-core test-actiweb # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: ./nsf2.4.0/.travis.yml000644 000766 000024 00000011416 13670420474 015313 0ustar00neumannstaff000000 000000 language: c sudo: false env: global: - KITS=$HOME/kits branches: only: - master - 2.2 - 2.3 matrix: include: # ---------------------------- - os: linux dist: xenial compiler: clang env: TCLTAG=core-8-branch - os: linux dist: xenial compiler: gcc-7 addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++-7 env: TCLTAG=core-8-branch - os: osx osx_image: xcode11.3 compiler: clang env: TCLTAG=core-8-branch - os: osx osx_image: xcode11.3 compiler: gcc-9 env: TCLTAG=core-8-branch # ---------------------------- - os: linux dist: xenial compiler: clang env: TCLTAG=core-8-7-a3 - os: linux dist: xenial compiler: gcc-7 addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++-7 env: TCLTAG=core-8-7-a3 - os: osx osx_image: xcode11.3 compiler: clang env: TCLTAG=core-8-7-a3 - os: osx osx_image: xcode11.3 compiler: gcc-9 env: TCLTAG=core-8-7-a3 # ---------------------------- - os: linux dist: xenial compiler: clang env: TCLTAG=core-8-5-19 - os: linux dist: xenial compiler: gcc-7 addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++-7 env: TCLTAG=core-8-5-19 - os: osx osx_image: xcode11.3 compiler: clang env: TCLTAG=core-8-5-19 - os: osx osx_image: xcode11.3 compiler: gcc-9 env: - TCLTAG=core-8-5-19 # ---------------------------- - os: linux dist: xenial compiler: clang env: TCLTAG=core-8-5-branch - os: linux dist: xenial compiler: gcc-7 addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++-7 env: TCLTAG=core-8-5-branch - os: osx osx_image: xcode11.3 compiler: clang env: TCLTAG=core-8-5-branch - os: osx osx_image: xcode11.3 compiler: gcc-9 env: - TCLTAG=core-8-5-branch # ---------------------------- - os: linux dist: xenial compiler: clang env: TCLTAG=core-8-6-10 - os: linux dist: xenial compiler: gcc-7 addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++-7 env: TCLTAG=core-8-6-10 - os: osx osx_image: xcode11.3 compiler: clang env: TCLTAG=core-8-6-10 - os: osx osx_image: xcode11.3 compiler: gcc-9 env: - TCLTAG=core-8-6-10 # ---------------------------- - os: linux dist: xenial compiler: clang env: TCLTAG=core-8-6-branch - os: linux dist: xenial compiler: gcc-7 addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++-7 env: TCLTAG=core-8-6-branch - os: osx osx_image: xcode11.3 compiler: clang env: TCLTAG=core-8-6-branch - os: osx osx_image: xcode11.3 compiler: gcc-9 env: TCLTAG=core-8-6-branch allow_failures: - env: TCLTAG=core-8-6-branch - env: TCLTAG=core-8-5-branch - env: TCLTAG=core-8-branch fast_finish: true cache: directories: - "$KITS" before_install: - openssl aes-256-cbc -K $encrypted_8d1065ce6623_key -iv $encrypted_8d1065ce6623_iv -in deploy_key.enc -out ./deploy_key -d - chmod 600 ./deploy_key - if echo "$TRAVIS_COMMIT_MESSAGE" | grep -F -q "[skip travis]" ; then echo "[skip travis] has been found, exiting" && exit 0 ; else echo "[skip travis] has not been found, continuing" ; fi install: - mkdir -p $KITS - if [ $TRAVIS_OS_NAME = linux ]; then URL=http://kitcreator.rkeene.org/kits/c8fe6fba3323b12b924b4a0716609abbaa00822c/tclkit; else URL=http://kitcreator.rkeene.org/kits/31eaf9ae17e769609700b41d1d3c9abeda27510d/tclkit; fi - if [ ! -f ${KITS}/tclkit.$TRAVIS_OS_NAME ]; then wget -O ${KITS}/tclkit.$TRAVIS_OS_NAME $URL && chmod +x ${KITS}/tclkit.$TRAVIS_OS_NAME; fi script: # - python3 -c 'import os,sys; os.set_blocking(sys.stdout.fileno(), True)' - python2 -c 'import os,sys,fcntl; flags = fcntl.fcntl(sys.stdout, fcntl.F_GETFL); fcntl.fcntl(sys.stdout, fcntl.F_SETFL, flags&~os.O_NONBLOCK);' - $KITS/tclkit.$TRAVIS_OS_NAME apps/build.tcl $HOME $TRAVIS_BUILD_DIR $TCLTAG after_success: - TARBALL="nsf_${TRAVIS_BRANCH}_${TCLTAG}_${TRAVIS_OS_NAME}_${CC}_$(date "+%Y%m%d")_${TRAVIS_BUILD_NUMBER}.tgz" - if [ -d $HOME/install ]; then tar -C $HOME/install -czf $TARBALL . && scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ./deploy_key $TARBALL sobernig@alice.wu.ac.at:/home/sobernig/builds; fi ./nsf2.4.0/aclocal.m4000644 000766 000024 00000001262 14274463622 015043 0ustar00neumannstaff000000 000000 # generated automatically by aclocal 1.16.5 -*- Autoconf -*- # Copyright (C) 1996-2021 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_include([m4/tcl.m4]) ./nsf2.4.0/nxsh.in000644 000766 000024 00000001251 13030507001 014464 0ustar00neumannstaff000000 000000 #! /bin/sh # Lookup a Tcl interpreter \ INTERP="tclsh@TCL_VERSION@"; \ INTERPS="@NSF_COMPATIBLE_TCLSH@ @TCL_EXEC_PREFIX@/bin/$INTERP"; \ for interp in $INTERPS; \ do if [ -x $interp ]; then INTERP=$interp; break; \ fi; done; \ exec $INTERP "$0" ${1+"$@"} # -*- tcl -*- # # Tiny scripted replacement of a binary nxsh. This script can be used # as interactive shell for testing or like a regular shell with the #! # markup in the first line of a script. It is designed to work with # multiple installed Tcl shells during development. # package require nx::shell 1.1 namespace import -force ::nx::* set exitCode [nx::shell run $argc $argv] exit $exitCode ./nsf2.4.0/deploy_key.appveyor.enc000644 000766 000024 00000006460 13454166031 017700 0ustar00neumannstaff000000 000000 r'#ފ- h%t^<[GxovMa+ٰ Ʃ+ɉM;rptͶO&Zn[^( \ ݆El,Sq|${ɰ#rι&:C yզL2> h G[᎟ј{tBbdYM`` eT!s#uרT-6ҘjaSen~,K@D`[ŔMo 5|9ي烸?}U&i9sGQȹ쁹5iER~=o^DiD7h۷n_fg2p]EG/:h0``'Y Ksle[}(\#7 Gxq`&`VN]Ҝ|gƤ"i'xTG tjOu@̺)_Pa(_z# +(lzx~\w*qKZ;a> ŝd 8lub@_'pd =H=*3Rg"FX}s3UMCyp]HaZ8}"o bMϝYy$Oʅ`L̟Ek~u.?Ҥy "//PwsGּɱBעw={ â0YZUx`; ecYgGH 96N*x uMzƄpluk~# e,IP_jb)*[{j(בnUW}ڒݔ4ӜAo.K4f2an[:+vsBF(S.=CLIUˆp&~Aj)z-鬆SGUزegs5TmU-_U>!X`_mڎ3AS Vj ܅VG] [mn:m˖kL,S{%bz'ޮxKpU=C#Ju#@S<:%{bZ+ge]SjЍHf+vGt_WVʝ(zG_7ǎQ"Q_:Sܶ-^[M9ՂL0Z?ׯw'!{d5#ji WT&ט19 ٱJ/uxw;䧕2(Z-Z/ݡ-ir2)[&oE-9]wKn,9SJ1>=s6P)GNqqd5ecTlbnCEQME _z$ f=Kq:)~OR1~SUC p8*ƄwBV b7;{l){c{PtVUx82rB! 'vꇤX$/.i-r..Pn:u/Pdo1(;w)@txViJCu{)\oQ# m<& p(Q=|YSB.4 Mb"lo!6b^F_xDN] J01v5wkHE|WmAռy?I p{]'l25s=loZ^2MH9KMl^UCgo];ܬ<sc<5kExy@쩄pKbP1fTkSPL2U.gU/n [/EH5Jq6.R_mZǽ~pEq2l@Eԁ < n`9ٟM)9QG8D~_ɿ:_./nsf2.4.0/autogen.sh000644 000766 000024 00000000134 12776662115 015201 0ustar00neumannstaff000000 000000 #!/bin/sh for pdir in `find . -name configure.ac` do (cd `dirname $pdir`; autoconf) done ./nsf2.4.0/README.aol000644 000766 000024 00000000472 13270041541 014622 0ustar00neumannstaff000000 000000 Starting with Aolserver 4.*/naviserver nsf can be loaded via package require. However, it is recommended to install the binaries under the aolserver directory. The recommended configuration is: ./configure --enable-threads --prefix=/usr/local/aolserver Then, you can do a make make install-aol

    6{\ >!r؍ >ZNz&IöH7CrҜflK2yJˡoL$Šoib@j./3=c*ڼ,ˢ_.9ٝWL+<+ AF;ޘCYn'%fKzf䏌^p.Q4)QE/j)\e[?{̛mu*Zn#8|"ѻyi3/⤇(L#۬tGǰD;yFzxM܂2bQ*f%W#rglv`"fbBYT ՑO5[]> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [265 0 R 266 0 R]>> endobj 265 0 obj <> endobj 266 0 obj <> endobj 267 0 obj <> stream x\n#}W um"^;8,^?j($Ԑ"C [S=֪$(nl*YNewq rjQZ.*ߦo:li-[UOwIomo>AߨG7vlykdM[+.y6:k`l,X{ט-ūպy_Ro"앷O~+~S5lR&E ZM/9LV16(,>'zfѫBݲjT.d-}ngӮ:MxX N~bNkhʥh]n-둝*8SACG}nnk0'atO ڭTO`b8`w/b}݆G,nݼ9j]L q Pc~l %0|j*6*ΉqQnaGˉ#Wݤ'-qtT٘( XC΍Cwj]q6g^d"zs`}J+cS9"zfֵQ1e5KQ9$1l1dp[{kxK6cWlė&]{@aumkEH!rΚ9o~6D~')bGwk߲Ƌ]3FRubb]iR,PsFF[zKU^e߱`?i^vM{W4E}얏 Qx5ݴ7skhX{Q5 cG 9<椎Xx/'B=vE')؜O9=g1M} )OB46=mk{M5 ֤PS㘠229IA+A|&iZʉPDr:g|imrI $q FtfŜ [vrj8e0s/zPh8;\O[]yaBs7S٠qr*(àىcwK!6tsk [ڵי AqOR,9T2[(N%$&voM 13f̷DX5?Q 1tʹ1j9Djkd݅ƌӆ"쏋} YL6A4ji&@4Hio`zK[Xw&oINK ȿFӱE#=ZNp XtD:K|KG9̎8j!F ^J,'D0z\"i.+R[vL .I}(CtaXG9Xͮ榻m1f0/n=QG9 >k'QQ@ANC/6#5\ARU9d6@njqk7Y4 Ya0NBr3HwagѺ&T'X5PexT.gDN ;b>/e 7ƴQq!17 3ƐfcP ʉh 耏rb9JaDࠃL]6XLT|"G9 DwF!F*ϔ,9c$SqD_o=-0xz=%g 8K-;#'?)4.(֗rm/T{n j=yfԷL'w8J} l>uO5C2~g׾%h+B7xo7 %RŚ^20%(Ka/׏ em淟s j.w:>!Gw{ ￿y߽yt;_@*mwb[?Fva{N4HvպCg,7,qB'P1pi1#rf37T1F!VƐ oF6 !O cR kS7{dkTgxo6h{oZMQjt]ElyG՟Z~ZV{LpeU 'ñGeTz,)Z4< %ӻ<JPl[r#Q>\I=F{t :Uݭl^kQC$T2?Qz g(&P ,yaIrP qVL,.ȡM+O}uTm׭%yDPm6VRD6Y뮛+V+!hm!RVDOYd"-lM$!߂|¢޽^N뇙bht.j̑ډ)w00%,y/l  KoUR2":.!z_fεil1q(N'0z11Q'-cJ)a#G#`yt c α 㹗bT8i~=kW_/{J;GtuSZ_Hғ(z I7.Yw_^}Co^sX/by|»w[r}29@֨! v1g?S޽sb~ է>_1_O~ړP.!?qc%'T^Z9PĩZ>Cm q" Qdz̠c9RjTgZۋ%>9Z0a=u886BuT-#>PY/^ >F :bC烊#J%^ RϚk7]spӦ.jQK/ y )5UgIs۰NNq)M8e*/9Cjf; (Y0QlْGz'%#mHL8LlŽ`Α wC.^zΗE!sCtДa<{_]?0(v}ߝ9 B(Oh;Frv݋H endstream endobj 268 0 obj 4249 endobj 34 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [269 0 R 270 0 R 271 0 R]>> endobj 269 0 obj <> endobj 270 0 obj <> endobj 271 0 obj <> endobj 273 0 obj <> stream xY˒۸W<O ow'^Õd1D8DcW9 ) B?}p}*W3QeaKxd&|LZ]qVKGɼλ6̓Rdd*|^i)#kaayfĴ%hg% S\m/gye'+\y9Ga4WH1].*gnxrqa{I[y=+ֲ.Hfxe=ᢌ"99LkS2c:Q. 6D\H/ך91>Y".9Q^:5)A5PԔwFgv9g] fSzRvRpRR?8G^p5f-J++~^æ:CQOu_/n%7mXL{o`?C9M+~u7ڿT맙r*0+f&VɊ`fs(Xˁʇvj]]|j[u7jő9F/RXW=Ʋ8 f +oDV,@nu?8EjUp8pfWbvElڇfw_ݾErx 23&GqVBYq2ƨ+x=?1vO$ _ͱ~NEJҽRtrYk4L۱6\#(Wu|))oc,rY;Y5ݡQ\ehsoL)3{ǬyLH$׉}^ DB0CvAJh)9\GJ5S4LYg(r:Q9-d[$-ڻ9#*+L0K^^遣bp W)jIJ#!jMRyr]\ IP2# '0R5& ^6킰 RuM2mKOYú X׋Hu{,:9z[!D~~Ȕ9d<٘!L L)HKN[EAS]'-CK8`6Y-LTL-]aAH" [4$k36:;XW>WCaʯiqOz)<(aBd޿dB;Ktbh`("9[$Z%jJvttp(Xe5)j8S c)1 פaնPI:8%f#E+tϪ"@3l٬0ָёiQ7/m)5ckɤlrSۄLat!1p\mSY#%hFD~AF(B:9H3\5k~"O3- F6!ѻi0pTBnERL $1qcqWm;_A:]uLN:Q fҳ.Rw2}w\ #Iu[p0a'YU_=*\Oy#? M(LKЖH`PCǥwD"phd"-uHmyb4Z_: _߾gI(]&8[fI4Kip (f~~MWJRCmxBFN[MxR'(ڍ,)E!zՐScoΓWb vAqw)f%/wGh` Coi19Ld%3S$Ss$~KnRRt+eҢU]bnli7#ExT楗bW6ejèwtո"z@.~]N8btZ1=zx_IC2gizq/g<=w߼Rͧ)w_on>$M+D:7Nu H +(rJHfvۛz6~񊀃uoǦߢ1G^1|qgq%5F<МQqD҅u~ľOȖO"ސ$<֔BUW]]V"L$I endstream endobj 274 0 obj 2351 endobj 35 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <>>> endobj 275 0 obj <> stream xYKoW4 7~{w`E:s#i$!.4j#Bw}͋a3 9gƘ/ڨ/B/jv/.p<~Yό'߸~s4og'^^'ncl =$-JEB>PÎpnza \|`p^q<̂>2;i %`ٻϞϾ~n6Ʌ-3-7+bU-?,͞-kբ.Wn6gvm]!N2#+7KV.ud.WlkneW;!s ֻ"o?DqBK9O]UTR8[psl9:׈:Gl~=N3"hJ.PRlz{hfU?Bi)&U! W*~[CCVo}YT-;-}pUl[uGIV}c( Ig쉸;ѳrC .4"BZQX% v؇nYOQ+6c%忠:/j}s:Ts]7j!))ugU,þ\6!JL-s .T:]7t(T1OR!4~,U|BB9j)s wn,ޭ4BU ҡ.˙cK-T,!TF' f_&حz zmuaw}_#X\I1{ e N $5h_i B["`bAe## an}I!DuHn]4S{y'5z` RC6]ڬxܜ2𘛔=(cP\<.5wG8%2Wk'At}݆K5p{ I3uX=Se ),y=sP,bFå5X"5m=KYOjДfYݗUZʣZS0^Z,T9Ӽ.+!Q @sw\{ldPaJ%Sz杓2pKwm5bfOߥ 'HJs;8N-Vq{;v(C[ezBL!I}(,E4b/Fb={S`?6CFTecA4*HXo;6WvǻnJe=v: Od~d ' ( <\Gn85Bxcz&zBZ8Ps˴4jDDl)ֱ6R8sn)kJs6G5v䰋siaY 'Qw9gv|&3NBj.ɯ;4/5~ :?Z-{G_(`48:ƜfZL):T~h6Wۦ=G)9z=o~&ppZ4WkG+HԸ9wn*n/>J[UFn@sK tem&lhڝ9sJnX. > 9Z`lHfF= P%/c!d %e,Td$4"A#r0Pԅ24͋1TÊGX?AJXamTw=Ko&1;DL|>SwU 9KQ/>uy5i]*nv\nFԘ 6X&G4fHr.N9ʖ$0#>6?iUsMO9GǺOU{"#?N%; ڟ]h Tܶ ʎtK@N5Tc=}wGХitaqʆcco~"Sr$p">uc:d=Z*T)ڢaT!1gW/K)5!wn GyܘOw{-VLUxF*R먷4H.B_LN:&%Pפ3YZ۫HQa'jku/m:xx7F}.wuyZdT`^ˏq0za&ӆBeWF4tg]DwjLO}|9Zݓ**N$KiW=&[7e4k6+IJC5􂋟#g+c,/;ޮkľcr/FX~.7py A}v,ބuAJ uU endstream endobj 276 0 obj 2441 endobj 36 0 obj <> /XObject <> /ProcSet [/PDF /Text /ImageC] /ColorSpace <>>> /Group <> /Annots [277 0 R]>> endobj 277 0 obj <> endobj 279 0 obj <> stream x\Ks7WQ0x?WuČwb(ECndah~|#Q*(LN v߮TB~ˆŕMߴ~KXCtp~$b14F)~U6-W,})&OW9zm|hZEzzw?tw?0Ekj]2DĺVFӴnqunotyw;պߛgݔ;ISblĻW2 Iq}vl:l ,Wc21clߗZcDr[ Mѩx6lԯFoks&1*,Mmr0Rֵ(WܮWjY4ymwF-}i,4#/%y6BR݆2asȓw}-s |>;2G[M9^[2; 8Z̲2vNYAʠ&D HLJhI KЕ Y,ݦ?o2Ơ'Xr_flX8."ȶ"Nx)ED~—oG[c-O昋'_AJlU` hlxR:!A4Ď:6UvX%Nti1`fl2jY@H Gr{{yJLrיּI* e;+9"r˴ASęspF0 @bYEAJb['8vVgNɽ0U%:6ߍby)> ĩu؅Uf,TG('d_/ŻO+V59w[5HjiA䪓ŶV{A q; Fj}ϓ x8K!PĚRQBA2325Ba4)@ e.SGd S- Fj81 eb{~#óZqAIq]<\Y^V9Pl_ م [O܋ PT`Sf!IF"@e[$ 9 Mi^}J'(G 3ƈ>bbsakKd^NSҋeȜ9"DRI0>! H(MQ#q=&4WvPmF<+):IqI,Pd_6d{Xu3@GgyJA[@iŮtYEv.p$ΐYNxJdWpr#;f#lb)%S氻u?*:i$͍0]Y'IqgcZ /Kw$/v?Nwp^ _4YC8Oٌ j^p||WGɘ1^Oa͑g-Nz)bEtyQAtx߶{TeB& y*l"[}(j65.|X-#Qn WA*A2uBpg:-rvSBtMjBpljQ+J,w8q30RTv +^Tp!1Hw sd[]}K]TjYlĆv_/ ʑXfŎ *7B*ڔ(Ap=\"G1X"o F=惹+?(՛rGGOZ=:Wʹ*F9oP;ՁY8jmVzꔠXFۭN9Vn8VǦ|2ߐ]Dr ﷫1HX׋n\_bz(ϊqJQ'Sq!`Sq:*ŧa^b_qbje8URO0E߹6+?*DI4VoGՋH]w/=//#CQդ1"4>r$ 6CTbQ5?Xh#3(4VxF%vax 5>Mj 8%A1ɬn1&مFHm[[gu0S|w}Re08e ZwOGߏBK*3%+KDRJDe\8E|qW# 84I2VQ&Gf96v:zCΆqK0Q-0$d`IO=I ƨRN/t EwB:ċExEQRAD焋AX!mn$ S"q Mwԏet@2e%aZ0FHK$G9nM ]sא[, CW!Ή&Bq*fdQ(N9/)%3%5%he|[\3>[zY'J:PuC`8@!u<+3:d;D%]5ƖШ~;g39k82=z6vd"Wcu!:؏zPur7"58V@\u b7&/ZFg^I=e9j*t]k)O 6a9 ΁1HdytQ &gquڊ'S;Cխyc\Xy-tcRD|5wT0&p8T̫`e_xfYO)?3gu ]1Aq8GZ\ `Z"e"Gn=(A4W[UJI7_CC2E1&BXآi:&Z1;#lG=& G^ZbR ɱ̫i:d5frFg/ 2/kO N81Zj2P @ `qFK1(J\Bp.3iS7j%7uDVk:q"axYbd;4&JNgҌZ)'(/3qAe T_rԆD=`QvdsW&qo̔8OQ] -m'T=WFP4\(J!8ZS;0ÝM#m'; .D% H'Mp:b;Q1j|@ы3 v;Fb#uI(e#}P$1)w9|ByRWaɷC>E0A{ ( kt\njy8cT = X #㕀k aMZX8ij^H(a*4h {/Y2;&*ܚD/Y bXSZ&QOigߞnb=8)qHX ;B~/f+.z1(RW:,(-&ɐ3^pKOo(au?$kzi<֠Jzj=tu|b-}D-NRB;b;-e!:v+KJQb*/쒘f!(GQ]a>TDgez)f4HINbv3bYru'D|+.~B/݁CBFtehrfJbk-zJ}dֳzJ9MZ{B!Zʗ9=ɛ |,qG7m6*/ (`HtwFNZ(jF'F2DA\xm) L-sm${q C!%F ;]K8;2j*W;sTCOIUrb N~χGaOe9d+ўn,i(8~=b j>rQޘC92%Xz4ݭ~by[1<^cCLO9i%a}ð#N)AYb/4g]'}k 7%93zR7S+_OR- _Llj5h2zLߚ8fhĩ|HdK[FxMf+ ؐꀿt]_<< rt@ArpyI_g??& endstream endobj 280 0 obj 5412 endobj 37 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <> /Annots [281 0 R 282 0 R 283 0 R 284 0 R 285 0 R]>> endobj 281 0 obj <> endobj 282 0 obj <> endobj 283 0 obj <> endobj 284 0 obj <> endobj 285 0 obj <> endobj 286 0 obj <> stream xYn}Wĥڗ~1F 0iCZdNS ReIuK ԭќ'M$0F0/(Q'2?lgZ3lgFIɳf|1gg^=z/:lպ6F2c%ɳ(n{^xN& b(f,V*g<>_gwݺX6eW={W,~mOO q>ynUzr0\"ƛyc,9=tũ@,f60UNO gs!Pe!Ei) aR M FKѿJJ&̬VCy~*^/ V TPվҳzd٦=8m]/a_ Y\U뺭k 'ۦ~!( Xt4 Jf6U[ˆ2rH{kA S`VzͼT"@4iPh=nWn_ [LK|@^iш\myN-Z0 ADk j҈hd P'*噜e׮a_#X~SpɤHCD|,]/n :P eS^ƤH#RS-?(t QM i425H%GS*wFOh3.)NppR5bUj]sKrSS4T7{BUy'pXUU6"pqPƇ>YuT$9DGOڽ/yzD91Tj LVjd"9OlLs5P+ϴSncOv[oQ\*L}:T[ nbGPu|o*S ?4Cꦋ;+ pv~ U1:1Wh 0A2VrW"~A .;/5ڸ Gaq ?;~]7cΏ?nT'&]LmTnDZD^dNE‘:+q*?@552j*/VjSشեﻫrz!UbęqCY7w"n=vu-xw܃~_!5 5+>6pj/Wnj"6&]XQEIu-uckf}]EWf͏of݁Tnla'm>]0eV@_?,20bcX \쒍ʡ p#&Lt1 3iZ;fFp׃ZUR Wq_˂wJeL:}ɫɱ"p]"^_D_JU7B45#RU 9L 6gV㿄{ݮDu5$Y12JtV=ݮnl`f@ҹGar`iIcǐ_@Pe *E0PRa<$% F<RLI^sM5oK0e_HŪƮ|gcnh<#eV7ۆc8eK1QQf=pb "+s!(vY})KfG&\U9> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <>>> endobj 288 0 obj <> stream xMn0>,E,J*\KH QIOV5$ g{ @brZB?ā P5 =S[Dpp>wAS a驔X*% ,@Mh \aXT[ Uj69-:5zJ#9WNDb[۔CxGc;;P0:–U1e]~,B{8PJϿ(JYѶmjإU![ZHoE滴"5:cnr/2XhJzn0͕+ aI)čgBi$b.3{#YKZmZ N]GbEp u%,tz. endstream endobj 289 0 obj 380 endobj 39 0 obj <> /XObject <> /ProcSet [/PDF /Text /ImageC] /ColorSpace <>>> /Group <>>> endobj 291 0 obj <> stream xYnS[x][4h^ 4&4)Nq0}~F9#9X?'Õ \EQl ߛjyUI. 0  oKn(76WFIٺ;+Lwxݙ[vP3Km7%&AYbU6aD*36atze )nd2BVQc"?hڠq sFRoonoG)!Ma5ٮVm/Z/L,zRZ!wwoQeAqyGC2 M`R b.VgJ#5SB[2a)# De@j.I2 "sGC?I2qU)k]Vc0,B-o@QOՁ;i)4vHV,N z)^Day$VtBc,U¡~`J&w 2Ef=/OzJ6 hCe ^'dEUf(RD}, X2J1: V)?!iܰEʎ-zm7FwmU=e1]^vvoUGG6\1߯y6MY=A1+AWqW3G5f-&aGe?e]̍yUma>ԓ]<0}!C`{IElXV1f9U X4, ߞoߣdQDA=PW?a&xOGj9| endstream endobj 292 0 obj 2300 endobj 40 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <>>> endobj 293 0 obj <> stream xZn$jRԲ FE"W䮺\>N)3Ksh̙s,y4lrB&9h6*DMqtϼ.Yxc~dӬNJ|qqy':cn0U+Y&g>铼յG}k}& 9+7L5#5,9i3%`c/7lp-*WEIXc!|*o˲X՟*6gb>OU>/*݋* ~`p>DC[YxbP5oꐙ}N 6{y).δLƯw,%yx^~.+p<*yX=gUlڦL/7d'}Ԃ ;f%v3VXRe:||S|nͨ)۲@ӂmSgY4'oߋEF^v~,IW H I{0e*&`䡵Jn0mm1JZeY>{A֛b9ϫ*>% KId T'1C&`1%;brgz~_/J4w 7z 6yAۼJ $'$w)ذMzVO2DDzcʺ~(E}ҍSAko8D+" _Jq1(f%r!1fȐ0*`e9–!s=R|С!$rGdORjTk\,& 2{SW?zq('յtU[0D3^yɲWeEݔqoHŢC| R8`` 92(x!ozTcy*b,Lg] ί7pf2HN,vDZ]@jo(@thR츮Odoc(Ū7$$mSN*AX?re!S! I[9AvVf@QOsT'+ Ouj30T7=6RӽŁ?63(>R *U8];eo.޼G 35 sm̛8gQDSMP!ȕ#8P$ۑhY0&`n4LCa gL f,#̩ Ԃ̗Of@)C +U0;Aw-5l2iIwE$썆man,54\ ˺^ClJd ƾBގ E0{Z4 XL:N%b h`O8Prv?+IdIXywIw3p#=E۸g8 ʛ>nl0"b$!v. 5@io($2i|UNͤ #ff[rHQ=R =yA.tu8C r#EZ+ڦrDS D,Í3Z,slgun@ ,QV0ӟа2MM-5LYU-Y_|[7- YC']>C>"ԏr!PQ#2`Z/[0C$¡HhyT uxa(Ms Kb\Sz(X_u؄hI*+@(T5̆PQ zO9M_"N7ZURH.cqqgBPrP8x!ԊAC09`G^: A('Sd3|$O^3:~Lt4|NI ?7l0$2ygȞR,YL"CUZ62B-_]\\$n_=ƓćcDAMct* A bRu'RřbYt@>z ^vQhZ8X h&՘;IH+3`3 K:P AC5'{u>^?ej9jQ/5^L:UA;p~tziXX>1\7Ğ^U3hEo8@ZA i ?\V endstream endobj 294 0 obj 3192 endobj 41 0 obj <> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <>>> endobj 295 0 obj <> stream xm?o1 | 0L[Nz( TW' -HBD`P }>gv/xY-9VLHUOk7a{^]Z>To?`P> /ProcSet [/PDF /Text] /ColorSpace <>>> /Group <>>> endobj 297 0 obj <> stream xy`ՙ53|}sٱ-vrX>rpPI)-$$!!\ WRr(-G-Bl$vJnٱsxdόFh"͌˛7}d@L`u  YHIZ$b&$cwv{v >,CXi,rp%( 4G \i>KXHw$ԀZQj 3iw릢gr rT;Q3J[$q9͖NZQZJ 8s!j}F9jz]9KFz`hg>,as3hHo6Oes2IFlT(npKǂVr/x>j%FDNjU-AހemN!|K<ǹ6jHhRKlR6'&w(F6oelZpR)U1[(;E|x\#χmު)h`o9igKd@ FhftR3`l@=+vR+5}'5iDy_M3+ ^U,(j.t֦.Ն[#n? AjRòwqSK x9_C|Wiua<8>e4u,A|,lkec&>oD0P,Շ: X>>mF|1Q{)+@8{ ?}m6_z͍&zkb ~p.ڸfŜi|[(ѣFχ 5xʗλp畻r?ɫb|\ 6;)NTofHV8>ʠ?f穅c Zϗ?~㳗}D'?.Xغy×W4pԌƀNjMѓ2(;kWے/zr_<}ï_Blׯ^{)`9 '*g ?WjtPe?qyu-3Z$?9Cm5| $)hwJW Oo8cuerfZ8{H'YNfM/U>}E$;!Gk4ΊmDUJ-г'71]}oM~& 4+-h\ ѩɍZ#it 8G1hV"X^F8PQA+PF?RW0F_oQǕJw5 ш cht׃yL_|gc` .E^7f0Fgѓ_~1#h4^}y1F-y}57g"5 uq{E&5^>G@=euSFԓT TG*)nޣ{|G¼2ڱ:ô=4ЩnV˷nH jů{fIGvoM; -.kMO+t<{vLaso3\US?~ʙ>wg۱p kL# />%sWu)cώ^^>اpdzo7k3E,뭦uJD\nH9Q\CM,K;v }%EEٵmWh=4ZZFQ+tBiyZf_ GνGwK2P458F0}P,]h}xS$/iȪ:gC#_Asg6=NbD!cS:8e;wS3Z"5~/ːJs^_!K4f pD:\emh4 i.)CBq }2/b(ܖ 0V;]xؿ).Ѥ@dw$)[(zዔ]ޑ4:ef-b mQzVY@#I**!Sj.ʀF(u4B_9r.F F FXՊ*a_"hsC]AܷuT4҄O(zEh +注. H@#\04W@#44#@#Mp4H@#\04W@#44#@#Mp4H@#\04W@#44#@#M|I]. QA96ܴu aC>%PhhhhA%P hoU.R@#xd1(4ˆu{4ˆ/.R@#@@#@@#@@# V.R@#' pb_ (4‰A]F8U> **`pf4P!$IƈyK0$-T2FfBRŲƅ.:m mD$jDX)Ƶu%~;3GFlmub #mTƕQA/T]uȠ $PzwPڨvwEm3:HeFGBPpuFFF4)=h$Qm:S\= eP, v.A]0FCh$7ܜ@]hfD-hj#3A#1*[f-G]yjH:#QjFɤ76nF%?l jYz6zS \`T3x֯]ݻoĹ]oX|δ 'h4f^zꗷ\|\kMWfHL#gYesъSulߺ쵫6+h4N#OZ4x)_\猵_𗗯phtѲOۆFČ ԁ46ըuc]=q 5ۣ]:Gf]:FG2cX{FEãg9+O"gο_hǮBD@fu u 5Ѷ'c2q_:F`<=KEl%EGC0p\Q*zмxs_GG#hI-sס!>ܽT)YgR ;'! F ,xvW5 vB}X'|WjݺlұaO!¬ Xu,M f]O2},noSRٓ8j"}뭄n(ҫ>GB(ek4đ|!jm$Bh2ea7\!u?P#'5H kX:Q\ .vw c@#i5bEX*JWm2V0#5<"9,֨G`_9 aY Q\PWj΅,{;V•Z<ϓZOsFb[#5jgh Fb\GbN]jT&EBb/VSDFE,I] #b[?#D-M'o$;+Q}^-j{lwCid"r@K#q=rc0LO8 4ʍ42oShid22@O#槜JBƀTh#jd2K^QN |@S#gXF1F!#(7tݳ2=rc\L_=hkd<rcdLW?4ʍ52hckdWnۂF1F+{.#qK(7tT@܀FJ4 hd2]*#(7%/H 4 hJ4 h4̅+t(7;~_6&Qn@l{e2@܀Fl}u@܀Fcl ?rd*&4 ht&4 ht(!h06#(7'@܀FGpNN@܀FGr?r˯Er'GQn@#sH](7&hH3E<r#r`UG`<枥멀T4XŝּYuQnw2ɨ 귪7hA`,ݏ XTXL_|F!>XuEeAk <rC0uλo٭n]oXbδkd:ڃrCP)֟weW^6 ݧ1yu+{UNN}n5hrzÑWM[̕vuƯY901[ N9hWԶkT׼]SWWsL52z~4TQn,$P3Llw^Q{jK2Ϻ6Z3LߏFa&,VƦ&SG#3 MQV Q{Frh4fBe[7j<[B0 !僥|<0q1Hsk.8ȿ^G]YTHsudc :A#4F]0QJ#} K#}+A#FZ %F0|h_P+Fn?^Z %({"`̓2L5V3<`c(Xp 42A"by*'n;{=nc6&+1Hn+es2ym4Hn,/A]1<.9Bv4c.9°`ʏQ8(H94y_ԕ#Q]٬biD:J*+?F[Sk/<ɣ [^3uH'* ?]_BT@#Y4khc̞V[4H&#QW~>4R*Xu8zfbF2!lP K:Q ('qog4t%rI6A<@JhyߝL2A#҈'0Jߛ8dU`W8]<9y(inHT Z|@nF)FLv5|Fd4R Yhԛ}|@64[J- FyLN]LgF?FC$,6VC)Fx :4d/`(aiWFЈN| `w<\sBqhZ@w 4F#V8epy|Fu7ݚw.A#Q(W0^:JȞ@#L4N]A8ab)]^v+68,֨GٴDN=Fl ϻBkT遾&q&}hF?֩K JFP?O!829ʏ@#MrLMhBڟ`(5ZN ~1y#~1@#~1@#~1@#9bQd ga,0?O`ß'0? ß sg9ys<9Yx4 <&h$H H&L@#1@#FbF2d44 h$h$H H&L@#1@#FbF2d44 h$h$H H&L@#1@#FbF2d44 h$h$H H&L@#1@#FbF2d44 h$h$H H&L@#1@#FbF2d44 h$h$H H&L@#1@#FbF2d44 h$h$H H&L@#1@#FbF2d44 h$h$H H&L@#1@#FbF2d44 h$h$H H&L@#1@#6w8F)F]+?ƒ&?GFA>[4SЈH#7u~k]h4b}3vEW}[nE7]wsN[:kjm4k#dBPβu]zUy5_ țSWst2VYF#3( 5͜;p곾iK8t׭C͟Sޛ727H94ڸD':t;\yݫ?JN=GnU4R L[sۧ+o _yW{'CxFޣJNUWx)Ficim)-ٍwyػ?vOvlh+ 5H~,G`UmCST9:wS_gf͟ 54 4ׄen'C!?F!$ܥ>@9_sƻ/ |g8~M ׭U%3hTe=eYޭqwSt/t-%XPV ,AX(VN,K;8w/C/sԃ$i ^gGȓ^8rovG0c!b߱b~?9ўꢋ! kWE4Bh >FH4 6F!4@#$Fh@#|ah@#l4Bh >FH4 6h9ipZukZEFRDV8O?>吗wuH)҂h-h$b?;c/Kp: f66h$!FVqzvbg 4 esyPV"h5 4ʸ<>Ե_A5hR,A][=NZkѤXl\Yuum%7GѤvOum%2)qt4L:K)ԵHWԩ"ѤisPV"GM`A#hZD58J,ϠѤMQV"Ux4fD/ A#hQum%ҟFDHAk$FBQV"hFrJ-Kd p&eI? گM! Q2@#h5FsXZ/HCnH ͺCѴ^Zt". 5aZ#h7Mo$R}#ԵH?7Ei.L4|P$"SvQ} J7O?dLm<(m^zŻe;s}W&y[u5+Ylh939ݻrݦ v^y5b]>ۓʝlZ23C<OZ [V(xWΏ._Yr\&mgvkv^>cu¬Yh;?іo`Plܔ}v&`L(Rݔ>3JwI:92EF塪H tX,XWFr6-!l[FElkr8~PxHhd]Oi(/(Oj$0H8XFԤF\(PT<WjB#bFA#zHc~bAԑ`:#DTЈ7u෸ƠpЈb}m%;޿JHWEݴVpU߸ğmw7hGMp$YRHnöK/p<'i]~ NM'J`f40d{MsNZ}ֹ/mM瞵Mݪa@2\YU}Βe': VlɜXUǀFA#r}5Ԝ{ӻxTkvh4ʋdĴz:[%i#(Y(. V64ECfڪ`PH8h4쑓jK=Sc@hR6e9ntÞgUtf噛.y5עge~U2)(gIU<+Tv]8TvR±YGϔ26Omવ_ٴu;zgZ=*qΦ<[pI#yNj79l4U ;sn7: (fdђ3UƮlf^ka¡.)j-?d8;v*m]ՠ hsv endstream endobj 298 0 obj 13049 endobj 290 0 obj <> stream xwXW[DXT@DD I F#M4X^{PcbIDcbCDEPT,Xs9׾2>\ٙ3gfΜ{gaaaaaaaaaaaaaaaaaaaaaaaa}0P6 0 5=H3{ 0>Rc3O 0 #0o߾ʋ65a)`ðajԨ+TЭ[ǏcI0%&&&#""̙(,5a\ͭ- u2d߾}#F@SNٓn0 +Rb oo-[xzzsNL\z5֭Cy_}ÇQ:uUhAܻwoy]&N/+˗/BqΨS֮][zu7-Yj 0"Ej?,Y^|YZ*Uڵ0t  `}o RRR˔)ӫW/+++Lܽ{={P5jTFF>aƠ.;vu}IYׇ=:rH}5k6|p\Bs"XXjrarE}: ۷oǧ_.QR0 +ZZZO?)?3շo_ĉ1O-6nܸ|%KVT vUuΝzę3g 0A|ar%R#͟??==vڥJ~Ã"Ǝ-[ɓ>dOk֭ۻw0?13ZXj 02..lD0xBK1 Xj 0CGaDr:6!SH1ƆvHHݦaMaU!Vgfrc$hgc8BҌJH1ƀv BYAj/^;w']m6f͚5dȐ>[[+y7hdH1E)k׮i'NثW/Qٽ{)s"P_(y|YfTabb"^Ij6lظqc"lѢYÇSjհj@ռys[[oٳ5jz P h7oۻ5^աCO2_E5n b՛6mrwwJoܸJjBSݻbJ`` ezWxx8dx%KG)HK*eccAb={P۷opp0 4_(#R([XX`4Xgz˗/Ij+WoHKKo?boР) 1 n߾E`(N^j$ER1c UΝQ6m {A mӦ *'3қM>s!&ʕ+Э•+Wl)!#~&MSN-Y$iTUx4H1ER8 *׮]#pa9My!/C+sn޼IR;z FE9s &LG!Tºu.]`WGԩS)Pā Zҥ!ўŋ#BvvvpIjp2]r>-n =c>!Uw ,")#Qj~(n 2̰/B0q }&gϞE_~FE&?~< /^_۪֭U+ R4oLA&5wD- G:]\\O 6Le 9@ 3@$5 Ej )#Cjb%/Pyܸqׂ,.E|$Wyb < 3treׯ_TRwܡ/333szPDEOTg}6k,NR Ġ SSth&cǎ);v c>*rڲe˰jӣG4K֭[6Iȫu(ܻwOrj)'OL/_ѨAQjK5]%(_h0e'hׯc Wk5mO>|Ge5ׯ={f,z;s^Qn bJT 7>RMW8 Gg … ϟ߭[ڵkϛ7o˖-umذ.0gK,f2'~q՗F{H666M4vMLL޽{wdH~P6j( [€ŋ>|HHH,ăzmڴp6/F팾)^0FJ>LekkWk"==}ʔ)_ ZPPfeeE:s挃 m۶_UVj͐ױQ;#1S taP!5z uYDj-rrrE[WY˗/`f͚(#"///]n&Sp qo6ZSa!Qjnݢ2IĉժU75oܸWIM|[iii)))DF3Ԕ[%naM֮];Ao#55R3f={N8Q4OKRF Iŋ(;99͙3jժꥆЬYfVVVm۶_2ŀk4l*޽KYĵ6) Ej0}h'2R1Ati4a }@^5I0ƃT]Eߚoac #UFFFvv.[ z.5}kMbM^G*OOϳgjj666׮]TmVgUcۆ1LQptMhD%6)zHǏNR;t萋Y.]`$RӓfA[0E )#o``烂oaaqgϞ <eDy7o޼} n?9sdɒ#Fܹ3Z(QJM Ci'rLMM>}rjj*!"Ui߻w~vҤI]ZJ2331 u i y€0M#ձcǜ6l}bB~P\wҟ4dȐU֭[*H~`TTT5L>+l0(T>PQ2xb1(KHH~ ѣ|SN  0 Yxx8 ;w,&N-66z&\wBnY۴ivZ߿oiiIeR+ l1,T۶m+SHK.eggGO}ZDD9r˗/YjH͠`Ѝg@Hի\"IIInݢ;RxÇ\3DV`g=GF* (R4:g [ }b *Eg a=HJElsF`1)R$d(XjD YTa #w1La!eݸqc&M<==;6tPΝ;{Nٳu۶m9"~k2r~,_^)S 6Cbq5jߟ2,ѻw3fr0XjpUa )#}̙%J3ʕ+_n>駟Fɓp);;[e}YCCCQ~/,Vr  4cǎDw) KjZ_0md#QjDԩSK~ נb \aTY5/&xR[f >>{TRo߾Ŋڵk(Kho<[0Anܸ!r^թS&7nر(?~u+Vu_9K?|'fΐڄ ʖ-[ >|!arBgR3qި6aDݺuKP%5c7nJKKQ9Ks,-- iaa͞=n9YjnflFrF{PjϞ=+SLJJ ^ZԔcNl호a, ={̌RDn޼n]Hhwj U[HHgppJСf͚aL&M*]3=yR-55`0E##URRW|yN)d̈˲322Zj)W2Vƣ:ھVOvƌsv]7+e )8+Ǐ/[l+WLRW}[x?0L)\1F:+ L),i/.{q3FWa);D S.c&f&fR 7oT8|5k>zH"k׾rJ^*<"z[XjA?RKKK^CΝw˗iZAlWۡ=|UvD*ưP=͛:::ر&Jϥ5iҤի[[[lA&K:88lٲS_޷o_Z$,,Yƒ%KhJBBBv,--ᲫWbY ,!O>&&&2 ImѢE...vvvkN( *7hG X&EϦr|)H9P֭cccm)>Lz_D.\Jʖ-{]#<PǏ |Ztt4VKBpAT;@$W^{Çԩk.ZtU,F%pׇlYSXnZ6k,n߾mjj\PF߾}!UVw:O,SreXFژ1cdsĉذa?5kPB˗+'+oPڵkUnKMNo4O?[RqDB^r?z899uT'},Yr޼y #wVVVUVm۶-=gϞ;88nt 1,,R|o?*;@Pϔ7Q R 0yB`D'̌F ӓ*˿1] "'QTu'Oos|KVx1L.56={Z?\px2tTӧOV&3Fȇhw#H'ߌ׮}Idh[jy}<>ShsLppp%ƌsʕSbȥSNǶnjiir}@UXk׮Ų߿8|04xۣTUn5k֔+Weak׮-_D޽{ޟYj59J%Wܹs߾}ŋOMM "OR+Fyx3z$J(:uJLDhmme5J>eʔZI Wf_t3k\ w2èAnܸB:uqƍ;ŋ ,P- Ξ=Gb޽eє3gREe-Z ~tww,JLekk{9)w6]0j(5zCYj7S9=(BR[xqPPMIHHZ*Tմi}R%8qZj lܸWK)gj :6D٭^Ze^˗LLLlRkժLYre޽Q1cFϞ=!Ĥ5j$0zǏ1RS#5)r*l4arRCѣ*Urvv._̙3CpK.!^zU "VVVIjQpwwwrr3gR8`F%>|˗jADagAuMz1z޽QxuZZrF7x32 CH[JD ,XD S۷u֘!R]Rr~!5,;VJ葒ӧOS{Ƣ7!4hÇa!R377GDU5jHI MDĴ}v STb71r~!51OhXF,Q bêU"U(@qבٳ*?zGǎ.] ]uˊO9Jؤz\]]nj#HdԨQXL"AAA.\Ȫa|#DR;p@Æ vZff&֘8H~YImѢEӧOS͝;wzRRR^x!};w#hUKc!RFD???GGc$EEE+T0p@AUNso9s6l |?ݻfԗ_s.YѢI2))CfffP!Mܻwoƍ1ŋIjhdpp0e:w^իמ={MkԨ76_~41,,Y~K/__=~8lHR1cƨQ>}|rxZDGp۶m4h@?冹~ _1. y(a(|"בرcNNN⿈ &-[VLn<|PʜRCFjyʨrYݠ3̞=-@CRKHH!͛7S+S3߉S˵ׯ-,,U( ZTIMnQ^%$5W?Yf{$Xj )xu*T@ Y@ O9&&&b2'aFjyʨӃ"$52++&~p4Tؿ6?~ْ.] O`af|ÇIjnnnYQe-UBR;w$5mӧn 1Tՙ;w,&N Q͛7]/Qj*sϛ7qqqXV^jMLL(Oc^3\V$55jm6ZrQ"~{ UZU!d6m.]®]jժИژ1cdsĉ/EEySHjц p H k֬YJ >^ eʔ)syxxO4ta0WETD ԩPh߾=$(,bhbo߾lmmJ"@˖-=zDFFRyƌh6ztYfͬmWxP;v-U">(r! Ooܸ'*d1#t萎e˖ pLƠG*'7c]ESDa2@aU^f1R3p2Aa>&H9={n۶#Gh}jԨ1|pzz\yB&AZRI&U^k1c=k.e׮]^Qj'N\rn^r&W0 !8B G~Ixxxz`+WnϞ=n;wL˖-o߾խ_^L Gb\ J Ő`׮]'u #<3F2GaD&H97o +W#hjɺpە/%)+hF RKAjN1yԿ! \b , 2ۿfjwXF>[XIᅦ2Q2_"##5j$Ȥveƫ/!~SN xMeԢ KoaSH7hr2337nܘFR[pΝ;/%)}f5CU!!!\HyԿ =zKeM"KM۴iSiffF/_@1"E"""̙ʔ)$+]dѣGq ۅJJ 111(%ο~zOOO\bW^&` E\G*\ܡoV^MRD<ڷo}v)*3KIJ׷o_lժݻܤ2>I ֬YիW,>>R_1*fc!5SSST{ui&WzIvZ?I~֬Y8S`Gd NIAb9 2h!c \r/_UjyZR3pU&`A]g}3U2IqZa'':Ѓꥦ2x Coٲe p. 9dgRS+V Xزe N v܉˰޽{_~w4ԩSWZPԬKP,+J ժUDk׮5f=}4 ƍkݺ5*Ipٿ,9"A\8p3F^jt jw=p(ti…8I###7n%ApcQFZp; s.JR:WhX``!Fa[9{^z3f̠EPL[L {ȑ#ݻ'/5WXK~~SH|؊ WP$g޼yJ>LRCDVp胤FΚ0aI ASXXF[Gb"%A Wϟ?7nܐ1hcc߽{0>dRasڢ[It,i^Qj9mFn?ծ^HĨtݿٳgLqhfBY $m8Ν;$-[(pѽ۷oIڵŗR%J¢UV۷G  *)SFJ|ŋ nKKbTI 2=s ^aɢn222(BjbE`C\ dԌ >|DHXڃZhh(͌MZHj\`֭[#/&Eg!?rxPD= @R|Qdd!SSS&>FҠAsss,EjP8r䈸Eucff+  &M`пXԌ >md#= :-3gΘ *PHnH///$5ܰxHH(O"Jrpp8~a۷c޽{cG?^Yj8)(wҥK˔-[5e(c!C\bŊꥆE@BTtiAIjvvvXQRRTUjiNe˖666^"1O)))(_~ΝpY>}v&mZP' 'J-͗_>hY5R'###w313=RkׯOwK1wwwzX̓"c̼qFQjammMP 1(~TN(LLNN&o~g8wK֭[u"~D޽{ R[lz1VjN1~zz:zF$ "Ν;GE:gc>| SAlr˿e~ +yHjxu>F111 m8ũu;B<5F|G>vYZZB(dW>:t033ϱcY̝;B1|@A֥'Nؽ{%K]q5H߶SݻҥKqU&㽼pq8tP9(55IQ'.,mmm#""f̘3gΆ cՙnT(GߠrGP  _} ۷WXgΜ)Y$fe'E_]|)9bDVre\O^t|-[TfGEm݄& ?4)|Ν %8!Fu紱1SؽDRo߿?}tB>>> J*O?D!rIVs5,Z/>I-$GOɵ8Fu2 7hr=|B($ԯ__={6&NQJjO]&O,5D$:u!54ǎUrM//5;8yCj_:Ӎjc4VPB D+ PD_|@jo$HVZbARSSS %dٌ$\ڰa(c* 5N毀QF| )aÆ k֬66jԈ~_rtRիW~>|WbArNJ+Pߔ2? }e֭n*|TI/_.͛ 5N毀QF| )'={ʗ/Q;wUZuҥ"Qj=oiݺu1Qpnݺ%JԮ]ƴU TRV޼y#IJ}~X;䥆H!!6 5Ӄ"_jc4O^b ? y-E6Ntta O6?Qݻw9Sͦdee)8oT(Gߠ[v_|rnΎ1L7eo!>ڶm۰af̘A~0QF| >|D2 7h11bT(GߠHĨQm,}#*9m,cvd$!޽qvvv˖-rqq133ҥ˓'Ohɓ\]]g͚ESvqڵDzM2eذaf[P03ݨ6QA#4iVZ|ɻw-,,>ٳo]|͛o"ڵk;;;C_~ŋ7QF| Rlmm [!#iݣ+%%ښ5kY+C?~R3,L7eoHڍ7\nݳg~b_P\w&%% 2jժVZH^Oho,5¨tXF>D!-^8(($$$@d١=zRtΝoaaR3,j7eCoOj|D2 7hee%^hTIW 9m,cvd$?OkG¨Q~V"3g:ӵ3(2MaJF<|ZJJʋ/ XXjyŨt aSؽ'1K(oըQEϟ߼y5kٳg qtt>|8hɒ%+RJQIF7lЯ_*ILLٳu۶m9B.Z Fm 2e-rumjCǨt aSؽ'1K(5hSNnںu%/ٻworr2>֭[ndd$,V\9ۏ+}m ԩS'J zaшN< @jŋ *z}o`ՙA1` K2Rr%f'xDqqqi˖-a( 6kwrJOYj +(:PCNo޼ˮ\?UV&=Bk!5(rQ:u n¨NvmAS]#(1K?Iŋ|tˢEIj4**j9sVONS_NRSY[n]bEb2aq*TPviӦe3-xeo߹E c;ٵ222KaGF*R,$RJ}>E0ĉժU0eƍ(4mt߾}4[ұcB4AIMLDvX ̕VL&W^>|ؿ:uv%KM vkedd TAYIjpի1%>>zPFXXXv٫Bf̘ѳgO&)) NUj0V:r%Ϟ=+SLJJ >E3ɤf͚F̿vZZ^1]+##cvgd򀔃(1KѣG+U\|3g x ;99͙3]DDYYY/W 2ծ]jN)#Ubb!ׯ ={,88_;wSMbŊW^}ȑ RRR\]];F*ͧ:1ghhI&Bkk3fOiz(,/ǏGK.X7o 5r@ӪU+Ғ /T6?'5kLEBBBCуC???RS'==rjEEE#7F`1 cHsbZv݋tٳgǏ1FElEY+W wLOubN}`ɾ}eggݻw IM6D[P*<_fMYzCԘRF*XL2WlY///ʮh 7`CSSS7771LOuaN#gggX vЁrZDDʽG|RAj*2dڲe ??K) g qbbbTy˗?|@Bj+WgÔ(o5i322׌ u{!dDXjL>hT$5 XjLnhT;wp[ ,5apWaF*StN`{0 lll]Eϟ?zh)O>ر/]TN70.Gie8pL=Xj ?RF]v!>B۠5jh4þ}\\\0Ú5kڷo)s]z5}:gΜ 6ݻѽ{^t):**ߟ{dgg㏎Ç+T0p@~TRf>}<{L@XX%KhuIXj ?RFڵkC˖-KMM>:ut֭[ZZZ@sfffכ4i=aiӦCO˷lJ*Wp¸AMuխ[722,W2220iӦ=`ҽ{&''UoQjʯ;x P^M6hXj ?Y(QSxx8샨_RVdIJjA URݻtSVݻ'O qO2RZRS~}@۶mm`ժU?50D]|//^'LMM,XL8> 5k &-[V|! QQQ4̙3s"E999=F)>‚VviQ'iiiF(5zYll,S4%Hg4! 6 MIjgϖ111jڴ)i?'8qZjwd/nbʯpsso9,HII.4XjJnܸѯ_?싛7ovttd_&%%Fo 7|)>`̘1i2P]2a1*#W/~m?F'GVTٹ|3gdǎ ԫWr!!F$SN9I L4tҨVZt VVVIj֭4g+""B\͚5k:1g۶m7q3a1*ܹӻwΝ;2** %. &[6So  |W޾}SX"XdI6mvA~pD/b"#Շz8SnܸARdocW ͛7sd[ d!U,5F%t]]]q;v,88… }d%|1EjtmV'OVX$..cǎWWΝ/1O=0:ujȑҴiBvFH%/5RcT"Jodיݺuaƌ1233'NH?HXXتUj?^2ZjuЌ2!%4;R%''/\P-dQj}PW^t,x꯿">|xȐ!9qĸqY֠#G "KHHd &=h (##*JTJ ׷͛7>|xv?e˖/5hŋ۷/\ֶm۷o_w(f5ʼ$,do=Xj:uj׮] !eڶm[2e`.~/o߾}71zK1ǘ| qzULLӉQΟ>o?"sXj>pWat1&HH 0TD0 h|cVV[ ,5a)#͵kT.>j(ʂyM+&>(%KyK-Rc fL2R=|0GSRRF;w&Ԋ*,5HGHձcǻwFEE 0`ܹW^GϚ5k.]jaaakk?˫J*C 'Cuɓ',K ̞ׯv͛z0`14F:RF*x̙%K1"&&q#v͙3'55RX;88'}~۷o/ȴذa;w8plٲ$hkknaa14F:yZJ( ӧ)5\hї_~)|ڬYHdakWWM6č7޼yR;vl͚5kRc it$Ӕ5j9Hmݺu4۱ch/4ʕ{KWOp&$?i0z6ImAAAQBBBժU6mo>xxHmܸqXiLL.#0|rA&5ww/_nz֭'֪Ur޽{0sL>|TzTACRF`1 hJj,--wu VTUV4GnK򲳳'6lhmm -]T{ٳg;warhp1;zۚ2nݺ%I+La Spgc$##*L!TD0w6F"}rBBֲeˁb6;w[YY;w.::,44ݻqƈ/^,J-,,YTmڵUTRwNNNf͢Νzj*ϙ3E!nnn޽f\Bs͛׬YO>h '5M~mPP٢Ek-W5VNWaB 9rеkW [nѧݻaGEEuҥI&hƌFzQIzz:%%%/__=~8CR;xkիiӦ/^tyڴi0˗===o޼ymvHH> :>I FОl!##c͚5M6}&@ɐ\&ӏʱ[nDz\BD&0Fg8DPkŊ(~:r9=+yPǏ @jHo?n߾հqFZ۶mU5`ժU(|+WDkdo&4[65RSyq߾}O<)ȞQ2e ")o2ZD nh9EF{Y0LA.?Ϟ={ԩjtQ^j[Hj_tXBB<4oޜR(8dO-,,@K;Xjժu֭UԂK ڢEԔ7ŋŋ SS hP;p[0E=ϟ |=zի E^A kYYYK.X""J R߿?ѐw->QjhB'HjÆ _gKĉժU{ U$5MFXToR%An߾|(w4B ݺuå/O4 SԼjJZpViʿrw(cA)u+\~z񠘛… y}L ;vhjjۋagAo mٲe LYn {$M֭[G" RlY///np`C5k mۖ2Qjy{{9+z%hmm Q^N䥆B! 1䤆h uwwwrrBQxQy1TTٹ|yA@ }k9 (E3 gp.̚5 ]/u?L /#F@ AjBR[^="9I ׮((% '`K?3| ǤШQ#D(17o$H-OkIjLFh&xAa6i|j̃g┌ 2ɓ' 5PߋWPb,111 Tp@\S:uUPXp!fشi7o~ƍ(Wb諘cpEf/^g'O&7uָ6òtG.55a)\~+C\l̘1R4a[zxWWW\4BryCVdddƍѽљ[jecc#vbWկ_Æ !y&M_.N^1c {U4<<BٻwoLE'N_5q!Zx,DHj(j({xϟcՋ~s.d`Pʭ3j>|86S^jt/ `ǿo޼4h˨Qvas:jc۫߿_ti@}6BR[|96ڵkk(qYH*RZNCW1,Y#\\aR ]㪛f // ʕÈG0*D=\c>}: k֬!rZ͚5Q]tA#_|Nw(WX/D *Fj԰"1@&D d7`Bm(_2e,,, 2 _QX`={0֡QW}{)Z)*y,KE(̌U &&޽[~- 9d6tPTriѣIj36 !m~BRAǧ˅ 'XZZBFTRVa]ݻwG{AQIplչsg 7Ԇ/.-T1U M6[YQj[n Xi=CR3Q1ܑ1U;v eNƅ:0׬`͸> 8ή,qĕ+W0ҙ3gP0aFLV(~ڵ+4#JJJ*&) JTq.IlٲuԁQƘ=ݼys1ah&|0,5`GByxe4eT@R/ػwt`u]* >~JhN4GX԰FDوMɤFv;< G2 U*GPa n7Rl>f°^>eл`mA'V>r{{A+b2as9uyaU #nWr+gF1}RL(L}Un]̉Bll,&6(c Rn߾رcO<=%%|2"ڵkk~QjZjվ}{hxuUP!X=!n(a*&J*I\!FUZ=ur{Ijnt)#Q333EQ#;qA6cx*ڶmDuIpe RΝS٪/b"I^j8(hMr#FJ;o߾TxXU1۫8 7|SL rR MQ^Xjc]EJy15LpBCCq_'I?RPBiPU1+ wSuQ#m1}ToooyQki-Rð1VAN7*&>`/Yb?Ԩe7WB ܹsE?97H1ޣiӦލAŐ;cBtz :M?sA WO05V~ -S:ۏt8@z{Q4OQ]\tz. `AG fVv킦 ۏ"+ҥK8ݵj-jw-}Lzzz5n+M $EQCk׎N[h(=y(9K`` 7H%м O|a;X\9 (G"4va1tb$rww(^΋!az쬩:Xn˥^HLL̍7 T7 $ݏܹϞ=hx&GƓΒ8Pk1B&^kMg %wM}LzHKK(ą|OR#j`؀Axx8 -{eB[h!O6;Øpϟ?4h0vXPw=z4G#F@ókݺ;0Y/Tci. vk0:fPď5{:u* %L~(`Xd D ;F 9rBippqc n:خ490VG5{n?\0&1Q۽{wժU3m4ѣieOA+$[¨j}nƞДq X-3g"+x c5$(V^@5 Emܹ54@$+ [s'4%jSNt/h9::Bqq (aL~Q:u4oIK`sd&f2X17j Gg5uans16t%0Ae3ne aEXMu̙+Zb[lAݻw=. 0ѬYyH>$X5a'˗/_L 8qB-^Sܹs)b|:uԮ]C )]tmã|2 >|x6mPooUVۗN#ٳg+8E޽L&aQcF(yRu޽}.]ZvSbb(jnnnTA&$ѣ̞=ѣ矪U.]ThSRR̙aJHHquVΜ9>?~ a@пAAADQkҤ?L.\ضm[A'j9$AthpԨQ֌dN?A ر#9+IBg20''ӧeV=3gEmB#DŋH8qB믿+٣5_p ,xAno&o޼)b@&31 }}R]vMz(jSmJJJJLLtv%ANd&QV OEپ}?7\A`ڴi)wޙ,j htT77~ME/UٳgEQ=zt6mttuܸqIQ=Cxխ[F kcǑwzjd20GɓjE̟?)Sۏpׯ_dŋ7i҄^54!jGX^wlѢ3g׻w]A`)\]]>l&*1 }>!7a߽{wM8Tq^z+VO2V@sRRR׊1 0ǶTaaaUT9r䈘+mua&?~T^A@El0 5'c]; 0ځQBLwa%K⻑bGzxx+_|DQF}wHر#**Ja5xܹt^Z@10FP'''߾}Xy5e?~D[[0WqAŠSL)Za=&1 cExNڿ͛7K+\<i"EhFt5aYDM9$j?_C(*k XEmƍNq֬YbŊQº00bۯT de>Iey&..ڵ:UlwbƊQĘ üy˗/wܾYkmwޅ*)={+WݽB gd1 2f5SkA'jߟ#G[n&IKKC)W߿o߾Wvqqٸq+hd1 &JD->>M6UT8qaî]Ȁ2eٳgҘ¿E `_ sevÇUGpppHH0aԩSi_k|„j4lĉAUQooo0 ڶmi&ϟoԨѷ~+s߾} \r%QR%, ~XQ %֩S'Hٳg{-[6$Hwvv5kVllڵk'/HD-)))<<<{]jնmۆ4D;vӈ#^#C\%>MoҥKk׮qoܸCp:í[oOOO(ϟvmŊp[lܸ1/\0ԻsuauHI M=~׉ ʙ3'|"GPu:|08}͚5tִiS PtB?W?EXIu1Q&\38nއtcܹ>ď?Hn#/%.ZH `;d^ֵX3YkwI {9lH/[ jǎ+X иzj88$&`D/^L͛-[zj|ɒ%Kq&D F @PJ*Agn$4h0`lH^&MOo\r.^dd%.(`֛-ehl&0sU۽{w˔)Ӷm[www ?~>>$j!>|8p@ uqi~3CCCݻwWV {ݻt n&=T0i EK.kM o^(Ϊ^b}n)Mݻ~X˖-KMM3gq~!s۶m$jp^*H~SBa %5AF?ѣTׯ_#'ڵkqLr6Žhذ!] (ӏ2N:CdCև5 4o<qϜ9?;w.\xϞ=AhbHFKȹs熌Z1ScPYTڌ3v#FM?[ngyMѢER}Wph~*q߭[M4EիWrg^@^Cc^5k]qE<@GƍGž EM`QSFHnsȁ+~۷^~aGyԩ$dn!={66[_&`Ae5kU(j?oQиw(зo_زY˗/%vEmHOxBFKD^׋D_}=wޅAn B(w߉{Qa!t[_`0ِwiҤ ҁ4"51ND|bbb;ݻw_ԹvPӠfXFtHHH\WLDZhq@i*N]~-[1c|svޝ-[6Qx/j 4XjUjhP'oa*T8x v/T$suu6m^NyzzbPrxΠn޽#oiq m% HCdCcy}"ExBV̙[4̭x􍀟߶mۊ-*]*Tֱٌ$ Hx=0/oY{QD}I]`9r_=7m#݊{H7iLԀ ҕ+Wnܸ1DSN/;vx+WĸHz{>}Z ύHAND/yfMXԔ7nHlzT  #헊㴛7o"``Ǩ 'G͢Aec cHa0d%5ޓ%*𠠟<}OPꘘ7n}gK j${MMsr߾}{޼ypUV$q}Q1w…]>\r@ݳrB;6e2J pǛ7oUƁȹpBnݤQ-~єAYf$V}} 2qf͚ :Qkڴ)ӧ֭[)LYQ2כ:u43&&.h5K[I~,]t:u`%:88iQX`mUٳaS(jx` I &Ȋ8di VFhItVGtttGٳ2a\ΝSG{Bjdt[СC%J7=/_N6%5WWݻwSzvAP3f8~ٯA n+EEE9#Q*j/^ʕ+;vE.ѦAi&&V]x14ye˖Znz왜|-gggYQ5|J?366mPkdv%dQc4kPLHU?~ YM>xRQ0իL2(֡CٳgJ{U2AMaQQ3v JkQV[={$tGzj\n:gTF6,*jb~^7( VI fiUx[[l7oݻw-T[ƺh5[X~оAiV1K6,$$'a۠Vbb]E3M*([Qt-[iUkW!cCŊp+1 IZ{.449yovdwXm­$7#b[]E5$֪iii8/vQ]XTCkEJŊS^V\5ɖ-%*#Kڵ;l 3( o߾ãL2_|ׯ{jժ,XO?wrf͚5N:t9))iٲe #Js1l*hSΞ=k lѠ_O%z|mݺҥK~~~3f̈+\={ +-Zl *aۊ+Vs׏WZEBڷoC])11̙3 `ApHq"555,,nݺo6^};v2eTm\mP}2JO/_\fMʕѫP<&LK .?[ZZ@?.!!UV=իן̍7S#FݻW&m۶ݴi[n]R1cP޽{?{LUkr[F JUUҪ,ѓI4G/ 027n͛7#YhǏgK d+WȑѣGGPz5h_ɒ%*"@eeJب L[ V"`0lٲAJJC%['**ʕ+K>w^.\y`d Q>}\v 4L`Eq˯jт.+… dk!H=y:uB!pL {y"]rCشAiJZ?Gˑ‚3Ǐ_"ׯ_RRuiXk8::Μ9TbEѴ^/$ӧ5s6mn+4zUݚ*T@$FЩ:ut*߸8ANv Q{|AGct .YD:ܵkJ"Qzu%FJF`k8M(IzaΜ9QJʚغAiJZ޽{S_iΜ9ݹsxI(S5t%JDDDlْL`p໑1FFFvҥ[n2se1l!V2_ү`wʖ-+f  [\2@C8kl g8{Ub8m4%X (p޽jժmذW^/F F>pE" o&o޼bŠnW4Xg%d2en޼ iѢ  :45PV-///1nnn[*U 5o߿/(j& Slڴ de؁ @[IjA6|pȷjݺ(j'O֭a,$o b$D0av!G;v0Vj5 :{GŔ~ڲهAi [5&8Zfƍ۷oϖ->5}:v1^b҈1Bg_1B[ qA0r;w.}l8,.$5A7ÐRЅ@ I&_[)5/^uÿzK¿ѴDPmKѣqAAA0|T'5J?TR(<͛c#Ϟ=ϙj JPQӋ@.ׯ1BgCʆWѨ3#/ У3g>/W&\Hi&̡nݺLd<nuAN<9o|*2ZkdR>T޽BKCʆW0_h>/𪲢6dDѢE/^Rd$鶒(}ٺu+0 ax|*)z̘1g$''XJ:6m%cQXA &4dzxC27.RQXK8^#~U ???Ab[(X8;@E6l؀KC!jb.PD *TH|)Y5q81-S%<_YʠTL ^ ֹsgA"(UMlSvi޼yRp|ߝaVv@,H V޽ i ("Gz Pdp2yۛ|7Ag2(j[T2rHi% t)}V~}qCt&z%Q?&HuΝM6V$:yQۺuk+Tu# axUӢ&>=ŋ!a^U @КNVV֭[Ϟ=@Ơ!;,.$+j>̝;7) 55%Lѣ۴ik׮8*5H'\-qgD {' ~(6N/iӦLJ٨Q͛7 ru>}ACM]kdARҪ)))ƶf N0+I f Wz*S ph2P6꾸< &8Phj׮=p@.dZ 0zD&Ml8ݪ…+R+Vl۶mQCeV`d 6Po߾qP1۪U+`SÀ5 @ɚe̚d -Jp+]|ѣGU5dhݺu/;,4<{?z?DK8Bқ"Rv(uui&D-((?m$ L /\p޽tdYfVe2%d,Yy湻BivkaAYbr2 %d6,$$ \reٲe֮ue|[(%.B*F,<5j.0D DҥK?^5]ܹ駟*)9p@ ŘmP JB5K%KbbǏe f̭[RRR_ ,W^bLܺup̃{Q ۠,Jz_m36 a WҪ>}N޽^Ԥ!OΝK!W\UR 6QFo׮]LLuժU}>zvx8pPtEmԩ(Y@5% *EQ]I?>p'Q<sոqk׮CN?FG1+9s[˗/oРᥝ~56k֬`8zܹcxi,jfmP 鶒(DM/=jz:wܦMjB-JA9r"GNa,0=z4nUve#0 ʐ7BQ3&VjUʁ~鉚v 00pѢEz&PPH"۷o456t[X~ 8P5@ٲeswwP6YLHX{!pTX4lPd2/j_ 4i'jbSM:U}t 2M0?4+[.J/'j Z#U,j aTB[iذa/͛7EM/!*^BṲ*JlXSw5lӧ#0 i̋[_>O"UFWڵ+o޼׮]3ָ́ϟR }2qFǎL"ӠAc>~xE{3gy+&]坜F C۷oҥkע$5s;lJ03bXJIþzVHII8qbf]T)AKTTaN&M(Xpa۶mSSSK,9|$={vm>Z@@%K j9rx^G2 E ={Xʄ8RHI`3TsLVڝ60\Jٳ=<<>>>>$j H渻.\$]+ӧ3ÜݻwU2M&C*jb.OΖ-[8:: f3?昬;`Ŕ4CJ(#\͛ `۷o{쉋3̡%)')))11y[]t֭aΝ;whM P^|vZΜ9\pxVP!f~1Yk\Cݔŋif͛7-[$Omʔ) Jzaѣ۴ik׮ƍ{aٲe>}#lڴ 2Af͚H@c! 5iiinnn={Ml%*;&k`nk{6_Sreӧ/^<""">>F...(f׬~%K.M4_97nD=H2&j*RQ Ezzzϟ^Ga>;ޱvUPyB)!mDz s޽{wM (1𸱜/_FFFz[ /4K8 bcX6ffý%cv30½1,j̇½QN#gEXKII15--MatݘL#`QcC;͛7M,e˖r)0,}?T7&$aKc^Q۷-/ښ5kfiXԘL4 S۶mU9sDЋdɒbŊSX &xxxxyyM:7nܘbQΝ;$j/_^ >|86m߾;,_|ׯ###v:mڴ *tܹsb+ٺ1E$aK1?$?~ܡCI&=yٳk׎rJҥD'~|u*!!V|n݊~~~3f8zhGyĉjժA6n˖-eX5&pa,냂(|rHkH@kN:uW6c&HLҮ];*s)Vpa  ߍN]n`Qc2 w(yL :PtotpFE >/^reWWWCQsrr?|رҳC<==)_ʕ+wqٺ1E$aK15s޽{Sz$ >K.u֢EEE!sBVf͚%իU^r EMn`Q ƚ#{D~ٳ' a~A"j|ɒ%Kq2JΟ?E}oQ  uʹ-Z Qc!آ"_ƒX0 N=r 2d l~Q"""ȑO~X|jj'VXSaKy2*a({:t#ґ}^jXS ?poQ˗҃(P ((ȄTTFƶFDDL>˗Vڇ'22]vĉ̘1cz:sA0ޢ42$cԩSL𯯯ťk׮b -ZD/}5kքa_裟zt gώ[ћڵrho-4KϟߡCo~ӳgOXj ,_ 6|[&QyDsqRSS[77*UPQ\^x1`8S^^^Fq aJt1887o70 jrC{]reȑ7n-jGݻwlJ,9acEh3ޔcNJ&Z~/T\ (i'O"'gΜ 4#Ç#u\\\ʕ+Go^#44ZPPݻwluhذ!ԬY3lEC&\3&Mںu+ihQ~\v-2˔)ӥKThѢϞ=3Vu"SL8T<&OjLXXZ_Eh5F9l*\xGĉHt;99A۩04bŊʡM +V.dիW(yŋ~z؋C(jp8?_zTTX<~d PrS0C4C AbΝe˖޽ÇFt?`ջwo---m̘10ڵk. ]v~f͚ʕ+K:uJ}ASi/`QS6aP.j3f@ڵkH16YHԪT2gl %* ;wnA".OF9r@=A+Tw D(#kٲG:Oz^٣ ,jJnʤI:t@mΟ?~m6tBE_E0p1T hVll(dܹs]1B۵kW޼yэ .^ ,cCh.] ۱cGXXX|XԇMXEJ+wwwp1gM F4ita$q *tȑ8ӢVz&pKu[QxSO~Ξ=}DŽQ4oXC޺u 3gHQOquu={x/[,622N2EM}؄U âv)XF0ORZċ"x\0x^0X2^믿cʖ-[.] . D_EŋڵC-ZdH_p')MjРAp߄uix4acV,~c` oӇ ֳge˖C(Q"&&F9YdRQӋ?m4q4J-{Ϟ=0%ڤI(PԤ{͢>l*FNe7zFCIVRRACeOjhpH5b()&LRŋ7mTZlRS3ر R(իWc%輭䄄 hZBBB0{ʗ)SEM}؄UنAߔڵk駔Ɛr>>>p/!a4~d?>W\P+=Z5\\\*M\9!dɒYԇMXmY$37V1tz>|xܹi&Jyl.** 3MX52cCXei0ޢ6O}f̘s9d}vJrqq :Լysgg>f_|ٿ2e4lĉiӦ =s… +W.""Bнcܹt޶mnڴ ~7n@ O0=OIMl bƛ!Gy& *RلU@I#=z4G#FoպukAY4&..ʕ+UTxر#} i߾K֮]䔘8>ѣGM6>}ϡknnn' G>˗D(@5IMM [۷MGSR5,EhLEMؼ(E#GO//KR Sd#3ǏgKłV\);ؤI.\MЉ"/۷o5kLDSX7a JnjQ!jÇ [n4>>k׮...2s/ƍuwyܹFj˜vΜ9$j^B؄U@UZ0ƅ رcG͚5غukŊU>}:[lb:GGǙ3gʊpT ???A'jQLGSR 6e` JnQ (jժA#7q=[JZveݺu'O7o jb8`Vnʒ%Kl2o}zժU===-g6aPG͞=ȑ#O8QZ nܸq0:D_>p@ZK/N-ʕq׮] 2~1bD\\ܘ1c4(Fǰ0gΜ4h`xix5xZ-B32 A8~fqzYOݻwwp0pl6aP(jPo rB_ Ȅ #M#{5Hɓ'{DM:vZ$08`D #imܹf͚-[gϞtfC*j… XR &xxxxyyM:JWobE0ewww]nUЭCBB.\ʈ ϧAPdrA6?82l7لU@(_K>?.5(QV?~T͚5 fGGksD #imMPBx@>ckJg6v4jg֮];**ʕ+0 3<(LaԜ9s dun''#F\z5&&@a0dZ,XЅ%pEԍ&3 c߼y3_|[nE&2c `V&ʖ51V``ED֭[0bEmb+{iJD0a&ޔ;vYXXdN?JNJ7_NES<(LlqQv+b|&8Я:Q˗8P6)SĘNWW؄U ^j`z&ᗊM`51MF񇠳)z DM_ЅEE_~ED WA ­۴iƘto :ɓ)}55tH_4xŋW\J'lL~3-EQjln<uVD A'j)ec8 &5$ڴi'O*U 4HO8RQ "K7[ϟ͢@$j$?0  z+:t{\P>cҽ)_}ޔ޳g/H>|x.]HZn-I1 W6(j[gI k8ӧOanؗ2ϟߨQ#٘fc_zbZ1l*`F&ZO@>|,)))zE+VϫMMҽ)6mWE۶mK&8aL>%K q )-Z1 EM6xxx`` [w#;gVЍ!}}}߼yM0D7ob+ƫ\<߾}w^c/̆!_&׉lX@IL~= s)~)xbDm8|l;So Fflkw,yf///˾!Qv-4 teb'~˜ ݻw[*qFz٘&fi~pڵk;v|5e"F9[TE͆` Z) h-Ga#ܹ300lٲݻwysJ*i/ Qoݺ52njâf^"4o ymiF~UVm۶m߇K.\;GּyN:8q8ya V)珎FfEF Xd4Wĉ5ktΝŷAԒX"-B|ƽ2eJppprrrBBϟ?SjԨ͛e&"?جY3-66g5*5_MXmYCEM{F... tTãUV4tT"j܊%Jn߾ F3fMXmY$c7E6=WH_|ت0"5}(yaVndoMɂ+Z-v 7 7Khdl â~,bMb+f؄U@a#F߁RǏ̝;BǷiӦJ*'N6lصk"##3c wwwi"4Yn /ޔE`V%,?$$dԨQ<7o^5dsN: >ٳ={̖-G͑#Lj#;tкukk\AX F?xSL~cC͛ҥKӇۏ?vpp Q+Z(M9r>AeLA^؄UAI#FsN&MgS?9$jЬիG$QBJeʔQm ЂxEBF`V%,ݻo߾)Rŋ9$jǏwrr&:Z…IDcQS[QrSxEB`V%,9y"*^Ç sH`cӲeppA^!؄U@I#F߾}{޼yUF)9"w_>m۶/^dQlDM MX7a~|da3O& [/ &42,zѻvׯ_Ν{[QrSxEB`VuݻA,XnZa o HȰ 7 7KMaýE2jY  7QFy7ke38 A0ޢښ5kMf&ðEh)rF޶m[Z|}}̙#ŋ=u̝;rDQ @޽{?{ >|V/׶a )"&J9111?I"""WReժU{QN9;;Ϛ5+66vڵKIIB Zm bћ+l*ׯ_D˗5i2G .l۶^ԩC>|3gΗ/_ӏ[UV-B()"!# F:t8MS*\p1H Eoɛ7odϞ֭[nUm &Jy̙{IԼi$%%%&& EmڴiIE 2aԢnE lDM MX42ygEѣGi&IG׮]Ǎ'cǎ,XիW"!Q[QrSxEB`VܣG9s+WnȐ!d>pׯ#-^8,^b~?~|\`}4FEɾ}neA^!؄U@y#Cݻ'#?|ܹs#;![ta Jn Hl*lC Jn Hl*lC o HȰ 7 7KsSxEBMXmYD+l*`Fޱc}_X 7Q0o#wykȈEh)rF޹sg͚5-[ֳgOԋZprEDD}Y bޛs (iׯ_*T(<<|޽qŊ(M6>}ϭt5v[1MMX42FwVBH~6IA`6aUPȣFŅr/NNN /R/.\bG[6mrJV Ϙ1wHYYfH\v^Aܳ "7e֭~!!!i>1EMŋJ(1bͭf\ ؄̀F6mZ!_} SD>T5Щ7n8q`&_~)V _r~܋/ztRA!Cʕ+M~5٘{6[`憩:dݺuIdP|?@ !dCM P+wwwJ͞=[jb^"Q3EmkSQdj;uz!I bڣGmVM(z@~pp%Ma()֭kڴ)/_N&ĀV\+c(lfFwF ~S%J!^75K,ANFFשS^| ݻ[wΜ9AAAc͛vu8qSYWWWʼn0ܳ "%7eذaSL˗IdP}!V_7lfF^vmbŠ\!!!+'O.Zh``ϯ*H^ٻwoҥm̙TH֭!ajn""1N 0&=cÇ&_ŋQFtt4l=- QrSPz۶m$jO >EMvi/1lfF~fj6uӧO~s _WۚN'[gϞU}j[qݲ1+DM!,55ŋ#Q}b@&sȈ$d26FO?dJYkY›ҷo"E:DMAGZZ|e26F!fY!o T)++K\CM p#|)rndo7Q3`H#WXٳƌC0o߾=%%Ř5v`")rCƍgggӗѝ:uaBuSrrruh lݱcGDDܫ>}PX9sP<: e˄ע&]P(PBST}6l?mڴ)QDPPо}J={={6K.OF }||E)TqQe˖E=rϟ֭6wUVC?.3G5FDI#F$& FgKYL[; sss6lxMVZ[n{.$Lrذa98tPhZԤj=##x3t.\ɓ'֭+U qT%%%m۶`A\7իC<<kٲS|!wԂj)(LwȖ.]1zDXF1bDmĈ *Ջj]vuE\IW޽{Kj֭[ׯCnݺբE OON:)Zj| :thŊ]"ӌtqtu_ bŊgp"""OƎ \re5P(japի! ٲ璍:t@M4.O?Tn=!!Ņ֬ pss/ߏuZxx8N }٣0g7nQfN[@7 lf$-c,w|C 0Y7nDK.~-8}PTJtڃ0৥QfӦMI4O 'O=ݶlBÂdݺuH'&jB WϞ=>}:*Q矑sE#:Dzƀ؜beL{ c(`֬YP'r4k֬TR7.](' ,(PmN٘SN4Ri]vuEoooB j5A) R.mLHQR0aeW7ȳM1˘KC 20J?zj7m{ _pj^| +_QӌƏi5ʄ$µW|5ٳˮ%?&[ڀ(g&j rssل]pA5 Fٲb(f =A2tԱl}aQcQ8LV{t(U2"}wpXrS[NǸ1 Ø%ÔmE~z``A.^ػwx\V%Jtܙ^?yuVjչsZxqmb1 E}^l"JnnnbbbÆ o޼ܚ6mcǎ ]vݿںukAQ62Qƍ ,ĩi,cpXٝ^*F3.fb+!_ÔD9T~}U,Jd{1DM *#Vȓfa¦cc|ԳgLMqjL2oݺe+!_ÔD闊 | FH1LJI«\l6cpXiSJ~RR9w9:p`6mlӦ 9njl߾Ȼ Kd#={ *m׮ ٵkׁFif́aʆˊZlljʕ+kƄT"j6cpX@a8z: LgΜ9t}W{C/Ν;ș9s͛Gx.Hì,vZl)FcÔ E5h"d+==EA:V"j-75(O⿋/FO>0RQVXo߾j\|GbC ѫWO>2/]c)ݼys̄YÔ E50hРEAE=DvccHHǏ_i;v, ??֠AC={F[ff 0S/f͚5TpӘf>LYm~m)7/ƾᰨ1FAS{ vڵ7|oϹs$c޽{m۶ׯ_F05k֬:`ӪU5a^_}aQcL =URd *K$ӧ"Ls7alpoaaQapoa1dXٳge73fʔ)Ȕc֘,j X9 S7n2+;;Ht1kX5aC:9sfs =<<|}}7md`q֞vͽyh94>=~#uww֭۝;wۙQQnIII-[ѷoT` -ZtZZĒ%K:wo@)hxƍۗ/_><<|Ϟ=9}4\r%8׮]7裏H DQ? 3f -1+VDS?S B&A7oFz֭^^^]v*IBPN~Fe&P * sƍ( jXH2 #F@_~tٲeѼ֭#W-[HCsssM vfýE?=U֭۶mtZtt42!HGA׳g~g?3_r;7m#|h$p]|5YA"jJǏ6q^hR?ʯ\2 :D￧yaRJ$jsT(j'NO(ڏ4ir Ñ#G>\yB"w;vT6"Q\>}:`… QCݐ?tppJȠ KRNN޽{ąyƢfM$'z/r%TCHa7nիW>}[~(i78P{3f |H=藠A^A3D'44 &\}͝;wH,X@@( Q =E *SdI8_}͝;7((?l=lԂ/#{npDq>}:Á:DǏC&J葦 5*JoHp3gΫYM`7jVrK(}v=jŨVJDάYRSS;wN|…ĬlƌŋZٲeW^ݽ{݃/SZO81YMԨ4sA  Q3xmz$Q踺hde))S9u4SMAKKKҹ8дiS HQ\p!H@g ,XhQA^=2?lQN>IIIh.dΜ9S"jb&M,_;n=TL2χN}0LAa`GW\ٹs':իWIԠ23!Aɮ1c`h(Zll,[gϞ J~:vfeears'OŽ0?32yV =Y%ytZ# Y!T/N/Z8"VL5Q%Aԛ/_ºeߓ&_5/?~9埭aP"E[i:W7l>AI;FG',T->}:FJLLgJ"Eߘh&5̝0'\lKEMs!C`HǏ%z Gܿz) JTF2_n:2lavE͸dL yPβQUVD~>/V5p0,Y$Ez D WRHEMsLP###QZDDT,5r 9f͚*U (jo1ZQ`m0| mrww' CoRI_!Q={6=r$233!1 6?oٵkWFFDm„ gϞuqqgRQӌ- ˗wލNSۏ=2]`Q JvcvSΚ5kHLL޽ 'jDP@A~=<9sf޽srrn߾}_:th˖-DE[nT˕+wkJ깺BN8!|+V~OXR?0lч&)*Zh``e @qWKHJJ-jpjժEA}z͚5֭sFEEJvc|̃?@ Rui222 SNI_ʂadc(~S[p1l>ۙQvc|3- 3- rssSRRh Fޢ/n\hѢήŊ 5^W!ӧ})QDڵ˕+pa%%WXٳFVn\ECUDץv65k֮];1ҥKQUmj%-R6[~p1wsaH;gffbQg}6|pZI-&Z|KA wQreGRu޽{Ϙ1CP4k,:B| ۷oС:uDJM49vrP᱃ViG!x vXr%jRz׫ܡC \V-\xΝ3k׮ݻw)S[nR?01>CN:կ_ "_-~(j׮][pahǫW0oݺi}L{zz5ʕ+(ʕr%(Mxx#GPθqPr͚5;A_ǎ/\zjM˲Csq:ͭ҈ j"(QFt ਿ.PZ2=~]vA[nnjSdI J*+VTQYvލtBk6Y3lQβQ_xwЅ 1?pqq!/ E@0Y5qk׮Ag矑8x @ t8 Pv4bi"## J.СCٶm_~ED $ Z7[!24iRnnn !n޼]4la;,= %,b*Qɯ&jv@^|Ipp,X@~&F쇗7dȐrF+;vLv5a„ǟ8qX _~)JVi,ZG۷KLQEh|uuuuMMM'O;v 5I8p 5`S`ioG&_ۋ""(_<|rY*jh Es$ř5u$R&\38nT {蔸rk~pj1S&|CKF50Zn 6inU5H6… :;;7jm%]vɒ%OVڠA' 7[4EMP- elڴogϞ|9KV7{}л/{-_}fL}:}퀰aiEƶtCpo1ӌbhpk -]ۀ{ftdlKJF>##%ߦ;wFkduܾ}{JJzWe)A|^R%u4$)FƦt i^m!jE)WBӧO˗/_X-U)''lٲH)jZ:u6n܈D.][$:^ -Iq"Cdc[ ʁ;ɢ5{kZn- O*~ PdIP * ~-HA֭['rʖeTi GL~1\Ԡ\#aԸqcQ$_o׮:s5DmŞIEm޼yδ`Q>>>Æ E/E :g;vEd# QC)mzP(jLh?҇ݻwaw0mۄ3VBiػZe:b B oj=?;v,ǎ{ϋ⒒ !CQ ?_-Byj+ :դTR4Iϫ4?~d2*s̾|`yF}6=՞lPm٘UgmzP(j5B4m4gϞ^V۰aCWMo颗@ ^|McVg8D<}t vwwLX"j#GDB\ DPwm1@\2FJcQ9Upo+j???  QBEMM-88ÈݻXQ\Oļyp`xxQ=ibLq!j UEi )O>8]jƢfsp2b=(jTƍ3-Zv|ڔ)S jFZZZʕ+۷/iӦ+V|(.'N,z:\`AGPWLU5\v JJJի2N4 ;4id NNNKƉVaիWF/lP[Q@Q;x([Ǐc!M?xa<ϗxQD:u*}2? ߶VH7k֌}6I~GnݺњP?~<Ğڵ }Q5kP}D/ψAkhUZ;ۜgTuʲXCoa[/_Ⱦ'MN?~9埭UԱҔǡ~khPz8q"0UZ9,[7XCSN2",jXCoavDS`HjjƍׯR… )̙37TҀ{AY8l۶m'NL_P۷۴iSD}!ŋ{߿?̤p*|ԨQzg͚Eo~Æ !!!gϞ-T3Θ1CvMm,ݹlCZbŊ 4$$$*Tӧ˔)3?C%{֨Q~TصkcǎhJbbbV"޼;֭[WT)ִi;vP\ 899;wNPbNa\t ?}46UZj zfdgP^rT7*a^|MV׮]F$&&ݿ.FFF7|...TЌ/DN:^ :}@PK.ywΝ$O>~ (kHQO 2 QCoĚ"Z-}+lA7(iUQϟ?OiHG},/\7($@",,l߾}b9-zЧ_{,C={tk8($++VZׯ߿ŋnj#[2҉F?JĠ^۠U;h  jF$jz@GdffznݺQPyC HXhݺuS\"NH*jI&SNۅ}n߾#Fѣyym۶EN![++bQc3^:|MqE (Qꀜ7]vUsҤIIIIT^iF(R^= QLGMfΜ+V XB ݼys*PFJ&[++bQc38|/&ЇAJ|||}fo\r(A+ 5 ZD  8uRQ;z(.%lڴ @G{T4k%{E,jl7U߿i^ȥݠb/_FPw.3rr;hJ"DŽmz{aM4ܪrX|/[Q7p2b=&kn7n6cN8|/~[ɞ1115k ,]t.]ܹm۷ q͛7lփ{\9[U%''{{{ggg uֳgOm;wԉ^jUVX[FA4)cXs6*Dd 4 ݷoСC+V5233!Fݻw Q؍VՌ7SkA#||oBB_%F![7.lփiFS*tm iUHXxx#G .1SSS¾⋓'OiF7עE?366Bvmo: ty4(r-JB3 ġCIҡ'O@5jԽ{vQ8,HO:5((`h4hGo: ty4lQ;&F0af͚*U TעN_>1𥧀իW#_5o: ty iX1˗/GEӧu!K6~n̙#fBpG4 rqMUa8V6! C߿_X1ҝ%Kx-j޽{ 71.\pm*066Wk׮ *qDDWtZ&RKcneҰ:DMP{5lذШ(+E}c6lxAKŋ{zz_}2YԌaaPIۖET:jM6>2?N)sss=me2–hfpelKwI ({bёy,1-7-6iFGƆt4+r8V cne>LD m-_[ԜԀƗ.]BlA*ҷ+,YRLUV^s޼yƕ6&G 0by¢f(/^x1:_ec|Ґ߾}ƭqp#eQSUDQo+Vxq?|ʕOnܼyӈ% ݣ.ZpAAAd3gD&puTٳg_x(5>|61:}XY̙qF$N<=?s=Z`B ܹSy&yvj(J(j4p@C??`Auĉ˖- "YϿ{@&M;FUR;/zt;vDDD@C6Q|||(‰=<<03}׭[=z4溲gǹp--ڹ59w\^մs(F W _~*U>T ԪU 9bM&Pr֭w|G$a"a $j;w5kg}Sy@uDVV СC ZadÇ~fdddpդj8!!! ֮]5_!:s&ˆ)&cdG$jT!>LeaŰ $S6m0/BkNZ2租~JDHĉ={o߾}qF˗/F_Qw߅4o|ҥV N K 'O`EߺbbWZ C")) %̚5k0;vonJ.QVti*((H +%%E_6zb !HyŇ~P; e˖kQ6P\R9ٳC Ě6EP z׮]y5_\9ܼy|y%=AC %^@dB?>m4oѷ[=!+_ȍdL)* `JOO6l]h7|R}||/퐊 *ST#F`L!j'GHGDD`tBw?Q>._HcAD˕W461٭qp;Urf/5tH*.8H!Ր!_G=O8*@ɞW4L j 5߾}zׯ)?QBɞW'VR\6!8;ҫpݫV syEppc{_wyGxPE*j"s3$p-l٢V,&Z+V;-XPu~1<{ SV1Gll޽{14h2n*H?vm$oBBB0eggx MիxRMg~i+?C.DQVvm$KÆ mFD222&_G=^*.:z0TApQX5j=ZJ#G_!j^4wߕ=Tdϥ)joVrr2lVzkQ srrv؁SДe)n,vqE &9bŊ} ZϞ=!R'O1BϞ= +P$E1%$$JIC5E K$(:V D~J"}AVPSϫ45sb(JnQCρG"///+5H.9Gx),^xޓzjJz75Hq j(ZhSN=Td%D5]߾}qɘdzKSH~Pn,vSuתU:QF ZLL EO& V,|Q\.^~iiiqqq:D$n(tA"j?S i&O2E`@~ݢ) ?F]O(lҥQ,d+  A!}[ZoյTRTlYz!DI&~~~޽..ڞ[JJ J ^hJ.D<#fj%kF>w\VVݴbE`AAA \|9sW E]t("ݻ/}ɲ}vz 06"}آE7=I,vOȉ'ğ01 _Q5W\HpllEdKvN ka[#_iLL2ƍ/7/cX C.Q)Y4{{k8}4Bhho&}OsQA߀Szڴin,v_Mȑ#lppcqnZ\\\HH^f]v޽;ٶmիO8188XM4#j־} 6gϞ\l۶- RJ8\8Toц#pp;5P>t… C5d#؏3dɒׯ?p@*UVX!F;v "IEM6>&jUV-\ɓ'nٲ$9gEf̘޻w/!!>aN\(FӲQ!P I&YsqqҠGNNNRQOhZbb"59sX֭]`Ȑ!;vʈaYXv۩3J?VI6< GM<Ծ}(H*j MQRZsQ>]֭[Q#""PɌ,n,v_!/}QDM6ph\Q*)j;[rQ࿿F'/_TRzz:$u֭]Ðrґqpc{~+jQeEmڵ!JHH+ m&- !C/^9l۶9,,VZf 7};ȣGL#ҾeQH$N$MsQhSrrru:k}tgbh}`e>,Ҍc.K#ƴXK4cX 31-_-<ŒѰtWbL;tK360c4,ݕbe>,Ҍc. Kw%ƄXsK4cX 3F]1Yfҍ6tbLYtc3/cd,ݡ`nen,ތ cK)XCYK79cX2=1J ɱtc}NJ`lKwRaaaaaaaaaaaaaaaaaaaaaaaaaaaaal>3 endstream endobj 299 0 obj 67940 endobj 300 0 obj <> stream x1 g *vw endstream endobj 301 0 obj 200 endobj 278 0 obj <> stream xw\AŊD+ƚ`4vE^أ^c%+", J"Btoy& Yawg=?x]Ns33L0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;FH ([90V &bfyMVVm!dadB6!!dC2###===UK9/"'-- mAuHI8 SݫWL}ڈ6TQ0rqzZ:W\\\ppsL9Z*v"'ZB1LLDekC6$֭[_<}gΜ)RȞ={wrrS+WX[||<&ׯa+$2f!1++ !,aLL%xZשS'K.H޽[a?,8[}W U̅**.* d"<{wQmnٲo߾՛={6ڱc2ɺ3fLv/˗upiӦ lӦ rHϟbgg7o<|ƍ7tP$` ͝;aҥ6nبQƍ<]vUZڵ+JTݾ}Ç0SSSjh;~0 Uy ڵk xu+V WJ!+WX'r&L@6 BZ/ oooᘐJ$I IQG~9ٖWF;Î;"8qrM‹+Y\Z'<<->##Wʒ0&l*xa0?`A!4 3{]*^83-˗ߏݻwǖdFGA$믿Fflll"E`sDhmmmooq G&Mĉ!2p/]JJJJOOG۱$2!I/v7n;wN$Z hLB?5lPofA!g̙ٻw/Ix"d{Idjj*~ D~YAϞ=6B+OXF`@~+!!޽{ުğYoI=IzUn]<;Vȡ!!!$͓_7p@J477F@fn,--PPȌC}||Fhxڎ%a4IbJJJ\\\xxx``ՑDbܹY`mDӦMq4q ل~bG.+{1dsHرC&^z=QJzi&d.]fff#GD!CyK꼼._VcId"H"XXXX@@=.oRI 'ݵk׆uw]Y.WƯ΂ KLL=z.]mۢ02$>y_RkF#3))Yft(d>~VroWnuR$RD $ByZpoܸ UBW^=ߴG?bKֹtZ +eIdB_a9zw-[VHzC Z SK"hxX Z}˖-Ϟ=`%XFV"H'}}}a%ª0 ÊgH",}pȭDAJdCiӦ o(`mm OC%eO=<< h)Z/0f!ѣG/ 7 DC^X25$i MNNF֗0FIHxmŊvvv m߾}͚5i߆ vy-Z#_>|8{FZj3vJ LD,D???eʕ+E:ujPPPÆ aIz{{ 3ʙT|yGqfffSL۷o=TÇ%a$*[дrЛyd8k9yܶm_uٰaݸqcrjժuq_WDpI80ExBDTL'NDDDjjժUPE #G;wquf=ӧO8K.+WLOO , m%QJ\lY޽) ,Ý;w!?Smz%cY=I"=qfǙa4xC$Q^q̙#Ι6mڒ%K(}]D[[[ {RƒQI h (xW5k֌9osYD'''8˔I'e,EA%8$FEEU^?ӭ[7lYfMJA&I1cFϞ=_qss7o2]]]7o,͵:I UD,}ps 0a„%K5ݻ7^Ytiڵ!ǏoРr`iӦJ**UrqqIKKɟA[ZZb &8cVc+a4 }=X KMMtbb"LGx9ݻh9_z4Oa88hENHH}scǎ9::9rD75rL8^"h|h 88xӧO?sXFW D6:DիW<’0FےUVݻwϟ?֬Y:q’0Fے8ze˖!Kzy7, mԔDH8gΜiذy~={&/rٲekjڵbŊؾ}֭[Y|||Ϟ=-Z7DGG߸qӉ&9C YtL)Ǝq’0FIT˕+wϟ?[n2g 666eطoŋ34sҤI7o>|)~~~5s6m9sXZZN21vt^OzK"hu$Q9ILDlI/)iZ7b2IsrrW&w)$v҅2U1BXFۨ#ʑpW6dLL dPȄN>]$8 x9AΝK*c!, mԑDH8֭;v,UTݻwDȔ$^v ,FHݻeD1vD6Hr$5k"B ";)A9+NI|LTGVD1vD6j>qV3f̘ŋÇ '26m@c{!;88?^YU1BXFۨ^8AC_z^vvv6V\͛7ӳgϐێ*c, mtƹK.pO:;SxQD6ħOnڴ 2jDdԁ%a G1 XFhD9֍n`Idm$^r^zAu;, mԑĬ܎ ĺa K"hu$WoΟ?jժuҥ޽ -, m>q;ͦM5kܻwa޽\R%a͇JbnCB86`Idm󡒘G 1XF|$汊M6L׮];qD^0FbŊaÆh޽ܹct~5D6[[[cݻ'Z ’0F px!XFg%a K0چ%р`IdmI R0C%իWW>>>LaIdmmI۷/ , mԔ?iӦ͚5[n ۷o/gÆ ݻvjee5`7+WVZǏ$gȐ!K.UsѣGA7onD6H"~-[?D9};wM49Çl2إK+Wϙ3rʔ)WtbŠ8Ⱦ}ڵk'Im9, mԑDp:u4$"I۶mիWvvv*Ulقl<:+8ΐD!6ʘ9Zߑ f'#%a:8q P:**$NqE9H@Аyĉ:u5jlEٿ%QTʘ9k֬[ss8]A0FI\zȑ#)Me@G%''۷o4qD1s0˗/mVm$2QG2>|8I3zZۼy?^FT#yfٿ%19-[lҤuYK"h58C+VV$ثRJJ\\\ J.ݩSƍ_pA&*miic%190GqgϞ D6꿗#-GaqΫWʘ9ׯ_PÒ0F8ܹ!00P6XF$Ο?0oXF$2 K"hmKwﲳ?t/5UBK"h-IbTTLݖF}͛7zjP`Idm%Itwwڵ%Q$2QGo߾b ;;o߾f͚W BDFFښO4 ذaEժUiӦ86P=zϚ5ٙ%QD6j~hѢSN A<<}XDYYYMv]be˖6, K"h;wXYY=x@!_,&M/^’'׎ׯoٲ$1&&~}XD ! DmdzkF"Po9.h.],\P#H?'g}%Q1$xLOOOKKKMMMIIyHj>M"##"hٳʕ+_|Y$~Ν, K #CτWH?T[_#Gԯ_KsLXu$,d #F# :;vTPa:[%QaI=06`rI7:Z:xABV{h`޽{ؾA%UTyAxD<Dpp0qqqZ>F,:f^Bm'$$hCZnmjj[[[޽4iJPuh"Z 4m|jժ͜9QN:t… ^Wxq???$ĉX֮QK$D 324.0!8lϞ=/^lgg%C@A>|L PPE֯_ߪUX GgG,h/_BRWa"H Rm۶ݲeK߾}ի7{lcd4ƌӮ];LaH{48j*oekԨ1dHQ/qڴic tRx|Ȝ3g [bȻxxx贾$ux5\>Z *R<|dgg޽{v?8p >LhXpY Z-vgI6$&&&}6*_at\~9ŊURilUreQ4&L@6 Ҋ !=x`$O6nnn^$`Lk/X2)3v+WN/_&kIO@ Z@j0ţ_~ 0/֭{M$$'h %QnݿƍΝS) BlH26.^xժU<._~VqZ-1)@DGÇG&H"k֬񃎁 WTRuԁ /\I6NHH@htxSl<5:,>>+CF@\zCIʣD$E)SO 6Ŀs6Ñu\ ޡC333KKKl /^!JSN9o$>qħ~ C>N3a mq t|!>ܦML}IQh???|􎁚 9AKAVЪ$2h"++ÇC0w[ {U0`+ƒƄu r.K,iٲ𯯯ӧu\T˗QC%..Vqk6$ƒ$!_'ʕ[z!ߒ((XÈ_c>|0***222<<<,,q0hРoV@/5rqaPC "hIY :믿0+]Ҳ޽{a`>~VI;lN0K0Ebo咘b ;;kk߾}͚5i߆ vy-Z#_ʽ{FZj3vJ &pJ,DFjժ u<~…Yf9::+W=ƍR%oE3-R^rʕEN:5((9koooSStqZB9ʗ/OGqfffSL۷o=TÇD-Y/ ę!"""lll(}M6u޽x͚5[h,`g 1%c`7y^zQ>/$$DDZ/ H+T@]+00^WX$Q|/% lܸ̄  ;>rn*uix+zU;piק̙3ΝKZj]vMxeƌ0iL$ 4z꺸ˆp/ڵ}k֬ K;tRR1K8bwsYMkԨDVVVӧ$ $Grryvva$@Aa[ 2bĈҥK_~]ƒi KdI*͚5y u) ;ΐDkՑSNYXXP :::$jˑ#G.񗉴͛'u) x?֦+u?c D%Qgǁף)$,O>aI4 XuɶmF!u)]Ò)))L Wm$GU\&!!!uԑC577oԨQJիH?/^R- ~>>>P|%Q|c%Q%~iϞ=?v233@gʒ E{|%QL4NQS׮]۰aCNߍ7H?àBb[l֭[ժUŇcV^cǎAAAȉ2dƍ;taaɓ'c%q…q唃uʊ^2G`͚5(kjPZ\p=-#ŻvZRGCp!2$jղswwG> o^_Ά ('..K.PBط\rX,:?ܹԥ`t:c vEEE /aOaaa///ӧODDN!ze˖ԩɓ'?~\L'N`VZZJDW`޻wښ&M?Ç_liӦ {~Cf۶mL5kB\2==C%Q`BG__ u$… *UuұiiiI">e۷﫯YhQ 8p'Cd=*He0ifggWR(J#.6$Q:i1re~L$U\! 5(H""+Z&^٫W/l"EPȁ|-Yݻw8pd.;tgΜGծ]۷oŒx9A7mD'hÿ655ҥK^Z7nΜ9 &$$L0R\nݚ5kįGPedpѢE?B!\28dAQT4ĉ'RT= [[[8tH@xϜ9Z,<ɓ'K] Fw#YYY?D!FL.+VLXn;wWX1ш%ȑ#)}}IBѣ-o߾#.6$NiA(5peq&Q=IO?n NNN,\軇JH`H$p0)K] Fw#;w FvM(S "ޢ ͚5q# zpBfǎǯZ͛7Œz?Ɩݺu;Ο}Nl?KKK?^F 32!˟r*%Q9\ExN KU&o$m$ "/H"Ϟ={PQ7iСCTLnx>%Q{rFcШi%eUT} %Ktpp?~ ;v @ŋ+T -=Px1zBpm۶SN)))R֩Sƍ_pvWPDz>,_zt؜EU*Uuւ Iۛ$۴ibLA&.\{\;gh#ݏݾ};DŒ( Ç_.#Լ_qMH֭[!3Khė/_B0<<<%ôʕ+D%..S1$DKyUٲe) SX!ILII[/Na A&1+V(A$b"$R6F7tAJ0I$ѣ8'h}݆%QVX1uTKhDrܹƒ_a"C۱$꒐KhAau$F?A렍^"Z͠%񝜷"{rrr>|(uA-4RwigeeWBn߾͎>Ch5DA߼yF͠A6o,u)4 ]ho(K[<>hr'Άc,$1C322SSS alٲGRBcPQhūWsFFcDTIbnOף6n(ammb]S|\`DT,zr cIyɓ4LXcSE^"I"25Dwww:^,zOy&۷oz?nX3z !Fuz{.0 *J](Aq>ydjԨ1tPH[[[ssI&;99z٬Y3w111N:3ʪ}ߗ?N_2+W_ag+WVZ۷חCNfg ^"J2].>>^uM0TgϞ N3ؤ$"lEu"va{@i {Æ DH 0ѯ[Cl}Yڵc6mO$8u֬Yؠ_~-Z׊ 믡]tq+Y$E'T\m۶VZ8pO>&`@E4h8gaGV:vX-[pt` tx]Wރ&@FGGc悕hlɓ^AU]^zUTqvv[o޼I{|9<<\,_}$%]QC@(}$af$1..޽{ׯ_[oݺtfp7.]#j֬ p̠r;v055 Gǎ ݡC֭[#1dd~wHh=zPKCCrJXXGFK8b-C&Y9H۷$.7ID7ID aKKKl7ڤLDAgh hp V'bt4Ma3DLK8WXٳqOFvoڴ)ݠ Tbaaa&|IΝMvE\ _WDN(nکS'X8t[6%I\v-m> W^H 8P|dlCKUƒ | uAG1zJ^]d/9j</cA+ly?lO=`W01$7=`jJbRRG}dgg){֬Y$s+Գgb#aD_>vܸq#RJa F1XԉxeI\ $~B/h)lReM9ӫ$l޼y"ELMM7n^uԹ}< Dxހ-,DDrcǎ}hOW Iy<|H!hÇ XYB#0!n@:t… N $rI#I<~=Q YϟuK:RNJeiӦ o\'1h ])))aaa/_~+ŋd%&''л Ā$1)) MrcИ$J$Ig+Qo1?^ +ѣGϟ?dI]^իO<P, .O˗/fee5`z9G9GLBBBq___\lذaϞ=Hddd;رcPPhtKbVVZ3ϒ+Ç0Eqo˹L2'NުUUV x͛߻w&M?5ٿe˖Ӯ]9s|ѣ˗9}0% \Bq|Ԥ0hIÆW~a xEo1K$%PO+H"Dwޔp zGp޽;;;J*[lA"-- _9g)'** `"E%* wڥ2~I"TѢEa0&8\BvzBKG!ad5ʦMlڴ2u"g͚5?ڵkuKˣdr`UJq`ʼnsI;a„J*C֬Y6Zïe˖5j$UȁPD'|r̙ G+VP?$ƍStիW+%Qߠ{d%| ̭wټy3zHffrNe(Wm۶AAA'N֭~君D^";m0#900 8iҤAףGH"==ӊ#>x\\_[n2~I"bŊ 10jKȒoSϞ=KjժJQaر|+W8f1y^"VBG{[zu 6,,v?3Hp! #d3BVQ() !}E9~I"SVJB y .8x/4\W ׉ ė{BQ:a(8f;ΰD dɒi{.$Ws:u*6vԩqY9G~urrqFrŋ+TP~}xDy[:H"G|| I433S^ag?Umpy!7 =qG+RQo̟?tŊK"N:1~l$I+DF㬰YO:aI4 *ӧdɒ$<{]tpwW& SŊu&d3]%р`Iԍ$kFtZ2ehUz{{㯶jժlٲ-Z9rV$,D᳤LPΛ7oV^k.YwV\鲫+:,c|pq9dȐ7wKU'U˕+WV- va&5---;ut)MS$/^\]+W#)lE6j(OӧO, ɓ*ד*G)t $== SÃVk|K"RZmDmH8fffrYzR92KPA^Q_P!K7Ɂ{2e[[[ssI&A6lh"ҴiSl,{s̱ٳ'x77jժ?^&>>p %}y111Nzn:ln_MMM84ٳ޹s'Ĺs"ٳ79G&ZBIKb"rYO!G&D^?$1-~y\}Iٿg z8 !ܺu+mG3%%ܺu MOOGfdddff.]ZC|G‘岞T9BҮ7om?Psrrlll*>B>%“G,DXzXׯO7oDGE}^&C駟/_%IL&ұcP6m ,#e=9۷o<5H{/… B<|$ !ӡ`OOIزeKoooʄID-UVm߾}(: Y~}/XH8\֓*#yd$ZYYU)GTJҥK}`߄@?^D EcAQU,%F"733eŒK.ѣUJ":3PjUhq?~|͚57o`RvY'u`0$$-<.7D ;;;999]TM=z:t.C(.i%'t{\%҇$h֬YcggW ·W8%?s?VϞ=ۮ]|.H"4' ^}݄8Q/$-$b?|ЧQ!kE:ujPP Zmjj2 nڴYf8{޽{ ;v, VbAx%>Z&{$ҽDiAMI,W'OX[[ kTGG={..] KNJJBď%QB (9Y*?Z&h)KTDa̙3e _vMeXB$/|Ǿ0M4aITƠ%%/0|/g6G$ʒ2MKP۴is\vĉ1?#4K2H":gg炿"KdIL޿H/ᰕA2MKPWX1l0laҹsg 2p@;;;̛ͮa`` ̡#F4nÇٳ'16l"u) (T!>Ɩ36!J"&K.;3225juV!&DHNNz[K\ƍ$;:Ν;uǏ3fԨQ#H[ PsYb&wٳgR$ Quرc2*W(I$z퓺IWGػw O>ŘHs'UӦMC/XسgIIIh;#?SfTޓ'O֯_" KqΝ L&t<|PP #G@\^&ŋEF cyh~IU%K@ QGE\v-22EYܹsڡSuaK]}*''NII G`` FQW;vضmfcXX>lӦM:.dp֭yԿx1۷cbbR333g1~xqŊaZK]`4/⢣1^ a?RB%J8998p@gGmz|?-BIa"mՇqÆ R1$e0_?iiiϟ?LjW\ 3>5j$<-^xսtY6\HmB{b|0x#FH] C͛7ep`$$$k׮0nq=sK3۷oS"<<|0?*xyMٿ6v{xx_hE~ݻwzn޼yqݻѨϧ~ڹs琐ŋ;uU8י3gz쉃={ҥKUV{$Xt|^%,,lyosim|駟qdroZZ4N>$֝D-ZP&1>>~ڵ[n=x uV@@mcL^&L +ūR w]TAs?y6ިQ#ma$ǎ z n&hǏ1ܽ{Wa\~u=`{nZjx{O2K7o uvF ::zΜ92dH߾}(hk_~={6Z~| *~֭Z.2-vȈ8qbV/^,>݆ #?&&_~P®]$tFw>fILL :T0_ӕ3ux~$9>C3 d__߯*88xСӧd%͛7#ȑ# .TѣGDZ1k׮egg 4} ԩSӲeK dVI] c:Ƒ"H"j6`Lm|󍓓ӌ3 k$͛Gfw}۷m&`9;w>ue,$o֬%h@C_rER0投= 8zh{} –"I<{ ͚5kf͚˥KfΜ!ϟ5H/>qOH2DcRAH]gmm8ءCɓ'w%99O>y1L;"CHٍ7Ļ6l%##cr­lݻwy%8GEMR0m*g$!!AHSi'$8m 6;.|MϞ=90޽{֭˟ a Қ a +K,IIIc??KgggT$))F%za4Eɒ%sߦ>}a-С .0xjrrǍ'a ȴiӺuϱ"##?͛7KK#ovvvy `$J ˅ pinYݺuݻRQdR±ݘ܀_VGJ]_`]hQ&M ?pi,W`<-|wh)Cw %{vۍQM ŋR]޽ =44T0ٳ.1)))Frv9f͚Ν,vc@h5Rǔ)S_f$cرT_r7IGVV%z"aOO5j<\}x+ Iߊ`d *H]! |B7o<{-ojbbreݜA rrrH$Y$--N:퓺 lBC !###===UK9/tѣGK*u7Ej@60J\ ;{1i$ ;=Q+@Q3*Jb ;~ᇶmۢK]A2033c?99" uLGPE9Ratimm3 ;DQ=gI@<k؊,1eee$uAt YYYa İ$AmDGGC1_{Y}Ə/u)$C3~ff&L'ODDD\v%Q jucI4rSp|VZyFH۷oq0>|sҥK,bPP0Qc,59uTժUū5 D sx߿qƹsXŠ6Μ9A?OX[l)D;d ݃Ò(ՈB!رc6m fȀuV "%XŠ6?~尰X<?~СC8`33fe!ɒ(y˗/,HNN޾}{߾}ͣ.  C6n/_ Q##tC1P s v K.a$Am=zΝ;׋/ 5oбa-;u4a„HX*q`ZBz4b;VbŻwJrvd4Eff&E­踓$bCQ!?%Q KbyXN!>))Ige =@Z~}#J"urrZjwMj{{ٳgcou KvmaaQz޽{رCۧS-BBA -(E |K"l͚5-[}#I7oҥKt4]aI*<8rȆ 9s:t=MZ~!OZ{6oԴH"m۶>I:'b߉'~P?rڥc"*9KH"CV<<<[6mzid>|E7Mq忿AHS0[dIiHM^*W~x䄆ӧ z2TA/Hټysz>c(q-[?-bI1 K,ׯ_ڵ &jhA8QQQP3tHt]hcҥ˔)C^LѢE Ή 8,}P}w = -KCQIꫯ "$3'L$޺u f͚a 1f͚8>:g@@~ceff}c{CE>Mٿ; TX *`Z~:2ovTA%QBBߨ[?ZԧO\ˏNZ:uTl9rH= waFǓ%i4gggL߂$*OSLdoo?xhjժثk׮ƹNG@2xyWX!/_޿—Hmmma!^r sZH/Z$F#:fpp04苖| ?$Idё RE,]~;qℐ믿`yCka" koɴ{=zD0Y͠`;w]k׮ɟ!?`*U s0,IUNثVZ85t[N4 wiӦq!h#ZMKh՗DzB̚5~CUB)CAx"zÇ$.^vĖ+V_;u" $` FrA%Qρ,]6_~EȏA!IOOA}U666 q臔/8*%ٳHЩHUN2$ZZZ?4l;}TKQԗDhҘI<03gΌ~ fD{ >>6NL#`ʒo#~"I$bnoٲe;t耮Ґ@>sLn*^ f!6վ*%1$$$Ddd$2Ő$erC'rrr,cI7 2Uٳgh5]FP_]\\<7<$qhzLGAv`ZXX@$O>[QQ0S`QFa ߢ[$20g/_~-Ṱ0k]UnѢ==ɟc1H[XB~*$n޼DH r%gS$UsU/h//U_]]]ȡNB@֭i29rdNN$5og755uvvɾzw޴W%saIdy+Z?i$/9::X͚5xh #~bŊlF 8d0ؾ};&qD$?a3kiD,I2dx+|T˗a>Hos^a 8 /($G!BqZ*Kb!@DZ w߾}ʆفh[ǎ[tݻS2F$Hifʤ',Ip)w>}gg6ivhI4 ܸ,khh}XP(D*fRb$w!ᔔ[n]||׮]6lXnO.y###5#orrr^^% !P1aT6F{acpML{ascRjAtI8a޽;wܶmuV/~ tn$Rb󂞬hF(R~ƃ?rF..9::"F033366c455 =jee@z/eޏf̕Xg|[~~~]\\.۟>}Zx!C;C0$$ea14G%Rb3BJdO"wƦsssSSS=z!zyy_U ph |||pAAA(Ü(%d(1Rb،ECbltXbbbbtttdddXX@ {npp? Nj /4KKKQJ(+$#s%@Z WNFF"F1>>>...VaSRR CJ>9I*SG(Šl>(,, 4"F…X1fggP('I :|Xh}Yt)ǜ9svpB &={۷EWi{AUUuƌB3-,,؞;::C{ݻw_d .EnW`ZKKĉӦMCfd Yb&+QTkElb|¡ %%%8 bp(&C ˗ɇI>[nߥKVCxyزe ߱c1pႚ.A۲eKLlkƍlg6lCbbԨQp,R6x̌[~?<<ر#z @{7o>z,2ȃE<+2`WP0^C9`!BlH0  Bׯg31mdd pW #zb"**JIfp;#ȉ9QxX9\M$J\nݾ};t萖 r3\H Y?D4snݺ!lH:P"ޫWx7%z{{W^XQ 'b=`B]]t7%ħ$JDͦsrrzJ4ŔJکS'VC!S4B>''kycJ;v,SXX`6m/&&fٲe˗/pCJ);{q01f.Yf$ %F%?33ZZZ"q\G"=WWWL/]]v3vvv*m۶qqqsOs~ Ν;CXs~JJJ𩻻;>0_.[/3%nݺu쎐&PM) >6vZ yOoU"YdHƨ(сN!8q"w*qȐ!9!OG$Y`Kuuug̘1rȀr`۫aq} 'Yr ) >65 677j]6a71jEba޺)((G9JwLmO8H_4aJH@jK$$6Q%M@McUٍB@#rLG@(.c dgBNP8/BGR9G;aQ(_BH%+C8%r|-uGV!K 7Ġ@uf_=Q(༸(QN~^aoȁSZZ:AR0`KAQ'x'%6#3J|S;.$PV?<-p#JY:{^bAI%g{]<|PO>EXYYɬHJsfF<)vPx*x4`m噆K~oAIKQ͑/cgHIIacT@A#oo$oT ATXXJ#:::55 }Dy~t/Qna;άVy*++Ѥ"JJJJ#444>>Mؓ'ON#/bD#pJ%IW|%e%#+ ݻwҸsNTTTZZRΤDy)OnnnbbbxxP 333gg簰0/QbAAÇH( ooo$_H(ϠBUUUbAAAȝN8+޽{ǎzzz[i޾}={UUU!AcqqlsJLJJ %%Ai^GII {ӧYYY (N477755OHh%ӷo_1H2T"6@,Wb!DDD>(+WpOף!\կ_i*))A#\۰"Z7dЎ666H)ri<ҥKhTTTA3%if̙hDH 6W˗ܹ %VVVU-4Xϭ[ yyyJ^# $]( /00G-[l߾m޽{/X@VqʁD$EEEuM[ DE4קŲ2\lbFFFbb"Nbdddxx8ƻweG, Bf󂦪cǎh0CUUѣGe5*4h_ wpp8qb-(hhhܸqͷ@-JLfE…Dxo1H},Xg ++ 055W*c\\\,!]PLRRRJJ HN%U'k|||4k%FDDٳgϞXd[L%^znTVVС6Zjd ./$\p|o1HNϤW^aa! ,B3(y8 OLzƌ8rf0Lb͛?~?bEo/\_{dG:/%!S+벞ʏTLͦfީDu"eFs5ċ/֙Nc?#_|.q~QVݺu5kuÔA^z 6L$Vb׮]Y>鯾JD3W>a۷O$`3|mڴoSRR 1SMMvРAܽD 鰵ƍmq+VP";(CC-R"A(,oU"҅ "}?~~^HMjDX{16y4bBčxƍN:_&V1b*j@yyyGj޷LH4&pXGvufVUUR.x%vX,, %OHP!%BJ) Rb}HCJ$XR"A4 XMNRb}H!!N:{lXYYUUU5zڴ%%ևHzrh|)S_In*׭[%%ևHrҥk׮]pAWWwܹV*..Fϝ;߽{۷WWW/^x+Vҍ7?u5aooon[eeeӧOǒ^C m#"%ևHgݰaHv$ya;;;kmm-X*W888XXXgϞ]QQxܰGX98&<<vЁ >Ygo={0OCCLFFFX|ؘus!(qԩm8ŋO^^^D>43AH[ m~͚5 ,խP8o<:::"X +a21gʕ?x=D>( wwX(q;) dUܿҗ/_[^bev6?VwHHHBBBVVNWH<|0 yŞ={ _!j`ڵ8pɓh&?'''斔@5U '?=o߾;w"Sرm|xs]vΝ;QQQiiiDP߿+Z[[;v b433311ٯ0---ٍ˗/#D Cc㢢"-) P +zyy:99 OV pvvv...hhyyyϞ={EUU) XĊPxuOOOdd0&&&999;;ӧeeeȚ_~!\@+&&&BpBHHH@ QQ@p˗5'ϛZ!7,((ʂSSSFht€Q#2D)3 Ii:^]]QPEEϋ al1,B;( CP(Pˑ*>L!aBCee%%A)]DPPٙ  㕘AiT!GO AAAAAAAAAAAAAAADɕl' endstream endobj 302 0 obj 30440 endobj 303 0 obj <> stream x{[UϽdL :ʣڴaԊ2 R$KT Z -by",AfqY_FYD\_ު*=d{2I{ϹG:9|;AAAAA-rdq@U~o56itN/Q)m(PCN!Q=_[ }D}V !Ι ؎4:evT>/P]U9seikj#z-R9jԧPwݠ>q7A} nPwݠ>q7A} nPwX =zcOTzP]f=ڊU Bں3sU@P]pw?bOlZ{yvWCu{'[6c}oc֟s+꡺<.|שX(Sf_UCu{ikV-FQ.TCuyܒ FQZ|]`oP=T{]8imkVqz.3`|ܛf1-8pOp"߾z>$oW$N\qxpE]W$FcN'̫Io+N9Akq:rū<\ʖW?t 2 t|Sy3@6SVɯ._e/# R6 %9uZ}NlH3g˩5Srفvi_ GĆe[mI;(9uƒY~i je_v;Ro隽RrU[>`v9F[dFoԁINfa׆뢥[y+fЧuSg̰eP-S?A;;E N:c>ixecWsAkS$ظ|&31P@} G O>#ԧPA}O>uiԧqP@}Ā48O]>b@}H_~gɎ/l\.~egzI.UD<=?tY35]Oԝߡ#F_*+|RfP[m;R?X}57u:uE,V?N9ly-\jt˛w}h䓞9GyuwmݫOo!P;zX}]P[nӣ-/O[|;.Rwzvͧ%>^i뚵56ܰ#L>fGV~SSW#qr3-\Ԉ5%s~&EN0ǮzPC3_~gͨg ~f~v~ HM[mA>ed޺sc Bx%t:G"}ɎVgծML =NHԕ]\Or.y\$=Yi(=KŮ1EM+{ãt[WN?7|{>iYUXɹzfwiߓ=^e\>˖SQ(3]3UzlTj{Ҹd^}' }_kWo(Pԧԧ~Pԧԧ~Pԧԧ~Pԧԧ~Pԧԧ~Pԧԧ~Pԧԧ~Pԧԧ~Pԧԧ~P^{Y/g`^N}U`s9H{ϒӒ7cby O^c]=s?zЋ %][ϰimhQ( Nv{:?|6+ssc^=s!w-/>ͦ1Exǝy鵟ص[ʧGn;SZm~[L27l>N-KPe2<=Brٰ+}Q[}C.Y\;eYdiy X.cEL2KNkEA(?-8sw`zUwJgFcvˌޞ._[?oL?c[O!;ri󸿁ۘp@5zU8\Q5;tV>%xG*GTjEy+G\$OXE2 2o>iQs , /*RgDI"Ak0/|S'^HI!O<*u}wH*MPC,!A8JfN4V&$[]-ÐR}Iezկ6f 1YeR&5#}9=?!]<),$"L`I 1T iMH1,;nu}#6uHtIH'ጆZ8NxB}TZd" Tf 3vLf` 'a 2VlBCT©az ,RܖG%}0k&Z3B  "X4Z 9M[7Hƒ@$aGт0d_+6!ǸmPWR!JR%"E*;.%cE3x9n-?r{@׌[/{4+O_J.w,wtn;v:;Sb*c"Ow5MLZQVE k:7l';DgJF(" dH@$ d1įA߳||qV3ʪHHEu<Uv8G$BZ=߿}҉4/Y(" Hh mPF!ӕY=o 4٨7HŁ~  εg54"d;Ǚ?JI z>ׇw$f54"%qfR-ԯ-4>c=jFYHmNYųǙ?ګf~&ׇw$.ՌRCZ+lNE~LNG}4IPfq&u$O4 RƚY3ᰡO 5>Nd fř#١딕c%5fdpYD&ԇw$V Nt+ ~@4ʷNuFM}Ul ꩼYig')z{ͬ ͿW |d3Ng.d!mNgyXQt2;Srtn!|}ۍ/ݶMD.c|~,߱!-ϔ3htdztoǬǃ<$GKQ? ^WB>a2N~Z$PH57m*ΔB WK 4ATm,SɿC tƚ$G)^t"d!M:;C^iH%4ѧ{2e2Gx6IH&O?&MC@JCxT#l*QnfYp8y#bTfm6$("7vkX{j㩢LR?էg"J;sF|<#PZ?/ϯUvϰL{j'zVBmO:9rMQVeL}6[M؏67ocɿp:+jF6;JaXm!QxGbg{/w<+ xqޑz}2/5~?71mƏ9ݵ3!\ǒq4>#>SY?{Y+ hPэgaNGYRTH|XTm:^8zY?^bOj2J$M|8GY?7HMׇf~WDYg}Y?{y=uH>( Ӹ~R]+ ^z=];?6}ޑY k_rUח;[pJHr mߡtI]щ }QU!H]z<,%]tI]щ _BTE+J#ɂk)3JWj?JW]T[ZДZu7+:14)GI"HU ְ:GSbMN`g?0lQeMEa _jը mj 6>r$@\VOJ1_bCj̯M/ļ>&Wi•,@lj̯M zRz$`)prt$=צ%D؎3',ڤFtH~VڤFLSM+˘DGk 64i !ie.zڜ`˼7:RN  -';q@d27@?0Bt}s$yH>Ț3f]+N@X$A \_UX2=\ BH4ϚVlGʘsN̕R9-b4PG@'šQ)'_ tM\FpJLf?"/:R#^p: ~tH- Z,~nMv6<;&hg8OG7mR Y?mB'i(]$3KM YV叚"ZƖfBo|`]%}TJ#8?^,̮K3r4?Jrf8M: 'l?biNٮ$m3@j)3@jq|j{q=4ºRMNGsdC%lZ'PQD=EL^cfhB#^rW9՘>Ky8ËT~`h HTN`(]64@N 5Iκ/s%^w$I7`c`ӣNgGY;RtH-qtAI]tZ-L}$BE8y烜p.JT,( 8m!`DIMqR5A6%Z׾dڃl(gsLl"5@%4C[$Jfs2)&H1EpA64!:iX$JjsqC>}VT=dͫᕊX$ 1a9a a p ^d2.E>.,/n9"is}"ABKCbRB  HSicD?:Pdt}l<Cf:9͜6[LH<w^O:GG A![ws A"^}brŧ!v~mߴ3@j F3@jm l0`v"T \?m6X*o1Hs pgW_$l}=BNFJIh:Mp&1\1N &$?D}Z`QN8+%Fp&1 Wڣ@D 1i30\4¬4Q}޸z P!T..cIQ}X)i*G5\IɃ/ic-R7 bǵ:M#@L>l .o՛qÇcx3)?lp&1|CT(oaxաJdɿu:#W:R]jhsMAG6>RA,rN뛔N.{̾{4Er9?ʗ8.{j>CX=V 0! c Zs.{:! M|o8? u}Tz }HnK"?,gqcߔIg"?tQB!dtُ.DQd>0&цz6bc#s { Ngžs'B?W+@KpPGFHQr9@f B&>u2PFv3'!-M [ aHВηJR$ E]$BgQ?@],'v.W]LPt$-B>"]!!.O?@P-\9h$ZB?ԍ!i({Fq>AAAAAAAAA͡ endstream endobj 304 0 obj 7348 endobj 305 0 obj <> stream xPA{f#,9%ArNHZr,EI(AD  Aܪw_WWWuzWzο{#44 8$2PLL< ? Ej[ZkO:!3ֿw Ȓ̞^`2"2)4<̏GAn!<@2ɾ'{_}lu ##M%/ If ,z>~r(=)7__~V?"4utF6Xr[3áA!v68s 7?R'Bo?em#mq߱yaH *ūB|~RR҅24ee3U H"8" 5{WM*z*I*c*/T%TTT)]c oRR/Px)M3IFKO+CkALE[K;@@ӧKG7Gץ''Wѿc@3130d2\caXfcgga,a8Ä`d2f bfjdzʴɬ͜\<μ΢͒r +U5,k K6$(a l}lK j$ FiCÚ#ccӐ3WWW"7=?ww'"#QD,$y8xxx.l &^}ɇS[7P8'/!($ &" "d,+T'B )&\.X-,(r^(, 'Z":*)GOJPJhKDKIJ2II&JH~r:+/CZA:HR LL̊,IDA@\Wy1yo S i = JJJJJ ʖYTP*:*UU*F6~QP TU['{_9u^uK3D w3<ohkhh_#Ӥ{TKg7Oo_ʀנ`P0ΰedjthҘӘd\cldrԤהƴ􍙨YY9lnbkb-"⥥e+U{kx~z7Zu[lvvQv=.5z93RG؜Z1W?E%A1\\\QytG;׺xXx{y{z.tIHսs}}r||}s}4 ulZV9] =u(XXhjLjX~ri(`Dk$9Jֈ.P>:p{PyeHqyXaæőQG*ukwOMlx'cONMLLyM-< zu:zz/i^xUZřzol<#}|v]{yمEG|x1R'O?exq{+YUYZ^dݬak~fpWd{{{R>>T@p~ir䬠 2gJm^ūSQA4o?2fYX_s4sqrxV tUEDŸi% R2r9 JTTjMwijkekgfe䙞5;mEeUuMm]}Cq8.!]HQ%>U7:N/""T"-|>Su-v$n6~8 b"_o21#%$u:.g>ə+=pAqoIWi Me.\(P/Wvq5L|uWU~÷1fMqZZol?utGvgNW~wqOٽھ7;1{{ѝ=z0=sJ/E_q&1ivM܍%RwZYa>qEgUjmyKRCwwuH1_HZc )= Ԃ4t8tF$S3 BDy?l&V"eb$$= ed%i YG*j'ihjjiS uvu/N^5h?e }J2nbB$Q/qo)i_?@ `V{H2T!L;*+26*;1#Gfc1GYW:`hdlb?qANf)2gD  (/-&pg@_F{C9Kwe+Uz5uW^}xc[5nm=6wSFvQw3p//@n@aPiHeXQGZc:FMXjյ4isprq D#.cNVS&3s brjzfvn~ӊ.ov}6c׬;yŀCBH(hbfŕm!'{$7T9y0il3gry|D(=phcɻҙ&F/_,~_ʼB[í6p[mz9OC+p\5`FA/L?$``I %`$WJSF(+MpL` BKAiE z,lW$;B̑6wd9=JBSa # (!ppFJNtu7aʔZF":!z;gڙWYrXY`a$yɛgƏH g҈N{HKlJ>*ѓݒ{!OA\H9O%G5WܾU4{&t乭d`mbi\k2l՜uEeդ ]]u'qg.{G纗wϐo@[mpP`x^QucZb%㪎ga8G"Dd F $FyUb((qx>Ҟ>APO%@UFA]BISN+B{Nnޕ31F &1 K-9*[ *%NK=nO"q'Wu 2>,-+}Tt,71Fs')T\T9kiFj%jTvMDLM3n?@ZZٌalupW8ES&.r'),"QT#dˏ1OO&mMCpLMh>l+7}oW手S?u~ZQ~;ayLDxpp*h%#$i@6PCQh b9}*aBC"f&J @ӣлKe{"b '3AB!*j:z&f6ˠg/cghc4e|L\bIJzM9{2s4.DS7O;y 1 Q)uN I!-Q+2'd]4hJ[;~vNn޼P8i~J 5`ri[F;}3/3_7N}{OX9aov{#'k(uȓު ~~v+ ~kh(mIcNE% endstream endobj 306 0 obj 5688 endobj 252 0 obj <> stream x۽JqPs pĤMl;dDDDDH# GZtҌu>8vKޒwSeX^(h=.W(ӠHەtS Vq@1+ ߀aVƒ8ko@0%U!߀aJB]ÔT|CS2 ΂m^7kJd`4m?G-Q[^tJhM5Wϧ/.SW1^O7\dAWM[dm> 蚲)tm1rϲdoD|}# toVe;Nڜo@ùG]S>%Kv  n!Gb"[ӶO2"-0 MoG.4cw2q [9"!esq)"ϊloOX.'Mqvyۓe߂xA̓.dtM)spHw8}'ikqx&nv[Wݑ1a_w{#I,+䣹`KNnJ~.K]0dmtmg][ӵCvmqh`ڮ*$K #a8ڮ$e:aS/ S(S(S(}:r 1r 1:r 1:|b6u R񴶫ڠS]ޣ3vu =ܰ?ֺcCF<8:~Vnl€{uoSg%& W:~Vnl)35tc7~VnlJЍM "Y.wc{/aQCqi5Y)/lB* uYI7\ԎEۿ_BkiZ^"<:4i~eEz>>T,c<'f`x[Po{\J8^4uM GZ'˭S`50`~~`DRC?oVҍҴd;m[f9ъ ߙg1@ 5c?lJNAps!ƫ)ͰxrkuWdO?A9U4nnwQst fofmr.4[UĺNXMfuws|rVzDu># toVx1S 9m|`lqS1&L>d\z1?{\%0|l:i-<^?M7p2%Y͓1Ŝ/0c㕠|W0r_ uYUzŮ(}w'l%oAzeKX]_M3)oг()7O]򷩏FN>e<Kx4r,s9vEe ݝxaFU||֎^":Y="'.WOF|U+O1@/|G|kY5lk1f:-Fgţt u񁑝 Ŝ:ӥ)^X1C%w(wguMY |H5*ƷQL>&=Oo`rta! ݍ?仆0^M[]'{I̬kM4L}nGzuH Z.f]PHqn179nc&B F1G7Zhv3q E륹azeC?oVҍw&#a,s->6 | gI s0=EKOw|<:Cq0 t=y{8$^a}W:[9|}{Q|G1RQv27ΎzuH ]Ń&?ndro|DQ(J٧C} [c%8~Q_Ϣ#g~֦{=m*>4bq A~QK7ʷ$n/-2w򩭶jc{PkߞhA 7W_h' CmMnWVC?ol7FA3( _zp 5K Ċ)<}D{GNZƣ-tc+ϲV&HEQp!,eE\OEuVPmڮۧhʴݑUumYC]jn"v_~cmnڮbmw'j=vv~ {mp.lSvQKbl؟Dx̭^[3z .A/:%uK@1mk>bA/}Ĵ|~L#qDzAy)Z&Ű|5AyR#*7|>F'MP۫Ԩ im_@Xjzuȷo\g?Ooɧp|m41%rɲk4:4c}&Mx(xHf7)u7Fv, ħX8.MXe< = ~*"w5O0b61|ZN㷦MD>+M%D>2)x5vdtYt6&cp;s6I.0_>J>Kb} SH9t0}JcQʗ?ȷ{eTBk1]Z[Hz|wSdˎ5_vbϔ EÏ->-gkӋ}"?dGs6k|zt7{.p?{s3MMrg\8 %#Vp^0 Z+:@c%"&~v w aTKԏt%4s Ci h}åcj핦|ٵ8_ˮQGJ6ƇɮqǎEnx-+{IuhI^Owust_5B=Z}x,=&o)#S};P/ }?zOdIY"Y';YaV`;!GFْόr{ v(]{^h3]M>+M%MvJ<ʧ}Pl1]Yq-O8ۆ|n"gמ;.Oy7Q`lZ4}⧈b^C}GL.w4|3nF$xgNl:xA#D)v3LO[d&>D@q3ga}eʷPKɗ/#|t|˷{+Bx_69q6:yTyItH׿63N>,/i~Hl˹Gln5۷۫ٺ7NJ[MVk-k+͏7߿? ŭbeD䝾-r'o2ֳ/v8/yq Q←ol}:A(SV舶LݧjZ#P2uih{@} }J&aQ)M蚶GLzAmLL蠶G֐Q^PX&tVۣl8(S5Z# C PwT(jv<k) |; (6rKmEi vٗ\Ur?/{`#FТ:ΠMoV^gz4uBJF`vT>~(?ʋK)JF`vLKR|˅*KPRʄP2s҅*kQOʄP8ΖfW,م^`J0AzE;*av5Zu/5Eߑo}GECrۘ'(ܞdTs :U2JUf(ф)E5/}/*Xg֯{>PBP,u&Z>L U0 t 'mhwT(;*invd[~\LۚZ쨢 |(w߄f|)kW@%U2* +xkԪK屓ޞf2QUM|X*U#3wn3q^੭]97Z&?PNy+SR\PSΎIQmyچ )ׯPK̶ޒ;s?Ka >Qype=z(|{É>  av0; E̻hkVo}GE֠'={  fԤ"T #;jfZɖ/4]Ku)==Ύ*{,{[/UbZf=x'/'iV·N|Z }G"̎@fGQA PQrMO+ѢRtwAgZKf@SrPzg7mj)[^MVc;Azh-t;AcPoS֩wN] S)~C-4I\Uy(mʓ'=gy;E[0F7D$XsHZnX5[wJ.Ҕ["42|0T }# UV^\]2aiE($(s*7bo0O7Piw%;Ny].jzcnʓwܓh`7CE* P-JNDh`-c\$7 @Qz{v?@!BeݽJx&-eW/|#<ߒ?8V5M]@*B PoKG ^>joѐ[K.^-|'b(|,D2aBͮ\}.ȷ:ҧ.J9%Wc)ϷK?i27k" 7CE(* Po|0TMxBCMlP/* :<ԡ6C. @sfȭl@msk[X+{PIBLhQPP%" |#*t|#tDKF@[\I씫l*Do}>„)ϷF-߲o|+x[,(RU0<,{ `7CE[巜| @7Zr:PJaT8-ouW(ϷBp TAC7]SZuaޘ݁p_ `?2 endstream endobj 307 0 obj 9616 endobj 308 0 obj <> stream x1 g O>cH endstream endobj 309 0 obj 145 endobj 206 0 obj <> stream xw\W5DE ĆKHbvذ"bł)bDz*#w& β{N9s=gf              ʊ|!r]/ՂSbdDȗˑIЕP~XeCC DHOOOMMMIIINNN"O&e .6@Cݫ@(*L68rR&r{BEH%>>a8dB,`)h%222..h2NQ^Aʀ_FZZZk֬A+ hEQ^!H@ݻ4a۶m:t(:$ (h22 D AR???ww4Q+! ժU5j… F 駟vvZVSSS Ɯ9s ;p y;B%pqqq-*P@:hWhc^^^NNNk›7oܳgOΝ;רQc̙͛7P@Rk:uTf~Ɋ+nܸqڴi(Ǝ SNEU5 B.Kٽ~Ǐ!#/ tHP Zjݺ58w쌅5k x&N2RJ?^0p@gh VHHH`pu\˯^7~vssYYY D4=Ntt4Z1ֺ%Vc7xK>}Uq3f0M011abMuuuA޽{nM/^q\ (`+ϟ?}DD=q DM@ M@Ν;L=Ч|4lȐO0>>>X8q"XiiB'7oބ" #M  BxZ'Qbcck׮ٳիWשSRB իgkk P:`#G ^6 M(.k-4֭[2j{.O srr$4ɯNJ*Vؽ{wv˗-[d[iC#iB!'׮]&c Dooo4C++Lj8bH700088˕+W>4(uq4ɩ!$4qBff&iQ@&{drU~@@:\@P\p ?r84RHhc,.ÇÁXMx54!...##aryѣe˖Ge0`?8m4ꂩ޽{'Lкu={m۶K.lssb>\*Ƈ^Z]B{{{##˗7klРAhD騘Sn۶ [mذACCI&=]pk׮ZZZl߿?chhϒ%KZj?,Zh.]b.\po߾Yj,H 9 D'p(Mرc*UB ;vhccMظq#V[tiݺu/_ Xƈ#+ IyӾ}/~O>_͛ǽ/`֭[!h0+]^zhh={D {Ξ=_~% ڵk8A;4Cv̘1ibDEE8p)5jԑ#Gvܩޯ_?KK˜BYODY ,8`kk˖ѫ,`e80666lH sa5nܘzgggMMM, 2d߾}Ǐ`FNl%''T2HOOG3DA[:t(3gΰe+&899BG:u zJ5WZ{ /իWǯFp) !ԀTR 1rℂEB+[F: -km{&@j͛7G+ތy`O>%0jӦ " 边5jC[^n+SJݻwu&k"Vt`˖-k֬AKWJʕ?|~N D?KXDOOZjV, *%,O`qB!{4:ZY`` JΝ;4%_|AoBBB F@-:t7'Bhk'#2Ç2 9H HXN8~ H8 M@1[ n:Dϟ\@[Ha0M!N2Bb TA',xFF ф˗=}h %1c2srSHBYx~"}-O> fs@a;v`?q?.]Ғϵkנl5dWnذ!DƆ_Pm&EׄD, hGk.plX&kF{C a7Xk+y&,駟`a-]~[Fa#G"5MSN,nܰaʱ2vg4k,o޽0lYWWJ@"25=w@V#U sY 67o>C!A }|||\ ~\\J̱(D 6%[5jzmᴤ4~=$JoEiBqbP#B|LMM555!%C&r@5)V222JvD8pǎNBY@@%42jBAytA Y!WLUmH9 & NKK8;;kNb5n ~ԩS!ݻweJ wȑ2 i!J *<<\b54IK9ei!d-ZDGה)SD&t+]ڵkFxb 'OnҤɐ!C?~ 2-ɓ;sG8N{Ç0;Ǐ(1111331b{̚>gΜf͚ 8Mb?8ɽ֪syKKK6 Ki!dׄ/2rbŊOOOHt̙m޽{ԩS5kdn:,Ioߞ ]lUV 4{J0W^ժU ޻w/,, qqqP!viӦթSٳg8:<˗q ]%U7ϝ;ׯ_?[ni!dܷoÇ5!A^C8q_Dcg#"OӦJ]ȁB]HahUTASBɎ;8")))h+D?~bbbʕ :;qqD̜9(YPa&r#)kB@/>"+4&z#` *xtݻaɡCH-IሶܦMV2w\n'@܂˗xAШQ) 2իWcWlTE!@@5+ф~8)$ݻ8 %xI&;;BT6ĥ$vvvP++ׯ_W^t ԩgΜTR% # Ё7nܾ}H o޼ C>I@:t7`f񐅠߿}=]ك?<ѣG+ܺuvrDx왃 RBll,:$P@hݠeff ZF݃2W8{ңPV@%5U@ FA@PC@Z` -%%%}1***""ALhc``мy;wuuu !"!p@QFjh z" 蒠 ̙3߲e M0AnN\\ h5kD@2 ЇO_ɔ;p`m۶tRY"8q!E"'LXMM/Yd%P [[[^zqԮ][]]}Ϟ=< oӧO;v,匝]͚5ST^ U(1ɓB&:w, 2iAiѢE6{ժU BժUl"ETDGG#+wvvڐbЦM!,]aÆϞ="P~ )Є}߀|RhBػw^y/NDh+܃AaaaBR p/Sʒiii)!VDc֬Ygڊ'((HMMM ʔWjii1r͛7oZhA/-zJhCʐ˗ mArss mHMRޟDblllРІYjV("͛7ІxQӦM6DAIHHrVР~PF.M eȑk׮ڊr/\ QV=zTGG^ё֭[ZJ^&T///55@ )g$$$  Cƍ?~(!AORRR{ mk. ㍌eddkBhC]t(o߾USS BEC |Іww .^B|Y[[ĉBBBb  B!mڴiBBІILL/Dr#66VCCNhC\׫Wu넶(kB[A(?G; TBTSS B&Dّ١CKԩS ֭[Z!ްaC !MFF^vvІ×/_ }v !JH߾}|8ML8qbB[AK5j#!DirI& mQHJJj֬6(eRRRh;QƍtR B!8uT׮]-A___555 !Bxͅ6 `V}B!8tP޽-ݻ3fR2z*4rȽ{Ş򅇇G 6E˗/iӦ{;uT%ڵtІG@@ڵkN믿6 7o5k;t_޲eˈ#F* v~OOOXpa>}LLL;|q8qBMM:(,X`B[A;o׮]ϟ>m4zh'cǎڵk7o$$$d̘1֭[Xyٲe?=z7oرΤI 8FFF( ++VZ} 3gĿ'Ljkk/_iBnnY`j*M͏?I1Ƶ!0`Q߳gOiʃxR]]MhC f}mo߾}D5[[똚^Zb{{+W_(ǏJ#.M&$MPe18pǎBB 3`ŋ:4>>BOO/44;d˗/"% 2$==ĉǏma:(A0rׯ_HT;w[QQQ2{6H! ҧIMME@āA===A* ɂrM` !!^hEa dՆ3(%P{h>4?uԣGՁPk,oٲGc <*;wF1s͛WV ZhC4mB5-Ztvayҥ0R!$G%AUEV-%4+++555::˗uKe˖i87; ;H[[[,8qB$4 k֬A("&ԫW$XnݺrQ*LJJ *i4add$bBWW׻w ߽{gjj+<\T&zi>UJ&XXXH|BĜLد+W zXpv Ui=>Æ ڊoi.nXX47oJ4C;vܹVڻwo$111(l߾& :::.]jL֮]<{lu>EhԩSӧOF"kH iG$47w.\0`@*U"9sԨQcȑlbŊ4K,a +dۗj•+W4iՊKׯ_&xyy&5nݺq&BCk[fe$V@!YeN.jDYA0[a]&* o߾EAWCdpFp(9BA@%AH<=LHH 8( vvv> 6 w? B$T{{{aaaЄLz$Xb{=Lp?,~~~֥b!QhG[ߜ&°܁4A$~U^z/OqOZXX >T,$ "77Wi!>>rz mE4k*ɓwܩ9n8č8͛߿yvuڕ}ǧUV?âEo{ntbbNm6r(O:}R>Ý#.\+Q}DGFK-, , ut+D0`%_>:5N e)1_MF0|'ܾ}M6~7D 5{ htLCC,Gw (Pw\-߽{[n"i(׬Y Dd6~̶B?KXDOOZjLGj,&hq|2M@%]6!辑,`sب N =6ŚH46m'?hD׬G4iҔ)S ܨ-Z$/0?Htڵ;twBjTm͖}@ ܉D?Fdd$|^& Ř- b *@BݻB!MPdkH㣥įN8ɓ'e4"Qٳgذa5vh7oޔj'7* B20MX|ѣ?⚀Rn]C!(& f$SJf Qr Rڱc|*kNYb~D4PdT\TBvHTBvHTBvTV:uTC.%4Մm M dGe5aҤI2n4ԄT===9A@ȎjjA@i*ׄwr>>...wܩ@Jjܚ0{l4;;iÇ/_lffcǎu-Ydp22s̱c m2k,\z##kܹUj'(!iBZZZLLLpp۷o={ٳ,lذaʕK.8,V.kjj mj*TTT3gXYYzƦ(Dd*.(+>>>,,nnnz(ի!]]]cšڠ&(L233 899Anܸq%T'N n>U:ԡCU"A߿((/^De@@@%aCFFFNNi ˊB6o߾T򪲀ޱcPR)SmKomm 5@e@@\ԄׯϜ9Sh+˗/,THIIA@Y@Gϟ?wppx&ƮSNL@jV\)Q 8.3ׯQ%P1P=PIPUPaPmѣxYggg*# D0444((5+埑#GrjժuaRPpŽPP >|@`AN~c ,| IDRR.ǏQBń|M]6cRP>A`d*r(&JpCTYXp! b Yx1dᅦ&ԬY˗B'A* ++K)@؀ }P.,--5557oތ #E *A1_]a 9]\e5u2*Di{n}}}  uBE`y B& uu`QhbI o^C3R B5j~ok)_6nܸdyӿc e|†KJ<֌ D_6<!Kg d!>A(/y);2|1((ӓ4DGG'''W4w 䉧@'Fpuu9J[+V _pCtpp Mo۳pJc ߎȑ#i9˗="Mo<|_̗aӦMQ߄6!???#MSu޿ے'N0aVR>G|m>T|#RGGG+++>ƍ7طz”[ M@=g2GG'MoXZZ>{Ç zEPV&3M'M4tA}y&=QXQݻe\Ĉ"--5k m)r4t9}I(kڲi޽Ud<ӄo۶mСX>tзACP\pAh+E:::=zx {չs46mJLL2McjժaXF[oԨ'OP[Uh~k׮k׮egjj!И3gNzzH& vbaa=cfHJڵkÇBB,0|߿~XM ҄ӧ㧠 ~!_޼y={~RF3g6osttįuԩR ɓ'+VqiӦ {;v, зo_,L:0ۨQ-&"gϞ 0dׄǏcyΝXF~*DΟ?/dЪU֭[c;tvvš5k`ؘil8eʔJ*![~uTTV8p 3+D& JAʕ+իoqiRȮ ,2wuuիOhT& E'8_b^3f0M011abMuuuAcSvkxb4諂aW"B]X˺x"~*&܁4lȐ&L@&N3a&"M "& 2ҥK۷27tM@?""_(Ubcck׮vN:h```P^=[[cʀCȑ#)WG  0dׄW-ܽ{'999榣WX{e˖l6mxxxc$MPLZj%Q%ECvMHMMes1hq.%/A`ȾUFV&" O4A(#4!MP|dkkk B), ŋ4$U$ JAP$ JAP$ JAP$ rJ 4HHJ&M mQ EBP,_|ӦMB[AiB&.mڴ @H4%=D!iB`1@-q.cǎ߅cffR?t\\\ǎ>}Z{&CT}hB"{~pj~hWW׹sn2iBrr2;PT(h&j… a Nlٲ%% 47 իW/^z]vmذ*o֬Y);89s[D'~;wn!ںC3r  D,pknn. =8a„ wޕdʔ)FOlޤI)bzƌ#00P$sɒ%R5 nܹ3ݭU4fĄxxx qF|ܹGB6o޼f͚+V˗/qF۷AAAch\YSC*^WW L W\:H4Jlbbb ݻпnܱm" ,.]*HAXB(LP+,#nDP)bE [#3%dLXXd +w6 >DMocc3x`L$6A1rH ,U`51w,'JOV!  휜?~tvvFmApeԇSN8q/ 5@ʀnat#}‚Trv?!:OE(,Pi$ȸKC-ۣE yug 1Dx U|"&8cJ A! |||A|:JGGG{YH ^NP*<=zCȝ ޽Rp8k A A ,طo?DFhC#O d f9 l@/ LqQQQo'L5 H M(u#F[NhC:++ bzz:bdD#I `j M +*'18q6F:@&y<<B_ %%%A{v &MXYY mA›7o444ط   = رc'MD/߿xVX E}IؠAWWW !BQ~Æ ===6 EѣGC    Ś?`Q $Κf$e˖'==5pgag9əطKk0gΜ'lZr4 bvܗ `, Y a33Ǐ2?|Ijjj'L%N(=Q7 6J7~^o J 2E MoL42[XX888H 3RiT~>|? 6 JN:ܹ_ӧ >|?|E@(ѭZ:qϟӑ2y{{&7x+xn)DrrѣG߿/ cbb!ۓ&7x+BANIIc@@˗/mmmI <Kg+B9}t˖-ٳw9::ZYY&7xH%˗/v:p >|?aaazmPVP?}dmm OOOhȤLQp4& svj޽{{xx3F8DVY9]vɸÇWTӧ2πH 4P)J HMMM{WZ%uA8qDO>ҥK(}ZCC>|xvv61w\θqNܸqc֭|rNlllCl>~xZXX`YkhhXbƍo޼."M T 8=xڵk)#]֯_?55{ M>}:~ K.X۷۵kK~nݺ}e?ijjv XCfD`3fTV 5a ~E42jԨ*U@.p[nVZZZN*H"xb Mɩ^z6m{zzZ[[T&ɟ?>--_5j&L4TM@?&&=z`l2,effΟ?˰iLŚ+WWD;lx?asQC4 +/D MYl Atԉn۶iĄH9& ;wIJ4 dCM¯ك^xT,M@[UV۶mEDݺucHd&ZZhӄ9s`_AX4!44TD@GMHJJYСC! 'OįOhƍGDD #@ov̙(:u*>}Vu80f2M055_կ_i… 0}t{{A5m499 MZj޽K^iRȘ;"vnRc!ԫW?5ida+W/ 333oݺ^`8oߞi mmmVVmڴis͛77k "`5 ȑ#"B( /# p.srrۘX  ~~~EQ\kIcTH4HH4HH4HH4HH4HH4HH4HH4HH4HH"//}@6<<4A*|Mgdi.wBYa߁bMw}i}߁Pb8M| ix>gx4PnoFEEݻwoxrþ5իG]rwްaòe.\8w٪狳ƹ3_ѷ %iBZZZ\\\HHs=Fallv+V,S p8_5 %4Pnrrr222"""|||^xakk{ٳsm狳ƹ3_cB_4(CP?};Ǐ߾}aϜ9sIsgYހO^H˗/3:::Eܻwj3qo' /WܠP!55qdd$D___dЯ^B@GLq8k;<? < 4Pnrss1Y@o 9<<<$$$00*YހO K`$, > stream xK"aqq^qqPwlbfʌ4#/ :]:yjOun`î .j57gg__^xyo@!B_ 38`00lO 2,=XƧx"b9(ESEDsl3_U"`J۸P^N4LWZ~Atv+VE Y7hgL]&ὡ}VhgVo }n /LL;U͔33K[3][K3i9Z骯ZYE53]yó9ҤjVJz)K;ӵ[u4LW˻7%=ڙE3a`_^X {aa/,셅^X {aa/,셅^X {aa/,셅^X {aa/,셅^X {aa/,셅^X {aa/,셅F/K(>L{Suv%Q'-/OwW5}#Lhvnniy霶eLŇG Xk/:?h\exsBI覽Vk}pQ[M=Aὃ}̴];}ZZ;ZhOg|},MZҲc3>}}D"+"-]*}DROgIOȦdbg}3JĸLss0)EO DZb1"Si?jGاh> stream xSGwESʇZyK| VrUz)WCɑEBE3$O"&%?Gd"˹NTܷeAz@ =۟ٞ      L7 O3@pPd/4a"#߰ Qz=^Oqo\_^2߼ORRĻŶu Ox,l^b*m^SMS8ݧ;J~dn4oYa-, $8qi,sfmM/8NHYUn2nn/xfT|YTD{WfBG[ZԼ_iEN(>B*vǙPȮ a3N&ۇ;ibjz+BlR?xriU`9c]QvAD x%LP}Xv_}T]]'Ȋ"$@i^q:a}M~Ce_dO WRK㹼c7y6g$7 >92wx';eYܛ[چZp13Yon| HQ`Ny&dXYl_SfG U./B>\-gRӚ.n!埗z#-6Ni.xLT[pRe.*fWsԣj ὂl6`"h&č{KV܃ZcΊ  u'? ?ķ2NsZ޲ҿ 7 KpЫkk”o|Xvu>4=6v-o@hD3P~ -AE}^D@R>_.USjЇ? 1>LTK            0K Ї^h0>R>/, &4vSc kH[<Ŷ䰽sK(C|__;tg5D1|{5m~|h<g:/KlF:Υ,2P8Sb,LWq=J_{Xx=1 ڕ1H~E[]>]Mz`om([i;+G Rf[֜s >ؿ|[~y\|պ4~֓unpM 0*oA}i}*ZxXd__$)FGey+UmE/#<v 9M={7@zI#-k =@B8BX$Qk:sl(۪CprͲ=oBlCknYpyFoe) 2we]xبO>/^&/pCU0گw@k68I~5 ;,8HXr8I&sG}R0Ե0cۥ{$ 8tfHB1 u}$t2ނO ',|{Gq&o9*S/[8U! C iaB:6rp)'!'7hyF^M+P dY6.x;$rr\]^ENC<粠y<a\͈Ʈs N:цbyNV*zqg6ȁUߝWMjOLJe< 5?I/ mKFe2(䚂X1lC#/R_R{8v}o Z /8ؗ_@7 iR`͵ 5Q5@ovisva_/( ɞ&*.v^ćmou_N|@8}@X[iT!M7N|-<"8)K.xyfHćQwՎC{ε{Jғ z ՟۳-ihm)Cڰ6;ZJm֒4> 8ѩ?0 e‰dED/'> > ,‚> ,9I~VÇ4r,vN:Y^L#͖TwrHN|М߼]ѸƎ5zl0$_jQz;ato446x*N|Bh04G"o:/K3t r a 7'27Fm '8+nAt76WRm}" 3m:n(THYVrՙ/D/! xo"'Z{`W !'n}Ň7t.3_|G / 7>D4) [{ćH7xä'      L3B}@Xt%0=@aA}@%}e@}@%ɐF&t#*x      &r endstream endobj 313 0 obj 3371 endobj 314 0 obj <> stream x pՙ\=t$9dlKeit\$6a,`&P&,n !R #3vxYW{Z߼^"̱'Wi1 ò/ AcM f-6Ir:]q86ȳ&,MGvĉO&([B767j9\vcR6mn?j7|l(ըdItbdWI YPoC&C[CeaAR4g-'Qɐh*q ) 6-F&CSM! ZdXIHʂըd8@R6@{ =CIYȒD h IKA&H"#OFiм#KYIFNgCs`p%n'$i8 H;+I|#=e,dI$Fd,IP<'܁Ӓ0IX М&NJ%0q,FNSi(xIjW18$`Y *x%BP 4GR9HH"D @$I$H"D @Ђ7IAH3D @$I$H"D @$I$H"D @$I$H"D @$I$H"D @$I$H"DPSJmꂟ-HAn2 v4h^յ-Ǧ.E 9{Ym]&L}$}vLo)l(KE~ϧ;8gضa(XUl@R3Go_?8qʫ=[>wȹusF. r|5$nK:1917/ɱǖoX;.Hʂ嫉%W}X|p^?I?7γvt(s;`ռDak_lg۩6,s, PTuVgxWy`-q;" i:NE[:§Jy玳pH6ȳ4̿πyb[,ES[%'xXZZTt{4ӗЯ?ƕ|QM6QLG1- LdWn0s._jT?ٽMkzAB>yw-fIKд, MQ7Udx2t3/kZ`}.Bh{uh#`BW,`NnCI!N5+. 曻Q[, v:oTtFs&3!Q* Pkx0JÊg}=Ś]p+St[rJY'>=y%ԧw~Ğ Y~f xgx{iMbԧaIsבS#K+a~iֹ:,n]T3;%()7gHǪsx}S0 :\X"֍TZHrPjtܒl gmas$ꄎ$c%)ZgΆS?5tPj|!գ }%INpsIzώɟ*#I4*X26IQw4Xo\I\ZS 'U䗄LgM#I)0ރs/.,'Qy$rKRF 6y܀pWɒ8X#N N$^N8u~x+HR HI I @HIZ@H@"Ieҹy.J".|nJ",|nJ\pU@.$a-3J{B.: |FI !\ ~I Q䂫rg0#rgߓ 5 ~nH{'$$$$ $$-I $iHI I @HIZ@H@$$$ $$-I $iHI I @HIZ@H@$$$P$IǨ2Y*gJuPj?Sw^2lή;.sVx7z䮣ǐq瑃7ܺy^+ *]clŕ۶_[ν胷߳Cb[n_MTROӬ,Y劫v]sms@Ữbb@{}casK*mYM|^Y]IVE셗l);ONgrJx*J|ޱ֛o|#} K9/kmmnoU];Q(<&徂ߠ9^"KRO\cuvⲎHǚ+>keD$XYkʢ?,T6O-" Pe7s912ѿz6Oc%?i9ͬuK`%e@`JzVw}n*pLnI4g4>*%%~:>QSV??ͺ7({9>sgK'i&68#<Q=Fz&Qw%Wc0+洤7B0涤GP`6qIEa s] TtŨ{T$K&銽groscpIFi 4HI$ -WҿrI˚$89nmRђd[-gʗ FJ lvl!:4HIS&L`%).F'JP2P5Ԩ=#%ʈF'VU0纫D+n֨=f2❑nSO1T$`$^Z`Fg+ldIeeuwパ$];Nu"uHINFeR fnEZFFB /B)Sh_B`&o%E1Ic,'jzYÝ &>oERI*j ჆, Zt}ۚG|~y}kj' w#xS#ڰi*{'~TQT4-e}w"o+M姛yF|K7.g$*.zE'77"=H鍕I/G14W8@R6 NՌGznwP3يC!PX]H\',)gYHNIӘ H%fY8p4Jڝq(;Xs1N"h8pWEY3jfsL- B3H IӐÝ/ܶUu8I?ӯiډ{}7q;o׶y\l%_}55{7^}Wu`삭_ >W ,툔[A4LTu ]yKBݺu˅.n:& xGUCxe >xlxpŽ!u 1vOaAKgwoo }<9XG']m5>/nuGׅ\Y@$I$H"D @$I$H"D @$I$H"!p>9 %0(siV?6iI+(IJ1b^ endstream endobj 315 0 obj 5613 endobj 189 0 obj <> stream xw\SW?p[mTi(8ZZ{UmDžZE۪uUZ۪m[87*@~g~iX$7'rrssc 鈈{H&sZ8JB$1˗BYC$% HC$KNC$kQttccc3=y = I1԰ڲ?_YfwA޽{VXat￯!m6}t=cø#R:qܹsUV!pӞ={p|r /^Qpq.]dd_hhh6mʕ+7r%KQ_~aaa>|hx>{̂ =-ƍ'zцCD"wm۶ {,v=zxɒ%:kٲX/BBBvZgg={k׮h [cE$*$$"+H","5XA` H VD8XDj$"R$ p`IE+H","5XA` H VD8XDj$"R$ p`IE+H","5XA` H VD8XDj$"R$ p`IE+H","5XA` H*$$"Y*(111..BϐwDjRAKrһ=<Yp!WX!nEX8Jn„ aÆ  gϊ[wUjUkG#RCia*S݇~w^q7|dWwDj1Mֽ{oݺ10cݼyB 8900ŋV5vqGy+(11ܹsn2$qG+H","5XA` H,TPBB՞b]VD ӯk.J;"5,wmڴwC H +hΝիW;w>/^\!żyDˡC4iRh:DѺd)+5DѺj)+5DI]AZ/BB$4 JgEDˠNY ]DȴHYiJ3WD 5='a֩χRcY;F0,=L9.ꬆL!f5¬>614n'2D -`YFp,YgS8D 5"fqP̈Yg84D¬}"tR0"G(kNj( u)¬S-mZO *iX”ZzZ,!k諧UJ!d9`7؇Rlp9Yt& ӻ۱V~zgInɺ$ |tʕ+kԨ-[6'''??ݻw3flݺUyxx4my8y^^^+W9ruqzzꅄX̦ԩSZ{n0aB2e ?4oiΝ;g8wRAH6gg9rFEEɓ'#ʔ)tRXI@u֡YXAuoرcrY/eeSqWjU EmVvmv.<,[ѣGӼu˖-Mզ}0֯__tiq6=zٳgΝ{u̝;7>qPPP~t)q,^x%޽kW+9ۉ9sVVMxyͅRV}wwwoذeЂ]LѢE1Ν;qGLc |+ $.gթS˗fvq:s̜9s Zwϟ?Ǭ.TZϏ{x[7N}{X-y8{Ǐ^ʗ/?NSkƍ{?bƍ3;ll8şO\E{af]J,XpĈ8KkXT]x^zٲe"\"111}A;r8@M4aox8{fv֬Y8޻wÇq|r:;øSĔ:y$ޑK*5mڴ͛7WT 'DDD&U.W_DE 188xڵX]bb"qwexRkׯo֬N:t(Z,X xwء3֭[]'ݵkp_N4 sF|Ea)bbwaaVn]L?Tzu}`=n-[, xwfYJlժ_l'BXc.~|%6sL$[TTԼyR& w鍸8*jԨRNFƝ"Ƿn2j3III" %''g'hl'K\raCޫW/'?~ÇLjx:[):tJ=Z[̙3#[/^lޗfw$bSqwΝ;+ π`߳gO̘1Cgw0~%J&,ܾ};[lVW^ŭٳgNټ/~IH"֙ixE 2xl.\`tE<6kLK֙v%;;zc׮]yD~awI̙3#FػwuNv_]6H"% mVD8X$¸##,E]`qJȂK";2U% D8X$¸##,E]aܑ".0KvDwdK";2R%`)㎌pawIqGF8X$¸##,E]aܑ".0KvDwdK";2R%`)㎌pawIqGF8X$¸##,E]aܑ".0K$b)aG!`)㎌pawIqGF8XJe]Krһ<W^Y:.m$b)aO2/_޼y3_~=!!!11u\֙۬ p1N>ݥK̙3'44}nnn;vGcV._ܢE ڼ`Sq'Vi^aСƍ]Ξ=kާGw],q:TtիWLW^N®VW6MyO}jgHz;EݤID#l3~m>Z=ZLq3ki;EwIIINNN111 6bŊ%JwVĸS\qM/^ٳgV6K0qyѣG}zdHk߾ NvDŋ.\8,,̼ϐX$bSqg8AYWvDd;("0KKw{ddwdN"w)u5ǸSĔ:|!C%JGEEqƌK,'L>C4iRh:_JA͛7c…~y>7I%Ɲ"t۝&O|ڵt AAAI;h To߾Wknʔ)]ѣG-[={/^X%a)bbܹO={VXq+WWPx>T&Mwץv}N ~TSy%7oO?wBqcƈ>}Ӿ⋱cǚ;Ɲ"&X͞=B 87nU@-%K|1nݲe n1N8؜N80~"5j={vl~#""t)q7~xqڨQMP011ʖ-[bryxx˗/acヷo[ʕ߯cܙvQh"ĝˠ/_^Z5ܹs')) 8"E~TSqqärH֭[Fbhg!wSNw) }޼y_L DܹSdz;3b)bzi II&ؽ,XpɢEs._Da'OڵkWTI|M Όw]xELڲR {/t{]Çw$bqgއ&X$bSq ,c*M".0KS+oDIJJ;vl܂/;J2#`)bJw(!!!7n8|W\K(5yQqGF8XwK+V}ҺTܥ߻woJ (жmۻweҤIA=ׯlN.7,XP7ڵK|@꿣p6wWX.ӰT9x3g*Tdgww?[hoti_3ZO:UD.嗍q'O ,WZտ>[ǸSĸK(ӦM޽{||<6ߺu.5-[;~N0ț7˗w!!!V׼111R#͛7{h ʞQZΝ۷o_;qwFwF>[ǸSĸKQϝ;g(%ŝJWTk׮q…]vե۝ׯuo#`)bzܙr5EZܥ^k.] իꊸߝNSoDQZ]+۷oGFFO;pNF$w$bqDܙWvDl*L\ɇ?~ܼϐX$bSqGK";2R%`)㎌pawIqGF8X$¸##,E]aܑ".0KvDwdK";2R%`)^wD3%(d,E,SdU֙}2 "?*L > K)˔ Y1'Z @F;%#Cjq>N {ȐZdSnh=2 fYa7:Jnh=8Ef=zH1NJ&z$ + 8g(VRKYCV‰avGjΐu1 T'GeIB㠓8 ^q11pɑq;78D:nlHO.ǗHw޼yoY ㎈㎈㎈㎈2ef&UDvE&Si=S$uRVh=kuRi=qcuS0&W5xjժ,X`f|L/۷oƚrϟ|2/^wd^捻8W^!3V\ɖ-ݻӻZbbb͚5qsy©SZjs<=='L ڷm6}tE|ذarz{ɋ[Z2hѢ~5o޼O2dMܡ5jgϞݶm۾}bgt5\ b E֬Yӻw:ukn>֭[ 6R֭ 8q={|2 . 3aaa=$U޼y=zN87QiPjU\ÄN]6N^v-ѫJ+C0~^)S >/^zg̘rzcɒ%-[NJ>WeƝ;wD!ݻWn],WX9rd֬YYp"آvxPlfq}d/-⿃ b3n݊ I+W]Wၰ:y$z8kXǎ=t˗՜9sϟǥ˖-+^8ؤIwww;n'?~ÁO;3(t5wdqO?(dRn(O nEVP5Ν;;DV֭w.~]PݺuÊK}:Kd`N?IU\Y&P uoCrhhz'S*#G,wl-3}||YX!nܸ-8q8X$^jq*UxڱcGr>tP$n-R^bE4FFFb \@… s;Dݼy'Fܺgm;2u)ILÇ#.]jx>b:s̘[\\JO͚5&'Æ R (תUt)qw%?e0=X{N/EjXѣϞ=ב{)={q geʔA.K}]o˖-M,Y.{ G>}иsN#{?жm[<;)qniqGFw:ax{.6͛7Gyb=e@Z {kԨ~Ħ yu;"ۿ޽{qu_$~ QFIw™3g̙ GE ٳϟ?W\:Cj3M'2DhfĊNCG*﫯' ;aƍ###m۶.111{K}ׯ_@jL $ V1#'7n8ӧXT%ǥF!.n|ʖ-3sνxx'7o+Wd]ʧ!}@ѣ1(, ~G4L l걁-UԴi6oތ bŅeVX̙SϸHpWWnݺ6cثW/U4ڱZ1;Mo~>}b0K>]j/^@e⹡]k>!Cಿk׮]}}}wapkذav._hѢ~{ٲet"r,b34?N08k֬%KDž ެ"##wލk0ʕ+g̘!~sNF={퍜թS'DÇE*֪UKMDGwXGBCCW-[/^{wn۷o|||vet.];wN\wwss뒢f͚Xv,Z.99 ?㎈HwVҽɮ[>|3???3f̆ p2iҤ8sL]:u?u#G_~:YQqw^FܵkW4b:|;w֯_wޭ[8p]Q rnsq.2m4ca۱cG3㎈lׯcbb?Of3."Lk9S""Z>3."۷ccc-fĸ#Y/_<|͛7_fr5jd˖oݢ}ƌ[nU=<<6m.Yø#YQFeϞ}РA8?..\@!{...y}n¥:t虻6h@]qGdLƍ(Q{/_FK۴i?O0.'N [~ÙӧO?nذaȐ!W\ٳ'{ǣ}ɒ%Xuɓ{yyU\yȑիիbwDZə3g-ƍW`]oߐ{X;vʸKj [l9r 'OFܕ)SfҥX}||X!pºuЈC{wx\rլYŋqGdL-[Ç=z4""BSڵqSҥoܸatkڵ˨q8Y<BG]={ܹs_ÙsF#ɇ8((_~C/^kλw_ 0)3___^dI&ܹv1M3g̙393ϟco[P!ϟ+74"<==.Opƍܳgq۶mx luq-gΜS???wM6E{mڴI-;#F||)ĸ#2h:u˗۶m[@dQÆ qxbV֌}G6'Ob[TiӦm޼RJcZV/~Wbɷwlٲ̙H<ggg,to.11bŊ;6v>Sj9!!M6yEy_(QB5P* u"pիϝ;W%00022 -[i+WܻwOvYJlժ]DDZF_A1tRd {[n5bS$hшSX1k9S""Z>3."Lk9S""Z>3."Lk9S""Z>3."Lk9S""^-S:"RF̐CGDhzH1cCVZ)ulJq#"Ŵ Yi=nDֱ!%H#FDYuxG#:?dXZZ""2?sņh=DDDDDDDDDDDDDDDDDDDDDDDDDDDDDg| endstream endobj 316 0 obj 12063 endobj 317 0 obj <> stream x t}5;^u]iȺ+he$'eb-0@ AH)JWH^/M^WjҔrp+43+{-Y՜~lw?;<rL5N(5*s^4AR4M3AV$!(FodYŪ"fɨg(B183$cv 52?D4hS[I!5õVHW&@ VOm#I]6QSAL˘ea$:XF y+6k' V$UIPǫ1:*j6$^S`)8i_$]~K<^]ԫ$=͕3x-jI z KcjI2 y,'ePm#IcAP3w EZk`̞pl+σAyp G٠ pj-FE(o {`IQP+:σѰJP+Ba`(Cgj 55Wypbkb!8 c WRS5c$<#t0 5Ԯ<{ X(6vݱmdP_HG_l\3zͧ,~uԡ,p֑kZxzEyuE;zW Wi,nC+Ma;UA|z4]o\65<]e5:1xuGeDa~m31=&-`H"Z??./S(:&+Vtr_8[$qgdvf !XjG6%l1YOyb%;xoΙߢ'۲\)j=/o39TU[G $q~h7ҽ?Np\r}gw7_m3,ڧI'zXՍ© g{_K|yg涒O/4߯s?02w\>e"n~<yBNr cVd}hX^rHE:qEb*u^1\NX_jC2z۽Yf:gN v6CS`8Ϝ w83n~k}t=Dy_T˙Gɱ9Ϝ|;a{*Lیct|~u)y*PAP˛0ldP#/5 j@P5 j@P5 j@P5 j@P5 j@P5 j@P5 <͓;mAgfmQЬH߰XI!șܕ jHQQy*ԘNt4soy x}ǁ}_P7ŊEd׾|xdǞ}PȑΘ羽oEs,)pG}~qgm;wUw޶eÚ|v( Jޡ9Q6~`{v߹}.o[V(4VgqvdMMׯ`q1c-zA.ƭxonot$}%4Ty&{I1޻b՚b,ju]}rEGYðPcry`􋝙 yVw4G|NN+L N-βPmo@k@⎶ OֈQC,p]4yOMmpn,vOI2ψY: Ty6 TMyvk?ۍWzV=k-)fir )p|LK֚pN?Og O~Odcqy83jL٢&fd3!"ə_ݐu˧^[ ˚ `8%ՅHB+Zy+VJYJʺdN*AS jdlvT#5R*]qs55f&LdԀI P3 PPj&j2j@$$T:)L=˕Ij&A 1LW+˸ڸ,Ф#$=| ^lrӗmLƯ|)mhud,o:)/cZl/1}wS_se,nAHBOb橬1}}ת䪩SY'cq AoAēz$>VӷU)07xr1XXY\_Q]5<z N2ϯpNt<>3$U.cqj>KREIѬ_/ Nsg,-XK.l;ךs -Z{*=f5g>"c_Y"XH9X^[L z,)}|Y#3j}7?v?&&hh@u\x5'o姟fVSdM>w~2s-2󯏎~S3(cؘj:g޳U wKUBcωc鎓S2{srPś7{Ք_/˪f5bۼ믟+ʩ海n5BVvBF55FHqHJ5B5FOU@ R5Rj@@ SP`'L,Q3849ӧ 5r_P"8~fU$7S ~`Qћ-(a]2.p Vcrk;e,nqScFc$p訨ٱg}wl^_0Mu@zN)|wh=?j"6HN J#}ٶs)uǭ#WUL}Mz0pKϪ#۶evj6o.>84|-?[6^{@> SGm|`պ 7n*mq -hr!FKPcGU߹bXB]}pe29Z{]f:iZ)s˙ ' V/\wvHH_wg{.sez*4+.XmBi#.Q;Ӂm)inJ Dq@I\LjmvooNePR*jbmc 4$czJ|@UK( jFfkH(PK^3hJsȚ-b6&\ג/$/Mb($b|qԵ%CY.1[JVԵšPe | endstream endobj 318 0 obj 5517 endobj 183 0 obj <> stream xy|L?pmQ[K#}MD,OXbߗ(PۧR")=CZZjm"vX# $y&s'gν}ܹs9>{LL CPh$xg ]=A!/xg =5!x'=)!xQsƞ8q"..ϳبBMڥ?tuu5}ݣQQQ Zzx77UZAAAVkAANAKJJrvv.\p>}֮]EoCO۷WZ%y e˖Y.trmOp4yJ ZttgXXX׮]kԨ1iҤ˗N˗/'O\r5kϰhѢu֫Wѣ+WVPNնmTUOm-d?~)Rm믉nroN{F׮]3:t(m޽xN*t` ZJh{֭[ίviӆϟO;7l@TZlIFvb&@PM(h޽{A۴(2*EǏG {Lm___:--[*V9v޾}PB34''jժ=C%VZXi- `-88\BcƌaOթSǸj1j(:qg}F{֬Y KZѭUAVMӳt"y4S^͛ggA;x 6իWOIIyÆ bþ|NE;cbbhMiϋ/TFuSyܽ{ɓٟHRQ'OnܸamcZbh <#g.T# 9aÆm`؏w  X0G` sD < X0G` sD < X0G` sD < X0G` sD < X0G` sD < X0G` sD < X0G` /9D*s$===))F-#4yJoVFΰsNggUVپz OIII}vnggϞm JٳgK , ѣc^W\Y\9ueddL:B l@@@ff&>i <%sx9nܸRJEDD:tr ]v9sfbbbhhǭ[.^Xf5kvȳ :)SG}dpuu]z5{=4y3ftw9~xIAٳ{iР4y4d;f͚EEEgkU{(hX̙痜٪U;vCAgłvZj999/^P7 Ϻs$==… wܱn#AA9" @@,y#Aa<0 9SbE߳gm!Pٺu,d-(hΑ~aÆ!!!ƂlٲZY.\:tm۶NϞ=-ZTtigg, [nI=zԨQ'O6@AdǗ(Qb޼ytsscjTʕ׬Y￧߿׻w>{lzOPPӧO2eʌ3)B5Nv>h94yJ-6UVмı~mN^|Fb i夂fiӦ7n *%BAdO6m_t4,6]vUZs um$9.ǂ 455dɒ*_((h̑8m޽4d$99.=z9swGns,h9.͛7˖-K} OaW 0 &t19K>}LWRǏӳ۷ooӦ mcņ~I&oS8G)RyȑђZ˗f_J1Xb^^^;p!2eDDD~.WBAA|ܸqCRjh}u%h=III钳ݺuW4  @̑+VԬYѣ꿵('X~ԩSQO@,y#Aa9" @@,y#Aa9" @@,y ͛j3H3彸{n\\#AMIϜ9ӹsbŊS...3f̐9ٳ_{?g/]4gΜ .X!hI(Ś5k5jT`B yzzݻޱcEoܮ];4]g7%nРUKFFF6mڔX~}n'WzG[lf!H cv.yTǨEDDPe+^xbb"=Eʞ={Zv[ftC|3̢E/^;vm Y+VZ999}+W=l|w?@/PB==zDJFZZō9vԨQ͛7OIIQB4$v6m|v٨@M>/_Օ`}9u;xѢEu֭WޤI( &-<LVR"bI(ƍȞk"]~-)H"2@t0tPCVAG+VfQpQoߞ7nYx1]1a2e迻v2.]HNKڞ0a̙3 7"&E]YdtZti[ovResqq { JxOSD7%m:Ck')))t{Xz .БT`… ڐ!Ch$RQFtмysooou.LBI6oLo>0226m';wӧO===YAk׮U-*Ju ZR({x?U13t۸m۶A}щ'h?~Ν; &2@G''Ǐ}JGGÇCSX1J642}+Scq]WWWJµkׯӳtYU{. LBaRآE *JTÆ CBB~ZSFGGSҳt@6CvBZLdWΝ;eqo.stq4*tYCl `1$,ܹ#KJCV^evRqEF|fe`ٳGw &.臈sM81**J &.臈ʭ IdCV;f@41X"Y4, tA? m'ALB] AM6든 &.脈&buK@tB|ͺ`i !bDlni X~,۬["K6.臈ͺ`i !bDlni X~,۬["K6.臈ͺ`i !bDlni X~,۬["K6.臈ͺ`i !bDlni X~,۬["K6.臈ͺ`i !bDlni X~,۬["K6.臈ͺ`i !bDlni X~ D=T`Hm- K]NNNwg7nܴihcϞ=ϟyuLP҅~FbffE^|i&뗠7oLMM ѵkUVټ:&hIBJJ۷s{9KtzURR۫_曒6wիgΜ4hPpp_EO-\pŊt,]sdd$N肠 &a gϞ۷/m,X ,,GzJNN6JŎ;ҫܞ?Χ: b)l3[ӽ@…njs%Zuꖓi>>>AAAO>]13-'VR""":TrpëT~:tɧ: bYZ~mZӞGVV`n9mMPӂ6tPLbxTfiA]6CNJ+PT$bIXZf̘vN:u4ou=(h1$,-h3gd;Q'bYc*_WDL0 kB =x@.臈fłlٲ2eDDD1$Uh]v*Tx ͺm[؂ &a.$&&Zy`J|ͺ`i !bDlni X~,۬["mNb霈 &a.Xf6~Q$bIغ NNN:Ήo(h1$P"b)ls-֭[ZZ5f'Oի{ĉaÆ9886z.]ξ}?M1$tcǎ0aBŊnܸA;/_ hСCm۶}wz … =<<,YvE|SEnʕ+[l)]tjjd/4lؐ6=|p7dz?rC*wPKDL0 %]عsgBf͚3|pv7.GI6(ݻϞ=ېUК6mzѕ+Wk/^P!b)/hTv~ ڈ#h1FٯRA|8+hto6mڴN:'8PЬHPXЪWN5j8;;o^Hnnn]ta#F˫Wz8`@A*MyA ;w$r}J,!! [1$4Qv@ i?<͢ƥ`$bI(/hZF"6m&a܉`JpEw&buK@C`f@41X"Y4, tA?D m- K]mDEEթSdɒݺu>9sfXX;6--Mh & 9FFFԩS)؟s䘖`-"6g[nƏ?7|p*btXK*usժUkΝI2aoEN ` +.xvCA?I!7y= ޭasA Y6!FZ>dh hF||<ȍVɼ|آpʕݻw[M.]`n޼ZIII8p?2m۶ř@wNҐ!C7om6z8nݺ*8;wQӧ###}}}قM={nݺUVNJMM9sW>}={f|;I~CUPO?o vt-*> 4HOOwuut̙#GWh|MffÇ[h!y =lٲ{hٳwL;BBBEo߾==lӦǏyt >\lm?&&XiUרQ#K.]Իwo9GAŪo߾:u5kyEz-PXc5=|IDDmǏ hFw7ŋlvΝzɒ%ׯÇatOJ3`f7(33І۫W!CzٵkիGÇ裏蘳gJ^2w\:9~8ݖva۷عsgzjÆ 4q}Ν;˿d߾}.\?C9 ٣Gʨ arz $T[;f/hl… z2?@T &jX',rꂃ{[DA: ݻw - !464v< }}QzI Rlu]rLJVL_Bеk͛wlb0t[AI/YhQ\\+ȩ%XժUQ=jC{ ֯_&MDEEe/htyCK/*O"oӦǍr^BŇnT={ad ڵk.ؐ/ݨ !O([((S mlMyK #FH>0ki'H^{@.2VBaβKHH0}SI_JP`f-iqEW_~XШ:ŋtt*y |aoٳgSyDA'OEFӇn.u6Q իWYfƂF%Ν;tP]$/'OB9qDɇ;3!JX4 Z```Ϟ=i-LBVhT%te]ݗ.]jbkAg` Wд3:4 NOOgqed[/IKK3? c-* X h h ![9$0-OȆwL[=d1%4~~~GRRReI ܻwۜFGw6 WPwLE"R-.?X*dDV 0>*Sgq2Kʻ 0>\-,ZGX!Ű#fq)h:šd=#fzl1Y"a:jv!O j -kn0Dv ͦ8DnV0DO2YDa5+C"faĢ$Fa5e݂fvk0DٖpYQcO, FcA{n\\MŠ,";Y(h _, kffi:uqt% XfMF ,XP!OOϽ{;v차/ڵ%y#3DهN&E>g?XJ[ +*m޼ytmܹK.]D OASXbŋOLL^{={Z ֭[[p,6z;L-ZJc*U_~26&&6.^H0@.www=… )R7,,ƍlY(UF.t6IAzv:`Æ Ҟ26h^ec^u/^PylvV23fȭ!`,*h۷o=tpG޽]U5kFyo>[_~Ϟ=7n\2{ O1ACBBn޼IS|7h'|IHHmC2B hq}+ 3?a)h+3%a}왇_Ruֱ.\䤤]rEozܹ еNHS`ϟ?[ҥKӞz.ӴޅޚgM*SL|||G,3??a54+p$t uցƍWl7|Ǵ.W͛&¸7I} ;wӧO===Yk׎қj˖-lQӍĉxx@sXS4쇒] zjnJ,Ii9l0ٽ{Y.\(9sӦM٧"FN{oΜ9[nSЭG&M._ȺGEEѝlѢEP@-)\0] >lIOO]6e8sXS2 a{$]v-^8wrrbFWREr hт^ҰaÐȐ!ŊvttgWNM׮]{nݺalIйsgCdoVƢ/ + agܹsG˗IIIrTff&Y`XDGX1`jC$bU!$,H6 CIY"mVHVD"۬2 &!f8D"Ye"MBXqDl0D%fa4 a5K!*ijC$bU!$,H6 CIY"mVHVD"۬2 &!f8D"Ye"M-`=6:#0ޡ{l;t/G`C'w _xx #*q|>:3xx ww=<7#*q3 w x'xMރ$+D1xxxG ww,{D;V`eO6`eӎ endstream endobj 319 0 obj 11894 endobj 320 0 obj <> stream x=leޝ-ҫK7;v:CZK]D!LaTR@UJuS%Y@4؎tRK4}'R#qRXEU50 cHS3U,ɊYqGk[YSW323xbxn`fYP65,J3CqPYnJ33CE/g(ތ鞜 -M91/4xgՠURwfufKcZEޙ_p᜚o 5拎uK.Je/l m6ˮ [=ޙ^VG^ [N2?[zܟۋA}A)7e}?H3)Rf^f_Iϟ>7AAgZ[]\f;YkyGV=3Ϝk՘ >ވXULb=VhgA<bwtK K K+Wܟ `hahahahziziziziziziziziziziziziziziziziq}9}|7K ޙJS\h |eis˗vvo{Ӕ}O>{wgsvַYCwwܽw?]>w/dfrܥ[;woܼg}ț7v߻F*eLǟ^zRwk՝Q#߾ze{rg>;k> zY)ewf^NSeմƋӕ3+V~\O>uh٥tɳMa4ڴ=?zuXKٗ':07{Leь;>d>4ΡAtjssq撒DzS?~*:u+gg~(O?{½>o{<@ifÓ{@Ӽ >ZwA"̻nڏE/zы^E/zы^/ͳ zwA"&D_.Hy$]pTcwB"+y$s.d~$nWʲ&XEU50=U,ɊYqB*jQVL\9aA0W,wg`cތi{%ޙm^E ޙ٢3a{r;34;&_u * ޙF|_:x~ksyg:˳޿|cwfh1_t"ovyg6W)}Nb{_ףha=Z_ףhziziq}9ԋ3BX?#3ZX?3ZX?3Z~/K Kg|pR'|c>xBO@I0<!'!|do 0> stream x{\MY-4F.ee\Bb$*Pb k ͌\zj\z df̸1tqKW*R;es*SY{ng AAAAAAr#QQBPd xudΟ?=J5Toee%?t >66nݺ?fffb˗/Scc{xxlݺY888`ӑ#Gt ٰaCrAL|vZ޽CCC]\\:t0W^mܸ]OC8**ok֬AgիbN:|󳷷o۶… KJJg}6n8,X`bbbnn/ܹsgKKKɓ'HŋҞ%P "YiР*]__'OfgghBOOo޽a;{zz;wԩS8x&ZJxӇ8VY۷y9`\nSLcZŋLMƍúDD2DWW%"##򡺲(ՇBt:::!oa;#`ccƇa <8#ȑ#q^ p aT·ÇdϞ=IfHH"1ܾ};&L@رcyqLw%0 V\|6mЮ\"1D[u&Z~gggmmmfLU|HIIA [n!Ƕ,)D&''#?!b $H/\ ^a677ݻ|G0x$VR| Xhyg}J644Ç5[ Q>D5 aT@@@@@@@@@@@@@ԠQ >T*b1BćgP"::Xćϟ¤I$,Q2ʕ+cƌA`աF244tss+,, 355,))300VPD&>ٳuttN8abbx쐐[[۔7no޼Yr,}`OeaLJ GJq億ЇEH s8u\zmڵ$YEЫWX5((Wrl2OOOL210`}$,'!hXZXXag''D&>TׯKXBBD| @<}V&dCrrr˖-+~LL%7>Хp򋍍5kD6l``ݺu,ĉ͚5=ztvvvppp&M`رWBw=i$ȓ'Ow+ǬćFZ*..ښ*6119rȟinnm6DvѣIII8ayyy_Ynݺz% Jںuk>}$kgg¨,惽=G-?>H__?44nqRcΝ%!xd⃯y7od>b,Sj033Cg2qD›>,X%RիWc4q%dC`` CCpA6FB J x~RU^ w^ӦM~޽% ۷o|ˋ0waÆ*XpaFFFV7ݻw5_e] 1Yv6!?ibә1ah޼9l9㣭ɆcȨ(އ#B.7je!ݻwj [e~k׮1O>-..VJ+{ui&=Ϝ9SYk ~~~$CS>oE>`QRR"aI>XV&bj*هqƩ^’Ai2YXFGGWo*;cʕWpΝ:bǎ.urڲԩSƍdNW_COOoϟ?G䧟~,(۷o˖-'L@aܽ{͛7cijjgΜgCnGaH⒟Ϟ=2e ߿aÆ{[ؘԒK۵kc?sY4i_2diӦ?oֶm[vmPЬYիW߽{wԩPS]tuÇWYܿ )ٳӦMWܹs;vȮ!#F ;wfff&%%c')8Ԓ#`bҥL41lEj_,}'kp&TD ЮCR8rNbٳѢPpigg4^@6U__˥M=ɇfgm۷o5:v4aGT{ttt.^'[Xy .ԩSGLV[[;00Pv,@uܹRKcџYcǨiii͛7G 0c6lzH(͇RKPLMɇ*d5eZ@u(P7rA7Ue\,ٹ/C|?;|PSs}s˖-,%$IOOJѣ؄cǎL~g}ҥKY |nm۶~›>*sdC]DE7lؐ}#m6 ̙ ###_z:mԨݡCҥK޸q`_=dqy޾}[OeL|pݞ~zN>>#뼼rϞ=U5!&ܛ___| R?92:ohСCŬ3'XBr|<ݝUEK@*ⱪJr>ՊL| f bUƍaРA$%%0|Xd k0UT³&dP7o\1܈fӦM+t)(a޽ epsso(S#E+TJAAXpv׹*gd[F|F| @@@@||gϞ?^P\޻w%!ފ||Ҋ5㦣$, V!| x| x| x| x| x| x| x| xjB !! } %4ie 4RBCQ VH M4 ʂ*IADe!BId     OaaaMxnݺCbbՑҥKG*?vW_}ԑ2Qe\]]v:eʔ}ٳoGק~ڡCK.߿ɉuJ 8p/^|ŋ<<<={&;l0$믿8q?M/RRRPw]v-..B&$$>}Z֮]իǏO߿b D._|͚5b^ÇɩM Ɔaƍ,>ӳ{Jܼy]Lu=f̘Ç/YE޸qDzA`UFEE!9s0Ю?`8裏)((`FzzzPPPXX6>>ԩSl7,%0 PRRDAW777 @;wXZZb=~xsCV\1˫gϞb^XP`6M;vѣG/_dϟQHAM<@ķ0S}T#    To 4y D~d x|  J!!LÃ<5]OM *@TȨf)**~YPPP^z/`jݼysٲe8 6 "7na eYԩS֭,XPp6}ػw/v۵kW:uٰa(oU8z([n6m¦)S CVV֊+N8Q,p6||سg[lym4]b7kkkmhhVVVgfə8q=PRR{DEE}>u֬Y .l׮ݘ1cxџ;wwMKKO&M=?T}fffƍuuu!*bq6$%d G E+c{}1O۽{7"2222d&%%9rB*`Hsc6mڰx~,/>R!;x(|D^zpqD[#G>={##hѢ0~'m6|4HRE֖ŷj*22RxӇ .DՠXE3A@陟ƨQ*XB8 > 2j%Ϊ0s@C#̺,|`z~1ʈ>رC@u|(,)0OܠiӦT17:U#:;@t؊?1`fOi+ n +?Ah-3޲~peoߎ08' >N:ݻw0?AWR}],0dٳ^z/^D$V8|˖-Ja4|d׼yk׮_RcΝk郞SNHGǘxm6..-Pa;|0?Ο k U Yx>aE$jggf֭!!!vwwuﱱ԰(..כ? Z3*k>ӱcGL2oݺņnݺ!Z, Y< 0Xo~؁&L`/`kɟ kG @-PRd* +W9nE!o!]3J܊)*owVSV>;/tA!j b]TTTQ} 4j1>*- jC&>@`b}3:HX$,dr)JuyÆ {Oq.??}`kkkllXv3իWb-ohhƾNOO-1c ԩɪU$, GgΜ W^AA8^̞=[GG'**ĉ눈DB3g^t˫N:\~siii'Olٲ͛7%84^>|_|aԩlX|֭ ;ּyxAq277WS2h۶sx0(M~~~sA7@L> 0o޼?M6/fJBTy 'U}`^OWWW&MC0 =t萙޽{%8 EWWR>ݻw#f˖-H>lڴiĉLy"!C ={V)U^za8|pSSS50R`yyi߾}6%G>>T6q 4"hт]+V>Kʇ0w\,I&O&U&x{{'͢@H@@@@@@@ԠQ >H>)!*C><2ԩS_|ܹs[liggw]DX=u,_\|cfF~z'QedCtttݺu,Y=n8D>}:{rW.]= (|PS¿kCCC6-|왞^IIEEE沇)a5C߾}ŷ-Zz*ôiXp33FM8P]C>>tڕ=z3fŜ>`iMHHpwwgPK¿k----,,\XXeƍCFFFVrrrU $E>>o߾cǎ:t2ӈ}6&;G mmmA,--"PŘC޹s1J /Ԅ|0Sjć7nE&>2| x| xdC7300044g~EFFZYYk׎q !!2!!!)))X}o޼ZZZLLLܵkW&M0"To`A)(ppp>o/o&aQ z}SGG,&&&]1ſM'$A>>^իWll, >' %,*!To.[ӳȀ'(|`eIvBBE%TaddH'''C8عsg&JXNB^,..~:>ddd BdCERc>HXT&ƈ| GԠA><C><C><@Jh:@>h:#H E2Bi@AAAAAnp endstream endobj 322 0 obj 7675 endobj 323 0 obj <> stream x Ss}M7a3%]4zyMIБ~zϦ+nhic!Mԓ~(m=MO,L$4xH_%_8ޯ"\L&B~&ighCqR@Kz?'ڙx&cEY Go"I-kgљ~:_C?tS{a=}٥G֯rS[4O]Go2`OCM#8Zxʽ?@~PP?( AA~PP?(:O v*s<OP0sBg_jyte}]j$ttbx3%=I5n2[VKO$G)U~Z 5Ǔej?X^X~pvˡp>}^wf9։X5E1WfH6*<̝Vq6d1 ϱFF/˟g|^g)ZLppwS:v ٞn9U|g,X+G:s7'*9 ߵcmONVuK 3ip}w?C,9>Xl]o@_=Q:B"IB%qFk-kIG{%qL1eIGs&sxH?/A켓xH?LODLxH? uA:$IGD#MQ1鈨">)G D# ဥƶn=6OAeF#ra8e:[Pr) bJycIVI9ހRO1לw,/7X7& 'XЍH㰈<-cRsr{cxnDXT|?X˝lwWaj?d}4?)Ή=F*&kgHm=uǿJVw팫fAKg+CD|3 ЍHۅo`rEXoַuB7"M>KI闱d?S;{o03o5f`Yq ~7%hI7 4f/yC.\f>gZI?gYIY+T|&HViYɎluKL?gbک;+:YcʹѥRQ[D~4w/ScL;є(Id2אEeRm|͊%92~ }&JhO﬒V4KhЂDd_: ߛ]*qk"ܹ~џbBw"v.3\o(Z l9ŧܵ5Z#2mN{G=ٰ}y娋P!ѵdou?{vܶqҮxC u=ԁы-~59}9m-w񭍷\;NIΦGs|SQZt_䦛Wr%E փ1ŧoMy֜]EPt-hn8YdӬh-TfLLoVy˭b 9OstC@¡ԪZƎksO3`W~$0=i3lhdTt9JgXA4[% fx~)[S/S9g `9^S1foiٲGY\T9gf`^[/Ohjkr' W+OP Wfq*rImNo{ʭ*k{xڧ׸?3_~vQvl]KP~?Ś`䒁u7mޢ7:\2*Q\Uі9}V +uF]k2C1ᩉ4w$դs~{1Zq9gfEK*0yf,WX[h봊8pWNUnJ尖G`W>@M>i3+5PhPcLfWMEq֙?ð<_t5DT=rVK)!    Єf endstream endobj 324 0 obj 5298 endobj 170 0 obj <> stream xy\MAb$ciA5K!g)L($2 #kL~-mc'21neE*ْJpwn۩9Ϲ~9SR?mI}ÁPrW }3AY]5: me$w7ܵP.RV/\\/tBH_?ckk>'|Cj?rHʕ׭[]fJ W<Pi'##{Æ Çi{ڵZPZTB'W͈%>666ӦM F6cOuOۻvo={d:ɓڵ+:uό36mK;|gӧ[YYl2((H}e˖iӦm۶t=O>]fo߾ْt$H@H=RjUJSSS>ydjjjÆ ׯgjg;;whn=6"""P۰IOƍi{Ν*ew}G}a R֭[igϞA/~ FqWu>$ˋϟ?O4PMCCCrO>qFZginОljرZ(XX7+WL(FXXX4o˗tVZQ#!_Pu٥ &<|BBBh;&&'NȞjݺz6Rn8ꖯZ֯_GgJ6|hSR% V=K0kkkWApDx,X@9~8K-ZzW6j(u ץKXN!C4f>kצ@311aL۴i 2OVVON-3gd;Fǎ߿MDEIEBlРAtz.ZOQ@ 6THw655e_^|95mٲ`Cǎ˓%%)s̙?~vvO3ׯ3mӳ:tP"Ǫӿ###pppHMMUiOBBMi}]zM6oߦ'O۳SQ{q۶mԒ)q7JJ"q=?xŋ)))g)Rlll44MÒM*"!|@I*f=ϙ3rljsʦb֭[CCC=z$eT4sʦz]Dez  ( #,P3G0X$g`@IP`9%A=sJz  ( #,P3G0X$g`@IP`9%A=sJz  ( #,P3G0X$g`@IP`9%A=sJz  ( #,P8"wN9'''##C+5(z>{MQg\v>$BիWEaȑsJ"_>tPXhQhh!C֬YS~}kkM6Θ1̌ ˓=)DH=]'O666޵k׉'6n3wwٳg._>!!!::e˖ׯ-)3zhHہ [[uֱg)%}'zJR5kk֔)STC7og<ؾ}{)߈>@6|h O׮]9ž]xq@@D |@It>ի޽{%7 %a$&&j‚vvqq̔(DۋJz  ( #,P2svvd>${5jHVjoҥĉ}Wgjjeԩciio߾||| ~}Ν#Gd'yiN%^ |@IsJJJ͚5,Xpq;;;>'VVVvZ˖-7oLڵ;zݻw$B9 `̙l֭[,|iIU?mPtP5kFӤ#FG>}:;I_h-ʲk׮}}?W>$By…Çg,|hŖZ$++VXO>W^b)u֥;88%Rl͛aÆ/\]]y{{&''7n8--ݳgO>}hcŊOQҥKvIAgʊUZZZ7MuhcjjڠA''')###GGǶmڵK3|;MU=z$ Dx=i[biْuB?qA(ի[ly_gʯ3<ū8P~g`@IP`9%A=sJz  ( #,P3G0X$g`@I?~.\ٳG+cPlhhxqe~'<<~2\C9%A=sJz  ( #,P3G0X$g`@IP`9%A=sJz  ( #,P3G0X$g`@IP`9%)#r@Y}߀]D}]S}]ShU 芼 fxˀ]PY25P~r@KW{I:(5o tc@."Ѫ^n('t ^C9!(j슪a}+&nv+nҟMmb *7tHiRht #z @W0)UU@zK QtW!-eQR6BU2CP.*Lx&;91K:١y-,ϟ?}T+GЇ2lƍ>RJtr kײ͛kN/HCH uM6[>!(#!ncc3mڴ0j\n駟v->>w>{Ls;$$_&$$4nG>Go^hOJ3''ݻwK_B:PFBUR˜ɓ'SSS6lX~={P?Ϗ޹sGs{Сq ۛ"6hDqR9s/5ݻ)s`JuҴJ^ >:>6M~hMmhhhffv>}ƍiME{&&&uPZ:;w FZ+W^hQtttxx˗߼y6k֌U׮]GIG CZ:vLL mO8=պukzp_eȐ![DDӧli/ĄvY5;v&WoܸATV?eT`1"<|,Xw?~}E^*UؒjҤI͛7a@@J#|ڶmkll|̙u$%%ӓh͛77G C9|hAAq1}tj9s&ۙ6:vx}픔ړv8pYh2C5FXYYjSLQO~-226(RSSkԨLF{2MN G C9|X̟??;;߯ZUE|ϝ;׬Y3v5kOY|yi*UNJ-U:uTrejСåKqō7Q:HeA(f;W\,Oi5SHЍ@=s%t,gE=t,P`( 3G0X"AO xГC=s%P`=)=3G0XAOJ xЙC=s%*tP` )13G0XBgJ  ЙC=s%*P` )%3G0XbCJ  ПRB=s%6P` ]*%3G0X@J ХA=s%tdP`I]*3G0X@J 4Ы@=s% 4P`I* 3G0X@J 4Ы(#rc%zK2X H_Ϲo޼ :V"ɓgΜYS}joO^UlEbbb2qD"eʔ)=ڴiS˖-@ :ԩS^:hРΝ;4‡6p_~F3({CH }+6!]fW^|VZO<'OSٳfӧ*?@!9}tFFe?C}91sbb"5>|ԪTNB$, ;CH }+6lggwСݻw0Yxi:|?޻wu K>_͛7ٱ/^TR.\(QG#%spp ?'N4l0667l¤`䘛YYY𱷷gѪV;6&&jժ/^`DX>RBߊM`=߹sI&fffpժUlEO>OrrrjmchhxU>IXJ!+++ړZ._,agTt{E%;u4h Ms-ZЂV^4)jР} ]v;RVmt1cPt҅Յ Tuر{UV5k֜3gD н*O=Ӳ}ݘC*jMl>}iCBիW4/b߾M{EzKb^Q9WTg`#,顇#e=CG`=GDD4j?̌YlY=T?s*ҥKՇClmmΝKi:uXZZ۷Cx顇#ݻWFGFF~!!!.]Y㯿Jabeeuk׮lrt˗;uDh +W8;;?CDYE"̙3`}…;wRtrrZ`{vʕnnncĨ?չsgR/ =J:Y$B>o4[(|5kƶi=>N45RT ZhѤI)(GdE >m߾}ɓcgg^7eeeN0ˋ}ZS!P","RϷnjԨѽ{rrrǖ]/\]]y{{Rfڸ{ XbEQ@>@'D`=z\0`Efмk׮rrrb}Q &MDZh׮]%B,LVIbi6fffdzǏ ʮ!|~#,ŀzK.g19 Y bs^^ׯK{B#tD[nٳg۴iS;utܹr^ |d9y֭ |t##t Wz{{ϛ7iӦrJݛ4i~ZQ] (|Zn=k,KKˎ;^~v͝1cyPP[a%%%߿ySNС§ :')@T2iҤSP޽;""RJ~D=;;{ɒ%PŇOQ߱c ϼyh^zݻW?ٴim޽|ͧ0Tnqw)#qqqpȑObb",,,h⒙ϫjժ5oj/#%*#_~EQ****))I1--֭[p<*a%~zRJ+Wvpp8tk a3d?~4iç`IPPڵRȨFT*U<==Kr4ݻ.߀@O+6n۶mҤIw>|8ͅ(LR{XX-Ml/]v^l-۶m;m4 qƞ={._\w3h8EUQkTi3UVuqq c=OW^M#:ΎrF+[nFJ S sUVsK !yJ .z_~ʊ=EKaÆv͛K,=WNYϞ=퀀ѣGÇ̬QF==*| A/߸qcѢE4աΜ9/_*N:RV-P#I(|K/ H0XЗؾ};>۷v9sJ#|h F ~Q°v~`믿ix"}Itڢ^ҥKjҤɼyvٺuk!""UU.]n߾=uwCGT*eg|rrr>:i:|;ʆ-ChңG zcǎK,aF222rqq477g[hABwy䉽=;a6mݻnA7Zd,]J.>--MPU?}P,^4Q#Q9T(@ 8-2V_谢) ݶoٳg/\@߳gn/'MI?U@@x}S*+`q}zZdr*"`PiA><hA4>@7`q}Z,/^ |@\WAqZd,] *#"c<4. |@×@qZ  hzx}#oGt["4%mIhO(C9I3X: @- x('iKwHN%aڣBpEmr$D::!qt["4%m=+ 8HD ޯ_H6X *A:otB-RtxBBm(ʕ+ӊWoΗO0{`Vd,q0(EЊ,Pٳ666Enaaqڵe˖ P_P뙖EMKN:*##C_PCEzxx2$++ JGٽ|R>$BY$ ѣGF T ,$%)m̚55Θ1cʔ)*>$ ٳgF> lͭ\ǏŸH`>Ν;@tR1^o۶mJJ'UF~^x!u ᣯ^|I=۹sg1^:$$dbYzNMM&~'L@ٓM>L3"OOӧO/Ynݺ6mqvv0`ܹsiCݻw?-[߿[noV֭[|}}e˖%''"רg`[vѿ۷o%Ã\\\(4hagϞ=qqqagguȈ#/zO+)777>w~ :)|'B=ss]zwSNѤO>:|(I ennN5Cڷo>m(suuUwԉm̙3  K?'>>^6I֭[G۴ڵ:|(222233qrrJOO_~f/--0ӷo_zoos>}N!|S3w\OOQFP=Mf)4hC)D9|0͔O?Q1c|||trkbѳW\) D`t]aÆ7o 1cư5kVf#F0qۭiӦΝ)@˖Ǔ?~LϦ?^5KᓝSzxU///5)'(-؆144d jՊ6~>}deeծ]'99qiiigUBhD1r%ߺ#0|ZhXZZ>}ccci fgg7p@722rttl۶BI)X<ͽs+SKRR i" I^GA>P"LIRgA^(VK G yJ&LzzJ"0| ~k׮;x U~К5уj()yeeerW^{USFFFW^=)D`T{bb"5ߏJӷo6mТᅲ-)D`(S$''SK%>BG+(zvZj@'>$g`@IP`9%A=sJz  ( #,P3G0X$g`@IP`9%A=sJz z]De!}: w EPFr:P^rW@}@y]Ae$%wܷPvr=P.r@}A];%=e!ww{rUPJ-@(++KKXbڵk1^eb*[nbz6m8-T|[nݽ{M3|𔔔{y{{0`ݺu{z뜜WWW__\CoҤItڿ~/tҏ?x?{キf:ȉ-qYfQ-X ,,㏪3CC cǎi~ÇNNN/^HNNbEu)Q]t}CzHPJ77>hժUᓔ4j(OOO;;j2tШ(vN:|hΝ;ӼTshRB1ulذA6I3888 m۶>_={vDD=?>OWMxMFSGV!|XsZ7M8LJiy_8pW^#G8p!rqqرcU $S- BО/_V!|7o<~X}+==XNFFFGi܇R:VEEEݻ7&&F =[r_(f v@lhZ@_or_(V s@Td p<Jܷ~E'(ܷ5O+Er{W?b%BS">%BwVEbU"tpg] Y%BwVEbU"tpg] )l1,*ygoM6vZ1zj5֪UÇ~֭yEEE ӧOWVm͚5)?|g]pomРgpp01qD8p ٳw!jO:EZJ!;k}ً_ll,^sCJ'OjCrssioߞ=1zhkkk[[ɓ'xvNKK1bSXXJ#|f  !wUY{ƍYt0ZSW^;vlҤIFFFtxb= LLLw4Sjᡣ>(@ BgϞ%$$'Oy˻ロƞ>rppY {K\zU3|ڶmK :V 𡗠,cԕ+W={ŔmCQ:>brgmٲZΝK˟ڵk?=>'Nر?yx`` ӳg 6X"ޣ,ڷoO>=%%ʪUV<2e :{u;v,5rO5RJ:u˫]%vwwg_Xt)!_pח_~٢E zfMa5!J˗/^:m{yyթSv8rm=z44ξyEPZ, 2{VcFF/z u  Y%BwVEbU"tpg] Y%BwVEbU"tpg] Y%BwVEbU"tpg] Y%B; J$M;cr侃9&M;cr侃9&M;cr侉$(14%>܃r<{F{r}WDr k endstream endobj 325 0 obj 11987 endobj 326 0 obj <> stream xxEJBz B5ХDHAAۧ"l"o\>G۝ygٙhرcǎ;vرcǎ;vرcǎ;vرcǎ;vرcǎ;vرcǎ;vرcǎ;vرcǎ;vرcǎ;v=qaǎpw܇ ;v>ڎJbÎ: Fz6ŎAX4=)v YMcGVi;* iz:nSHpbǎ A;va-ܦر#"Mߏ;vadܦر#!MOm;i?McGG;v McG6"Mm;$Xܦر#6ŎA،4m߼eGlA;ъ SHӣpb, ,jH#qb F942{zt%nS4i5;99q zhe;B Mm Arvquuss'wWWWiY;?E;&M Սx{{yv"UpQ?4= )vф]\ 9bt$BBz{&eMոۑ6~,$FG5p+WZJpLW\1wdkOw7&jM瑦6ŎC'B(GWm_xy]E=Mc i&7hTW]EhnS II{xyKh;uDWtQB;4d7MK/qMr"ПvT_D;4)I-.$wCp%TMCAuήI7YLI~զnSP$z7M_ܦء5MH:0424@YTX Q+tDUnSio߀O$yvԯʔ6 i7OEk*1."$ͥB5*Loܦ!jn/0,:!eԄpbAq77^C;$ZC7يDbKfr|ThKQepbGcz{ãҲJ駲[Ć#jwjz= 4MzMooEt!C7Pez6ŎNCԬ6ZH<[H<%*Uotm =-2[Hl/Lґ3[2pbGcԴpD\Jퟷ">ѡMVjj@ȷ.tmPEj# 1j]+rÈ25.L)nSxH BhxD IL-ӊDbW1]tm bSorS߶ۋV'/vkךP {2p_VoBnV{dE|"R㩇Dj}TM*|Għdv,{يDbwN٩~^n.2p UEKMG6O.kޝSG(Wʴm A|PJH.*-cE|"8'-!*[UnS8UobLZMMP+SQeJp|&sK+A}kI^zbtHb5 L1nSXUoZӡt[%MǞK=8Sz]B5}& )PozO@Px\r{|U c#P29>\?PMBiVշ70e{uSx.[nR nSXV.]GD\1k̚xي5>F^ 3doغU+-?gF ]Z29."ď25IɸMaj}P&jMtԭu-8|g<0+VZz^XvzuUժ˗-^0w攉 TѭCĘ0bA 9ݤ$ܦB]wITGSԡ{aN:sμZt&lƳpKZpM?z>=:Oq!C. 5?)Po訣3;v/?dqL9y4auUj`sΞ9}ʤ cFXѣSq~d7M<%(5<&%6BjãR[wZw{nj8S̠y |?ku>,>mڔ)'M;zAzuTBH:1."߇覕:nRnSX^.Z MLmWؾs^} V9ƌ7ȼptx,,7nѣ* ԯgiqD7MUf7ݤxܦB](M\[Pܾ{>3x0Yx)"C 4_EYҎ%mZ%EpSCS:)Po-u !VE:vѳw>}iFcC%x>ztҩ}IRA>pI!?5'Mm +Tۅ42 $"yRjFVN6mwܹK]v#+ߍcJO v)ԱC‚ԤHJ 5'Mm +T3IQÏ8R-r K,Sqf7=HfQBQTTX*3-9!.:"4 ivӚMm +TiFB# U'gͣ)^%OVdgl"!>:2<8Џ#%Mm +Ԭig!j_ЈظI)i$,r !2KKMIIJL%t%nZ;IMa}yzOHHh`S bb"CtVl79nRnSXn.TO4pFZH>6..ts>0AD V6F.]ob6ys-nSX/xiݷ5EԠVҐo·Kx뵞7B"o.!M6}4雰ɱ pP]2/vż SEZ{6l}4U\}8{_siZaO|4򕙣?1vvqcCB Oܦo&\]w vҷ|+@ȟkHMa.M/ov%ϟў0(HMa .M>5{|9xC].]m}.Be%sjy.X Z9; qɷFxFPyɛ:iE ѷ!a'\|TB2[ _pQaviSw5/!.v7r˅_L(Z|Ûlݾ2jߦ*!s-Z$i=nS8ɷKdn_pva^p]Fr.0NU#t-nSbp]v[ E^4CB k,]݆bb6M|]݀Ubo6' |PӜ\]Z_bZ\o6E ] ۥe <ĩUy4})p s6vR#[wMۓ%lUwƐۯH5(RinSag xOTK vIhyO髸M aR OT[pRwKY~\84})PbX8} F6Al/6EJiMx b4} )p '.ߊ<߽,Em?n}bD/-#zxC)Rg<38WE/d8|(zxG)8 XǤs{<\d:)[uʊɚq"pkfG`H4e\ɓ0YR04})0.p=R K̰nHQ@Bb4})5f{..%MY HR5}$"i/ܦOkG+)M w+$)H DW+A>[С!ĉjr~**ͪjJio&/ď"E9$᠐5ҟ }-eP?v281n}AAȉlurmF%5vee0Bm`p$?P}crjr4I ? P8,PHmW+iXW|~V!he;0ui7R^~DHC_{ HЕp`w/AB8@&JolngsfwWWr3Ԧ#7XZzC N W t &mk &FJٓA!  /Owʩ )kUQG!MBƒ%~aC#᪡_UL{a/ At3WG)O|ӮU:i~:i1ѕϤV*t~{tZ~,t"oz N}xUVU 骕+#tM r馰~>ä5hm;j鐙|V 4Ya褝]E{ޯ"pw%jkE?hj5Jd uJߧ7andAd'Mo-*QHNeڪڬx2c6ɍ;uٸmF^޺)UusXlC,9T_?_n>n_@R nE ʝ# (/_* Z>,^[<+op$LI:(m)% p!1_G=%?4hZgkЃJy+qRpG Sx=3V績wigWwJxЬ DMy7o` $ʩAZpaQ^'ԸV#X/O #ll :s iOoȏU4 _/wWuJcAأ8L d2"=? _wӄ]8#dX[9^Ikt`hdiBsQaA~>.DGm~DPpq>cufHc&ubV@kwJX `f_BB\䶈M{aZ Q뼉ч:=jKzz'd%M|=/DO`qzrҴHxl"5]b){*J{OɞcP;{ᴇPl+Bō9 $_!gh|گ`9Lhucn\:kzKfr|Th#_ɕ>?J6 Wvِsn 䶕z{ãҲJ駲[Ć#jw Diy6Lہ?mƁl[.D> 9\Eh?82.)3oޖߊCuK0&)_懥,υ7^"#04:!5ͳk􄘰@)т[,Vai{T{ÀZ\ҚKiٺKvth<*ğPOFiF<wt/"]tHTŽ/H靝rÈYM破7A gz`w^&bs^ӻe!5hNy(WH,GM(Fq!={ފ%y!4]~"y󰇃yj28Lbi8YBk:nG}hMZt[c[9ih=J+Z丛'zo-{$ֳe58+f9Oa^~ L 4OwF0|x .FAH6C4MwI+li#J0m$EDK5ӌAkޭ!L1ԴhTbZnI'hJ0m$ 'B)3ztҒ\j?=ŋV6A}dر㧾qK=Q‘F"%/C.XFE*\`I u;d?,micޞ܎HN{Xt/tk5_d^enӒ=i?Lŝ{wKp x`WZz5$ކs[֘0{VXl3Lond%^촇/\=ћPi:|&wiq?m;TGSԡ{aN:sμZt$pd>bY.}h̚6yXO=,}pc -jiӦL|gtt)ԱC‚ԤHJit'E5xopİ`B\ ;jR#,*Tuˬ¢42!d%EEy92Ӓ#B} 4,vI Dc`h\+u"Nj%ЈhBiss)̵!99Y-[fH {i+ۇ;0mxoLwL(rE?6 QFD5OLJNIMK'ȴIS2HRSRc E=iI[|z$e,"OMx!-x.u.qb:7O/_BQѱq -j'hHbbBBo-ޘN>#D<7!{؄m QWH?|4<222 #ckCO+ՖJt' .OMy*|@VQ .hU{{Y!AN7!4$$$8(0 OG:rwsuYӼ[E )ndp3nW!MzAё()"S%tFuVgXEwr+&x7Cy]":;`6pZծHolZweHIrݾ F;)h# Do85IfyjG_\W7~gm%u*ӂ~k"MUǹZ *|D bM;Qfhf ,Ë5sŸI.lo C80h,Or((Oi #^v.8t'78(}CW;Ȑ/灉4? K0ѝ|)Fѿ|H,gyEE8QBōe\x7%Wu4Ԕ v W<٤g<ѝ\/AiP'z6G&FMl޿sflz,QA?`!=<8Hqb.2IcOVz)^`(-#[9ySg>~1!M/@0D?ݪ{𨘞ܾkcp)*JHAXM/'~k"D^"ML:j&艾{.*k8>> mY4X`=ገsg(7>{,oSK^3g!"Jd O}l8>ء=V{JĩeXXDߵkW_EDx8T 6^Yby9 XTMCHӲZ}e&'_xUkv%RX4 nS})#'k\UhMqK6=ѷ |k3*婪39M2鹶KO <<ED7[Wz.˼3pRi?Mˑ6M<1DV]g1<ѻ~'-}l e|_y >$ˡ$AfP[ xaD a#8bG9|CQ \~ %ddHӳ*9&]{`DWJݭ!2i4mFON7>eeH3* FOn̞9tX'|[wdBe? MV!Mtu kbh-OL9Lb_GLX $W!MOLu=c* ?pXd2ji Yygn Bf-6i;X$?i#\ dQȣHӂYb$Ihvmw2D2/X:N!MK7BoBZpi=OrcHӓ+TLY,xMqgK#MOX ny+?滩ᐜ1'y_fRm"؀4 S샱Z ^ 7uB"1BzߔpsH+TD|ẀSyW2{_@/aVHߙa6eQ4ZFq*QtC} gL>[y/ *+lB#apc?m5p46s #׿}ȱfie7rP|'$ܨ[a@#A MXhvK/NKmZAk471c O"M+t\CR0VCg8`<\QddG6E^a2z~ &'BAL~_"]Y>4Tʝԃ  5s|$- i)Bm%:7rXJ ܦYm%3M0ϛpO9iNIeF\mEovN^؎4-Hp`%pP/ڻajo T%-<<i mag)iBȳ$ڻ:ppSZ;8rxG=}r`S{-X̀H۩8>l-o]j3;I[<zԵ/w.v!M`Y2L/*\6.;HTN 4-6>eҷVdoT^JF&.JVk^F'm2mу "ZWiʁ)i%ˎv7`|kD/6m‰tJT=Hӊ\Ր|*ŬDڻX T=-HӊԄH85o/Bpz`-}n|fV+H,)q;kVlaߡP,;Ҵ1£6CMJ{'8p$=&tw)v+pK "o!Mwh'Q!iUˊx, k6ҴDJcrB^Woih@gȍFH^|lΩD<64]hd{ym r wRZHӝq“֜ų1*t8U%мxiZ6kV LcYt-]8n/NxҴbx}6% <7|cˇHqf]|s.'\彎>Bn.E14޹̇m"#MK,Gpݓ=p17HR܁p*,.e>Yi[Sӯ+P-kck)dg\|4]t|t8S\Og5uWxC"MKC(i_bTNYM>hҴP@Ux rafsr>:W_ M9Hg)vhc&҅Ŏ!Ms_z4x^7쑉G.~4-u|l7d}h+VпQdWm ifbblʔ~Z|gk\ KMP;ͧܩòs4Y%߀[ja#ېypDKl t6"XpH t>mLIؘxߪc`xA#Mဟd2$+ 3jۄ&J3Z5t&y&~碖P:qz/$0|4m.ǡ5LDa%He @פYU TKkg xnѤ|7<WDtO~Mo9mzRjs " sJ. TGN[Imz0iup mz&U"bq G Z&&K9JhFD,"G`<~96R̆2 DI7ď F &4mt4Kj:0 !B`5gc#I[#[,u0Q5#}9 K 4mz4O琚&ٕ@7>[iETaF[W@g%mn'bj1ߜKϨEMFJM3 ttLt jh'8o5ՀZ"AlhvOHzv#{@ jτFV!fBx&t+LixuP;Xz29*~G㬕~85-*QI<8ڳyAV!FPC DЙӘT/Gwuw5x߱~&?0.,'t' /ĈbZ(`MYeitBw2Ij*|ˈy;"&dC:m zDt2Nw Q4jZ3~%_S]25oIsy/HЅđC xZi}KnӿDXĵ2'P8b6hZgx]9j!ҋw@ }Y$} Q]7\ѬnDmSРiOޯސ{%S舟;w 1vaKp=ob3j)s{Z:oz7? ).K6WEj.8"S9QC& ?Nh,jU;S&HM)v3a: ˲ƼqW&K5KdEԙE2:-g@{hdz?gR0͑Ee,ozA?M!w`Hs%==y'!&=FMW7 %L}vOx2f''g#.MѽLq1 zy1O'Zr[/,y2&y|ҐI9xg~]Siuٱ4.aӲVi1Ƽ:|6x1Zӹ`J }iEvqu#c>5ŖO6BЫ ߼< H];v*f7Ot=~@lX?"ᙞф]\ 9bt$-t!CntޤIY}8=l{A&p&?ij*9`V}MM~,$FG5p+WZ?7Jdj効#]{z}5URpjshoB3Q>FkQAv.}tee~+U%/$p993xCC%7iT!%MvD&ޢTW]hj;!5 ugyY-,lt\\鐔. D&3_Gt":\׻d\@m-=\ +1 {r _n %e ݊@rAQz? 5|'F 5Qn 9@#Ծer .%igJAoK)i A:veg<쳞`<%F Z|"ܦkxd6N% .M;S'fUX0%j:u!᱉$U"B|\#1*ap ExWi脔 Rի 1ÃQP?`ہ%:j'8gp45mW]l/Lґ3lp{ފ%y!"i:vNu}ij/\PgȊے\ZӡdtZӡ"izS C|P3 uuOS ;ԕi!xZ 5,z:ɛ :}Q;HZgHM{O)Ym:8]ujBꈧiM+;/X.}:%-Wv%lݾGWupld Z&LJ|4m+N=QےůuȮPC#b)MQ\=}c}RWf ۽]>4ד%u;]5(~K̙C&;5!*N34:%VbA:.)TP .irWܹ׀'L5oUk}ll>m| 0acVXxi1wiI~丈?j3M'NgʑT=B#4[Z>p x`WZz5y N49/ Xl3Lond%Ƅu#*:(?ɐ!JU=˔?Qu^>`بΜ3o⇖,]0sG{~@G.}h̚6yXO=m VSliAcgpT|uT|rf^q=n3g?0oރl8 [z/1~;wS&M3r[6&ifi֩߾.2iNHm_ܡkY߁C+3~NN0)=3GW_3ӧM2e cG:_JI'E4ᴪbDO c:˼~TG*} n ꊭr>!@nt`]K 6˪~FQNHh[PԮci={ӗ G`[ۧWYn]:/iBJ:A'$abġ s%9 Y9+ . e<)5#+u;vܥK׮]1xq"]J;uЮ /;35)!6+'D5։G?369K,yIAfpY֏IQÏ8R-r KRcx8m8qɼJ rZe%'EG-iݴZb4G8Z>) . RJAф3Zeeg汢e5ANNvV˖i)-#Ã^Lb$%X>} _BԾ~QqSRI222>,2",-5%%)1!>PtHӝ4#,N"gA\!fpԐ?ȨظXoZ9<>.&&*2<480@[/if['yC\Sr!rZF 'eMÆ𫕳DnQaa!A]Y, R[ldb3.2'VEz92joRA!!aZilhH׊tNw7Wgja['e|w^tb|e \tpo 8|||u~~~6#sׇZL.:ij2>;/9K1v(sDž^I]]{x;Ga ]pcٍ^bϼ֨/N{yD\7`oܶ%&jGrC-lz]{̡ylVZЬժ,N:;YF\p83i5/l~<ڰRꋭ2oVpsxT\58"` ZxY:(jYG\Q83U׆S#~h{߀W\إ:-QƇffp - Bh|!ئbd͊ Z'4$$$ {>vhdP[ll7|T3D:32`,le*{86kAG$p-mXf:(fifpl]9yHdueb䡌%NfpN(rV[l||3i/U(xE[5B4Ouu8+nqK"Q[̆B48z 3'cie#anDa'cie#Fy}$:尟Mrm@ۉ*S2oVrmdIgRmuJPƬ:Y^m(zH!\b:mQJ6ެk1xֲI$bC7+66A Ysx &2H:QJ>5K.eU`{2۩[YɈw`n wa[3[[=YɈRC]l/z tFmu:7+9*߻xoe&1<|`=b딢囕P{$cP[l.wf%'ޅ !lKk [+*mYɊ*ndp9yu;zfb\ֱرu!M;/9.p~Y9m.NUufbl; wdjG:ݑ䝗p Y&Y#108\lMnv$i y {ow0NS7[`6Άp9vv$S4cGi?w:kO#ul^H\˦6 #]}l~]^f!#U#H[7Ҵ}@ r35&|1bleS4-֮d;B2qCqfIlc9΢89ucT M埙mD5:^ǰ)N=3#:5jwJg3ǽ'[kpAv04[dcwg&jpgp+/-[uʯ'=F[&3:&xrJOop$;ۊӝ1]:_";y.o~}=ϡcc D/SԸ7nzD{\[C~yS4M، ߻ek<^c|*/H駅\Kw8\U0NxױuF!M?%R Q{8 ;   1iI_ErD}]X6W܂ԄSp/6E,vZ. n>'[;|-YqfܦӸMH_(?pExז?T2iznSDC̟PAp׊כĉi*v?8鍸M#[Hd+<'R\ 4g?E`n#(7fMÜvf76AV+dUSsjϸ Wf_v2e0iu;ZϼkA?]5ߗMacM?=~:mipVɄHs`J-K?]ҫADST0y?Mjuw1S7,Vږ}VTT5Mw13f5CmKr./d4ոMw؝t䓧p!O2a:tnSEe]Rφgye+0iznSEm]˟s"0病L4)".A ~4GlB`Q~atHa? ў8eR4nSF]]B᪓wr0!OFLarܦiox}sN+aq.2ܦ9Mܳ+k oBextj#7󐦗6Et'^g h8q7+"M/m ޭhxP7Nܥg>CMuw|][@{k<*bbܦ޻E`Qwa2$.D^ x&6/N fBܦH@ޙMd?5/~R& 6Ŏh#j.. M?;VH#jDZl3+6K6ŎEڽ&!| |o izvp8m5]h{s_卨F~)v1fOv ✯WeriU.V Ky>%qA8úxiz6nS4 [|]=gQEOrdҴik>ꢦU@M=} `!'[`vɞH3Mv:ù}x(sO28pc xDz'|o+qfS4=s)ɩiYs*n|.Ng-`1zq~euKs>cY^H GWR^^f41 f$pS SMCp%ۋ0izሉ Ro~&WPmΕ*8hXb:~&0ؔ8-xӺk@.JΣ]79:ishMZeVPNfijL4m}?Ić£ov )"P,6h:8%/QӆtJC]\ RKIBfj^OK3B}c]&5j`N%y6Vᚖ~NL3t[iQj1QrDz.M Ř~6wp@V{<E K;ݸH*ѽtl-erxop3H98}4<4m¨i-T\޻h˸`ѐ(QWx:MFTYSwM /k`SϚNl{e ,~a#&s$q*  ◃<:Aij~ Vܫg qII+Q#.SOI!;Q8XAλ@KSTnTƤy:d E i)"W_vW>I9:v%psss~(v~0ysL @,ɜ]HiӺpH mʿx 9{xxxzzyy"bW58IFWUG eYMQ?d-m!hJф 9{{m0"ɡR#2!IꚐ5j 1sHMWk!Z BIT4C{yu+Wʳk?3[r劥}==9-֕Ov顸M-93;R l˶P41pѕNҤ茢4O|H@rN͋v]L{D*s)?'FXڝtX)%M­lJn.N͸uԚ3PqK\PcMG g#tˉĬ ib,MJ:򨴚NՅkGNzo$$_Qxn)VLi[k1n|RH$d7#$](b!j_/WgVuk[UM!lcr ߀Z(G_,u/1TKvӄB"cgHiƽhFv >{P6Ej!Q w>?X61=}#bWS̎ $GDGQē^T ܦHloϋ(C,`1 9 )HNt&E50楗^E5g5V ,`11p&ib$ɴĘ ?8H$#ط]l ,4:~u.YU.(,&1-k+HΖdGmvAvLQp>,E݂_.Ilr95 Fӑə$ O夓ʼn^i:f/}Ȕ- 5F41IZf 3PC߀脴6ςl';zy=41Zb d QXU]E즘\/i@"XKW$œ0bF 7Pg}ڍusZi^~լ;+匱1lon֌=FK34Xb8M=RZ$/3)|xj`ڼ?4@slNs^o*#P{7#7_; V7^7ƹf %=,Cst@(1);"}ؖ*KV$ے{wNt7RI!CI$G -Wq;(!\?NٕNW;R< KW<ͮy?_Qj9P㴹@ڍ73ri9Iܰ)HgT^Yh0U`LFiRx(B#ug~`FNk\HsUaFbL8t:w(Ѩ(W=a>#^&  M=R!Z?[|<^3"7e)`FoL. tkuafRN-[uڬ4%2+<ˍ &vJKkmv2e__T0I  Vh#)9gm(ֱRчx"Z`Jԋ<#CC&vqo5L?mi^__ *_ +Сp;Lt_/=`[4pG}~+y؞MGv2hF5ptkn585aQ<2l(@﫿 C?Ş#l:vu8EkR{:jC `i*4xIT*afp(r쵼}[mqky߂#8 OY*-s!S_(>*撊~svkҼ"[0C <$<Ҙ|rΉhiNdA 3e뻲RBUǝBƔ쒺eW0o BML?iޓv[|{ˀ݃؀tހh{{q; XMFS7Dy鉨Xb%[L4h8 *m!)D=EY)P};Zkڻ~eƊ<r)N]FB:P~Q!Y_;yh8 =RsK_PծQpM@" {fv֗E*I"]oz|t|Xw)Ñvp;X Wf&2xTLVz~ycE]+3ژӑZk[lˈO%2_XfaWN )"n0YEU)N1D>g35qƶo`<,$yɜ72L~3qBnt:ʛSR丈3uqBU'ׄ>v.8d~Cȗ߸k] 6BM~]8HQa* WN(v"_?`f~#5KlqϽrU|޳ŵ?ʹ_ٿuВ9p5Y̫#Qw)% pc%*Dj ?RQNd! Ћ$U9o4]sifZ𨸴ܒڶ9VݼcCSwueN wSNyvmݰM̙[%w ?$"s wJrD!C/dU(~( \.wi<dfaeSg߼%Pn>tc~q< kqcǎv;KiEWlq9EL˫ 5%tj4~tt';&!-e+VZfE]-:.k֬Z5|钅fMX]l 7-&gQj  h֝;H3ZtyӝZǝ]K.,ҐSX^7k/t<}~|a,Yp`ީuU%yqL -8-'ThV?Nw28 v:]8f:jXTCӲ J*k[;Ϛ5{E^g,8>g͚7wjg[s}UYanRZbWx;8݈N5NOAs0%ّ’꺆ήXx|KY(/;-ctitIqzt"]uG @CC5jctP`u;=L"iHht|z~EӴ;y8z7-Nh3i󀯪g5ߎ{Z 3clNLn0cjK֪Z 5]jbyCi5Y!I;a˓* ]ov?Loe&!Am1 p3lM[W4uS* b`pڇY_IFKZTaZJ.I8:(l}X:u=-U?8F|:SbSIm,c3x{{ʎRNavDKE5}MFۈ:- V=ִM^FGIHl44:d.PԶϘ?tJ8e|k4GdVwi +NpAXĢ5bZ' c;x8{ɏrz\~h\__*}N5ƙy$y%+F;iVfc<Ưf׾\..kьӁhl,>5U(5L~&!1;fpٌkXi;w3{M;oqڕϟPUfY.n7)vZSr\i;jT[R>oC׮߸yvK {6۴iCh.`awy_ŵL'g׵tMUkmشfu.7v鉱Č)DZծ`~r*lG{9.Y|ʕ!k,x6WZlpR1\|)oq-ho}4O1kނŃV \egzaU+V,_dޮzT d ck{ϰb~r2/RZeL-il6cy,\x}lox13-݈Yݴ UlG6MH*(on5wEͯ],^h|ӺZk*2QR}BCEeD5}H괜Ω=gdeo6;07=JK_s"aَ>"bS2ʫ뛘}БLj,-IKJ36v:Ը Z6$fW645uttv2ouv45UWe%"Cq ss?K`LRK1qiYyEMmv>::Z[kK r3SL$yسi!/q!PUcR3 K*jja*&PuU%EYiI(4r}7SqXP꣍ )Yť5(d%"a~t^_ayI a;jPUN+((*.)1":@)CqqQA^nvFZr!:\jRqpo1LG*BB#cը=VzR669Y)LjևiQڎ'G.#O[J@Fmx:!9%5#3++''^>vlgЅUrJUnмL*T@V'gdvn΂Eq Q2J[/n7-vڏ驥rZ53׈T^NE%'%& 1QhJ!Tu ~귰t%Є"$Szʯ LMIJB} PITv~/b&Eb S@GDE 8{5h@בz]VR*߁ٮ~ LR 9:\5v`z 11QHh51 $.a}\4@s aa:.i6@רZ Q*Xm_sC2b@Fh_;i6[&gF` arUVh~vZ{!J2 |cfϘP)hf&L=༱W\"T`|8tPS*Kvה_).DaJ]QuzEON_S(N_$ ~oI6|mDNC: !%6=פCqC t ;%P܅apf[Yґ|N'!xA/HoF:q'D?'0t8qk<1nH FuB^!x G:w`јn)c$ ?%;?f7!xR܄Hu:t,ct 7'Cq !ʵ]ֳ' vcҡ[He xt;Ptґ\?@5<vCҡ 7WےMu}݄`? );~tH:Ay']øKx6h]_Du10-Un;v׮8e1F𱐦E.U\θ+uG)6 Nt(,c}o{NK:aef__?36Jhל*f;[O=vҡp  XO,XBa@3ϏZM?H-&h N23Y}StbDLnjۍJMHۤCvLS̽ ed =3Ŧ=B!dR)3gt $QH%i/Z#Yg s<6ͅ^{yZ.bhCS'Kd-O:^ۢA49Z'7C Y0bExEVv1<k`fH巂2e< 8Ȯű\j2`wҡpY%reܛ| ԁV2 pt>x:X?ps\?~!'T! Ss6f49ǭWҡpMxU3R3+qy@! WCBuh> QH9rz4$3Pu*R/MТ KDB;'#A/<$ᶸ^f4uRFo 7u؟L"q[t(8((4aQ;=l(@)\8}8Q&-^% GL7-WF$Cd}?Ng aGT8O:xi]L| >*ebno8Hʤ"+Cf!TaS;}WVJ\TQ py0L*2p[# 7@$ .:>-4NˀFP \e2eҡpNáJaH,)J1DY"NGʤ" KC4fQq%iQ!2tcN~S=ٸ-n2-`Vã++ 3b3.qIEnH 5䬢wCD(Prxt(HcJNI݃;}475.9;:?-~G:n@=D2Uhd|Z^YC;PCy>PD4 p[iLT9\T!c)F=x]y?}\LNG3;H'NO-g))8@-3OAw>`suVhҺ;w>iDn~&Z?5=mTZc؛>ڎ:q 2jtvI]ncO'`iLr$?txmi,ύ} lq[2E&g״}λj :~G -Ip[?@wTAϧ}pf9}L19YT4J;8;)qi9Md7]3Lkpc{6?> E2.&1g5i.Ldsiw@%yD4xbӰS|,:-pkDs~dϝTYv}y͸5,59c,)"*,s_xO?[7<չ"k~sD n Ù_;t-$rc彼ֺ9"㴒@]R>c9-a"5.9$ȏO^:}2=>>zw-o?s1$V5Od|?mۋ\ my֍qDn,cʋWw6`up@W7tgjk/Xe睞^6iL6aFD0<>}O!hSw;EdyrJjz,^nMx^>yī>8Wr_x3Z247-4'PS;m]]zNVj}lbfAEcyCܴwБɓ'Oe'_#㫞8u 9|p߮V0\Udkp:M.,gF4//1͜}kv 79%5mޱ{-vU^^ѣ>4o-V-]0{Z[mi^zBtFLYC&@7 [RR=Ltx p𡍀u~y}{Ϭk6nپkҡpKRR3r ˫j:::, |`1 }~i~PW]QZQHPi':#~C _P,Wj#cR3 K*jj)pWfkpyU_W[]UY^RTo1J8M|8b&vg;j$5~꣑yE%2khzgE PP\\T`תRNu{dcvҡp}0Rh# )YY99^5,>g~gЅUrq|9y>&# ڇrZ5'$&% RS<ӖHE%'%& 1QhJ!  YGY8t-0I(K huNc0,P>OEF!6&:2R ӪUJtTi~oy o4b& ?i tq)/XMӅj5!JktJ瀏Ťcv.ҡp #`RVk4Z6t|,>wҨ5;}'Pjϊ(q5P,n{s'+wLZá5k6^(}}h1'}Ibqҡ5#6wh~ԛeb̓%IJ ޜO/!2S:UwxwZ䰯F]5*-! T"2e< 8Jm8cI+:]SiVi\&_B#.uhB8aߢΔ|{CO4C2:1'p3`i!t7jFj?_*ENtQLai(XFIDhB*Ў2p3`Jԋwl9dMK]`[4Z G8[t)V{`I(v+actF)LNi9CB# G-*'"#I'MlҡxoS7O=aE>q2-!FUta{pf7t=13eCr)+򹈻RZO8[]sg:$Quiwt^5J4gt("uvW4C6Yx\=EY)PqoinZ|Tx ]N8[IveVã+"03)VQ0jx<>uzgx}lrVQVsg"Bߗ:=.gpzH-Y: OƔ"ԕE"|P!iCታ]Tiye YElM% ?(/^87t:P$ N(hz؊|.ʂ$:=>luV'7rZ,S$fU<¿ӏVe%rq?uz\$ ??^s)OM*n}Ԋ|r8+)VN[,VPx!|7!91+kK z<:ml;SBҜCs:=.?j# }2&?r]6u"8Q_b(ӖV+PZtyӝZE~B:>8;)өBNQ8V3P;V,u?-P=@:Ot;>cE>HucՓ@N+zcrNi]Vs1NV VP<i5t:\wԱקiKgƊ\M.iwg'tj;E~?)&2jZ{[wg'2NQ8]դC"ZYXܳ Tf&Q)*ҡMQ>[_4uS* b%WP\FL IUaQLKg|JٺY]yE%њ <VN:Ww.N+ %3KɮQ*t(.{ʄƙy$y%+F;i^Tl`oˣu N[)P\Iwaup@W7tgjk/Xe%~VB:"QbB;SNIM[Ϝ+mϿsvW^9/<ԙ[-^[g-6>Nŵ88<&fT4vΘ78aO ?ɓ'ON#۵uê z-NS-[tP\/BGܒi~czۑcrm ۽cˆUK̞V[3SPYt!P\JW\q>/oYW;ppޱuڡ fv4Tf%#Cev:t(.e++:rc_+nؼuΛv%vܱmu/TU(ЃNiyCq%794>&!!hm/Zv͛oM֯]=lp꒼Mn:=>N;?٧Pff;C҃`e-]=s/\t+WCpU/\40*mW+$iK!+ёLG-UuQi+il6cy,\x ,^h93zۛk+2uZ٤Cq!/Fb8:4ehOcRZNAIEmcs{Ԟ3f2xӺ;ZkJ sӓz$(=,v:t(.d.xC *(!!5#C:;[[+J ! *MLҡ_sJ;ѿ Er&<26>)53;#j*K rҒ Q:FM[a ͹ce#TN+((*.)1OtR⢂쌴CtDVݴ%cHBR:R|yK}0Rh# )YY99ܒgЅUrݴe^N(ݬzj\ֆ룢c I)ԴKNJL7bB,Jn"N 3H@X"U@t%Fׅi*L:4-Gt2P7JC$_4Kd 6,LE@"MӅj5!JktUN'{GW(du3MFjHk*DhZm(h5:DTʡ?7U*N'{ÏU!)R8 7ꪑՁA"X"rB52TFF4U*Nsvi}8T ^aDt@MVBĐ`C"Q0 C;i;O:ahZxWuX~؁BHWaFi#Pg켣qRpph͚h{x 7t(ss8dkFlN1ԛũ$L>^mK:kJۇ]UY}]#`vN}IѹӍ81v|<_Ό#^΋OĭM:u+;*$l'I?ݎvŎEzдg*w+]E$ lo3e8DQQtPIaۛ_u]D.vZG:9*XG|F^bI=w1v\>9sޠ8v:t(8w *uIƿӡC`,Xq7XX!Ä׍c'E?LR&p[jI2N|/mb#_Ihx7t(ׂ|6p{71 \t21Mf+4`S!p q\vBqc>ME9gQ>tǽt˽cbqk.wPHnK7le6SC*HPer^/ʛb?C7ήKS[:= ҡ`زld0H,4ްgṟ}K&X, BQ>t i;.IFRە`QP@t(&LJFkN\rLKrXtTjnW)PXV`"y24]t(,f2e؋|PeJ&5KM<*eLYȕ{T7"Trf&\:a'nQ1P5a/-Wi4!δd D:_ 1F/6D. TPKܠBv6a\ n*F@n@ҡ Jm| ڨ׸={+jC" w1 )R=op{r9C D<8|ӏt(^iBDEťiE>q"->Fa>+{,wZyً{8ן𶩩}/ XMG2Oc$Ã?j|R5lSMpZjzQwi3鼴=Q3Z䁛p"UHf7 mUO.NBM,N(+٠UI:^G8@hIP)`l+9pZ(Eƥf_ie=x< `=F?uzp:11:53'w> 3 esrq<8l8x`SF]TN?P] Z%s5:psy/T*rIa4A ԇ33f )Ap8aL.}ԗB⍛5/< :lz99-"CQI"uCU\s`_:EƇw]LGL|ps^l zbX0Os:@=)bbFAU i.dNnoGd8 tyo3{yO()bVQM;hӞ?nosdLrϘ\~ky>XxXFkх]̣N{&9ρ1}/Ϡ=ngvU^5j/@N+4zCrNImc$+N1DP=@ܜ_>fD{ 33vhS.ONGSrJ8Q_ *7槌M}ZE|i29]VyGMDNӞLn/O64//13悁i:Zbr:ҘJ.tuړ&qILթӔ#PN#)POͅ:Hqs^ vZ:}`5iEҡx~sQh䜒=;}Q=9nZoH*m 0i-E7Pko㞋7ǤC29-Sb[Oo)bS=%nϏHI,jNo.Jy4*ܞŋuZ$ NL/h:~~Œpt4 PBp~@:/sM*4 չ4v|O1kjcy~Z|TJJX4E#ScjƔҺ7&궁:4BdnѺqD?CbF5GQUk%kvd op^o[uqV2 R=Pܬ&i.t]3,[{oȕ>nYS* 2b™Kyi% 7HeT,SEťԵMdh=w/+gx6s/>{xƕfחESD:g'PSu|V6u\a}÷'OpA9uԉ;;|p߮W/]0sjsuzSD?:NK:/v^a>rKk[Z0r{:|ȱcsɱG:έV/[8F"Ѵ]pc1`_# IQƤ꺆斶ήT_SUV*V ݴ3:AI @_@Z\Z^YSSW1Uey) 8P+h;:aF:QORӠyE%%%eeQ^^^VZR\\ JȃvL)9--#++''' yy9ٙ)I ƘH]F%GJ#K"vϤC11*uL5'&%qH*$9)1!Ӫ2 x@ÓINt(fR aWht111[ܭ1QPv"Ii璌#PpL/]DPha:>"""2+"!z.< DFҞN vCcKd2RBB9FՄ(r)2ZKtRӯeVjAbD"rBTqR#PQMv QZUgPKkN/!8YQk(ǩ􃤃P_! 7[T] #IMCP JĐBq('Q\٤PJD:. Yu.aQ(NxNBqQ5AQ( k7BҗHDLuqBWuz*(k?(1B ]t(rUJ'2aJrzp( #xk*ICLc~t0 Čqt0 +)cP`vzP(N|mv:t( 7> stream xYPT͓6/s9ADJΙ% "(Q(((J b@PP~UM'tOO[V<#"B`ZBâ)&N.I ;*Bu@;#Y-t>Q@E `}J4 >`=3R"xjƫ;Ơ <' BG ҇`mOJ|^"?[^~a`TDg8H ٽf.x#-'RF%üv[~cc!h򋈶COI 0ؽ3F%LَnA0rPOT^';k~Ʀ0}`\7= A1)` _)HO_)['$W?Z-VB룵h5fF)"ZAk }j*_Z5m- OPww;џBc@ @h^=JyKKgYg_b~-\s{ZkJMyNxPbv "A, p .C_D7gЫ#Qǘb08LsӄÌc1_X,3V݅ua(vp8-]up </7ƻ%|~ $+!P@8Gh'<$6tDўDL#STTTTjT6TTTT TfQSSP漏Χ~FD" tI.hR>tAf KM>rr3y@#DGFHSBs! -Vր֓6 ](aKtt8zaz#z js (o "AyWWʙ:Q̦!̍YXX|YrXrֳ~ge3b f+dka{fgac?Ǿȡ͑1 ssr&qVsqqqspEp͵̭}{G'O72/oo)U>N]|1|g6E XL" +.,"(|HExQUT$QNdJ$#)Z%X +*,vJlDW/(K(KJHIIVI>ғfNn~/#("S(sW槬l9rrfrrr+(*|TPUt.חէ771D1*3zioo\gjddҳ |W'\ަf*fSۙZ[P,-aK3b˩BvX+Sb"֑7m666ollm1ع]jo_`|螘=4{j d; :;:\\.w߫7k>}B:i=ݯ{`<=.ylyZyVyyzUxzx~sgW˷wO˯o_˿)@'$`% ,cЮʠ`ǐP|Gh[}Xp؝pH㑫sʅ((j_Tk4#ňdjǖn9]JOIXH4Nv_~ˠ`PMUjvzd{&>dg!>NNn>OL徠}Qe+Wӝ33Cv޾z5dgvQ~cxiduym͕wt*ދAЪGO?}wzЯl~fn؏?C#<)BRa??> 3;@S)($D fH0#vGÓ(Sm 1&K% 8 bUu~~6ACjCEEDGnQ^FDWdřK$KgL%<љ![3'":o1_ $h..*Wp?sYtTù/^٨dQ|zkxlM=fmTUBíۅwJJ f;8p#CJ?MSOܟ?$L{>:Wӆ3b޼xskbR+}X]]8/k_e66ֿM}٬p{?#aC6c&SsK1k%[{+G'g'Ww7OM&:SyB1{EtEŀs}ypy<ϛ{ҧ^Q @%6X.x%&+3IxqH|-JbBJX؇qu7x%o–25XZBΙYb3sJr/5?2?_UPLz Re^N\9xCPu¹ "5)'.Ie\~~U>eZN+.kO=+#wǮ=hxzk JvuBr{kM[;mi`8?Yl\@2#$_g'drD,B2"Cr(:u@ϡ-$Ӂ,@PGQmY4Z ddz& s3%bF N珫-1npTd01jU3$Rn:mv|^b!{iam}_i`b@!*Hr2d 7P($gwFe^IW F Skq"$^O !~18OeFN-A]Ib"&c4&EMG;AO_Ϡ0ʄebcebb`Kce(Ņ>cK;W%`,-!4!"rFXxDdT&{r/ԕUU;>hikk?ѯ742234Ř{YdY^}jzml/G1ʩ˰}nZ~]^}| ~) ##=(Q7ciT=[؟ژ|P c_fYlyH-)/%)8~Zjs\.kܯ^(s}%MSG{WzE/flC#{΍&>~<)FB@1IYSj{Wv:Ǻ*p8G,,4d),!|+22ms=.8I=l ՁԅtCYي9yZ *9vRBTs%UΉwRe L"o"ϻVY{nJ>~g?uCp]~<.0$g'o}JbZiF}V{NE%eK+m+_p~#c'ϴ[]kU_ήhÛ"[n[?r{0Tp{{j{G5lL_o -7K endstream endobj 329 0 obj 5933 endobj 159 0 obj <> stream xmlE?pg ­x7 x}`aB';`yi3\0ߙI~qX2_VI#q#$KO~a2/Oyyꮮ_ULwMwuoqk >#?(ӟ{WTx ԍ:tKtj4F>:)=jtB:a\@'Ns:s0tx =@'@j-mUo Db:o,D\ J+VA}nK6nEl>u Ҩo>X ը^@0E]`)`Տlv||:3::zܹ 7z| CZqu7ܼyرc? sVǏOSm۷o_r(9`/N{Z <:::۷z){]b7nP7 >cv1ۇ@ {ގ9rN,X{twwS7:4bP}.`#R7:^TAXD*99˅Tצ!''O%߶:QF'&&G/u*-3 B7O,-95[H}m %>zvE{BsdK'A{m.g'XM^&̒{Bc ȖK}${=67VK15X=RqW(>ND9 ٫dhQXX7tm-6UncMgmbP}.lY Q|c=ϣl\InsluB |u\(Gt>b邧{xp(2ѵsPUc ȖBꌠ{'s uDҔ?+mXUAsd uvGʄm}Ƶ;o,9bU ~L,4OWbpB Ȓ-l6;>>~=w܁|\^LezGLrz,ŬF,ƚBddɖ?7nX[fo͛ǎC9_K{Z/ťB}}uJ=@!̱)?STW\A9_E6Y{( EaǗ_~Idw{ºTсn߾SO$WR'9:]&{ xNعquz?fs߾}(c!$Gl'`+dH=@ 8y/s1T#Gd뾣GR'9:N>-{ B x$UtwwS7:4J{NV,S_uggŧN5 \#2'R7:^Ҟ P: ~m:`.F U挏;r>751-͕VZ󅒆֖T}[K/Ж*U[ /8t萏+Op0{uMA*sm\+L4X:11Wck=?U~-zD>]^zgl-d6jK~RAOnɓ}ى'|_v䃹0-s hy眙\-k~}l w $9s֭[_ob K^Ȗ9Jb4C+[$?RaZX`J˻\[)ʯofʿ1'|^}@{Ç_p_C)v~ډ'ۃ_jr=rueuGi9\hϖ:63w&31G˫ɽHFg CO֓v^{,/Lڪt, @#:=쿪_~{Qu@̅ 2GIQމE=Eذ'jQ{yfY3(?x*bGzPg0؂Ŏأls8;=MԌhK bآ_+7"k+baq!77=\V2OӑuNa[BQ{L0I֝-9-\{-򞞺Geno[̲cQJbd/r>`&a!oz^xԩS% LuM ْGEGmR2VvU;ec k5j{A{ YB٫Cxyaw3(GGtlɣdҔ投㶇|, =6Ks;MLWj(V&5=*{d++v.C٫ߟNY0088|GIyN<C x![kYs.ŪX.W ۳J=\76K ƌnGÏtU>XeM4o{TJw}}h;cp,y.llj,j/jM?G_-$fx-U^n,,]SřvD1O\#ޏer˥|`["%{A{y ?Xԏ=;]wݥAP{'[(cZ/ %\]Y.2e[­ |Zيns}uyyyuMA bZ$g}>S3G}`ߧN A k}أ.kDggS:ٳg ˢ`k ^Ȗ?=BшeԱcXfu3:G50-^Jvd/Rf/2uB` >̱NNrt\rU@#WR]kѣGOF-BX*r`>N GYT,;;;Q4#6rIimG}>}.h``:Qo.Dž'*9ZQs{1??O@0r /N8%y{kD[}a xtOnɓqDeo=<|SG.>;qj<^e|_5}.u 3gܺuK?7"E%UrV r٣FAa[BIiv .o1Xwĉ:Di$ɤiTxN !xmHx/Pk[)C@cw}:`4?>~=>H$0b rx'MxA]o}/>>;00>F@Yo^uDʩ湀i ?OYA=44G?86a!,(<#IP{ F|!#={VaCSL7<<,Zxl]xN O;C@0u_*bO~Gl>c b~gac515kTy%sb1vd2iSb4b4 =b Pר> >uT㰐ҥKP>:ioo/uBf<@ Xʽeff:`z?/~ >:!P.`5sUi?0mdPW_e<:&bU4{`)8Q׫^z%>Pz!{2ePgЇ/27N 4>z:`Up !l->6NjKQ:wVv{ou,ԵX6뮻|ZY8우ј|)b\@uՙ3g,gJC)?o8_{t,2r=uQWu_|0L&/\}ƹ@,2 ꢮi{Gy|}qcǎ>P"?{{?ԕm'Oder*Ny,)Ejd}S ZuhUnxGNEsYD{.ǟ'ޖF} 0;#[=7<,uZ{\@ um*ﳉxX䭷BjQQF}o %Ң sPWԺ_dRao<,rMJ(LWE}l"Z\:[{lקkU4244$9M7 zzz{gv^4lƗVA?DQB[C34w8am\ JڨM(ߐN yl:@?tB0ĄCC+D!/슟:- shLLXA,:AC7Gq`H7<<Uxa5ϽX### 0i?C8}.r!c-> 9xyk΢,%hNGwx`8sh C̻IRih@tᰮ)D5jĥ3,哭2 uZb|`'L&RCh2-z\M#nz_K]%ï!3m!Nc)Uo?jI- 8ǶQ~GWèfjb6xnh@RK%>}繸'W~/nhhw`K¢#^.ԛ>ϥn4UGК13Z2#J}AkSҭ1ϥi %ש}CC tEfjAԞP7^r"=u(P9hTա{:l6kzb}}}X3 5yY6dǗ_~Idk=siH~#CKC&5!JF.N#Ld6[^Z۷z)<I=B[7E`\R+y7nP7 >cv1?y.^>PRݏ@1<<̿E,~t9>=4jގ9rx. .)Z_$/Vx;-5B==="f注{twwS7:+\>NaRxSdd2iR3+MUVe`IWj==B‹h!Zx]*NoCŹlbGvtb6_ۤNVcׯ_{s+*Sz<2v#DO.R.[h$fVWT 8 lbZhޚ###UPE1q6nc}nK+6dX\pROG'8G (f+Mʟ 63)@D%f FL3~*|ۖ]c97yLcmc%Ik}.Bأn4jG3sӺ400#$D9]|)˅%b\\p.ƗD4=f߱2]Kz֜ýsAxpL&z~z'eu߰R;[֜sx W{Mfd{챵:YY;}lX͕bm%\0`ׂK3iOMFcH^|buzqaZ蒘KLB7TEu1 "{0nMe؂~YNZHRan0vlP a}T͌=bn4V̢qK s+igd*E\^ 6A-D46VJB!X(!KsNlN.mwP|}mgt+lLkU} =>PB67M¾U===A%DN٧Bc ?1uB܄zCESC'rVhCz*uڵk=ٜcV<>ԩh.:88HI[e8xD m=}膆W\V7z lEoo/u zdsqv .>}=J8}}.!g $bu0#22\O\h:];;;ws,',>YMhDl^600@(xuusioof?yǯC=Ν;pGҝ摁e\gg'|Bv[}W'Ow}}.*ǏOSm۷o)%:Gh v./z$[ gho>ĉ/b]SIx|I@?Cɗ9s֭[_ob 1jR-ݾ}`hfHdWÇ/\믿??\~=P_'ۃ_j7=&InܸA(ܷo_&f|C ?_~^zYOP*a59\ʑ#G4<.zO>$~;<>~y 3M$鍎t:ԩh"Y)vw={{o8A^|Ei3P>IeT+ ]zUM&!t D Yt!ُGy$ȡN:Ŏ$zBv{Ieq\&ƲeӳFdb>/c v]f bppݦd2: Ù0ETx cˈ=%IXukx#$&VBt&skkcT,WecN9sT m*N+,h>q d2 =(b~߯ʷGtw(Iesl&{NvOF'&&G/u|HX)?|nx$Bs*C #`Ī ![|ܹsxg'Jf w=,%I ygZtͯ}4= $fgbtegW{GGZ^UYTcBu#flz=1T؉jM=*,`i7M0%|sػC4;? x1R[NЕ\,Të$E&oY=X\pec6-ǹ*bV d4$ @% n@*?QbXJ6x=6Wr]{>ԕ{G5+nnmm, -1ߩŝ6& =;L8cxxi KRu"PK64=BN.l\=63<1]3νT*5>b@ǜȱg*QXc>ů*"hLHd5gyܹs +&GmgLmxK`=6Q`egE!FY@dyGWӅA&*WIvgxE!2Ģ1 ~$ r6ɼ+Ψ{>Kf/=v'}esʴ!bxyأGJaw!2#[^xLI{p3G+؋"y|:;;Y VeVnbm1KOcM7Kc>bXՂ ^Kb<=+FW|cō:Bղftk|s c-v-O aډ'DsM2}NVH}.?^l,}+,GEqiq{̖QorUkfr˥ʈ\n6-Qn֐?NmYWKeEUA:b5zh=88(BPo"\,%n󋹲ťBm}uyB~ii)_(nD3˫k^'o)  9J;.uU=b|c8W_}BIso@a,ټs}CyR0Lf*SO:%xB}.W=26d2f6̙RXDL*}6[úfW^Nrt\vǜ. f~`W\1- YQ񥠖Q3m1y=###,NME0RuѣGO6*`_O(;Dg5!WcJ,{XJcbB3_ugg9hRQ2![ BmXObK=\*&qCJ3d2.% ͩ[YJڟȴ|}.KX>?d@_|šC =ErXLX` #=a,aFɤ!N,9{tvv~'iW_}uIW^ybxqǥR)/i+/Asٿ͛7o>ĉ//A@K |Wܙ3gnݺE%矿,f r9rGqh`AVKgT؃;| ^7LrH9qD{{{K֋YKIRQ*X"bq30RkCC:t^{.>xi,~%I PHsX0X.U& [|vX%%O1\`Yh0uuL*bO"RE $AFb)T}{e?.Rۂ?ᅬ \V[xBkT=ۋ/R'$\9t:b|122"YZ,J!=0d5}.ҐEBʼnAʫ8-Rncn&؋FUW^aOOeDu5+Gé7,-H45}'i#kZiN,uB%Ix*5Ug8NkK="ʢ!ꄄ]cElH5KTDPm {D u+ԩSɓ'L&ŬC-GCEjh.;4 N%FN=uoKSƎjbOOsHy.v[dۙLƴ0Soo/1+CCC"j` aԵqrIL:[<= GQQF}oC$JWĔȏ,|p{:"o>b8 gwp,NQ0 *8kڲpkP(2m s.-urth/@#íЄa5a]Kh }.{x[s gG[hP}.hiE쏨m\aihhs^^>TLmb= }.YUd:s^Z hN{f-{AE&iewN04On+]|FTS e{|.{{Z|Vآ=]-U~l0#7PD9N-:|'6mi0k.PsZax:GBp͑JNr^Z< c+*2Q V\_s3)1+Sg]|&:aw:JQ o u#kbXr.X@5,}9hHR!0 o׽ jBrД<çt:X;#G@ ; /i]7;Vb3€vr:-@f1 NZ{F!Ea!Wc+{sl!T*ec-Q$jFI-{Ц7~j{@l+Pܶ XFE3uBf]!lRtxd.4;^k552ЖFxLV!bfƨk _  \ lv=jͽb uBayHk~bjoFw,f֒by.[? \ T9:- Xd2C& E\ T 4o0iK- GˤP'J06 Ew 6atxi[ھ]P0`GԢNH}m2a?` kma13ʥ:W; 8{@xDCjb"}}}6N4G24mtl{%c>:`13W?RF0%F\ &P'G0Wx6gtsi괴"Q#E)rS2B]0ZNKyH;'P-b?R† D2ĘI|F &aD b/nG]|%oJ 0 6l ;҈.V"cA`m1L&#bwBDuB }.Uz= kB#=<~BGO90_˴ M@(|*.IzKawm^\mUQi2 tW:7ŹA*9*5m ԍ: Qv"o`pׇ:!&}**;m!]B@SQP%Dq6dS+5L΄YĜ̈́DRB{LA#vd2 ;4L6{F(Tb9/^͛ {4_T1s.Ju:; om5Α*[~dQ)v+\^E(lag]T*~dQ0ȳո{#r?6ٲ.rE%Rvm9JxUlU0Dݤ:TX@;1Suأ6}^ 9rKx-<"F44zpMv0g)hp]F1@f7xh>Ux/^d!G22$\}zUjyxn50(5SeOJ^ AKacyBKBwUԘ@q?݈`Ĵ-4v}.@%g1u7"ajQ@N_zFGGϝ;wa)Ls"Lr̽\4WEeW`E" MQX ^Ҏ7nQ'| )w1d]D>fUdK$d2J |gj;kKg[ d/?STW\AHCX0S@]BN7_ JI}G, ub{n/:G^Bw ?:Q&Yak7`;^z饐Dutt#۷o?SȫM3|yx+o?!q=}]FdUi~Zϟgˉ'BJYRƍ鍂?]}! EH}l?5%:#jooRU9ڔ>d2̱OQgbRת:ёNK RTrsyw5VQGBaBW^EF{LJ~H K*W 7VsĎl.?! yISK>* >a冷.nsifAZbK+zTY%sI* a2dc}nK+6dq{ b06zcFT9U* MI6GqV;86 ?eRb+`6R VQP(ʓm:cb%/{~*{챹Q3Šui؃+#{P." (eJO]<&'F&&''΃e)W'wߝei+GBʴ1 [6 KLqxǦ׽MA%^nomgZ-3|er'*?g7W&v5S| pA3)Lﴧ4Zc#:7bKּM+322h{=NWX( =4-aK%x=6 b_yTic5^ KbK~.sfcS}JeXn;;.Kr)?sSvvieTyy@pWF(b]2_уoxON`DЖK%x=VvmgòӚQ9hc0;⣳[{͙*v,Vms%WiX/J`<];Bß.;Kb hKx<; 9V&J}59iA'.hs8o|bnňluX sl#uQSTSh[oE^z汇9Tͅ10ԶXblr:_^ 'Jx9|ÙYb+agߊKP캹i (v=HKxbˤ17v$*VgJ, Jx9ӓbnbRF5;ImABZ4[͛7{h@Z/<4h4^s͵ɱlǧgiΔR/- Biڭk@iдբyp{h@[K.) *&܆{lM5krX[-,9+.hsfCKjtz[4ssA m /TbZl7vOviyaflblbzD.qJx9!gz4xXۢ{g> hKx٥+9]FYؙ 6Y'*JXo,?l/.dիW׮]COuJ}V,Quуć~CFKɥDh=mcԎy[)'myuPwVK37BB Q'9:\)ElR7hd2A_8![(oٖ[*{'s @D m[LVv\_wl07-&0-ֳS9G8T{2GNrt>}9SJoo.%sC W]b[bܘ&6q,y,;e"WgӀ{2LTV_wvv"gbF(4sіrpbb dKFy]*A#NBcur:FW z%&rES\{2K6xoԩ6BM#}}}z U}]h [„: ֖|.[XX;sv q>h Q{(ÅM>;qNjbXOuࠞDd={"!BXE앩r̙[nQ ;|o&ق\p/-`Q˹ 7kH,bsQE6b +SÇ/\믿aCYp;qD{{{Kܢ֓O>#l}6E{[=dVQP(26;yLI}ٳ'}RA>/{ldzzzOTZy{h#a%;9:XL&>sÇ.i!\pKk,ԐUH>b |:VQp(J@?o}륗^?_6=\ MOkHZo碇\VQh_δΩSXO~gSO=F¤ o&]>VQEVQ%__ܹs>>O1&ez`VQ'b(UȽױ;||W?^yGP,ݝfǕQ8p仯<{]dVQ&` dg=%q{Gm<26KtttܸqcmMPoa5cnj|s@6U* \VxY>{6",5c?Smɋ۷o.=Dd|gjW }A4w*z衇T 33 =$}L,ԙ%ׄ A!sgH$ܿo͝9ƍa13*'ͽ*~ui>PgW]ӧOs>+ef֖KPa]Sm$˛(? mٹI)d/|l6~3H03+-awUC6Mp?0uZơ!V:rocmVЕ͕{Pº>pEV qC5E}gm~k?e]6?X/̈vݴ' %8O6EƋìLNKCt>,lv3>X̅ZX.dJ=ha lT}}} :G؄^لjÏEoc5ٯfxQLL;C5tM,!$dY?Ru3=x_2] ~/c,ok/U)'V^O %kJE6Eࠒm q###<aNN}OGRUK{PB!a@#NVtb}Rdc-5\%y.=4r2"|F~ґmH1=Yϥ0?=111=%@6Ap9:OL&} = ́vʓ_L"4{8{XVDjbΥfِ kj,٬uQF0Id,bΌly]٪ os;O7ۋ}$ )ޫckj ٜi0L}|!{QfTj}XV,nlKc٨nhA|腙^5na=0Hv &$[1bQg 믿l=Q>&˛9@tWEoS:(BbĩC䉾?]*mᇏӀC`@bZ og0mس?Xzzz>أO> ;mQW_ĉ/;uBߵ 400*w3W7ߕ w̙[n(|M_"(srXg #=`>|… ڵkoÎ `wĉ/uH@srXg ]2̓!=&kC/ˡ!ԧ~:ȡxl6HUڢ$<{ Z@tZ̽ %xmx?s… w}`EuNQ}.-xΝ;'u  ~D4Ꜣ\8>5eM>j&9y]wݥ2~p%vd2MQ M<ɒN}Y5Y_#:>%v<{رcjk,,CCC{ڃG Cν{יQjg?:288dH+Pgh hXΌH98|khC;D"qwk8c(3{xAKh9iKs_ v 9$0 do;nr-"[jFϟ?wh8W4y4CHlOh-L={zg 9xԱ}x+lG Ǣwzzz+uf\L*l.?gt!bۺH]B5'tX*'V>1G.la< {Ĩ@kc/#:SUu>3Ղ$$0~Ғ!ikhd<H>`l(`2QlR'Z|588#_C/ףRToo!UbJ Z<#F`~kR'a%HhX[ L*3ɋ$1M4 [R?} ԩفpƒy..xk@H |URQ;R' }..BVL5aI* d:9A=\؅άZèd2)6Ɂqp>`̷=.FsIR"`nr"6E-;eᗾ]4MUaŌTr2X[TA H ;u" #!k@ Hg2@P8;Kax-;}.`) /ٜCI#L&E Z<@!DuO>nt '0b.B[Xψ i;he.sS#.d2JQ%)m6z;9W^ދ ? !a1I`,][[rp`{oj[2Wqx3Tm ǐ_7+vBsh:cDdXƹ0p(~7 * ?0 xP(N#whVrz}}}&9g%cZAښ=t,1>@^gh }.yǾs,>4]t@-̱tݡeUv'5 &@ Da~*i Y?ΩXL>t:],|.F*V=F\6r=9U{"1(at}  :& Dfps t94 F Uoo ѤUˡw:ԼGNXDQ>ʂ;ma\lkjDϤRO'=bHR:N HE u?=ކ܉:!O___?YT#֥3˹֢A),I⊡o5s {4`g=(N(@yQA{uc-N5т|p ˆ=&4"6CN(+SYUI =I;#ËG"hl5A{pr .JͨQv{Ɲ+uēU =vI+VDaأQP!S8i) %IgO6wV.D\O*q;([[AAT644VQ2M=4/r^$SY;= PYBZ̐5DgG#MF>q^XCn7=Rb I#qM6.t%ÙZaN(*m\=Y==7Q,S'cOqmCuhh$nKU2nps=›=U;"S1:EM`Iǩ.kpp"ϽEmQUXgp+b:c/|eohkL=Ј|j{^B`===^VULx1x@]WuZ :j|w./m| 0_>w^bddĜ-=_ydUUH'jQ5@whh8]|)LJ~H@i݆jyYU[t1nC#RT ʫH%^ +tUL:Sk\ڋ/*Ŋ= )@4XGQRUȑ-SupUz;nZbS-ѾTLN/~: 7oܿ4>ȵMpN5\E8'4ItlӖ |ՓO:;;#{lUBu.a"cI"EGSǣs&?J{u-bdbfhhraQ}>hU?NJ^gq-N+ӧO0}(mUkX =4mN2U׾j{~r a:#fhh(JGVUaV~D\ruU]~VQ^1׮]Mm\z52GNՈİ=UDNd:uAUxԆUC\CTqX-KY-؉ݱ7dmȒ_r7bJ]g sr{bhKZS/Ш=*Uk=S|[ؒ[T8rA&'(G:xԆ@½\ vxYUOԷ =$il6KQdoX) B^?( =o=r=l5h5:Q+SȗRwo᛿H}qQݸ0hQ?ۜ3Y%Nib5i/wWV{LWutM-8?^OT++a'$HLMuFH(Tª?~tڨ%J載uaP~+"{!;_-+WirX/vߓ(lO3cmFxw/HvߴDv{5&Gl!uFx>QbdO 1.{\@g˓ӧOS'D"Ѩ[tp]hhYԑ- d~hG|qOڴ/%A|gjc'R!Ξ=~n$I6SOU?x饗^|^xK.\8w\<q,uFO {𹧊|e92?!Am҉1!MBwy'M6>Ѐy=C_&R!bpNy!{vڛ\ l{{{www6;w/ɦ:MNJUsDa~zbbbf{PvPNuC̾}~phoo9򪽿|4@f7n57|scǎXx'z~g&Uu~%ō`J*/N)[H6co7*~uqJ+\kv}$5bEqRut֭ロ.ׅ>T>@G@o~ꩧ )[He6G2LFqϊr\\c5?[vibbnugP\v{ ta˳lީ՟۷䤭F7nܠNo|Ǽ&/[He6G0{ juK?G:VrFx1Tԉ!UB{H߃|qs[M*wwwS7:؏D)RQ'9: 6u>{gle٣Dͮ)Mf冷g+ P6[L\X^Zܴ[YaF_Zv޽;;ܵ}*{|nc$0bs?F7?QI덨 {}.s[M(,ݙD]\_7gttF={H?xܹ8xt~ڗ_Gyy&Yl$?qVuS Q'كy.s[MXL}&ьĔՔ>aiQ[o q?{xtmnk'?d2|bx%g]-n0Q݊ X|幩mk/Mo_,߈>>0^{n+řp*w7 m= vѕͫGTͺq=!{Xa{/L^@3ϟO$r0־|=JKţ?1-Vnثʟ5cW*Y5KQ? v *1eW6_iLje:odhQZItDn[־}}Q邨X!{f&)ٍ+|R/\ۥoP^*Z܈>>gL&Nzvm%٣ڠa:%ָ;}.kD#7K{Xc+>}?tAQ|= Rque9]̤SJf%6+@}F=続Q є:նS+tKed 'z術'OjcϞ=eQGI(҉%Ɔ~Y[AzFX؈|r}^{n+ʸrp:cX$1_&#_^&-׹"{Xa>H QJ:{.NMNR+5ʺ͖ǒX/#6WתonFy~;E=dhegBe.LdjRИ=J?m6sөTjjV8dꫯJD)Q3tJ#1+:TP P턍etO-oc>>/=da|LxICF8˕S{kj2SOT,J)>gMy?<:otrR+[-66)\`V=>"rɭ?@J+44ݱ n߳\}6=,[fqӧޑ<h\ntui24/UGK Z)2J8].j_s+:O}.s3vmeCos Tz;=,GЉ3yC\#{>#cccZػwtARkZ]gS4Wrr)0jzxR79o\4n?];F?\[[rZ8xtA:֮C_˼уy.p=22"]8s--zZtAT:=[_:̳ǵk׼)B /H9kk3૯zgOy 3No l/~i\[:R7xꩧKOl*r$__}rW\b=ggݻ?sGV-9g.a<]??|u$hmsݻյ-?:ccǎ_`o3݃y.p\s>LC_|Gioux:.?_zVs=<{i/vTٳرcΝ'|ԩSعsg_bImPo}6җ-dv_uy.WNxz^.>_B#^كw8#[ӧH >Y:% yt0H\<422e|;qɢ(' sHVIOs ??~\FGGOm.HxHs9/+=~K5gߝDpY<:=>SГx?V+qwd/Hʣ{#ҿZM>Ծ%}Z"г鲄YK;HhӣDotA!}~Z=\'}N>C'7OUFǎ.;_ӳG<.KIhϻo=._ݮzҿOZe4<<,]wH#HOIhϻϺ?ViK'1Sҧ?gC={'H .>;|m||\o.KhI`CO <%>G.HGO c?g &r_<j^ >/|͘ZKy}ͳpeZqN;=T5n+(BO2}$[o%]cJҿl栛g/)BOQb:ztA>eJPF7 eG>(#rV1tiS !BA\'rSO=%]'~0.H7t/ڼE}y dHI<'xtL\>΀ҿ xpͳT=|a&}lNIBK^x$xܾ}[x*ҿŐ>'X!!}+._L?IFC@v!}3o?&{esѧaKD"O._N^c!Z2X~ӣɉ w=qj;p(͛7@[Z0'P~h0kJ &yWqppP,@WHd-cp J"~)}.Em34F@W={H9ytY.bd']vEp)0k]THy^oQ9~ܹsC/d2yȑQ˘-]۱٭wuҥb(]`o?.^|E⇎>A حRϜ9CЃw1R{I9Ο?ك<.ȑ .t[;\&&&>g+{hե^[7<ꓽK5cLJ˙XN >ԒFSK.~p E`j-Ck l}&?n{re3+'R ["@KRD탱kK3>t,{nn:_(SWc l}zH5m KӕGVK9o$Hl*Wb)S[Qc&ъV6+/]X-{w+]fsbv>O\g3t&YXظh)s˅RGKF tbbej50b=#=e`9VWV.h&XF=D;{=  Faefk#ggJ9<>߿tЃ3\s6!}Xn722"]8s_V1g}..MV._v_cew|Pn /H9/]0wm˗.%6B'\L€˭׬Lv>АtO>qKFֽW._V.q/BbQа]˧~7/]B.e`+6^|YY  oݻ?sW_}o8^<=QẔՙ\Z]\,^uvWc]~]s8ڥLpe2# +AÇ?3 _|G}eNp_ڠ"=\A[XӁu^ 2Om6Fǟ}Y6: } g}./YWiܲ/eX,t޽{ey"@8uU5uchX9ygf_umx|Ϟ=ns' p4{֬ԋr~3-$kmybbWH,©y.Y} H_衇>m|llwLLN\@-Չۿղ??{o}[ǎtu#g pre]SՉǏkW^n<А'Nڵ˻Y'}'F ]O:u*?裞ӂ?bE5{ǵ=?~ܕI>GZb=1 sԁ^zIr?ѣ*k>Ak !@HVͽDjzH-35===e}.>u`Z+{?x7KfA ẖ 3?ϽXG:{EKz04[nI!VKe/]u3%]Ӛٷo޼OHE3 \ Nm.IDs>T;"e@鳠 =Р!]v5߆ЊtYtvt  t>W&}-aj-&dpJ 1ckv d LsoUSO__>AoOO-H[{e5]uÇ7ްLaj=(Ǎ֏7@@cttT. w0MN6Є:CCC:{zzz|xxX,LLL~XO \Z bC<[?@0o^r6A51C 4s ###Ee3}ipn#@7 {t[ntY9{: Hc THfs>yG ڠЗ%>ytY>66FnsA7WhB> z5>>9č1և*.gtnvUXRt\eUB__v~Fz݀rz}UQڛь,hJ}4Ą;m7 )+ e@1w~sƜVBZetCUsPm_50i dc tCq]o=l }.@w2ՔJՂ$\A1U#d$ 4>>>88(] Ͷ3/@ .eq+sl}Ȉ%юI]vt!.jFW &^7}5[p3{ yEmGD+ɓ'TfD0Ƹ[Y7qm1x5a1=mNvMMzanı=-@WꠐݸJytti1Fvk9DŽ\U5ЕUp][А"}`nA ;'}́ТC^ Hռo@?r<~zqH| h@jR ]Fqll7t}===/u)]˜OۓI׺>1pa-B#pKWI׷FtBż݃HڥbqΝJ$ϟf#Gq >tիbjq׮].]*o/"a=sA8kYܹ#]3gz@7вtA,<ݻ'];<P>Wl]vѡsɥgRVslVKz}.}YtYls(e"XPYw~f53Y)ht2SN5-n!{*g"XC+i#9չd% lhюLXYY[AT100wK uQRX6v]ZlnUKn4Cno~Ԇĺ.a[y=Zm,5_>-olaٍLlɴhpN=sAhtYݺϻam/JR.泋t:,,l܄"4Nm.CDT }.OحΞ=+]2>a n9s(['}/tw!{0 u&K: ݻw=e144$]0O|ҥO84tv/|J FGGĄtA\,{޽?.{P}Woo^@7zܸqC^Y yǮ_.]{y.4={q邸q%;|g}&!/裏.!EӛnϞ=ǎ;wŪ .LNN~\ -8p`Ν `}.s.;: h5b1+zW]~>_c*HcllL,pZ|_z'N_ǿ︸}H,@1Q:WGyg||\Ohԕ-=PzJ0ڵ_0R޽{]gHd"z#d {:wy}'?яܭjQGL>Q:\tvk~1e ̳!ʯWX֣OKG5RG,c\Jg l}.s N _`Կ}yVǢ <% ٲu,V/i% `8)HH*ړ>G3o`&L *ڐ>A0`%|z4D"}ҷ~[E-"Xp<m{I׷>5H$&&&KxRxNJZQ7qX%{8C;"5k=+]b3=quNst\Sbe4麷)8%nxP]\;#˙:kn9t9{۳/ ڸ[Hg 丗|1{4! L]{4҅mb`` IW!aP<{0"dv766fzo:#]y \ JP>>7U?^V.KwXX5dRaF2wAg[Ν; <s@0\|Yb=x҅ A߼ta ̳tQaӌI7<~_=Es [ܹs T.,g\6_-7}~%jiMAa=Eك>=.\Hˍ?=Ttsr>RPh/֗\T}.ۭ\{__y[՟쑛{?]OOgV{J.n e=.^h^+_[gtVH4)£쑛jdb=\_^Rۮ#=80-dk|nC~P7dCk Kv~˼Bb[kne_f(Tdzefceqw{QcJ(U6lmg%=YytOvQAwgVjur5{[w7[u_Dq-- [0Gn.i05O VѺY%-䶷l0{DNg+mUN@[)Tetc{XTrE4 sJH/o%*IWURA>%"",{oo|)%u챙-JFNc1njm?z?KlڂQWI4`cMC6@'.^h}=6#5ebeGt*_(nZ)W~Hj!{@]|ٕRlrnׇݺO&{kVH XIo o[!{@{sY7RlrBn'= SQܒ GQolfuk#kɭ|vd=/vVn'=suѳ>#:PrX]ckjŶUhׯ_w=^l[=koiz9}C4mf(W=bm](Y}dRui23:e= fggX6}[]>UzulX_[{[}K>,ZYZ13UI$9}VLjacRBevLrjͬ( dpyIxm_[=kn[󪄳zqi(Lum|rk9Xbfec |ud-_]#2O5{[em1+W8sx{q6yA_|dʬ拋EgzG 3&g -5@j؈mpmu62\SKIp͛fWݬŝ=/*{8V\---.-eբõIBX,UL.rb[宽‡){\Ndt!.}>(f;wt?${[>S=n766&]կ~E\zv뾗_~Y188Hܸq>@[iܹ#]0xO>I7z=AH&ҥ7ڗc|m1\AxK<޽{|^rPA~p]ՃN8웗.;uMPwt޽{GuKڵkJPs_?D0h뿞zNs<4۷odd߿E__ߣ>W-}ݺu׆PI|bKPHץAd_3B6H,ks 6H,k6(S }16@kTX%} 5*>S="]y."]uME^E{t6O{tՊ6OL&x`]ђ`ђ< cфIa>υ[5-ItMmO%\-*Ot x~@b]pcGHW]A @s%>t`҇ɼуzջ0\Jk Tb P@%s*1D PuMJ*1x=J{h*1͛zƭMz=^F߸qxoڳLFam[hS\t5 䙏#u~ xh GS~d#Nwكi4Qz'~fH,S/^t=xhyFcr7xܾ}[3ҟ C>e r1~\~]s+{p%x? W3\E/A ?0{ܺuKC d)]qǕ+WFҭ[`)pn^:1C ._L*j.,< }0t.Xi`Y+n~:d={e2h;C T̳͛7 †FR /_nyq;Mt@h5NmDK֭[2Ԯ~5ӻ] {>yPQve endstream endobj 330 0 obj 41607 endobj 142 0 obj <> endobj 331 0 obj <> endobj 332 0 obj <> stream x|y|TE{M/5Kw;MHH0}IH4$lYaEA3,2*# ! 62wmPD8AQIN0ys֭:=NSFjD7kaC˸/FBIaVGsnI<~N܅_FmDHes-;Bz% 5fլR8GPMOey|:^<qku /7!T ;5,[\VҼ\oioJJNIMK/( Z4lxXRwa!={[P Sb; CKfO#e_4H: G^@w br>18$!odG].}N>=kA-KE&T[ZOFhfGV4-muGa=`}bć6no ʭtje1h% v鞾}آd4 .@Z3h헡*̃K;P$\Qa2Nzg?PTcZdDGѫz(i8W}MPu*>,5EFH^s,JFCQj`-AwG[~'<:X3px>^»//;#TMmQa*1cbcpgv.Kmr1AI( Inv]{ԍa:>A_ h8\8qxz?LcZL'yfSil =ľp]A^s'GKu-pA#Zt1 &Lۉ}AG=DC+pvUh+5pIބx;tDGmVi4uZZT<24Qj{d+IpWVsw4 *rBt9jkPs?C5ŁX,BEirT}#2I5@\pXeȁ2-FHD*pѰ Qewwe5:av׸5eQ.WmZj1= K"R·PuB DGճݳ7D4P k.O鲸˺,+>^?t l ֓jԆy.'%] ws^=`tE{ M鶉6$-.pZIZ ɇwׄ>Up'(`9Iu_:gB5be3UQ ]'hh, 37[a1ԗBNH% .^="$ ~Ctgu7uApeiZ@q51~6 ð3n)Dʠ;8IMdPHhg$ gsNHg#/pYMXФWX5@kk@;FnZna4JU0q5kVEue:hq5]@NP+sSW5Y#ZPdMIs:X4FCQ.XE$ee]z/S ~Oq p?u @ $ ´[>蜌2ǃQ $!]!= qR2Ҡ}M+(#,BIOZcFS/X{}Lp\6#9^Ssp'+k'KRo 2Aj!ExvGc;{m kHŅ:4]zW5)*V^gGZ!mv&q,yv/0[Mb},'Z:Nu^ݥfWNKWNKuƼ#)FUttS})%/G.^l#1G7h&Ɔ9͵o t\[^4mc(&6B)؝.ul4CkLigEحsj&.i7.守8ݕŇ=2ZQk?'.]ٌ)".xا/3(VaE/6lױ㮇~wW48A;WM3~tY5$:CƝ:)xk `A,Jǫ~hVWSjuQe1U]$}YѬݺL̮әd2YJ/C낾aV)Q:܊#-l7?\BF[0dɀlSn7Dn3j3(*rotfw¾ˊy|ti3NRW_02'k "G H_>; v'R=(kՕJ̓sj֡5 ~óffF hBĂJj{g ѢVkxVMPCo~*cT "3 >^¬ҽaRKc&c wIf\( [z;LςL 'M4k#"v F{ܨ-E-hFqkBBng\K7B Lpw_wXb,A%i[Rx}y͍rF9#\niڃX-IR_":mkv}')EkץmY& 5J6jfttT aJ+) Z^:)1VTkSogLQuqqTKMquŝ&KH _:Bu3]LAB`=>O&ס:d>F&jJKTVI}nZmw4XxQCQu:yMkm_o"NZ ߋ\ W֥x*Fhhnt`V+$$8SHX-eVR8Įge)Ukbܙnqw7Ϊȼ[잎|S&7g| p|,rQyۚglnooT|U4?3.m2uƌS𐎎͋7}%{?hEExA*gS[0L{Ed4M̏ulbr-RV/*5ZN۬EgFS7E?}:h.:"e3/˃%:i@9NY)2U\d.pyo4 Ú3jOHFu!xS-']s;i!~8nǔ'_r)nmw.>VN78lMl"Tq-qad7c* w#K~6ġYb.g`Yh3` Eccp }Ual5BtmZ[ >̏rL'Xzla@6z; }K,P >k]=Sr3P"Cv$b3NI" w7.SSR*RS,Kِ*(&$X(ܢTj'5,-FҦ/it]6y*[/U k{ī̱.D-QP Z"I[+*!IRaPLe3x:g?#DHQexÉMP P4mיhe2^HBͷ8)H%ǂ>¥p\DKbge+~J1+\@&*ɂaX1*װ|\|@ϜWG%Һ4⏭ItdT\%Ԟ~qyn[nBzBRk3a` }gؕ(9P4U7}+UU3Y7OGv3/(_a^U>z>G*mAӆa.X(9]\g#Nbdd3\mrQ3xdlƤ'?&g8pVt!j3CW6t˯ǫ|mJo<ƸR#bR/UV2ѝLa+jGkd"+m8dy5aJK>KO· &X.,S2譏Wv<.uV2{xo؜PtCk+l$TU |/B $4b ᕎǽW\:9*ڇ{L`Ǡ'3NFB:]E R0g];S0Z\.=&}}(0yB{ ŁOvX'D%|*ki Ca`J (K, @ P;*=/y}i֩+[zX2 j5,bA( K)`z1<%hl3+Gu㣏btV><_e؆'ۂHI~"ДRI<y}wJD04RJX!k(U<5\Y}*.Qι.PvE8[s{[IW0l-C^AT"M6B <((xXN K1J_(% @!m("B嫉R5a [cg:H .ykĠإ];qwQ+vkbу;n`/EIbV<Lq\C,8:{; ,-qĤ1q`fHB^!E' 8l"B|Dw=2%}a5 ?Ky$Z ^#)Qr[ƾ E5(|2xJJ +l* $ϐ'Y[ꄼm2gC:| x \\c؟3k_0+8xDf-fbgْh *PDS({P`Ğw]+r=\J^ 9s X0}̙^8{ m7.Eڟ~w?$}g}ߏ7oJi5 Nz$ #D[R _n5Z[)cJE d@\,㖵61g/9.YҏKJELi̼RW _~^Z%Ę5be5^c8>1(918#g ,QSuTOp?svD(Tޥ[4'lYL)8?>sfpy+Lԩ>-^:.CO5{e6Y~/*>+vxɆo ${βZЋt Ol%aگi,MK2%CLæ7LLo^6^6dSZUqVGEӪk)wK2"i$Ea}8Co+r+qy7߬Lw C-o&rl6(hS@,/Y?pL2j`u  uh`r} BHQX$NGWiq{ HoAV%w/ȭWޫbl*TmbSb/ľ:^d{ *4{^EV`4 $2\xUBA"0)s)A X+hL=6lS(l!(B(T't'\ˉm( ["VBvn$. +dWxxc- ySD}M#/:1cȇűCxfޏ [a))wL (U\9uOVRUCը:}H^{:*Mγ -* 3w~k<_!)%<8s6p` L|X f3ˮ-}XH}U)N2zظauɱJGQъ6nh Z=7|d-AoRuQ% Za/_M/K[ 5ɮ!bZӏ>-˄ ٭9Qp5y J*ZP:4^5nLxr!=Cv&b*!`w͙u|8:ziX߶G~'3Mz{Iw ^PMW-/ⷢ, r(xXͼLƣL5F2rC5`8&mkZZG8P~%-6sr Clĺȴ?(e-%RTaǴNpe7EG?{~0|{ V):2,w,~ۏŸ J) |wc+,t0b%5b(,)co׺E U01g( %x#J2F q q H`5U 09Z(ܥWX56dE6 ԣ9a{u_E^ dJ1ޔc"y9P٩ ֔#G :}/tYzCt#+ pCx2/-R(ֻutGbsaw*R?z}nhꌪ-eߔ Fx: =uAu4KH9΃sk/~R%~NLjЄA @ӡ e6C cBP9~+k?'}ciH!9&'l ' e]nB }#vH]38|2}Px@2^8P ˠ3D6+ t%WGr&nBo柦cr{Cty~WqSVP òJ$ϱJIoyQ %CsJ^g`LbT6fkܧ:Y#"Hv,>T2n2@N'ֺ%wc+5>itCK3+ Vk3/ӕA^lcٯ%"ƱjTZQ`{( Ey`C wB m? 0AZZBImZx[NtG wQ5*y` nho*߮?v%x}](.Nl9~!e2J$gϗSRҹȄ9iHOӊd L S^ĵ; ',`M,O8zfRjCCرiF|lG,W'lFX%؄qQ58lq ,BZFia-ݦ'A7X77@wz}akrӱx39KrC`KY5뚘O-S',Il_~ˊD zzmX#hhcUj|.m6{wщ=?[O#ۄ޻jպutKs8đpd׻wڿ׮93x7_iS_R"`JlԀV"&Y2NySz*VX5:{rXW {IN`.@\ٓn_|x KW`mac hȞ؉` "c˄]&W+w"1v'Sc64os;fD}&{sU^=UݡI撤$#\~3}m|қh7^jf1!=%rAK̳B B i:$)p_kul/zO+|o$3VB^y1Я RH P~7WA*cp4|*ЯL ""Y0R L-N BO7 RDH ljBTE@AO'C"BpOd;B&ꙡB xڳ_A(C BKA .yx=~+B p %B>^2K>R! dre em "/ =ZNԸ"YDžicUi40"9<ʦ~ (⃬a#(LSP'F}aA&&L(QaLSryOAw"da42*fP0ͣ!Jf0ͣ|y\O%ieI_L@]&B?ZɆyW>2I,X:F34@-2='Y}2Mu*<)G eH\GɴB.i)GdZ-eZCe:|L6@dKh\L~ɴQH@Mr2ML[ۍN|/ݰH/Q7tXe!iLϗ8yt\L:2-EaJepLxj,eL+Ǟvf|iٙΒ~-KmQf;,E[Β g_s)ؼ`I{S Y fR w6@m-F#AP=\foo2v""X{Ƀh υkMPpr>.˿Jl4H96cf Tr=m֦FUp 'm4)i6h&5A;-sz=}>A|g}}ZG??_@[ATFngBRUlE…upݡάY̬\?hkX|l\JAvC'csۚhhkm=ʆsߴc=z_ww\@aڍiZlpBMAUm ; w;,;Rs-͋аߴ~h}sjC ӬF">~f565lkhovnW}9\6ذh~SGâ^nےm90%d/^w;/|t޴u/覹 K,l&C Yp&4>a<ؒХ͋eqdLs`3ZO|ϒ)7DE E] }W/tX.]8]Tkb֚"Ǭ5k*J @#eݞg gg9z3F,ucRIw;rU%r bPyP#Pqht8=1~%dO"A͡lQ(= k]JP@_ JZH!MIb*Os>O]|,G A'hB'B|HNG22QFC~ psG0\Yvwu0cXӵ7+}1)&,?0a)6v4ZVt:_^IZu]v9OrS hJSDYq+׆*oX9i5nM.!ǑƐƐƉRRʛ&o endstream endobj 333 0 obj 13793 endobj 143 0 obj <> endobj 334 0 obj <> endobj 335 0 obj <> stream x{y|yֻ[dHHH א BBȅ"P@D `[AMQDb]*Vؚ} !{33ggwΜsf\ `ooګƒ7a~{=̒- /;~MP.Y^ hj7y @~QЈ$ }Onln[_o`,_^l~=0%ǰNk_">]y7SN`~nYmK-іZ4iF@x??dM8^AJPk@5-` ?dGxO!NIMK|cB1̓r'Ako1vC0 ;Y- 7d̰M28xSؾ ^mpC3v+ |y~ HBB<3f7`c.0@:4,]s#x~k0H/#=_cDRqԹ ͋mzx_pe`*8?Y<.\pNOkDuq\2Sɍdi"W*ZΤh3&Ie&1s.μ\b.kdl;.a=[\7:f>w{_%2a )ٟ_ XRO<؎8N yl`sSEQ^u->@IA=r4[.n!hIIM dqj1NV)s,C W+zs٠„ )ǂsXTymn\ږlZF-#-[% W~o3{~"?i >>୰5{\oEwe{cgrpPfK#*n_цԢ/:&PQ=mzMEyWeX4Ho{ {"0oDRvӹR_nۺj UeDe7 TG;+{&ijs\UbtCmM70Ą8QT4w[/7v.ŒGQ/i5=]dQθ!)-+^1ǘVH#'" ~dP9᧖4e ts3Xgn!anY-۩`{%?~zXV .# g7J^1*F`^Fԝ[=ł>HKŴl#um.sۭX.ZS9t,H!Ď+%Yvz;'6tz+(Ll@N"YάA&1R8LFkk`?YR?Og-hEr6NiL(O쎔*V} [ s&ϹsN*y^fbEmgg 6)4siLLLg%| `VKivNާa(c]w}KA:M: h!#bV *uVClў0?jK8djES(nN`tA`ȟg6¾ gm?9#UP g~y{1n&tQBCY46SȚ}f䫘8,?ۅ2J# > =::}̙8Y'o(53GQ՛<&v;bh*m'{V=&<< fb)E*95qދ oq=|{Oc"#y5 jV΁J!M{EPZzWm82:OŮcW=,eB'us?$ZVŮ5d#S9$֩%y|#%}? -˒;=IU8u_Ғ~(`-"A ʠ $ F ьӑ!h $.$Hr f' P&m;GؾpU=Ĕ$>Y]y F{901,Οx݃[7i;ՓϮN.șhKʏ9p<♨M2ee=H4-ͤacA1u?hr9!?Gc*Iea2IɄh^UT0A8_'#a#CRm IA0p8080apea%"fD0JdDHK,({qx!MrG8J"(~b9:\yh/qh~պ cX6{ҥ ePMQ8_:xMI6fӝly71s)l>#? Q]g,CbPrYCuunC#OfLk:A b]ё]7njBD0ZF_o~yMjܗYŠp*;-TQi&iny\՜0TA41*T#,ӊg* yiʨ p"7\1Tv`,g*pe,y \Ǐz5,E$:qD"`$Υqak679v: J/_DZ'mS9@JɅ}0Pzƪ5Y6ye0 &%$w c% 0cĈ8p5NRGeT y^,`> -d#:q;_ X)ƻb'9CswoFl+r@&67~A±Ow!{}-?ɶ<7R&xA@3Ƒ좢jmܐ 2e:5c4~Xߙڜ3r< "ʼnc<(?$FncVmgrh.G*rvqߢ꾚quqK8ր1 $UE.hL\b''8`r ,s!sQ%a$@|cy-P U y(ԡn2JDχ/+ƺ_u<`?K*̝9uO؉X,gj㣻E%oI}(aj$Ypq ѭTjVSh¡e5>:۶yȥ(xNGDZ%(qE?HuA&{KRw7V/¡/>((bP q/&R+Y%wSv:Ai2)TjlN@FICJm`xь[è5K^4"9Ţ"$+3VШȾ^JJܔ5x uIkrOAr|GSh1;!OQ6Vw"6{;z)Ȟf<3?/dn28s+=bM Q+ *RC9ěJx^yQ(qUuQjT]~'Mvx]IDž'ZTĢ۸4Rg#z\{~z 1v7ٟ^,zU2!x(b4pM\i'ZlbD⌔}\rJcp{LN3s[LlАpB(U4L'`ar)b0R)-9)<.:@%%:l0MF-P3\\rP8[q:~oM)&d֗?IDL~:6 !5%! ɊŢMk Zmv_ԎIJNR2v)++9İcTIpvNaG',{NcECZ5UEl#zd_Qźf{@AxVa! 22KӈID-m$MEHF*J Fd67^e9Z^QɒP"Q&-M-=Փ8[3$!{gw)~ۦo)̺x=*/7ˡbtCzΖ{ƪ$}C -ꨈn(+J.Q&x"+6U9%I92v}wNףp`<)yP !O ]6rXð2<cEQUy(o"vd6e2'ZBlܫ4TNTj-_ުypOQYmV+V6YTrf;E,Sn7*_'*ujШLf6ۙm.3tSa*AlW Wj,t*Ke8^*F*.vܭk1Ucf?ҫP*DtwE 1,/(DRʔeԪt KCNluW3W$hs;4%ܡB! D1956M&։ -G`T<#~1ɿ%LӱbO:pInfK뫗Vyu7 P %Haj6Q&:CytME:H4LbpԮ4R| :$tFVG2Uԕ*JJ&!%uoc\bsRB>vdnd;\V 6IDRE++phs{$Nk_>p>DAڰ:`&jb,n>Ϛ#& mP0$%O Fum}rfqf]k-)rրڭOM֥Zvїvt5'}N^qf-$Kt[-3'|m ;v8f/G&,zaӶdȼNbd=m';m{}6fmbrz.BbU2<.ejwp׺\2z(tj2Z.C'*&~3F fuf[ĽfA> y'.]N@].ybxN`]{{;A>%2+aWGv*l3\@4DK0*˪2QvglΝ0O_KT( 4D1H䃙,1g3-|iZ оzuY93{sO>`/~On7~/Qjfܶ5$㛿ٸ& aߜ !>xpZZCQGLbT^dNט?T_uR@o9_r.+.* p><, 'gW6 qPrۃw}{sMw@ݚa9A>VUGѤOCQgұ:/RX q6+#H/eIMK,uIVH:1#qc~i/lƜoz/'Q'=v/Gl⛧/ē' Ϝԡfђł++x&'n:+XaJ$MpJCLE oPbh5A0$h=Zl} B HC^*Ct}2~_ꓭNjg6l->Eo[A)DA'XE֚CB'gە|.K& 0Feԧq!&1PhF 9W^wz_>C_<%<$Q+ ֐\ȨSӓKvjS=|ȑҲ^6kcK+g|䦭Ӷiέ~-Ih|_qk$,oCvMLjj\NӦR:) dR`Ot)%Wt7J({i 5~ȕ}G$eRaFb/yuOf?!y% KY򦁷Y\YIj!?+=c_?`k?3Lj&]]4HTvGbQT7qXX٠ʨ@˥A"X4H)M F#Fk]T|Ɇ5Bf@+FG;DoȞOo}.ß6g]9Pa,ƥ"2`Y#ބ$1`@$zO H^y,+/dd=&w2(8B m967}t}\p *SoqR ȴ9ٳg"=ߤԉw|yƱUS#v++1%TA0MHY^;P]3O֜x\]׷ˊ;ws<:y1/w{_ܿ?hѸM;?7'ރF[ e{1 {VȘ>&0&n 3N^Pw d )\Qga?HE8`I||Б}}?jgfH fwΏGǦiPG"ei#n➆T nNstSVvglŃ#wbf%C:8^>^롔n.IoOk>xd *{znOҪh|52jJtqp]q. EY.]| rIډؒclLӈ8RjQSJaj#)nPg^N)OT EbT٤jVժ BJ)Ucf-afl1)f#-^R]o*V5#oijW$b#Z6o]=t%,'5'TjhP;K&6.\˗H%,U>w>ꍝ:r7Gbo ˇKT(n>LVgukއPHzǔHݘQlYiXYf64 Msl|<_Fv7ٞ1\h`1,ngnvnyeu/&@z̖sqt#V.9V f*%j%GĒ(iEm],菼!(SٮY%̵gГާr`6lZm!mDGDĔH˥Z3Tҕ`82g]x$JfqXۛCجc?[ˋOixM|( }3/A/ۦ'-T~U c>%=_u5?f>Yh.GfLp|(PD; sY),߇tЋus·(^` B 'c1''a=u`X/aڶ#?NϊUؿAJ1d(~5gІN,&&#DVfcDG]h6$x1KL8d.dz `CYDs.|֍?> CE:@2|A-YbiAʴHiʴJF2˗ʴFnKOȴNnWH+aLd~d()&Y*fOL[dȴMnL62@@d:Q.G]rBv|˴G.,>2$LJx#1.>N qX2VHE&Ҹ Vʸ7mAFnvv%Qe-+ۢމKgz䦥VD7Ty)$\de[Ӳ+&DGۚψ.\f@2[^ m0sЌ%ٟg?}>˷n>~5!ueCDO}fﵽ//ݾ]Y ]/>Znɱn6fر|Jb֎u)/ag1Gg ;܇xMO&eS=𭣱V6-D"伐-R,E&p4Eh!xq=IwRnx9y 9ќbonv삌QW* o o5iRZmo]]`8]}"ͻriԋz,[chR),b K+[KD7F⣭>Hg~cӲ!&[ۖym,o[j6x6Dh^VoQ۶ll].-DV.9毡[J\$*m~EiIoyvrIO]<R?ֺeYxU+,[lVL],mBD Ӥ~00D6cx;L=0#/ "*s)UwC'G4Gbр%yC~ &@:3 9&wgfɋ?dxQy5bs7" cG=?s-aj_J3%}dWs> endobj 337 0 obj <> endobj 338 0 obj <> stream x `T7~νwξܙ;Lr'3dKV @@Hw""E@ܨ E.nV+ֶm_k*|眙 Am~2wΜ9Ϲ`7'n^ipZ hXJN7]zxͦx?oxo}֊kW-[.M5kT`k7]y&~׽qˊe@x5WވlZv0}Jv|?y٦UlrbX|~U'ÇnB Иy( JXh2[6`wr>?‘h B*΀j\m]}CcS^1}Ytu/?fޔy׈Kj~|m5{o- OPͯ}?y.Kp,@ io_A#X @^6!0 < m`%-:] :}v0 `e~9td!XփIAtBڎ? E}`lׁ@zKW? >JR.j)>w[&ހUjp5$@UC/@_PTgҩPYǢp(>qj1=j*B.J OZzOeq(;.?I|'᲋}g=sNvw| }OBIg_*Զr=߶egJC!}R)[Uʊ8T еç`{$ 䚊IC$lß'ŃC3g&<@[b ֝Ssn>ÂCqJ~%rO:ضvc N2sq#\ZѶvmVtG-|' >~]q'}ͶûN;olhx!m}3zP(>S+\ m=w*2֛ȥmkch[ɷ\{Iq {"ҵ.@grfW$v<0~Y#C#@[$G0up[zytioV9"<>tII'?GHnC\L^s,Tg!ݽ3><~sIvh-C>7ʻ]D <QBT z}">'S/n/@7$$90V&Rj|X:rsr>;GgΕϘ3g&oѯ&|Rӱcں/N*?il饝T_E9iRƑ7Q;?2s6qY̽|^u~%UBjY;²-A6o{J7= wӂ')H 5U g{πVYRt'qmZE t C^;Xyk.[8KщU늜>)9'P?}sz`]ԟDE`7/b+~B$iHC"xr{:[iKИPcޓ$;p#9py=Gi 8|X:pWn$l}跗">PX~d8}R 7^$O>-ov/PaA;h#z2@Qz8g):iLyVgĚ8S$&LR0u,- |Z0V%I*CTu&HN%,PpM\mpCktVjk$# T++Q󱿆Q^2?N>O3,1k̑zK.iW0ΰpHzKKWl2e!}I vT-f2?iduj$ F Qg:[LiR59i}.ܻ 6hL &UCaBI/B|@p3. 4 : cVAǞCx{8yy#?鬯gLi4sӡ-~>cFYeݯ}o|O+O w5, p6{\tX +dI(IdI0 KL.ξ%Bp"Ѐ֧Jv)DRshypZ*G#j>@4tp@#HX~*г hRz`Wxcs?z?=<_`>_XR.)؂q#ZUJCCPq0/МG@T[hcSIu T ?A=R k <wq~~ĿdD1 Ԋ<T2'-k@2Zti0/ֲ@(z}}Zc,4s#9W +4g]Vx~\D(9.:0 ZJ+< /CSzH!GDBY f8iP29I-==ݕəOiumCh?RE!R&! G$TZqG&ޅq@XtxRDQfQ eT i2K}pn.7庺pYUWK7SQh$ES^ ,&&KF C*:ǚ2o CzS*WZ3s3X|W9}^"yYOaǂ.*,Y8T=MJAVuj|TV i`\3/ %VE4!bJ""Sf!20~n?7O˷?aћo9~Џ~iM1cfO_\sՏ_RO}a - E׊*}*qP_=ȷT?5>`J-#r(GxhQцInhVr r 6L=eαTJ@c)dvDa5j=lZ zV::3b|Zu;v;(LYQA=rmOYʀoIbD)u( >TE9$Jk(hw/O(RPHS])$\0G6LEP#=]1ՙ]d`X/.r5G;VחM-3R5 챥/5Ew%ixwvS D;гs{덅j6UV䞹gՕ #X?aB4X*Vf;mB㳫lULM9g;?}ɜ-s 7w_3=Uσ| ݗ(4c+DSxtmD rm&|-_[˷R~0Gb—#Fyz({zhzTTR*jG3`JhL0bEc(eDi$Be0C,b% &|?ֲf\z_.טnțkUVwü=\ccl2S8~ۢHa!Yq Zg$*[Y>o;rZs`Tf Ȥ#UqaDW{٣*({X4iC2I&J)^ fV"e42VC믂NcۢgyMf@Ȑ@̇`q[[ 8޴v3!fȹ; l,GP(;3j)r3GNc1:`qQfW+*{M'J!0e!Lc͆BɠHP9],P a mU]UU#URnBDVH1U0$Ω$1,:3JN .Ĭ L >c΢l^T i[љ>mYHl|op/3ǯŸٜrCVMgҹ[7:^y+J~2-yEp^Li"朡,ҢBԈif1gXNiG mFgș_ }#j]U*ea&S 1vYXV8UDx@dHe1!X>Y5a\.Z)'d`bʤ +ktg~Ʃ-b;\e_ݹܳ;kgp|m/~if";TQ}H%H'4Y:UhІ4r|!PJIFhGAL9UGbJJ-.*A5P%zZJFQ*BB$B.lW,ʂI2/9"cDƷL)_"g$ٝԃ-z47|2|5ÛptvMf@r`DGh72;QZE$ qQ l* 4ex+PÎO)^aycX뮎WfS}z͐q{[J;%ò+5aܶ~ɗ7}{.@j:&ymp@sfӸOk4zA}H'bT+3# ļ,fF3C SqEfA`BآC,c?hbx,:OA4#߅PZP|G; onߺt6jUOm'fCcF5{oZwkx5:Z3,(p<D(ӰNZtEu],BE߿FɲοMz0q7!0]x}UejLs˫.Y\Fdz+!,e-Qw}@C=Qw=eWO_H£8Dɤ,1dWg@:ɚ 0Qp׬*q_FWZ_-TΝsn<^x+i]./>|mYBgPcM7YAV 4≗:Y0StjeA bdlBLS㈪] sݸ}8d ~*V~u19FKͺ)7@T@aL1: ? M'Ǧ/ŨK1q5}D j{2Zź}`a23,%DUN=& !Ƀ b(|fhc5~ɱ?̫XD!1!gя3{\./c MH h>3Uf:dX쥍aH1Q3ID ƒP(9\+qOD[*X :qhCHTmW D  Z Javt.^Q1I7@jU7.δ?_;$¡Mk}$ttPFY*^| 'Z#Th-AY ◔mE"XdkK|,o]Y_9:_]S5!2emN7V* b+vVq8cql9H8 >q.A$BM%ϙE2wُ*'/ӫq0tGRz%q (r .^TQ_0*!VLHh[ȡ-{-uge+*FEEQU'_ӹ=2pª]hXPljm3[B_huf]&(sWdLwOn:jZjʘɌMM"0_cX=O gBzwJ ZL)Ng"؏iaL 0|dt<[a(ٴGen V)Ck,кfGX1qumƹ7Rl= KBcA3BkA: {ޛгp(K 7?RdKN!p<'ZT]aqļAnO6ZL!Ziūf-t|TŧVZ/C*;o-omYX5XDO%Kb}&.1 1Bxe "$r[pTpQVS7m\xi{;?^͚k7<[TK}G .P45NKut왷~oq{7< ڪm!%*FL=l@+񜰈`>|G`%\.SF0;:?'G,cFm46,yȋy>D=P_Qb B}SM/ &ik/7ȍ>}QP_#E++%*秫=+u;; ޞopZN7z58}UZxbuIdN|iVc: a` =LQ0fC"'MQ.Cq֍ˀe~78PALBDQB=n" ?\5}Qވl>Kb޼#UCC 箪b܉܉Mr'F{*3;&#`Ό&BbS3&%1Ot6zּ7:s̚E&bqӭt߃8q9DN+,`eX "(jS;e;ȎOR5 IATv kuU5R-/za;^b1zv2`<+8K>zcz!+Q keK i$Hw#1gƽh:P4J$!$J6&ol~#,Zv> 쮫l^TUuhG55}{G9|[9j35j]6qA>z WRm-;}/[]ɬΉM!Ar^-eF'm[2$$!BHxܘߨn13hBmD(8ØƍZ,6LƧtmB6q.t1)";&exw>LSEP+U!X K3:*"^EW|Hw[zk|կ_d/98l55R_GruU`9ZU2uWEX ?G A7^jpF - $g}{Owo3I_oG'-&.z˱zˉAIH}߈*Ot9lЅ q2a<5u 틉I|zjczoryGSa^`fL R]tܗɍxNM5&E%xT4NI KAb6bUe6zG5 rQ|hxHZʏK1ZgTJq`rH 2I$tZ,@eԍM8 8F./el/ɔO3~5UG׍aՅVx+$4HNiJ]gں%ˉvkݗje,fm5'!ua9-O3YD!-dNZ#?ix8|=^ L-3`x #'Vj& ۚb\uޣ!ѐdyRDe3c%O`* Oj2=֛a\nZ iݨ2FA蘾^89ˁ M86 0o @W a߲0tڿ䷙ZD4Zﴭyk=^Ǔpa1"'03N Y[)3J4 B)#?YLc5ZX/I{Y-Pc4b2(Ð1Z 8K1qCdX$n8~JOPbP(aC$r_/%_z>m1!uZ3u`wF7#J)פ(bT[1 2ubG AHf;uDȴ.P*V-RQБh$A2)H8 _Q45Fhd*Uca"ǤDLxMFA$|ӍݡlL<|NĊS9-u=`_t񸗳fs7#.=Dž43H>:Ol\}RKflTU&Ws `GVxw-+A߄׮orLJ= 7/}߻b%bd_;Un1"ho?UdlXFdlaϨGN;QLŸ=K{ӔJ.CQ뤙uZ>pQnq>_q) Tv?ٳ^5`X^S0n /-NC7c*|=Z1 sZ–h펄?RC>I#S7tԧNx)Gt:BgVWn]JmN;L<x~@ VIuM& &CfLS ZF HJҵZ`Q4!_I"%?*0շ[~%Bۻ]ԭM3SUf;*#`0W=Bg(N5ZF#/2|ZBO!tL@DX,G:U8NM3oݙoQDԹB %A.hppU_m7M55MM=&VajJLRcXEp1kWL T*1NTn5H7;x<%68*+wO$ %($tseWSK/ ̋ѿmn\{K6spI N{͍u,ϵd/~gތC [a}l||}{[x8Ȼj84l!ZJC]۵K i2됝qn)lw1x)hRiu8Ḅ&c&D x f<  f:s6'$Ή! 'TNR];3C->3B h3!󓾔L?q.Թx6n|k.:L#>g\#3~*o֙+,{ f=&:cq<其š㥋-VJqv{w͓pgFPEkx@[Q5F*UU&k}?V|K٥X^W rJr⯗+B33;Pz,*ǯSPo]\9ZA6^ F1g~W4:¥i򊔦KѪPh+֫^FsiT|@!Y )]JHcKu:.*hZ56&yӼR2jE#y䏰LΓcύ#B>mY>```P4~l4j]{ݴpo`W coqR-6H)mprjZM=-?]eZ?.\Ju7i* CS662O1v@_)(iJaxTgRT,q/h]ܑT\*UߠQd5bjn3[%55U9=Wq=%j{k릷۸Y %bU&q+۹umE#Tbl$8!EC< ]#UfP4_Uٺ.oE"3;!ԓ4bLh 0\?QdIOX!a+N gw\bU~SRK #C 7-s< Sk筪 D6ոv=\G&ω?]wzu*j[hnۙ=M[wQz\g&7nmrtKov]Y8yqUJ㚖腲 |ƨ `M{> r'e욧nsuZ'^E'sb;><,n*MR2Wx#R(xm1zW|67t:7NmmնVTx ӆ|UԫZZFRтc'x R-e/MĖfP0tjZG CMEL_`q_]+^(7M(Rjf`a&rfFir0:fL44ҳ4M8餮utn =uZ@?C۪cj1jINfu:#4E eK],jq{-.r(/"UO}f+0gOowǙ=psiNB/3R͹ v?M-} 1.{p 5wŪ;AWM]}z}2+ ?ZğPψh^>M:lux^Gv?'K{5 P".U*da+ aBV W? p/avpH]dsOߣ?Mjςx ^Ef^kE%,rɪXBH-Fl,A%4Bx8BJD81Gn2.DQ,Xjso.ǫ9%:^TmW{w0;?nðiѫ4jtĶ5>άb኱xijfxyYZi h}MkA_X fz_ב\s[d|ٞ sO*Ah74F"%Ub)\B&_P媅Qp rɄ wyNZoR `e#Հv)- a1I*]PUE-!  5>aSQvՙwpFE*Ur< +: T( :*&0%dNtעC+-!ke¸x2 ZZrS9Ttvm3$fsZYᎧ?oݾ.&=YkYx%ۦ2e[wPͅޛyom0vmN|,GR@썻*ʻRYR hQGDL8U1# 6,AL+%&g0h2RMfVa%AVGQgƄɴ+I'U 4,;ҜXy c% .qұ-SX;ZH}0u?OQhrQ4Xɉͯ;OXt`ŠkfS.8l n$agA)ɒU9T&7]ѫX|u},8yc Glx%xD9X^%Շř$ |Z>Dqn✓7J߷B+?tG-%]CBR{!C wUa9R)BñDTJϭN"8 꿨<]xT'3wum35ZҶ7鲻0N9U` :,%TֶlpnzK7bmi>9_WKFjn5徹n\k;]c8t1 AMF&VP.钊~ɠ[^E:ޮ6jGbȍQ>c9$9}mw}ZHZB݄.!$tz#Y -NV]A w% `JQ ,ҿJ7' }}W}k6ޛw-껾nڝ_wP7/>܆H%ZsG=P2#{B`!QQ;HcE#>wZ[lyT*X| .VuD{ XG"謎v/"'h jWiq!OJ'Cu>R2FT ߈j1g㺄7A oJHcq"o ]0m_LV(YL&eFtۺ[ .s};+KNO?UC |BP!M1REEPwЊE VhdtGGzl]E<Πfq1#0)lL**:+R͊w6Ս̃Q8m#UU5Og /ˬ/ 8@Z|XFՓ`bĨ)ؠwP &~^7MбYP#6dw ZZdb a++ SPz2_= I}fL.é!YyڤK(UX!HeSz*;3 RSGy):.p8TnRarwNIػҪmo (TW">(yqPUAX1/Jƽ㮇[V~o?gi?󓼽4>*NbD=x,c$+,-Οۗ<Ο"/V,HtsUe!e^ёe\XJry.Ij5⍷֠uWl~Z*/̗zn_eN?> V9gA1-9ӊ&R?&N5Yt1XS' w6e_rR`ѶI٠(?M(ِ. 03iPIJܩ8Ax4~9/ S]QOlDt[b]tggvFX.PPYWb;*.ΛMuV]ET|,y`B$~LF x:~vD'&@6:CsXd=װYٌC9ۼSB,b}@xʤE˥Y8(&:] e~StPTԔٟx*5V,6*!61=S5Shl: ֞d7i`}YӼv/Y+Sa-4Pm?SmޠM-%S9xH:gmV-#'Rd 6Z#$>ET3CS:X*-U\]-e$ [i|;ya`*U$ap sI:%\DD%|.[N@X9HNh5XZ&])!1/ 0`y넺|9I>lVj&}*d,E2[J E`^劐"O(1lcztcq z|9PKVmLF3@9Osm e3tvSMr|r~[o׼D{VH];jԮ NӳJl>v[tH&{?cU|}!C!EHDKNbא1{E_ļlLj {>sz3vJtr8,-_N˕ZI+ycK/Š_N冒m{b]1"RMaћkkFY ^kpĝe j'Z 7 ׭ zE8n/諝Y;o~ߚ>UˉW؎;;iӵ R::'Ȱeor;k|؟yboL\(dYoʓ Ȇ{p$W.$ -% ġ]$ʑJ.&BB p;w. +;ǏX^ ).W,VlYAK/*ArJuť$R( -0OgфwHH;z҆C!jO(].sYagje^~]O [ZyUkz~$\F4O9uZ+KIWqiZ=!{ƭW{ bD>ߏ QQ(Q'C()<l -#S"d9nNѷ˜-CNfn"Yx $*~y Q1K@B‘5KpduV .W9б38]+M炫[6{VSpd k jA[ F*Ă3 KAue;cGR1 {f)A^u |X,b5҅n={IrCA*N}!NL\:nNbȾBT֥5O 5~ j^x79_3kk=W N牺Y͍}VfJЊ1^~(Hbۉ_j'v9$djt!pJbe]6p"JDld=aqJiCK鲈E@HJYAv]>Θ7h^ M&7]]h5^#v]Fb"[_u& &m`dJ~*K")~w2MX?mr|Ims[g<6ZyYK ̵!EɭWj[fFIB[Z(L3vON Wo\GU$>bl : RO_ fh7ɻrɭޞr\aװpiJ9.6kD|/x5ZRJ'-%+qx(4t5H B`qy0J'1X[waؔakJ,-NvS8ɻ0~$ZqlRJt7`ڤl=9jѴUofa-AqpQ(*IͶ7Zm.>XAt=bh@"4K6YD k0K,@,A3Hb7?*k21Ⲑ(WY\xIl#>2]`EOer2Zؕp]4wh:wы]u%`>>!xayv3&ަ#Av1%A+r#Wndˍrh [{$u[r1&ȇr˫jX#:ؖ3/p8'x< GIijE4.0F.)H,x$2qąW#D p=MeܯmGT*#j(ߩG)G fe8H^9^ sYd9b:c|4h^SM 7qza[4;}w5!t]yK^orLkcEscVkРۮyc[w^]E[9R5gkpCS Y cUvRpX螺87rakؽJliUp2z 3` ^cLiY/"ibgpyE-2 ǯ6.R_v/z駡GkLqgp}C0]xqhWMnBF0'?Gf6HA83C@gF,Ti =/NcGND_W,l O9RZ6,gW)^p< 65% N B e?qõ'2L>3ܖy?3 C[ֺim鸠P5P`‘V3ht|fJ~lNMk.yXiF/[rυ̺褶pł{;jQnH:,ڝZQzXv|~Y0Q|_IT;66wBˢ<㆟XMtPh&FԕH:RS<b%-!.ỉVw]>őJG+$Jc$"DG5F>!GrDW|k@q\P$B10Ї}($BŲ)ˋ}K\wVSqS__)%6՚kUM_.qrWݟសVej=<lzxO|:7 וk@xh"t&.=z0v?_=wˎp&](~k}_|}?rSj~׫:UUרDMyB^VWBEf ̓ZZ6kTj^m](5r WRݤRr^njCțCմˮ\k!rƮI(V1FXUqڒRxI WҬ)5>R)Nh+//&UAP-1^4ژI%eT_^ۼ[l ͖I! 9ij:\YS@5u$!yO ("Q@dZF~m㨵3]3k;ۭ38uOwfm̰Μ{blr{~vn EN۵Sb7d'2Nq^4}=Vϐsr!W`@gц? 3@ ev _mD]t-l3<.-d-%x)`s5lNtX ]MMP%TvY˲aTeLHZ7L6벎mъDsB^ʃ5lL&hʦ1LQٝq+҈(#p '&7t$N#U3*znn.y^N_+qå}J[a*^V6`k˸Co ,u˝ŁE2=F:t+ܤc%*?NC ӵOO_|7~6pyref^9p.jƋ))`M-t:q۽/VT8˶l2wÂx 提v 1<͚tF=U%ꋡ8˙M!1WwH}"{[i2 'GemSoM=gڣ}Zo}p> nG|SЊc۰zC<U@%zx [a8qrW~5GcFT@iއFtqVhsy+Х . 24fСya7 h`uWoi^$~<0x==0}{6Ga)lbA Kewm]P_u|3? o!OPϾ: '9}{ ppD OWx>5Z0Q= Ė I `!Қ%%HcMf 2DyY#_qXh,ې~Q1|)@ Q^Qu'v~RwH(i*~m3@ZIԵmE{6bP~)ͨw ؄vmCۑNmȷmhЁ6݇ w z]"g^㠃: 5A1<=N-:~b=?QWbq9;Tcs*ր{UZLO:_*փH Pq{Tb螧8جbHK(6QC1[_@q*(bi8+IyIq9@qQSX\Jbg SR`o+TrA_4 w҆p4z`8T,Iۂ=rL@8n Q5V)1ʊ]Օ(w**dJsR0&ro *yh'р_^+IμhFKbPPFW$oDah0+)[2fHJb{8.{2@yh]w8$Kޘ D25H5mlRQDO&V }x1 |}q?)VXc>T!W |HҌpoPH.4'*4CE `Mư>R1*ReUREZQ?< {+EXeˑ, E(P,G*΁6+`$FzDE (u B% cA̋i~w{n^ A~݈B|Hn`SBP95(mއ)0$=H=GNb¼Jo1Ue(طR{Wׁ΅~ /2.IR0LDDӣn+TR6 1?iybZxgWMBTFV DҾ2sImijAx^ |c.(HQIV)T BJe*4}Jh1VSꮛJ=1R+@cT3eڈڂIˉ:CqJi (FO#֚+J'r>򑫀~,׌Ŭ }E_GsTR'cjf{eE W$JYdo/JYQaڳ/RuP=ԪtqIGKC([\*;F-5:+H#cH {h#(aSgJ&y^@ׇ|}H38?[U|_ǯC|rMJ#hː_L׽kxt.L? ryh{-όxyIiX2$#\V_mʋ/7]s9|Y+N8''&,E} L'VNXxrѓtIzN?{txL=]I|sckR/>O+t$#I[țor҅ BNg:#9~sy>k>7z7 2gij́XDnƾ(^y1S%b(ѩLytçxJSЕ>1#~}G~oe/ {+G|k(K|SKtGxhd̳#;#Ň k##g#P89аM ,Z.>8TD+0tEnqEn/VrWm&i`MY9I$sҤԴ$P(ͅbjJsbP( K$1!`FaieE-Vk?Wl8(a*PrRf,Z֏2n_?Vjo8mc%jLcge?| e7:vg2I=RyfxDz*jo䴏0NCǔ.3y'3~BOV;ۍ1#cαbV1ӿm= lݾ;c9yB#qv'g6 vH endstream endobj 339 0 obj 22549 endobj 145 0 obj <> endobj 340 0 obj <> endobj 341 0 obj <> stream x: X\ՙ; 3003w1̃H0ELb !I@cUۊVcmӗUmD6Zmf[mmmںںy@|t~oߏ#Q$.?7v?}FN#K'JҼ /`쩫ƆFl;]pB⚡CW TBޛw "톁~=zڍ?п}d/nD( Fכ~C_7:xmŞ8_P|-vC0aD!!E~1 {Ed8݄k ّr{JHПxO;}KBJ3BNng?WR6wA(AcRձ[΁)C70> N$i{[=<8ӳ 1}4taa6IZ@\}i6ts[7ڧOm> B,yL~qΖJJ.Өgjѩ)3Ի0z@3AtG >~:*T>A9xٶi`j,w,ewPL,w{>Kߟ^%,P¬xJ\T6FDiLd'HRɓzTPQxţC*BQwpkfgHQƝ@~bp9*`:€&AҌI3 S1fQ |[KfPF]g94#YfDzP. YB# uL 8vU&[1˴s(Di2N_XW^XmRߩoQLrr00*_%<::EɬªzV?"o!}CQ"8#ʀPM0ur!КQz)]i 'Gh8=5x&\n17( 9ߖ“[o3]9fB@_$Pb.dꮪd So&L+ՙBoC3ǎ={JJ^Zxgy)oWxbY8/<o`@}sQMjϪ -:W:k.vTdZZ#7Y$?px#K$rK`sTe9\y9f=:wƁD,rHKVkv[aڣwFIw[,ZR:6ԻB:l 2 i]`*{x 9ȷ BH%$뱃Qm~fk _WM&7ȴINN,\;t[{>1Pw^J'<{9] EK[BK1ɪ0EΗ-ǓKVA;QjRw`TýӆWҚt^}ǯ6:׿VSue.'p *DJ0a&p%MI0 ^ sc{=3MNi+Pj`H،@lHP'rmn{|bYrK/6ye Yq(mXxgLuq_e56zDzЀuQ Q,+)Vrn1n0 q bfmDY]H5̑D @ph50UmVHDGq`U<d2[Xi9.zI\c&?z8˭GD%W ̞b^o/,Y+]+N떭wֶ6+m a{E%-_Ю6*#UZ 3 n+]$aE$3ˤu3V`w\o_:3[Snîg!}Y'0JiC#]lHwosoz6* BTW.+)A\-Ucfz9@ZLr%nn^$p.FRMr9?%ic,t޵|8K5M^J9^+_3wl_sNHl311[nNܖz-[뭼{cבy]+ZW\ڎN{;8XnLc?pW!Q2/da&`, U#c^hܷSgFbZ۳hݻ!T|.vE.e%9SSNF⸼}d~Aɸkީ=mN"^qb6 /hVXDă <B6$X*->4.9(դ%t_ٺzvzMmT_a{w&*/ %\豃.FȢ踝nI`q ~}W }V1敳kYI.)fsa1K2ir;+6}+:oL5l[ݔ:˒5MW.K;eEmm|o۪D1_jTR9.ǣ§639B NKrprs/&HM"kkNK,?=tSu6o>W:Z6e2*#L:zKz/;[Rn:xd1ͬ=ː^G{]&txz݆b7TI߫ou#u!t>'iч_m#fgwd8KDa:QJ$TpjM$Dl;яOʲѦ/V_Fܾ,<|cFgo o. 4 L]Oc"9)™rs|x?)`ջ˖%gOHyN?( cAa-Dm@ n[ 4zzBP,˅fQ=[WgʲTo|\D0uq D:GrJZrw n, "Wf΂dXDz3luS:cV5!uzӡzSEaB`/5"Q J<(VF2ɓKnJ2%5UNlO%ubteA_HM}OԺ^uR]괻EK4hK4^^JYQG/6OquiYK3ƷQC#ahGƒ M;끘?GTڏ-|5MYPPh@Ew]2r D%O rI^#D2< 0|'YB\VT,/M·  $lAFAAfl ?rxP48 g*8 yȿv_Cfc`!̵^֯ T2 ioFȑA ;/a7O`gPnɺyG 49k9~%z|/8,r p+.&2K` Fs&g 8`asq5Ȇq7rX*pPX :W# Yc 2g08,-5\x7EaJPHFȹ/R A|%g[9RN~N FLY 8GOi \d uء )АI&R`LZFF$:4>x`p|rp N?4ohMC#}K$>\JɁ`rқd]u*~3s~hO:87087WQj?:6qpp!{r{ˡC}c@z'ޗSOKIzi|gg> endobj 343 0 obj <> endobj 344 0 obj <> stream xX{\e?{ ̅& 3 *7@ /cjjh(# 30!d*Dy)%\-?MSK _̍Zm:{Eos<<@<_jw ǡ 3/4jTȿJߊk DJ /@2{^١-~cBThf K+NVQ>g]sw R.UmSv'7\NwUx pdwU8\3N u H3cwHP>ů Bxxen,VqtKtS7M!2ŹpE(q#)\H@#,›!.+,{[,,J"@0䘸¸r a0k ?uaDQ&(5 I2\/&8.,P[1GydϷdduI&M<A +94/b> lX-`ޜL,-F̌s"-fA6rsZiLEt]G6Bha?1 XMfU+ 0jz @,NlɹJ~Stpi⧚!3nMk焙ͦ3sr__x8DcEzš!+Ekq GR0[a@VV;LQ0Ie2c9RuR30RsN> =Bq'`ZS#\:3g,z>ڬ7 p͇ݺ٤ Eb:[ m>SjF=twXRGJN 4*"dI̜dL19311s2Ɛs?!.0lX֬5! mBtݹ豣Se  zɱHN/CҾ/^lxq{MeN 7<{V|犧ɳ,[vb)F0QTs~Jר*MQAk Dݦ7XaDg,[_вX)IR!c_Bx]PMM^!$µ_sq11 خ`~t[lΨe|0`zAd_`> >X 6ꔆA &ˆN=) V`T(9iTj0oNovQYָt[^2=zPqCۗ}9a{@4j ^1)^ o ,pjS 4d6!&f 屜` :*<,&0& ܶv,O)`r;uov \Ւ7ph\b)ܒ1#ıqr YnxlCk=?Uo ӇKma4!z뎧l3<ק>bZ[^D2BZ>VD?ΏOEV `Qt@\c: TR,YқSd9mOWުYyev{soC8dن l ln=DD_,H5q[vuIk+J~f${@'qd='nV Uao:MJ\wDO ;t6(_q-| mB#6+C7PWKW>AHָֻ/t]\gijE?x9~u+{Z{u;+=_ʇ\ٚSV>dMU2Q+Jۓw;+z< OH@u+b:cۤ]mM) ՟Qң\ Alq^j\j?z=[(s5~WQo` 2Wc'>\ Fv:%76YWKqr12Iqr3dqrT!_)ZjPqRlU>FKz)NTՠ^C.Hgk8/-R{>SžLЯC\ܟ#DˈI55Ԧ8};Mq#m'D 4V'AU'F\#+DՒ`&\%DgQaR?kM4[\鮬pK0t$QTUb iᖂ$GR)ɒ``zm44,2ʪ [)eŕD^B|s)8vG|mXA0OKw0w5pC?xbBW]BGC!MxgHM¿v~Oo~KE?PJ:|LĻ$IkĿ"JAxK˄~Fx #‹#jv?yt }d4 ;p m O$|b?A81#o&L|A#F4;d;`uԢ궒w -+Ȳ"YxD)qAdHiJ=!eԪ+8˨U5i&\Jf]5nD=% ꗓŅ.bsT}'&ixXL}: #%K[C{$͡8sg>D  gQ$A87N#D3IN;z"{ 'h6㉏#K80B+qI> endobj 346 0 obj <> endobj 347 0 obj <> stream x| |չ4W[3[mY޴؎[ۑ8ĉۉV$$! %@ppoSV'(].m.p/Ph)}Rem3; }{43k{gb_"Dv5MۛͫEz!_6o۽:{q$?G(ޞ߯_@>z!CQ }5ۇH [ tu"J4Pҷo*AHtis{OI .Btkb`hx&:GJBz##^^" jQ<| "1,5#}% Jɜ, kͶ?T7lxGl>χi?Q&Nͼ]]Fh:ʵ;P3?/}^DgQ'\7cyFO§^G?A f`߂0ڊ֢Z:r%9Z~5*t'-VZr-z *A/,Q5&ĭd>y~7V}Pg9~t(=L<"hBԳ3o$wBC0臤\OK-az}VF(R e%EBoA~q:l+X2&Aj*ˤH((@yDPz(Vk[~:mZNR_IZP|IKY-sIIتS$R' MQunb%"jSɚp}ʐT۪{$y$ nQ&:E",?/$IG $#7taBOPX29sERE$I!7.ۗt& 쩼c7N*ݹ9B#ۂqOG/A 9la8bpE![\zz֜T=TzPvϻfj,fcqrlwYR+`c1tŶTR Ԛtwlcnmanz#7jjźmTH wC-kZtѶtV𸒎h5vj<1[gԜb\NG:2b,A=td$Zj| '<6Z5_l;6v3$:l?\ә8!Lj:jllXX6Va;0uͭjr d͍mIEG/,o ʶdlH`ep]ʨP+[̀S+[Nݱ i0F=9xӤՊe46AсKΖhW⒃%s;l0cg&Eι7Щc$TyR]JɶE)LI<I\0E[RI[Ϛ+X, [ò5lllN R9b9QuU = TټaqFM2br%o$6Ѩ:e#[v*B\bMiD"׵>BduGU[[$Z0ͭIbftEN#16U{/ Bbud@5)AcX}[vv;y+ZROFsdO[[i~ڠ-p=@SPiM^ lnp N$= q Y;7S3 D{Ɉ9R)Hؘy ֑NOdҌH:cq=&\Aj<ۢ0z`쬢4X> n'$Wo Jj ]wd823r7EįBBh{ZS?&&p7!R" t.Bo_{s~~搯HXW#WQ%TGU|y?q nň~`QrQexe\M@S_uR-hWl$ 7Ao/?QAp#狽JU^bH{<D^SDXQ#")ڠ[0}ֻ<\ҩ:N2M"HgTdU)ʋmhD%j*_E*;RtT1Ru1QnhKEW;vPK ;BP  (JPT߯U*^%T`s%%5.<+-:Q\,Er@u@ETJtL>a8. SE9ӨD;Ǡ#Sg},-QE:=F-[ Z*ō0qmPN&o]릦GFCc}I3={{Ųs[qʍˌYM+26IVmn9dm\!{SV7ykU2,2#Ad4Jɤ2ІnsZj揰x Å?r91`(ə#rBB> fV!D#K\#vP(IxHwPR%v{!nBv;u^ s7+/'rj,B W4”Pŝԁ ߧvn"|,qD1u,҈0)Y9+:<b Q0V5(_F TikM 6#,>"T!g Ao}eJxP`/|!VXEPy ż(f^Zͯ⫌=ɷ롳 dՅW}hNRt!bGZHLh\wȜ"r.)KE w["I2IddD<) _rH&q|*tջzc#.7<;@Ȯ̴L 8e&j&.O{AN2e!Wf07L^enT %O*o ^s;3)VsBt}8kq(ļ ՙ5SgI367`G(zrd B&3 :{ %[6\'AYikɤի1x gK{ -ï.|[?DJdC2٥veDh'gtGT{r1g=&PkIq 8(>vsWNhHgFfe*X ܍;_o/ޘA)Q2}Mm8wQ}>}jמ/Ѵ{}DΟyءkvς"?ic2W{ϙ} G{ A@\e !げcH BJ(Tn?᠔j, F`5>?g[ )&4`? E:b^`׮n"I^kI[] :Ӯ:}֕mX^spUF˖XcS&+6[,UߜV>*XneS6qy*чd].rsDEU5`y~9<90P#y@JeC a6?V1!0'6(EGA{=aOy S=O8!**iz;tDd\޹`-emjm1BPS5}6*,\!)Z[QuMDl<UZl`"=o.Bo86K*qmy9ִ״ӾIR_-)7$ØlBMosڎxwlO~jO{mBA_˜Iꣲ!ƲɅ`IdGQ%?iv_] ,.+[B=ר+}6I(3U%,\I wtfܑUXD媵:^j p9 mǮFz9r,-,YWoNbq3h;v)B4"/XJL"Ȇ&MNLOoR?woާM˲r6|1Wlas+4yrЬ|[B4QR1\5zӫ?_E˅Q0o[ز%/(6 v1Wח{D=YVO$\.:LTaU3.9P9:*|QiP>'ߩLj'*iuLEPWiYOڐvvOW+`Jj+ʎJ i4y s.sN`\Þn0Tyj#S Młq8myF1N9V& \FN uue>nYˉC'"eaP]״Zn45c*F]mo4:^|۶; ^zj/Ӧ J;BVe Tqq3 EA4Ygֿ`o4J2,sȊeQYllLd=~T--tJ*tPzDJIu' (EQ2!ХR ᐡ}qۿy;*pIHr_U tڈUN I&xk_<Я:}sm5˯,w"945ŹmzҞ# xzzjss n; L=)T U/}y Ύv?."`əŇp7B4m+VJZH WRBs b_*uN3;788S٭r;yv+x>yNI z[?~XCG/.+˓e4{;b_hv^-f|w{=$D!AkÅ׫Ȣ$"'7R+5ƶ{ >T3j&ɖ1v%p'ՂՆ*[T6mM`yuuT%]mI9!uT}.gyljӬLqBվJ/^ĥ8wܰ@jo}ᥡuyK,%[NK?˖~oʛHF__t}IQR_[<&lQٝ]Xf] @IY~OrNGc wwܙ%*VkgI=!@  c+ (Ȟ0*RVJJ WhL9J1y޼B. #<ϧ8`K09Y𬪒BΧPwh\lЩK^&uJU5ЊeuD~[~.~?lhϐ a?}tT HjBݨnSF |Vjްg +: +zBAT%ua}~N;,h͒IBBI$;xY@0}q /,v)7 %@)D/N9M9h(%m]Qc*Mִ=wY3rCo[WJƠm.h_=UZeH+TőziTW[ւdLGye 7>T~ɖH))"L#P[=*IxX qA,!8AE;Ѻ`nI׮ۢۧCK9T-ngz[eR o(wR 5(v09Mda<߱b ͠'4ݑuΓ\d@W|}N-XƗ<)sgXe^GBɊ,%SuҦV׌-:B*B:sm0z/?|%aV[jȯMu@YʐYn4d^p3xG~3ft*]j x6F;Ezޮ/}GS/Vϙ $7ƃ|Lƃ ~Jw."\7;'Il tty]LgAEEogI.p"kRNٮ6k.(kEH82^…ݺs6߿c[E* k#vJ]h._2YE޸bպK~(=uT"Rt'0ҒPai,er;r\e9FY\ދBBDž=r9y@1f^/@vۍ>"NqQϺy( su9-"իWۗ/Jbd%G֊J}x֜p[*"fzuN!J˛Qr`Fehg$l?(ȥvS$C$'b-W:/ZnWeH*za%"Cuj"懦93ߐiB}Up(*Rs zZFh"K2]"V6 % $k3!ɾP̬LèL,eYYL"Bt]ϗe5vaw/!No%L2A~88 \~p1dFo0Ǚ0O0&"NͧXu}.σ%TDoSE"LHWPaR OljUpS`|5|.^嶡<oF`;Ua}Ɗ$gWZtZ+ŒOy;NԵ/5Tŷ!L6uO EўG۫|NVn9QNc f\n3jj54Ojxk5&h !lbJRi9ɜcp\R8t贊/ 2/*{ uObEqPk:+WEdԅFg#UY8me[~;MTRaDaL !fTRjQ2ZZGm6[-jkm }rD?OOI1כL68]|&Nǽx| [Ue// fGI? ԟ]̆43wŋN.*Os5)96 m=9б\Xս«:t`T6yCmKOsy5!tь\"31;夂Xշ7CtE3td˱/(ԥ٣u&Ggge_R{3y>J\ǎq_Boׯ?W;(u>[_MC_YsXbU& 7"-߸SS'E4ϋjqQ@A9tǭߍy23+p>;5lqG 0ߌnxMSv ! `]G 2Ch6m6mniW*,,$Z7x !&Gٓ!P94ٖsd.ԨxVgΩ( 30,X郮˔G6\:Uܲ2B wy[VhuZjifΜUfe21x7s3rs)eLi"^׼kߙA9Amlvۛj4-[]^M&6[C"f\9h78k$%UJXDb_؀;JDJ)=X4* c31` ƊhluV#m}z\7ZE:Zg L+ zˈ2I>nj;_ \Q Hg!=BSߎ;b=ϝY+FroZ^- 7vY2 bJinK+jcSIo6)`--^d]ӿ޵ :k!-Qİ@:bU XVg#4-\kzjα yf {.Dg=~nÜOYuJ NzYUrS.VZS4kqi.d( +᭾Jpȯ޹~ÑheLTktwb+,z}{e Q-/yb]2~ݍ^1#[ "c$\5FHO/ ]g|$g u^pc x}3_? ]:b{>PޙM)+xKQv3Ib x?@Hp#B KDHPƋI !E!e!U+Bct,B d djDȼ B,<B֗Xv(w܉y!!kwv}#P*GDquԦ!4R)DLp!9ڒhIx4-B2BHN0iZF4iZn<3i"DG4/%/iʤ--M|/G4Ws4fP78EHNq?i -6MA]iZҴwW!4-FSiZFN h9jpWt:MzE? ׈yRW4|CHܔy ^xV.ޞ^VsL8$Gk04]rϧi\? Η4Kr8ڈ4#Yf4fh&Mv?igh4ϰbZQ~'"n}i´4UIW¹s=iT21Pokg[M\?6Kȿ 8DYr;n֘vC*п[#_g\E; 5V.U%Ajz)+2;s_zq=^.'=xms]P3yb^Wtie _k" xz ʚIpֳ4pw,+2//(_S'IaZ?Я0y"rΝ_PFy?$ׁV77oFk,%H͏LeIRd~yOi{PC?D>üE[n!@~o{ڨؼ .;WĠ?g1e}};&O%ǘG«y.S2E٣L>317y3\7*b1E5jbfq8ȈÇɊã+=\s$> endobj 349 0 obj <> endobj 350 0 obj <> stream x E\UI:w9:gL2jtDaaoWPWQ@Q ZEePq]EW}e]d݅I:a}aR]U}U?y: 2ɭ5qk; 0""[y 淾-Byi]0zyWY>@s/=wΞEup Y Ў^8WþEw5}̚L`nhg\}HA})f叧}!ò -^N/xg׭ B^ؿ0Ca-`" BZ7Mf vDx}ȏPn"PEq@E(YJf+*kj5465(~DKށ 03Q܁5\O;K-vtUHAVߏ $ԈVлhBBPգ sYdCKP= T'pVzFF&~ |+ez|* + LjG{i\:W~{3 qEs+r@t)WgM@%jRzw&;w3ia ڎH@ߡ{<ڋ>@c/RܙhƢ׏cx0Lff\ݎ.E*tZG1C L`F^Ԅ&@0'p|#~\2/!Rvt?Q2X)<Oſ7[Q~K4ae_a;3="Hs8S~+i܂BR$`ԛV-ɽ{E@`CG0+hz}@*1؀#x<>_x{WGMd?bd'n:?dsܟro:BHV u8 {/\>đkS$411{ovtv~\Un:.*7ik_|= q39x/ B܅WU[.OX%S"בd yG19t1W1->+gl;^^AF8:1wf}ʖff/ʮ1^1;9Ң2c[xѭh-Ǔ0Oї[@ FT #;B<ǛG:ރ?? /  |~"bL`*ff:<2&x{OY:rlv ќ[s%kovJF?l33Cc |CBoq8?Xf,i% ] 󑨻_҆xtz 08cBALn$cYt Iy#Ә;f>ZDČh0n޽C%-zE ǜ'2K av x2>'P܊"a؞ !H<ձd< Rx1`5 Q;Q,$a :=˘,tak@Nx9J^z܎jlRo'pg_g_',\@2 H`#&f8HMҐ4'X&|/5~ Fclfiwgb3@`MZ4jlpK xx hy9ȅ4'Jpn+@DZ92A p nō8qWΈǁ}w |q7;}E&JjN3|D@thX3aXt`%GA]`yDOF=΅Gsx5JwI R2}>b^e|.Ag(pZR[{D^U osлP|`2]iinjlT_W[]UYQ^)-IEx, `z$킍Z&A!Eڦl<2|x mGf@njӻej;nyz| yiG*##1/7ƒ<,"w94"&AZoSfBp<}POu]zaӇ6 ن4h0BnWdFjj HgAu{"CuKtLl،ǎ4l7(IwY(2ۚRAm:64h1=<9=e:/rތwhCM:i^f06/_&w7i-;:p.M_^ Dy w#7tL7-e$7;2L+w#C".;XYލ_(;rg}R$t(,)tꞒFޖ'FP1VfSk6r|?e1QLny #g:|V guӭoDݚ@";gFGBJ_`_;.."kvuI2'aCc3:eë́FqmnBJ&M=/qL{?}z$yX8xwڇ]8;#ώ7y}ҙ,$|}\n[q!JА|Ӹ ɓv>i@C::JKb/ЎA:ԶQ-`B5,0Ƞ@e^Ga$qcrFGG65{QKco#UBXE'dG2`os4@A4FgH8ؾ߮ct>7cC<Yr& ,)XCCPKa0 W^j#xWWTVo`R^"e\$F2HDeG&҈הJ764XPn0frspķ^"}N.55NP"߸.;fFН9Ti[x\J,،8BSpfϫM7q>J;TR */&T4|mMm,otZW%_3gwϝ{wq/>1hi` P 3w=p=M}1?ϻygً }`26ϻދA=O*- J*f3*.Y2 OC΅ f mڐ[엽(k*zGOVi}YQ8:|}~ ?#Q.]fPApbHH' C%%XTŢQH}>yvA=E(> * k,\ zFl:a !]tWg)VNdܤ-("ERϺ{pf:GF#=npaZsˡC->.+MY~˿RNqPA걕}2d[AR:K!DBWXY`[䷔3s?*g Z|.P)Nh%$4Fc4ƶhE**Hߐ'/x4rVoEޝL&|-$DIyހ7exQ</Z`қ8Τ2- QpJSP QpRW"nJ+@qҟ'u-snнRZlpBK'w\Q}6(< %B4C F㘀`l)1@5(ES\P =+B E~o7C݁.t(fk)ʸʣXIMeP|uF\_fuAmuX*?u)wQM,ڇyZxΒlHv\VSX *ꅐ+gE7 'bi*ޱX/$O _&^ڣk4?R4:+$#`;9D]mER  _1Y|^K*h!jl9G#mlOG_:Q^:U.~v۰LV<ՒEU2pnbΡ.QKZ'mSVDదl5ĦHKoޏxwNMI{UíWZnLXtcǒL[f6Hq %&EhbF8d>J~@HsV#} ^o0yz𿶨ښbpGi|{VǎR w:jC}=Tm&*i `Zc9ڃ\'%\svxKlQ&]r/pLѼǮt .s?Z>hƢOr@(<Xʊjֺ۠vIƺw=ZXNMەy[00A%Y"&CR@.%`fY=J3lϠN`\(WjvyFPNMC/h(7zAoj.U`%o4}Uј]d5Ba4^qobiL:Cu]시 qQ>(Km\ӑ<+UOm$ Z}H6=־1:/.ھpmgS]˧{[cwEMvnMQ}G!b.@H@/;{+C. HCBAaXM(`ИY8\XrDU$A!9-[΋jyln 3b%/*WMN# i] q[FI Gy%N P,ckFo(\1Q$ek_FeVlENlΏ$-`٣GaaeB"1ck7sC}#[⎙h0[Ѻ ]6j1GހmP琍鰑am? YаG~vv!C) h̵*e[UCK<˸B+uPv\Hna\J&Ocaft3MMgfڡb</g0&ﵛtQϊ%#` E`WHw5B{LJv:bOXd;jDP  THJxmӏ&jJY`#PRR@YP h;* lh a{='b/:X,c8eZw(Q߲Q~򐍘-k >.–p0c 38mtLX6SƂ?qE=Ag~qtSi* ᶚ(C ê#,W6|q/$4aךfZF]0]4/gWjj„:UN.ǖ<|ݐKکyt\}=Rܞjj&d[ƍ+pm yf۳O0h"Bl{ TWP>eͪckSĴWE.)YeX%qB~mЮ! Ѣ6ȃBb- a3xNd_{3kq6jiό]*(//K~T*sij !p~L0"K'D N8Hj 24ԃW%1dmjmMkT%"#T[]NRU 4hZ F{<+KJp)i!Yx F!ݵ]]]"4Y`Q!P&T0RS/?zcѫ_icyYv3~b+y3)%517p[\ DX;>gP <5[<9tȹнeՔpR=ua 5CeU1b8U[!GV;cdKJWXaIJosCg7n-g[r~&䵬_lOE"zWtI;/&a;3^[N웿j/~0٥ShBbj&0}/ea>OhY|s[ks7L9w7W}lmܑ 6ioϝp\O\5fVxtR=?Jcp&fJǪ*yyb'/ԓ;$H+G'<?8B՚sRk0t..I#ѸU4`MT c$= H)EP%j6KĊb @X!ZeGǬR& i&(t'=U+(fPSN/P:&Yei|N):$r\voA)&M;jk?uojԤ_/ն|Aa-vQcs8KB\rqzZTHӯ)R_R:d;EeR_Eyl )tfznqr5d%ʾ\Q4:ȃ'u_򟋟;,>&\\TӕcYDz+1R̶/y[;ttRSR݂Z%,T[Rh4ҰJ*˝y':"6 U3k8P7**.8[0и(l8дHQfv""Ysp,\gQubvx\Gʠ_HQڇC1!D ^woh?7O `*z'V`1ϣ0 'p,fUgUaF#17nNnC{KhƦH*HҞ HLDL@BDB=įx0qL#|>o]-aq/)$j♌hbqOmM 8Xؐ؝$D*Īľ!*Odދ Ƭ‚3Bqe^v.տ]puvVuvA3r_x!PjZIq8?K^)M-m>@(rPS_~qW'leUb yhz9~UL3inoQ8Mfnzd?G/[q!>3 %e_8ppyTҾPxkkA=t 32=B<g9zRs q'_jkJ}i_)T:b2esf Du7Idvv ?xĹMsvwW;paaaxKYk쵎zh~ΫrIkžp0٭f\`l1c@FehҠĘNi0iMS4ҿ:f:[N4l-BOf=7 'ȳoqBpmU[MOQV_U,`XYh=6ۥsaKw [71)Lk|(EX$`7!ZtUNR<,{{pym=iCu[OZ7q[OɾQ r X*AG7a ڽB0HDO{;Ipj]AS{r@[yVub5%Ѩv2fa'SJ 0`-Eu":Om*@BaPV\.Q+ vBLt?>bAdM|`v㮋yg_@XeL_5H̉߿KoQhkd7=qEv1dG*8v~Tg]WW~/ D CJqSY19ot.]YfLm0"? y'KSb)%q[5"µSZE6#]YeW+UP+ÂԴ@mlZ`Aۗ~*,9mke:<5'v|񧏯dCۆԩ<6(w fT |sossLyC.8YP {RHR&۝rUK/}˹"(X&C"ow%kB&J>]Ӄ*MEPbz,L3dT$>:Ìd9-΄ZBcBBkCBCB\SZU kV-uҺԨ/ e}S4L  }&:Ρب3691:WY29)_d;8.8h!2vx|Rywtۙ YQ,H5vތu3\4l. ApH Q! ^^JcO:Zcܜ*^'@ 9 H(Ճ_"ѠJ 51'b*}It=q<mT2'̒Ӌ߾⊷}r^]ww}~y|>-v.?pk$uT Z ̀$KNSk !, yg##?i|ž*R=+8;9;/xwwoM`zs%%u-#mKdžlFSa }sp:/w{*~j 8_N7w`x`"M=yڴP^2N[[rϟ8v ~l}-l(z~~W+WL׷ǵ+y\7$ QbifzӵLL[R/ .k<Wr\CmK`E`hQ:!?B,zYT 5(e^U4RX`R%;(@LTFPA_# zeGvvt F)Nij\YXjvraܳ۞e7UCk=4T}9Ÿ [m6{ { HfUR>L\(OBľ j/J/UydWWOZk4>LP Uy VdC*Vu\b-.X6x:}75zOuihiȺHw99a#RUSUt0ȖCԤ@ןf$H.䅨ӓ;)h2I*ig3s2=fDHQg!Wkk!UBe@\}Q©ԉ,\Ǐ?=?r}>$}nR7>'v`u+Fّw;|ta|Ѕ:|Rs\&,vhowuҍ7ãt[4[u><ͥm8-.w̨ؖ'=,Δ!o_ZWAۑLyuuEyV6YTC7pzY:'VPH.]o7ן1S]U*|5`Urȧ/߁p&M6OJ:T=^Nj |y+?Of(v mV#ׄĨDZ_KUcWOys!f/:83oـOd@xC,,cD,JqKNƈ骳y-*Huۮ^Gu܈h.^c?Te]ڒS̏*)Axfηغ-KR.e4[˭i|&|#׃ƲacQidnq`b#aAYǰ;V6{x:WBb_{XoC#68@OVG"(oƍ6G~ `ķЭNHA%(+k*+ TUی,b4mt "t{:tLN%X8ƢQJv.P٫& >7+JJibllk Z #Ţwu(=UK\UV5_kg~zY_ꇴzf~-Ϳ޿Ή$G|G:][_ƖZѰo4}TߺJ&%?Ёi~T.3`6a~X0e8\g̢=wp'Z%s.*;5U_E#E.F_ëB킣pQ?oIUr":m6|J6볗?; X|NbcFtކ=qu5َwFAܨSX4bF@(B܎l0DX~74U xGjBFꀱLFFkRodm6Yku^jL[l`27S7ӷXاU&4e\mAm̓55kVN]qx=-&_;ԌŞ([~Ht%yg RsVѕnScKMjg4ZefNX4mXY{Ri&(fooOo F@灔O)˔wr%Kyۤ1]:2Kww\܌$@_tGpp:ͻ$ }῭G1>FNUQ{n&9\,B4sn%y:}J$agKNqIÙ7d5Z2!!«Y 6ĴÜ2,r_gR R?ScE2wfS1quH5*uJ.}S\E>][0 ;ٿ=kL]6? ADsn߻HݓvT&k} _3M~Z\Zz=sc{J?~Hߟ\/O220 Fk7 'Qn(|=%BhuXŒ^pp<šۂAvo`H Je}I䁙!u^`*].?EZ?XS/iPMEb8|y;3(b1EEEh8eZjtflG7Dc (5 !!`r'D){{"/:Ny]o5<[y`kft4{Ujh\7nnÕu4\wsã&pk ǥxXq[-:UUEcBPWoaR\ڃV|P5&ԇ&i+o4$!zI'CcA'a:F7TN]MR:\X3<<Ȥ~2Wv bD @"i.XD` O[ {6%rmkA{7ye*Az\7C*S*->z =h;"-X+4%gR ‰xNhՍ_v膶7 1W_]9'"k 7@":rTRp~W<^k Ja{ӧէη8_Sk%]^ͼ,k3)3T{>sfl?Ӄ(;(d`:I{8^ g2鹰5?j.L&B]B_}oѐN`UC (ap7VbIc}^{ э՚;3+ʧ;-|^ 5|9@gCuHbUԞl׮Rg.z ?aUNTf2~j>Ly@/AOSSvF6F c2Dn Nd?\`#Ήl Jxys̘Gf6؄ iP=v}XOp>=G=mc9[ub!.vh02^4H؃*F;iZllm'X u>@fb8TMB_,^akiLbR7ݜn<=xjݴ0 E~ԫ˅r"&!;[\"q邢:v=Fֳpsm%Gku竮]_;RFי")gʵLZVs+'ίWq.[~ _D$:B ڕ^(*G(sEEѥQGkDQ8TLZzBr~~" x~z^ՄMVRg$#e}q2aY!@ȣD0avA"p#d7>b4*c̴DC SHfv$a:G%ZRRUK@@!yڪez.څąW(.WzUb']-6hhn6WSٵ7u+YCȲ+md G6ˑd6t7 %$f3m6cHkdݦntgӦet3ms ?ys=W "AaAP8貖SzU䌘Yau->db(,XXf)Y 9!%Z *CPm{#jֈ_U__7ϰ+JǙ?,*gL_:`G;c'5\]A_ =~sEvA_QYP* ] hes8pYߜ;Up኷b\79.iqZ{ <թmAM{j-ПN۴6L~!%$Ƃ[L%_:M榙_N'pih0bu"M|0Gi̶au]n0:֖[u Gނ ,)+ouw/AmYx㲥~#jy9Wwb=eZru`%$/g,1*|PE?p+φY9C}[ɾ9Jl,Gz0^h>`VuT9U?;Qd_b6/`򖶰fS? (>b ߬UU߷|?om֠]]ӸML}n|ŵai0X_: ԟ3rSNic)+m}.{KTU5*Z *~_bSlvbADجn-/}KB.Fė>ա@[҄]oi=#E'ӗ5^Uў-1eo2,~_ZUlg~Q6h]`a1T,v۞z#eni㺸vb!e)E/J0fiY7K.uoTJ[X\ !~O#`ɾ2n1LId*6IaXYRz¢G2D ~]cOo ̹EקynqugTĔ"%~t%(f,|n GbiyTC t| `fGm7mx [/ZPŦ,&jbQwZK%w6"x-8`KZfPmMEȼ ј&+O7mih*/--ond[YYQAhkN7lΦӢ%O춢|Yl;ӍEM?D77{rf(c?):Ѩm호$ͳ7E6;+nwCX><[cx @mᘇ9TިFeU)ދ|e9?|߯oo @0˔[WXپ`X75nݛ4/9+)Ыo^wo CUt'(y n \Nޔ6 ]XA4G?|* ?-Ҿx h||pJȓ}˵:Wн!"ÓDkr7,)"KDeDPSDhVxl7D]IBm%Mao9"\7ET/QCmGGo_yU!Z?CuDElADF }D}HD۷ݿu=ۻhy7u^6YW~At?'!#}_:D1rt_j|-_[弁[EFj%χNV$tE(P%2~2ѓYo<*{5@CǕ5>:h2ȫ(EAy\n o kujZ*֡rt:TyU^CWP:Ty9_EE9bQ.[ooo3|I2aa;re"c/:_+ +7oɫ(G^-˗H jZmQ QA2t&x!Ozh B[!A E(Aahr 'TMc#jB ^ a%ACM">IazrQBۈ(r2N!? JxVDžE5TOFƵ!ma{TpHx<.JzC;n 1_+àT/ReD<'jx* JK}cRݗJ%sG$He[J" *p`3Jr$ƕ v'2ae[f0GdJI"& %'307yh053x?94I FLRN'ƐA+J6a:Qnj%>QR4J7+#'{Q-:\2R :<4>N+09(񃉡8MV"LI1 EWPd&t~%l:#&L|I~U/ډ#Ē:Əa[Z׫m^8oA1((b'*bLi`vI~ۯ*m_xM~mzGStd +8-4 :5ȯ"-$2y#.=%˯5\r\*$yU+ӕd}rYeKL I~Z>A^~P{5z )OLŒ>^l离7g6,Yːxbe9xu^W VB~򳐟K0Li̹iCXCx])?\ ;`| Y"O >"sܐ=90{A]t3œn7 'w )ȝгF;AEnNOclὈw‡NԉJS ^ࣀdr'19Q؈"&J&!ft7G(cZaF]a9 ydB(` `WrWQ%lyS QtW -v{| m &Ǥ+z9V= 8 xp`-"RD,mu5ᠠMkTBE9kPM5@5pE͆< ] + QʨBJh   Ej! VCRP5TCҟ3o\|3D6GgȾiىi[z @tyvD4S=YGj>^ F='qy'%ޖdіS-/\lbxE1 D h]1 .v#/8*piԵ4ݦvmڵ۴iݦݦ/Z0GTt&`j )fel' 'p9mYc3:6y;cK5JB\OwSJVh{ ,3a!jXg72T ~Pb-bch4uFHF~Y4%yNto8ČД]zީ׆w26 +Sz;Rv@aaTkw*.1d?BS3a \rIYbs'5캤c'O`Yy4gܓݶkŊ g*{Qs RsVZIقcRkV./8K;gˉ#r[ZVp깅{ޥ ޮK^oVgٰTgdΈtdUǛcxBkx'YqWڌΥ#8``QԱ}2K+aa :aSNRϑ;㧎%:ҵ}ץ#xtO?{’&ݥjy^}Gw..𼺣"/-߱[tro2&zs|0?Uo2xԪت(Q(!oUE-NήD'it:`4?giJg^"q~`6s -|z G/rKo=#@*\z`nfNjVr endstream endobj 351 0 obj 23430 endobj 162 0 obj <> endobj 352 0 obj <> endobj 353 0 obj <> stream xy`T0~ιwg2LdB % k"&hL@@@-P4.qŽ.{PյZk ť֨m#Jf~Ϲw&l=]= !=Zg?O-o"g08!ps߼OR"zV/>z?w Bk[hD Q^\%P,9KκxEP9oY4/YVY_?]U[~!-+_pa֍"E+F|B70>/ˆ}#`° T No08hY6É\"x}~x^0DcDqR@(JP)JWTVUe5(N4yJSsK'K8nAEȇP`,Vώrp!fwHԏE (wѭгI栿1aR8zrG*tN -( ==@5rmXdAC{DL0BjsZQ=[5ڃ>F~1,&< +i4yncdd=sr^0Ip]kѽh;z ?wk0~9E#7e'dͽ-.AeՆ:<4m ]FOwb?> _ć@ỉy;7fssܟcnanU)d8gKݯB77g|Bߡa V,Vb ~2n邧vs/zſ( G%琥d]go&ɌcÛ>¼|Fzvîadf?V RQXٝV#3 0'4%078} Ta+ 6/kz|q?)?_owGc# "udDZ;N:"r YKY _ɯd'y|c (bԌ2i`*L 3bf gnav3bOc[{QlVZ){%^3>sTIRHidf8>As:|i_3/`J|hقxU*,eHqSG*"oIś 0RpMN`v0`"Ah,b7zFo3"<']@Bob:#ėœtWD')@'a>`^y@a0~Ŭܕ%MؿS f i~gg/E?eGo2v\2 !cwVan!](~'?Ȅr玨dB,3sk Y հg}_F vplU:^wg:~t橁6f~]zvpǶL>doa eߠN/-6{ʜAOa?k1C6uN4Qa{rMTNFm =qfg͝sSf4N0>SW[]UYQ^.-I D<C]Nfyd4uZZT (n zXa45x@G:-p"3ELqLPCI* 5%N S!9Y̡Lzhx564|X^2UWZjj*+@)R K5.l4s o47MϪC22/貘Tj) '[fYPV-*t<MKvZD]}e7n/^"$='5*ߣ>Ss#G(tHW79x#iBMRr%Ȝ47vua!ÐB7.Awl1DJ c(*fl1` >3+zj+x4`p{=P  RzYOUi9/9YIkST84}bƜS= Ȅ5o'ԔbuLה*{KiFSs:YŠq^Ӕak]֔ +c+2Ԉ7lt<;ll"٧mI#!dz#M6Z"҄ouS\u=An?5<7424;"xs:C!Ȥ6 -ˇ# glP4.jDRѲLUX8Yva-TJU,_ʊX\Rvq(O>R5-[ieeؚnlj8he6 KgXՔ9XQ߳O/-z LfPΉ@hޔX%/Jg6_fE֗zq$*-=? L^ M/ذWxE7^ݑ1FQ&ږY9Cfy(6sd )oK^llJ07H9%3\1a ?ä5}WmϾ}t|^KibhE,VF Zj kuV-x,6#E}^oE6jk \RW˕4E׼OkhlO*O^+K⤫œ{ n,ST0@ 0EbrAR xyȏ'U8|ُ/6%Mןs6ߢ~18?Jt~eљ޿k5ET VL.E,Șg_#G}DAK7 I ^HKG>p[y 5"&Z`b`/2=Seq{M]r hnwd@aQQ:M˸A(=ˣ'Hلœ"!-.ϦFtVq>h0D<#Z5e ,Z$S*K͇o}qYCyGsv3+"?v8ѥxг'oPbyñG_)Vlc5}|| @}rR`Zq큻5z6Hj\Eŷ.~xIǫ- W[Ln;K"-ZWj7S4]t(wE]h0y|guu vaQZҒЦ<nځ{k %߱p3d-j6:CrugND"?zfbw0Ŷ_̟~̉^?>ݳkn{f߀b(rcX2^}~ NG<8_ʯ'[ј%#=_FN7 ' R`b/)ۆǴsxy dp F%xs#"=yC7GVHcsKa|ָ#&EDl%3|}97e}ŁզjGqbrin0WMVdDf Wn0Y4Q4 o!#P\ R#Lz nCxܦm:rD|[&YBd>s ˃QƮT< Ga#]&sS?&b/׿d@=A5@JL{;R~e ZHC^=yaNtAOeM̂骹5#%>撬Fe@N4Mpo4Dgga:oXu⠂\@#U^6O‘7ea.*l>EEL#}2T!ДUWq[ ZZ桬F׫iy5a&R:CLaoilF. kNwR6 z֐ h[yШe4|T%iyqZ>e&K)wb۳vl i?S(=̵M؉Zƃv_o׹},;./U$-PIe=;<I˾t DZ(m1IA  4Q ֚l>'DKi/'ICȣagH_ *J/A_̏&L0` &` Sۋ J3yکeڬRo1xp_X1h(S7"|Fhۗ;;ω,_n֤sN].ZXvu];;ޞ]9JM| v=KXK$JtΫ|L!/ՠ[4T1uz|Kl?e=r`=3%?2$3#]C]3]م{qɋm[wg~S~J-ޙ37UAB]f0n8qg_+>-_o[X{َl˨70y hB-(Jb 3lr¦bS '5#!JҒ8a˜ȇZC(ԣ~Ȏ4ϾBxS|VO/x9{>oWQ1EЏqR\^_^~ah]rjCv%&GnFGUV*bG2h %iVLlPBvvoEeXШIR.5J`ĥ#h7ev}~^wWAI!P;A,{JllPSN%Py7jPGu3(d0@ɀ=Y43Qxv07ĞWʺJтX*K+j$2%l>KBVXr)+;\/Al<.^XfwϹ}Γfߝ#éq]KgL;"5-WN= >ޯs )4 +[ݜ) 2FΚpy՚gÑÓ~@?xFL2DQʖWF[jb3jm#⏄sHM94 X8x5ps"MX5:ݞxvvp~'2#"2 {vD#%bCN#,:- ,evKeEioJ@h3KOs Zl~Gxq$τً%$nUMUI.;u`")%EZN6G} k+CN빶gjL׾s}حo?j6]h/VlXk?jorf 9k鷦K?p|o9ιW'/Êk[(!ixh',`j %ep1Rݶx5:i4򘔋mWU}`Zpj6ngOP&~n?%4$&H,KMln? uGXXڜEyZn=N˵֤Ǔ'bS$Xmj kB cܝ*X&^`FaH; .Wԋ]6qx{R>S#3v?c74"&D⛝C$*狜^=z+Ny2Y3gޟXuzeF 7G‰N8qC`NMmmC%"~W4hxp.rAפf`m<=~bW9sTKŖwƃt|M&ݨQl"`C>SB!-BRG%M4q1iCT- 3D4OC@@Gy> rZn?zЈe WDNh|2*ǃ?td:~x\՘ Lu:,BW0<9„+#VGupPkSa\CU&SfXMĶtU&3m,x~W)~#Η8J \ARZT7I3 59P7K΂}$ʂsimUMmLSCa&84 -vRY3JǑwwRc>pVKXEJϔ Ǡ$td}ToppV5gXjxEol41;)lvg((ffYWL&'kUf[]TxYeo?H'x<_9=K:%prcA,9);a砉 J4ig>|ݜ\~\7:6Ǫے(Yp|*5'@o铔^+Koo2/$.);a}5G)t b, Pc/&  b=*/1'5ӚE)l])/ E_!gRkXgz|֥Iړ|+W8oq>|Z.]p.r))iL)IO8mGט)Md6k-~ŊB~>(4ZBjuV+Z֯cth8>D[v _ bLaf>׋Au(cb^&x[SkY-/XYQO1aD AxC^@06z[D.JBЙXNtzuu԰-j,Waz&o[z jqFS[oFզM1p5P5*BhX,mc1b2nb&{a]Mm r{pupwδ{ LJi'cܒ?SF{ /d)QnnH]@H>"Q3wt_H1@Yh5<b}SaN#mf݉lO'vaI B:=su6}4K7hHxM,FR}2rWwL^`ky1S0 ۬"¦ 2N!u{+{d^*rO^u›Hաz\UT癆'zxW{u (ZesT(huFl9[4y= *Pt%N׊2Os L?]1ss)<ؘ -VRuh*UpG#"7ayAj1Fj$X\"X{%Ɏ/G6ASȈϘl1S5Z/ت͊|2\YDqa__?7|evk;\nBguW5c %FEXmUgnJp}:([)g/^KƬc}A;&Ǩkb~NTٻR.Kq y6^1v5| g3Uheجv2ɿlx寿\ux3׻g?lߛsG׹-ӵߧ~?GP/xNgn\T|i퉝Ŭh=P83g&V(.N߁67+ٜ~Fɧ%|6ɶϢh:G JgCTk8`hg3X䍥8UK"h4j5 eZ!ym#P2%<<{wyZyX[D Rh<8Py~Dq 5! C:2[GfWޕ д< A 8o LI~MV}jldh+{4Ww>-Nl(|X?ũgo {^x"y=xᔛCͼ}Nu-EF\,Y]̙ppAju)ەǶV ͉tŗ8m-eqsYsżļOAZ? (e,n{6&bØ(ZTKri"IxE/BA0h!YLG#%&Kp%Kr%l{HwEEoGFsQe%VT]a;,sg]CeiLT#PEYQUqE{nrϨ G? PY1փoR jOjOo ֟ЛzMeSMiL_^<8fd6k<0Cy 3ξ]jnetDoʤLLG$*_ T農 /ފ:K@c A* 'Rmiԩ`Gr^ U[ _ |ASX(i(P>90KT>0s~s8oo!Iڟ+sYF $ӥڄY! MXH&NCnG!- ;C84)9X2⡳u8ɔP?)#k#K@AQ9,?%(8zd.UC22_V}eTgϤS9z8.*(KqX飫*.J-ѕdX&Sߓq=-1ݱؾ$+cP Ky;Mf? h(,h8 vl?;9 TYw%%Fᮑ!;vV?[1Qn, .@j^m!.1uGߡB>KuK`}\ZYW c1!|$yEӏd /.3OKN89Dzg͗mW< e7RKUJA:N;#xnDxJ:Wc<-&D֠'3յ]}\< l k\u{ߔXēxE{^9Wp$X$G̪ fV/)^T% #' a)M42%)Ot'DF\F6{1hɸRrʄh*шE y⏰b܆`?~41ZpP4Дi&(Vfǃ4^D qK['6Lp 8]8Yʮ^zg]J:,";\e 'oܥ`ܮܹw]g|ujE>O[ed/E"zLD{oh*شw= $j)3eXGFdFd5LnS)8PG!ƃD9sV`Wh[RYV^ムštz) _`]vioKz](u!PWP6)Pc25v@.6;HvH&;.߶3-#پ 8p )h(ѐw R1?]rЏﰋBV+h$cJ?Y-RɭOsZuwGqq.NPq:KFzlj+G4S41br,~߭7;NF9;DZ/Xxqu?Z݂[͎N%d}kwydy%m׹owwY\jq #}>5??7[$izgX@0R\^Ty{q0u~nybeRr:؊P1Px]PVMlq! B ` J'łKrjB^m_A2Rp.\μN] ܜ^SY YHNjvzW7$E*zWn䰴 sĂe)-(. g(MZ'% Lyq;& !StCt5Hr v>P }`NwASZzb65>n^H%bQlMH Axv84x&v+E~+i>{ة_N,ns5$aWM.p_bu[|6y}n|YbݵըfP`BLO庩HR>hdED,BaheNK&2%#RT ,.PLefC . *0a%P5 M uVx/KG[B_8x;c9&p TUA9 UJlnM.BU8T}.7 i,U2Ch/65c9 ; ; POp HX֙7dfT?~i9TmUWFBfZci0~|CJ 3Y̡ "yPȅīۉZ*qȫasvlo^%rPu5Pڒ>c RY|RJ78u Y}̹ov5I4ڣ~.).}R#^j,k(Q>ϥ~W9(!G|\>rt Q>@ y.㓃^Ol('@IӉC~iQ꟔7N(9eGi4M _x>22'7;I.= 0!g1&{'%Rb; j,Q+4fI$Vk(atZZW 5.ERy-ڿsjM .lp40[8zgoH!< A[~GǮZk~֐a[5bZ&NkRks:AW3W7NiQkY5t:vHV=U@+Јwg?..MD 8ݛ=$(&]Ff/ˆ ՉV5F֠mVܼꆭ6(=cj0we%ntF&x{G z'?\ ìsAmTmV#j$l==G~0OkTD˳ի)WqoJ_` `j2Tq,o5 FhDV2Z-%q?Pgm h!ÍA|#Z ћF m"f[;<%F ʠR:Q٭\dH)k!9]g#G?yboBzd˦_6Phla a'>'_NJJ=3^84tXg9x9gȜ6[1Q;-.0{d$CNKn;L OYJM{k>߯Y}%]p>\֠2,>W6PܤUqPysSԨLE)%oӯSQ$w>>zRx];7uvԆթm{*V=6m~/<~9+sm_yXڠrkG\lm~~/of Oj{WiTO +oڦ{/psWA^BYsRMF!4*zH4HA 3H35FR-1ilSlblu {t[5( 9qE>~S#O$A3>}=GZ/cHbYZV ވfEZE kQ?U`]ɮ78QKi-E-h}ANbA b&`$M&mZnZgߴŤ0R؁SZ q;VP\79D ]PYg 6JF+%ǣjRjJ`c䥫l55xM}-as .?a|/pTݵt{gb*+>[Y4+|kˇ/:rG_}Wc]d03>bG)f ~ĵ [;(ԞsRIc;5PҚ.֐鐞p:Nchӳe1bN:W*v " F*լip6f:{gf3l6~w蓮/Xnn éL<@c]qD""U T6|+|7>wq##l Y5{r*;\.] lPP _4C;wnVTck$ޤb7{sGF+~sZ?QqM?ܵW,&3Wc_? }?dbGʸÔ)S  { JdC v%_L<ԂPm\J%)\Tܐ6[S87nh}R%Wps\]_N_\VZZ\5{߂FËJ ]Ǚ984<$GWl ֋%/(JD*Ɂ۰Dj#imR$"[~|EZ*` #-3{cOY' @ski$ PRr3@Uӆr!E%K*kt3ʧ1ՋЂ55U%%;JߨP2r&_ 8[hu:[=N,նtxl-B0 |Եpc}ϒ/Q=#*`SM[u5(jDMe(Fh_aO%ƆÅ5Je?k[|G܃>Cܷ~|}QJ, o+A98 nyp%Die2cO5E awv̟$Aɴ6Ϭ)YgejWlB}=fˇ7_x%nd^z}ʤҞdIvx׹/o8u{=^/Z{ Pp=.Rz1:B7tb;ԸBu͚fwkrfhǕf ( `ڀٜ.LIR.v贚DH#P^.kQh,0W#*lN&ͤ5]mZAimv_E*p[ ^"?8PYV]@% 0n1#Mp ;o { N*3֦.V$0R #d2>MB‡:A\d%w8gќn&+Ѽaqo_L;x77$i3^xImpA0F3Yޭyd Dͪ|CY0\Peiƀ^Ȯ¸$wdfbb652{t嬊''Hݒ=}g۹iV K:: +Uq暮+ahd 5n2R㥥/nj]=)xݍ'?'Uy{%۠m}ƶ.IٰNӛY\jNx@"Cp["݅<{ˮ_kuڏ+P[ RM%y2_̗HEÑ%\`JJ+ԥ##h4p1>+.+7&٬(*(,){2 F>ޓL!BfwiiK%z+#0>cGm{w<|!4'qM'.#iT:bRiperK9558cOy~f.]35'a@&rO6^tL1!k QIIW]qt8n8"hu$8)rY }q?J?]H%'ձ.egJf :9w|$N##ڦ6:M'oLŸOٴjޱ1E\^,W7ZˊE[VuQbA֮s!&ŧqdۨju~5vdʜͱMM1{R|̝9<F~x7@nY&.3p&P{%R\w=o*TjsU%bU*WU*^UR_fZjL4ַ]ȺThxQTD2DtKFHud.9Hf[cx^o9̦P BpM0ևBE`JWMP_TIVURd:t+HTղek-khׇV׉rn96͂R !!7[_W'$ h$`}_`4Dʃ,OtEEd:V]^OJ |SJ,J8؋NY#ޝF2EYBɀ.=4wp/1-#_@I$ܶζUYo.KiixVar2YPK:j]tYFF-bH\&waj_z.>C{3F}}[wouo1C?3sR.̄Ky<:\~J9%+eh75tG>v] U‚9m­.+7(C8&A'3X^"{~ HS 0wN(=%LI-5 !Is1?[?פAkJϏGv7Z/517XLM&G^|qiϢj 'סnvS+ٯXfU~g2ϱl>9߉4eZ%`i!vR ̌(;h}CsHolwa}zQ\汗N=޹52']'ȡS9n}`5kSLi4}>9)0acO}GO9u@} m[ > . j$ϛҋ*("*7z83s/Dm8aeRH*X@}ߏ>=Fcѷg/&t?#tŚjR!MLW+,[[k*_uy1\6-zBsttxX;Pyg땿ӝǯĊόMFtʸjVFwKQ#ay33OK_@4DZ,Y={WQ5-krj Wev}5 bGiǡ >mׯhMԪm^ ۤP!ʈFY(M}OzL{|u%ttğ=sS}:w?<٣7= >g8!<ʮ#H D^x~19F3l[Z{7Zo6a=f5fbdp$k, QVAS +kQMbd =_kULS^>\yc'a#{;z>fPxmw1n2KZC^LBk&'6&3 n la/ȳђOz[㉭8C>|YlZ[س0iFBބ04*$G+_|^j1E?h~ ϋ45~C3c4^^~I(p w)XK$]\]$# pӑWJe:i]p<7ΝTg'W,'Cx#sҕ鹣0VB_T{++Wsn*2U~9uj##gTwNFvG㪑>h=M& d+WNÈW@VzdB DTEů%;n@"<@F\K4Iv S z{ڋT:TE6@m1._zkƱe$gM6iy}wծ{+oe~j:6(x MR!W풖߻eneL,xlFNЂwCᲸ%U5Fvbż҈I-{b.[yyH8'K;C/~ y#KJ tip*ZUmŻg^LyH$K&%tXWR a |I@aL`Jb*>DklS\6!]η0&&].R+kT+UשvROmwRw{Z n.ļ63n=fV8$tEA*p:;Bᰀ! oU0LwԦOKZFr a3Y!^*/{6ٓ|ԿE(GG7u]nKߕe2v^9:I2'##9GSc/7O~cfgQjЁ:ϯA#g d;)0X* gz|L*|kzUe6\f+1Q` que 1ڴs{R}u%vp# )|edCY+޶_Xg>J 䳠iZ8=Te-޿xQ]G9{61r=ZJ6ͳ-gfp:ıZyԿu2(0&tywqFKvhL b[@1;rP`\na]nDUzT!oXzFMhҹYHGr'aB-t%5XSo?,IF'vu;t|AS' {Ժ>c]7~X=WsQf?Ǧ}"ֽqOBeb{ԑ&Y\'丬or9`9u˚ӹ%)Qd{68CtI,Y E5৙;M+D?MLAaQf1q܇Eqd/A7 r-ڂ&I8ɐ"r8n: 7 ,ِO%?yH$K8&5@Iq5^Bk , k(&]t*/#Cەrwf3vhSP9[];pFnH~v9X7hP3 ϻG̃}}Hq砯70H0RTQ_%|)_Ɨ|%?l[,C|Z5X`T('8 Ci[ښvu4 S> INjS4icf63 g(a AԄFMiXMx`rp3Yp8uN6\H92(s2z{ij $dN1{<$8dܹsF >m!}r$*)bJV>xJ#Nt:zO\\Tvq ru$L DQD qB]Gɩz.p"..!K{' tbgJ|^F@,.j7hcU&cUeyB;:dY_ƮO1h{0FNi/9tcjGo*x}/?z|f%O)zYhTx'nX;s'wI70u@>7J!GhpTKUff! *JLz]9g&޲ҸRh0~n 퐬 ٭6+ iJMTVcC-0P1z1LGG>/;.o4_G gwpps"y8s?e|Ⓢguo7٭M2dEϿļ/e""5B{{gSN!ALj&W/c9Dg)@{";եws~Tc'N:qD!5%?x8~<1~:<0p"@xK5+܀_;(ŒD4@31 @x8!N~ngvJ]ExsZN!ĵ@!Bm!0mAox!>D(BVoy~ ]BƜV!?P0BeGe-B.RUAyG*(_-|_"B!zf շ ԒAh߂FwD`D[\v#m@o<[C(m4|\IPܞS:':N.7*8 ߑY! 'ry9s t#$=^ Sp%$M i]q9?\\sr 9bȾHD|Zu ڋhmM)J!f1"Z a4@:v%Ia\wPBHo;!WGuC?&IDIȍ<JJ1]p_ZwRTn$O9f\R֖+@@Va5MR)n"u+B2SɹBh "M{RvZZnJ] t/Nh"-^ww*B~.Z ͕\vвeKޛ-y=}>: v{h^^>_жCwv>@9n%v%N6-~ vE";:󅴿|-ͤAS]t˸ϴZSIgm/?km{i;56V;wi $]NRi:!ہ⟾bey|e[7S\ߖ)o.~[f@\9ٿtI~qUe[ĈrԂݝ,-/+{z2ErK+nRה(&= m7]W,#f nmOwC\it=eb/z2@ic3ڻKѶW5 I@]=m@ѝ!mK_b1Ӌގ]mr}5+vtm 4pW7UgOTl+F[]3id/[$Js9ON*#'{Z-JZ i ݐKsnȵwO޶LmrQަ+wWoWFIhun`ޥU_iMu#2?g6Ս9);d/AC>>>`OǯD?&7^:62L̏;K2]2Wύe6U0bwI϶΋d*LPx+mʣZTUUWcMӗjcpt]x;f4^FGz(׍>ؕMUy3ѕ$ʄ(0NhZ. Z͋bH AT(vn =,:vЙ*kؼ9002_CN #0 "cec鱍c1ǘ0ǖ06S zyc-cZ$2[ٮ3 4`:0 |&6K >hRJ;u*<`vH;8G;X,Z;gx8=qN1 'M߮ቧ(3e`Aѐmb⦡QVqok#X5Cp-6Zмxӈ!]c|w+\ 1`Բa_$AzK8s]^ֻZ[cwz2Y~uZmj 0n~$60 < E@B(ܵw һ]C'Ev0.5[* r44F$K5uՁ׺Ӏ֯ uM*)VkQ1kR.  !'\BgZ]x2:o)M>B͔9QV hQ_ eir\g鯾 9Tۺd;h+2z;~~CpP^Ըj0 -^t6@Q*Y\DA_ Q&6+Q Q#%` 1̮4dhEB2C^-0 f34_ endstream endobj 354 0 obj 28000 endobj 203 0 obj <> endobj 355 0 obj <> endobj 356 0 obj <> stream x{ x3#YFIeYq6+ǎ$Nb%qcK"l9!lN&!M q%B4P'6]ׅBC)C < 隣gIs9ܳs#hgnkk/1nֆ\vj];;?|!!ݑw~AFq7 t^2xFs;ކpmǡvcH0" ;Z6@Уh7:ЉX}9 5נ2"qD*+Hf5ZTdr>by$ڏhVp?VCxn8n}8Wb?o5~t;p͠.Ԇ6a)zVTe01/\}hBSG}CF}LE؀ ЮFgx|5^x?<P ڀ:B@o*! p-mHGoPk39^yYҷc}^ytA١M J r9/ۛtgΞfZ̩&AjXJˤ)8Z׮#}U^AOH8"`*ITٱU7wB ū> 'rWyD @9@UK1PU '($Qq/N+ɵ- $Ew29{$ݒ.Ḹ<Cmq{E[[}WGf\8hwewc%Z80\e77"nz]hiy^Yk\ ʸ.X4rGV7ϧ:=c.*-SR&Șڈ۸^׻yxnLۗqUv*;:'CM5ml UV g׮i.'*aZ *DhP\;Gk]" X>ya /ܬ;VcU:6VZ&gwmuqklv,Z 66C3q/ߓ Z\fuhfc 9eQVS3N,sO:$;OVhwnN94 }VB9ʮ$e{ F9ů$sGu Hו7V*(+M fpo +a@ []˂F{LJ$,p}'BxڍͧYQkj~Typ80k'y㯄'$H;n 9vu1nc: pB'x(l#B&r^X$l$l%i`2a2ՐPg!΂?xC6i [{R7ΛhIHYY(<6h /Ƭc`ОDg@`t%"$ &/?w5].=0WrAP$QRR;bA -/סqhp.y"eUVhemZcd:*JAJ>5lwJ;*mHŖصX{i*9qaƥ=n[OL-Sl X6UVl嶈LP[RQo4\94z)T8E3F;q?,_A\{?./^Pݯo\_Hlxql fL633<ך ,uށbPYF%!ya }TJe,ovn\V2hHΣg6,.L/o%2DɑKWɭrRy /xqR\i08Ƀ>2ItaE); psqٮus3I3nnC2l-أajl7iD]d"ŋ޲;ݐImfuf옶RȔ uyZ)K9amfFh5JCb4ҍzo2̻Q^yo^l3o6o1"%~?7^ĖG(Are .bTGά= I%wϭtWL5T| is 2=.Q,)]rSұA/O&iJ!8f$+3῱A,np77^\(QiiVc*]Դ>*;Qز5RMS>^rgWT[ :™1a&uTZkl߬ԯ 7-Aʦ6 -3T٨/eJKZhHSm//Wi:ۙj PEf_]T83}WeRU,bϸe(Gq\{!~?ols>|~ N%CKjF@$iؑꥄf\ewZUUY[Y⮻O-*-пmhW fQ`f毥LOSun|bq떽] rmYLd)@D~*ˬˢFX)Kbl*eMq]ePP̉gST($`GȁdN`[Pp: ډr[A6㪥UT 6dc_2R-<g/.+[͋ fK.W;$j(nL?koLs?}-B+ft Yerzllm|yBD&K2 h:ZT3z~'E1u+XkWCHa^hY%CMҙW]M}w6sLŖ4G RZAi2hx9 XG YRƭѥ' CC^ 1!̚)~ݨtɿ/|=Qn.rLNb] $~B_4hVUgU:\ Yg~Ot.Md.wT>vܘs$)^|3դfle6q+J54:Kl33F_)QPp{dFnTJKӨs0}s_X ({d$'߇ȆT2'?'奖N/`2>Kpښt'uMkgqձ\r #]cQ_|ϕD믯g53#֐(C.Wm<\:UaY *ؚ5L R `{ ۫qE(9ZW.S7@Oղ߾sgz-L$uv[h߱t?oJ1HʿcTrA$8حʧ+ՒM / >j;TmIӓ{e*Iݝ4=FfpfcfX\>^q^]8fg VVLG1mqI# k,֍o}܉ Bh<h:BRUю:0$0Td/n  r_:[ stռM7c.kTTmi\cb`.+8-{$}3U[o*;V9x5<;+7A{ HdA7~˪7dP&g5NUqK4 s!k_c1ODD[!~KQWj~md6&*#}ee<2[ ښDeԛ\&gIz龱8TF6>W; *JsUźj2:O cGً?3 ̎q{rZhsF3 /%+WlxM/45Z;~lU3Xմ~ʳсT6VUZjZmU V/-=+Aw9K.B|`g)xEF(+јՓqq9Mq#lQڨҌV/\BO: $Iʼny1H^W\WS4'5OgMfmwLf~9,gmphY}ة12w? ;n H̊ŭx>"82|ޙﶉ/n-"Qb8%{OMk$[V]%/Z(deA2C&XTޱ 5m 5@pgpRQV(:Xv=uUطurx8pC zeVNo~O݁n㢙ov U<|SAN@C( I%r9LO6GhZQ+1Da DɎ$)SOfBSk 74}W8D$N.`F;C ,̵Z"tLvxnP6430h7Kyv?B9Ӣ%F^.j yb.YdDIfeN٪.h&o2snf۽"Svskє{f^ݟ}G1֟55ff~P߯KMi2IOş@,rчLEQuwFnHv:Tv]!8;7vpνLL$^+l{Y%+nyVZ#Pnn7){;7* s)G ܐ߈G\C!j gQ4k;3eJcNqn\FħASiySQ9gAw{vr/L(+I>KTr|e` t|<(?ɩV5ձ.~HM!tn[²gAF0s?ʡ1݌58)bnnCMJIH x,AanV5b:ݛnMb5tbN5JNFGVuU-y'Zg(l ,].'IM!3wWO$Q,5*|י|=҈&_/hägX+M֛XX%jnaBjB^Mѕ:"W+J:ob:]u+ɤ ̯,nɽn?.,qvLT3,8o]tWvt{v&;eel[ +{*?-J=N[__ 洹G ;,שY?:*yB}LxGP2_=pHY$@4"c ʞ jQ=fEմ!(hFH WK u!YB[R,@HGH;#iDHۍ!2MDȼo=R.F+9_#4h%` Lȋ0(WhPŀ-)V)LHMu-*M@4cT̠tI&VȨ`Y_b #7NN`j^A{A6E o 0g 2P:#jNA1=,AQK!n`%5.:&*$adT{yXxdBDOɻ IxXxV*`qRDHAuğJxXO 0#Mc^:! ʐ<L?a3e^V 0Wӈ>a;@ Q M0W] 0ϲi=r{K*xw 0_~ד\~nn1}p`h3ƕ Fb=9ܲ^nMOWwl[ ntTGzږv GErrso .yy@~|+R`!. rm`g(tpH_kv^1ܺ_kE h Dra.GVŀK \_Nnx(@΁6E#}=1"{N~uuˀ:71Ŏy};A:z0z".9@N.END'KۉcλHW FE{`Ԏm90ǸF0;. wؑӗYN@_03:5$C Q=.(CmB=⮠0V~U|(@鸊VrbWQ<.cp2ړ'UhNġro{G9@Yzˡ5B@[xF{;i/v%^PH!:ވ :7W.yX_o]1Hx WBXb3"V9\kS;yYDVe^6u?< ڡ5 TQϝbGA?W2wKa^[|$K!(߯:Vo&ug(QG0J;/1Xp6mHDk<=  %$ "̂+&^ʂ^^>gHҪ*.I%u 99$Ĵ}.cm,\E<@,IK"0;x̾ ?]ӈWf&j D59988Bݼh!y :oY߳xb`1 v6iT{'uv!1J$ V^@w*p%=oHX5>W%exևb>.wڏ8)n:l>xÌpp0}=W =+=/U> F#fk11GԚGx#[#ĭEߣoFgt|Oc? .\SSTéo>hwmx{}H,> endobj 358 0 obj <> endobj 359 0 obj <> stream x{ |TEW^$}tNҝ%d#@’ HhC .3ꨣ3s]^gnp<32.3Ψ  _'!(~>UWu 1"N÷um3y%tmPzLj̱kmX/N:n_c^&wvqϦD1e=*,(?r WxdyGP. tuu/Q.yE_Tj"g A(PQ9~U1#"fHV BL|Iȳ5Eў%ނaZ:Q=H;&v#KwH釘8drvz Qh݋+Wh?;D^_bH%;ItXɥ7XX%ȏVv-/y5 !`x.-'ӔGm)cw)n ?~::H_V^lt'=JB¯#VnGY4sHpP^Nhyi%&2z*ƒZXw#wP ba{7ߓfLecl6{RJ+MJ&^I~ZGp=/OJVitt|r+s-A"fƞd1[kBxwc^^C,a?faD|^p0_ʧ4>{b|ߓK[JUDZ#?"U+O*C ~ |OTB͘%NWaa}Ɯmdc?daOٛ,$HOS+Lє_CC'Yo }nF=D"➅El{}*)JgrIRJ[>*W*3l :7qNSid_H )Bi% }y,P" S6!8ڙw>3CR0*l g'τ_ vJň˅SWD0V7#X?Ӈ!-݆_J ezVn&4COBd~0V:ˇY}>c '%::Mc7 I0" 0%8oW[t7;AM^mBav =#(SK3X2͟H =& ;}^}'-"ƾ`QnA_y ydr\ |$ywӏʡ>~Y'>͗O)ɸcT&Rh ^DIJz݊scЏýJDpRC! qK43g1JCaPoj(3tCPQMyXnXp~ɷyKeEJ! Z_n O 'BӡCO~;P_7?}Go%{5t-ϱߒwgb1\z ]X184iQNqЛh?@#ƶP ;;z4q>J5YIN|i_KacPlǤ25وS3͢zltS ,[FCF̏Jv{%8Ӯʟi)6}K/jmY8ow̚ӧM(/KK]Ey9ljϚ<)3#=-5%9)1!cDMF"K}j0Ts*|AU >As746lj ՔN5x!PDž@J(ĠpژA 2uF_ F[~KI1 Z!FC :Y,&)zP"s f8BPm.jolt8:J˹&Hκ`KP &AЭ`] hevvwlʝ#ކ`+xB}M[3]i=*/uܷ}bRl߮٠bpP";y25su +H;22cѨZtΎΆIIk隚~~KI->2q`(ۄ$ԹԼx|:9aTTx@?vuM> X`ToACͩ:MXvOϯk6Ob,>&]`Q S=>媒agMEvtvckE푲Jk2Hs:kI^[vw9ϊ9ogKIl\_d)ions6/ZѮ6sۼR}x.LILY"W+B5k=l2#E Sgm9p|Nᓼu V/8|{]2V%+vBWКETcrBNJ]R\ q)OmiLGڮdI;>YlvF"^yjD#&SsӘlc'%ljԜㅜ;= )O[pl5q⛚LM#[,龈!"; KۃF1~+(l16tDMlsg;!<'A swMt::a?UH\7Atۊxkׁn2tgVkl:{oWpxjs: )}ct8ܭٷu .׳j@ :͋5vsۊ6"%CxupꗴO)b%-[g M4C2N.iPNd1NʲeRN2J77_Zh;U`f֌py*x:Ϊ򡳚ΐɏh*ULqNy]%b2G?b&?'/X57>S45؍hj52>J"iX]ZYqqaVR^O9LҡDаYl;G%D{3j &-5k7&I6O\|kq ݵyoz@lZ MIruw%Lwo?d %~ܖ"tE ӧO}!*ЪMl*GΫ̩(Osf")SNRQϓ$#^x[rRjJE}sfhՕ-KU8=)g;ykVL,_>s=\vJsbffڒZ1d: /.')IxDw"G+3HQQsRjϱ%Q>ΉѢyb!hJQJ)ٙZ%LqĤԱɚK47V57F)S(ۡ,K/hlb55S4c&f)rcZR*)ߦH 1tW"\DԈPشjq"?}k5h[g1ZENX2Ov-HuF!QvVd.tuu%5[^~5ZTsd1"X3Gsl <ZV&C!x]`<|!<@Xw[~ BpNjs".CwCeeutQa9yOm0x;NxX>m6SmO"5ڝVբw-?͉S4Z"=ǿYwͅ5};$ҲZn4$hH4 1ѩ))(q`}L:Ď1e(ɰZlm[mvژ-5wXvXUŷՌ%%O撧9c vʏEϋ-,Ec v'ު#)YMz;КrSTUIH;qz+3s5-0Vz;#}ǃ3-/,bѿ>KJ[:e8'SfNN_g*1cIYRoүoNz;CGIt_ g匛bl2J =I=ie\f_׾aѓM9:1'YT]s͚]|,4,!K\ś&ŴY,5Ҵ*^&Uى5$Y*qscm#Ť8lYÒoE69+<ߙSy,EglcӒ5g=/QJb*sFN ~ g)qH\84Qw\d9,KKwx'Dr8-rgȇ [Bΐ:V>3*k/FBi*p`ѧCɨ \y<.LJUYӲ B<Wqrg<5eIrYofq6ھ|y;nL]l0efgNTcR-h*{9۩Ys5[3k ?k8RW=eiΝc$YssƦmAj$x08&SBwIuHwFpKY?߿;"[C')-;_ld]UGkx敃KG ]vuP,O8hVaJYW`eʦ-έ']ܬQYsӠl!16 _bUayܪ;9px#|;ݬ0{qjj~UE%RznyKߌ:jy/Q~0eRn*6/:  1s**MF79s ܳM7[ٗNK!ZF$4{z'[=Grj*V ).S#ŚJUOy'VK+-znBu%)#yֶJy-vw\$;EWy@Scs-*#FZ,R)MxJeTr\cKdod3QR̙5T-2 q!Ë]f%ߑ?`kM7϶ӶmsMRlΚ^Vx* lpVVi٭ N{㧎M>py\Mo-u]c{`9M,wxYb<͓F4-G窞;".1^#(CҽS6EsZ*{x2'ܫȋ;7r l ") l2Iy^cj5Gs27TL.FOy⼽J?uɎWdw#Wyv@?0SɷQ!3kٖDocQ?W bw䍰>3Gs'rٹ hZ%hZM&kq։/o Ctɂe{BDrXXG}<\,EՊߙ ,!e~cM vrJOo[Y< ?Si?qċܩce%vwދG^xvo.).(XO34~gJ#?l[Wse@-=@Wh׋ ?wFp<~ןXôP?A> ~dD,[5Df3Dqߵ }F5t=Fnv RP&jJ>sHeo(oCfک2xoeT_ S]6R貉~,Zy_%ROuYr. KJ ge#%tD]]6S_(.ǰ2SdpŚ$]V(d2=i.+m҄lDѴF2ϛF]\~ d3ꭦuYsB?"G?"G?"G?"G?"G?"G?"G?"G?"G?"G1t=b3œ sl!"21/r,4V]V.s;W]O 9'jQU GExStr.sW4s]ƚZ"?Y鍺4vw>K.sb!5,eeXv2Y"?OQ7XȈ .捔n"f[v>DFWnK)c[#B*@B|M׌s]ȯ߲gnaiŊE֮k<2._<#>ygSR}}kg*܀ZՀ-0̘Ĉn`b &7d"] v{}I@[nmC>`/ Q[/d%wW p*EM>C`JֿgO p"?,CSm }/V c[ňQQ> ;\c 5NQjh=/kʏ&ɧ1="C@ x0PU;54PEx'6(_ /#vOS`:ES`8?@ L|64Z|6pIyB.Qa3zCz~ozL|=/2=l=W.U-c%?p?F"XC ( !KBZw;v3G|$~t^`G䏆ZMs=P~GQCHm x hhy -o5 *6@<+jvaiPݍ0B ! 1(lQ>Gu$+nyn{\m\z ^:L! U:F\GIvQzH6jgjX|Ob&NG)|QA)A+%8VPZ^쐖U876jIsϗ3-@BcPY94Ip~˩RJN#rBznʪ`R;VGV̶SeZ15VcaEDXGVđiEY&$h+C9{^RIuirB'ditB$k\m w v״06WnZdER|Xm2زl[-Vlk2."RLN]ԩ;H=H5@">!DGHtHh>;E6ޏk}w^JomhMIoz h-~& ot96]PevTL_\z˘8WŨ^P= > W1}kT|v%g57ݐj+A0]+]lV[mEM/Dz 5pGppG@pGGpGp^l`+M~`6Y~_ հ_ ~5W~5W հ_ հ_-W~5W~Tk A5[AnAnnAnA[ nwþ[G`G`DaG`GG`G`DؿVZ@zEV?V|@'F\V@;5m`)L,: <~O<O<<O@O<O<j𬖞⛥ ZѾQs X\*j@BԴKj ՂL-`'Z00L-L-`jS`jS Z"ZԂExS  R m5:5`% T,ځ`iKe"Qp 78܂ 78p 78p-8p p 78܂c#8F8F11pcDpc##8F8t5{Te`n}#{Wgcg4ac`x/J?O_r+;%*vK6¦:}9 <@> d*PJ ^Zm4SsŰD[?6iH֘ZcvZcVtnn h|MswĬ3oGLݎ1wLㆬOY ="tF_H/iHUff31SCdLJk=1䨴?%!ǥ}hȱٺ!GC2duCzd:< ;;كxݐ}h;\v^ysLǓHMqfibTbԞav@0iϴc2)231L6%6sjfY1Kf2'w$gFmOȫ#sL<&f5uQ5ysYu,LK\ӚmE+ڇ *>Ţx#'aFuY\;!72;S]æ4Ws0A~ЁRPV0!Ę3yJM&̊>OO'&ȹ[kV&{^a;M {6i4BD*&ink'c`ЌUkSWƆ,uH'y}6z؛^]r~C/[yz 691&tξu }qLIFH-A umah1oAn]ܹFU 6G<ߚ<!8٠.V޼0H[n CōΆ-뼽2F7]wc1/j@s/on\sh-A3uԯh ޗK[`#mGsx]A.ڒZބϛb՛vpd>כlw> >E{&~Ŧv 62n%zf_Z}b_9͛;x xo= D~/>`%"7Y$.sD`@c E |"9Os0 endstream endobj 360 0 obj 10820 endobj 361 0 obj <> endobj xref 0 362 0000000000 65535 f 0000000016 00000 n 0000006276 00000 n 0000011771 00000 n 0000024780 00000 n 0000027462 00000 n 0000033448 00000 n 0000038133 00000 n 0000041347 00000 n 0000045598 00000 n 0000049934 00000 n 0000053392 00000 n 0000056654 00000 n 0000061811 00000 n 0000065951 00000 n 0000069853 00000 n 0000072119 00000 n 0000077722 00000 n 0000081664 00000 n 0000086446 00000 n 0000091023 00000 n 0000095296 00000 n 0000100404 00000 n 0000103920 00000 n 0000106770 00000 n 0000109900 00000 n 0000113852 00000 n 0000118879 00000 n 0000123607 00000 n 0000127808 00000 n 0000131531 00000 n 0000134873 00000 n 0000139354 00000 n 0000144408 00000 n 0000149389 00000 n 0000152605 00000 n 0000155464 00000 n 0000161483 00000 n 0000164558 00000 n 0000165343 00000 n 0000168059 00000 n 0000171657 00000 n 0000172284 00000 n 0000006212 00000 n 0000006063 00000 n 0000000081 00000 n 0000000849 00000 n 0000003981 00000 n 0000005258 00000 n 0000005924 00000 n 0000000186 00000 n 0000000299 00000 n 0000000433 00000 n 0000000579 00000 n 0000000716 00000 n 0000001289 00000 n 0000001787 00000 n 0000001946 00000 n 0000002406 00000 n 0000002571 00000 n 0000002692 00000 n 0000003843 00000 n 0000001023 00000 n 0000001160 00000 n 0000001441 00000 n 0000001551 00000 n 0000001679 00000 n 0000002068 00000 n 0000002178 00000 n 0000002299 00000 n 0000002814 00000 n 0000002948 00000 n 0000003087 00000 n 0000003449 00000 n 0000003609 00000 n 0000003728 00000 n 0000003223 00000 n 0000003336 00000 n 0000004149 00000 n 0000004274 00000 n 0000005088 00000 n 0000004409 00000 n 0000004552 00000 n 0000004708 00000 n 0000004843 00000 n 0000004979 00000 n 0000005423 00000 n 0000005780 00000 n 0000005524 00000 n 0000005646 00000 n 0000006600 00000 n 0000008555 00000 n 0000008577 00000 n 0000011234 00000 n 0000012957 00000 n 0000013092 00000 n 0000013227 00000 n 0000013362 00000 n 0000013497 00000 n 0000013633 00000 n 0000013769 00000 n 0000013906 00000 n 0000014043 00000 n 0000014180 00000 n 0000014318 00000 n 0000014456 00000 n 0000014593 00000 n 0000014731 00000 n 0000014869 00000 n 0000015007 00000 n 0000015144 00000 n 0000015281 00000 n 0000015419 00000 n 0000015557 00000 n 0000015695 00000 n 0000015832 00000 n 0000015969 00000 n 0000016106 00000 n 0000016244 00000 n 0000016382 00000 n 0000016520 00000 n 0000016658 00000 n 0000016796 00000 n 0000016934 00000 n 0000017072 00000 n 0000017210 00000 n 0000017347 00000 n 0000017484 00000 n 0000017621 00000 n 0000017758 00000 n 0000017896 00000 n 0000018034 00000 n 0000018172 00000 n 0000018310 00000 n 0000018448 00000 n 0000018584 00000 n 0000018719 00000 n 0000018854 00000 n 0000012435 00000 n 0000012785 00000 n 0000011256 00000 n 0000011749 00000 n 0000489021 00000 n 0000503884 00000 n 0000516200 00000 n 0000539838 00000 n 0000546933 00000 n 0000018990 00000 n 0000024757 00000 n 0000025143 00000 n 0000025281 00000 n 0000025418 00000 n 0000025556 00000 n 0000025693 00000 n 0000025831 00000 n 0000552460 00000 n 0000566160 00000 n 0000025969 00000 n 0000027439 00000 n 0000447192 00000 n 0000027788 00000 n 0000033425 00000 n 0000590666 00000 n 0000033765 00000 n 0000038110 00000 n 0000038456 00000 n 0000038593 00000 n 0000041324 00000 n 0000041711 00000 n 0000041847 00000 n 0000383759 00000 n 0000041984 00000 n 0000045575 00000 n 0000045950 00000 n 0000046087 00000 n 0000370368 00000 n 0000046224 00000 n 0000049911 00000 n 0000050240 00000 n 0000053369 00000 n 0000053765 00000 n 0000053903 00000 n 0000054041 00000 n 0000356498 00000 n 0000054179 00000 n 0000056631 00000 n 0000057027 00000 n 0000057163 00000 n 0000057300 00000 n 0000338499 00000 n 0000057437 00000 n 0000061788 00000 n 0000062163 00000 n 0000062300 00000 n 0000062437 00000 n 0000062575 00000 n 0000065928 00000 n 0000066304 00000 n 0000066442 00000 n 0000329096 00000 n 0000066580 00000 n 0000069830 00000 n 0000070201 00000 n 0000619762 00000 n 0000070338 00000 n 0000072096 00000 n 0000308539 00000 n 0000072458 00000 n 0000077699 00000 n 0000078054 00000 n 0000078191 00000 n 0000078329 00000 n 0000081641 00000 n 0000082000 00000 n 0000082137 00000 n 0000086423 00000 n 0000086802 00000 n 0000086940 00000 n 0000087075 00000 n 0000091000 00000 n 0000091359 00000 n 0000091496 00000 n 0000095273 00000 n 0000095632 00000 n 0000095769 00000 n 0000100381 00000 n 0000100710 00000 n 0000103897 00000 n 0000104238 00000 n 0000106747 00000 n 0000107100 00000 n 0000109877 00000 n 0000110230 00000 n 0000113829 00000 n 0000114184 00000 n 0000114322 00000 n 0000114460 00000 n 0000118856 00000 n 0000119215 00000 n 0000119353 00000 n 0000123584 00000 n 0000123939 00000 n 0000124077 00000 n 0000124215 00000 n 0000127785 00000 n 0000128156 00000 n 0000128294 00000 n 0000128432 00000 n 0000128570 00000 n 0000128708 00000 n 0000131508 00000 n 0000131888 00000 n 0000298360 00000 n 0000132026 00000 n 0000134850 00000 n 0000135221 00000 n 0000135358 00000 n 0000135496 00000 n 0000135632 00000 n 0000135770 00000 n 0000139331 00000 n 0000139686 00000 n 0000139824 00000 n 0000139962 00000 n 0000144385 00000 n 0000144764 00000 n 0000144902 00000 n 0000145040 00000 n 0000149366 00000 n 0000149742 00000 n 0000149879 00000 n 0000150017 00000 n 0000629874 00000 n 0000150154 00000 n 0000152582 00000 n 0000152923 00000 n 0000155441 00000 n 0000155833 00000 n 0000254360 00000 n 0000155971 00000 n 0000161460 00000 n 0000161839 00000 n 0000161977 00000 n 0000162114 00000 n 0000162251 00000 n 0000162387 00000 n 0000162523 00000 n 0000164535 00000 n 0000164864 00000 n 0000165321 00000 n 0000185802 00000 n 0000165659 00000 n 0000168036 00000 n 0000168365 00000 n 0000171634 00000 n 0000171963 00000 n 0000172262 00000 n 0000172554 00000 n 0000185778 00000 n 0000253939 00000 n 0000253963 00000 n 0000254338 00000 n 0000284997 00000 n 0000285021 00000 n 0000292544 00000 n 0000292567 00000 n 0000298337 00000 n 0000308174 00000 n 0000308197 00000 n 0000308517 00000 n 0000328061 00000 n 0000328085 00000 n 0000329074 00000 n 0000332665 00000 n 0000332688 00000 n 0000338476 00000 n 0000350759 00000 n 0000350783 00000 n 0000356475 00000 n 0000368589 00000 n 0000368613 00000 n 0000370345 00000 n 0000378240 00000 n 0000378263 00000 n 0000383736 00000 n 0000395943 00000 n 0000395967 00000 n 0000441130 00000 n 0000441154 00000 n 0000447169 00000 n 0000488997 00000 n 0000489777 00000 n 0000489975 00000 n 0000503860 00000 n 0000504595 00000 n 0000504787 00000 n 0000516176 00000 n 0000516983 00000 n 0000517173 00000 n 0000539814 00000 n 0000540528 00000 n 0000540719 00000 n 0000546910 00000 n 0000547575 00000 n 0000547760 00000 n 0000552437 00000 n 0000553154 00000 n 0000553353 00000 n 0000566136 00000 n 0000566924 00000 n 0000567120 00000 n 0000590642 00000 n 0000591441 00000 n 0000591646 00000 n 0000619738 00000 n 0000620436 00000 n 0000620631 00000 n 0000629851 00000 n 0000630521 00000 n 0000630722 00000 n 0000641634 00000 n 0000641658 00000 n trailer < <3727849D0A3A4ACDA93FD3E7315DD150>]>> startxref 641802 %%EOF ./nsf2.4.0/doc/next-tutorial/value-checkers.png000644 000766 000024 00000103021 12501766547 022175 0ustar00neumannstaff000000 000000 PNG  IHDR뚶oYiCCPICC ProfilexXgTM 9sNsEҐd0%(J(("J$A@1"H ޳g:zUs>y4FE89P"]x#t֞hop\r:$Y!^ޑF9," OG!t,'?l{~ϱC'yzF@|yb~XPP${z̑ 9,/?~ž^}zzȍ"Â=y FF\I#}S oO{~?7cDijmcGqv_o{@{2,' GAvI(YJGNFVfoM;_,vFcDrcH'O p~ $P@S` 3pdB@8 @"HY (%T:h- x`|X[ Jb!AHT M2l gBh(J\@7;PB/hZ6aL`NXU` ~p8"7] ?ë("P(I JerA"PPBTՆCQh,̓Dh2:} .A_E7{ÁǨaL0N?aLsӄ<|aX&0VkubN(vXq8 %K:pc <ύ]$|!ߎ(h()(,))PPTQQP|" ;B !PD'^VD"QhM 3ğ$:IJ&&U:I/H+Bڔ.Q)k(Pܠ2:NUJL5FZZڍ:" '1R;44!ٴt8:!::oJt(z~z=z2}2}}/,0 C Cua%F:FFXRL(&!&`FL̜:>c,,,>,,7Xlema}͆fcf;vm]̞>sqpsTr qrrqqqs>\b jZȣSók{wwOϞ/k~ />7@@ 9>u!a!Gtyaa8:W""Z"""OE*AEbbbb#ⰸxyQ DDĄ$IRG2FNrFI\*IEꫴY>_222U2/edMeddrrO) ˷WWQ0HhحT,\< bHz\O5%(FoA7qIcZGCV;m~mo+s:::tF6Gg1333\2R474504!Ԙ,*51#ٚ330o-L-,^XXY k.h#k`gKon[kfkc^>ھہաaQ1qIӠ3ss >*>?(|0`[}wjwO[GZmOK U/2%wOϜo?_߂b^@I@ ˠ`!;tA= K W /_0 Elb@h͘ҘoƆ;qd.0r<:ߝ0sTc1cpDBbP$ܤɎm))'RfSRҨ"&OOΐ(9%UM8%{i9J9`τy~V\ܸ<| M )./yV[z,l 9˳7/\dtB[Sʡ+lWTVO_S\SSQSE-\szK7nd5O7=n>o4k쾥r&fHRts;mmMwVWz~N;=}#c3s˯k۽O{{{z=4|Oƣ{jwTZ+>nVnQi}mthX׸ç&O6ߧb^xyu7oEޘV??3Y?|X8=W3/7opɧ>|KWiZrZ=r JݫVoBֶ37X7Tٷ9ux]#׫ݐ0߹ ¾,W@ 俿g 1EN \К!bA*Chyf$3Ͱxahi]P2QU璠DKKKO v5W**&))T1VUTRǪ7ѩYUckgo\`R`ovEV6)v))INǝ]bD pv'{xyEOVox84< T9zllc4'yRxR9XNRg2љ;YkN͟yuf‘sv;zŖK*VUB S-5o85xk qpS|֔;mw=#AUOmoÛ}MZl|55hصe?O |qp+bo8R5ef]R?s]i_iYwE*fuiÍ?6Ӷ¶]v~I2_Q6hA V gEI^B4yt F4S<&/ M"< |95MB-7EgI 򒶗1UVUf֪a%ͦC[f0o8c4ihdlbj?IanV)Ӳ9gΊ  ,(+),c;t"% J*W5ט9^;xݫFhC n_j|uT/Ao`C>GʃC kh>37~j̈́ݤ /]_v{s˴;Y4~xq`qd!gE/_Q_?{abGjZzІOM-m_,JM,qm(NHTilik3b`bead_+\@JhXxD zk2We.ʗ*SUTNVIPPUwgϯåˡǩiccceijdNcAڏ-wl6m:9/|=[='^_{~X\ ?%l-V19| 6HB\v|YB$LOIҘZV~djFlfPlS:speȥ̣ AιEK%K?M0^>rq@@`+#WGjFj=6x}FǍݞjz<2Η~_m_X\xѳѻpoJo_>=8<;2GϺߛhQ=UU7GFN83Uy/#879߳sbׯF3/SV ku'&~ BB{Wݾ s` ?Ns7~` 0"զRijc` <@08ґ 8xV!<ICzHxJ.Bm3h`8?E5Tm G$&Ӊ%a` & (!/FF')FC9AeFEFD#OsV.. =4C(/3LLWXrYX_`e9+/\'#"d /𔔐ܐz$],"/))JbRrJjZ}55okhO,ꡑlhcjeRk:d݂ueU-}}5g nGgךO?s_`[0mHp@DوQcb[⫏ :!x5Y~#?}#aO-3  8oDY:N2p Qk !FHQl@(фnC#"La 8.{?zAcfIc2nEAGE1I$\&Rc$3R+|Q6cWhhh`Lzr 6F3ƷLT̵,, ^pHsLRz]c W)ЎsaF [Ȕtڔ"{BM^SA@F hkiYiVČLBLϘO'Y[XWL1:;>wfq9p;70{^w/˿#;(1}k4#FƴƊ9ϐpxV"UR~ gjmɁLSgsΌF /-yVuA"t2y5249n4Ͷ i{~uծ:zGPCzOv>B묷3?>R }YttyuN[;={GEt\[;H Xʐ8ø{nE%~ pHYs   IDATx} xUՙG ؠBh Zatt(5T\m*;´A+0w"("@T("dU@Y]UE@P2("TevMTPE@ʀ"(@VP5QE@PU@*"(YA@PV`DE@PT ("dU@Y]UE@P2("& d}0MF*?zrnWܩ:Gpu r_0:; 9}k͡. (#3vhJAlduV%}[Mg@$͢p3<5 Prg@:  >UȚDppr8ppr9%`* .u?H045+GFt&Xg@YXkߖ1JkM)8PpʝS= J,e 3 zf4)#0ɩ7U>)C]%9Ԝ"A*XTrY!phֲm g%%:'ǺpvoL>]8(P2uo4@_kL@4&+pBMۻQ$&O3g3d%cuLCri; E J]ړ4PAy$@/iX}LT4YD?pb@۱N+,, 858 76]%tYS,G{Cvj9zHЏH/IzYrL'A#?DPxYP>֪[&͗ t;D}ʎ'DVs ]V`64[̑K/ %V3<$,/F +y'E[y\PR,ȝ2 貽޷]9yYzDv? +6ʖK|.XMDR8l+69ص^uWo.[VLeZ{O^/h -+]8,zdn!.俬.C-ݾOE2s Dd瀯[VCeVseCj_ob] ֖n~-xQʎaI&t]MVյ[wqi:;[!sXr]yUgYuO;قdyh-j썆VCvpVfCoPr/wXǚ^n5;p7=6C[cE %({;֕s?ڀ^}eIc|qa `T-#>9h>O6=!e{BxRZje{߾q"rIĩ~r &^z*;LxͲ{b5T/Sv ;UI%‰2u֕]3QJ̔@3]T*6A}r0'&/BG`M5.(^/7H,9ҹUĈX'NyK+?3U+t .S  eev{rէNHޕ壉2y<}Kdiw/.?-A伳Wd^h̛xXW r /aLC®m}߫➰-Tse6u7$܉ ]1728qy?)߬Z%o[$&N_|L,A9E"{Xxx|ZW2^EC6󛤲|,7S&b S+Z;8T4ù@t?n.rZ<\^:q(z^@tý[h}ϚLD_Kß⠁J \D5<<Y}JOw Y{نȌ)˵Qp,xCZU'=NmΛ7E~ѭIE4R^! (S 'E>#eaٰ UV\H/?Y8px.؋\ ɡNp4yU3Y],7ٺ'rvJͼdN,b40ă;ue5*c*ًel*yl^e5R67lb3c#l5rgde;wHܑF#]}C.%ȧn&i@N _coE6WYk'd ۛ[}~ԪYno`/ak}Xy3跚k\i;,v[;PI̪G6eV :eխrvWKr;.;?h[78t`MD%[-nG}$xdG̼/e29>m:C9|5@#$WI04OP}| ']9ER2!ɘDIqRT"%𛛞]2TT,%Ižv8ooϰ1JܴȈ{> L/L6cXhҤyJ$FXPQLc(V'N^vyc=>!N`*՚|eR@Y|' ({@7͵"(G@PP (@0Pz\+"xT "U@7͵"(G@PP (@0Pz\+"xT "Q?f4׊@D\H,|hfquGښF8  +烧WY+]£±~~-nJx5\.MH| Nѱj7wJQ0::R% BՐR^ͧ" ASW| 6ʇx|&/G;yV:cL :Gќs,ޘ=^(G|f*(!΄QH4[U@ 5 _* 3lʇKI8{&43g>@JˤѤKJ9*Z2;8fƙg?y*MėU\lug֛R# (+HرqtpܨxO[ěeJ Xoc (R?HJ,f*.4ǘcx!_.[zET@$tf/wPu9sW29q֨E@¢AGGù޹H}<k]$5qPu 8u@')O撒Sb * A :S"ɋ"[w^\e+d3WPiG@e; LyBoY> >ly|ug [{0׏s]PiE2aNٜj|A{Q@@bS.ė5QШ !&W R5!b岼RшB@PZp ]䓝MhQRv~xU^#7Лr4[ƟQ qZ 0dYĪ# (S (@pCY+>,E+! SY @SP:w#}ſ_Y1$!O۽@,߬:>C٫y*gt2NJ 4@mO띸&\m e9d JE`*Σ\Hk"sgLY>;3@; l )*`_OHSy㛈"!6<wGz #b3bZ:ܳ SQ*,U8% 8e* G(ଲ>|y2mTeOYxdSZ p23(~n7z*E2N_QȷWF9+]s݋og^I^' ׍rnHЏҽ4=\صZBm5u_qLsi1^F~z֛ (*dxvf'͕9s ;^ΐ{#9!t";EWP_^{pXEv>̾#ǐ}O{E;v#r%hGAAe߲i;%kS̞XIc Wodl6] +WS_ PT YKׂQé7\,BVuCd55֔ኋj ^{[v[ηWb!rkk˛VKf{pxZV__UKI鬷7[U將ޘ -eI?Y4Z^`4`/nne [VCUsE4Y- rHyC5V?J_Ͱ 3S]MVVfk}Vk"J堵e);;Jxyjn,6 g?ڦ H~WAQ&ͰNʭM֡WVH[UúGk[l A;#iWY-VG*_u~mPe!OXvhGFF<ֵǶӾmjnoU3.%L0 DgGت[XheRfѦuV=D6)՟G\Vc 7k}sLNg~?)ӉT&TR BHEBׂ( #疭ZGi0l j OnGA?ۍj1 !8)\ZulB90QcC)*jkUeu᯷ڝ%SiuRlPDz'.tBTNꬎ.\Z4ZPLKPPD:TglM=H.#!//eMcw6;T:+A]) )B-@9sM;@{Bk*H;D{1m"r65N687jfX{ZUY(N[$m̤oj@m؎<o;Q@]*^W^v**q, `?^yy2o%H`|E.  g,޾1`_d{40ߵ>? B'D".Lg9',e_\4l5JC i\Nh,M.`LD (p*=Q'eOT3k婗KJ9P_M[$>$ȃҍ=ƺwk|kwx9O.)^r~J<6J!G j{^]ZtwygA.MZT*K1*4+ʌT\z57Fs v E$˜p6$}d~ 4_y!KX6{"a64>9oY:o&{L{~ N1uP^D[T?:։wciw-R/C<8{r~N1fC/ja;1ZA*4@{%(?!]ힶe ֤O pe#~+I`;YO]F蒩/_).|(=#f4IfYKݭӅ5ipߍM׉GPm8>(.)q66<roh*es;m~ˤFRi\}lidi" htƤF>E}mTjX߼20-ƪ=ԏ"(C` M>R.! (jC( P$sUxF96Њ"(" (C4"(P464"(@8 ("06T ? ("!2N)" ==6@# IDAT2 RqX>5\V0͕"Jr4QzRf2un{JJ &<wp)ci)3~ЍHd 1ccY_߁Yz'Ƈ0BĆSO Xm^iϛθ zY"6FV/I'fZ sBMbpїX_U)vZĈʛOJuJ7 !#LRj\=aQA2 f=T@lNSzc-v'J;;Q&j|_DL e-*ob_@6>˴XiU@٫uV;.v`Frw|ir!CeJp*!"373|(F](T:ҒU@@, dFfD%V$g??%:^(illxPH7\SZuOM`{b⻔IPPGqtdD*$6P6H~oHN:/ԙy4#z*37?U@1QΎXeȺ-4vm0i*WϬD6Lv^436J?G! P.ff76:;[J# .Ĉ&^찌Su$4FLA1X;CQwc)Oas%f&mx>a3ɸd{#̟*32nm@PʘGt ;-"  )NJ#l*3I9Y}3/JEY\M0Pz$ (-E_չXP@@PKpJG@!u9(0Te±cEw?Y,u% !WY{)*,-:Ǒ4?tVp̺g -"#|;&{xWtGIH@(> $Op$~ x7A'_M)*,U=::wYYʆ&A,"ބ~ß½(コ ꂊHIP|@`\~PC5 t^(VTf҂++sI^&cR@΃7ܪ<o82Yz-/H:)g1X#AG½ }ʣI28&B*uO;CYQy6ԑ?௿r dH3Lv /?t0 qSpd /%hA aX[2`Rh~F92٫Y;.v`JE:e3 .Lg@f4k2 dTb'e83Re=Btˋ* ߫ L{ ՙ9 м8L8?g@q)X˶-<H[96 tI%j2]י[\FKܸm/p&Ȳ6[Pkh2S'NTKd2sL1mLXEDڶ-[ZS-m2a6ǀzԗ)!кm-SX^dִ7ݛd䩶̜1C&OX"_8fﺣ\-6>r00+ 9 }WUAW'zER&Ch"9pfCJbT!rIX'k8;gq<..)$p\BUU~Ȩ\O VK YvJoWj9,n$98SR Pտy!DySge "d۞Dlacѕk13Kt!V,-{;E=En+{dxmM3,}O{E;v#r%hG!9•*glZגյrt==—]hiW+K9?;a̫q.s{`zvٲ3E V8MX!ێTPY+YP8rn.,nvD C䱻yl5r`ϑ;!e>zHaZgBVꐴbY,GO@ؾϮowE-+@,' `ˊv,C:۰pZUI2Fxc`7o#(\SfIy\+_Aj*nռfy谚_ji=dU7[=-ֵWe5:BT6YVWh*iǖ.-S>4YnwyuҼ*cv~KhQPU)Wi[,Weۂrj~䤚y5VOpM$^Y^i5v#\ya5T"D:3WtLK.GK]q^l#ia٨Z:Vݪ֝SuqGu*Vs~z90DG*]u~)⯼&lG*RG;;jP锽vh-FEz[HYꬖ7-[q[^oU7/_7AB:&+WaaPcS@v;Do+HowZ]v'N Y-l]N7?ncwڕQ8;&ӒQԪhj#JEUʎ~N+FjkUeuʭ5dM_;ec¦2]Ugu8u[atlËk" x2ʢɌ8z(3xU@apʓ*H5GG S LoU:) *B-?l.A*HJD7:#Y\3H~GnoPJ1{* w~IBdW̙X wr^+R1cL  Nc4vQ›d [\?:Cd6cGP牘Κ ׁaim׶Z{َ)M,F$]DSȋ{REv.4{[{oDd/њ$W8q瞨'*bk婗KQ%;Bd̝}|yɇd>E#^YF֐klǥ1y\l=$G {C{^Ytw֕&f80~ZY[P,.Fj2{4DO7Vɴd'2FE 7Ț?}[..F[:S rWc;CC#Suu*jb6a7l)<|BB/bJzϹFPviI6'kؕr vt0p0 5 {txr-Pʁ7Nwv8[{Dpjm]CHi|en@kO>存9iM;T.Z9o,]+{/R1{EB"}o<#K_*OݴFdZy` G#7Jh\r|yJdRyɩWK6λXVKɬrMٛq XΜ`rpeA~6(WbݯB eŲ H߱VT~d\VJ`r*T֟IR<)5󮒥;:KK|P >,E:t p4@\-JWL:d3`r6g5rgp RBPiq#CuXe8znٟVۇ;9H]u E">&A؀l@ӹjtzۭسqҥYrU➏!s~gc [^]˯_g<8Ђ{ٸ桉xՙ$F;%3Ya:aoG _8lX.&8{2[ㆦj2&͝us cJ˜goA?Eߕc/ydF>K){Ǐ{}jr/Ɲr!,애2}ߟ#M+e>Йs<95 43;~4$=ǻdhn#HtH'qX,P&Ro7d22M}MNک%u{~9? K$&9 w8'L _VL%ܳ-1O9nt:3ȕQr=;I $97/f‰eKn 3[,%8=\ X4RFG,!z^|b7Rp?9r;b8~ EIjf8"69.Q@`AF" h$&264khE@P" (5VE  xjE@*ZsoE@P*Wf_P" (5VE  xjE@*㡀ŠVE@Hj(c2SB}cΞ;~~52Ѯ?֡1ɁWdP9BGrwήp7Mo8#kXy;`^r#VO4*`/>A^:+/pJ>_,|troD GU>D)s2U@<6z2-T6.1# ;>яRv0 ;:#1VψrAE(3'( p&^*1mD1`A2J@ bçP_KXT3aæzl:#;(Ct>7csJĸUJpf879;됃ʓ"1* vVF0P8p({BsF?oGP8agB%HtT;7a#nCf(/PKN)JUJp خc]F (.d@ LqQ )ءwM%VQx7gB?#;LGtؑQpʹ9\dX+0zLpjix9kFJ@ Oj|* *'tPyّP)a3h1f*>vjT\ Ɠ8DYJ늲AyaQfȞ V*2U@fDKʅ GNh ;SFQ9|@Ea7cLe,R"O72 T|X^ Ww2R@Έ!@R8x)8ۣT*eӡDM);ψc)7F^2]z3y H 2L9!"1) =!D Ȍa(e;Gf|2cĘ"r)rͧR}*IX̸"gKH۝/..+/\*Uԟ"{u#h7ԯ"(@#Kk"CU9de`8';E CF97&J_WB"~C``jMq4+ՎgIϸowܧe׻)~W]Gʔ j|/;;lмLׁscś|:r!G oLJ0x uEHwd8~X '~9R@"[΍hxsca .:~<< L3D٠E`5?_wp7 2sv%E SиroHbD3޽H i;oj;GTBܣ h7 -sĵ&;a~N`U@Zh=̊NBܟI4|~O^3n|Nx*o?g@tyx67QIk5q-i`0')WNmN2vE o҅ocCzFHtNY|N=NA#܆ ݁WBrB2)xd~"Ph* , c-"V"(8"H?mֽDZU#ٲW -"8|S@@!p#r=?E@ ǗFfa|\0 d=)IG ;\CF~x~MS h:@f7x( ŏ=n *ͭ"[<֩ qx!.b0h6Bslwb08tG1_yKK+πPɘzxO{[2['@ O ѯ85f p3;0y jE'{ar &x//.7]c_q^vTZQ~+3 q)c.#eݯr`?X 뚨pmk!(3߃;LlۗG1ᤤ?}s,B#>?ǂfVr(by=J%7pI#xMIb̎ 4zF0|FuzHtM9"KHc>^ `aG/^bEml8[ST^ډ2N%E`pҼ.4g`U> 2n+U':|&M\9zIeYAdLp6 2O=xx$E>L|L2nRFÙ_֗`/g`[!y>`C;{3 "̀‹ĮF]FJŲqÎG/vS(Xw!Rȋ:ʅvF4¥*n/}# @rH)w9;k\٨y\~hېPң5B>Xfд##\v=ݜ?s ?3GLv,.&u^P|gU>҇B@OyG1~`6!׃f 9*J+yrHЙt#Y)oΔE Mt&`=& )YFO{9gt~b}}>@g@Y^ ;|2OuU ?{˖ IDAT;lvƩ#p='~T<&Rg9ahp"P<(0\09i6C_!Oi{I*z(DŽg|,Rv|`jv_4j?b/?@;/S^(#3&TR ?ը:I`B|;L^S ,LʉNb3 ^p7|w7|& -EqBӁ dw~#3!_z82CY DSoа KV?@0S>¾whOλ8Zn5xfbs]Sa]欈;W#`Ǟm:Q>1e=Q1PߝxG90P, &?Nt祽爰wy!ؖ5oM|*) Dߙ$5Ƶu븉Oҋ#7$:vbG)LQyu\R/(G.#E6 Lg`ޚX,"ϊ i}!"#Q>yݓ0׶#1hȶ0;rFt9 4G'+ejѾB(_r8L3R.˶G"Dhg.ދDxsYDe7\=y> ;`l漧 .t,wzyT 劃#;26RGup/eM\.)) ?#U4~*hg|x<\#/kufCc Z{t)v 7nT̂x-WGQնlm3S 8~߼㟃#3))ۤ]I(tT@^T4Alt ~o܌w#1NHTDȪs rFr&͝"{pH/ +ªo-m!HoQiQ#џ gzF񡲛*R/tT)|E!k N?#Uk~qC #yƺۣT_튋׭(&Y+t&<:lrO]J05)Ǎ|FOHjTop;I;,3O_ǻT_v/[{dKNX %9ŷߓU߃y`' ESR:t-H7 ^B~mA/a'?x.͎aS$S!SO`x(;qJ9ߑO1[ϣ~Uǧo! 3692c``^Ta?O+A\Exw"wEo!WٓI;*?y؇]*ND`*+ޔR!@n 2Ey|\E]wGwxj\ª"hT@ r{H,8BwX qBgcu=|0b/ /1m;arvd_0 S) Go& k3c|E&Z8/-͸DN@(1^w`?6gP6E\ D'`p$R~<咶#]h,j S^d,\ZΚ<1O8gT4 V{VYAt%)}?/ 73*@nĨyǑ}OY~󂕳襒 8S⥒vA7BuԌ} uD3B:# nT~FeK7d;E (  <%ܝ# N" 8^πʕ#?#&Q]-OqņgE pY/0N nT3~* (Mzr<:ɍz\(i#Ҏ") @R/@."i0I-<:A]gsIO_c=jHh1EJ))=}8%_  oF)}+E(!wR5J|Z+vh/ۊ{qtH}ɨpaya9Kb-Q8~^tB ꊲ:8TBs R.);̋F22 S?ř(h{`o5H\ ([v;̯IF yHw=;!Β3NXXN~p|l'>siKP/eZkZxWl[D!=;2ƋF)s\z[&}!bE@ ~*"is)7Rmo ~9x[1yer0o@LZ?vK$T` ύ0ٙpKӎ6% gRRLG1e${} u7d6^O M{L9s QH_P һ _gFi$sc^؝>3wqc t(E2y~XF Geu=pQ5͟QRztA(5I9΂ 8&gn22v3v_SqvM:KY&e Qg V;;Ψ aNjeLZAV1;363bCl;;.q (~* 5~q;P(??a?nOGe-39S"}ʼnVy&-q}bScoE7*(^5>H&kszu}`L]R6 e,j*Uxg RYhfbx(wNYrv;aa鏔$q)s g%G)5߿a;g`x)>b6KM̡v?Z7IBOZ}UՅ@ e6CO]S"$@~/#U 9!WP:@()"3Ro9@g@9fLqT@T^ O,9u: ;ea"N~C<LyuljG%E S q)H?l3:`N! 6 G`r$: v|vE`v6_>-*f;*0V$SੈJi#}?Ix~7\$[!l-\nm`s ؕD-^ \ǯ3dŘ_7V̕8yX83{襣2Ǥra7;n4wG9܋|rV>Ts r$&t G93df%-* M]Ѥu81)ondi0 V@<?LjjGBAXb:t#=ap&9eu3;{sg apwd.1*2=**nTNδKrJ `!`H3B:''tgFOY\h`+?rbظrfT #x4aAJw.aΉӋ7wZjO jLn'aFӼWS82V+QM'P*+~* _FZQZ\%F_( HG- A͝/r}?JPB Gk畖LsBBsq ~h):?mwo2Q9a,ݎDn&ĸŤi.0RJ`EFRu?޻W/E: y^a7_R0Ӎ R΀rli㏷;wa0xv.;?>5VvNρMJaWc$l:S(=V\q Ζ/G(U5^3x|0fCx0Kzը5 "exH m܄~*aJ76Ĉ| y̯ٯZ??3O:/·;%amrSP=]5 ew:HHrWl_l+1 9#n?x@a"/x!7׌_ޟh>GOǡc<<EI(<\ (!'j. |%11TK |wN$:.K_ L㤓T:]}OL;:OydMM"Ɵ@!e^#^4VD۰ zA)=Jp;1DG(Dxx%x`g#쬔ƈd]M2u6F κ/3'3uGǨE O0#|(ޙ(,Hlg*hǸ#fۊqp4 ww<3aԞ2~΀LDϩaM"p"P GFZSl*PVt` UQ@yPZ4@PwE GAI*T@)oE _P5[ug+)*B`Z*fV#_sf7ܗV9xM@\#9b"p"/ ЩRvBizBHc>"/1Gs'݄w;9C6x;0`WR g@@"t3`~8Y rq+9;\L;HԡP!~p::v gB ۞ Nt0?E r64/" JǬR< 0Tb%@1PpE71UeYE4Nc! KhǞV RcE PYJf@礜#()# (ec" ]f(ygy 90/-E3!0?h^lJETPTu]a8Xtׂa``~4 Jh1wN{ag8 U`~W䈈RA! ; {Jv b,\12:@Qfifτ ?7x;0/?{܏ZGIwvpM(Y>3L75 :)`{4:*|)~-]&Z¼P~\ ;ϰ +h?5+N4:*|Ṽe:x/ A"pԤ Zhnޡ\ᮠ'%EЫx ]\~t#{&5dp?MY9DߧΗBi"@Pd*x(ϜpGIPtHE!d4@N" ('E3"πR̗zSPH%gPVfLU@c>r_KkK+(BAUw6f@n~f;S^G@Gcy_y]@g@2[Z" /;Ned< l*?`gG@P@cow:?Iwv<lߎ}`U k`ҭPR2hidjޒ*N(60o6gQp{; 2xmLX5BG@ ]]~o+:EWρd42˃y@"3B(, e$]!A "U@*AFm\Cz!΄ލ8o=7TԡH ȯDQa '4JJ`I9m6GE<:+x4~̀x|4Vġʇ@()@@Ac? 6 i\E@OjhRAf=cJRɼQ ~̀^aTphFEШ9l_:h4"HT40֨"P*Zϟ2{>$e(ᏗF\FJp1Gw+i*)*B+3 :82ҳv ;`qBL; 0k_(\u>,bN{sGHR\g/#lp8n ʍ uSRrU@Q`?Êʭܗ*wfv澌4@E$W՞76Jt)ǹɐ>J&})KMo9haEI?T_R(~-]^F&挆w;KlaGPL' @"k@i߄bރ'4JqHR"; ҔSO[Vy%ԭHR9c6kXQQr6`%E U:49΀r4I|X2$LPi\@P.S%Z Pπ I-"TetMrиA)# 5C@:IDATMIiN|˽s qia|?/;5ITD5m!} ]LNlC_rG7k {H;_?#}%E PT՜|%djڳ(6Lr*o4 }[=07;aW>|!t>bTC{T}uy1SyXD(!nJ 1?p{ކ#<)%E PT՜~ekj"z&/%Q Ar>yA'N0.:}ѿ "`%E Q T^_c-A3mǝq<δl.-wny'TSR U@P[Fg@PE|ʁ<ݞ~W4H7i$]^W?v7G@Pq>ЏY.3x2Vk­H`7~G #Qy>))AEP`S&I+E@A@P (|ŢovE` x4dsk# (5XeC<6(㌀*qTf@/%@@PTr!_΋C_vx#L^t;$񝭨`<-"12N~̀) 3 Xt3xؾ&糖62^J"B@ ~$zkaf隼-"}Σ8컝WF-2TTǐ e0HFxAu<oժ(@@oBP12+z3G1 3?wb3?0>f"F@i,<86l$o3Kr|=0/*u;`C7Ÿm0 E* j π8\KFPJ wqAYͰ"|Y f@"Qݭ|~.A?("T<ͷ"T4m((# (s4dP@sd*Ӏ9@g@8h0̃ na1 vߤ>0~@F|-C.̀~gũ~znwývcqI<_]g@}<IaւW:vpv>qlžNCpyw9p%x6U WK0$ӏȕ F2.Y2>`)e~̀"_u fcs_AG^ +!a) XX6{/\yC™`^dJŰk`ҭ`^lމȺtm<.:Rto;e6C^GI*apCx}0Ghfqnq:;$xqD=υ_1.tE`NGB;aͰ"޼ڤNf__5|7JO'*)B@Ptوd#:R^()i!3?SX Q08P)_Wy?\"Q,E8HOy)e$R&FBE'Fk|>eCQ2BKZ(Ap L \zzxTv?!^HL̈RIl eli*cF#]0͜ !O;g'gwi5:5a`ҝg{Ϝ}arg#M<&3N()^"3 /ոFkZB?L|FTL'vpT=mspئkPS U@^!_Kp~%4| J04"!<Wy^8 8&+)A#'%E  (V* #xNiny xTeA$g@)ZB  y 0TbX&9I*4hPبQ ( „ *#( @D֬[Hh;{}~^x]kk==|*~cQ&玾>G=}RZ/ٷdy 5YXk1nK{u(iVGI< ŕSph j(9Ʃ?ˎ\NsapH7-Z&DP>)j#*zHlodgʶ&#tiXNvY'J@BvJpT"Lr h*%ŧ?q咑nfo+J{9>Y"vRnQj(G1 K[9ڇyy_x3%YioT}::(B@*(9̿П\z2;ه8VY%XDV*|(}ڊ ;Q fp1|?N͡^`V:?Zr|K›\S^Rc,k3r:VXJo-:C{8IS - O{1#>G9Ow\Nip-\9u npJ"](RX1+K1y)];ξ8xG>.N_.h_It=׎I=i%ha_5 J|vRdzIoIA @[հ'IHl3惔"z{0MM!'֫q3 =G$Icll6ʷ{O޶X}s.uM"*ܫn_1C\,l & Ǔ`Y_Nn5Jy4';M( (@ 4Wd8h'vpzRLZ> j)w'T4 H`_!jg sḽk?=/63]ٞ'ݔh(@ >܄7cKRcwF|O$&y󥹳M$0u1:S \@GP>/<;z!|ўorTQ^,:u@(@H`FDC9ӭft*+asKc $  $ $PT?@@I Pɰ9h H@ (@c $  $ $PT?@@I Pɰ9h H@ (@c $  $ $PT?@@I Pɰ9h H@ (@c $  $ $PT?@@I Pɰ9h H@ (@c $  $ $PT?@@I Pɰ9h H@ (@c $  $cXIENDB`./nsf2.4.0/doc/next-tutorial/object-class-appclass.png000644 000766 000024 00000061076 12501766547 023466 0ustar00neumannstaff000000 000000 PNG  IHDR pHYs  iTXtXML:com.adobe.xmp 5 2 1 m @IDATx]Eֽ$'AbBA1(E5`ETLȊpQI b@PWTW]Q(7o潉==~ߝP]Tթ[5{8#"@e•]"@ɟ"BH!,tf"@g D Y&DY !DBg $"@@ Йe"@ɟu"BH!,tf"P" q>73">9L@fœ؎ zN#0W=i͜ }v`QweszT`;0pX"!p0C C,u+:]Q@![/N9Tig53 ;"0XBVy27C$G[A5/s\?,[L6m*ud$'6m2+WACy v걣@ľ*SLx3+z.;wFA$u֕O2o<߿h ޽ĉezb?~.L^x9swޑ] F|y?}{ҢE Lf͒3gPo.Æ f͚I۶meĈ9rtA:vhҿrJyꩧ3^z%۶m&Fu /0ԁHcEE#Kj[CT5E?ư)_ӭ[7^z\IQRwgG5ΤI/8gm-^\s<ܛ:uj?n&sw|Ms\\9gϞNƍ3j2rC0Ƿrwq9a{cǎ5JN=12eu+tG RO.Mm*OfH _&#A*%#~WU[jG#UzK3̙c9ZB~Κ5kayכksptqƙ sK󟍟K:eʔq?s77liٲqF:%}0Zj9Kt>59 JDC*&ZPoVSE} æE!ADP1r&ܫ]=͛73ϔ;Q+w &dVXD4ib񣝍9w}0 İ1DoL>Unю|ZjG}4N:uu !0Q@@.3uBx_mn=uxފ]2mڴ"On}|vb%n^U&ڵEE2avf#y= -?'6s3z`Q :%ٲeDWnV,\DK.u9VjJF-W\q3FN=T/M &fѱ|s1{@m_~>̤#DT2`1cf$$POH|#(QfS4,uTmNST|3tdml%{ut4oΝk'xq!M?߻woG?2td&mF~_R%}vF&˗; E%K{iРo#)#ԓn7?GTWV^xT )D 'DuΝTԿ=rT;'`-@S UŤF-[@} :hy{}I=غL2cn + .$r}," QOޏ&)77Hk)ƌ;><S {ZGڑ%DMuY4^zifTC{(so$h}!$`U[wy`\p"$l l Ra0/G~Hc'FppqWw% 1194 6F ;X 적onp?IA+a'#HLJ}@"ww>L6#u}dffi"jզ0 fnptYثI^!xDkKp5/ ԝ? +'s.fn ^ - elغnoҚQzHLJ}mp1i$[WP,G뒏~RlO"`k2U~A%u*t"@&fT#`oRvҦMR4eodܸqF^+&σFppq3fW^˟=n#+?B[#"T#6ۈuѢE\{dԨQrKÆ _~eyꩧdԩ}e׮]r7J #FH&" I{] p?>3,]T~iC_~{2~x۷kҹsgݻ M&s̑M6I>}QFry畔#B#_Ⓖ Fsgȩ*ݻw7>|UTVM֭+5k֔r%Hƍur饗 /0L(8u}^pI`"dx@cjT)J*U{n%K!bOybŊ9H4(̒ >\{SҽkN~h8 ,;,z΃@!8G ^UL:cƌ1dpϞ=Cm(@-=En@VO?-ZH۶mRJrq0p}s\ }f+Ͳ ByJ^uT'fk_,^YaS j60ZuFͪ۴T70¥)Jf$;ZucwZl٤ N/t>GP_rRg򘧸Q^$D˗#DE^ 3۶m s @IA3!?;]믿._uB|g6ᣏ>*L0@bf&KBiuE: y嗋x}'Gy$zo̙ҫW/Zf9R}]dYg%3n&L(Uʕ+uE:XL%A@οjmƪUbf(:\}vtNGw4tiӦΛo|嗎鋣[:{;vtэ%wa{]w(q;CutS8gȐ!… d Lx9/_zj>t֭hBysP?"*) Wr䯥J /_{rGUW]G5;v:W\ak|r>yfڵk 6{.o?l2ndLװN;-\ @ `Crw2_u.0=G!ԭ(@W_4>}V>G.PecƟX VjԨalC-[fݵkWÇ~h}c ݒvH#?2Ob"KHDaN:I~mYxرC^zh>hsrr_֮]+j7j*}ؼ[vmҤ1 6dyd]<Z!ЪU+ѣٝr 'Ds<:f͚::ulv' .En? -x|l 6+%F2qx]=1ӎ]=*T@!D@t!D`TH`Rzꩧ=D U8HE1L!^ @(3HYoه#VE&";HÖ!"@|߷EÄ"@r?w2d"@o h0"@@ [L-$ F$aː Eۢa¼B`ܸqff7{lOL?su*MfGm~7&.kEs駟E]3D C:"|[4Ow}1D")4d 'D $,4&")$LDD_$"@2E)|"P Иd"@@3E"@ Ly"@@"@/Bc "@A>O(@HXhL2 D SH"Iu>p@ȺRRJ/ .Xlc+&3PWPgzFy%}*bS@ݝ@Ag(Q%DCĿ{;!@}A=oC-".6Q]n}Bʪ_^*8,a!ʛlS8EĦnඑctCuO0ڳ&?(ݪoEoUsT U,G[G?v_MnBhx(R|U݃%4pAbQI]4r;=|?Ώ\UUkt8O4\RŸzG6uF ?UZǨmuE:MuE TPZuj!~Ě|Z7~^#y*4gďZccT:U@?P'+.>艹uǨ^:@7B;!d[:(΍ ?GZ@ pSNREDPnIߚ{H J_~sc}Uש`ovpA7<![$,JGiǪTߩV}V;AI Fǫx^*R0J.$ג< 88BO 5R}Pk8W=UR=Du%~=4sJQb6k*v/q&~ K|ZJˈ{IV?z`v F TOULOWD"w tZglPXO#4/Jk @Ϫj^]@a?SKUoӨC]$uWc&@Q̥ \<|.ȿ I܍F\%7w)^;V~Ia*vEq`Q%zJO#\wB#*0'UI#TT?/꡺*: mi$zUYx*Cե8$/0$_I0`P%L0*QRCB죊_ZNt } z%+5XsєgԲh{Cˡɤ%GIEo"DVm޷ۄ067 do-}@N_+l>oPˆz$>5s[{ ~0l"=ޭHv, fU=6n@YߦzޟX8 MJ1K@qgD1BWPB& y;ڷX=kEB'IU?T-V?0?bRE m!~%zLO$֥W}G%RF4*^!KDSߵ Zo۽T\ TCu֛ԥ-?y :'I+G.Z1oO=΋_^m&{^Oj#LLeJ@ 0eWŨ2o<ڵԨQCԩ#5ѣGGЪU+ԩS@]U}.R)@&#?aA?FwrI'I.]瞓AIJ3A"Ňi]9aAˆfH  =}F&G„=/oF85jWڴi#C~O{O?yݽ{wĉez5q#<5\#SL1}]iܸLԋʆ  /͛KΝ媫7O7o#FHv̽믿ޤ7ϟo[ű+&M*0REk?PkBCJ RI(+FUUVm m7U |9˗wuԫWϜϜ9QRwgnݺ~X[>lsm\Gޫjs[lt\ۍ;r9[ͽ'xKo9묳̽_~ٳs]w9jBrj׮[X\P:0ߠP`6,!\i9aY lgbΠ _eU~&5k֔|PVX!JR~}}hG`L9{>O?dao^q3'0`ȷ~k\1(KZ䦛n2iw}eǎH2eD;3f-eӦMDI?ѣDPwPP(jTݿ$&@ ]N6w9aj6s V[+~ 8PVP}_\2j&4vX^1zRJ!C=$*TrВ%KN:Hf̘Q$&mJy?d0" ۑ\(:hB)[6{OzEnMm8V&z 0Zn-j2o~M`ذa&-x{1ȑ#܃ n`#@g7L!R?^ҷlbFcu…f x0 q_r%f[n=z;&c4h ͚53&K/T8ycs=o'm۶kVz%=JXⷮH =<3ICU۩bYT}gn,ZL2Q7{#~3s ^\=={ӢE V<؝+~9:x q̙IQ۾w:y58*Wѹs?!2R=U޿j-U,oLxkYavJZ8I_NaEPM* ,]TVZ% k1s 0 Lj:`9KZ9]"Ku9 T;4LV KM8GXpB!/&\_f;;2A2\bQ?=ɭ]$'nN5hn{-穆EB>PwPHRiҚ.چj+ XO7|vUN_J!. Ǩ?qp@om@swhL6^K A39I M?3mp[a$zjdCva3%lw#9K, `2Ҍp_.k:G![Ǥ14>Q'}Ft?_eD ŖKTA_ d#@ (6y$XDxN@:jy|G5Xa \"S0I'})>-db9 )#Uۦ0 $H@ ݿ_@Ť#@ ȝ< " gϒ=#:/ IPHL"(twsjBHoӘ)=ZbݰL ԲE]&Ӈ`GÂI3I ׏KӋkqIīG%={G#IaΞ%}';d_F&2HmEP8v8۟ԑH6w?ɡNj =R|@Q Z>.o\SW4=1 `G$P21Ru^Y׮]cǎ@Al=}BFv(t6^4X+=Ϫ{UWM7TbSNN:)믿^ /z%z!vv\x210@WANfyA]_߯y)E%g3 F~>m2a9Ko!=z&Mg-]gu1By8q/șg) 6c=V~h[nAIݺu#EEك7\ 7:J>c{7Ǩu{3c9:燯|7`i#ci#&TAuk=/V˖-eرkcƌ &:kO0Xyᇍ?åN:ү_?~0)ԯ__>39s.3akAgѡE]$+WzKp|˪Ub8@P(":cǔ`!Rr kDd0ju{=2իW7~N?tYd `aʙ؁><0oRvG=A?_~={4ď}{ 4llֆ?"@F@:0^Js;Y[*;'|[8 _.6[^z%{Gd0cw1aۀ;jrp0"#Zw8Im-sNV=NO7vß`L"A.[0_b٭ח/_.o1/K xOny>k[pyM#")GcAh МO8_=/L #@ǀɿ4xl /}b(HMd*aQ9zjI<$07C .¤p|udΜ9i=ˇHdRߟfp>K@`[9kn=ꫯ]vɍ7h1"j_̗Z3@98@G^Jڎ7fi׮[48'NtN9nRLz۷/nQ:qvWO>Hʕ~ⰿ?l»KO k;M%^̙3ͳ =@>m܈$5+f NNs`WW L fЊ=#6{.WYʎ 4 >9h͛77_cퟱ=4AcU} ^`=TuV$p=.WXo;?](MRّ3QxT~(/X@;0A'?6ópAxAh 0kad:)h]2=,|N'辤c1cƘ]A)꜂ I&ҬY3 2ydY퍒'*ix z*fGje~Ku*u k+VPg ~z6ׄ*Xу}AXөS';s75p@ѿu4/"`Oa0)yC̆H Pn X;4kށ w<.[Lʗ//u)vB:=mn/rmVO`,օI ܢ[DhٲhCtD0?M+,6 X=([3F ~4h-FݏgyFF%|򉩯0ab+׌{GZn-}}4M3vУDM \E[lSE'KNʣ7JߑIGE+47[UoT=Z[`[:O+~/=-L?N:7vJ;w)0S?!w0b՜k 'eb ̕͘1#g7DMG o@z99' SHJSZD%[U"7`_Lkczryѣ .7a}o6?ҹsghV70ҡCر :Tϓ쭨:JG7`7E1fl'\C74TWER|KG3sTG^'۝:}C;jTkXӃB@hâ~ႅ 0`C=dV~,[2f)\xf u?X0dso"b94ك *r'@ďG: >E"?aY} գ{hIM% &u*wa.Tgh_믿|V=>sƯ7z˘X믿UrXI.Sc>S߿f4Q%?D &z6M0кCA)`ö6#:czT 6 ؑFc\\{Wa,a5kV10|f>`YGq0FF ~+s(ڸqYUd8@QwKV05A"H06OuJLB]gZBSg0@1$.<ӦM3W_}w}oRVT9`˒aÆիm5k쩌?^9>_wu9,M(PBv_jRX^mwh {^$ -Z0Kr}Za$ƃ坰4T0MiEMj :k#6hq :iݴ2MO 6>Zh lgO6=x@N3?$`W.}?Iۀ.Lo?3nO BD=9y.jL%m]_)%ڳ)@Psϵ9L]hv0Z@Y/60 D?"0>@6n$7_㾖R~0Xs?HrL"6$AC@IEACbȔ)֍D ?֙:NlbyN@}l.̏wzd]bߤ{9#$y@ ]Hc?z1Q@[GcMv ~4t5p`@lvE'ogx;{!#">C FF&~}V9NԒ?cK죄iCl-><iaډ[콤ܴT_"Cp&6~;A[IhB[G طDc  !TE .rz C",cDc(Ź5Yⷮޢ[9-ÅQ?.bȄ{;+Wt?s 9䓋su+ײ]w+Edo0򯨊|n;n:+`*9R꾪xk>QemK:E}: [;iʠArc|rٱc_|!r;v0 $|ҮUa<&F]ό[`9sOfk7c _|QW.Z~F:uDwXt!uq֮]+SLqG){ @A,fX[lG-OB?tE /[L`L c;kiEHܦ~6-ٳmFjn/X7~746mjıӧ˜(\S%@>=j CoT`L֮ ._ `'0 A &r zŗ6{'Q`#'B׹ԕM0!c:4,v}6[8qP>+Ҽ5nX>hYdI>>Ѭ}P0K֭kޔ+@M(Eys#j*,X!7xI5&aJ_՜uך?aZ{G7tMfI.BCW̰OjOZ@xYfɝVLab>=L[?7|t(ŷ:uCT̪/襩xA+EE`,Kk%5: :  D (b<'UYn޼y3,Ĉܢ_;Q5k Cǎ7;XbG%yN!M@b}uVQk!KJXo`_y&nq_Hc%t+ kh,}衇=7\FǾG@{i"+&[ꒇTk:k}UAѹ6 z6ۋWM;]=2Pct^ #*>X/{apG Rճ9Wټ.Oцl4jTC_^\Go$4#4 =J;U^4fV%_\qM׶eu֢;f=\Hɟ/t2J40`uNWըh\@P \ Tf(UQ!}wW_2@p?8e( OLB3}4UOתxn!Eآe!{GuU)D TNfTm/GzS:,#UGӒv2O̓> 6#Fؿ=zFֿ4MȾD}V LN`"vV1OUa+UdN5Z'Qdڴi2gyw_Og &w!\pYb63bK h[ڸҮ` M'OAٰa{;;q:c'.9rsǚcG"wwގ=A!uQs䯈R m[TnJNy]=3{VX e˖c|M(DߍHgv䧟Hi`;̞ܹf'MEj@|@]=Քcvfo#SN5jo2n8sN?On3l9p@Q,TjUwqܼҡCYt :T3 1XoWO2Z`6xc5jY @A!0 D$쮞~ʖ-+mڴ=OgBm.~f'>\ƴ I1[IK8Pa.A@\~ D 14$Ɔw Eآeƈ  'Ɔw Eآeƈ  'Ɔw Eآeƈ  'Ɔw Eآeƈ  'Ɔw@.?2AZ5CJA`뾭;kۥKLj>@6b5xcx~FO*z$YC6^䳖s +;":vx9m HKh̶A;yٽ+P`@v'@ WZGcƨڪ5UbOJUΎAA& kUWnSE}>ajBO /&"`+\4d4h(fU=h[~&:Qzz)"2G09mC%~ ss4:_5,^ꃽi ?m H ,!oUE#=ڎ/h1fijX ;? ꍵE kq1Ѹ+܃YV52o}4SH5 bl \EiH"xmhK츎k 4r?6Ƥ7g .ȣP07D:51-\Hxq#Z?1܎*AP!K` \?-azBO7>EB4°ǖ&Ans$kfAVp|ꋪ)p4-!"#=mqcoG$l~+~bfުcc.+p1ӂth wۀѸďH6꯯yy8 bKĐ{$v#=28<, oFa#y*&1&a!}jt0c+fƷ2uI"';*-Y$! "@_Bɯ+t v"| ~C};c%D+5Eu|*&mMJ&Tq_:FA„xÄAy=\=Jֳaz  @dFA$C 3 "@ D"@=Q"@o%"@<@ȌoزqKI2(1>=:iF%۷_޽{ȑ#c\xL:žݶmʗKeڴiR{;С̝;׻E _eUa\D8q瞲i&ᅲz< ׯC͛Oƍ7|#7|u]ҿٺuT^]{9;vl0ʕ+'_|rC=$s̑GyD.\(ÇN:rꫯJ5{3fȲe䩧A˓^%D Ud͚5vZoJӦM~rG+"s1Ҷm[[ qLbHދƤII&K͚5_nIx y7ΝGݲd5k+4.HZhA %^؍Ad0_z}2uTڵ-[LO0A8 Cx;Ć[oܻ[ȼyd2dց LJ={2en$=#@O+$G ?#ygdƬ &Aƍ3S,:6mŋcwq1z9HڵmҮ];Yh9_`{Arү_?cw}VZҾ}{cѣ<D_D ,[SZw!{」^ajs bŊaZjOA}?©S'-MWXs5!)U i0"@ 0"@WB"@|G"@BҌ"#G 0CӰt̟?_Վ 㮟;ø~>Υyp#_G=W93;hx{x36"j( z>ΞwX3&"J1gNPJ |iN@"${h~ު_ _@=#\٤LJ\x8A!0 DPP¯zG%=T1? 8Uq01D(d+WVC# _ 0(tU=N{(S͙h,pED 5%z?|Wdlq%Y=^vsvO ?>B>HߪE:ƚS#z\%x 6cU PJXJ@-[u!ܯr&fWU_QYVt;ԋ:f|"?>^N a_¯#PG'@II,z%@ }T9Rr-ηc;Z "F:ARddve?裓~;)// џyRB9W_5]p2gՒYbo`varE :mfL5 64֨QCz!Crp~?H3<#:uۈ[nF< %@J XJ˪bڪU۫vW*EEl7|;:wԖL:o㏣ח.]B`R ^!@ iC$B WH3"@ 0"@WB"@|Gu}$;'%'d(`nIߖw$&@ Kfb/MAb+<0 DKHM;46y/Ҹ;o\_l)#`ݮlUݨ^u`nG$~#U!7p@@M * {oRݢ \qϚl%J؊#D`ߒHM y6 hc$!#ہ?8P0R*h/c {% )FÅ F bv z`jآӍ%JEnĄ=j[ⷣ~iQR;8Ceű% q.$oGvTo,cԏeߺ1ܻqޚ|Z7~Q>O$"nR“ u{ d6e'y1>_AHCl1!X?JSމ"n2f k!+(ip m`q؃oJ)"FG1ك-['g^S,õ$DZD9 ǔ  XP,1p?cğ:'HQ(x@CIȞ3nv$gGB((J!D!@Y3D @g= D Y&DY !DBg $"@@ Йe"@ɟu"BH!,tf"@g DՕ*IENDB`./nsf2.4.0/doc/next-tutorial/next-tutorial.txt000644 000766 000024 00000270755 14274465045 022167 0ustar00neumannstaff000000 000000 Tutorial for the Next Scripting Language ========================================== Gustaf Neumann , Stefan Sobernig v2.4.0, Aug 2022: Written for the Initial Release of the Next Scripting Framework. :Author Initials: GN :toc: :toclevels: 4 :icons: :numbered: :website: http://www.xotcl.org/ .Abstract ***************************************************************************** This document provides a tutorial for the Next Scripting Language NX. ***************************************************************************** The Next Scripting Language (NX) is a highly flexible object oriented scripting language based on Tcl <>. NX is a successor of XOTcl 1 <> and was developed based on 10 years of experience with XOTcl in projects containing several hundred thousand lines of code. While XOTcl was the first language designed to provide _language support for design patterns_, the focus of the Next Scripting Framework and NX is on combining this with _Language Oriented Programming_. In many respects, NX was designed to ease the learning of the language for novices (by using a more mainstream terminology, higher orthogonality of the methods, less predefined methods), to improve maintainability (remove sources of common errors) and to encourage developers to write better structured programs (to provide interfaces) especially for large projects, where many developers are involved. The Next Scripting Language is based on the Next Scripting Framework (NSF) which was developed based on the notion of language oriented programming. The Next Scripting Frameworks provides C-level support for defining and hosting multiple object systems in a single Tcl interpreter. The name of the Next Scripting Framework is derived from the universal method combinator "next", which was introduced in XOTcl. The combinator "next" serves as a single instrument for method combination with filters, per-object and transitive per-class mixin classes, object methods and multiple inheritance. The definition of NX is fully scripted (e.g. defined in +nx.tcl+). The Next Scripting Framework is shipped with three language definitions, containing NX and XOTcl 2. Most of the existing XOTcl 1 programs can be used without modification in the Next Scripting Framework by using XOTcl 2. The Next Scripting Framework requires Tcl 8.5 or newer. == NX and its Roots Object oriented extensions of Tcl have quite a long history. Two of the most prominent early Tcl based OO languages were _incr Tcl_ (abbreviated as itcl) and Object Tcl (_OTcl_ <>). While itcl provides a traditional C++/Java-like object system, OTcl was following the CLOS approach and supports a dynamic object system, allowing incremental class and object extensions and re-classing of objects. Extended Object Tcl (abbreviated as XOTcl <>) is a successor of OTcl and was the first language providing language support for design patterns. XOTcl extends OTcl by providing namespace support, adding assertions, dynamic object aggregations, slots and by introducing per-object and per-class filters and per-object and per-class mixins. XOTcl was so far released in more than 30 versions. It is described in its detail in more than 20 papers and serves as a basis for other object systems like TclOO [Donal ???]. The scripting language _NX_ and the _Next Scripting Framework_ <> extend the basic ideas of XOTcl by providing support for _language-oriented programming_. The the Next Scripting Framework supports multiple object systems concurrently. Effectively, every object system has different base classes for creating objects and classes. Therefore, these object systems can have different interfaces and can follow different naming conventions for built-in methods. Currently, the Next Scripting Framework is packaged with three object systems: NX, XOTcl 2.0, and TclCool (the language introduced by TIP#279). image::languages.png[align="center",width=500,title="Language History of the Next Scripting Language",alt="Languages"] {set:img-languages:Figure {figure-number}} The primary purpose of this document is to introduce NX to beginners. We expect some prior knowledge of programming languages, and some knowledge about Tcl. In the following sections we introduce NX by examples. In later sections we introduce the more advanced concepts of the language. Conceptually, most of the addressed concepts are very similar to XOTcl. Concerning the differences between NX and XOTcl, please refer to the _Migration Guide for the Next Scripting Language_. == Introductory Overview Example: Stack A classical programming example is the implementation of a stack, which is most likely familiar to many readers from many introductory programming courses. A stack is a last-in first-out data structure which is manipulated via operations like +push+ (add something to the stack) and +pop+ remove an entry from the stack. These operations are called _methods_ in the context of object oriented programming systems. Primary goals of object orientation are encapsulation and abstraction. Therefore, we define a common unit (a class) that defines and encapsulates the behavior of a stack and provides methods to a user of the data structure that abstract from the actual implementation. === Define a Class "Stack" In our first example, we define a class named +Stack+ with the methods +push+ and +pop+. When an instance of the stack is created (e.g. a concrete stack +s1+) the stack will contain an instance variable named +things+, initialized with an empty list. [[xmp-class-stack]] .Listing {counter:figure-number}: Class Stack {set:xmp-class-stack:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create Stack { # # Stack of Things # :variable things {} :public method push {thing} { set :things [linsert ${:things} 0 $thing] return $thing } :public method pop {} { set top [lindex ${:things} 0] set :things [lrange ${:things} 1 end] return $top } } -------------------------------------------------- Typically, classes are defined in NX via +nx::Class create+, followed by the name of the new class (here: +Stack+). The definition of the stack placed between curly braces and contains here just the method definitions. Methods of the class are defined via +:method+ followed by the name of the method, an argument list and the body of the method, consisting of Tcl and NX statements. When an instance of +Stack+ is created, it will contain an instance variable named +things+. If several +Stack+ instances are created, each of the instances will have their own (same-named but different) instance variable. The instance variable +things+ is used in our example as a list for the internal representation of the stack. We define in a next step the methods to access and modify this list structure. A user of the stack using the provided methods does not have to have any knowledge about the name or the structure of the internal representation (the instance variable +things+). The method +push+ receives an argument +thing+ which should be placed on the stack. Note that we do not have to specify the type of the element on the stack, so we can push strings as well as numbers or other kind of things. When an element is pushed, we add this element as the first element to the list +things+. We insert the element using the Tcl command +linsert+ which receives the list as first element, the position where the element should be added as second and the new element as third argument. To access the value of the instance variable we use Tcl's dollar operator followed by the name. The names of instance variables are preceded with a colon +:+. Since the name contains a non-plain character, Tcl requires us to put braces around the name. The command +linsert+ and its arguments are placed between square brackets. This means that the function +linsert+ is called and a new list is returned, where the new element is inserted at the first position (index 0) in the list +things+. The result of the +linsert+ function is assigned again to the instance variable +things+, which is updated this way. Finally, the method +push+ returns the pushed thing using the +return+ statement. The method +pop+ returns the most recently stacked element and removes it from the stack. Therefore, it takes the first element from the list (using the Tcl command +lindex+), assigns it to the method-scoped variable +top+, removes the element from the instance variable +things+ (by using the Tcl command +lrange+) and returns the value popped element +top+. This finishes our first implementation of the stack, more enhanced versions will follow. Note that the methods +push+ and +pop+ are defined as +public+; this means that these methods can be used from all other objects in the system. Therefore, these methods provide an interface to the stack implementation. [[xmp-using-stack]] .Listing {counter:figure-number}: Using the Stack {set:xmp-using-stack:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- #!/usr/bin/env tclsh package require nx nx::Class create Stack { # # Stack of Things # .... } Stack create s1 s1 push a s1 push b s1 push c puts [s1 pop] puts [s1 pop] s1 destroy -------------------------------------------------- Now we want to use the stack. The code snippet in <> shows how to use the class Stack in a script. Since NX is based on Tcl, the script will be called with the Tcl shell +tclsh+. In the Tcl shell we have to +require package nx+ to use the Next Scripting Framework and NX. The next lines contain the definition of the stack as presented before. Of course, it is as well possible to make the definition of the stack an own package, such we could simple say +package require stack+, or to save the definition of a stack simply in a file and load it via +source+. In line 12 we create an instance of the stack, namely the stack object +s1+. The object +s1+ is an instance of +Stack+ and has therefore access to its methods. The methods like +push+ or +pop+ can be invoked via a command starting with the object name followed by the method name. In lines 13-15 we push on the stack the values +a+, then +b+, and +c+. In line 16 we output the result of the +pop+ method using the Tcl command +puts+. We will see on standard output the value+c+ (the last stacked item). The output of the line 17 is the value +b+ (the previously stacked item). Finally, in line 18 we destroy the object. This is not necessary here, but shows the life cycle of an object. In some respects, +destroy+ is the counterpart of +create+ from line 12. [[fig-class-object]] image::object-class-appclass.png[title="Class and Object Diagram",align="center"] {set:fig-class-object:Figure {figure-number}} <> shows the actual class and object structure of the first +Stack+ example. Note that the common root class is +nx::Object+ that contains methods for all objects. Since classes are as well objects in NX, +nx::Class+ is a specialization of +nx::Object+. +nx::Class+ provides methods for creating objects, such as the method +create+ which is used to create objects (and classes as well). === Define an Object Named "stack" The definition of the stack in <> follows the traditional object oriented approach, found in practically every object oriented programming language: Define a class with some methods, create instances from this class, and use the methods defined in the class in the instances of the class. In our next example, we introduce _generic objects_ and _object specific methods_. With NX, we can define generic objects, which are instances of the most generic class +nx::Object+ (sometimes called _common root class_). +nx::Object+ is predefined and contains a minimal set of methods applicable to all NX objects. In this example, we define a generic object named +stack+ and provide methods for this object. The methods defined above were methods provided by a class for objects. Now we define object specific methods, which are methods applicable only to the object for which they are defined. [[xmp-object-stack]] .Listing {counter:figure-number}: Object stack {set:xmp-object-stack:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Object create stack { :object variable things {} :public object method push {thing} { set :things [linsert ${:things} 0 $thing] return $thing } :public object method pop {} { set top [lindex ${:things} 0] set :things [lrange ${:things} 1 end] return $top } } -------------------------------------------------- The example in <> defines the object +stack+ in a very similar way as the class +Stack+. But the following points are different. - First, we use +nx::Object+ instead of +nx::Class+ to denote that we want to create a generic object, not a class. - We use +:object variable+ to define the variable +things+ just for this single instance (the object +stack+). - The definition for the methods +push+ and +pop+ are the same as before, but here we defined these with +object method+. Therefore, these two methods +push+ and +pop+ are object-specific. In order to use the stack, we can use directly the object +stack+ in the same way as we have used the object +s1+ in <> (e.g. +stack push a+). <> shows the class diagram for this the object +stack+. [[img-object-stack]] image::object-stack.png[title="Object stack",align="center"] {set:img-object-stack:Figure {figure-number}} A reader might wonder when to use a class +Stack+ or rather an object +stack+. A big difference is certainly that one can define easily multiple instances of a class, while the object is actually a single, tailored entity. The concept of the object +stack+ is similar to a module, providing a certain functionality via a common interface, without providing the functionality to create multiple instances. The reuse of methods provided by the class to objects is as well a difference. If the methods of the class are updated, all instances of the class will immediately get the modified behavior. However, this does not mean that the reuse for the methods of +stack+ is not possible. NX allows for example to copy objects (similar to prototype-based languages) or to reuse methods via e.g. aliases (more about this later). Note that we use capitalized names for classes and lowercase names for instances. This is not required and a pure convention making it easier to understand scripts without much analysis. === Implementing Features using Mixin Classes So far, the definition of the stack methods was pretty minimal. Suppose, we want to define "safe stacks" that protect e.g. against stack under-runs (a stack under-run happens, when more +pop+ than +push+ operations are issued on a stack). Safety checking can be implemented mostly independent of the implementation details of the stack (usage of internal data structures). There are as well different ways of checking the safety. Therefore, we say that safety checking is orthogonal to the stack core implementation. With NX we can define stack-safety as a separate class using methods with the same names as the implementations before, and "mix" this behavior into classes or objects. The implementation of +Safety+ in <> uses a counter to check for stack under-runs and to issue error messages, when this happens. [[xmp-class-safety]] .Listing {counter:figure-number}: Class Safety {set:xmp-class-safety:Listing {figure-number}} [source,tcl,numbered] -------------------------------------------------- nx::Class create Safety { # # Implement stack safety by defining an additional # instance variable named "count" that keeps track of # the number of stacked elements. The methods of # this class have the same names and argument lists # as the methods of Stack; these methods "shadow" # the methods of class Stack. # :variable count 0 :public method push {thing} { incr :count next } :public method pop {} { if {${:count} == 0} { error "Stack empty!" } incr :count -1 next } } -------------------------------------------------- Note that all the methods of the class +Safety+ end with +next+. This command is a primitive command of NX, which calls the same-named method with the same argument list as the current invocation. Assume we save the definition of the class +Stack+ in a file named +Stack.tcl+ and the definition of the class +Safety+ in a file named +Safety.tcl+ in the current directory. When we load the classes +Stack+ and +Safety+ into the same script (see the terminal dialog in <>), we can define e.g. a certain stack +s2+ as a safe stack, while all other stacks (such as +s1+) might be still "unsafe". This can be achieved via the option +-mixin+ at the object creation time (see line 9 in <>) of s2. The option +-mixin+ mixes the class +Safety+ into the new instance +s2+. [[xmp-using-class-safety]] .Listing {counter:figure-number}: Using the Class Safety {set:xmp-using-class-safety:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- % package require nx 2.0 % source Stack.tcl ::Stack % source Safety.tcl ::Safety % Stack create s1 ::s1 % Stack create s2 -object-mixin Safety ::s2 % s2 push a % s2 pop a % s2 pop Stack empty! % s1 info precedence ::Stack ::nx::Object % s2 info precedence ::Safety ::Stack ::nx::Object -------------------------------------------------- When the method +push+ of +s2+ is called, first the method of the mixin class +Safety+ will be invoked that increments the counter and continues with +next+ to call the shadowed method, here the method +push+ of the +Stack+ implementation that actually pushes the item. The same happens, when +s2 pop+ is invoked, first the method of +Safety+ is called, then the method of the +Stack+. When the stack is empty (the value of +count+ reaches 0), and +pop+ is invoked, the mixin class +Safety+ generates an error message (raises an exception), and does not invoke the method of the +Stack+. The last two commands in <> use introspection to query for the objects +s1+ and +s2+ in which order the involved classes are processed. This order is called the +precedence order+ and is obtained via +info precedence+. We see that the mixin class +Safety+ is only in use for +s2+, and takes precedence over +Stack+. The common root class +nx::Object+ is for both +s1+ and +s2+ the base class. [[img-per-object-mixin]] image::per-object-mixin.png[title="Per-object Mixin",align="center"] {set:img-per-object-mixin:Figure {figure-number}} Note that in <>, the class +Safety+ is only mixed into a single object (here +s2+), therefore, we refer to this case as a _per-object mixin_. <> shows the class diagram, where the class +Safety+ is used as a per-object mixin for +s2+. The mixin class +Safety+ can be used as well in other ways, such as e.g. for defining classes of safe stacks: [[xmp-class-safestack]] .Listing {counter:figure-number}: Class SafeStack {set:xmp-class-safestack:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- # # Create a safe stack class by using Stack and mixin # Safety # nx::Class create SafeStack -superclasses Stack -mixins Safety SafeStack create s3 -------------------------------------------------- The difference of a per-class mixin and a per-object mixin is that the per-class mixin is applicable to all instances of the class. Therefore, we call these mixins also sometimes instance mixins. In our example in <>, +Safety+ is mixed into the definition of +SafeStack+. Therefore, all instances of the class +SafeStack+ (here the instance +s3+) will be using the safety definitions. [[img-per-class-mixin]] image::per-class-mixin.png[title="Per-class Mixin",align="center"] {set:img-per-class-mixin:Figure {figure-number}} <> shows the class diagram for this definition. Note that we could use +Safety+ as well as a per-class mixin on +Stack+. In this case, all stacks would be safe stacks and we could not provide a selective feature selection (which might be perfectly fine). === Define Different Kinds of Stacks The definition of +Stack+ is generic and allows all kind of elements to be stacked. Suppose, we want to use the generic stack definition, but a certain stack (say, stack +s4+) should be a stack for integers only. This behavior can be achieved by the same means as introduced already in <>, namely object-specific methods. [[xmp-object-integer-stack]] .Listing {counter:figure-number}: Object Integer Stack {set:xmp-object-integer-stack:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- Stack create s4 { # # Create a stack with an object-specific method # to check the type of entries # :public object method push {thing:integer} { next } } -------------------------------------------------- The program snippet in <> defines an instance +s4+ of the class +Stack+ and provides an object specific method for +push+ to implement an integer stack. The method +pull+ is the same for the integer stack as for all other stacks, so it will be reused as usual from the class +Stack+. The object-specific method +push+ of +s4+ has a value constraint in its argument list (+thing:integer+) that makes sure that only integers can be stacked. In case the argument is not an integer, an exception will be raised. Of course, one could perform the value constraint checking as well in the body of the method +proc+ by accepting a generic argument and by performing the test for the value in the body of the method. In the case, the passed value is an integer, the +push+ method of <> calls +next+, and therefore calls the shadowed generic definition of +push+ as provided by +Stack+. [[xmp-class-integer-stack]] .Listing {counter:figure-number}: Class IntegerStack {set:xmp-class-integer-stack:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create IntegerStack -superclass Stack { # # Create a Stack accepting only integers # :public method push {thing:integer} { next } } -------------------------------------------------- An alternative approach is shown in <>, where the class +IntegerStack+ is defined, using the same method definition as +s4+, this time on the class level. === Define Object Specific Methods on Classes In our previous examples we defined methods provided by classes (applicable for their instances) and object-specific methods (methods defined on objects, which are only applicable for these objects). In this section, we introduce methods that are defined on the class objects. Such methods are sometimes called _class methods_ or _static methods_. In NX classes are objects, they are specialized objects with additional methods. Methods for classes are often used for managing the life-cycles of the instances of the classes (we will come to this point in later sections in more detail). Since classes are objects, we can use exactly the same notation as above to define class methods by using +object method+. The methods defined on the class object are in all respects identical with object specific methods shown in the examples above. [[xmp-stack2]] .Listing {counter:figure-number}: Class Stack2 {set:xmp-stack2:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create Stack2 { :public object method available_stacks {} { return [llength [:info instances]] } :variable things {} :public method push {thing} { set :things [linsert ${:things} 0 $thing] return $thing } :public method pop {} { set top [lindex ${:things} 0] set :things [lrange ${:things} 1 end] return $top } } Stack2 create s1 Stack2 create s2 puts [Stack2 available_stacks] -------------------------------------------------- The class +Stack2+ in <> consists of the earlier definition of the class +Stack+ and is extended by the class-specific method +available_stacks+, which returns the current number of instances of the stack. The final command +puts+ (line 26) prints 2 to the console. [[img-stack2]] image::stack2.png[align="center",title="Stack2"] {set:img-stack2:Figure {figure-number}} The class diagram in <> shows the diagrammatic representation of the class object-specific method +available_stacks+. Since every class is a specialization of the common root class +nx::Object+, the common root class is often omitted from the class diagrams, so it was omitted here as well in the diagram. == Basic Language Features of NX === Variables and Properties In general, NX does not need variable declarations. It allows one to create or modify variables on the fly by using for example the Tcl commands +set+ and +unset+. Depending on the variable name (or more precisely, depending on the variable name's prefix consisting of colons "+:+") a variable is either local to a method, or it is an instance variable, or a global variable. The rules are: - A variable without any colon prefix refers typically to a method scoped variable. Such a variable is created during the invocation of the method, and it is deleted, when the method ends. In the example below, the variable +a+ is method scoped. - A variable with a single colon prefix refers to an instance variable. An instance variable is part of the object; when the object is destroyed, its instance variables are deleted as well. In the example below, the variable +b+ is an instance variable. - A variable with two leading colons refers to a global variable. The lifespan of a globale variable ends when the variable is explicitly unset or the script terminates. Variables, which are placed in Tcl namespaces, are also global variables. In the example below, the variable +c+ is a global variable. [[xmp-var-resolver]] .Listing {counter:figure-number}: Scopes of Variables {set:xmp-var-resolver:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create Foo { :public method foo args {...} # "a" is a method scoped variable set a 1 # "b" is an Instance variable set :b 2 # "c" is a global variable/namespaced variable set ::c 3 } } -------------------------------------------------- <> shows a method +foo+ of some class +Foo+ referring to differently scoped variables. ==== Properties: Configurable Instance Variables As described above, there is no need to declare instance variables in NX. In many cases, a developer might want to define some value constraints for variables, or to provide defaults, or to make variables configurable upon object creation. Often, variables are "inherited", meaning that the variables declared in a general class are also available in a more specialized class. For these purposes NX provides _variable handlers_ responsible for the management of instance variables. We distinguish in NX between configurable variables (called +property+) and variables that are not configurable (called +variable+). ========================================= A *property* is a definition of a configurable instance variable. ========================================= The term configurable means that (a) one can provide at creation time of an instance a value for this variable, and (b), one can query the value via the accessor function +cget+ and (c), one can change the value of the variable via +configure+ at run time. Since the general accessor function +cget+ and +configure+ are available, an application developer does not have to program own accessor methods. When value checkers are provided, each time, the value of the variable is to be changed, the constrained are checked as well. [[img-person-student]] image::person-student.png[align="center",title="Classes Person and Student"] {set:img-person-student:Figure {figure-number}} The class diagram above defines the classes +Person+ and +Student+. For both classes, configurable instance variable are specified by defining these as properties. The listing below shows an implementation of this conceptual model in NX. [[xmp-properties]] .Listing {counter:figure-number}: Properties {set:xmp-properties:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- # # Define a class Person with properties "name" # and "birthday" # nx::Class create Person { :property name:required :property birthday } # # Define a class Student as specialization of Person # with additional properties # nx::Class create Student -superclass Person { :property matnr:required :property {oncampus:boolean true} } # # Create instances using configure parameters # for the initialization # Person create p1 -name Bob Student create s1 -name Susan -matnr 4711 # Access property value via accessor method puts "The name of s1 is [s1 cget -name]" -------------------------------------------------- By defining +name+ and +birthday+ as properties of +Person+, NX makes these configurable. When we create an instance of +Person+ named +p1+, we can provide a value for e.g. the name by specifying +-name+ during creation. The properties result in non-positional configure parameters which can be provided in any order. In our listing, we create an instance of +Person+ using the configure parameter +name+ and provide the value of +Bob+ to the instance variable +name+. The class +Student+ is defined as a specialization of +Person+ with two additional properties: +matnr+ and +oncampus+. The property +matnr+ is required (it has to be provided, when an instance of this class is created), and the property +oncampus+ is boolean, and is per default set to +true+. Note that the class +Student+ inherits the properties of +Person+. So, +Student+ has four properties in total. The property definitions provide the +configure parameters+ for instance creation. Many other languages require such parameters to be passed via arguments of a constructor, which is often error prone, when values are to be passed to superclasses. Also in dynamic languages, the relationships between classes can be easily changed, and different superclasses might have different requirements in their constructors. The declarative approach in NX reduces the need for tailored constructor methods significantly. Note that the property +matnr+ of class +Student+ is required. This means, that if we try to create an instance of +Student+, a run time exception will be triggered. The property +oncamups+ is boolean and contains a default value. Providing a default value means that whenever we create an instance of this class the object will contain such an instance variable, even when we provide no value via the configure parameters. In our listing, we create an instance of +Student+ using the two configure parameters +name+ and +matnr+. Finally, we use method +cget+ to obtain the value of the instance variable +name+ of object +s1+. ==== Non-configurable Instance Variables In practice, not all instance variables should be configurable. But still, we want to be able to provide defaults similar to properties. To define non-configurable instance variables the predefined method +variable+ can be used. Such instance variables are often used for e.g. keeping the internal state of an object. The usage of +variable+ is in many respects similar to +property+. One difference is, that +property+ uses the same syntax as for method parameters, whereas +variable+ receives the default value as a separate argument (similar to the +variable+ command in plain Tcl). The introductory Stack example in <> uses already the method +variable+. [[xmp-variable]] .Listing {counter:figure-number}: Declaring Variables {set:xmp-variable:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create Base { :variable x 1 # ... } nx::Class create Derived -superclass Base { :variable y 2 # ... } # Create instance of the class Derived Derived create d1 # Object d1 has instance variables # x == 1 and y == 2 -------------------------------------------------- Note that the variable definitions are inherited in the same way as properties. The example in <> shows a class +Derived+ that inherits from +Base+. When an instance +d1+ is created, it will contain the two instance variables +x+ and +y+. Note that the variable declarations from +property+ and +variable+ are used to initialize (and to configure) the instances variables of an object. [[xmp-constructor]] .Listing {counter:figure-number}: Setting Variables in the Constructor {set:xmp-constructor:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create Base2 { # ... :method init {} { set :x 1 # .... } } nx::Class create Derived2 -superclass Base2 { # ... :method init {} { set :y 2 next # .... } } # Create instance of the class Derived2 Derived2 create d2 -------------------------------------------------- In many other object oriented languages, the instance variables are initialized solely by the constructor (similar to class +Derived2+ in <>). This approach is certainly also possible in NX. Note that the approach using constructors requires an explicit method chaining between the constructors and is less declarative than the approach in NX using +property+ and +variable+. Both, +property+ and +variable+ provide much more functionalities. One can for example declare +public+, +protected+ or +private+ accessor methods, or one can define variables to be incremental (for e.g. adding values to a list of values), or one can define variables specific behavior. === Method Definitions The basic building blocks of an object oriented program are object and classes, which contain named pieces of code, the methods. =========================================== *Methods* are subroutines (pieces of code) associated with objects and/or classes. A method has a name, receives optionally arguments during invocation and returns a value. =========================================== Plain Tcl provides subroutines, which are not associated with objects or classes. Tcl distinguishes between +proc+s (scripted subroutines) and commands (system-languages implemented subroutines). Methods might have different scopes, defining, on which kind of objects these methods are applicable to. These are described in more detail later on. For the time being, we deal here with methods defined on classes, which are applicable for the instance of these classes. ==== Scripted Methods Since NX is a scripting language, most methods are most likely scripted methods, in which the method body contains Tcl code. [[xmp-fido1]] .Listing {counter:figure-number}: Scripted method {set:xmp-fido1:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- # Define a class nx::Class create Dog { # Define a scripted method for the class :public method bark {} { puts "[self] Bark, bark, bark." } } # Create an instance of the class Dog create fido # The following line prints "::fido Bark, bark, bark." fido bark -------------------------------------------------- In the example above we create a class +Dog+ with a scripted method named +bark+. The method body defines the code, which is executed when the method is invoked. In this example, the method +bar+ prints out a line on the terminal starting with the object name (this is determined by the built-in command +self+) followed by "Bark, bark, bark.". This method is defined on a class and applicable to instances of the class (here the instance +fido+). ==== C-implemented Methods Not all of the methods usable in NX are scripted methods; many predefined methods are defined in the underlying system language, which is typically C. For example, in <> we used the method +create+ to create the class +Dog+ and to create the dog instance +fido+. These methods are implemented in C in the next scripting framework. C-implemented methods are not only provided by the underlying framework but might be as well defined by application developers. This is an advanced topic, not covered here. However, application developer might reuse some generic C code to define their own C-implemented methods. Such methods are for example _accessors_, _forwarders_ and _aliases_. =========================================== An *accessor method* is a method that accesses instance variables of an object. A call to an accessor without arguments uses the accessor as a getter, obtaining the actual value of the associated variable. A call to an accessor with an argument uses it as a setter, setting the value of the associated variable. =========================================== NX provides support for C-implemented accessor methods. Accessors have already been mentioned in the section about properties. When the option +-accessor public|protected|private+ is provided to a +variable+ or +property+ definition, NX creates automatically a same-named accessors method. [[xmp-fido2]] .Listing {counter:figure-number}: Accessor Methods {set:xmp-fido2:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create Dog { :public method bark {} { puts "[self] Bark, bark, bark." } :method init {} { Tail create [self]::tail} } nx::Class create Tail { :property -accessor public {length:double 5} :public method wag {} {return Joy} } # Create an instance of the class Dog create fido # Use the accessor "length" as a getter, to obtain the value # of a property. The following call returns the length of the # tail of fido fido::tail length get # Use the accessor "length" as a setter, to alter the value # of a property. The following call changes the length of # the tail of fido fido::tail length set 10 # Show that an invalid value raises an error fido::tail length set "Hello" -------------------------------------------------- <> shows an extended example, where every dog has a tail. The object +tail+ is created as a subobject of the dog in the constructor +init+. The subobject can be accessed by providing the full name of the subobject +fido::tail+. The method +length+ is an C-implemented accessor, that enforces the value constraint (here a floating point number, since length uses the value constraint +double+). Line 25 will therefore raise an exception, since the provided values cannot be converted to a double number. [[xmp-fido3]] .Listing {counter:figure-number}: Forwarder Methods {set:xmp-fido3:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create Dog { :public method bark {} { puts "[self] Bark, bark, bark." } :method init {} { Tail create [self]::tail :public object forward wag [self]::tail wag } } nx::Class create Tail { :property {length 5} :public method wag {} {return Joy} } # Create an instance of the class Dog create fido # The invocation of "fido wag" is delegated to "fido::tail wag". # Therefore, the following method returns "Joy". fido wag -------------------------------------------------- <> again extends the example by adding a forwarder named +wag+ to the object (e.g. +fido+). The forwarder redirects all calls of the form +fido wag+ with arbitrary arguments to the subobject +fido::tail+. =========================================== A *forwarder method* is a C-implemented method that redirects an invocation for a certain method to either a method of another object or to some other method of the same object. Forwarding an invocation of a method to some other object is a means of delegation. =========================================== The functionality of the forwarder can just as well be implemented as a scripted method, but for the most common cases, the forward implementation is more efficient, and the +forward+ method expresses the intention of the developer. The method +forwarder+ has several options to change e.g. the order of the arguments, or to substitute certain patterns in the argument list etc. This will be described in later sections. ==== Method-Aliases =========================================== An *alias method* is a means to register either an existing method, or a Tcl proc, or a Tcl command as a method with the provided name on a class or object. =========================================== In some way, the method alias is a restricted form of a forwarder, though it does not support delegation to different objects or argument reordering. The advantage of the method alias compared to a forwarder is that it has close to zero overhead, especially for aliasing c-implemented methods. [[xmp-fido4]] .Listing {counter:figure-number}: Method-Alias {set:xmp-fido4:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create Dog { :public method bark {} { puts "[self] Bark, bark, bark." } # Define a public alias for the method "bark" :public alias warn [:info method handle bark] # ... } # Create an instance of the class Dog create fido # The following line prints "::fido Bark, bark, bark." fido warn -------------------------------------------------- <> extends the last example by defining an alias for the method +bark+. The example only shows the bare mechanism. In general, method aliases are very powerful means for reusing pre-existing functionality. The full object system of NX and XOTcl2 is built from aliases, reusing functionality provided by the next scripting framework under different names. Method aliases are as well a means for implementing traits in NX. === Method Protection All kinds of methods might have different kind of protections in NX. The call-protection defines from which calling context methods might be called. The Next Scripting Framework supports as well redefinition protection for methods. NX distinguishes between +public+, +protected+ and +private+ methods, where the default call-protection is +protected+. =========================================== A *public* method can be called from every context. A *protected* method can only be invoked from the same object. A *private* method can only be invoked from methods defined on the same entity (defined on the same class or on the same object) via the invocation with the local flag (i.e. "+: -local foo+"). =========================================== All kind of method protections are applicable for all kind of methods, either scripted or C-implemented. The distinction between public and protected leads to interfaces for classes and objects. Public methods are intended for consumers of these entities. Public methods define the intended ways of providing methods for external usages (usages, from other objects or classes). Protected methods are intended for the implementor of the class or subclasses and not for public usage. The distinction between protected and public reduces the coupling between consumers and the implementation, and offers more flexibility to the developer. [[xmp-protected-method]] .Listing {counter:figure-number}: Protected Methods {set:xmp-protected-method:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create Foo { # Define a public method :public method foo {} { # .... return [:helper] } # Define a protected method :method helper {} { return 1 } } # Create an instance of the class: Foo create f1 # The invocation of the public method "foo" returns 1 f1 foo # The invocation of the protected method "helper" raises an error: f1 helper -------------------------------------------------- The example above uses +:protected method helper ...+. We could have used here as well +:method helper ...+, since the default method call-protection is already protected. The method call-protection of +private+ goes one step further and helps to hide implementation details also for implementors of subclasses. Private methods are a means for avoiding unanticipated name clashes. Consider the following example: [[xmp-private-method]] .Listing {counter:figure-number}: Private Methods {set:xmp-private-method:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create Base { :private method helper {a b} {expr {$a + $b}} :public method foo {a b} {: -local helper $a $b} } nx::Class create Sub -superclass Base { :public method bar {a b} {: -local helper $a $b} :private method helper {a b} {expr {$a * $b}} :create s1 } s1 foo 3 4 ;# returns 7 s1 bar 3 4 ;# returns 12 s1 helper 3 4 ;# raises error: unable to dispatch method helper -------------------------------------------------- The base class implements a public method +foo+ using the helper method named +helper+. The derived class implements as well a public method +bar+, which is also using a helper method named +helper+. When an instance +s1+ is created from the derived class, the method +foo+ is invoked which uses in turn the private method of the base class. Therefore, the invocation +s1 foo 3 4+ returns its sum. If the +local+ flag had not been used in helper, +s1+ would have tried to call the helper of +Sub+, which would be incorrect. For all other purposes, the private methods are "invisible" in all situations, e.g., when mixins are used, or within the +next+-path, etc. By using the +-local+ flag at the call site it is possible to invoke only the local definition of the method. If we would call the method without this flag, the resolution order would be the standard resolution order, starting with filters, mixins, object methods and the full intrinsic class hierarchy. NX supports the modifier +private+ for methods and properties. In all cases +private+ is an instrument to avoid unanticipated interactions and means actually "accessible for methods defined on the same entity (object or class)". The main usage for +private+ is to improve locality of the code e.g. for compositional operations. In order to improve locality for properties, a private property defines therefore internally a variable with a different name to avoid unintended interactions. The variable should be accessed via the private accessor, which can be invoked with the +-local+ flag. In the following example class +D+ introduces a private property with the same name as a property in the superclass. [[xmp-private-properties]] .Listing {counter:figure-number}: Private Properties {set:xmp-private-properties:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- # # Define a class C with a property "x" and a public accessor # nx::Class create C { :property -accessor public {x c} } # # Define a subclass D with a private property "x" # and a method bar, which is capable of accessing # the private property. # nx::Class create D -superclass C { :property -accessor private {x d} :public method bar {p} {return [: -local $p get]} } # # The private and public (or protected) properties # define internally separate variable that do not # conflict. # D create d1 puts [d1 x get] ;# prints "c" puts [d1 bar x] ;# prints "d" -------------------------------------------------- Without the +private+ definition of the property, the definition of property +x+ in class +D+ would shadow the definition of the property in the superclass +C+ for its instances (+d1 x+ or +set :x+ would return +d+ instead of +c+). === Applicability of Methods As defined above, a method is a subroutine defined on an object or class. This object (or class) contains the method. If the object (or class) is deleted, the contained methods will be deleted as well. ==== Instance Methods =========================================== Typically, methods are defined on a class, and the methods defined on the class are applicable to the instances (direct or indirect) of this class. These methods are called *instance methods*. =========================================== In the following example method, +foo+ is an instance method defined on class +C+. [[xmp-instance-applicable]] .Listing {counter:figure-number}: Methods applicable for instances {set:xmp-instance-applicable:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create C { :public method foo {} {return 1} :create c1 } # Method "foo" is defined on class "C" # and applicable to the instances of "C" c1 foo -------------------------------------------------- There are many programming languages that only allow these types of methods. However, NX also allows methods to be defined on objects. ==== Object Methods =========================================== Methods defined on objects are *object methods*. Object methods are only applicable on the object, on which they are defined. Object methods cannot be inherited from other objects. =========================================== The following example defines an object method +bar+ on the instance +c1+ of class +C+, and as well as the object specific method +baz+ defined on the object +o1+. An object method is defined via +object method+. Note that we can define an object method that shadows (redefines) for this object methods provided from classes. [[xmp-object-applicable1]] .Listing {counter:figure-number}: Object Method {set:xmp-object-applicable1:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create C { :public method foo {} {return 1} :create c1 { :public object method foo {} {return 2} :public object method bar {} {return 3} } } # Method "bar" is an object specific method of "c1" c1 bar # object-specific method "foo" returns 2 c1 foo # Method "baz" is an object specific method of "o1" nx::Object create o1 { :public object method baz {} {return 4} } o1 baz -------------------------------------------------- ==== Class Methods ========================================= A *class method* is a method defined on a class, which is only applicable to the class object itself. The class method is actually an object method of the class object. ========================================= In NX, all classes are objects. Classes are in NX special kind of objects that have e.g. the ability to create instances and to provide methods for the instances. Classes manage their instances. The general method set for classes is defined on the meta-classes (more about this later). The following example defines a public class method +bar+ on class +C+. The class method is specified by using the modifier +object+ in front of +method+ in the method definition command. [[xmp-object-applicable2]] .Listing {counter:figure-number}: Class Methods {set:xmp-object-applicable2:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create C { # # Define a class method "bar" and an instance # method "foo" # :public object method bar {} {return 2} :public method foo {} {return 1} # # Create an instance of the current class # :create c1 } # Method "bar" is a class method of class "C" # therefore, applicable on the class object "C" C bar # Method "foo" is an instance method of "C" # therefore, applicable on instance "c1" c1 foo # When trying to invoke the class method on the # instance, an error will be raised. c1 bar -------------------------------------------------- In some other object-oriented programming languages, class methods are called "static methods". === Ensemble Methods NX provides _ensemble methods_ as a means to structure the method name space and to group related methods. Ensemble methods are similar in concept to Tcl's ensemble commands. ========================================= An *ensemble method* is a form of a hierarchical method consisting of a container method and sub-methods. The first argument of the container method is interpreted as a selector (the sub-method). Every sub-method can be a container method as well. ========================================= Ensemble methods provide a means to group related commands together, and they are extensible in various ways. It is possible to add sub-methods at any time to existing ensembles. Furthermore, it is possible to extend ensemble methods via mixin classes. The following example defines an ensemble method for +string+. An ensemble method is defined when the provide method name contains a space. [[xmp-ensemble-methods]] .Listing {counter:figure-number}: Ensemble Method {set:xmp-ensemble-methods:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create C { # Define an ensemble method "string" with sub-methods # "length", "tolower" and "info" :public method "string length" {x} {....} :public method "string tolower" {x} {...} :public method "string info" {x} {...} #... :create c1 } # Invoke the ensemble method c1 string length "hello world" -------------------------------------------------- === Method Resolution When a method is invoked, the applicable method is searched in the following order: [align="center"] ++++ Per-object Mixins -> Per-class Mixins -> Object -> Intrinsic Class Hierarchy ++++ In the case, no mixins are involved, first the object is searched for an object method with the given name, and then the class hierarchy of the object. The method can be defined multiple times on the search path, so some of these method definitions might be _shadowed_ by the more specific definitions. [[xmp-method-resolution]] .Listing {counter:figure-number}: Method Resolution with Intrinsic Classes {set:xmp-method-resolution:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create C { :public method foo {} { return "C foo: [next]" } } nx::Class create D -superclass C { :public method foo {} { return "D foo: [next]" } :create d1 { :public object method foo {} { return "d1 foo: [next]" } } } # Invoke the method foo d1 foo # result: "d1 foo: D foo: C foo: " # Query the precedence order from NX via introspection d1 info precedence # result: "::D ::C ::nx::Object" -------------------------------------------------- Consider the example in <>. When the method +foo+ is invoked on object +d1+, the object method has the highest precedence and is therefore invoked. The object methods shadows the same-named methods in the class hierarchy, namely the method +foo+ of class +D+ and the method +foo+ of class +C+. The shadowed methods can be still invoked, either via the primitive +next+ or via method handles (we used already method handles in the section about method aliases). In the example above, +next+ calls the shadowed method and add their results to the results of every method. So, the final result contains parts from +d1+, +D+ and +C+. Note that the topmost +next+ in method +foo+ of class +C+ shadows no method +foo+ and simply returns empty (and not an error message). The introspection method +info precedence+ provides information about the order, in which classes processed during method resolution. [[xmp-method-resolution2]] .Listing {counter:figure-number}: Method Resolution with Mixin Classes {set:xmp-method-resolution2:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create M1 { :public method foo {} { return "M1 foo: [next]"} } nx::Class create M2 { :public method foo {} { return "M2 foo: [next]"} } # # "d1" is created based on the definitions of the last example # # Add the methods from "M1" as per-object mixin to "d1" d1 object mixins add M1 # # Add the methods from "M2" as per-class mixin to class "C" C mixins add M2 # Invoke the method foo d1 foo # result: "M1 foo: M2 foo: d1 foo: D foo: C foo: " # Query the precedence order from NX via introspection d1 info precedence # result: "::M1 ::M2 ::D ::C ::nx::Object" -------------------------------------------------- The example in <> is an extension of the previous example. We define here two additional classes +M1+ and +M2+ which are used as per-object and per-class mixins. Both classes define the method +foo+, these methods shadow the definitions of the intrinsic class hierarchy. Therefore, an invocation of +foo+ on object +d1+ causes first an invocation of method in the per-object mixin. [[xmp-method-resolution3]] .Listing {counter:figure-number}: Method Invocation Flags {set:xmp-method-resolution3:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- # # "d1" is created based on the definitions of the last two examples, # the mixins "M1" and "M2" are registered. # # Define a public object method "bar", which calls the method # "foo" which various invocation options: # d1 public object method bar {} { puts [:foo] puts [: -local foo] puts [: -intrinsic foo] puts [: -system foo] } # Invoke the method "bar" d1 bar -------------------------------------------------- In the first line of the body of method +bar+, the method +foo+ is called as usual with an implicit receiver, which defaults to the current object (therefore, the call is equivalent to +d1 foo+). The next three calls show how to provide flags that influence the method resolution. The flags can be provided between the colon and the method name. These flags are used rather seldom but can be helpful in some situations. The invocation flag +-local+ means that the method has to be resolved from the same place, where the current method is defined. Since the current method is defined as an object method, +foo+ is resolved as an object method. The effect is that the mixin definitions are ignored. The invocation flag +-local+ was already introduced in the section about method protection, where it was used to call _private_ methods. The invocation flag +-intrinsic+ means that the method has to be resolved from the intrinsic definitions, meaning simply without mixins. The effect is here the same as with the invocation flag +-local+. The invocation flag +-system+ means that the method has to be resolved from basic - typically predefined - classes of the object system. This can be useful, when script overloads system methods, but still want to call the shadowed methods from the base classes. In our case, we have no definitions of +foo+ on the base sclasses, therefore, an error message is returned. The output of <> is: ---- M1 foo: M2 foo: d1 foo: D foo: C foo: d1 foo: D foo: C foo: d1 foo: D foo: C foo: ::d1: unable to dispatch method 'foo' ---- === Parameters NX provides a generalized mechanism for passing values to either methods (we refer to these as _method parameters_) or to objects (these are called _configure parameters_). Both kind of parameters might have different features, such as: - Positional and non-positional parameters - Required and non-required parameters - Default values for parameters - Value-checking for parameters - Multiplicity of parameters TODO: complete list above and provide a short summary of the section Before we discuss method and configure parameters in more detail, we describe the parameter features in the subsequent sections based on method parameters. ==== Positional and Non-Positional Parameters If the position of a parameter in the list of formal arguments (e.g. passed to a function) is significant for its meaning, this is a _positional_ parameter. If the meaning of the parameter is independent of its position, this is a _non-positional_ parameter. When we call a method with positional parameters, the meaning of the parameters (the association with the argument in the argument list of the method) is determined by its position. When we call a method with non-positional parameters, their meaning is determined via a name passed with the argument during invocation. [[xmp-posnonpos]] .Listing {counter:figure-number}: Positional and Non-Positional Method Parameters {set:xmp-posnonpos:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Object create o1 { # # Method foo has positional parameters: # :public object method foo {x y} { puts "x=$x y=$y" } # # Method bar has non-positional parameters: # :public object method bar {-x -y} { puts "x=$x y=$y" } # # Method baz has non-positional and # positional parameters: # :public object method baz {-x -y a} { puts "x? [info exists x] y? [info exists y] a=$a" } } # invoke foo (positional parameters) o1 foo 1 2 # invoke bar (non-positional parameters) o1 bar -y 3 -x 1 o1 bar -x 1 -y 3 # invoke baz (positional and non-positional parameters) o1 baz -x 1 100 o1 baz 200 o1 baz -- -y -------------------------------------------------- Consider the example in <>. The method +foo+ has the argument list +x y+. This means that the first argument is passed in an invocation like +o1 foo 1 2+ to +x+ (here, the value +1+), and the second argument is passed to +y+ (here the value +2+). Method +bar+ has in contrary just with non-positional arguments. Here we pass the names of the parameter together with the values. In the invocation +o1 bar -y 3 -x 1+ the names of the parameters are prefixed with a dash ("-"). No matter whether in which order we write the non-positional parameters in the invocation (see line 30 and 31 in <>) in both cases the variables +x+ and +y+ in the body of the method +bar+ get the same values assigned (+x+ becomes +1+, +y+ becomes +3+). It is certainly possible to combine positional and non-positional arguments. Method +baz+ provides two non-positional parameter (+-y+ and +-y+) and one positional parameter (namely +a+). The invocation in line 34 passes the value of +1+ to +x+ and the value of +100+ to +a+. There is no value passed to +y+, therefore, value of +y+ will be undefined in the body of +baz+, +info exists y+ checks for the existence of the variable +y+ and returns +0+. The invocation in line 35 passes only a value to the positional parameter. A more tricky case is in line 36, where we want to pass +-y+ as a value to the positional parameter +a+. The case is more tricky since syntactically the argument parser might consider +-y+ as the name of one of the non-positional parameters. Therefore, we use +--+ (double dash) to indicate the end of the block of the non-positional parameters and therefore the value of +-y+ is passed to +a+. ==== Optional and Required Parameters Per default positional parameters are required, and non-positional parameters are optional (they can be left out). By using parameter options, we can as well define positional parameters, which are optional, and non-positional parameters, which are required. [[xmp-optional-req]] .Listing {counter:figure-number}: Optional and Required Method Parameters {set:xmp-optional-req:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Object create o2 { # # Method foo has one required and one optional # positional parameter: # :public object method foo {x:required y:optional} { puts "x=$x y? [info exists y]" } # # Method bar has one required and one optional # non-positional parameter: # :public object method bar {-x:required -y:optional} { puts "x=$x y? [info exists y]" } } # invoke foo (one optional positional parameter is missing) o2 foo 1 -------------------------------------------------- The example in <> defined method +foo+ with one required and one optional positional parameter. For this purpose we use the parameter options +required+ and +optional+. The parameter options are separated from the parameter name by a colon. If there are multiple parameter options, these are separated by commas (we show this in later examples). The parameter definition +x:required+ for method +foo+ is equivalent to +x+ without any parameter options (see e.g. previous example), since positional parameters are per default required. The invocation in line 21 of <> will lead to an undefined variable +y+ in method +foo+, because no value us passed to the optional parameter. Note that only trailing positional parameters might be optional. If we would call method +foo+ of <> with only one argument, the system would raise an exception. Similarly, we define method +bar+ in <> with one required and one optional non-positional parameter. The parameter definition +-y:optional+ is equivalent to +-y+, since non-positional parameter are per default optional. However, the non-positional parameter +-x:required+ is required. If we invoke +bar+ without it, the system will raise an exception. ==== Default Values for Parameters Optional parameters might have a default value. This default value is used, when no argument is provided for the corresponding parameter. Default values can be specified for positional and non-positional parameters. [[xmp-default-value]] .Listing {counter:figure-number}: Method Parameters with Default Values {set:xmp-default-value:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Object create o3 { # # Positional parameter with default value: # :public object method foo {{x 1} {y 2}} { puts "x=$x y=$y" } # # Non-positional parameter with default value: # :public object method bar {{-x 10} {-y 20}} { puts "x=$x y=$y" } } # use default values o3 foo o3 bar -------------------------------------------------- In order to define a default value for a parameter, the parameter specification must be of the form of a 2-element list, where the second argument is the default value. See for an example in <>. ==== Value Constraints NX provides value constraints for all kind of parameters. By specifying value constraints, a developer can restrict the permissible values for a parameter and document the expected values in the source code. Value checking in NX is conditional, it can be turned on or off in general, or on a per-usage level (more about this later). The same mechanisms can be used not only for input value checking, but as well for return value checking (we will address this point as well later). ===== Built-in Value Constraints NX comes with a set of built-in value constraints, which can be extended on the scripting level. The built-in checkers are either the native checkers provided directly by the Next Scripting Framework (the most efficient checkers) or the value checkers provided by Tcl through +string is ...+. The built-in checkers have as well the advantage that they can be used also at any time during bootstrap of an object system, at a time, when e.g. no objects or methods are defined. The same checkers are used as well for all C-implemented primitives of NX and the Next Scripting Framework. [[img-value-checkers]] image::value-checkers.png[align="center",title="General Applicable Value Checkers in NX"] {set:img-value-checkers:Figure {figure-number}} <> shows the built-in general applicable value checkers available in NX, which can be used for all method and configure parameters. In the next step, we show how to use these value-checkers for checking permissible values for method parameters. Then we will show, how to provide more detailed value constraints. [[xmp-value-check]] .Listing {counter:figure-number}: Method Parameters with Value Constraints {set:xmp-value-check:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Object create o4 { # # Positional parameter with value constraints: # :public object method foo {x:integer o:object,optional} { puts "x=$x o? [info exists o]" } # # Non-positional parameter with value constraints: # :public object method bar {{-x:integer 10} {-verbose:boolean false}} { puts "x=$x verbose=$verbose" } } # The following invocation raises an exception, since the # value "a" for parameter "x" is not an integer o4 foo a -------------------------------------------------- Value constraints are specified as parameter options in the parameter specifications. The parameter specification +x:integer+ defines +x+ as a required positional parameter which value is constraint to an integer. The parameter specification +o:object,optional+ shows how to combine multiple parameter options. The parameter +o+ is an optional positional parameter, its value must be an object (see <>). Value constraints are specified exactly the same way for non-positional parameters (see method +bar+ in <>). [[xmp-check-parameterized]] .Listing {counter:figure-number}: Parameterized Value Constraints {set:xmp-check-parameterized:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- # # Create classes for Person and Project # nx::Class create Person nx::Class create Project nx::Object create o5 { # # Parameterized value constraints # :public object method work { -person:object,type=Person -project:object,type=Project } { # ... } } # # Create a Person and a Project instance # Person create gustaf Project create nx # # Use method with value constraints # o5 work -person gustaf -project nx -------------------------------------------------- The native checkers +object+, +class+, +metaclass+ and +baseclass+ can be further specialized with the parameter option +type+ to restrict the permissible values to instances of certain classes. We can use for example the native value constraint +object+ either for testing whether an argument is some object (without further constraints, as in <>, method +foo+), or we can constrain the value further to some type (direct or indirect instance of a class). This is shown by method +work+ in <> which requires the parameter +-person+ to be an instance of class +Person+ and the parameter +-project+ to be an instance of class +Project+. ===== Scripted Value Constraints The set of predefined value checkers can be extended by application programs via defining methods following certain conventions. The user defined value checkers are defined as methods of the class +nx::Slot+ or of one of its subclasses or instances. We will address such cases in the next sections. In the following example we define two new value checkers on class +nx::Slot+. The first value checker is called +groupsize+, the second one is called +choice+. [[xmp-user-types]] .Listing {counter:figure-number}: Scripted Value Checker for Method Parameters {set:xmp-user-types:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- # # Value checker named "groupsize" # ::nx::Slot method type=groupsize {name value} { if {$value < 1 || $value > 6} { error "Value '$value' of parameter $name is not between 1 and 6" } } # # Value checker named "choice" with extra argument # ::nx::Slot method type=choice {name value arg} { if {$value ni [split $arg |]} { error "Value '$value' of parameter $name not in permissible values $arg" } } # # Create an application class D # using the new value checkers # nx::Class create D { :public method foo {a:groupsize} { # ... } :public method bar {a:choice,arg=red|yellow|green b:choice,arg=good|bad} { # ... } } D create d1 # testing "groupsize"; # the second call (with value 10) will raise an exception: d1 foo 2 d1 foo 10 # testing "choice" # the second call (with value pink for parameter a) # will raise an exception: d1 bar green good d1 bar pink bad -------------------------------------------------- In order to define a checker +groupsize+ a method of the name +type=groupsize+ is defined. This method receives two arguments, +name+ and +value+. The first argument is the name of the parameter (mostly used for the error message) and the second parameter is provided value. The value checker simply tests whether the provided value is between 1 and 3 and raises an exception if this is not the case (invocation in line 36 in <>). The checker +groupsize+ has the permissible values defined in its method's body. It is as well possible to define more generic checkers that can be parameterized. For this parameterization, one can pass an argument to the checker method (last argument). The checker +choice+ can be used for restricting the values to a set of predefined constants. This set is defined in the parameter specification. The parameter +a+ of method +bar+ in <> is restricted to the values +red+, +yellow+ or +green+, and the parameter +b+ is restricted to +good+ or +bad+. Note that the syntax of the permissible values is solely defined by the definition of the value checker in lines 13 to 17. The invocation in line 39 will be ok, the invocation in line 40 will raise an exception, since +pink+ is not allowed. If the same checks are used in many places in the program, defining names for the value checker will be the better choice since it improves maintainability. For seldom used kind of checks, the parameterized value checkers might be more convenient. ==== Multiplicity ***************************************************************************** *Multiplicity* is used to define whether a parameter should receive single or multiple values. ***************************************************************************** A multiplicity specification has a lower and an upper bound. A lower bound of +0+ means that the value might be empty. A lower bound of +1+ means that the parameter needs at least one value. The upper bound might be +1+ or +n+ (or synonymously +*+). While the upper bound of +1+ states that at most one value has to be passed, the upper bound of +n+ says that multiple values are permitted. Other kinds of multiplicity are currently not allowed. The multiplicity is written as parameter option in the parameter specification in the form _lower-bound_.._upper-bound_. If no multiplicity is defined the default multiplicity is +1..1+, which means: provide exactly one (atomic) value (this was the case in the previous examples). [[xmp-multiplicity]] .Listing {counter:figure-number}: Method Parameters with Explicit Multiplicity {set:xmp-multiplicity:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Object create o6 { # # Positional parameter with a possibly empty # single value # :public object method foo {x:integer,0..1} { puts "x=$x" } # # Positional parameter with a possibly empty # list of values value # :public object method bar {x:integer,0..n} { puts "x=$x" } # # Positional parameter with a nonempty # list of values # :public object method baz {x:integer,1..n} { puts "x=$x" } } -------------------------------------------------- <> contains three examples for positional parameters with different multiplicities. Multiplicity is often combined with value constraints. A parameter specification of the form +x:integer,0..n+ means that the parameter +x+ receives a list of integers, which might be empty. Note that the value constraints are applied to every single element of the list. The parameter specification +x:integer,0..1+ means that +x+ might be an integer or it might be empty. This is one style of specifying that no explicit value is passed for a certain parameter. Another style is to use required or optional parameters. NX does not enforce any particular style for handling unspecified values. All the examples in <> are for single positional parameters. Certainly, multiplicity is fully orthogonal with the other parameter features and can be used as well for multiple parameters, non-positional parameter, default values, etc. ==== Defaults substitution Optional object and method parameters can set a default value. Recall that default values can be specified for positional and non-positional parameters, alike. This default value is used to define a corresponding method-local and object variable, respectively, and to set it to the default value. By default, the default value is taken literally (without any substitutions). Default values can also be preprocessed into a final value using Tcl substitution as provided by the Tcl +[subst]+ command. To control the kind of substitutions to be performed, the parameter option +substdefault+ can be provided. [[substdefault]] .Listing {counter:figure-number}: Default-value substitution using +substdefault+ {set:substdefault:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- nx::Class create ::D nx::Class create ::C { # # By default, all substitutions (command, variable, control # characters) are active, when "substdefault" is used: # :property {d:object,type=::D,substdefault {[::D new]}} # # The actual property values are computed and # set at instantiation time. # :create ::c } ::c cget -d -------------------------------------------------- <> uses +substdefault+ to provide a default value for the property +d+. In this example, the default value is a fresh instance of class +::D+. When the parameter option +substdefault+ is used default, all substitution kinds of Tcl are active: command, variable, and backslash substitution. +substdefault+ can be parameterized to include or to exclude any combination of substitution kinds by providing a bit mask: - +substdefault=0b111+: all substitutions active (default) - +substdefault=0b100+: substitute backslashes only (like +subst -novariables -nocommands+) - +substdefault=0b010+: substitute variables only (like +subst -nobackslashes -nocommands+) - +substdefault=0b001+: substitute commands only (like +subst -nobackslashes -novariables+) - +substdefault=0b000+: substitute nothing (like +subst -nobackslashes -nocommands -novariables+, noop) == Advanced Language Features ... === Objects, Classes and Meta-Classes ... === Resolution Order and Next-Path ... === Details on Method and Configure Parameters The parameter specifications are used in NX for the following purposes. They are used for - the specification of input arguments of methods and commands, for - the specification of return values of methods and commands, and for - the specification for the initialization of objects. We refer to the first two as method parameters and the last one as configure parameters. The examples in the previous sections all parameter specification were specifications of method parameters. ***************************************************************************** *Method parameters* specify properties about permissible values passed to methods. ***************************************************************************** The method parameter specify how methods are invoked, how the actual arguments are passed to local variables of the invoked method and what kind of checks should be performed on these. ***************************************************************************** *Configure parameters* are parameters that specify, how objects can be parameterized upon creation. ***************************************************************************** Syntactically, configure parameters and method parameters are the same, although there are certain differences (e.g. some parameter options are only applicable for objects parameters, the list of object parameters is computed dynamically from the class structures, object parameters are often used in combination with special setter methods, etc.). Consider the following example, where we define the two application classes +Person+ and +Student+ with a few properties. [[xmp-object-parameters]] .Listing {counter:figure-number}: Configure Parameters {set:xmp-object-parameters:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- # # Define a class Person with properties "name" # and "birthday" # nx::Class create Person { :property name:required :property birthday } # # Define a class Student as specialization of Person # with and additional property # nx::Class create Student -superclass Person { :property matnr:required :property {oncampus:boolean true} } # # Create instances using configure parameters # for the initialization # Person create p1 -name Bob Student create s1 -name Susan -matnr 4711 # Access property value via "cget" method puts "The name of s1 is [s1 cget -name]" -------------------------------------------------- The class +Person+ has two properties +name+ and +birthday+, where the property +name+ is required, the property +birthday+ is not. The class +Student+ is a subclass of +Person+ with the additional required property +matnr+ and an optional property +oncampus+ with the default value +true+ (see <>). The class diagram below visualizes these definitions. [[img-configure-parameters]] image::configure-parameter.png[align="center",title="System and Application Classes"] {set:img-configure-parameters:Figure {figure-number}} In NX, these definitions imply that instances of the class of +Person+ have the properties +name+ and +birthday+ as _non-positional object parameters_. Furthermore, it implies that instances of +Student+ will have the configure parameters of +Person+ augmented with the object parameters from +Student+ (namely +matnr+ and +oncampus+). Based on these configure parameters, we can create a +Person+ named +Bob+ and a +Student+ named +Susan+ with the matriculation number +4711+ (see line 23 and 24 in <>). After the object +s1+ is created it has the instance variables +name+, +matnr+ and +oncampus+ (the latter is initialized with the default value). ==== Configure Parameters available for all NX Objects The configure parameters are not limited to the application defined properties, also NX provides some predefined definitions. Since +Person+ is a subclass of +nx::Object+ also the configure parameters of +nx::Object+ are inherited. In the introductory stack example, we used +-mixins+ applied to an object to denote per-object mixins (see <>). Since +mixins+ is defined as a parameter on +nx::Object+ it can be used as an object parameter +-mixins+ for all objects in NX. To put it in other words, every object can be configured to have per-object mixins. If we would remove this definition, this feature would be removed as well. As shown in the introductory examples, every object can be configured via a scripted initialization block (the optional scripted block specified at object creation as last argument; see <> or <>). The scripted block and its meaning are as well defined by the means of configure parameters. However, this configure parameter is positional (last argument) and optional (it can be omitted). The following listing shows the configure parameters of +Person p1+ and +Student s1+. [[xmp-object-parameter-list]] .Listing {counter:figure-number}: Computed Actual Configure Parameter {set:xmp-object-parameter-list:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- Configure parameters for Person p1: Command: p1 info lookup syntax configure Result: -name /value/ ?-birthday /value/? ?-object-mixins /mixinreg .../? ?-class /class/? ?-object-filters /filterreg .../? ?/__initblock/? Configure parameter for Student s1: Command: s1 info lookup syntax configure Result: ?-oncampus /boolean/? -matnr /value/ -name /value/ ?-birthday /value/? ?-object-mixins /mixinreg .../? ?-class /class/? ?-object-filters /filterreg .../? ?/__initblock/? -------------------------------------------------- The given parameter show, how (a) objects can be configured at run time or (b) how new instances can be configured at creation time via the +new+ or +create+ methods. Introspection can be used to obtain the configuration parameters from an object via +p1 info lookup parameters configure+ (returning the configure parameters currently applicable for +configure+ or +cget+) or from a class +Person info lookup parameters create+ on a class (returning the configure parameters applicable when an object of this class is created) The listed configure parameter types +mixinreg+ and +filterreg+ are for converting definitions of filters and mixins. The last value +__initblock+ says that the content of this variable will be executed in the context of the object being created (before the constructor +init+ is called). More about the configure parameter types later. ==== Configure Parameters available for all NX Classes Since classes are certain kind of objects, classes are parameterized in the same way as objects. A typical parameter for a class definition is the relation of the class to its superclass.In our example, we have specified, that +Student+ has +Person+ as superclass via the non-positional configure parameter +-superclass+. If no superclass is specified for a class, the default superclass is +nx::Object+. Therefore, +nx::Object+ is the default value for the parameter +superclass+. Another frequently used parameter for classes is +-mixins+ to denote per-class mixins (see e.g. the introductory Stack example in <>), which is defined in the same way. Since +Student+ is an instance of the meta-class +nx::Class+ it inherits the configure parameters from +nx::Class+ (see class diagram <>). Therefore, one can use e.g. +-superclass+ in the definition of classes. Since +nx::Class+ is a subclass of +nx::Object+, the meta-class +nx::Class+ inherits the parameter definitions from the most general class +nx::Object+. Therefore, every class might as well be configured with a scripted initialization block the same way as objects can be configured. We used actually this scripted initialization block in most examples for defining the methods of the class. The following listing shows (simplified) the parameters applicable for +Class Student+. [[xmp-class-parameter-list]] .Listing {counter:figure-number}: Parameters for Classes {set:xmp-class-parameter-list:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- Configure parameter for class nx::Class Command: nx::Class info lookup syntax configure Result: ?-superclass /class .../? ?-mixins /mixinreg .../? ?-filters /filterreg .../? ?-object-mixins /mixinreg .../? ?-class /class/? ?-object-filters /filterreg .../? ?/__initblock/? -------------------------------------------------- ==== User defined Parameter Types More detailed definition of the configure parameter types comes here. ==== Slot Classes and Slot Objects In one of the previous sections, we defined scripted (application defined) checker methods on a class named +nx::Slot+. In general, NX offers the possibility to define value checkers not only for all usages of parameters but as well differently for method parameters or configure parameters [[img-slots]] image::slots.png[align="center",title="Slot Classes and Objects"] {set:img-slots:Figure {figure-number}} ==== Attribute Slots Still Missing - return value checking - switch - initcmd ... - subst rules - converter - incremental slots == Miscellaneous ... === Profiling ... === Unknown Handlers NX provides two kinds of unknown handlers: - Unknown handlers for methods - Unknown handlers for objects and classes ==== Unknown Handlers for Methods Object and classes might be equipped with a method +unknown+ which is called in cases, where an unknown method is called. The method unknown receives as first argument the called method followed by the provided arguments [[xmp-unknown-method]] .Listing {counter:figure-number}: Unknown Method Handler {set:xmp-unknown-method:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- ::nx::Object create o { :object method unknown {called_method args} { puts "Unknown method '$called_method' called" } } # Invoke an unknown method for object o: o foo 1 2 3 # Output will be: "Unknown method 'foo' called" -------------------------------------------------- Without any provision of an unknown method handler, an error will be raised, when an unknown method is called. ==== Unknown Handlers for Objects and Classes The next scripting framework provides in addition to unknown method handlers also a means to dynamically create objects and classes, when these are referenced. This happens e.g. when superclasses, mixins, or parent objects are referenced. This mechanism can be used to implement e.g. lazy loading of these classes. Nsf allows one to register multiple unknown handlers, each identified by a key (a unique name, different from the keys of other unknown handlers). [[xmp-unknown-class]] .Listing {counter:figure-number}: Unknown Class Handler {set:xmp-unknown-class:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- ::nx::Class public object method __unknown {name} { # A very simple unknown handler, showing just how # the mechanism works. puts "***** __unknown called with <$name>" ::nx::Class create $name } # Register an unknown handler as a method of ::nx::Class ::nsf::object::unknown::add nx {::nx::Class __unknown} ::nx::Object create o { # The class M is unknown at this point :object mixins add M # The line above has triggered the unknown class handler, # class M is now defined puts [:info object mixins] # The output will be: # ***** __unknown called with <::M> # ::M } -------------------------------------------------- The Next Scripting Framework allows one to add, query, delete and list unknown handlers. [[xmp-unknown-registration]] .Listing {counter:figure-number}: Unknown Handler registration {set:xmp-unknown-registration:Listing {figure-number}} [source,tcl,numbers] -------------------------------------------------- # Interface for unknown handlers: # nsf::object::unknown::add /key/ /handler/ # nsf::object::unknown::get /key/ # nsf::object::unknown::delete /key/ # nsf::object::unknown::keys -------------------------------------------------- [bibliography] .References - [[Zdun, Strembeck, Neumann 2007]] U. Zdun, M. Strembeck, G. Neumann: Object-Based and Class-Based Composition of Transitive Mixins, Information and Software Technology, 49(8) 2007 . - [[Neumann and Zdun 1999a]] G. Neumann and U. Zdun: Filters as a language support for design patterns in object-oriented scripting languages. In Proceedings of COOTS'99, 5th Conference on Object-Oriented Technologies and Systems, San Diego, May 1999. - [[Neumann and Zdun 1999b]] G. Neumann and U. Zdun: Implementing object-specific design patterns using per-object mixins. In Proc. of NOSA`99, Second Nordic Workshop on Software Architecture, Ronneby, Sweden, August 1999. - [[Neumann and Zdun 1999c]] G. Neumann and U. Zdun: Enhancing object-based system composition through per-object mixins. In Proceedings of Asia-Pacific Software Engineering Conference (APSEC), Takamatsu, Japan, December 1999. - [[Neumann and Zdun 2000a]] G. Neumann and U. Zdun: XOTCL, an object-oriented scripting language. In Proceedings of Tcl2k: The 7th USENIX Tcl/Tk Conference, Austin, Texas, February 2000. - [[Neumann and Zdun 2000b]] G. Neumann and U. Zdun: Towards the Usage of Dynamic Object Aggregations as a Form of Composition In: Proceedings of Symposium of Applied Computing (SAC'00), Como, Italy, Mar 19-21, 2000. - [[Neumann and Sobernig 2009]] G. Neumann, S. Sobernig: XOTcl 2.0 - A Ten-Year Retrospective and Outlook, in: Proceedings of the Sixteenth Annual Tcl/Tk Conference, Portland, Oregon, October, 2009. - [[Ousterhout 1990]] J. K. Ousterhout: Tcl: An embeddable command language. In Proc. of the 1990 Winter USENIX Conference, January 1990. - [[Ousterhout 1998]] J. K. Ousterhout: Scripting: Higher Level Programming for the 21st Century, IEEE Computer 31(3), March 1998. - [[Wetherall and Lindblad 1995]] D. Wetherall and C. J. Lindblad: Extending Tcl for Dynamic Object-Oriented Programming. Proc. of the Tcl/Tk Workshop '95, July 1995. ./nsf2.4.0/doc/next-tutorial/person-student0.png000644 000766 000024 00000105470 12146730150 022342 0ustar00neumannstaff000000 000000 PNG  IHDRAjeYiCCPICC ProfilexXeTU]^{y..i0@BBQJJQ@PDDBPQEE{?wy\~s"аH#]   cee׶ @㒻sno72[^BF!`D\ }l$OH;%>'0 z45<}`G|$BCpxkaOOszzȍC<م wGzRX]n5o7=kihG [} ijccGv__{`{0,'?MAv$[J"'#+;힯l@#E!Tm9cy$lq g>d+@@H9ԁ60gA HI dӠrP k <1x ^)|`lB@8$@d@ΐA1P"tʂr"T݀nC]P?4 =yh ڀQ0 f`!XVu`3p< * wSx bF$Q*(=%凊DAe QzT5B-~h4-VGt6}݌Aы_2#QØ`04L!2 ӋyYbXa2 &`ױQ vñq8K'.+]uppx"/7ĻB|-?oRR RQYRPʡj@I#4v BPO%",D>*њH> A8CC/F,0 cc5aE&z&&8R{LS(f!fFg,\,:,,,,c,kڬYnQ ؂ΰfG[d?˾ȡ͑L\2 *ϵ̭ĝ=ȓDѡP(=E^N^cދü||||^Ux,^R \rJjf6~%By"U ='X S +ŕωJ`$T%$*$&$I:uRRRR-R_]HIQ y)K/k*,&$'&-W*D,o(TUyIEE tnm%eHzyee2 F+lU]գwU)E5}STVU#wO՞ > OSM SZZZZ}/k\+ۤwXSo?l@o`oPbƐ߰pH(clf|x„ۤdTi֬읹yylajgjް-2򵕰UkuGYD>[[wZU;]"145kSNNٝ[]p..]V+U5~qBӸ{x8zzlyZzVxxxy-zy3;7?PX=8#v}XpXqF§"" "#"/GAQZDf(F$&5f:V34vqtqaqCe7NNNMLJ>sבGS~8ftJ!)8QLrnRR̤֥QEM@<1!Q+'s K&0k+;{ɢ;N (?=v3Wrrsg,)?  Ɯ*2/j-(>]UPTzgYF9scחsgo\0ybsPEa%2cCU%K5/g]ޮbsF6z5k3_j 1 nxxh}Sf-[eM MPŖVۦۚHݩ{ӽvB{JNG|JgxBL{NX >|`~N_Cwo * 6)5=R|44<t ׉Iɹ!Ͽ}+̫״ px+Խiw^x|~~CGYٚ9?sͅ/t_ʾ|MТwٖ(^Zyζ~Ͼ Ǎ̓[m_f^{FzPHT { 1CN \К!jA*hBi0|fffa{aIi]P2QU疠DKIIkTULV WޯbƭUgBSVD;G'S7C/K? 0(߸4)',S[I=nbt9%n_k@7wo_`$S~7 ][ GEG FF[>x&P[ptQcId|)T4t4Ltvjss^<4wWn"^"b>~2A2!H= i{C+lGD*K2MPNw"ck%O%JWkjmU=!ƌ.6]k:rE̝/wA>o`>ʃC kh>37~b̈́ݤs^r{f[)iw*3il\|ҧϖ J_~d{Rr앤صu[ۂvH8 XP DIim1h3d`bceX+T@JhXxDuz2Wd.ȗ*UUT>BC[Sa_[SKˀbH1sp1Z,a-M ---MǟNK._ͻ3 ޯ}}g>ῠΆ GG (Śz(1>;,p M &'ҘZV~DjF\fpl˓:sOsa%Qc PpϢŒϥʦν8?^>ra@@`Х#WFjFj=:xmzG7zye/mwҾֱֵֹ޽~gwj }zqxfdɱ'v?;4YEˢW9~5?dF\|çi _\}SXβDLAX!넟TMv J\Fjt&̑1H *' h;o :Rm 0C (Mp`C4Tt=`:XvQ3H恮@Hbb0Xv9n!a*yphDl$q2Hd_uM<-:%; SaN3 2eq`YfeS`{~Cc3k;grW5_NG0E@'/%j!F+6.^,))!.PX&TV_KnC} b|\<{iTkўYC#{[(8ˤt^}HJ [j;cd{. \ w5X&U5$@Аp3?}bŵK%T8RuL0qi23'O)<#;Qt^q`)Gٓy+*\zP]V[g{M:KNmw;g{$-#x"}ų׌omsg?̹]fjygmsSxy(DWň ؂h ~HxD Aa 8n(({ITA'{1D 3UĦb'pxU|~ʝAPF$IdUr= u9 'M)-m(-zm7Gh*UGYBX ll˜vx(̔!4>~%*h&(VN䠨AlLD7}E2:rlr?G*S>EC3@+Z;Y'OZ]`Ɉl,fblhe~%J=S> nkGz}h|]Յ`B3GDE>9zA\bƣIP㛩Q'Nfg՞8th.U^MYs/KV__oi̽Ӭr{½ݨj]'G ZO&n=_z%g]Yʼ/6T$Itٮ?31Lf Qp 4^o 1AJd AI&t `,[p /Ql}6Zh4uLˀu^npp[xM*zhI&L%NHQDMNޠY]K3%̘ۘ2ǰPԲγdgɑ)+[=O!ŌǯS9LH}_)(&-*!)(%,!="sY"JiSyCeK V'aTӲIխ՟56k1KT yado̙e߾D=z]}^Aܙ9sfy̙= ,#j7kMhӺM 00Hk L7700 h|XX -`@0TXXccn~SyccӺM2  YsSH@Z ,HzG w>n)YoSiYUH\Ly`4 ;E@=A޲75(rHzX@?}n)) f8l7rJwP޾zKp/?, ~nPn 9{BhTg^wPr0 @^ %R) STiɉHӽ o@&ʄ8pn}|q4 ҉H4b,02Cս?n#Կ^Գm{?"h 9NK`&(-@do$*>b@0%UUN^ x!NE;`A=e}dF8;AFʁAp @Hc;'_z<~ )5ɋ@3GdWa)JmsgZHaqnٻUHνrb`>pԖ{{AC_K4TK~NʮG9> 'H%Ssq=BM-8K'z9t5t=PmHqg쨡&˫UdYނ D YUV_TfWXe;ZU^;N>5V?b5`^>7_9R^3^p&l  e)'VMAwmwOb'Fٴ؞\*OZv( ˓uud} c Gk([&}k*Z.]҇N˫ǟW%cH+ۤ8Y9x𰴔3R$pnHmͿ9 gѧ(zkJS#TJu (ےz驺C~)me ʺglX%rmܽux6nm۾!=# ;ye[.ywؠw%*ljk͹`9/\Ho$,Vo l)'u=(8vIߵQM'C{TҵXUm;y.+4{`ُ]/;훿"7`JrIGaT =Cwٟ h_HѾ4'˓rFRt\V:2`;Qa|; ͛^8Nfgv&ɻ'?zrϯWOųD޼&ܢS{eov٢0DnpHX ) 7+k$-APuw92!]MU.Z-}|A% >w^)%-Urxvd呪Rg/u6o[yF)rY O<^p[^h4I[4}߼BB`)t8uC q|oތdtPz1 (Kf+Ԍvldõa;ӏʒKZ n,sхOi%q15c"\3~xL6p兑="wt. 5 "i3JU YY~VwfڧaIo@00l06pST@ RR.&I= h[090!jAPOJΪݙnY}e|p$]k Lgu;,OkTDim+j~J`JV.+갚 3҆n,̗]ՕRc;\wġjuswʑ3+n'vJZ,eJJQiqц]NxngǛ f T+Jl.6WtWCIx#B$a!Bkڬ"OjdaU "f})iZtdbՔ JtU5[-6댯R3,@ ]4XdRdʧ xƒ eMpS"F;FF*P\9~Qs_SFR,$y@U,oM;H 4; aAC[I\45D!; 0tkWpBg<_AXFBݲL+޻5cۮGGԫv!rO`Xs0 h% &qx\tN쉧>+dI[W`,AuV" =% KZ%##Cvi#^BY@N%TAg[`OՎQzDU?Vbz%xY싐H1{<%2%kGjցef_O#LpX ؅ Kξgoda ^(+P ]-[>&^-.E+6ɹ2 Zvh㌝\BK~);C֐z:yS._p$e>vްȸ*aXdd(p4'%fX2 2 &i(@_X! 4:tZ5gc"3cw?=@O!0Y3 ^jcgyKѝ Ie,`,0 ke,`, Fg'XX E-`@0EvZ>wsģ^=Z) T*сn9rox,ȩչSy44;X`^,`͋ Eɼ"aD^~J6Ū!~(\3aTGxcXcפu3rbr Ur/}W/wTa4>y߇ߍ"w{d%.UwQ9f@XSYٍb{PlYKZJWO`X-W]*xJszU49b1B{}@\Q)?I*U( Xd'u-/kп+X׀5[en l05V+'kj#݌oXdz2]0 4[* YFzu8k#N{^$o9#H|,@򓛷@1!Br=o])"czhU#W<1*[m#v]7b` _2"owhlpӼzVsťNW:sed…̳x3*eowj^x׎$Fbb11c*d*-O9-_s=19YgeӖeKSnPp@uY=5nx+|r1 LmS(RpC[?:yWޥd+e+E]|BJ:rjGour SRï#k׭ <Ȱ$|MaXd8FD 1@_bzY#}eXrh%crfY"ꜣ28wFv.X!g뻤k&քE&&5&x=)K@9zȜdНMXTLW'F)|c=ݽ)}gJMqLvsinG-\gzT-|tǚf`[Yhr%o°`d᰹@ RRzrK i[#9;^ '%}Ȁ`g~󥳲mNfygzzMqC'oIlSvX)6 )EI6gt:+j~J`JV.+jA1F /+0 0 tEyP.@rwʑ3bfJ0cJQ,2rf )=W6rzp^s;bWJnz=w>͖-QmUO]xhuXp3h\۞r|`nx*_ ˞5yvteN7} Tie9In4lW{#x[~UB TXp~`5V>V}{Z>f7 T5,WYc\Ua MDU P(^] #ǔH*5lGSPaAй˚NuqWu[#V#-#CV7?H:G,2V[C[:2N:lۡ.\~j󟶈`:rV-o#|ҵ`+ tiT g2¾%ޓ9Ŏj| x9/ HrXCbuṊ:LFEXA?d<98X(ݺ[cpq{+;P,_J7~fAr\ 6ĩg6x&c^^l=;fYԉC3vt7s߆jv\3'7cQNL`&Yuo?sO/<){,ת@k`D *z\x65/+UX]3'UU8oYzhHyWa+?UoyFU^ 9`RR\cO)T2Ϟ 7*=zN9A`$ Z7sPA>@4tKdy63,KfrȢ,0L# RzCMvvVdd9Ge %p^>3v!6Kߙ~ tɲvE/ a!M&p$ln{g?_B@9;r0 I24 k$,'nC+&;N[JԸCM.6&; n9]Vl&@.Cre0x=G{ƪ{fN0!*Xtt*\&&Ggk$N{$kI(3N1pz|'9oM{8ćQ91WVp÷M-"X`äU0'CգX[|}|dx,ȩV3SMu:Wr*NHǐ9Qq^+NG { {$NʼsgBOfKO% cT'Iƍr2CrԀ`r_JO9ydj1C^?~Yͮ_xHnQo|wڷSrPU9pėspdwވq*coj ph-e q} ~@"P4w`oZIդXM(σXTGL~2wʭvmF-Zⱪ\ 5>Ex^0ZXM%c?C \'-"ț }Vm*' }A}^XcKLtF EF,[7F6Ƞ.= "&c?/nO- Eoz2]漍@!ު75ZGF^edl*C_뢙,n]M QwYu)e4*_vbիJ}*o҇O/vM7.3dOE$pjrjR,N<,74@ Fh/Ir,ngYƱ ~b"ow^YdgitMk|rl]Ə/e26G9׋ƻdO\Cb޶A@h8ɥfx֏-^d'񼫗%f9;]kP/5^>y0vtRX}{ȥw0O:d-M;&=(yCG$q`oR <*ia񿀧ӖIAzbr.AYٴA)Cjer6XW!%>u{hSV\'8(,/0l9GFaSd*cĎvD1x& w dq*4GP_EJf 5ˡfN46_"3%ǹpUPզؙwC@~r dA hȌn‚ U-* X`>l*S\ј! 8q}UT8}do/єUgh8%Jzdz*Z='?0x!ܹf(t| IDAT! 57xxPˢlɞB4g:t庎sKNj" }Y:I6*˶#ZC l8| g< 'SMY#ȡNOci 9l*z,;7@Y*h:PYrNПA;hߠO ӽ=4ڇxEo_) SC0N?q j}y| ~>M'aoP o`#Տǡg3 lHco7Hr0q3RFLO0er\EnGw;;ۜ==pHup>z,{} q6=O:a}zSnA+t& *=>AJ[sO>J jK th#`@*JK͇- gҧh =P :ۊEf7x<} $yär@h@-SGP@ }{?/(/PHL{ğ PBgjpAԽBO`}~b@0eVAw-uO%i^ 'yWFO,cP 99ieb t&)tO UcZ}M1 2M9VYpD{"l׎ϡ/U x _A_N%,AOIU>7@ B ЛA٦ f4-{MM\ ր`7ь V_ Mo:? 5-&ېCoA+$A-]G8A7;F[h77OpKohՀ}F9&Y"4M5:A jB:^wC?4pOpJY N <=;e{ )*%thLv)zk.+Я@Cw@q 0~3¹C?C97ޝ{T cznkɾCdm"Yv%mЃP-\$} Z6.FP>D49W$SOMtؚ`:rH]w$ӟ8!AP 6?q-665'Onbi17 '-E@O@>e$J HeJ} Y\\5(P-zV'\S-Њ#!( 380F+̋p!'R4;)lUㅰӬk@0iLD,#h7G#D]]'D?Rp Q4+D(9bziSq\ppBߋ%l̳&lg&8%MO0>v5F{lyY rzZ UsoeqJz@/I }_|* h\`cs'"Zc Ϲ۔3NMʑ$M&FQ R,`5h"VR>偖'bL"ZgiG]1E DLFL*?{8e5eo<ڑ))fN0%5q*(qA=`#Ih(jaU"D&L-'Aߎ _3@[^6|9I?i Nj9S !#Oli>8cx[ .TT JK&P=p\|6 L♢h_s a,JMO0!!u dQjı 0ށx*XĀ`*bb8=%L JMbh[,] \1|83NHrXj<bRSMӡ '<uҗ/Scfʴ $ &g%T \=8zVB&@tq2lekRӬCu. K(_1RbДj,4? `҉y:tM8ӓk݂Q!JM87Ks~YЀ, ·wwLݓ]|SīSeGs $] $J}z7z']L\0 2ٍAC*jTxnf8Le }[!,&JĦ'XNХ('п ]XS98ЋI]iNp]%OHL6[#$pY..ԋOjmu2a҈'MS_A$J$ަ#ROLŦ5u2=AZ@C:Ld[X~ 1ߢhhT>stm2ǀ`2ܗD#ڹ?9cZ`ʝT h'ŻظkhRmbTkFLO0ij jR)qB)ьi^  Qj,Oz8~5O}B Rjܭ8KkJg,0{  S*!JM5TJx!JM~E\L~2R`4VJ4@CӀ`tm Fg̔O4Do@ 7hʦzQ9C-l*6:ɬq@+tAMY Ǚ#~+WGlf83%DLDp8MHԯAK mTX`@N`nzi(u;GF] x-w q2?LgoDbTsTp:ڝD@O'K;j"xȓM3#ĆIݪ;=C9_|Jv\^"CB 4:' ̑7`FG3| 3|v~dK&iͰh%ť ,XP,GD0'Haa=CdpਔHsw ;i+y.ZyVryr)dz}9W˩av-f_#:&=AcjJNa.K8X*[!XgqiaTV7΢NsO啟gZѓ)4dg<-I ˥a[?-y?#Y'=k4GӒ.iGo[MhwQ_]:(=wKs>_/Gke#S{&^Ow٘4qoj :Ƙd6!| EnAsٛ=tB_FKg}wg[\~:Y#%U@EZ++dI.~0\'{ "5yp@Y{X`BQ e10-]- HG>R\9%zNb  R;;afy.C,N^ wNS t73qr^^h~I>%Ygd[[,/(]*s䄚aTg_sRԇ?)TwaYi}P9U$g??ȄSCsD프t,s ^z !.;aY8_x\Z#>oT~Q6}beerŘ'l|v]hrRf3_]%}\[/bAxUWɽP_iT[&>6^+E~uHL)09tP +UD3Hr,eO1h"^a Q,[Fe333dq# %  Hv؜ edIvV Kyyq= =@`Ix`bYbt,ݥSvFHs>G]R %hԇLL8*#ҧ5y7\}__bw挬lY@L)Ȓ9UHU 0v~DWʪjUrQR'>f,>ǿ˨4nɯf90_ѿ4&?e2Y'b ̏JmEÂ{>"*g/>.5E\j? .۫w݇07_vf(Rbn']O=W)'_*ky3GdWa)Pji=,w?wK}UaI7~Xt Py{T a#Y+ю-U;&t0-w<zMה4=C?[N9xQUڼ4ξ- ݵG?W/Oޱ{X WVZrn(N$`7j_L""$b Shu|9YyJS= >Y=\2S |ўOD+:%Ir/m--Ҷ@UՌp + h >go,B N r;ߋF[%*j=GX`+vO]Afdi-6,o5oz9%Oj:69_e˖v')Vh:!b[] }&a&UG,}yAPZ!U9*~+`՗y+0rV>( X徱8oYVWSոxK#8L?4 J< ):Yxv`DY(9B ʻP~FG-c<\7FX ~^&_eֳRaT;}j%%\2X b,"ωݲ>ƪ>6>p(?Mt1W|-1r(d1ryp52c E8fg@ND..{@kgYXI:O{ä*cI6(珧žFcUhr7i"Y/Hk[;`R'M6Ijc _ǰ>p#1.a>" Pb nӓԬ{ެeN0pn-Ísqz޲CN*8X ԿMXX * W昣r Xf2I$״ms>-ga/I:lYfW"Y@>tx'b]dd4]$k? rT9[X CeZģgB ŕO4ȭ.!/= }*JI/ `h؉Je!80/-@?sg[YK2Yc\J ExWkL9z5o],dUXmmVY]ՂEܯUdZVg{eHj*B\Ue hVofUpѳJ-8 ʭƎӨd}APM/1'0Z˵w*i,P![H˻|MU^wR$ct[!4u6d0:v^*_s-mP)<,%|i?tFyk$xqu hBDgopY2 ?.HO)%O;"!o8y䮵&(RTZ;/}TK=Er\ /;ʚQocJ0DC;$7[Oֺrϓb*51rn Of*`͐lQL?T,/.<R)Yd~ }װ=d(=D#*aS0u/PoglLÌqdHPayіHm8_%Wz *ځW߄  |W r뚺  _OYdc8640SL'8Ggn4Ӵil ͌Mg4O=W܁Kr+虬/j8Wmydϱbr h`a٩s򥺹[GVt(Cme}'JP׺P-'~-anJka/s$@ӟ'ܿGh.Q6ʑts}cXZ@<6/c P+@iD/N(N5^:sUTbt[.x-Y_|V{KbVӚ=Vz+.UWcJ^Pc:~*ӫ>-[M0ʽNnYl*ڃYmQ6lԙ:"ۍ-/~PVᓢ:~wՓ%GvFjrm_Bg7ombluP9 :-;Է: i=^erGF^.7}7y F Ӂ >EVFU*|ZX>;`Տz;`uNQutڔ_L?ߪlAJ0Ѓif@0N ~ >$r^86ś~lKe5{nTxse02e2YT\/_|Yed…̳ ʜJcfQI=d~feG}n*W6ʒ dKk>9l7<2tl?r/Һ~eS5Pk )6mX QB Z{##$v]䠐="!c;/Y͗0-{ʦ-ʖNlC#b+7[<gE~Y+S IDATtۤ&%r9m]~ݖ_](aS؅$04$7J0VlዓfQZ迥Kc OQo]v͔n/AROywDk^svz;QayOߗ_GG֮[%rI+B^Sa݇cPW?< ַ?ք3rmqiQ֭Y&=I7mX&_ 4xCQͻ^yJN eJHԬ$yztf1U4oCS=p6TåivD;I,uWJ&KsPSȞ-v|UK ʷU|8ʤ[6ه ~/j;fݾuRRrZ֢7x;yO,7Mț0G1u`Sol%(v\$kÝRS]n\"{ K~)#kOt~67czk,b,b"C$N$zRG9Wp2wF1*^bdaQcaÃl 3*}2Dfs:gfoh,z+g$cRa6A9g9!:,^L#TbrsWdS1X`o;&߇V5b,0y=)/NdR_4 i2dT/HӪ!&!ː8g`y]INvòGWpgTD j Yd4YL "vJ[Z0rŹdeo24171l1,I$ϟ!ɟ: v>>pрc6N~ Uw 72 C 4Kx:Lø SRUo [-ح(Wu-Ŋ2Ooho01,17ʩG8*>;iS'{i'ptL3agm<*͞My򥰱sL{:l&@<@'- m<[)<$ ;pN d)ƛ% $ KX|}YðC4mJ+,9 oTJemb뾣a)GΨNƒWòՄ/lcn;6U)Ai(͗~(O q3hۇ>Í Dgtc4ƻ2^ z5ЛTE!jk cY]R_NG:A@!wtZ6aAi+";jio*|c pZJ# [h OHV_XO)IL{߬ ҕN;x̣6 l6u~R%'"[MH?N*[x*rC@82gW㾷jD[)qN6f"f( VC ĿS5؉G^u^1s:G'$j*? No:H3b w*-Ck͡Xzg oDd4OvPՔ?F7[一UCZ`{IVaGplQqȯߪ%痑jBOUx:v29vi$i(CVWGU^ilNũgE*5P oꯠ\̰ :>[Ht.x$ϯG?#dga~۝Uˌ/ su_ͿȲUf;z +mHq΋]kܖߒo/oQ^ĉoSz±[:YyNQcyۺ9wbh8xk nN+r͆ǡ_=# +.> +ߺҸ;Wz>psiv |LHPi |ݎtS*륧?U@KdpgU0lٸUv>*g8}z3?-Ug^NaqtHup,9xfJ++fUA{:< Y˰ti] .)~-}9wS 6wwCζp;P,[ߡg}5jYfO=w@"a'%DNV>A+w˯!K"\~0OHM)Pd턞ͲOr,;ƛ6>׺ðϙ[ r}y\k ۥS!r e>%p*g"Y)O:.[;{eR|bnh12PiS7I(&4PNX{aPlAf0FமXUAGU^=̧qދ_=9CfhW~1dHy@EWL`+<QuU d0c'pj*E5D[RvKm -4QEY6,3=c"7(ɻ콫L6˔"qtp@z1}p6Nɒ,j ^: [}9M8*gderx%v&3>rh'>(SX_~4h VcLHY`(-weVeZt-Rt*refkP@O '~I_x 9·$Ut"V ۈ3b,0- 8pʕTԵ4 8L eb1m2 h,HCO=Wp' 0DZB֗]RYarK}GdWÒ[( G)% ݇,+ r򥺹[GV3ʉRzʏ'õ:Th0ecc"YȄ ̉pGzQdiQX*aPM~CՂݢjn廚WQo)oUbzl/YRV]UE`H=E-ESӅaY CڀBX @2te+0[&2}݇OwWwBo\,MyķM>mǘ9 qA $A )MyPW L(d21Qz,(A%WFC:7NV`"S>ʃsVPO|%`Տz;`vrc3ؖ?}j@p@{E`]<~[RYV=7^ \6.Le2YN^kwፅ|wBYيt+,1[d|œ=:2CXV[8%}neU(wm% Ȣ2f"fl۽OcYw5fdqtcc cw%{ #8%q[eH=Ǡ{̇CcR_ߍb?cf kkqǑ_1: ȻsP.;|ɑsr.r^dq$AP;/Y{/Guʽʦ-ʖNn/Ǝ_QYvno±#3 Ay`wt_V}ed$ ]6yIܸGN!d 1ũSYaqciP, .gmX GuL"z0(ͻ@T"޵cĹP6KJ|dIl}y~{dU1 "af67{@aXVjXs"hO[L{ RotF\21`N[6&u8s42I-/OPmZ3IDj[҃T*ӊ*ʄ˸ ~:`d\6JQ}AM/θ$N#ob {Ld+Eq ק.aQ3bX6Sdq6Go`ǨxɊAKÆΖ1e͜2:gndY9g9Px2Ɏa 41.c%P~ksd!7'H-l Lj |LjaF%k)/bl,s aAca 3di80,dBL쐰X41Zs/Y;줇G UHa(,09Y%uOdOʞ ?zs R(%kX`Vg+P"z_'Ca'4l n|*G={nC%p"%b~V2Y$nOf3 %jz-y:;Vq Od Jg{cMT{ޏ~ES.UGn@9o'|x$6fv~h! JQR5rA 0=A\xET6(ŋʞZ~侑ޠB %}p;+qzne'h婈14;m NopmrAyT <Uvj G M$wAyՏa4iZ@L3:*}7T"{oLGq^n .E&pnD}3bboo@A I$qKGeڑPh=x']%?ξ3#B=4&27&ӿxpN[髼(̝4=97Hr uL$ BiSjMӡxnv6&) aP~H-%}GȭA_M Y@w@x4Ĭ1Ay9^w KgnyfOgoWb^Aqŧ_F,c34V2@S5 }LG>TAF7Rn_nc&1AWtΨat^:U;vYϠcCjjd, tBր4W2g#K*}A7a9uf(q"Sd NJs"T] IBA)#9+A9$6 ڏ[UǻC$9Ys;M*ċILAU*:B:(A[=6ey9и:O*FupDy̿9o:;`9j'tj0DU*;Q _s6g`w}9íKnuO 36 QD nyu€!du|o]sqptHqt3٧ojEH21n@ǽQC4^;+z#2ch-R h=n~Mm1.2V?ҾQc`*eGV 0m܀0AX̜49I2X@˪/>MJƣ6Uu='зOG}IA6} ҜRzsBk[U@nKE}g9&!ޟ]{ =AI؁jX n<#O_Gكmr3Sd76J7U7i -`vfiC$p=P-99[({;rzilܴY?:YFCȣAN;6bɗ8(<(c}M"ޠ>sDv^"_ܭ>$9RX >SQHνc|Wos/hP%K48ɕ]!I=zk7:?oc@goAO /p_8t$FFm/?oU8Ǖ_\Kԗ}V; 49_?,:Z[P`MWuOVS_T^a8_J,kAV)gt]5.ey9"T.z9&l2Ҫ'ya< 5b,# /E1K:jxFK!fH֥$qWML(sV)f_)]E<ɺ:ygÑ28g[#?oWrU>٘\^=loEJzNKu4x\׳G<,- .AJ @wtL|VvEz{QeQQːw#Hd5x==)G"ˠZe#6lXnحH[7n+U-7 HV2$+Krɻ@v}%*v2vʒ_T3@#1Nߌ2׫L N0&3'u=(B݈č-o>>:#ݧDgmgt~ގ4{`ُ]/;훿"7`JsIGvX?>|#X]`7mw$A"&~*յwxy4j2(w.EIQ,ˈe9gk~wZeȍ7߽p֝HMwO~r˟_/C,7IMS{eov٢0Dnd=5%zقV c/۷='_E|{Pi~;WӱJhT;J>]e[R']/J^dTeoGKYR(YGwl@;e-⸓zqaM6m,1GG $$PdXF،|lC_p\;'CY2fKAE/rQ,V\NT5kRkw} eў—grv]d>!&A㪎SR`зbaS)YASyy^gߥÏ) 2iL|,R%AZ 4<* g8*$N?Z8),t}ܳ>)j ts 20Hs 9jXXX`b8"ujm~   8Hipccc'EG +h 4т(YJ%7nz̑sj_~r6SƜZٜ,,~%ĽlHΉ׭['6l񷀾WtxK`@ hs_sJig?YÙLRENjP_)_ zV BO< ]1ǘE>$@ߜfC}02$~y)o./Ћ$A!Yʍ?l-?c#i1%-tT~[b(iG}$a)6m r9諎 /k ۰8-AW_^n& C1Hyx1B5 gXZM1 /\T!0immD7d2L.bCIKKK2ٔq-tO#/L^:^8yH"V QmA75(5h\a9T^)W̓)ePN+oS<-믿.}{cXli"#[# r9&ga 3- ȡl|ZaIDATQF`{1΢'!?×* (w|'IGqx!;a]Iak׮>ꪫ٘4sqtЋ+=9twYSf4 h7>r?i_io oDu (62Ty>*^'/o4!] 5]-/#kHYT~e'W/g쒣K/ GfG@>^>Jb8^- .-r"|U@}P/xr1I`אXq'=@ aif^~2BC,{Hr2| !{3_5dTLsX&Mۯ]|jp<#DD^OLL<:njjzc:͒$@!z /s˓ `/^.̰( xE0C7ُkh8A̰8 xr=1/wGp E_f=~eHRHj6ުְU_$3PHxO Ps,^k9U /s[\jzUjHL9 mZou;ǛsT5!#s WN *Na֦uٓmku%[<H|s>KOF,JA-.|&r&wqON !Oۧ &X^{ȣ.4jG6ʿH<{t&SAZy(y"~ `!@l-؇QckhBcCu8 ! (yt ~=Ġn?ǯ D_B mJ p "3vĿ"@̳;UzT/f;c3x@ @4xVA>(v&mA"o|;a+xGҦ d3 uMA!~&g>?8BM}4@ !c=griS B_X"H+0wP93Aݞ4zÙxKax{  I_ ^vj4 l0I6Ff"s zY<m7l&h[ ro' C]őºpQ z%Bviخ:AI+w74<9VpX?iX-Q!P hM, p/4A6^P!}(3BJh#@*\li^p&8/S6 b0?)Q%4 󎃿]٬ FZyڶp`K%@,(a!o je|a9a4-w{ ,@[hg<4_x$ 0;8(jKdݶY퓕j KʍKة-"K_26E{E3um󲮩֙Q.o ʄ[,kgf*i9lٶC&L"d]|QR<.T? m_o+d#;b3EѮױ> Ejkkeuv4iZII4 {q&"Go./qУtaUZs?R@kxz.<1P?_p4ܠB'&E߸D:ۣOgshL3NF''';q} T=^mEƶh{pktϾ#ѱXkѦԯ NMcvrjsߩq}>:zh< N ,McfQ\9op_/i'>d{>o͝/W|s>-^;/Z$ 3Y4J0-w^qswPTDz.%%?,{ҭ+;z}S~vc8rXk i=2.DOJPۏ?X˨9c&񙪫;WM}rzU8 Srdߠ޽GpIҔ @#l P%7"'^p?Ky[䋍uNot-,V,ŋKWWUʫot%J> [lGV=[#E}2bYÁVyp&:M[g⧗_([IÖz>t ꤡᳲ̄*Jؚv\!N fVW(]~M/hygbd|B:6,FƢ[cAgAe#1FM-:_C9k#5A]xuwl!K9,N틮9. HTϥ7\B sώ r":c 2BFGN0 ~O(@qSW9p< kѬ3-a#VX.<3Cb##&*u9uGR:]//SDzqZY{6!##aYT^gރ@ J*O.~\Bb[ÛҀ4KΏi7γG"u_5O;3:3 Eo dD".f& 5 2 1 m 4IDATxU҆ $H`!!gqw[~\ ݝ;w2s33wHԜ>TW>cpr 4iԁ]H8hh 8/hh 8/hh 8ǫ&To0 v4׮@!zEp1I,&DI0bĈзoЫWZGe%S|ݤSrvȩn*ѾN*~¼faB **O?0 /hoK,Dgy{o GuTŽܟ8/LLr\OI oMއ_}հK38#ZaaSP{gr뭷K-Tof;/awW\qEl½_|}衇?N:thׯ_8Gxx_~835\uj>C5oVuӼ/\q饗mrM7fMw}(S\ 9$7SO$ Ijɲ &м&ZMxnck?|}}GN|E%\{=[W-/W_xv2~agqV[mIO?~c&r?_;ct(!0f*ISjcTB|L;4|iS ᧟~t 7 ~ڲ{gٓY?,(ό$ЧOG0=L3'@U!)|''ɟI7}];駟+I `> %MTJԵI+I#lW^yE90zb8- q.ݷ|vz-=ƴ3<2DI&$97K/ $\ve?%3ojʩ+*)m?A9ȭ8L:$o{x{6,y^(Lì.nK/4ׇ??s}vنضz^b1C4{WaÆ1yFmnDO5OG'03Wjtʔd3)c@f{챚'NmFŠ2sLgyf5_|E-|h@>}ëzϴj/f>i1^{-lȑA6trfbzG˗ Fc@Nk/!ៅGSCW8Q$05'Cd0gBB|oDJbMW)ZpW' 8jXRKZd^$cI-pjyz%<,MݱWp $LK6[,ƆŐUaYf ehlE=%`&CR ۱TgV >)]6@ '!eJ 7ܠ2$V2Hb$N*?ҮM>zNЈ뮻q@/atPZ*&;]-Sx62;J+i7 ^XgyF!56e]41!A{-hn Ȣ '|1ELdbmڎ@V \^%%zDX!qڈ6?d K4 ar NSy<@Xi?o6z vXi$]xᅺ߭[7h_|q4hP^K|p^Map;qe𘪰5NGeX%2,1aeyqW{O?tbj5\3;n`m4< .vЖ袋Fh<'|roF&&%XB' l3[SO=> 2`Zxa)[_ ,@~#/6f@.uW􍆔@M+$F6ٳڰ1b:_\_%?ryZiG^l묳NSE;p@ңdC W[mp=~;o᪫ gȐ![?^o C[8_x\̇̎86vj| T QfuְKWN9+rZ ذVUVYExpl/I'p7o6bW4oL` ,JzȹO$S'ɩI$S"fvG;C.IARQFi[hBȋ c~>|xa5߯rhHW|^-yQ]&O2]V0'U\+XNG b :5jb׋怗C@MME% Y ^621W/atrPE]Tt,dꫯAyXk3a/VfmJ{Jhɺ]3e!>Yw GkY/й0\s޼Bgfk>:x {챇8J=hm"㶻khhCy]*QnK.DN8ih|b)+~l)'⋡8jO;fMRg>9rhR$ Ӳklμ3ct 87qr矏#($Li{'PRÑ7zpsύBQ0r 8h⬓,WO?UL@"KlK ,2_?2#}f _~qWIn.Ѓ>weB}ES^[+Q'/B>01S2Om!4::<O.B!K/G+yzs0b nqfxl$Aviu<،EYKbl'`g0[Wbut桇nN$P cN[.&ÕW^ZO/PPh,D} o<++屦"1 m y_k{c!o`x9@M40~'n Nr G#8ѸIB#6L1;ŇpdV'{fF9ddsemOA=pxa@xɧQ9K5yG[veD 1%PWh,@."CaJf#4 5%}l$0\5򢁷df$˗fGҶ̄ƹبy m^+P_%i.ok/}P4l}J ELgu_5qwR봘\77Z)`;uVnQfC9ƌSrwt Vnю#WQKo4o}^zLy X{NFC9D1/|GfC }C9RqJ ׮!).&Ӳ԰hr#`u“G qd3KuiL|um7ydiWbZǴ(/MԁpI'|R=mOe:ZN 4ُ`ǽ*FRVThFYg=zZ\+6 `yE ,DzWKl6 $ΝF{RkYfK Lu%' =IIo4;ޑ7eW׊k ,1#B[:'+bL9C4z %܊yډsVa9H>Zy&6pzeYl4R{pab:lv<0 &'/;6h;&nCؼxac˛wMzڙoyֆK ;bhF `xh!ŌO3V)x{XviXPn֎zWHjd Z.߀ot,Tqq5|z#}# \<I$߸i}qeM6OF z\[~~d_UpOh<}8㓣J C_`p^|$FqхB|Ն>裩ޮ=f h/U;U}3O),b^CbV0VeFbv'&_qf=\cTZrmdfخ3OM7Zi5Nj&6p7Z^Le{eZթ[ z8YuFູ>,pgש 8R@HEj^n$K"py@̚g@|SO6\H+B"b VL>1Sz'iEr8יPC4҄#Fz$r`QxZXjAe'l6uAPm0w˄Ъf^.6C(# TvApѾc4H4J-' WF;VOI܍05eKE!9@L;h7^BF50l)lD2]S"C j^+k[o -\Xve3<~pa!CVVoΰھ뮻χ>B%09 A?~h8jԨ8|~-3pUW; 4(lFӶ4LAvrOC]I'4\}n _}Ue]B߾}u7SM5~RҘ^N8aXeU1-NUa4mk=lv4R|hb̅SwMuږ:0GK)0c}GaiUSŎY*6pѣG<+AK;r@4,'Y#4 3O2 P5'7ԚX&pjVM|&pjVM|&pj>\WYxw|S!Űuq|Y%&DVy.."Y%׉CxNiv.M-p$.f>-8˓S-K eܗuvĄX\h_g8e8z>Lp"ؼRH\/WǑILb~%}~^x޼-:.PR\?h93~Ӳ2My=j:&_ o D켚PU\VKkrBIIjMklRu0$;̓4q6l7J\s3x S%AIB6IkM@ xI YA9kWbs9ڑD'۳>; #Yf /1k6|믿#O]w5*?J(oj Y=.Qo\r%[nmڦD*NS1YWmֺ9+J@ͣ?bc?J(tL0z'52l⣏>ZTV)Zxn6<)c*eL6JG¨I8(G!>,Z<蠃bϞ=#BHTpxDu 6n˭V۔uקO&I￿bğ1myl.,6 X);knI/{60Z&, mĭ^zi0Y:²bhs:p(k+@O RY=JQ̓ȟly6 ;08CL!<2TLU0=L,̊W CfJ/Ժ뮫`C|Zdi|ݿ#TV!\stM_|+{wE^xaJJ(EDKT\p?3QVNWXƇ~mJX=< /l) Ony{z/144OB#r8 g>IT$ S#ZI%q0, 8; /N50~F# VBvbT#i+SI(N)3n>t)$:5/)/B0ܠy1U%Wjh ~Z؎:4/IIF=ƤLIaEzJ{FH 𓼋:Jl%96T54hP :t]wZ(7.,P?Ł 72'oȔ98$r`a!-:եL*>0Akc&3\{jX]y袋Fz6[uLlͦqkxy0C&xɛ0Jqk#nT?¼/,v/f 7ܠv.kN)JM>HoX/LXT\9R#G g2!RmE 8[79;b8[79;b8[79;b8[79;b8[79gYD"SҲցuHsK a(M|j{\Eɏ7]\šJ 6wr $%`Ay6xt L/2(\ ժ!Ůi#J ;cemg5!l;.kt% Z[Dq?\0$K5ڬ4/ILZHb$$Q ?byD!%!C+@G}*!j2X &-iK 4I]| guV]Nj&O?@I ~z+B#urV@և@)%Nh{V2AqGuf3YOb( |/Vlm595XOO LaA/뜱IE-<+Kk]~[~l:+gm5u+$~q)X*5Вڱ1:NchV h&Ƥ*cJ eXD8m[7-&dI)U0:,Nf7Md`-0|i8Z­si2ׄҷo_IDSX5~g(f(^zUVY%*H}ᤓN餓ԃ0={Ԩ%;F2YZdu` RhD0`@z`І }ht @TvApѾc4HtI ki`- X*\r`1FwZL Lс )*0ұ@f:8E(-D O2Q֓^ӰkvZ/5`P.jD @l0&m֑@lrEE8y-`æm֖:Z)U:.Βz'@Jܰ/hh 8/hh 8q̈Zɱ?IENDB`./nsf2.4.0/doc/next-tutorial/next-tutorial.html000644 000766 000024 00000537350 14274463622 022310 0ustar00neumannstaff000000 000000 Tutorial for the Next Scripting Language